How to read bmp file header in python?
Asked Answered
F

2

2

I need to read the header of a bmp file with python. I tried like this but it obviously returns just a bunch of non intelligible bytes:

f = open(input_filename,"rb")
data = bytearray(f.read())
f.close()
print(data[:14])

My idea was to find a module, or something fast, in order to log image info while opening it. I know about this function in matlab that does exactly what i want: imfinfo(). But I can't find a counterpart in python.

To be clear, this is what I get with matlab:

       FileModDate: '20-Oct-2017 09:42:24'
          FileSize: 1311798
            Format: 'bmp'
     FormatVersion: 'Version 3 (Microsoft Windows 3.x)'
             Width: 1280
            Height: 1024
          BitDepth: 8
         ColorType: 'indexed'
   FormatSignature: 'BM'
NumColormapEntries: 256
          Colormap: [256x3 double]
           RedMask: []
         GreenMask: []
          BlueMask: []
   ImageDataOffset: 1078
  BitmapHeaderSize: 40
         NumPlanes: 1
   CompressionType: 'none'
        BitmapSize: 1310720
    HorzResolution: 0
    VertResolution: 0
     NumColorsUsed: 256
NumImportantColors: 0
Fineable answered 29/10, 2017 at 18:37 Comment(3)
Did you try PIL's Image.info? effbot.org/imagingbook/image.htm#tag-Image.Image.infoNunnery
with PIL this is what I get {'dpi': (0, 0), 'compression': 0}Fineable
I think that you should look at the struct module. docs.python.org/3/library/struct.html#module-structTellurize
H
12

You can use the imghdr module (which is in the python stdlib):

>>> import imghdr
>>> print(imghdr.what(input_filename))
bmp

This will extract the image type from the header, but that is all. There is nothing else in the Python standard library that can get more detailed information - you need a third-party library to do such a specialized task. To get an idea of the complexity of this, take at look at BMP file format. Based on the specification outlined there, it might be feasible to write some pure Python code to extract a few items of information, but it won't be easy to get it right for an arbitrary bitmap image file.

UPDATE:

Below is a simple script to extract some basic information from a bitmap header using the struct module. See the BMP file format mentioned above for how to interpret the various values, and note that this script will only work with the most common version of the format (i.e. Windows BITMAPINFOHEADER):

import struct

bmp = open(fn, 'rb')
print('Type:', bmp.read(2).decode())
print('Size: %s' % struct.unpack('I', bmp.read(4)))
print('Reserved 1: %s' % struct.unpack('H', bmp.read(2)))
print('Reserved 2: %s' % struct.unpack('H', bmp.read(2)))
print('Offset: %s' % struct.unpack('I', bmp.read(4)))

print('DIB Header Size: %s' % struct.unpack('I', bmp.read(4)))
print('Width: %s' % struct.unpack('I', bmp.read(4)))
print('Height: %s' % struct.unpack('I', bmp.read(4)))
print('Colour Planes: %s' % struct.unpack('H', bmp.read(2)))
print('Bits per Pixel: %s' % struct.unpack('H', bmp.read(2)))
print('Compression Method: %s' % struct.unpack('I', bmp.read(4)))
print('Raw Image Size: %s' % struct.unpack('I', bmp.read(4)))
print('Horizontal Resolution: %s' % struct.unpack('I', bmp.read(4)))
print('Vertical Resolution: %s' % struct.unpack('I', bmp.read(4)))
print('Number of Colours: %s' % struct.unpack('I', bmp.read(4)))
print('Important Colours: %s' % struct.unpack('I', bmp.read(4)))

output:

Type: BM
Size: 287518
Reserved 1: 0
Reserved 2: 0
Offset: 1078
DIB Header Size: 40
Width: 657
Height: 434
Colour Planes: 1
Bits per Pixel: 8
Compression Method: 0
Raw Image Size: 286440
Horizontal Resolution: 11811
Vertical Resolution: 11811
Number of Colours: 256
Important Colours: 0        
Horologist answered 29/10, 2017 at 18:45 Comment(7)
This just returns the image extension. I'm looking for the file headerFineable
@RobiNoob. It's not just returning the extension, it's determining the type of the image from the header. But anyway, what specific information do you actually need?Horologist
@RobiNoob. Yes, I know - but what specific information do you really, actually need? If you want what matlab gives you, then just use that. If you want something quicker, you might have to settle for less.Horologist
I'm translating a script from matlab to python so I cannot use matlab ahah. Anyway I would like to retrieve the information I cannot access just loading the image. For example I can do img.shape or img.size to get information about the pixels but I don't know how to get the format version for exampleFineable
@RobiNoob. Bitmap headers can contain quite a lot of info, with some of it being application-specific. Can you please give a precise list of the specific items you need? If you limit it to only what you really need, it might be feasible to write a one-off solution in pure python.Horologist
I don't need any information actually but since I'm working with astronomical data it's good to have as much information as I can. Why is the header there if we cannot read it?Fineable
@RobiNoob. I have updated my answer with a simple script that extracts some basic header information.Horologist
P
2

Here is a shorter example how to extract the whole bmp header information using struct module.

import struct

with open(file_name, "rb") as f:
     file_data = f.read()

header_data = struct.unpack('<2sIHHIIIIHHIIIIII', file_data[:54])

print(header_data)

Output:

(b'BM', 690, 0, 0, 150, 124, 15, 9, 1, 32, 3, 0, 3780, 3780, 0, 0)

If you don't want to save the whole header data, but to get only one value from it you can use the unpack_from() function, which can be used to get data at specific offset.

Here is an example:

import struct

with open(file_name, "rb") as f:
     file_data = f.read()

image_width = struct.unpack_from('<i', file_data, 18)[0]
image_height = struct.unpack_from('<i', file_data, 22)[0]

print(image_width, image_height)
Parachronism answered 26/6, 2021 at 11:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.