在 Java 中读取 BMP 标头 [duplicate]

reading BMP header in Java [duplicate]

提问人:Andres Ordonez 提问时间:9/2/2023 更新时间:9/4/2023 访问量:66

问:

我想读取 BMP 图像的标题,以便当一个人写入图像 bmp 的路径时,它会显示:

  • 文件大小(以字节为单位)
  • 宽度(以像素为单位)
  • 高度(以像素为单位)

我正在研究 Java,老师建议使用 FileInputStream 和 FileOutputStream。

Java 映像 文件输入流 流程管理

评论

0赞 VGR 9/2/2023
由于您还没有向我们展示您的任何代码,因此很难知道从哪里开始解释。你以前用过这些课程吗?你以前用过 File 类吗?你以前写过 Java 程序吗?你有关于BMP格式的任何信息吗?
0赞 aled 9/2/2023
你没有提出任何问题。你有什么问题?

答:

1赞 Reilas 9/2/2023 #1

"...我想阅读BMP图像的标题......”

这是关于位图图像格式的维基百科文章,特别是文件头部分。
维基百科 – BMP 文件格式 – 位图文件头

宽度和高度的字节偏移量为 1822

"...老师建议使用 FileInputStream 和 FileOutputStream”

可以使用 InputStream#readNBytes 方法获取数据的前 n 个字节。在这种情况下,n + 4 自最后一个字段以来是 4 个字节。

try (FileInputStream stream = new FileInputStream("image.bmp")) {
    byte[] b = stream.readNBytes(0x32 + 4);
}

"...当一个人写入图像 BMP 的路径时,它会显示:

  • 文件大小(以字节为单位)
  • 宽度(以像素为单位)
  • 高度(以像素为单位)

..."

您可以利用 ByteBuffer 类来转换数值。

我正在使用以下 NASA 位图图像。
NASA – SVS – ID 13326 – frame_0001.bmp (3840×3840) 的帧文件索引

try (FileInputStream stream = new FileInputStream("files/frame_0001.bmp")) {
    byte[] b = stream.readNBytes(0x32 + 4);
    ByteBuffer bb = ByteBuffer.allocate(b.length);
    for (byte x : b) bb.put((byte) (x & 0xff));
    bb.order(ByteOrder.LITTLE_ENDIAN);
    String id;
    int size, sizeB, offset, width, height, planes, bpp,
        hSize, compression, image, h_ppm, v_ppm, colors, important;
    byte[] reserved1, reserved2;
    id = new String(Arrays.copyOfRange(b, 0, 2));
    bb.position(2);
    size = bb.getInt();
    reserved1 = Arrays.copyOfRange(b, 6, 8);
    reserved2 = Arrays.copyOfRange(b, 8, 10);
    bb.position(10);
    offset = bb.getInt();
    hSize = bb.getInt();
    width = bb.getInt();
    height = bb.getInt();
    planes = bb.getChar();
    bpp = bb.getChar();
    compression = bb.getInt();
    sizeB = bb.getInt();
    h_ppm = bb.getInt();
    v_ppm = bb.getInt();
    colors = bb.getInt();
    important = bb.getInt();
    String string
        = "b= %,d (0x%1$x), %s%n".formatted(b.length, Arrays.toString(b))
        + "id= '%s', %s%n".formatted(id, Arrays.toString(id.getBytes()))
        + "size= %,d%n".formatted(size)
        + "reserved1= %s%n".formatted(Arrays.toString(reserved1))
        + "reserved2= %s%n".formatted(Arrays.toString(reserved2))
        + "offset= %,d (0x%1$x)%n".formatted(offset)
        + "hSize= %,d (0x%1$x)%n".formatted(hSize)
        + "width= %,d%n".formatted(width)
        + "height= %,d%n".formatted(height)
        + "planes= %,d%n".formatted(planes)
        + "bpp= %,d%n".formatted(bpp)
        + "compression= %d%n".formatted(compression)
        + "sizeB= %,d%n".formatted(sizeB)
        + "h_ppm= %d%n".formatted(h_ppm)
        + "v_ppm= %d%n".formatted(v_ppm)
        + "colors= %d%n".formatted(colors)
        + "important= %d%n".formatted(important);
    System.out.println(string);
}

输出

b= 54 (0x36), [66, 77, 54, 4, -31, 0, 0, 0, 0, 0, 54, 4, 0, 0, 40, 0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, -31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
id= 'BM', [66, 77]
size= 14,746,678
reserved1= [0, 0]
reserved2= [0, 0]
offset= 1,078 (0x436)
hSize= 40 (0x28)
width= 3,840
height= 3,840
planes= 1
bpp= 8
compression= 0
sizeB= 14,745,600
h_ppm= 0
v_ppm= 0
colors= 0
important= 0

另一种方法是使用按位和移位操作