How to Read in a Bmp File

The BMP format, ofttimes referred to as the Windows Bitmap Format is in my stance, ane of the simplest ways to shop paradigm information in a reckoner. Fifty-fifty though it was originally defined past Microsoft for its operating systems, nowadays its usage is widespread and can exist recognized by practically every major imaging software. For the same reason, there are lots of libraries and APIs to work with images stored in this format.
The purpose of this mail is to provide some guidance for those programmers who can't or don't want to use a third party library to work with images in the BMP format (e.grand. targeting embedded platforms, developing sensitive proprietary software or for learning purposes). And even though our working example will be presented in the c linguistic communication, it  can be easily ported to other languages if necessary.

If you're hither simply for the lawmaking, here'south a somewhat stripped-downwards implementation of the functions to open and save BMP files. Exist enlightened that for legibility no safety validations are being performed (eastward.k. bank check for NULL pointers, validate file operations, etc.) equally they are left to the reader. You can download the source code "bmp.c" and the sample image "img.bmp" from this link

img
Instance image (actually a jpg)
#include  #include  #include  #ascertain DATA_OFFSET_OFFSET 0x000A #define WIDTH_OFFSET 0x0012 #define HEIGHT_OFFSET 0x0016 #define BITS_PER_PIXEL_OFFSET 0x001C #define HEADER_SIZE 14 #define INFO_HEADER_SIZE twoscore #define NO_COMPRESION 0 #define MAX_NUMBER_OF_COLORS 0 #define ALL_COLORS_REQUIRED 0  typedef unsigned int int32; typedef short int16; typedef unsigned char byte;  void ReadImage(const char *fileName,byte **pixels, int32 *width, int32 *height, int32 *bytesPerPixel) {         FILE *imageFile = fopen(fileName, "rb");         int32 dataOffset;         fseek(imageFile, DATA_OFFSET_OFFSET, SEEK_SET);         fread(&dataOffset, four, one, imageFile);         fseek(imageFile, WIDTH_OFFSET, SEEK_SET);         fread(width, 4, i, imageFile);         fseek(imageFile, HEIGHT_OFFSET, SEEK_SET);         fread(height, 4, 1, imageFile);         int16 bitsPerPixel;         fseek(imageFile, BITS_PER_PIXEL_OFFSET, SEEK_SET);         fread(&bitsPerPixel, 2, 1, imageFile);         *bytesPerPixel = ((int32)bitsPerPixel) / eight;          int paddedRowSize = (int)(four * ceil((float)(*width) / iv.0f))*(*bytesPerPixel);         int unpaddedRowSize = (*width)*(*bytesPerPixel);         int totalSize = unpaddedRowSize*(*height);         *pixels = (byte*)malloc(totalSize);         int i = 0;         byte *currentRowPointer = *pixels+((*top-i)*unpaddedRowSize);         for (i = 0; i < *height; i++)         {                 fseek(imageFile, dataOffset+(i*paddedRowSize), SEEK_SET); 	        fread(currentRowPointer, one, unpaddedRowSize, imageFile); 	        currentRowPointer -= unpaddedRowSize;         }          fclose(imageFile); }  void WriteImage(const char *fileName, byte *pixels, int32 width, int32 pinnacle,int32 bytesPerPixel) {         FILE *outputFile = fopen(fileName, "wb");         //*****HEADER************//         const char *BM = "BM";         fwrite(&BM[0], 1, one, outputFile);         fwrite(&BM[1], 1, one, outputFile);         int paddedRowSize = (int)(four * ceil((float)width/4.0f))*bytesPerPixel;         int32 fileSize = paddedRowSize*acme + HEADER_SIZE + INFO_HEADER_SIZE;         fwrite(&fileSize, 4, 1, outputFile);         int32 reserved = 0x0000;         fwrite(&reserved, 4, ane, outputFile);         int32 dataOffset = HEADER_SIZE+INFO_HEADER_SIZE;         fwrite(&dataOffset, iv, 1, outputFile);          //*******INFO*HEADER******//         int32 infoHeaderSize = INFO_HEADER_SIZE;         fwrite(&infoHeaderSize, iv, 1, outputFile);         fwrite(&width, 4, one, outputFile);         fwrite(&elevation, four, 1, outputFile);         int16 planes = 1; //ever 1         fwrite(&planes, 2, 1, outputFile);         int16 bitsPerPixel = bytesPerPixel * 8;         fwrite(&bitsPerPixel, 2, i, outputFile);         //write pinch         int32 compression = NO_COMPRESION;         fwrite(&compression, 4, 1, outputFile);         write image size (in bytes)         int32 imageSize = width*height*bytesPerPixel;         fwrite(&imageSize, 4, ane, outputFile);         int32 resolutionX = 11811; //300 dpi         int32 resolutionY = 11811; //300 dpi         fwrite(&resolutionX, four, 1, outputFile);         fwrite(&resolutionY, 4, 1, outputFile);         int32 colorsUsed = MAX_NUMBER_OF_COLORS;         fwrite(&colorsUsed, iv, 1, outputFile);         int32 importantColors = ALL_COLORS_REQUIRED;         fwrite(&importantColors, 4, one, outputFile);         int i = 0;         int unpaddedRowSize = width*bytesPerPixel;         for ( i = 0; i < height; i++)         {                 int pixelOffset = ((top - i) - i)*unpaddedRowSize;                 fwrite(&pixels[pixelOffset], i, paddedRowSize, outputFile);	         }         fclose(outputFile); }  int chief() {         byte *pixels;         int32 width;         int32 elevation;         int32 bytesPerPixel;         ReadImage("img.bmp", &pixels, &width, &peak,&bytesPerPixel);         WriteImage("img2.bmp", pixels, width, height, bytesPerPixel);         free(pixels);         return 0; }        

