Reputation: 13
I am still a noob in c++ and I am currently trying to create a program which loads manually a 256-colors bitmap to an array and prints out the value of each pixel in the consol. It seems those values, most the times, are not correct.
My other outputs (e.g. values inside the info header) are all just fine except for biSizeImage
, which is 5 Bytes. Should not this be something like 25 Bytes?
For test purposes I took two 5 x 5 images. One of these is all black, the other one is totally white.
I would expect for the black, an output similar to this:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
But I am getting:
0 0 0 0 0
0 0 0 0 0
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
With the completely white picture my results are even more strange:
4294967295 255 4294967295 255 4294967295
255 4294967295 255 4294967295 255
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
3452816845 3452816845 3452816845 3452816845 3452816845
Below you can see my current code:
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
using namespace std;
#pragma pack(push,1)
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType; // Specifies the type of file. This member must be BM. (0x4D42)
unsigned int bfSize; // Specifies the size of the file, in bytes.
short bfReserved1; // Reserved; must be set to zero.
short bfReserved2; // Reserved; must be set to zero.
unsigned int bfOffBits; // Specifies the byte offset from the BITMAPFILEHEADER structure to the actual bitmap data in the file.
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
unsigned int biSize; // Specifies the number of bytes required by the BITMAPINFOHEADER structure.
int biWidth; // Specifies the width of the bitmap, in pixels.
int biHeight; // Specifies the height of the bitmap, in pixels.
unsigned short biPlanes; // Specifies the number of planes for the target device. This member must be set to 1.
unsigned short biBitCount; // Specifies the number of bits per pixel. This value must be 1,4, 8, or 24.
unsigned int biCompression; // Specifies the type of compression for a compressed bitmap. Itcan be one of the following values: BI_RGB, BI_RLE8, BI_RLE4
unsigned int biSizeImage; // Specifies the size, in bytes, of the image. It is valid to set this member to zero if the bitmap is in the BI_RGB format.
int biXPelsPerMeter; // Specifies the horizontal resolution, in pixels per meter, of the target device for the bitmap.
int biYPelsPerMeter; // Specifies the vertical resolution, in pixels per meter, of the target device for the bitmap.
unsigned int biClrUsed; // Specifies the number of color indexes in the color table actually used by the bitmap.
unsigned int biClrImportant; // Specifies the number of color indexes that are considered important for displaying the bitmap. If this value is zero, all colors are important.
} BITMAPINFOHEADER;
typedef struct tagRGBPIXEL{
unsigned char b;
unsigned char g;
unsigned char r;
} rgbPIXEL;
#pragma pack(pop)
typedef struct tagBITMAP{
BITMAPFILEHEADER FILEHEADER;
BITMAPINFOHEADER INFOHEADER;
rgbPIXEL* IMAGEDATA;
}BITMAP;
void main (){
string sImageLocation = "C:/BMP.bmp";
BITMAP bmpImage;
FILE* fbmpImage = NULL;
unsigned int ImagePixelAmount = 0;
bool bImageLoaded = false;
do{
//Open the image file
fopen_s(&fbmpImage, sImageLocation.c_str(), "rb");
//Check whether the image could be loaded successfully or not
if(fbmpImage == NULL){
cout << "Loading the image file failed!" << " " << endl;
}
if(fbmpImage != NULL){
cout << "Loaded the image file successfully!" << endl;
bImageLoaded = true;
}
cout << endl;
cout << endl;
cout << endl;
//Read the BITMAP FILE HEADER
fseek(fbmpImage, 0, SEEK_SET);
fread(&bmpImage.FILEHEADER, sizeof(BITMAPFILEHEADER), 1, fbmpImage);
//Check if the image is a valid bitmap file
if(bmpImage.FILEHEADER.bfType != 19778){
bImageLoaded = false;
cout << "Image is not a valid Bitmap file!" << endl;
fclose(fbmpImage);
}
}while(bImageLoaded = false);
//Show the information of the BITMAP FILE HEADER in the consol
cout << "Bitmap File Header Data Values:" << endl;
cout << endl;
cout << "Image Type: " << bmpImage.FILEHEADER.bfType << endl;
cout << "Image Size: " << bmpImage.FILEHEADER.bfSize << " Bytes" << endl;
cout << "Reserved: " << bmpImage.FILEHEADER.bfReserved1 << endl;
cout << "Reserved: " << bmpImage.FILEHEADER.bfReserved2 << endl;
cout << "Byte Offset: " << bmpImage.FILEHEADER.bfOffBits << endl;
cout << endl;
cout << endl;
cout << endl;
//Read the BITMAP INFO HEADER
fread(&bmpImage.INFOHEADER, sizeof(BITMAPINFOHEADER), 1, fbmpImage);
cout << "Bitmap Info Header Data Values: " << endl;
cout << endl;
cout << "Size of Bitmap Info Header: " << bmpImage.INFOHEADER.biSize << " Bytes" << endl;
cout << "Width of Bitmap: " << bmpImage.INFOHEADER.biWidth << " Pixel" << endl;
cout << "Height of Bitmap: " << bmpImage.INFOHEADER.biHeight << " Pixel" << endl;
cout << "Size of Image Data: " << bmpImage.INFOHEADER.biHeight << " Bytes" << endl;
cout << "Bit Count: " << bmpImage.INFOHEADER.biBitCount << " Bits Per Pixel" << endl;
cout << "Amount of color indexes: " << bmpImage.INFOHEADER.biClrUsed << endl;
cout << "Compression: " << bmpImage.INFOHEADER.biCompression << endl;
cout << endl;
cout << endl;
cout << endl;
ImagePixelAmount = bmpImage.INFOHEADER.biHeight * bmpImage.INFOHEADER.biWidth;
//Create space in memory and read in pixel data from the image
bmpImage.IMAGEDATA = (rgbPIXEL*)malloc(sizeof(rgbPIXEL) * ImagePixelAmount);
cout << "Memory for image created" << endl;
fseek(fbmpImage, bmpImage.FILEHEADER.bfOffBits, SEEK_SET);
fread(bmpImage.IMAGEDATA, ImagePixelAmount * sizeof(rgbPIXEL), 1, fbmpImage);
fclose(fbmpImage);
//Show the pixel data in the consol in numbers instead of ASCII-symbols
for(int y =0; y < bmpImage.INFOHEADER.biHeight; y++){
for(int x = 0; x < bmpImage.INFOHEADER.biWidth; x++){
cout << "Red: " <<(unsigned int) bmpImage.IMAGEDATA[y * bmpImage.INFOHEADER.biWidth + x].r << " ";
cout << "Green: " <<(unsigned int) bmpImage.IMAGEDATA[y * bmpImage.INFOHEADER.biWidth + x].g << " ";
cout << "Blue: " <<(unsigned int) bmpImage.IMAGEDATA[y * bmpImage.INFOHEADER.biWidth + x].b << " ";
}
cout << endl;
}
cout << endl;
cout << endl;
cout << endl;
cout << "Press any key to quit the programm" << endl;
_getch();
return;
}
Update:
According to Hans Passant I changed my code to load 24-bit bitmaps. With a red bitmap I would assume the printed values of each pixel being red = 255, green = 0 and blue = 0
. However the actual values I am recieving for each pixel are red = 237, green = 28 and blue = 36
. With any other image I have the same trouble.
Upvotes: 1
Views: 2534
Reputation: 6597
Are you sure that you are reading in a solid pure red (255,0,0 RGB) BMP? I ask because I created one and your program output the following:
Red: 255 Green: 0 Blue: 0 Red: 255 Green: 0 Blue: 0
Red: 0 Green: 0 Blue: 0 Red: 0 Green: 255 Blue: 0
Still not correct, but closer to what you would expect. But why is the second line wrong?
The bits representing the bitmap pixels are packed in rows. The size of each row is rounded up to a multiple of 4 bytes (a 32-bit DWORD) by padding. - source
Here is an excerpt from the Paint generated BMP:
0000 ff00 00ff 0000 0000 ff00 00ff 0000
which is:
00
: Green (0)
00
: Blue (0)
ff
: Red (255)
00
: Green (0)
00
: Blue (0)
ff
: Red (255)
00
: Padding
00
: Padding
00
: Green (0)
00
: Blue (0)
ff
: Red (255)
00
: Green (0)
00
: Blue (0)
ff
: Red (255)
00
: Padding
00
: Padding
Remember, the amount of padding is equal to (width * channels) % 4
, which in this case is (2 * 3) % 4 = 2
, so our two paddings added onto the end of each row of pixels.
I have not had the time to completely check your code, but I do not believe you are accounting for this padding. Note though that a 32-bit (GBRA) BMP does not have this padding as (width * 4) % 4
is always 0
.
Here is a stand-alone program that should work. I ripped out the relevant parts for BMP loading from an older project. You can see where I account for the padding in 24-bit BMP files.
Also, another example from the Wikipedia article.
Edit
Forgot to mention this is a 2x2 red BMP image. The excerpt above is the pixel array, and the file in full is as follows:
424d 4600 0000 0000 0000 3600 0000 2800
0000 0200 0000 0200 0000 0100 1800 0000
0000 1000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 ff00 00ff 0000 0000
ff00 00ff 0000
Upvotes: 2