Date: 02-16-2022
Return to Index
created by gbSnippets
'A bitmap file has a well-defined structure, consisting of the following sections:
'1. File Header 'BITMAPFILEHEADER data structure
'2. Info Header 'BITMAPINFOHEADER data structure
'3. Palette Table 'Bytes
'4. Color Data 'Bytes
'In the case of a 24bit or 32bit bitmap, the palette is not required and
'is not included in the bitmap file.
'This snippet, and all of the other "BMP Tutor" snippets provided
'with gbSnippets deal only with 24bit and 32bit bitmaps.
'Bitmap File Classification
'Bitmap files are classified as DIBs - Device Independent Bitmaps - because
'they content all information required to recreate the image on any display
'device (as opposed to DDBs - device dependent bitmaps - whose Window data
'structures do not contain the bytes which define pixel colors).
'Working With Bitmap Files
'Reading/Editing/Saving bitmaps requires familiarity with the two header
'data structures, BITMAPFILEHEADER and BITMAPINFOHEADER. It also requires an
'understanding of the format used to store image color data in the file.
'A programmer can read a bitmap file using PowerBASIC Get statements,
'modify the headers or color data using conventional coding, and then
'write the headers and color data back to the file - all without the
'use of Windows API and without having to display the image.
'However, there is an entire family of API, called the GDI - Graphics
'Device Interface - which supports reading, editing, and writing bitmaps.
'The majority of GDI API focus on editing/manipulating bitmaps.
'Color Data Format
'The image color data in a bitmap file is not stored in top/left to
'bottom/right pixel progression. Instead, the image color data is
'is stored with the image upside down (top scanline of the image at
'the bottom of the stored image color data).
'Also, the color data is stored in BGR byte sequence (instead of RGB),
'and may contain (unused) bytes which align scanlines on 4 byte boundaries.
'These padding bytes may be required in 24bit bitmaps, depending on the
'number of pixels in each row. But with 32bit bitmaps, which use 4 bytes
'per pixel, no padding bytes are required because pixel data automatically
'aligns on 4 byte boundaries.
'Data Structures
'Here are the two header data structures, and their elements, that make up a
'bitmap file. Comments on each elements is provided.
Type BITMAPFILEHEADER
bfType AS WORD 'must be 'BM'
bfSize AS DWord 'size (bytes) of the *.bmp file (headers and color data)
bfReserved1 AS WORD 'not used
bfReserved2 AS WORD 'not used
bfOffBits AS DWord 'offset (color data starts at .bfOffBits + 1 within the file
End Type
Type BITMAPINFOHEADER
biSize As DWord 'size of this structure (40 bytes)
biWidth As Long 'image width - pixel width of image (does not include padding bytes)
biHeight As Long 'image height - pixel height of image
biPlanes As Word 'bit planes - always 1
biBitCount As Word 'resolution (24 or 32 bits per pixel for this tutorial)
biCompression As DWord 'compression method (%BI_RGB for uncompressed)
biSizeImage AS DWord '0 for %BI_RGB compression
biXPelsPerMeter As Long 'pixels per meter X of target device (typically not used)
biYPelsPerMeter As Long 'pixels per meter Y of target device (typically not used)
biClrUsed AS DWord 'no palette with 24/32bit bitmaps, so set to zero
biClrImportant AS DWord 'no palette with 24/32bit bitmaps, so set to zero
End Type
'These two data structures are used to begin a bitmap file, followed by the image
'color data as described in the next paragraph.
'Color Data (Bytes)
'The color data in a bitmap file (24/32bit) consists of one byte each for the red, green, and
'blue color components of each pixel. A 32bit bitmap uses an additional byte for handling
'transparency (referred to as the alpha channel).
'The color data is stored one row of bytes after another (rows are also called scanlines),
'starting with the bottom row of pixels from the image. This is called a top-down format
'and is commonly used in bitmap files.
'With 24/32bit images, there are 3 bytes used to define the color of each pixel. The
'bytes are stored in blue, green, and then red order - followed by the alpaha channel byte
'(32bit images only).
'Windows requires that the number of bytes in a scanline be evenly divisible by 4 (it is
'called 'aligned on a Long boundary'). Depending on the pixel width, a 24bit bitmap may not
'meet that requirement. In that case, the scanline must be padded with enough bytes to meet
'the requirement. For example, a scanline for a 6 pixel wide 24bit image would have 6x3=18
'bytes. It would need an additional 2 bytes to pad it to the next multiple of 4 bytes. 32bit
'bitmaps, with 4 bytes per pixel, are always aligned on Long boundaries, so no padding bytes
'are required. Additional details are provided in another BMP Tutor snippet.
'Color Data Arrays
'The image color data of a bitmap file is typically read into an array for easy access.
'The array must have the same number of bytes as the combined color data and padding
'bytes. When retreiving color data, single dimension or two dimensional arrays can be used,
'depending on the preference of the programmer.
'Here are two examples of arrays which might be used to store the image color data.
Dim Buffer(n) As Bytes 'contains image color data plus padding bytes
Dim Buffer(x,y) As Bytes 'contains image color data plus padding bytes
'Generally speaking, an array with two dimensions is easiest to work with since an x,y
'element is easier to associate with with a specific pixel in the image. Sizing of these
'arrays is covered further down this page, as well as in a separate snippet.
'For the case of the two-dimension array, here is sample code of two loops which are useful
'in moving through the color data. These loops assumed zero-based arrays are used. Note also
'that because bitmaps are upside down (last scanline is first in the array), these loops
'start with pixels in the bottom row of pixels.
'byte by byte B.G.R.B.G.R ....
For y = 0 to h-1 'each row
For x = 0 To w*3-1 '1 byte at a time, 1 pixel = 3 bytes, BGR byte order, ignores padding bytes
...
Next x
Next y
'3 bytes per loop BGR.BGR.BGR ...
For y = 0 to h-1 'each row
For x = 0 To w*3-4 Step 3 '3 bytes at a time, 1 pixel = 3 bytes, BGR byte order, ignores padding bytes)
...
Next x
Next y
'These loops are used in several of the other "BMP Tutor" snippets.
'When reading in the color data from a file into an array, it's also possible to read the
'image data directly into an array of type RGBTriple (24bit bitmaps) or RGBQUAd (32bit bitmaps).
'Some programmers prefer to work with data in this format.
Type RGBTRIPLE BYTE Type RGBQUAD
rgbtBlue As Byte rgbBlue As Byte
rgbtGreen As Byte rgbGreen As Byte
rgbtRed As Byte rgbRed As Byte
End Type rgbReserved As Byte
End Type
'To read image color data directly into these data structures requires that the scanlines
'use no padding bytes. For 32bit bitmaps, this is always the case. But for 24bit bitmaps
'a programmer must be ensure that the bitmap dimensions require no padding bytes.
'Note that in both data structures, a BGR element sequence is used instead of RGB.
'Sample Code
'Reading or writing a bitmap file consists primarily of just 3 GET or three PUT statements,
'corresponding to reading/writing the two bitmap header structures and the byte array
'of image color data.
'The two headers are very easy to create. Just declare a variable of each type like this:
Local bmpheader As BitmapFileHeader
Local bmpinfo As BitmapInfoHeader
'Then fill out each of the structure elements (see the descriptions provided earlier in
'this tutorial).
'Building the array containing the image color data requires a little more effort, plus
'there are several types of arrays which will work. But regardless of the array type, the
'buffer array must be created and sized to read in all of the color data and all of the padding
'bytes. Examples of this are given in other snippets, but here's the basic code involved.
'Create Buffer array to hold image color data
padding = (4 - (w*3) Mod 4) Mod 4 'w = pixel width
Dim Buffer(w*3+padding-1,h-1) As Byte 'pixel color array data (0-based array)
'Read Bitmap File
Open fSource For Binary as #1
Get #1, , bmpheader 'get BITMAPFILEHEADER
Get #1, , bmpinfo 'get BITMAPINFOHEADER
Get #1, , Buffer() 'read image data into structure start,length,variable
Close #1
'Write Bitmap File
Open fTarget For Binary as #1
Put #1,, bmpheader 'BITMAPFILEHEADER
Put #1,, bmpinfo 'BITMAPINFOHEADER
Put #1,, Buffer() 'image data (size is paddesize)
Close #1
'More detailed examples of the code needed to read/edit/write bitmap files are provided
'in other 'BMP Tutor" snippets.
'gbs_00512
'Date: 03-10-2012
http://www.garybeene.com/sw/gbsnippets.htm