我正在嘗試在 C 中翻轉 BMP 影像。我遇到了一個問題,當我嘗試讀取 BMP 標頭時,一切正常且值正確,但是當我嘗試讀取 DIB 標頭時,我得到了所有值除了影像大小(原始位圖資料)。我得到一個零,考慮到我在 BMP 標頭中得到了檔案大小,這真的很奇怪。我嘗試除錯代碼并在線查找問題,但這并沒有多大幫助。
這是我的代碼:
#include <stdlib.h>
typedef unsigned int int32;
typedef unsigned short int int16;
typedef unsigned char char8;
struct BITMAP_header {
char name[2]; // BM
int32 size;
int garbage; // ?
int32 image_offset; //offset from where the image starts in the file
};
struct DIB_header {
int32 header_size;
int32 width;
int32 height;
int16 colorplanes;
int16 bitsperpixel;
int32 compression;
int32 image_size;
int32 temp[4];
};
struct RGB
{
char8 blue;
char8 green;
char8 red;
};
struct Image {
struct RGB** rgb;
int height;
int width;
};
struct Image readImage(FILE *fp, int height, int width) {
struct Image pic;
pic.rgb = (struct RGB**)malloc(height * sizeof(void*)); // pointer to a row of rgb data (pixels)
pic.height = height;
pic.width = width;
for (int i = height-1; i >=0 ; i--)
{
pic.rgb[i] = (struct RGB*)malloc(width * sizeof(struct RGB)); // allocating a row of pixels
fread(pic.rgb[i], width, sizeof(struct RGB), fp);
}
return pic;
}
void freeImage(struct Image pic) {
for (int i = pic.height -1; i>= 0; i--)
{
free(pic.rgb[i]);
}
free(pic.rgb);
}
void createImage(struct BITMAP_header header, struct DIB_header dibheader, struct Image pic) {
FILE* fpw = fopen("new.bmp", "w");
if (fpw == NULL) {
return 1;
}
fwrite(header.name, 2, 1, fpw);
fwrite(&header.size, 3 * sizeof(int), 1, fpw);
fwrite(&dibheader, sizeof(struct DIB_header), 1, fpw);
int count = 0;
for (int i = pic.height - 1; i >= 0; i--) {
fwrite(pic.rgb[count], pic.width, sizeof(struct RGB), fpw);
count ;
}
fclose(fpw);
}
int openbmpfile() {
FILE* fp = fopen("C:\\Users\\User\\Downloads\\MARBLES.BMP", "rb"); // read binary
if (fp == NULL) {
return 1;
}
struct BITMAP_header header;
struct DIB_header dibheader;
fread(header.name, 2, 1, fp); //BM
fread(&header.size, 3 * sizeof(int), 1, fp); // 12 bytes
printf("First two characters: %c%c\n", header.name[0], header.name[1]);
if ((header.name[0] != 'B') || (header.name[1] != 'M')) {
fclose(fp);
return 1;
}
printf("Size: %d\n", header.size);
printf("Offset: %d\n", header.image_offset);
fread(&dibheader.header_size, sizeof(struct DIB_header) , 1, fp);
printf("Header size: %d\nWidth: %d\nHeight: %d\nColor planes: %d\nBits per pixel: %d\nCompression: %d\nImage size: %d\n",
dibheader.header_size, dibheader.width, dibheader.height, dibheader.colorplanes, dibheader.bitsperpixel,
dibheader.compression, dibheader.image_size);
if ((dibheader.header_size != 40) || (dibheader.compression != 0) || (dibheader.bitsperpixel != 24)) {
fclose(fp);
return 1;
}
fseek(fp, header.image_offset, SEEK_SET);
struct Image image = readImage(fp, dibheader.height, dibheader.width);
createImage(header, dibheader, image);
fclose(fp);
freeImage(image);
return 0;
}
int main() {
openbmpfile();
}
我還嘗試通過將標頭大小減少檔案大小來手動寫入大小,但它不起作用。
提前致謝!
uj5u.com熱心網友回復:
格式期望結構大小為 14 和 40 為BITMAP_header和DIB_header。但是編譯器對齊結構,大小會有所不同。您必須使用特定于編譯器的標志來禁用結構對齊(不清楚您使用的是哪個編譯器)。RGB結構上也有同樣的問題。
還有位元組序依賴性,事實上位圖不以 RGB 格式存盤像素,它翻轉位元組。
typedef unsigned int int32;
這將隱藏unsigned為signed. 應該對結構中的某些值進行簽名。例如,高度可能是負數,表示它應該被翻轉。
你可以一一讀取整數,使用
void readint(FILE *f, int *val, int size)
{
unsigned char buf[4];
fread(buf, size, 1, f);
*val = 0;
for (int i = size - 1; i >= 0; i--)
*val = (buf[i] << (8 * i));
}
void writeint(FILE* f, int val, int size)
{
unsigned char buf[4];
for (int i = size - 1; i >= 0; i--)
buf[i] = (val >> 8 * i) & 0xff;
fwrite(buf, size, 1, f);
}
然后你讀取一個 24 位位圖,如下所示:
fread(header.name, 2, 1, fp); //BM
readint(fp, &header.size, 4);
readint(fp, &header.garbage, 4);
readint(fp, &header.image_offset, 4);
readint(fp, &dibheader.header_size, 4);
readint(fp, &dibheader.width, 4);
readint(fp, &dibheader.height, 4);
readint(fp, &dibheader.colorplanes, 2);
readint(fp, &dibheader.bitsperpixel, 2);
readint(fp, &dibheader.compression, 4);
readint(fp, &dibheader.image_size, 4);
readint(fp, &dibheader.temp[0], 4);
readint(fp, &dibheader.temp[1], 4);
readint(fp, &dibheader.temp[2], 4);
readint(fp, &dibheader.temp[3], 4);
char *buf = malloc(dibheader.image_size);
if (!buf)
return 0;
fread(buf, 1, dibheader.image_size, fp);
還有其他一些問題你必須考慮,例如位圖的寬度對齊等。你想從寬度是 4 的倍數的 24 位位圖開始。
要寫入位圖,使用二進制標志,以相同的順序寫入
FILE* fout = fopen("new.bmp", "wb");
if (fout == NULL) return 0;
fwrite(header.name, 1, 2, fout);
writeint(fout, header.size, 4);
writeint(fout, header.reserved, 4);
writeint(fout, header.image_offset, 4);
writeint(fout, info.header_size, 4);
writeint(fout, info.width, 4);
writeint(fout, info.height, 4);
writeint(fout, info.colorplanes, 2);
writeint(fout, info.bitsperpixel, 2);
writeint(fout, info.compression, 4);
writeint(fout, info.image_size, 4);
writeint(fout, info.temp[0], 4);
writeint(fout, info.temp[1], 4);
writeint(fout, info.temp[2], 4);
writeint(fout, info.temp[3], 4);
fwrite(buf, 1, info.image_size, fout);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/381461.html
