1. Technology
Write your own 24 bit BMP
Did you ever dream of writing your own bitmap image? A 24 bit Bitmap file is relatevely simple to write. We should have an understading of BMP's header and should know how to write the data part. This article shows how.
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• GDI graphics in Delphi
• Handling images using Delphi
• Graphics programming

Article submitted by Thaha Hussain for the Delphi Programming Quickies Contest.

What is a header?
Let's learn the header of BMP. A header is a place where the picture's basic information is stored. For example, colors used, width of the picture, height of the picture etc. The following is the header structure of a standard 24 bit BMP file.

bfType1 : Byte ; (* "B" *)
bfType2 : Byte ; (* "M" *)
bfSize : LongInt ; (* Size of File. Zero is acceptable *)
bfReserved1 : Word ; (* Zero *)
bfReserved2 : Word ; (* Zero *)
bfOffBits : LongInt ; (* Offset to beginning of BitMap *)
biSize : LongInt ; (* Number of Bytes in Structure *)
biWidth : LongInt ; (* Width of BitMap in Pixels *)
biHeight : LongInt ; (* Height of BitMap in Pixels *)
biPlanes : Word ; (* Planes in target device = 1 *)
biBitCount : Word ; (* Bits per Pixel 1, 4, 8, or 24 *)
biCompression : LongInt ; (* BI_RGB = 0, BI_RLE8, BI_RLE4 *)
biSizeImage : LongInt ; (* Size of Image Part (often ignored) *)
biXPelsPerMeter : LongInt ; (* Always Zero *)
biYPelsPerMeter : LongInt ; (* Always Zero *)
biClrUsed : LongInt ; (* Number of Colors used in Palette *)
biClrImportant : LongInt ; (* Number of Colors that are Important *)

In a 24 bit BMP, the header is immediately followed by the picture's data.

The art of writing a binary file
Usually the basic unit of a binary file is byte. The data type, 'word' (please see the header) needs 2 bytes to store and LongInt needs 4 bytes. So the above header needs a total of 54 bytes storage space.

We can now write files byte-wise. But using a structure is very easy and standard practice in writing these type of files.

Few elementary things regarding the binary file
The picture below is the screen-shot of a BMP opened in a Hex Editor. Hex Editor is a tool for viewing any file in its elementary form. There are two panes. On the left side, there is numbers in Hex and in right, its equivalent ASCII. The ASCII character 'B' is the equivalent of the Hex number 42 (Number 66 in our normal decimal system and is not seen in Hex Editor). The bytes which cannot be represented in ASCII is shown as a dot (.) in the right pane. One who dosen't know how to convert Hex to decimal (though it is simple) can use the Windows calculator in Scientific mode.

The portion selected represents the header of the BMP (54 Bytes). The remainig bytes are used for keeping the picture's data.

Important: Long Integer (4 bytes) is represented in a Hex file from Right to Left (As Arabic is written). For example, the Hex representation of Long Intger (0A) (00) (00) (00) is actually (00) (00) (00) (0A).

In the above example, width and height of the HelloWorld.BMP is both 10 pixels. 10 in decimal is (0A) or (00) (00) (00) (0A) in Hexadecimal. As we all know, the zeroes in the left side will not alter the value of a number! And in a hex Editor it is seen in reverse!

The reverse rule and zero padding is applicable for data type 'word' also (2 bytes). Zeroes are padded to maintain the size of the data type.

By now, we undestood the secret of Hex editing.

The Data Part
The data of a BMP is stored as Pixels(Picture Elements). A Pixel is a combination of 3 bytes.1 byte for Blue, 1 byte for Green and 1 byte for Red. The maximum value for each is 'FF' in Hex (255 in Decimal).

Pure Red is Blue - 00, Green - 00 and Red in FF. In other words, (00) (00) (FF) will represent a red pixel. In our demonstration we are writing a pale magenta BMP. So, it would be, (FF) (CC) (FF). The first FF for Blue, CC for Green and the last FF for Red.

Few things to remember
1) Unfortunately, BMP data is not written from left to right -> left to right etc (like we read a book), insted it is written from right to left -> right to left etc from Bottom to Top. That means writing of pixel data starts from Bottom Right and ends in Top Left. In our example the problem will not reflect, since all the 100 (10 x 10) pixels are same pale magenta!

2) The number of bytes of the Picture Data in one each row should be a multiple of 4. We have to padd extra zeroes to kame it a multiple of 4. In our case, the picture's width is 10 pixels. So find the remainder of the division 10 / 4. The remainder is 2. So TWO zero bytes should be padded with each row's data.

The following is the program source you can use to test your own bitmap image format. Place a TButton on the Form and paste the code below...


//---------------------------------------------------------------------
//                 Write your own  24 Bit BMP
//           (C) K.O. Thaha Hussain MCA, 2003 Sept
//          I used Hexadecimal Numbers just for Style
//            Hex editors make use of that system.
//   (Example $28 in Hex is Equal to 40 in decimal system. You can make use
//              either hex or Decimal system
// --------------------------------------------------------------------


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, 
  Controls, Forms, Dialogs, StdCtrls, Buttons;


Type
 TBmpHeader = Packed Record
  bfType1         : Byte;
  bfType2         : Byte;
  bfSize          : LongInt;
  bfReserved1     : Word;
  bfReserved2     : Word;
  bfOffBits       : LongInt;
  biSize          : LongInt;
  biWidth         : LongInt;
  biHeight        : LongInt;
  biPlanes        : Word;
  biBitCount      : Word;
  biCompression   : LongInt;
  biSizeImage     : LongInt;
  biXPelsPerMeter : LongInt;
  biYPelsPerMeter : LongInt;
  biClrUsed       : LongInt;
  biClrImportant  : LongInt;
 End ;

   // Each pixel is a combination of Blue, Green and Red Values
   // In other words, A pixel is uniquely represented by 3 bytes
   // Maximum Value of any of them is $FF (255 in Decimal)
   TRGB = Record
         rgbBlue : BYTE;  //intensity of blue in the color
         rgbGreen: BYTE;  //intensity of green in the color
         rgbRed  : BYTE;  //intensity of red in the color
   End;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}


procedure TForm1.Button1Click(Sender: TObject);
 Var
  MyBitmapHeader : TBmpHeader;
  MyRGB : TRGBQUAD;
  MyFile : File;
  MyBuffer : Byte ;

  i, j : Integer;
begin
  With MyBitmapHeader do
  Begin
    bfType1         :=  $42;  
    bfType2         :=  $4D;  
    bfSize          :=  $00000000;
    bfReserved1     :=  $0000;
    bfReserved2     :=  $0000;
    bfOffBits       :=  $36; 
    biSize          :=  $28;
    biWidth         :=  $0000000A;
    biHeight        :=  $0000000A;
    biPlanes        :=  $0001;
    biBitCount      :=  $0018;
    biCompression   :=  $00000000;
    biSizeImage     :=  $00000000;
    biXPelsPerMeter :=  $00000000;
    biYPelsPerMeter :=  $00000000;
    biClrUsed       :=  $00000000;
    biClrImportant  :=  $00000000;
  end;

  //Open output file
  AssignFile(MyFile, 'C:\HelloWorld.BMP');
  Rewrite(MyFile,1);

  //Finish writing the Header
  BlockWrite (MyFile, MyBitmapHeader, SizeOf(TBmpHeader)); 


  //Now starts the data part

  MyRGB.rgbBlue :=$FF;
  MyRGB.rgbGreen  := $cc;
  MyRGB.rgbRed := $FF;

  //  This will be a pale magenta color 
  //  For Bright Red:-   Blue = $00, Green =$00 and Red= $FF 


  for i:= 1 to 10 do
  begin
     for j:= 1 to 10 do
     begin
         BlockWrite(MyFile, MyRGB, 3); //Block size is 3 bytes
     end;
    //Two Zeroes should be padded  
    //to make each row a multiple of 4
    // ie,  10 mod 4  = 2 (zeroes should be 
    //padded two times)
    MyBuffer := $00;
    BlockWrite(MyFile, MyBuffer, 1);
    MyBuffer := $00;
    BlockWrite(MyFile, MyBuffer, 1);
 end;

  CloseFile(MyFile);
  ShowMessage ('BMP file is successfully written!');
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  Caption:= 'Thaha Hussain''s 24 bit BMP creation demonstration';
  Button1.Caption:= 'Write my BMP';
end;

end.

©2014 About.com. All rights reserved.