The BMP file structure

The structure of a minimal BMP file looks like this:

Name Size Offset (Hex) Clarification/Notes
Bitmap File Header
BMP signature 2 bytes 0x00 The characters 'B' and 'One thousand'
File size 4 bytes 0x02 Size in bytes of the file including headers and pixel data
Reserved 4 bytes 0x06 Unused
Data offset 4 bytes 0x0A Start in the file where the pixel data is stored
Bitmap Information Header
Size of the header 4 bytes 0x0E The header is fixed size: twoscore bytes
Width iv bytes 0x12 Width of the prototype in pixels
Elevation iv bytes 0x16 Meridian of the image in pixels
Planes 2 bytes 0x1A Number of color planes (must be one)
Bits per pixel 2 bytes 0x1C Number of bits per pixel
Compression 4 bytes 0x1E Compression method
Image size four bytes 0x22 Can be 0 if image is not compressed, otherwise is the size of the compressed paradigm
Pixels per meter in X centrality 4 bytes 0x26 Horizontal resolution in pixels per meter
Pixels per meter in Y axis four bytes 0x2A Vertical resolution in pixels per meter
Colors used four bytes 0x2E Number used colors
Important colors 4 bytes 0x32 Number of important color. Tin can be 0 If all colors are important
Color tabular array Only if Bits per pixel < 8
Data
Pixel data Variable Variable Stored bottom-upward

As the table shows, in that location are mainly three parts:

  • Bitmap file header: provides information near the file itself.
  • Bitmap information header: contains the properties of the pixel data.
  • Data: the actual pixel data.

About of the time you volition be working with 24-bit RGB color or viii-bit grayscale images but it's of import to consider that in the case where the pixels are represented with less than 8 bits, a Color Table must be included in the bitmap data header. Other optional fields might exist nowadays in the file but for simplicity they are not covered in this post. For more than information most this you can consult this Wikipedia commodity or this mail service by Nathan Liesch.

Reading a BMP file

