我想从已存储的RGB值生成BMP文件。
我在OS X上进行编程,因此无法使用预定义的BMP标头。
我尝试过以下操作,但预览说文件已损坏。
void bitmap(Image * image) {
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;
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;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
bfh.bfType = 0x4d42;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bfh.bfOffBits = 0x36;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = image->getWidth();
bih.biHeight = image->getHeight();
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0x0ec4;
bih.biYPelsPerMeter = 0x0ec4;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE *file = fopen("a.bmp", "wb");
if (!file) {
cout << "File not found";
return;
}
fwrite(&bfh, 1, sizeof(bfh), file);
fwrite(&bih, 1, sizeof(bfh), file);
for (int x = 0; x < image->getWidth(); x++) {
for (int y = 0; y < image->getHeight(); y++) {
float r = image->getPixel(x, y).r;
float g = image->getPixel(x, y).g;
float b = image->getPixel(x, y).b;
fwrite(&r, 1, 1, file);
fwrite(&g, 1, 1, file);
fwrite(&b, 1, 1, file);
}
}
}
我不确定我是否正确理解了结构。我已经尝试过阅读但我必须遗漏一些东西。
这是文件的十六进制输出
42 4D 00 02 38 00 00 00 00 00 00 00 36 00 00 00 28 00 00 00 80 02 00 00 E0 01 00 00 01 00 18 00 00 00 00 00 00 00 00 00 C4 0E 00 00 C4 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
答案 0 :(得分:8)
这个问题很好,因为它启发了一些陷阱。以下是代码中的所有问题。通过修复它们,一切都按预期工作:
您的bfSize字段不包含位图的大小
常规:BITMAPFILEHEADER
变为大,因为它以2字节值开头,后跟4字节值。填充规则说这个结构第一个字段将是4个字节而不是2个。解决方案:通过从BITMAPFILEHEADER
中排除它来单独编写幻数:
unsigned short magic=0x4d42; //This field is _not_ included in `BITMAPFILEHEADER`
fwrite(&magic,1,sizeof(magic),file);
// Write the remaining part of the header (if you did not get an I/O error...)
此修改还意味着BITMAPFILEHEADER::bfSize
为2+sizeof(BITMAPFILEHADER) + sizeof(BITMAPINFOHEADER)+ biWidth*biHeight*3
您已经通过sizeof(bfh)
展位bfh
和bih
,因此完整的BITMAPINFOHEADER
永远不会被写入
BMP文件格式要求每条扫描线都是DWORD对齐的,因此根据宽度,您可能需要在每条扫描线后写入零字节
如果您认为第一条扫描线已启动,则您的图像是颠倒的,因为您的身高是正面的。
位图文件以行方式存储,因此您应该在最里面的循环中遍历 x - 坐标
您还编写了错误的像素值。你应该写unsigned char
而不是浮点数。您写的是正确的大小(1个字节),但它不是正确的值:
unsigned char r = image->getPixel(x, y).r/255; //If 1.0f is white.
此外,位图是BGR(A)而不是RGB(A)。
假设你有一个很好的宽度,一个工作的例子是
void bitmap()
{
typedef struct /**** BMP file header structure ****/
{
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER;
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;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
/* Magic number for file. It does not fit in the header structure due to alignment requirements, so put it outside */
unsigned short bfType=0x4d42;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = 2+sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+640*480*3;
bfh.bfOffBits = 0x36;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = 640;
bih.biHeight = 480;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 5000;
bih.biYPelsPerMeter = 5000;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
FILE *file = fopen("a.bmp", "wb");
if (!file)
{
printf("Could not write file\n");
return;
}
/*Write headers*/
fwrite(&bfType,1,sizeof(bfType),file);
fwrite(&bfh, 1, sizeof(bfh), file);
fwrite(&bih, 1, sizeof(bih), file);
/*Write bitmap*/
for (int y = bih.biHeight-1; y>=0; y--) /*Scanline loop backwards*/
{
for (int x = 0; x < bih.biWidth; x++) /*Column loop forwards*/
{
/*compute some pixel values*/
unsigned char r = 255*((float)x/bih.biWidth);
unsigned char g = 255*((float)y/bih.biHeight);
unsigned char b = 0;
fwrite(&b, 1, 1, file);
fwrite(&g, 1, 1, file);
fwrite(&r, 1, 1, file);
}
}
fclose(file);
}
答案 1 :(得分:-1)
user877329的代码对我有用。 (因为我使用C,所以做了一些小的更改) 注意:请注意变量的“大小”,因为它可能有所不同,具体取决于您编译的平台。