Introduction
Just recently we needed some embedded C code to decompress bitmap files (we use bitmaps in our Retinal camera to display icon-like images on the video screen for such applications as giving user-feedback). I include this code here not because it's anything fancy, but because I couldn't find any on the net. Much can be found on the bitmap format and windows applications that uses standard API to decompress, but nothing for embedded systems.
The bitmap format is used by image files using the .bmp extension. It was developed by Microsoft who uses bitmap images in the windows operating system for storing icons. The bitmap format uses the following structs in its header:
typedef struct /**** BMP file header structure ****/ { unsigned short bfType; /* Magic number for file */ unsigned int bfSize; /* Size of file */ unsigned short bfReserved1; /* Reserved */ unsigned short bfReserved2; /* ... */ unsigned int bfOffBits; /* Offset to bitmap data */ } BITMAPFILEHEADER; # define BF_TYPE 0x4D42 /* "MB" */ typedef struct /**** BMP file info structure ****/ { unsigned int biSize; /* Size of info header */ int biWidth; /* Width of image */ int biHeight; /* Height of image */ unsigned short biPlanes; /* Number of color planes */ unsigned short biBitCount; /* Number of bits per pixel */ unsigned int biCompression; /* Type of compression to use */ unsigned int biSizeImage; /* Size of image data */ int biXPelsPerMeter; /* X pixels per meter */ int biYPelsPerMeter; /* Y pixels per meter */ unsigned int biClrUsed; /* Number of colors used */ unsigned int biClrImportant; /* Number of important colors */ } BITMAPINFOHEADER; /* * Constants for the biCompression field... */ # define BI_RGB 0 /* No compression - straight BGR data */ # define BI_RLE8 1 /* 8-bit run-length compression */ # define BI_RLE4 2 /* 4-bit run-length compression */ # define BI_BITFIELDS 3 /* RGB bitmap with RGB masks */ typedef struct /**** Colormap entry structure ****/ { unsigned char rgbBlue; /* Blue value */ unsigned char rgbGreen; /* Green value */ unsigned char rgbRed; /* Red value */ unsigned char rgbReserved; /* Reserved */ } RGBQUAD; typedef struct /**** Bitmap information structure ****/ { BITMAPINFOHEADER bmiHeader; /* Image header */ RGBQUAD bmiColors[256]; /* Image colormap */ } BITMAPINFO;
And here is the code that displays both bitmap and compressed bitmap files. The type of compression used is 8 bit Run Length Encoding (RLE), in which essentially, recurring pixels are stored as a single pixel with a count value. The compression algorithm can be found here. Other information on bitmaps can be found on the same site.
// displays bitmap image top left corner at Xoff, Yoff int BmpDisplay(const char *Image, int Xoff, int Yoff) { unsigned char * ImageData; // pointer to array keeping the binary bitmap data unsigned int Width; // width of image unsigned int DisplayWidth; // width of display unsigned int Height; // height of image unsigned int Compression; // stores value of compression int x,y; // coordinates BITMAPFILEHEADER * BMFH = (BITMAPFILEHEADER *) Image; BITMAPINFOHEADER * BMIH = (BITMAPINFOHEADER *) (Image + sizeof(BITMAPFILEHEADER)); if(8 != SwapBytesShort(BMIH->biBitCount)) { OutStr("biBitCount is %d, should be 8 !!!",SwapBytesShort(BMIH->biBitCount)); return ERR_BITCOUNT_NOT_8; } // calculate offset to 1st byte of image ImageData = (unsigned char *)(Image + SwapBytesInt(BMFH->bfOffBits)); DisplayWidth = Width = SwapBytesInt(BMIH->biWidth); Compression = SwapBytesInt(BMIH->biCompression); if (0 != Width & 0x03) { Width &= ~0x03; Width+=4; } Height = SwapBytesInt(BMIH->biHeight); // No compression if(0 == Compression) { for(y=Height-1;y>=0;y--) { for(x=0;x<Width;x++) { if(x<DisplayWidth) plot_pixel(x+Xoff,y+Yoff,*ImageData); ImageData++; } } } // Bitmap is 8-bit RLE compressed else if (1 == Compression) { unsigned char firstByte, secondByte; unsigned int currX, currY, i, state; currX = Xoff; currY = Yoff; state = 0; while(state == 0) { firstByte = *ImageData; ImageData++; if(0 != firstByte) { secondByte =*ImageData; for(i=0; i < firstByte; i++) { plot_pixel(currX, currY, secondByte); currX++; } ImageData++; } else // value is zero { firstByte = *ImageData; // store next byte ImageData++; switch (firstByte) { case 0: currX = Xoff; currY++; // move cursor to beginning of next line break; case 1: state = ERR_NONE; return ERR_NONE; // end of bitmap, finish plotting case 2: currX += (int)(*ImageData); // read byte and add value to x value ImageData++; currY += (int)(*ImageData); // read byte and add value to y value ImageData++; break; // for any other value, print the next firstByte bytes default: for(i = 0; i < firstByte; i++) { secondByte = *ImageData; plot_pixel(currX, currY, secondByte); ImageData++; currX++; } if(0 != firstByte & 0x01) // if the run doesn't end on a word boundary, ImageData++; // advance the pointer } // END switch } // END else } // END while } // END else(if 1 == compression) else { return ERR_COMPRESSION_NOT_SUPPORTED; } return ERR_NONE; }