To excerpt the pixel information you could decide to read every field from the header based on the table above. Just in reality in that location are simply 4 parts we're interested in:

  • The information first (so you know where the pixel  data is)
  • Image peak
  • Paradigm width
  • Bits per pixel

This can be achieved with the regular fopen role by moving to the correct offset within the file (using fseek):

#define DATA_OFFSET_OFFSET 0x000A #ascertain WIDTH_OFFSET 0x0012 #define HEIGHT_OFFSET 0x0016 #ascertain BITS_PER_PIXEL_OFFSET 0x001C  FILE *imageFile = fopen(fileName, "rb"); int32 dataOffset; fseek(imageFile, DATA_OFFSET_OFFSET, SEEK_SET); fread(&dataOffset, iv, ane, imageFile); fseek(imageFile, WIDTH_OFFSET, SEEK_SET); fread(width, four, 1, imageFile); fseek(imageFile, HEIGHT_OFFSET, SEEK_SET); fread(height, 4, 1, imageFile); int16 bitsPerPixel; fseek(imageFile, BITS_PER_PIXEL_OFFSET, SEEK_SET); fread(&bitsPerPixel, ii, one, imageFile);        

Once we take this information we can allocate enough memory to contain the pixel data, that is height x width x bytes per pixel  (bits per pixel divided past viii).

At this point you lot might exist tempted to just read the rest of the file starting from the information outset. If you practice, you might find that your paradigm is upside-down and information technology has some extra pixels. Our example image would wait like this:

weird

This is because the epitome is stored bottom-up and the rows contain padding bytes to make their size a multiple of 4. In that location are many ways of treatment this situation. I option is to have a pointer to the last row of the (past at present empty) pixel assortment, read a row from the file into that address (ignoring the padding bytes) and moving the pointer to the next row. The following code snippet illustrates this process:

//point to the final row of our pixel array (unpadded) byte *currentRowPointer = *pixels+((*superlative-ane)*unpaddedRowSize); for (i = 0; i < *height; i++) {    fseek(imageFile, dataOffset+(i*paddedRowSize), SEEK_SET);    fread(currentRowPointer, 1, unpaddedRowSize, imageFile);    currentRowPointer -= unpaddedRowSize; }        

At present you lot take a pixel assortment to work with!

Writing BMP files

If you lot want other programs to exist able to work with the a file you created, you need to adhere to the file'southward structure specification. This is quite straightforward if y'all follow the table above. Look at the code sample for more details.

At this stage the key is to remember that rows must exist padded to a multiple of 4 and stored lesser-up. To practise this you can only contrary the process we used for reading the file:

for ( i = 0; i < summit; i++) {    //get-go writing from the kickoff of last row in the pixel array    int pixelOffset = ((top - i) - 1)*unpaddedRowSize;    fwrite(&pixels[pixelOffset], 1, paddedRowSize, outputFile); }        

And with that piece of lawmaking we covered the well-nigh basic operations. The provided source code was tested on Windows, Ubuntu and RHEL, but you might need to make some changes for other targets.

Notes for Windows users:
Make sure to open the output file in binary fashion. Remember that in Windows line endings are represented with 2 characters (\n and \r). For this reason, if your file is open in text style, every time you lot write the value x (0x0A, the \northward character) an actress 13 volition be added (0x0D, the \r character). These kind of errors are very difficult to debug without a Hex editor and lot of patience.

If you're using Visual Studio you lot might experience problems with the fopen part. You can alter it openf_s or add the _CRT_SECURE_NO_WARNINGS pre-processor definition equally explained hither.

Y'all can use BITMAPFILEHEADER and BITMAPINFOHEADER to read/write the file header.

Notes for Linux users:
Since we're using math.h remember to link your program with the -lm pick (gcc and other compilers).

wintrects1964.blogspot.com

Source: https://elcharolin.wordpress.com/2018/11/28/read-and-write-bmp-files-in-c-c/

0 Response to "How to Read in a Bmp File"

Postar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel