从24bpp位图获取每个像素的RGB值,以便在C中转换为GBA格式

我想从.bmp文件中读取每个像素的RGB值,因此我可以将bmp转换为适合GBA(GameBoy Advance)的格式。

我需要为每个像素获取RGB,然后将此信息写入文件。

我试图使用结构:

 typedef struct { char signature[2]; unsigned int fileSize; unsigned int reserved; unsigned int offset; }BmpHeader; typedef struct { unsigned int headerSize; unsigned int width; unsigned int height; unsigned short planeCount; unsigned short bitDepth; unsigned int compression; unsigned int compressedImageSize; unsigned int horizontalResolution; unsigned int verticalResolution; unsigned int numColors; unsigned int importantColors; }BmpImageInfo; typedef struct { unsigned char blue; unsigned char green; unsigned char red; unsigned char reserved; }Rgb; typedef struct { BmpHeader header; BmpImageInfo info; Rgb colors[256]; unsigned short image[1]; }BmpFile; 

但我只需要RGB结构。 所以让我说我读“in.bmp”:

 FILE *inFile, *outFile; inFile = fopen("C://in.bmp", "rb"); Rgb Palette[256]; for(i=0;i<256;i++) { fread(&Palette[i],sizeof(Rgb),1,inFile); } fclose(inFile); 

它是否正确? 如何仅将RGB信息写入文件?

您首先需要获得嵌入式调色板中可用的颜色数量。 这在DIB标题中可用。

然后,您可以读取包含调色板的所有颜色组件。

您可以看到所有标题信息,如偏移量,以了解在哪里寻找: http : //en.wikipedia.org/wiki/BMP_file_format 。

这应该工作:(编辑:添加代码写入文件)

 FILE *inFile, *outFile; BMPHeader header; BMPImageInfo info; RGB *palette, *p; int i = 0; inFile = fopen("C://in.bmp", "rb"); if( !inFile ) return; if( fread(&header, sizeof(BMPHeader), 1, inFile) != 1 ) return; // Manage error and close file if( fread&info, sizeof(BMPImageInfo), 1, inFile) != 1 ) return; // Manage error and close file if( info.numColors > 0 ) { palette = (RGB*)malloc(sizeof(RGB) * info.numColors); if( fread(palette, sizeof(RGB), info.numColors, inFile) != info.numColors ) return; // manage error and close file } fclose(inFile) // Binary method => if read later by another computer outFile = fopen("path", "wb"); if( !outFile ) return; if( fwrite(&info.numColors, sizeof(unsigned int), 1, outFile) != 1 ) return; // Manage Error and close file if( fwrite(&palette, sizeof(RGB), info.numColors, outFile) != info.numColors ) return; // Manage error and close file fclose(outFile); // Text method => if read later by human outFile = fopen("path", "w"); if( !outFile ) return; for( i=0; ired, p->green, p->blue) < 0 ) return; // Manage error and close file } fclose(outFile); 

如果你在Windows上,你可以使用win32中的LoadBitmap函数

然后给定句柄将其转换为DIB位图并以这种方式获得像素

我做了一些测试并扩展了Patrice的程序。 我不是一个优秀的C程序员,所以所有的功劳都归他所有,我的部分并不像他那样优雅 – 对不起。

警告:未来巨大的源代码。

 #include  #pragma pack(2) typedef struct { char signature[2]; unsigned int fileSize; unsigned int reserved; unsigned int offset; } BmpHeader; typedef struct { unsigned int headerSize; unsigned int width; unsigned int height; unsigned short planeCount; unsigned short bitDepth; unsigned int compression; unsigned int compressedImageSize; unsigned int horizontalResolution; unsigned int verticalResolution; unsigned int numColors; unsigned int importantColors; } BmpImageInfo; typedef struct { unsigned char blue; unsigned char green; unsigned char red; //unsigned char reserved; Removed for convenience in fread; info.bitDepth/8 doesn't seem to work for some reason } Rgb; int main( int argc, char **argv ) { FILE *inFile; BmpHeader header; BmpImageInfo info; Rgb *palette; int i = 0; printf( "Opening file %s for reading.\n", argv[1] ); inFile = fopen( argv[1], "rb" ); if( !inFile ) { printf( "Error opening file %s.\n", argv[1] ); return -1; } if( fread(&header, 1, sizeof(BmpHeader), inFile) != sizeof(BmpHeader) ) { printf( "Error reading bmp header.\n" ); return -1; } if( fread(&info, 1, sizeof(BmpImageInfo), inFile) != sizeof(BmpImageInfo) ) { printf( "Error reading image info.\n" ); return -1; } if( info.numColors > 0 ) { printf( "Reading palette.\n" ); palette = (Rgb*)malloc(sizeof(Rgb) * info.numColors); if( fread(palette, sizeof(Rgb), info.numColors, inFile) != (info.numColors * sizeof(Rgb)) ) { printf( "Error reading palette.\n" ); return -1; // error } } printf( "Opening file %s for writing.\n", argv[2] ); FILE *outFile = fopen( argv[2], "wb" ); if( !outFile ) { printf( "Error opening outputfile.\n" ); return -1; } Rgb *pixel = (Rgb*) malloc( sizeof(Rgb) ); int read, j; for( j=0; jred, pixel->green, pixel->blue ); } if( read % 4 != 0 ) { read = 4 - (read%4); printf( "Padding: %d bytes\n", read ); fread( pixel, read, 1, inFile ); } } printf( "Done.\n" ); fclose(inFile); fclose(outFile); printf( "\nBMP-Info:\n" ); printf( "Width x Height: %ix %i\n", info.width, info.height ); printf( "Depth: %i\n", (int)info.bitDepth ); return 0; } 

