Here is my solution to reading a ".BMP" file created by a Raspberry Pi camera.
Code: Select all
(rc err rgb)←Read_BI_RGB fname;tie;bits;len;type;size;unused;start;headersize;width;height;planes;bpp;comp;isize;hres;vres;ncols;ignore;bytes;padded_len;unpadded_len;padding;vec;item;rgb;shape;mat
⍝ Reads pixel data from a Device-independent bitmap file in BI_RGB form.
⍝ rc ←→ Return code 0=OK 1=Error
⍝ err ←→'OK' or error text
⍝ rgb ←→ 3D array of pixel colours or ⍬ if error
⍝ Return pixel data from a Device-independent bitmaps(DIB) with ".BMP" bitmap file (of Windows "BITMAPINFOHEADER" type BI_RGB)
⍝ BI_RGB: The bitmap is in uncompressed red green blue (RGB) format that is not compressed and does not use color masks.
⍝ See https://en.wikipedia.org/wiki/BMP_file_format
⍝ For compatibility reasons, most applications use the older DIB headers for saving files.
⍝ With OS/2 no longer supported after Windows 2000, the most common format i use now has the BITMAPINFOHEADER header.
⍝ NOTE This is also the format used in Raspberry Pi Camera images when ".BMP" file is requested.
⍝ NOTE All values are to be stored as unsigned integers except where noted (such as width and height)
⍝ The pixels are returned as a 3 dimensional matrix
⍝ with the 3 colour planes (Red Green Blue) in the 1st dimension
⍝ and the other two dimensions being the rows and columns of the origional image
⍝ This allows easy processing by colour EG rgb[1;;] ⍝ Just the RED image
rc←1 ⍝ default for error
rgb←⍬ ⍝ default for error
⍝ Get the bits from the file as a boolean vector
tie←fname ⎕NTIE 0
bits←⎕NREAD tie 11 ¯1 0 ⍝ Read the whole file as a bit string
⎕NUNTIE tie
⍝ Process the bitmap header to check it is in the expected format
⍝ Bitmap type as 2 character: BM. BA, CI, CP, IC, or PT
len←16 ⍝ 2 bytes/characters
type←80 ⎕DR len↑bits ⍝ Convert first 16 bits into 2 characters
bits←len↓bits ⍝ drop the data already used
:If 'BM'≢type ⍝ Check if the expected type
err←'Not a Windows ".BMP" type bitmap'
:Return
:End
⍝ Size of the BMP file including header, pallet, bitmap data etc
len←32 ⍝ 4 bytes
size←323 ⎕DR len↑bits ⍝ size data NOT USED HERE
bits←len↓bits
⍝ 4 (Application specific) unused bytes
len←32 ⍝ 4 bytes
unused←323 ⎕DR len↑bits ⍝ this data NOT USED HERE
bits←len↓bits
⍝ Staring point of bitmap pixels in the data
len←32 ⍝ 4 bytes
start←323 ⎕DR len↑bits ⍝ 54 expected (14 for bitmap header, 40 for DID header)
bits←len↓bits
⍝ DIB header (bitmap information header)
len←32 ⍝ 4 bytes
headersize←323 ⎕DR len↑bits ⍝ Size of the DIB header
bits←len↓bits
:If headersize≠40 ⍝ DIB header is expected to take up 40 bytes
err←'Not a "BITMAPINFOHEADER"'
:Return
:End
⍝ We appear to have read a windows "BITMAPINFOHEADER" BI_RGB file
⍝ Next item in the header is the bitmap width (columns) in pixels (signed integer)
len←32 ⍝ 4 bytes
width←323 ⎕DR len↑bits
bits←len↓bits
⍝ the bitmap height (rows) in pixels (signed integer)
len←32 ⍝ 4 bytes
height←323 ⎕DR len↑bits ⍝ NOTE a negative value implies an inverted image (top to bottom)
bits←len↓bits
⍝ the number of color planes (must be 1)
len←16 ⍝ 2 bytes
planes←163 ⎕DR len↑bits ⍝ NOT USED HERE
bits←len↓bits
⍝ the number of bits per pixel, (24) which is the color depth of the image. Typical values are 1, 4, 8, 16, 24 and 32.
len←16 ⍝ 2 bytes
bpp←163 ⎕DR len↑bits
bits←len↓bits
:If bpp≠24
err←'Unexpected colour depth'
:Return
:End
⍝ the compression method being used. 0=BI_RGB (Most Common) means NO COMPRESSION
len←32 ⍝ 4 bytes
comp←323 ⎕DR len↑bits
bits←len↓bits
:If comp≠0 ⍝ Expected to be 0
err←'Compressed bitmat'
:Return
:End
⍝ The next block of the header can be ignored.
⍝ the image size. This is the size of the raw bitmap data; a dummy 0 can be given for BI_RGB bitmaps.
len←32 ⍝ 4 bytes
isize←323 ⎕DR len↑bits ⍝ NOT USED HERE
bits←len↓bits
⍝ the horizontal resolution of the image. (pixel per meter, signed integer)
len←32 ⍝ 4 bytes
hres←323 ⎕DR len↑bits ⍝ NOT USED HERE
bits←len↓bits
⍝ the vertical resolution of the image. (pixel per meter, signed integer)
len←32 ⍝ 4 bytes
vres←323 ⎕DR len↑bits ⍝ NOT USED HERE
bits←len↓bits
⍝ the number of colors in the color palette, or 0 to default to 2n
len←32 ⍝ 4 bytes
ncols←323 ⎕DR len↑bits ⍝ NOT USED HERE
bits←len↓bits
⍝ the number of important colors used, or 0 when every color is important; generally ignored
len←32 ⍝ 4 bytes
ignore←323 ⎕DR len↑bits ⍝ NOT USED HERE
bits←len↓bits
⍝ Pixels
⍝ The 24-bit pixel (24 bpp) format supports 16,777,216 distinct colors
⍝ and stores 1 pixel value per 3 bytes.
⍝ Each pixel value defines the red, green and blue samples of the pixel.
⍝ Specifically, in the order: Blue, Green and Red (8 bits per each sample).
⍝ Convert bit vector into 8 bit unsigned integer vector. 83 ⎕DR would produced 8 bit signed values.
bytes←⎕UCS 80 ⎕DR bits ⍝ blue green red unsigned 8 bit values 0-255
⍝ Check for padded rows (All rows must be a multiple of 4 bytes)
padded_len←(⍴bytes)÷height ⍝ bytes in each row as supplied with any padding
unpadded_len←width×3 ⍝ bytes in each row without trailing padding
padding←padded_len-unpadded_len ⍝ number of padding bytes at end of each row
:If padding≠0 ⍝ Need to remove padding bytes
bytes←,(height,unpadded_len)↑(height,padded_len)⍴bytes
:End
⍝ convert byte vector into a 2D array with 3 columns
mat←⌽(((⍴bytes)÷3),3)⍴bytes ⍝ one row per pixel each with a columns for each colour in RGB order
⍝ convert into a 3D array with the most useful orientation for colour manipulation
rgb←3 2 1⍉(height,width,3)⍴mat ⍝ colours by rows by columns
rc←0
err←'OK'
⍝⍝⍝ commented out code to cross-check against CBits property read via ⎕WC
⍝⍝ vec←256⊥⍉mat ⍝ vector of RGB 24bit pixels
⍝⍝ CBits←⊖(height,width)⍴vec ⍝ matches dyalog CBits property of a Bitmap
⍝⍝ 'item'⎕WC'Bitmap'('File'fname)
⍝⍝ :If CBits≢item.CBits
⍝⍝ rc←1
⍝⍝ err←'Problem CBits cross-check failed'
⍝⍝ rgb←⍬
⍝⍝ :End
I used the commented out code at the end to confirm that the function could return the same data as available in the CBits property when tested under Windows.
However, I have returned the pixel array as a "number of colours" by "number of rows", by "number of columns" byte array, which (I expect) will make further processing easier