.BMP FILE FORMAT (UN-LAMED) BY YSS   (Text version - Right click to download)


.BMP FILE FORMAT (UN-LAMED) BY YSS
----------------------------------
This reference text is all copyright material, but this internet version
can be distributed freely to anyone.  All material has been tested.
Compressed .BMPs not discussed.  All values are 'hex' unless not obvious.
Any incomplete understanding of an offset description, see comments below.



OFFS.  BYTES
ADDR.  USED  
 ^     ^
0000   2     42 4D -> ASCII 'BM'= .BMP ID
0002   4     File size (4 Byte LO-HI)
0006   4     Reserved.  Set to 0
000A   4     Offset to where actual bitmap starts
000E   4     Offset from here to RGB index tbl (should be 40 decimal always??)
0012   4     This bitmap's Pixel width (must be rounded to 4 byte boundary)
0016   4      ''    ''      ''   height
001A   2     # of planes.  Always set to 1.
001C   2     # of bits/pixel.  Values: 1,4,8,16,24 decimal ONLY?? (see 0036)
001E   2     Compression.  0=not cpx'd.  1=256 color cpx'd.  2=16 color cpx'd
0022   4     Byte size of bitmap image
0026   4     Horizontal resolution (pixels/meter)
002A   4     Vertical     ''          ''    ''
002E   4     # of 4 byte entries in RGB index tbl. 0=max # of entries used
0032   4     # of important colors in index tbl.  0=all colors important
0036   ??    RGB index color tbl stored as 4 bytes blu-grn-red-0.
             Stored in order of importance.  Most important colors first.
             If # of bits/pixel = 24 -> $ tbl doesn't exist and bitmap
             immediately follows, starting at this 0036. (001C=bits/pixel).
             The # of 4 byte indexes is in [002E], unless [002E]=0, in which
             case there will be the maximum # of colors allowed by 001C.
             Bitmap follows immediately after this tbl.  Offset start found at
             [000A] (see above). Lenght in [0022].  So..
             
[000A] [22]  Start of bitmap.
  .          Bitmap stored in scan lines, from left to right, starting from
  .          bottom, going upwards.
  .


(NOTE FOR BEGINNERS:  Note how there are three columns in the memory map
 list.  The first column is named 'OFFS. ADDR.' and it has a bunch of
 hexadecimal numbers below it.  The second column is named 'BYTES USED' and
 has some numbers as well.  Here are the meanings:

 'OFFS. ADDR.' means "offset address" and that column is an offset (a number
 to be added) to the address in memory of the bitmap itself, if you load it
 someway into memory from a file.  What that means is that offset 0000 is the
 very first byte of the file.  Offset 0002 is the THIRD byte of the file, and
 so on..

 'BYTES USED' is the number of bytes one has to read starting at that very
 offset (in lo-hi format) in order to get an actual useful value for that
 entry.  Hang in there, you'll figure it out in time.)




COMMENTS
--------

This .BMP format description is not a thorough study of the .BMP format, since
that wasn't intended.  It's merely a translation into a real programmer's
logical understanding of whatever those microsoft "brains" tried to say in the
"official documentation" on the format itself.  Take a look at it yourself
and you'll know exactly what we mean.
Ah the process of thought...                                                                 


Here's an estimate on the offset values' meanings according to observations.
Some of the estimates were observed directly from .BMP files, while others
from the "translation" itself.  No guarantees can be made since this format
isn't our stuff:




0006 (RESERVED) can be ignored.  Absolute waste of space.


000E (Offset from here to RGB index tbl) may be ignored, since it seems to be
      40 decimal always, -> 28 00 00 00
            ** this value seems to hold true, and as far as our study went it
               did, but watch out for it.  If you'll be writing serious
               graphics viewers, plan on using it.




0012 (Pixel width) = number of pixels on a scan line of this bitmap.

     The actual value to be used has to be calculated to the nearest next 4
     byte boundary, because one scan line won't immediately follow the other
     within the file. This is reasonable, since a variety of pixel packing
     formats were needed.  Example:

               If value in [0012] = 2962 decimal, ->
               value to use in my read routine = 2964.  Why? ->
               2962/4 = 740.5, and 740*4 = 2960, which is 2 bytes behind,
               and we need the NEXT nearest byte boundary.  Therefore,
               add 4 to result of 740*4, -> 2964.
               One 8086 machine language approach can be:

               XOR BH,BH
               MOV AX,0B92   ->2962 decimal
               SHR AX,1
               RCL BH,1  (OR RCR)
               SHR AX,1
               RCL BH,1
               SHL AX,1
               SHL AX,1
               TEST BH,BH
               JE A:
               ADD AX,0004
            A:              

               At this point, AX has the usable pixel width value.
               (Note how there's no instruction/parameter indenting
               and how it's all CAPITALS. See XMPL0012.COM)




0016 (Pixel height)= number of scan lines in this bitmap.
                  
001A (# of planes) can be ignored.  Always 1, -> 01 00 00 00  (That's what
                   the official document says anyway)


001C (# of bits/pixel): For the possible values  1,4,8,16,24 :

              1 = 2   colors, foreground/b'ground -> 01 00
              4 = 16    ''                        -> 04 00
              8 = 256   ''    (2^8)               -> 08 00
             16 = 65536 ''                        -> 10 00
          if 24 -> no RGB index tbl used.         -> 18 00

      What a great idea, to use TWO BYTES to store either a 1, a 4, an 8,
      a 16 or a 24 ONLY!!  Brilliant!
      


001E  (Compression)  is 0 if the bitmap isn't compressed, -> 00 00.
                     1 = RLE8 -> 01 00
                     2 = RLE4 -> 02 00

      They have 2 compression methods, which they call RLE8 and RLE4.  Don't
      let the fancy letters fool you.  They're pretty simple.
      These compression formats won't be discussed here.




0022  (Byte size of bitmap image):

      If a bitmap image is 70 pixels wide by 40 pixels high, ->
      it occupies 70*40 pixels -> 2800 pixels.
      If it's a 4 bits/pixel image, that is, a 16 color image (2^4),
      -> it only occupies half the bytes, since 2 pixels will be fitted
      on a single byte.  Therefore, a 1400 would be stored in this offset,
      so 1400 decimal goes as ->  78 05.
      If pixels are 8 bits long -> for the same image of 70x40 pixels,
      2800 bytes are used, so the value 2800 decimal goes here (F0 0A).


0026 and 002A (Horizontal and vertical resolution in pixels/meter,
     respectively) can be ignored, unless one's doing professional scientific
     graphics, in which case one wouldn't be using this ridiculous format
     anyway.


0032  (# of important colors in index tbl)
      Important colors are those that have the highest precedence on the
      bitmap, in a manner that by lacking the other not-so important colors
      the bitmap may still be dithered to display an acceptable image.
      No comments.



0036  (Actual RGB index tbl):

      RGB index tbl has the values to be loaded into VGA's palette regs to
      get the right mixes stored blu-green-red, and a 0.  Ex:
                for RGB values  R=141 G=12 B=58, an index entry would be
                                                 3A 0C 8D 00

      For 256 color values -which is what we tested upon- the bytes, being
      supposed to have values to be written directly into the DAC's color
      registers needed to be divided by 64 decimal before being actually
      output to the registers to get useful results.  This is an increased
      level of precision for color values, but they never mentioned the fact
      in any of the format descriptions we read.  That's the kind of stuff
      you just have to guess.
            
      The pixel values in the bitmap will be actual indexes into this RGB
      table, of course (VGA programmers know this).

      ** If there are 24 bits/pixel, that is, if offset 001C has a value of
         18 00 (24 decimal) -> this offset (0036) will be the actual start
         of the bitmap itself.


      ** If RGB index tbl exists, ->
         it will have a byte size of 4 times the value in offset 002E,
         unless the value in 002E is 0.
         If the value in 002E is 0 -> there will be a maximum # of entries
         according to the value in 001C:

         001C = 1 ->     2 RGB entries (8 bytes, since each entry is 4 bytes)
              = 4 ->    16  ''    ''   (64 bytes)
              = 8 ->   256  ''    ''   (1024 bytes)
              =16 -> 65536
              and of course, if = 24 -> RGB index tbl non-existent, so
              bitmap follows immediately at this same offset 0036.



        Same thing put another way:

        If RGB index tbl exists (that is, [001C] <> 24 decimal), ->
        len of RGB index tbl = [002E]*4, unless [002E]=0, in which case,
         ''     ''   ''   '' = 2^[001C]*4
                                                                 



About the start of the actual bitmap:
------------------------------------

003E = start of bitmap in case of a 24 bits/pixel bitmap

** The actual bitmap follows the RGB index tbl, if any.  If there's no such
   table, which is the case ONLY in case of 24 bits/pixel, then the start
   is offset 003E.


000A appears to have the start of the actual bitmap in any case, so it can be
     looked up to see where the bitmap will start.  It's byte length is in
     offset 0022 which can be seen as redundant, since nothing else follows
     the bitmap.  The length could be easily calculated from
                                          len = file length - bitmap start.

     Bottom line on .BMP: "Redundancy, repetition, logic..??
     Buy, reproduce, obey.. WASTE".  Dilbert comics are SO right.


Otherwise it's a "viable" graphics storage format :) .

Yss1989-,sdD+J.
pixelrat@hotmail.com