reading BMP header in Java

94 Views Asked by At

I want to read the header of a BMP image so that when a person writes the path of an image bmp, it displays:

  • the File size in bytes
  • the Width in pixels
  • the Height in pixels

I'm working on Java and the teacher suggested to use FileInputStream and FileOutputStream.

1

There are 1 best solutions below

0
Reilas On

"... I want to read the header of a BMP image ..."

Here is the Wikipedia article on the Bitmap image format, specifically the file header section.
Wikipedia – BMP file format – Bitmap file header.

The byte offsets for width and height are 18 and 22.

"... the teacher suggested to use FileInputStream and FileOutputStream"

You can use the InputStream#readNBytes method to obtain the first n bytes of data.  In this case, n + 4 since the last field is 4 bytes.

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

"... when a person writes the path of an image bmp, it displays:

  • the File size in bytes
  • the Width in pixels
  • the Height in pixels

..."

You could utilize the ByteBuffer class to convert the numeric values.

I am using the following NASA bitmap image.
NASA – SVS – Index of Frames Files for 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);
}

Output

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

Another approach is to use bit-wise and shift operations.