我编写了一个原始的Bitmap Writer,用于准备位图头,计算数据部分并将其写为二进制文件。
问题是,该程序工作在800x600分辨率,但不能用于某种任意分辨率。
#include <stdio.h>
#include <stdlib.h> // malloc()
#include <string.h>
/*
* File Write , check this link : https://www.codingunit.com/c-tutorial-binary-file-io
*
*/
typedef enum { FALSE, TRUE } boolean;
/* For 54 byte header data
*
* http://blog.paphus.com/blog/2012/08/14/write-your-own-bitmaps/
*/
#pragma pack(push,1)
typedef struct BitmapHeaderType {
unsigned char b0; // 0
unsigned char b1; // 1
unsigned int fullFileSize; // 2...5
unsigned int reserved; // 6...9
unsigned int pixelOffset; // 10..13 HEADER SIZE
unsigned int bitmapInfoHeaderSize; // 14..17 BITMAP INFO HEADER SIZE
unsigned int pixelWidth; // 18..21 image width
unsigned int pixelHeight; // 22..25 image height
unsigned short int numberOfColorPlanes; // 26..27 the number of color planes
unsigned short int bitPerPixel; // 28..29 24bit, 32bit, bit size
unsigned int compessionState; // 30..33 compression state, 0 for disable compression
unsigned int sizeOfRawPixel; // 34..37 size of pixel data including paddings (24 bit padding changes data section)
unsigned int horizontalResolution; // 38..41 just leave 2835
unsigned int verticalResolution; // 42..45 just leave 2835
unsigned int numberOfColors; // 46..49 set 0 for default
unsigned int numberOfImportantColors; // 50..53 set 0 for default
} BitmapHeader;
#pragma pack(pop)
void handleBitmapHeader(BitmapHeader *header, int width, int height);
int closestMultipleOfFour(int num);
void writeToFile(unsigned char* bytes, int len, char fileName[]);
void setPixel(unsigned char *data, int x, int y, unsigned char red, unsigned char green, unsigned char blue, int width, int height);
int main()
{
//int width = 800; // compiling OK, runtime OK
int width = 100; // compiling OK, runtime FAILED
int height = 600;
BitmapHeader *header = (BitmapHeader *)malloc(sizeof(BitmapHeader));
handleBitmapHeader(header, width, height);
unsigned char *data = (unsigned char *)malloc(header->sizeOfRawPixel);
unsigned char *bitmap = (unsigned char *)malloc(header->fullFileSize);
// left top corner
setPixel(data, 0 , 0 , 255, 0, 0, width, height);
setPixel(data, 0 , 1 , 255, 0, 0, width, height);
setPixel(data, 1 , 0 , 255, 0, 0, width, height);
setPixel(data, 1 , 1 , 255, 0, 0, width, height);
// right top corner
setPixel(data, width-1 , 0 , 255, 0, 0, width, height);
setPixel(data, width-1 , 1 , 255, 0, 0, width, height);
setPixel(data, width-2 , 0 , 255, 0, 0, width, height);
setPixel(data, width-2 , 1 , 255, 0, 0, width, height);
// left bottom corner
setPixel(data, 0 , height-1 , 255, 0, 0, width, height);
setPixel(data, 0 , height-2 , 255, 0, 0, width, height);
setPixel(data, 1 , height-1 , 255, 0, 0, width, height);
setPixel(data, 1 , height-2 , 255, 0, 0, width, height);
// right bottom corner
setPixel(data, width-1 , height-1 , 255, 0, 0, width, height);
setPixel(data, width-1 , height-2 , 255, 0, 0, width, height);
setPixel(data, width-2 , height-1 , 255, 0, 0, width, height);
setPixel(data, width-2 , height-2 , 255, 0, 0, width, height);
// copy header to bitmap
memcpy(bitmap, header, header->pixelOffset);
// copy data to bitmap
memcpy(bitmap+header->pixelOffset, data, header->fullFileSize);
char fileName[] = "sampleBitmap.bmp";
// write
writeToFile((unsigned char *)bitmap , header->fullFileSize, fileName);
free(header);
free(data);
free(bitmap);
return 0;
}
void handleBitmapHeader(BitmapHeader *header, int width, int height)
{
// Calculate row with padding
int rowWithPadding = closestMultipleOfFour(width*3);
int rawSize = height * rowWithPadding;
printf("Row With Padding : %4d\n", rowWithPadding);
printf("Raw Size : Decimal[%4d], Hex[%4x]\n", rawSize, rawSize);
header->b0 = 'B';
header->b1 = 'M';
header->fullFileSize = rawSize + 54;
header->reserved = 0x00000000;
header->pixelOffset = 54;
header->bitmapInfoHeaderSize = 40;
header->pixelWidth = (unsigned int)width;
header->pixelHeight = (unsigned int)height;
header->numberOfColorPlanes = 1;
header->bitPerPixel = 24;
header->compessionState = 0;
header->sizeOfRawPixel = (unsigned int) rawSize;
header->horizontalResolution = 0x2835;
header->verticalResolution = 0x2835;
header->numberOfColors = 0;
header->numberOfImportantColors = 0;
}
int closestMultipleOfFour(int num)
{
return (num + 3) & ~0x03;
}
void writeToFile(unsigned char* bytes, int len, char fileName[])
{
FILE *filePtr;
printf("HIT A : len = %d\n", len);
filePtr = fopen(fileName, "wb"); // wb for write binary
printf("HIT B\n");
if(!filePtr)
{
printf("ERROR::writeToFile()::Unable to open file : \"%s\"\n", fileName);
return;
}
fwrite(bytes, len, 1, filePtr);
fclose(filePtr);
}
void setPixel(unsigned char *data, int x, int y, unsigned char red, unsigned char green, unsigned char blue, int width, int height)
{
y = height-1-y;
int index = 0;
int padSize = 0;
if(x < width && y == 0) // no need to calculate padding
index = x * 3;
else
{
boolean isPadding = ( (width*3) % 4 == 0) ? FALSE : TRUE;
if(isPadding == TRUE) {
padSize = closestMultipleOfFour(width * 3);
} else {
index = (y*width + x)*3;
}
}
int bytes = 0;
*(data + index+padSize + bytes++) = blue;
*(data + index+padSize + bytes++) = green;
*(data + index+padSize + bytes) = red;
}
请通知以下行;
//int width = 800; // compiling OK, runtime OK
int width = 100; // compiling OK, runtime FAILED
int height = 600;
如果您只是以800x600分辨率运行,那么
int width = 800; // compiling OK, runtime OK
/int width = 100; // compiling OK, runtime FAILED
int height = 600;
程序运行成功。并且还通知对于这两个条件,程序正在成功编译。
我尝试使用gcc和MS VS,两种分辨率的行为相同。
我也尝试用MS VS调试程序但是在调试时,程序触发了一个断点,然后直接问我一个dll(我不是MS的MS调试专家)
似乎有问题的部分是writeToFile()
函数中存在的这一行;
filePtr = fopen(fileName, "wb"); // wb for write binary
关于我哪里出错的任何想法?
答案 0 :(得分:3)
程序崩溃了,因为这行正在访问超出范围的内存:
memcpy(bitmap + header->pixelOffset, data, header->fullFileSize);
我认为你需要的是
memcpy(bitmap + header->pixelOffset, data, header->sizeOfRawPixel);
因为bitmap
是一个包含header
和原始数据的缓冲区。