home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / formats / msbmp / code / bmp_code.txt
Text File  |  1994-06-01  |  57KB  |  1,382 lines

  1. This file contains examples of Windows BMP and OS2 BMP header structures,
  2. how to read, write, display, decode, and encode a BMP file, and how
  3. to use all the functions in the BMP library.
  4.  
  5.  
  6. BMP Header File
  7.  
  8. BMP.H
  9.  
  10.  
  11. /****************************************************************************\
  12. **  Title:   BMP.H                                                          **
  13. **  Purpose: BMP Header file                                                **
  14. **  Version: 1.0                                                            **
  15. **  Date:    October 1991                                                   **
  16. **  Author:  James D. Murray, Anaheim, CA, USA                              **
  17. **                                                                          **
  18. **  This header file contains the structures for the three flavors of the   **
  19. **  BMP image file format (OS/2 1.x, WIndows 3.0, and OS/2 2.0).  Each BMP  **
  20. **  file will contain a BMPINFO header followed by either a PMINFPHEAD,     **
  21. **  WININFOHEAD, or PM2INFOHEAD header.  To simplify reading and writing    **
  22. **  BMP files the BMP file format structure defined in BMP.H contains       **
  23. **  structures for all three flavors of the BMP image file format.          **
  24. **                                                                          **
  25. **  Copyright (C) 1991 Graphics Software Labs.  All rights reserved.        **
  26. \****************************************************************************/
  27. #ifndef BMP_H
  28. #define BMP_H   1
  29.  
  30. #include "datatype.h"        /* Include the data type definitions */
  31.  
  32. #define COMPRESS_RGB        0L      /* No compression               */
  33. #define COMPRESS_RLE8       1L      /* 8 bits per pixel compression */
  34. #define COMPRESS_RLE4       2L      /* 4 bits per pixel compression */
  35. #define BMP_ID              0x4d42  /* BMP "magic" number           */
  36.  
  37. #define LSN(value)    ((value) & 0x0f)        /* Least-significant nibble */
  38. #define MSN(value)    (((value) & 0xf0) >> 4)    /* Most-significant nibble  */
  39.  
  40. /*
  41. **  BMP File Format Bitmap Header.
  42. */
  43. typedef struct _BmpInfo     /* Offset   Description                      */
  44. {
  45.     WORD   Type;            /*  00h     File Type Identifier             */
  46.     DWORD  FileSize;        /*  02h     Size of File                     */
  47.     WORD   Reserved1;       /*  06h     Reserved (should be 0)           */
  48.     WORD   Reserved2;       /*  08h     Reserved (should be 0)           */
  49.     DWORD  Offset;          /*  0Ah     Offset to bitmap data            */
  50. } BMPINFO;
  51.  
  52. /*
  53. **  Presentation Manager (OS/2 1.x) Information Header Format.
  54. */
  55. typedef struct _PmInfoHeader   /* Offset   Description                     */
  56. {
  57.     DWORD   Size;               /*  0Eh     Size of Remianing Header        */
  58.     WORD    Width;              /*  12h     Width of Bitmap in Pixels       */
  59.     WORD    Height;             /*  14h     Height of Bitmap in Pixels      */
  60.     WORD    Planes;             /*  16h     Number of Planes                */
  61.     WORD    BitCount;           /*  18h     Color Bits Per Pixel            */
  62. } PMINFOHEAD;
  63.  
  64. /*
  65. **  Windows 3.x Information Header Format.
  66. */
  67. typedef struct _WinInfoHeader   /* Offset  Description                      */
  68. {
  69.     DWORD  Size;                /*  0Eh    Size of Remianing Header         */
  70.     DWORD  Width;               /*  12h    Width of Bitmap in Pixels        */
  71.     DWORD  Height;              /*  16h    Height of Bitmap in Pixels       */
  72.     WORD   Planes;              /*  1Ah    Number of Planes                 */
  73.     WORD   BitCount;            /*  1Ch    Bits Per Pixel                   */
  74.     DWORD  Compression;         /*  1Eh    Compression Scheme (0=none)      */
  75.     DWORD  SizeImage;           /*  22h    Size of bitmap in bytes          */
  76.     DWORD  XPelsPerMeter;       /*  26h    Horz. Resolution in Pixels/Meter */
  77.     DWORD  YPelsPerMeter;       /*  2Ah    Vert. Resolution in Pixels/Meter */
  78.     DWORD  ClrUsed;             /*  2Eh    Number of Colors in Color Table  */
  79.     DWORD  ClrImportant;        /*  32h    Number of Important Colors       */
  80. } WININFOHEAD;
  81.  
  82. /*
  83. **  Presentation Manager (OS/2 2.0) Information Header Format.
  84. */
  85. typedef struct _Pm2InfoHeader   /* Offset  Description                      */
  86. {  
  87.     DWORD   Size;               /*  0Eh    Size of Info Header (always 64)  */
  88.     WORD    Width;              /*  12h    Width of Bitmap in Pixels        */
  89.     WORD    Height;             /*  14h    Height of Bitmap in Pixels       */
  90.     WORD    Planes;             /*  16h    Number of Planes                 */
  91.     WORD    BitCount;           /*  18h    Color Bits Per Pixel             */
  92.     DWORD   Compression;        /*  1Ah    Compression Scheme (0=none)      */
  93.     DWORD   SizeImage;          /*  1Eh    Size of bitmap in bytes          */
  94.     DWORD   XPelsPerMeter;      /*  22h    Horz. Resolution in Pixels/Meter */
  95.     DWORD   YPelsPerMeter;      /*  26h    Vert. Resolution in Pixels/Meter */
  96.     DWORD   ClrUsed;            /*  2Ah    Number of Colors in Color Table  */
  97.     DWORD   ClrImportant;       /*  2Eh    Number of Important Colors       */
  98.     WORD    Units;              /*  32h    Resolution Mesaurement Used      */
  99.     WORD    Reserved;           /*  34h    Reserved FIelds (always 0)       */
  100.     WORD    Recording;          /*  36h    Orientation of Bitmap            */
  101.     WORD    Rendering;          /*  38h    Halftone Algorithm Used on Image */
  102.     DWORD   Size1;              /*  3Ah    Halftone Algorithm Data          */
  103.     DWORD   Size2;              /*  3Eh    Halftone Algorithm Data          */
  104.     DWORD   ColorEncoding;      /*  42h    Color Table Format (always 0)    */
  105.     DWORD   Identifier;         /*  46h    Misc. Field for Application Use  */
  106. } PM2INFOHEAD;
  107.  
  108. /*
  109. **  Presentation Manager (OS/2) RGB Color Triple.
  110. */
  111. typedef struct _PmRgbTriple
  112. {
  113.     BYTE   rgbBlue;             /* Blue Intensity Value  */
  114.     BYTE   rgbGreen;            /* Green Intensity Value */
  115.     BYTE   rgbRed;              /* Red Intensity Value   */
  116. } PMRGBTRIPLE;
  117.  
  118. /*
  119. **  Windows 3.x RGB Color Quadruple.
  120. */
  121. typedef struct _WinRgbQuad
  122. {
  123.     BYTE   rgbBlue;             /* Blue Intensity Value   */
  124.     BYTE   rgbGreen;            /* Green Intensity Value  */
  125.     BYTE   rgbRed;              /* Red Intensity Value    */
  126.     BYTE   rgbReserved;         /* Reserved (should be 0) */
  127. } WINRGBQUAD;
  128.  
  129. /*
  130. **  OS/2 2.0 RGB Color Quadruple.
  131. */
  132. typedef struct _Pm2RgbQuad
  133. {
  134.     BYTE   rgbBlue;             /* Blue Intensity Value   */
  135.     BYTE   rgbGreen;            /* Green Intensity Value  */
  136.     BYTE   rgbRed;              /* Red Intensity Value    */
  137.     BYTE   rgbReserved;         /* Reserved (should be 0) */
  138. } PM2RGBQUAD;
  139.  
  140.  
  141. /*
  142. ** Composite structure of the BMP image file format.
  143. **
  144. ** This structure holds information for all three flavors of the BMP format.
  145. */
  146. typedef struct _BmpHeader
  147. {
  148.     BMPINFO      Header;        /* Bitmap Header                */
  149.     PMINFOHEAD   PmInfo;        /* OS/2 1.x Information Header  */
  150.     PMRGBTRIPLE *PmColorTable;  /* OS/2 1.x Color Table         */
  151.     WININFOHEAD  WinInfo;       /* Windows 3 Information Header */
  152.     WINRGBQUAD  *WinColorTable; /* Windows 3 Color Table        */
  153.     PM2INFOHEAD  Pm2Info;       /* OS/2 2.0 Information Header  */
  154.     PM2RGBQUAD  *Pm2ColorTable; /* OS/2 2.0 Color Table         */
  155. } BMPHEADER;
  156.  
  157. /*
  158. **  Function prototypes
  159. */
  160. SHORT ReadBmpHeader(BMPHEADER *, FILE *);
  161. VOID  WriteBmpHeader(BMPHEADER *, FILE *);
  162. SHORT BmpEncodeScanLine(BYTE *, WORD, WORD, DWORD, FILE *);
  163. SHORT BmpDecodeScanLine(BYTE *, WORD, WORD, DWORD, FILE *);
  164.  
  165. #endif /* BMP_H */
  166.  
  167.  
  168.  
  169. BMP Header Reader
  170.  
  171. BMPREAD.C
  172.  
  173.  
  174. The function reads the header(s) of a BMP file.  The data is stored in
  175. the appropriate areas of the header structure
  176. depending upon the flavor of the BMP file being read.
  177.  
  178.  
  179. /****************************************************************************\
  180. **  Title:        BMPREAD                                                   **
  181. **  Purpose:      Display the data in a BMP image file header.              **
  182. **  Version:      1.0                                                       **
  183. **  Date:         September 1991                                            **
  184. **  Author:       James D. Murray, Anaheim, CA, USA                         **
  185. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  186. **                                                                          **
  187. **  This module contains the following function:                            **
  188. **                                                                          **
  189. **      ReadBmpHeader - Read a BMP header from a FILE stream.               **
  190. **                                                                          **
  191. **  Copyright (C) 1991 James D. Murray.  All rights reserved.               **
  192. \****************************************************************************/
  193. #include <stdio.h>
  194. #include <stdlib.h>
  195. #include "endianio.h"
  196. #include "bmp.h"
  197.  
  198. /* External global variables */
  199. WORD (*GetWord)(FILE *);
  200. DWORD (*GetDword)(FILE *);
  201.  
  202. /*
  203. **  Read a Windows or PM BMP header.
  204. **
  205. **  This function reads the information from a FILE stream open
  206. **  to a BMP file and writes the information to a BMPHEADER structure.
  207. **
  208. **  Returns: Nothing.
  209. */
  210. SHORT
  211. ReadBmpHeader(BmpHead, FpBmp)
  212. BMPHEADER *BmpHead;     /* Pointer to BMP header structure  */
  213. FILE      *FpBmp;       /* BMP image file input FILE stream */
  214. {
  215.     register SHORT i;       /* Loop Counter */
  216.     DWORD InfoHeaderSize;   /* Size of the BMP information header in bytes */
  217.     WORD  NumColors;        /* Number of colors in color table */
  218.  
  219.     GetWord  = GetLittleWord;    /* Read using little-endian byte order */
  220.     GetDword = GetLittleDword;
  221.  
  222.     BmpHead->Header.Type      = GetWord(FpBmp);
  223.     BmpHead->Header.FileSize  = GetDword(FpBmp);
  224.     BmpHead->Header.Reserved1 = GetWord(FpBmp);
  225.     BmpHead->Header.Reserved2 = GetWord(FpBmp);
  226.     BmpHead->Header.Offset    = GetDword(FpBmp);
  227.  
  228.     InfoHeaderSize            = GetDword(FpBmp);
  229.  
  230.     /*
  231.     ** The type of information found in a BMP structure is indicated by
  232.     ** the Size (Information Headere Size) field with a non-zero value.
  233.     */
  234.     BmpHead->PmInfo.Size   = 0;
  235.     BmpHead->WinInfo.Size  = 0;
  236.     BmpHead->Pm2Info.Size  = 0;
  237.  
  238.     /*
  239.     ** The size if the information header indicates if the BMP file
  240.     ** originated on an MS Windows or OS/2 Presentation Manager system.
  241.     */
  242.     if (InfoHeaderSize == 12L)         /* OS/2 1.x */
  243.     {
  244.         BmpHead->PmInfo.Size     = InfoHeaderSize;
  245.         BmpHead->PmInfo.Width    = GetWord(FpBmp);
  246.         BmpHead->PmInfo.Height   = GetWord(FpBmp);
  247.         BmpHead->PmInfo.Planes   = GetWord(FpBmp);
  248.         BmpHead->PmInfo.BitCount = GetWord(FpBmp);
  249.  
  250.         if (BmpHead->PmInfo.BitCount != 24)
  251.         {
  252.             /* Determine number of entries in color table */
  253.             NumColors = (WORD) (1U << (BmpHead->PmInfo.Planes *
  254.               BmpHead->PmInfo.BitCount));
  255.  
  256.             /* Allocate memory for the color table entries */
  257.             if ((BmpHead->PmColorTable = (PMRGBTRIPLE *)
  258.                  calloc((size_t) NumColors, sizeof(PMRGBTRIPLE))) ==
  259.                  (PMRGBTRIPLE *) NULL)
  260.                 return(-1);
  261.  
  262.             /* Read in the color table one color triple at a time */
  263.             for (i = 0; i < NumColors; i++)
  264.             {
  265.                 BmpHead->PmColorTable[i].rgbBlue  = GetByte(FpBmp);
  266.                 BmpHead->PmColorTable[i].rgbGreen = GetByte(FpBmp);
  267.                 BmpHead->PmColorTable[i].rgbRed   = GetByte(FpBmp);
  268.             }
  269.         }
  270.     }
  271.     else                               /* Windows 3 */
  272.     if (InfoHeaderSize == 40L)
  273.     {                              
  274.         BmpHead->WinInfo.Size          = InfoHeaderSize;
  275.         BmpHead->WinInfo.Width         = GetDword(FpBmp);
  276.         BmpHead->WinInfo.Height        = GetDword(FpBmp);
  277.         BmpHead->WinInfo.Planes        = GetWord(FpBmp);
  278.         BmpHead->WinInfo.BitCount      = GetWord(FpBmp);
  279.         BmpHead->WinInfo.Compression   = GetDword(FpBmp);
  280.         BmpHead->WinInfo.SizeImage     = GetDword(FpBmp);
  281.         BmpHead->WinInfo.XPelsPerMeter = GetDword(FpBmp);
  282.         BmpHead->WinInfo.YPelsPerMeter = GetDword(FpBmp);
  283.         BmpHead->WinInfo.ClrUsed       = GetDword(FpBmp);
  284.         BmpHead->WinInfo.ClrImportant  = GetDword(FpBmp);
  285.  
  286.         /* Read in the color table (if any) */
  287.         if (BmpHead->WinInfo.BitCount != 24 || BmpHead->WinInfo.ClrUsed != 0)
  288.         {
  289.             /* Determine number of entries in color table */
  290.             if (BmpHead->WinInfo.ClrUsed)
  291.                 NumColors = BmpHead->WinInfo.ClrUsed;
  292.             else
  293.                 NumColors = (WORD) (1U << (BmpHead->WinInfo.Planes *
  294.                   BmpHead->WinInfo.BitCount));
  295.  
  296.             /* Allocate memory for the color table entries */
  297.             if ((BmpHead->WinColorTable = (WINRGBQUAD *)
  298.                  calloc((size_t) NumColors, sizeof(WINRGBQUAD))) ==
  299.                  (WINRGBQUAD *) NULL)
  300.                 return(-1);
  301.       
  302.             /* Read in the color table one color quad at a time */
  303.             for (i = 0; i < NumColors; i++)
  304.             {
  305.                 BmpHead->WinColorTable[i].rgbBlue     = GetByte(FpBmp);
  306.                 BmpHead->WinColorTable[i].rgbGreen    = GetByte(FpBmp);
  307.                 BmpHead->WinColorTable[i].rgbRed      = GetByte(FpBmp);
  308.                 BmpHead->WinColorTable[i].rgbReserved = GetByte(FpBmp);
  309.             }
  310.         }
  311.     }
  312.     else                               /* OS/2 2.0 */
  313.     if (InfoHeaderSize == 64L)
  314.     {                              
  315.         BmpHead->Pm2Info.Size          = InfoHeaderSize;
  316.         BmpHead->Pm2Info.Width         = GetDword(FpBmp);
  317.         BmpHead->Pm2Info.Height        = GetDword(FpBmp);
  318.         BmpHead->Pm2Info.Planes        = GetWord(FpBmp);
  319.         BmpHead->Pm2Info.BitCount      = GetWord(FpBmp);
  320.         BmpHead->Pm2Info.Compression   = GetDword(FpBmp);
  321.         BmpHead->Pm2Info.SizeImage     = GetDword(FpBmp);
  322.         BmpHead->Pm2Info.XPelsPerMeter = GetDword(FpBmp);
  323.         BmpHead->Pm2Info.YPelsPerMeter = GetDword(FpBmp);
  324.         BmpHead->Pm2Info.ClrUsed       = GetDword(FpBmp);
  325.         BmpHead->Pm2Info.ClrImportant  = GetDword(FpBmp);
  326.         BmpHead->Pm2Info.Units         = GetWord(FpBmp);
  327.         BmpHead->Pm2Info.Reserved      = GetWord(FpBmp);
  328.         BmpHead->Pm2Info.Recording     = GetWord(FpBmp);
  329.         BmpHead->Pm2Info.Rendering     = GetWord(FpBmp);
  330.         BmpHead->Pm2Info.Size1         = GetDword(FpBmp);
  331.         BmpHead->Pm2Info.Size2         = GetDword(FpBmp);
  332.         BmpHead->Pm2Info.ColorEncoding = GetDword(FpBmp);
  333.         BmpHead->Pm2Info.Identifier    = GetDword(FpBmp);
  334.       
  335.         /* Read in the color table (if any) */
  336.         if (BmpHead->Pm2Info.BitCount != 24 || BmpHead->Pm2Info.ClrUsed != 0)
  337.         {
  338.             /* Determine number of entries in color table */
  339.             if (BmpHead->Pm2Info.ClrUsed)
  340.                 NumColors = BmpHead->Pm2Info.ClrUsed;
  341.             else
  342.                 NumColors = (WORD) (1U << (BmpHead->Pm2Info.Planes *
  343.                   BmpHead->Pm2Info.BitCount));
  344.  
  345.             /* Allocate memory for the color table entries */
  346.             if ((BmpHead->Pm2ColorTable = (PM2RGBQUAD *)
  347.                  calloc((size_t) NumColors, sizeof(PM2RGBQUAD))) ==
  348.                  (PM2RGBQUAD *) NULL)
  349.                 return(-1);
  350.       
  351.             /* Read in the color table one color quad at a time */
  352.             for (i = 0; i < NumColors; i++)
  353.             {
  354.                 BmpHead->Pm2ColorTable[i].rgbBlue     = GetByte(FpBmp);
  355.                 BmpHead->Pm2ColorTable[i].rgbGreen    = GetByte(FpBmp);
  356.                 BmpHead->Pm2ColorTable[i].rgbRed      = GetByte(FpBmp);
  357.                 BmpHead->Pm2ColorTable[i].rgbReserved = GetByte(FpBmp);
  358.             }
  359.         }
  360.     }
  361.     return(0);
  362. }
  363.  
  364.  
  365.  
  366. BMP Header Writer
  367.  
  368. BMPWRITE.C
  369.  
  370. This function writes out the headers of a BMP file.  The version of
  371. the information header may be selected.  The 
  372. header data is always written in little-endian order.
  373.  
  374.  
  375. /****************************************************************************\
  376. **  Title:        BMPWRITE                                                  **
  377. **  Purpose:      Display the data in a BMP image file header.              **
  378. **  Version:      1.0                                                       **
  379. **  Date:         September 1991                                            **
  380. **  Author:       James D. Murray, Anaheim, CA, USA                         **
  381. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  382. **                                                                          **
  383. **  This module contains the following function:                            **
  384. **                                                                          **
  385. **      WriteBmpHeader - Write a BMP header to a FILE stream.               **
  386. **                                                                          **
  387. **  Copyright (C) 1991 Graphics Software Labs.  All rights reserved.        **
  388. \****************************************************************************/
  389. #include <stdio.h>
  390. #include "endianio.h"
  391. #include "bmp.h"
  392.  
  393. /* External global variables */
  394. VOID (*PutWord)(WORD, FILE *);
  395. VOID (*PutDword)(DWORD, FILE *);
  396.  
  397. /*
  398. **  Write a Windows or PM BMP header.
  399. **
  400. **  This function reads the information from a BMPHEADER structure
  401. **  and writes it to a FILE stream in the form of a BMP header.
  402. **
  403. **  Returns: Nothing.
  404. */
  405. VOID
  406. WriteBmpHeader(BmpHead, FpBmp)
  407. BMPHEADER *BmpHead;     /* Pointer to BMP header structure  */
  408. FILE      *FpBmp;       /* BMP image file output FILE stream */
  409. {
  410.     register SHORT i;   /* Loop counter */
  411.     WORD  NumColors;    /* Number of colors in color table */
  412.  
  413.     PutWord  = PutLittleWord;   /* Write using little-endian byte order */
  414.     PutDword = PutLittleDword;  
  415.  
  416.     /* Write the bit map file header */
  417.     PutWord(BmpHead->Header.Type,      FpBmp);
  418.     PutDword(BmpHead->Header.FileSize, FpBmp);
  419.     PutWord(BmpHead->Header.Reserved1, FpBmp);
  420.     PutWord(BmpHead->Header.Reserved2, FpBmp);
  421.     PutDword(BmpHead->Header.Offset,   FpBmp);
  422.  
  423.     /*
  424.     ** Write the bit map information header.
  425.     **
  426.     ** The size if the information header indicates if the BMP file
  427.     ** originated on an MS Windows or OS/2 Presentation Manager system.
  428.     */
  429.     if (BmpHead->PmInfo.Size)          /* OS/2 1.x */
  430.     {
  431.         PutWord(BmpHead->PmInfo.Size,     FpBmp);
  432.         PutWord(BmpHead->PmInfo.Width,    FpBmp);
  433.         PutWord(BmpHead->PmInfo.Height,   FpBmp);
  434.         PutWord(BmpHead->PmInfo.Planes,   FpBmp);
  435.         PutWord(BmpHead->PmInfo.BitCount, FpBmp);
  436.  
  437.         if (BmpHead->PmColorTable)
  438.         {
  439.             /* Determine number of entries in color table */
  440.             NumColors = (WORD) (1U << (BmpHead->PmInfo.Planes *
  441.               BmpHead->PmInfo.BitCount));
  442.  
  443.             /* Write the color table one color triple at a time */
  444.             for (i = 0; i < NumColors; i++)
  445.             {
  446.                  PutByte(BmpHead->PmColorTable[i].rgbBlue,  FpBmp);
  447.                  PutByte(BmpHead->PmColorTable[i].rgbGreen, FpBmp);
  448.                  PutByte(BmpHead->PmColorTable[i].rgbRed,   FpBmp);
  449.             }
  450.         }
  451.     }
  452.     else                               /* Windows 3 */
  453.     if (BmpHead->WinInfo.Size)
  454.     {                              
  455.         PutDword(BmpHead->WinInfo.Size,          FpBmp);
  456.         PutDword(BmpHead->WinInfo.Width,         FpBmp);
  457.         PutDword(BmpHead->WinInfo.Height,        FpBmp);
  458.         PutWord(BmpHead->WinInfo.Planes,         FpBmp);
  459.         PutWord(BmpHead->WinInfo.BitCount,       FpBmp);
  460.         PutDword(BmpHead->WinInfo.Compression,   FpBmp);
  461.         PutDword(BmpHead->WinInfo.SizeImage,     FpBmp);
  462.         PutDword(BmpHead->WinInfo.XPelsPerMeter, FpBmp);
  463.         PutDword(BmpHead->WinInfo.YPelsPerMeter, FpBmp);
  464.         PutDword(BmpHead->WinInfo.ClrUsed,       FpBmp);
  465.         PutDword(BmpHead->WinInfo.ClrImportant,  FpBmp);
  466.  
  467.         if (BmpHead->WinColorTable)
  468.         {
  469.             /* Determine number of entries in color table */
  470.             if (BmpHead->WinInfo.ClrUsed)
  471.                 NumColors = BmpHead->WinInfo.ClrUsed;
  472.             else
  473.                 NumColors = (WORD) (1U << (BmpHead->WinInfo.Planes *
  474.                   BmpHead->WinInfo.BitCount));
  475.  
  476.             /* Write the color table one color quad at a time */
  477.             for (i = 0; i < NumColors; i++)
  478.             {
  479.                 PutByte(BmpHead->WinColorTable[i].rgbBlue,     FpBmp);
  480.                 PutByte(BmpHead->WinColorTable[i].rgbGreen,    FpBmp);
  481.                 PutByte(BmpHead->WinColorTable[i].rgbRed,      FpBmp);
  482.                 PutByte(BmpHead->WinColorTable[i].rgbReserved, FpBmp);
  483.             }
  484.         }
  485.     }
  486.     else                               /* OS/2 2.0 */
  487.     if (BmpHead->Pm2Info.Size)
  488.     {                              
  489.         PutDword(BmpHead->Pm2Info.Size,          FpBmp);
  490.         PutDword(BmpHead->Pm2Info.Width,         FpBmp);
  491.         PutDword(BmpHead->Pm2Info.Height,        FpBmp);
  492.         PutWord( BmpHead->Pm2Info.Planes,        FpBmp);
  493.         PutWord( BmpHead->Pm2Info.BitCount,      FpBmp);
  494.         PutDword(BmpHead->Pm2Info.Compression,   FpBmp);
  495.         PutDword(BmpHead->Pm2Info.SizeImage,     FpBmp);
  496.         PutDword(BmpHead->Pm2Info.XPelsPerMeter, FpBmp);
  497.         PutDword(BmpHead->Pm2Info.YPelsPerMeter, FpBmp);
  498.         PutDword(BmpHead->Pm2Info.ClrUsed,       FpBmp);
  499.         PutDword(BmpHead->Pm2Info.ClrImportant,  FpBmp);
  500.         PutWord( BmpHead->Pm2Info.Units,         FpBmp);
  501.         PutWord( BmpHead->Pm2Info.Reserved,      FpBmp);
  502.         PutWord( BmpHead->Pm2Info.Recording,     FpBmp);
  503.         PutWord( BmpHead->Pm2Info.Rendering,     FpBmp);
  504.         PutDword(BmpHead->Pm2Info.Size1,         FpBmp);
  505.         PutDword(BmpHead->Pm2Info.Size2,         FpBmp);
  506.         PutDword(BmpHead->Pm2Info.ColorEncoding, FpBmp);
  507.         PutDword(BmpHead->Pm2Info.Identifier,    FpBmp);
  508.  
  509.         if (BmpHead->Pm2ColorTable)
  510.         {
  511.             /* Determine number of entries in color table */
  512.             if (BmpHead->Pm2Info.ClrUsed)
  513.                 NumColors = BmpHead->Pm2Info.ClrUsed;
  514.             else
  515.                 NumColors = (WORD) (1U << (BmpHead->Pm2Info.Planes *
  516.                   BmpHead->Pm2Info.BitCount));
  517.  
  518.             /* Write the color table one color quad at a time */
  519.             for (i = 0; i < NumColors; i++)
  520.             {
  521.                 PutByte(BmpHead->Pm2ColorTable[i].rgbBlue,     FpBmp);
  522.                 PutByte(BmpHead->Pm2ColorTable[i].rgbGreen,    FpBmp);
  523.                 PutByte(BmpHead->Pm2ColorTable[i].rgbRed,      FpBmp);
  524.                 PutByte(BmpHead->Pm2ColorTable[i].rgbReserved, FpBmp);
  525.             }
  526.         }
  527.     }
  528. }
  529.  
  530.  
  531.  
  532. BMP File Information Lister
  533.  
  534. BMPHEAD.C
  535.  
  536. This useful program displays the information found in the header and
  537. color table of a BMP file.  It is also a useful 
  538. example of how to use several of the functions in the BMP library.
  539.  
  540.  
  541. /****************************************************************************\
  542. **  Title:        BMPHEAD                                                   **
  543. **  Purpose:      Display the data in a BMP image file header.              **
  544. **  Version:      1.0                                                       **
  545. **  Date:         September 1991                                            **
  546. **  Author:       James D. Murray, Anaheim, CA, USA                         **
  547. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  548. **                                                                          **
  549. **  BMPHEAD displays all real information contained within the              **
  550. **  header of a BMP image file including the array of color map             **
  551. **  values.                                                                 **
  552. **                                                                          **
  553. **  Copyright (C) 1991 James D. Murray.  All rights reserved.               **
  554. \****************************************************************************/
  555. #include <stdio.h>
  556. #include <stdlib.h>
  557. #include <string.h>
  558. #include <conio.h>
  559. #include "endianio.h"
  560. #include "bmp.h"
  561.  
  562.  
  563. int
  564. main(argc, argv)
  565. int argc;
  566. char *argv[];
  567. {
  568.     register WORD i;                    /* Loop Counter */
  569.     BMPHEADER  bmpHead;
  570.     WORD       NumberColorTableEntries;
  571.     CHAR       BmpFileName[80];         /* Holder for the BMP image file name */
  572.     FILE      *fpBmpIn;                 /* File pointer to the BMP image file */
  573.  
  574.     puts("BMPHEAD - Display the header info within a BMP image file (v1.00)\n");
  575.  
  576.     /* Check for proper number of command line arguments */
  577.     if (argc < 2)
  578.     {
  579.         fputs("Usage: BMPHEAD filename.bmp\n\n", stderr);
  580.         exit(-1);
  581.     }
  582.  
  583.     /* Add the .bmp extension to the file name if no extension exists */
  584.     strcpy(BmpFileName, argv[1]);
  585.     if (!strrchr(argv[1], '.'))
  586.         strcat(BmpFileName, ".bmp");
  587.  
  588.     /* Open the BMP image file */
  589.     if ((fpBmpIn = fopen(BmpFileName, "rb")) == NULL)
  590.     {
  591.         fprintf(stderr, "BMPHEAD: Cannot open file %s\n", BmpFileName);
  592.         exit(-2);
  593.     }
  594.  
  595.     /* Read the BMP image file header information */
  596.     ReadBmpHeader(&bmpHead, fpBmpIn);
  597.  
  598.     /* Check for FILE stream error */
  599.     if (ferror(fpBmpIn))
  600.     {
  601.         fputs("BMPHEAD: Error reading header information!\n", stderr);
  602.         exit(-4);
  603.     }
  604.  
  605.     /* Check the Identification Type */
  606.     if (bmpHead.Header.Type != BMP_ID)
  607.     {
  608.         fprintf(stderr, "BMPHEAD: %s is not a BMP-format file!\n",
  609.           BmpFileName);
  610.         exit(-5);
  611.     }
  612.  
  613.     /*
  614.     ** Display the BMP file information.
  615.     */
  616.     printf("            File Type: %x\n",    bmpHead.Header.Type);
  617.     printf("            File Size: %ld\n",   bmpHead.Header.FileSize);
  618.     printf("            Reserved1: %d\n",    bmpHead.Header.Reserved1);
  619.     printf("            Reserved2: %d\n",    bmpHead.Header.Reserved2);
  620.     printf("    Image Data Offset: %ld\n\n", bmpHead.Header.Offset);
  621.  
  622.     if (bmpHead.PmInfo.Size)         /* OS/2 1.x bitmap */
  623.     {
  624.         printf("   Size of Header: %ld", bmpHead.PmInfo.Size);
  625.         puts("\t(OS/2 1.x Bitmap)");
  626.  
  627.         printf("   Width of Image: %d",  bmpHead.PmInfo.Width);
  628.         puts("\t(in Pixels)");
  629.  
  630.         printf("  Height of Image: %d",  bmpHead.PmInfo.Height);
  631.         puts("\t(in Pixels)");
  632.  
  633.         printf(" Number of Planes: %d",  bmpHead.PmInfo.Planes);
  634.         puts("\t(Must be 1)");
  635.  
  636.         printf("   Bits Per Pixel: %d",  bmpHead.PmInfo.BitCount);
  637.         printf("\t(%ld Colors Total)\n", 1L << (bmpHead.PmInfo.Planes * 
  638. bmpHead.PmInfo.BitCount));
  639.     }
  640.     else
  641.     if (bmpHead.WinInfo.Size)           /* Windows 3.0 bitmap */
  642.     {
  643.         printf("       Size of Header: %ld", bmpHead.WinInfo.Size);
  644.         puts("\t(Windows 3.0 Bitmap)");
  645.         printf("       Width of Image: %ld", bmpHead.WinInfo.Width);
  646.         puts("\t(in Pixels)");
  647.         printf("      Height of Image: %ld", bmpHead.WinInfo.Height);
  648.         puts("\t(in Pixels)");
  649.         printf("     Number of Planes: %d",  bmpHead.WinInfo.Planes);
  650.         puts("\t(Must be 1)");
  651.         printf("       Bits Per Pixel: %d",  bmpHead.WinInfo.BitCount);
  652.         printf("\t(%ld Colors Total)\n", 1L << (bmpHead.WinInfo.Planes * 
  653. bmpHead.WinInfo.BitCount));
  654.         printf("          Compression: %ld", bmpHead.WinInfo.Compression);
  655.         switch (bmpHead.WinInfo.Compression)
  656.         {
  657.             case COMPRESS_RGB:
  658.                 puts("\t(No Compression)");
  659.                 break;
  660.             case COMPRESS_RLE4:
  661.                 puts("\t(4-bits Per Pixel Encoding)");
  662.                 break;
  663.             case COMPRESS_RLE8:
  664.                 puts("\t(8-bits Per Pixel Encoding)");
  665.                 break;
  666.             default:
  667.                 puts("\t(Unknown Compression Format)");
  668.                 break;
  669.         }
  670.         printf("        Size of Image: %ld", bmpHead.WinInfo.SizeImage);
  671.         puts("\t(in Bytes)");
  672.  
  673.         printf("Horizontal Resolution: %ld", bmpHead.WinInfo.XPelsPerMeter);
  674.         puts("\t(in Pixels Per Meter)");
  675.  
  676.         printf("  Vertical Resolution: %ld", bmpHead.WinInfo.YPelsPerMeter);
  677.         puts("\t(in Pixels Per Meter)");
  678.  
  679.         printf("   Color Indexes Used: %ld", bmpHead.WinInfo.ClrUsed);
  680.         if (bmpHead.WinInfo.BitCount == 24)
  681.             puts("\t(No Color Table)");
  682.         else
  683.         if (bmpHead.WinInfo.ClrUsed != 0)
  684.             printf("\t(%lu Entries in Color Table)\n", bmpHead.WinInfo.ClrUsed);
  685.         else
  686.             printf("\t(%lu Entries in Color Table)\n",
  687.               (DWORD) (1U << (bmpHead.WinInfo.Planes * bmpHead.WinInfo.BitCount)));
  688.  
  689.         printf("     Colors Important: %ld", bmpHead.WinInfo.ClrImportant);
  690.         if (bmpHead.WinInfo.ClrImportant == 0)
  691.             printf("\t(All Colors Are Important)");
  692.         else
  693.             printf("\t(%ld Colors Are Important)", bmpHead.WinInfo.ClrImportant);
  694.         fputc('\n', stdout);
  695.     }
  696.     else
  697.     if (bmpHead.PmInfo.Size)         /* OS/2 2.0 bitmap */
  698.     {
  699.         printf("       Size of Header: %ld", bmpHead.Pm2Info.Size);
  700.         puts("\t(OS/2 2.0 Bitmap)");
  701.         printf("       Width of Image: %ld", bmpHead.Pm2Info.Width);
  702.         puts("\t(in Pixels)");
  703.         printf("      Height of Image: %ld", bmpHead.Pm2Info.Height);
  704.         puts("\t(in Pixels)");
  705.         printf("     Number of Planes: %d",  bmpHead.Pm2Info.Planes);
  706.         puts("\t(Must be 1)");
  707.         printf("       Bits Per Pixel: %d",  bmpHead.Pm2Info.BitCount);
  708.         printf("\t(%ld Colors Total)\n", 1L << (bmpHead.Pm2Info.Planes * 
  709. bmpHead.Pm2Info.BitCount));
  710.         printf("          Compression: %ld", bmpHead.Pm2Info.Compression);
  711.         switch (bmpHead.Pm2Info.Compression)
  712.         {
  713.             case COMPRESS_RGB:
  714.                 puts("\t(No Compression)");
  715.                 break;
  716.             case COMPRESS_RLE4:
  717.                 puts("\t(4-bits Per Pixel Encoding)");
  718.                 break;
  719.             case COMPRESS_RLE8:
  720.                 puts("\t(8-bits Per Pixel Encoding)");
  721.                 break;
  722.             default:
  723.                 puts("\t(Unknown Compression Format)");
  724.                 break;
  725.         }
  726.         printf("        Size of Image: %ld", bmpHead.Pm2Info.SizeImage);
  727.         puts("\t(in Bytes)");
  728.  
  729.         printf("Horizontal Resolution: %ld", bmpHead.Pm2Info.XPelsPerMeter);
  730.         puts("\t(in Pixels Per Meter)");
  731.  
  732.         printf("  Vertical Resolution: %ld", bmpHead.Pm2Info.YPelsPerMeter);
  733.         puts("\t(in Pixels Per Meter)");
  734.  
  735.         printf("   Color Indexes Used: %ld", bmpHead.Pm2Info.ClrUsed);
  736.         if (bmpHead.Pm2Info.BitCount == 24)
  737.             puts("\t(No Color Table)");
  738.         else
  739.         if (bmpHead.Pm2Info.ClrUsed != 0)
  740.             printf("\t(%lu Entries in Color Table)\n", bmpHead.Pm2Info.ClrUsed);
  741.         else
  742.             printf("\t(%lu Entries in Color Table)\n",
  743.               (DWORD) (1U << (bmpHead.Pm2Info.Planes * bmpHead.Pm2Info.BitCount)));
  744.  
  745.         printf("     Colors Important: %ld", bmpHead.Pm2Info.ClrImportant);
  746.         if (bmpHead.Pm2Info.ClrImportant == 0)
  747.             printf("\t(All Colors Are Important)");
  748.         else
  749.             printf("\t(%ld Colors Are Important)", bmpHead.Pm2Info.ClrImportant);
  750.         fputc('\n', stdout);
  751.     }
  752.     else
  753.     {
  754.         fputs("BMPHEAD: No BMP information read!\n", stderr);
  755.         exit(-7);
  756.     }
  757.  
  758.  
  759.     /*
  760.     ** Display the color table (if any).
  761.     **
  762.     ** Use ClrUsed to determine the number of entries in the
  763.     ** color table.  If ClrUsed is 0, then the number of entries
  764.     ** is calculated using BitCount.  Typically, bitmaps with
  765.     ** 24-bits per pixel do not have color tables unless ClrUsed
  766.     ** is non-zero.  All other types of bitmaps (1, 4, or 8-bits per
  767.     ** pixel) do.
  768.     */
  769.  
  770.     /* Display the color table */      /* OS/2 1.x */
  771.     if (bmpHead.PmInfo.Size && bmpHead.PmInfo.BitCount != 24)
  772.     {
  773.         /* Determine the number of RGB entries in the color table */
  774.         NumberColorTableEntries =
  775.           (WORD) (1U << (bmpHead.PmInfo.Planes * bmpHead.PmInfo.BitCount));
  776.  
  777.         fputs("\nHit Enter for color table information...", stdout);
  778.         getch();
  779.         putchar('\n');
  780.  
  781.         printf("\nNumber of Color Table Entries: %u\n\n", NumberColorTableEntries);
  782.         puts("Color\tRed\tGreen\tBlue");
  783.  
  784.         for (i = 0; i < NumberColorTableEntries; i++)
  785.         {
  786.             printf("%03u\t%03u\t%03u\t%03u\n",
  787.               i,
  788.               bmpHead.PmColorTable[i].rgbRed,
  789.               bmpHead.PmColorTable[i].rgbGreen,
  790.               bmpHead.PmColorTable[i].rgbBlue);
  791.  
  792.             if (i && i % 22 == 0)
  793.             {
  794.                 fputs("Hit Enter for next page...", stdout);
  795.                 getch();        
  796.                 puts("\n\nColor\tRed\tGreen\tBlue\n");
  797.             }
  798.         }
  799.     }
  800.     else                               /* Windows 3.0 */
  801.     if (bmpHead.WinInfo.Size && 
  802.        (bmpHead.WinInfo.BitCount != 24 || bmpHead.WinInfo.ClrUsed != 0))
  803.     {
  804.         /* Determine the number of RGB entries in the color table */
  805.         if (bmpHead.WinInfo.ClrUsed != 0)
  806.             NumberColorTableEntries = (WORD) bmpHead.WinInfo.ClrUsed;
  807.         else
  808.             NumberColorTableEntries =
  809.               (WORD) (1U << (bmpHead.WinInfo.Planes * bmpHead.WinInfo.BitCount));
  810.  
  811.         fputs("\nHit Enter for color table information...", stdout);
  812.         getch();
  813.         fputc('\n', stdout);
  814.  
  815.         printf("\nNumber of Color Table Entries: %u\n\n", NumberColorTableEntries);
  816.  
  817.         puts("Color\tRed\tGreen\tBlue\tReserved\n");
  818.         for (i = 0; i < NumberColorTableEntries; i++)
  819.         {
  820.             printf("%03u\t%03u\t%03u\t%03u\t%03u\n",
  821.               i,
  822.               bmpHead.WinColorTable[i].rgbRed,
  823.               bmpHead.WinColorTable[i].rgbGreen,
  824.               bmpHead.WinColorTable[i].rgbBlue,
  825.               bmpHead.WinColorTable[i].rgbReserved);
  826.  
  827.             if (i && i % 22 == 0)
  828.             {
  829.                 fputs("Hit Enter for next page...", stdout);
  830.                 getch();        
  831.                 puts("\n\nColor\tRed\tGreen\tBlue\tReserved\n");
  832.             }
  833.          }
  834.     }
  835.     else                               /* OS/2 2.0 */
  836.     if (bmpHead.Pm2Info.Size &&
  837.        (bmpHead.Pm2Info.BitCount != 24 || bmpHead.Pm2Info.ClrUsed != 0))
  838.     {
  839.         /* Determine the number of RGB entries in the color table */
  840.         if (bmpHead.Pm2Info.ClrUsed != 0)
  841.             NumberColorTableEntries = (WORD) bmpHead.Pm2Info.ClrUsed;
  842.         else
  843.             NumberColorTableEntries =
  844.               (WORD) (1U << (bmpHead.Pm2Info.Planes * bmpHead.Pm2Info.BitCount));
  845.  
  846.         fputs("\nHit Enter for color table information...", stdout);
  847.         getch();
  848.         fputc('\n', stdout);
  849.  
  850.         printf("\nNumber of Color Table Entries: %u\n\n", NumberColorTableEntries);
  851.  
  852.         puts("Color\tRed\tGreen\tBlue\tReserved\n");
  853.         for (i = 0; i < NumberColorTableEntries; i++)
  854.         {
  855.             printf("%03u\t%03u\t%03u\t%03u\t%03u\n",
  856.               i,
  857.               bmpHead.Pm2ColorTable[i].rgbRed,
  858.               bmpHead.Pm2ColorTable[i].rgbGreen,
  859.               bmpHead.Pm2ColorTable[i].rgbBlue,
  860.               bmpHead.Pm2ColorTable[i].rgbReserved);
  861.  
  862.             if (i && i % 22 == 0)
  863.             {
  864.                 fputs("Hit Enter for next page...", stdout);
  865.                 getch();        
  866.                 puts("\n\nColor\tRed\tGreen\tBlue\tReserved\n");
  867.             }
  868.          }
  869.     }
  870.  
  871.     fclose(fpBmpIn);
  872.     return(0);
  873. }
  874.  
  875.                                                     
  876.  
  877.  
  878. BMP Run-Length Encoder
  879.  
  880. BMPENCOD.C
  881.  
  882. This function encodes raw BMP data into 4-bit or 8-bit BMP RLE data.
  883. The algorithm always uses encoded runs for pixel runs greater than
  884. five pixels in length, otherwise raw runs are used.  Delta and end
  885. of bitmap escape sequences are not included in the encoding.  The
  886. end of bitmap escape code must be written by the function calling
  887. BmpEncodeData().
  888.  
  889.  
  890. /****************************************************************************\
  891. **  Title:        BMPENCODE                                                 **
  892. **  Purpose:      Display the data in a BMP image file header.              **
  893. **  Version:      1.0                                                       **
  894. **  Date:         September 1991                                            **
  895. **  Author:       James D. Murray, Anaheim, CA, USA                         **
  896. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  897. **                                                                          **
  898. **  This module contains the following function:                            **
  899. **                                                                          **
  900. **      BmpEncodeScanLine -   **
  901. **                                                                          **
  902. **  Copyright (C) 1991 Graphics Software Labs.  All rights reserved.        **
  903. \****************************************************************************/
  904. #include <stdio.h>
  905. #include <stdlib.h>
  906. #include <string.h>
  907. #include "endianio.h"
  908. #include "bmp.h"
  909.  
  910. /*
  911. Read encoded data from a FILE stream and write to a buffer.
  912.  
  913. Pixels are either 4-bits or 8-bits in size.  The Method parameter
  914. indcates the size with a value of COMPRESS_RLE4 or COMPRESS_RLE8.
  915.  
  916. Note that this code only writes absolute runs of pixels that are the same
  917. value.  Literal runs may just as easily represent a line of pixels with
  918. different values.
  919.  
  920. For 4-bit pixels the MSN (Most Significant Nibble) is the first pixel
  921. value and the LSN (Least Significant Nibble) is the second pixel value.
  922. This particular algorithm encodes 4-bit per pixel data two nibbles at a time.
  923. In other words, if you had the raw run "11 11 15" only first four nibbles
  924. would be encoded in the run.  The fifth nibble would be treated part of
  925. of the next run.  Not the most efficient scheme, but it
  926. simplifies the algorithm by not needing to tear apart bytes into sparate
  927. nibble values and add padding for odd-length pixel runs.  So there.
  928.  
  929. **  Method may have one of the following values:
  930. **
  931. **      0 - Unencoded
  932. **      1 - Four bits per pixel
  933. **      2 - Eight bits per pixel
  934. **
  935. **
  936. */
  937. SHORT
  938. BmpEncodeScanLine(EncodedBuffer, BufferSize, LineLength, Method, FpBmp)
  939. BYTE  *EncodedBuffer;    /* Pointer to buffer to hold encodeded scan line   */
  940. WORD   BufferSize;       /* Size of buffer holding unencoded data           */
  941. WORD   LineLength;       /* The length of a scan line in pixels             */
  942. DWORD  Method;           /* Encoding method to use                          */
  943. FILE  *FpBmp;            /* FILE pointer to the open input BMP image file   */
  944. {
  945.     WORD    runCount;       /* The number of pixels in the current run      */
  946.     WORD    pixelCount;     /* The number of pixels read from the scan line */
  947.     SHORT   bufIndex;       /* The index of DecodedBuffer                   */
  948.     BYTE    pixelValue1;    /* Pixel value read from the scan line (4-byte max) */
  949.     BYTE    pixelValue2;    /* Pixel value read from the scan line          */
  950.  
  951.     /* Check that a proper compression method has been specified */
  952.     if (Method != COMPRESS_RLE4 && Method != COMPRESS_RLE8)
  953.         return(-1);
  954.  
  955.     bufIndex   = 0;
  956.     runCount   = (Method == COMPRESS_RLE4 ? 2 : 1);
  957.     pixelCount = (Method == COMPRESS_RLE4 ? 2 : 1);
  958.  
  959.     /* Read in first pixel value */
  960.     pixelValue1 = GetByte(FpBmp);
  961.  
  962.     /* Main encoding loop */
  963.     for (;;)
  964.     {
  965.         /* Read in another pixel value */
  966.         pixelValue2 = GetByte(FpBmp);
  967.  
  968.         /* Count number of pixels read so far */
  969.         pixelCount += (Method == COMPRESS_RLE4 ? 2 : 1);
  970.  
  971.         /* If the pixels are the same then start or continue a run */
  972.         if (pixelValue1 == pixelValue2)   /* Compare pixels */
  973.         {
  974.             /* Advance the run count */
  975.             runCount += (Method == COMPRESS_RLE4 ? 2 : 1);
  976.  
  977.             if (runCount < 256)     /* Maximum run-length is 256 pixels     */
  978.             {
  979.                 if (pixelCount < LineLength)  /* Don't run past end of scan line */
  980.                     continue;       /* Continue reading the run             */
  981.             }
  982.         }
  983.  
  984.         /*
  985.         ** If we have gotten this far then we have either come to the end of
  986.         ** a pixel run, have reached the maximum number of pixels encodable
  987.         ** in a run, or read to the end of the scan line.  Now encode the
  988.         ** current run.
  989.         */
  990.  
  991.         /*
  992.         ** Literal runs must have a runCount greater than 2 or the
  993.         ** literal run indicator will be confused with an escape code.
  994.         ** This scheme will also only encode even-length runs as literal
  995.         ** runs.  This frees us from keeping track of left over nibbles
  996.         ** from odd-length runs.
  997.         */
  998. #if 0
  999.         if (runCount > 2 && runCount < 8 && !(runCount % 2))    /* Write a Literal Run 
  1000. */
  1001. #endif
  1002.         if (runCount < 0)
  1003.         {
  1004.             /* Make sure writing this next run will not overflow the buffer */
  1005.             if (bufIndex + runCount >= BufferSize - 2)
  1006.                 return(-1);
  1007.  
  1008.             EncodedBuffer[bufIndex++] = 0;          /* Literal Run indicator  */
  1009.             EncodedBuffer[bufIndex++] = runCount;   /* Number of pixels in run */
  1010.  
  1011.             if (Method == COMPRESS_RLE4)
  1012.                 runCount /= 2;
  1013.  
  1014.             /* Write the pixel data run */
  1015.             while (runCount--)
  1016.                 EncodedBuffer[bufIndex++] = pixelValue1;
  1017.         }
  1018.         else                /* Write an Encoded Run */
  1019.         {
  1020. printf("runCount: %d  value %d\n", runCount, pixelValue1);
  1021.             EncodedBuffer[bufIndex++] = runCount;    /* Number of pixels in run */
  1022.             EncodedBuffer[bufIndex++] = pixelValue1; /* Value of pixels in run */
  1023.         }
  1024.  
  1025.         /* If we've encoded the entire line then break out of the loop */
  1026.         if (pixelCount == LineLength)
  1027.             break;
  1028.  
  1029.         /* Start a new pixel run count  */
  1030.         runCount = (Method == COMPRESS_RLE4 ? 2 : 1);
  1031.  
  1032.         /* Store next pixel value run to match */
  1033.         pixelValue1 = pixelValue2;
  1034.     }
  1035.     /* Write an End of Scan Line Escape Code */
  1036.     EncodedBuffer[bufIndex++] = 0;          
  1037.     EncodedBuffer[bufIndex++] = 0;
  1038.  
  1039.     return(bufIndex);
  1040. }
  1041.  
  1042.  
  1043. BMP Run-length Decoder
  1044.  
  1045. BMPDECOD.C
  1046.  
  1047. This function decodes 4-bit and 8-bit BMP RLE image data.  Note the
  1048. delta escape sequences are not supported because this function can
  1049. only decode one scan line at a time.
  1050.  
  1051.  
  1052. /****************************************************************************\
  1053. **  Title:        BMPDECODE                                                 **
  1054. **  Purpose:      Display the data in a BMP image file header.              **
  1055. **  Version:      1.0                                                       **
  1056. **  Date:         September 1991                                            **
  1057. **  Author:       James D. Murray, Anaheim, CA, USA                         **
  1058. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  1059. **                                                                          **
  1060. **  This module contains the following function:                            **
  1061. **                                                                          **
  1062. **  Copyright (C) 1991 Graphics Software Labs.  All rights reserved.        **
  1063. \****************************************************************************/
  1064. #include <stdio.h>
  1065. #include <stdlib.h>
  1066. #include <string.h>
  1067. #include "endianio.h"
  1068. #include "bmp.h"
  1069.  
  1070.  
  1071. SHORT
  1072. BmpDecodeScanLine(DecodedBuffer, LineLength, BufferSize, Method, FpBmp)
  1073. BYTE *DecodedBuffer;    /* Pointer to buffer to hold decoded data         */
  1074. WORD  BufferSize;       /* Size of buffer to hold decoded data in bytes   */
  1075. WORD  LineLength;       /* The length of a scan line in pixels            */
  1076. DWORD Method;           /* Data encoding method used on scan line data    */
  1077. FILE *FpBmp;            /* FILE pointer to the open input BMP image file  */
  1078. {
  1079.     BYTE    runCount;       /* Number of pixels in the run  */
  1080.     BYTE    runValue;       /* Value of pixels in the run   */
  1081.     BYTE    Value;          /* Temporary pixel value holder */
  1082.     WORD    bufIndex;       /* The index of DecodedBuffer   */
  1083.  
  1084.     /* Check that a proper compression method has been specified */
  1085.     if (Method != COMPRESS_RLE4 && Method != COMPRESS_RLE8)
  1086.         return(-1);
  1087.  
  1088.     bufIndex = 0;         /* Initialize the buffer index  */
  1089.     
  1090.     /*
  1091.     ** Subtract 2 bytes from the size of the buffer to save room for
  1092.     ** the end-of-scan-line marker.  The buffer should have two more
  1093.     ** bytes than it need to hold the scan line, of course.
  1094.     */
  1095.     BufferSize -= 2;
  1096.  
  1097.     /* Main decoding loop */
  1098.     while (bufIndex < BufferSize)
  1099.     {
  1100.         runCount = GetByte(FpBmp);  /* Number of pixels in the run */
  1101.         runValue = GetByte(FpBmp);  /* Value of pixels in the run  */
  1102.  
  1103.         switch(runCount)
  1104.         {
  1105.             case 0:        /* Literal Run or Escape Code */
  1106.                 switch(runValue)
  1107.                 {
  1108.                     case 0:             /* End of Scan Line Escape Code */
  1109.                         puts("End of scan line Code");
  1110.                     case 1:             /* End of Bitmap Escape Code */
  1111.                         puts("End of bit map Code");
  1112.                         return(bufIndex);
  1113.                     case 2:             /* Delta Escape Code (not supported) */
  1114.                         fputs("Delta Escape Codes not supported!", stderr);
  1115.                         return(-1);
  1116.                     default:            /* Literal Run */
  1117.                         /* Check for a possible buffer overflow */
  1118.                         if (bufIndex + runValue > BufferSize)
  1119.                             return(-2);
  1120.  
  1121.                         if (Method == COMPRESS_RLE8)
  1122.                         {
  1123.                             while (runValue--)
  1124.                                 DecodedBuffer[bufIndex++] = GetByte(FpBmp);
  1125.                         }
  1126.                         else
  1127.                         if (Method == COMPRESS_RLE4)
  1128.                         {
  1129.                             /*
  1130.                             ** Alternate writing the most-significant and
  1131.                             ** Least-significant nibble to the buffer.  The
  1132.                             ** odd-length literal runs are a bit tricky.
  1133.                             */
  1134.                             while (runValue--)
  1135.                             {
  1136.                                 Value = GetByte(FpBmp);
  1137.                                 DecodedBuffer[bufIndex] = (MSN(Value) << 4);
  1138.                                 if (runValue--)
  1139.                                     DecodedBuffer[bufIndex++] |= LSN(Value);
  1140.                             }
  1141.                         }
  1142.                 }
  1143.                 break;
  1144.             default:    /* Encoded Run */
  1145.                 if (Method == COMPRESS_RLE4)            /* Write a 4-bit value */
  1146.                 {
  1147.                     /* Check for a possible buffer overflow */
  1148.                     if (bufIndex + (runCount / 2) > BufferSize)
  1149.                         return(-2);
  1150.  
  1151.                     /*
  1152.                     ** Alternate writing the most-significant and
  1153.                     ** Least-significant nibble to the buffer.
  1154.                     */
  1155.                     while (runCount--)
  1156.                     {
  1157.                         DecodedBuffer[bufIndex] = (MSN(runValue) << 4);
  1158.                         if (runCount--)
  1159.                             DecodedBuffer[bufIndex++] |= LSN(runValue);
  1160.                     }
  1161.                 }
  1162.                 else    /* Write an 8-bit value */
  1163.                 {
  1164. printf("bufIndex %d  runCount %d  BufferSize %d\n", bufIndex, runCount, BufferSize);
  1165.                     /* Check for a possible buffer overflow */
  1166.                     if (bufIndex + runCount > BufferSize)
  1167.                        return(-2);
  1168.  
  1169.                     while (runCount--)
  1170.                         DecodedBuffer[bufIndex++] = runValue;
  1171.                 }
  1172.                 break;
  1173.         }
  1174.     }
  1175.     fputs("BMPDECOD: No End of Scan line code!\n", stderr);
  1176.     return(-3);     /* No End-of-Scan Line or End-of-Bitmap code! */
  1177. }
  1178.  
  1179.  
  1180.  
  1181. BMP File Reader and Writer
  1182.  
  1183. BMPCODE.C
  1184.  
  1185. This code is an example of how to use all the functions in the BMP
  1186. library.  This program will encode and decode BMP files and may
  1187. be modified to change the flavor of a BMP file as well.
  1188.  
  1189.  
  1190. /****************************************************************************\
  1191. **  Title:        BMPCODE                                                   **
  1192. **  Purpose:      Read, decode, encode, and write a BMP image file.         **
  1193. **  Version:      1.0                                                       **
  1194. **  Date:         September 1991                                            **
  1195. **  Author:       James D. Murray, Anaheim, CA, USA                         **
  1196. **  C Compilers:  Borland C++ v2.0, Microsoft C v6.00a                      **
  1197. **                                                                          **
  1198. **  This program is an example of how to use the BMP library functions to   **
  1199. **  read, write, encode, and decode a BMP image file.  BMP files may be     **
  1200. **  decoded and reencoded using a different encoding scheme or left         **
  1201. **  unencoded (raw).  With a little effort this code could be modified to   **
  1202. **  convert one flavor of BMP image file to another (for example, Windows 3 **
  1203. **  to OS/2 1.x).                                                           **
  1204. **                                                                          **
  1205. **  Copyright (C) 1991 Graphics Software Labs.  All rights reserved.        **
  1206. \****************************************************************************/
  1207. #include <stdio.h>
  1208. #include <stdlib.h>
  1209. #include <string.h>
  1210. #include "endianio.h"
  1211. #include "bmp.h"
  1212.  
  1213.  
  1214. int
  1215. main(argc, argv)
  1216. int argc;           /* Number of command line arguments */
  1217. char *argv[];       /* Array of command line arguments  */
  1218. {
  1219.     register WORD i, j;             /* Loop counters                     */
  1220.     FILE         *fpBmpIn;          /* BMP image file input FILE stream  */
  1221.     FILE         *fpBmpOut;         /* BMP image file output FILE stream */
  1222.     BYTE         *buffer;           /* Buffer to hold scan line data     */
  1223.     WORD          bufSize;          /* Size of the scan line buffer      */
  1224.     SHORT         byteCount;        /* Number of bytes in a buffer              */
  1225.     DWORD         compression;      /* Compression value */
  1226.     BMPHEADER     bmpHead;          /* BMP image file header structure   */
  1227.  
  1228.     puts("BMPCODE - Decode and recode a BMP image file (v1.00)\n");
  1229.  
  1230.     /* Check for proper number of command line arguments */
  1231.     if (argc < 3)
  1232.     {
  1233.         fputs("Usage: BMPHEAD input_filename.bmp output_filename.bmp\n\n",
  1234.           stderr);
  1235.         exit(-1);
  1236.     }
  1237.  
  1238.     /* Open the input BMP image file */
  1239.     if ((fpBmpIn = fopen(argv[1], "rb")) == (FILE *) NULL)
  1240.     {
  1241.         fprintf(stderr, "BMPHEAD: Cannot open input file %s\n", argv[1]);
  1242.         exit(-2);
  1243.     }
  1244.  
  1245.     /* Open the output BMP image file */
  1246.     if ((fpBmpOut = fopen(argv[2], "wb")) == (FILE *) NULL)
  1247.     {
  1248.         fprintf(stderr, "BMPHEAD: Cannot open output file %s\n", argv[2]);
  1249.         exit(-3);
  1250.     }
  1251.  
  1252.     /* Read the BMP image file header information */
  1253.     ReadBmpHeader(&bmpHead, fpBmpIn);
  1254.  
  1255.     /* Check for FILE stream error */
  1256.     if (ferror(fpBmpIn))
  1257.     {
  1258.         fputs("BMPHEAD: Error reading header information!\n", stderr);
  1259.         exit(-4);
  1260.     }
  1261.  
  1262.     /* Check the Identification Type */
  1263.     if (bmpHead.Header.Type != BMP_ID)
  1264.     {
  1265.         fprintf(stderr, "BMPHEAD: %s is not a BMP-format file!\n", argv[1]);
  1266.         exit(-5);
  1267.     }
  1268.  
  1269.     /* Seek to the bitmap data (we should already be at the data) */
  1270.     fseek(fpBmpIn, bmpHead.Header.Offset, SEEK_SET);
  1271.  
  1272.     /*
  1273.     ** If the BMP file is unencoded then encode it.  If it's encoded then
  1274.     ** unencode it.  Write out a new BMP image file.
  1275.     */
  1276.     if (bmpHead.WinInfo.Size)   /* Windows 3.x BMP file */
  1277.     {
  1278.         /* Calculate the size of the scan line buffer in bytes */
  1279.         bufSize = (bmpHead.WinInfo.Width * ((bmpHead.WinInfo.BitCount + 7) >> 3) + 2);
  1280.  
  1281.         /* Allocate scan line buffer memory */
  1282.         if ((buffer = (BYTE *) calloc(bufSize, sizeof(BYTE))) == (BYTE *) NULL)
  1283.         {
  1284.             fputs("BMPCODE: Error allocating memory.\n", stderr);
  1285.             exit(-7);
  1286.         }
  1287.  
  1288.         /* If the BMP file contains compressed image data, then decode it */
  1289.         if (bmpHead.WinInfo.Compression == COMPRESS_RLE4 ||
  1290.             bmpHead.WinInfo.Compression == COMPRESS_RLE8)
  1291.         {
  1292.             printf("Decoding BMP File %s to %s\n", argv[1], argv[2]);
  1293.  
  1294.             /* Save compression type */
  1295.             compression = bmpHead.WinInfo.Compression;
  1296.  
  1297.             /* Change header to "not compressed" */
  1298.             bmpHead.WinInfo.Compression = COMPRESS_RGB;
  1299.  
  1300.             /* Write out the header and color table */
  1301.             WriteBmpHeader(&bmpHead, fpBmpOut);
  1302.  
  1303.             /* Check that we are a the image data offset specified in the header before 
  1304. reading */
  1305.             if (ftell(fpBmpIn) != bmpHead.Header.Offset)
  1306.                 printf("WARNING: At %ld, should be %ld\n", 
  1307.                     ftell(fpBmpIn), bmpHead.Header.Offset);
  1308.  
  1309.             for (i = 0; i < bmpHead.WinInfo.Height; i++)
  1310.             {
  1311.                 /* Decode a scan line */
  1312.                 if ((byteCount =
  1313.                     BmpDecodeScanLine(buffer, bmpHead.WinInfo.Width,
  1314.                       bufSize, compression, fpBmpIn)) < 0)
  1315.                 {
  1316.                     fputs("BMPCODE: Error decoding scan line.\n", stderr);
  1317.                     exit(-8);
  1318.                 }
  1319.  
  1320.                 /* Write the decoded scan line to the output file */
  1321.                 for (j = 0; j < byteCount; j++)
  1322.                     PutByte(buffer[j], fpBmpOut);
  1323.             }
  1324.         }
  1325.         else    /* The BMP file contains uncompressed image data */    
  1326.         if (bmpHead.WinInfo.Compression == COMPRESS_RGB &&
  1327.            (bmpHead.WinInfo.BitCount == 4 || bmpHead.WinInfo.BitCount == 8))
  1328.         {
  1329.             printf("Encoding BMP File %s to %s\n", argv[1], argv[2]);
  1330.  
  1331.             /* Change header to "compressed" */
  1332.             bmpHead.WinInfo.Compression =
  1333.               (bmpHead.WinInfo.BitCount == 4 ? COMPRESS_RLE4 : COMPRESS_RLE8);
  1334.  
  1335.             /* Write out the header and color table */
  1336.             WriteBmpHeader(&bmpHead, fpBmpOut);
  1337.  
  1338.             /* Check that we are a the image data offset specified in the header before 
  1339. reading */
  1340.             if (ftell(fpBmpIn) != bmpHead.Header.Offset)
  1341.                 printf("WARNING: At %ld, should be %ld\n", 
  1342.                     ftell(fpBmpIn), bmpHead.Header.Offset);
  1343.  
  1344.             for (i = 0; i < bmpHead.WinInfo.Height; i++)
  1345.             {
  1346.                 /* Encode a scan line */
  1347.                 if ((byteCount =
  1348.                    BmpEncodeScanLine(buffer, bmpHead.WinInfo.Width,
  1349.                    bufSize, bmpHead.WinInfo.Compression, fpBmpIn)) < 0)
  1350.                 {
  1351.                     fputs("BMPCODE: Error encoding scan line.\n", stderr);
  1352.                     exit(-10);
  1353.                 }
  1354.  
  1355.                 /* Write the Encoded scan line to the output file */
  1356.                 for (j = 0; j < byteCount; j++)
  1357.                     PutByte(buffer[j], fpBmpOut);
  1358.             }
  1359.  
  1360.             /* Write end-of-bitmap escape code */
  1361.             PutByte(0, fpBmpOut);
  1362.             PutByte(1, fpBmpOut);
  1363.         }
  1364.     }                                       
  1365.     else
  1366.     if (bmpHead.PmInfo.Size)    /* OS/2 1.x BMP file */
  1367.     {
  1368.  
  1369.     }
  1370.     else
  1371.     if (bmpHead.Pm2Info.Size)    /* OS/2 2.0 BMP file */
  1372.     {
  1373.  
  1374.     }
  1375.  
  1376.     fclose(fpBmpIn);
  1377.     fclose(fpBmpOut);
  1378.  
  1379.     return(0);      /* Successful termination */
  1380. }
  1381.  
  1382.