该程序读出存储在文件中的像素信息。 它考虑了填充,但仅适用于每像素颜色深度为24位的bmps(如果需要其他深度,则必须自定义Rgb结构)。 希望这会对你有所帮助,但正如我所说,它只是Patrice代码的扩展。

这是我的testfile的示例输出:

 $ ./a.out test.bmp out.txt Opening file test.bmp for reading. Opening file out.txt for writing. ------ Row 1 Pixel 1: 0 0 0 Pixel 2: 0 0 0 Pixel 3: 0 0 0 Pixel 4: 0 0 0 Pixel 5: 0 0 0 Padding: 1 bytes ------ Row 2 Pixel 1: 0 0 0 Pixel 2: 232 33 33 Pixel 3: 0 0 0 Pixel 4: 232 33 33 Pixel 5: 0 0 0 Padding: 1 bytes ------ Row 3 Pixel 1: 0 0 0 Pixel 2: 0 0 0 Pixel 3: 232 33 33 Pixel 4: 0 0 0 Pixel 5: 0 0 0 Padding: 1 bytes ------ Row 4 Pixel 1: 0 0 0 Pixel 2: 232 33 33 Pixel 3: 0 0 0 Pixel 4: 232 33 33 Pixel 5: 0 0 0 Padding: 1 bytes ------ Row 5 Pixel 1: 0 0 0 Pixel 2: 0 0 0 Pixel 3: 0 0 0 Pixel 4: 0 0 0 Pixel 5: 0 0 0 Padding: 1 bytes Done. BMP-Info: Width x Height: 5 x 5 Depth: 24 

编辑:是的,我的图像显示红十字。 请注意,图像是上下颠倒存储的,因此文件的第1行实际上是图像的第5行。 D’哦,忘了写一些文件,代码打开,但这是作为一个练习由你决定;)。

如果你保证它是一个未压缩的24bpp位图并且它的宽度可以被4整除,那么它相对简单:

  1. 在文件开头读取BmpHeader
  2. 如果没有寻求,请阅读BmpImageInfo
  3. 文件的开头寻找BmpHeaderoffset字节。 请注意,在24位位图中没有调色板(至少不是我们关心的调色板)!
  4. 读取BGR三元组(按此顺序,此处没有reserved未使用的成员)。 将有( BmpImageInfo的成员) width * abs(height)三胞胎。 我记得,如果height是正值(标准情况),你读到的第一行颜色将是图像的底线 ,从那里上升。 但是,如果height为负,则文件中的第一行颜色是图像的顶部 ,从那里向下。

如果你不能做出这些保证,那么事情会变得更加复杂。

免责声明:我在这里无偿地吹响自己的号角。 几年前,我写了一个小的(一个源文件)实用程序,以便携式(100%ANSI C)方式完成您所说的内容: glbmp libbmpread 。 它的来源可能会解释你的问题 – 它处理任何位深度的未压缩(无RLE)位图,并且应该在GBA上正常运行。

请参阅.bmp文件格式的维基百科页面,该格式提供了有关文件结构的大量信息,应该可以帮助您解析它。

http://en.wikipedia.org/wiki/BMP_file_format

在您的代码中,您首先必须读取数据的起始地址(在文件头中指定)和图像的高度。 然后寻求这个位置。 之后,您逐行读取一行(标题指定每个像素的位数),并且必须在其末尾处理32位填充。 请注意,在24位图像(RGB)中,信息以BGR顺序存储。 此外,如果高度值不是负值,则图像被倒置存储。

我不熟悉BMP文件格式,但您不需要先读取标题信息吗? 就像是:

 BmpHeader header; fread(&header,sizeof(BmpHeader),1,inFile); 

并阅读您需要的详细图像信息:

 BmpImageInfo info; fread(&info,sizeof(BmpImageInfo),1,inFile); 

并阅读调色板信息。

一旦你有了,你就会知道文件大小和数据偏移量。 您可以预先分配足够的空间并一次性读入,这可能是最简单的。 或者,你可以在块中读入并解析你正在进行的操作(减少没有足够内存的可能性,但解析更复杂)。

您还可以从信息部分了解是否启用了压缩,图像尺寸等。

如果您正在同时阅读所有内容,请跳转到数据的偏移量,并执行以下操作:

 Rgb* rgb = offset; blueVal = rgb->blue; greenVal = rgb->green; redVal = rgb->red; rgb += sizeof( Rgb ); 

等等。 显然,代码不会检查错误,缓冲区结束等等,因此您需要这样做。 您可能还必须阅读调色板信息以了解图像数据。

或者,正如其他人所说,请查看维基百科上的格式规范

如果BMP文件有调色板,则下面的代码应该有效:

  FILE *inFile, *outFile; inFile = fopen("C:/in.bmp", "rb"); Rgb Palette[256]; if ( inFile ) { // Bypass headers fseek(inFile, sizeof(BmpHeader) + sizeof(BmpImageInfo), SEEK_SET); // Load the whole palette fread(Palette, sizeof(Palette), 1, inFile); fclose(inFile); } 

您可能会发现查看我多年前为编写BMP文件而编写的一些C代码很有用,位于:

http://david.tribble.com/src/bmp/bmp.html

我相信它可以处理各种像素位大小(1/2/4/8/24)以及RLE压缩。