从 24bpp 位图获取每个像素的 RGB 值,以便在 C 中转换为 GBA 格式
题
我想读取每个像素的 RGB 值 .bmp
文件,这样我就可以转换 bmp
转换为适合 GBA (GameBoy Advance) 的格式。
我需要获取每个像素的 RGB,然后将此信息写入文件。
我正在尝试使用 <windows.h>
结构:
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。组织/维基/ 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; i<info.numColors; ++i )
{
p = &palette[i];
if( fprintf(outFile, "R:%d, G:%d, B:%d\n", p->red, p->green, p->blue) < 0 )
return; // Manage error and close file
}
fclose(outFile);
其他提示
如果您使用的是Windows,你可以使用从Win32的LoadBitmap 功能
然后给出的处理将其转换为位图DIB并获得像素这种方式
我做了位测试和扩展帕特里斯的程序的位。我不是一个很好的C程序员,因此所有归功于他和我的部分不能作为他的优雅 - 为此后悔
警告:提前巨源代码
#include <stdio.h>
#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; j<info.height; j++ ) {
printf( "------ Row %d\n", j+1 );
read = 0;
for( i=0; i<info.width; i++ ) {
if( fread(pixel, 1, sizeof(Rgb), inFile) != sizeof(Rgb) ) {
printf( "Error reading pixel!\n" );
return -1;
}
read += sizeof(Rgb);
printf( "Pixel %d: %3d %3d %3d\n", i+1, pixel->red, 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: %i x %i\n", info.width, info.height );
printf( "Depth: %i\n", (int)info.bitDepth );
return 0;
}
此程序读出存储在文件中的像素信息。这需要填充到,但只有在每一个像素的颜色深度24位BMP的工作(如果你需要其他的深处,你将不得不自定义RGB结构)。希望这可以帮助你,但正如我所说,这只是帕特里斯代码的扩展。
下面是从我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'哦,忘了写东西以文件的代码打开,但留下作为一个锻炼; Tibial给你;)
。如果你保证它是一个未压缩的 24bpp 位图并且它的宽度可以被 4 整除,那么它相对简单:
- 读一读
BmpHeader
在文件的开头。 - 无需寻找,阅读
BmpImageInfo
. - 寻求到
BmpHeader
的offset
字节来自 文件的开头. 。请注意,24 位位图中没有调色板(至少我们不关心)! - 读取 BGR 三元组(按此顺序,并且没有
reserved
此处未使用的成员)。将有 (BmpImageInfo
的成员)width * abs(height)
三胞胎。我记得,如果height
为正(标准情况),您读取的第一行颜色将是 底部 图像的线,从那里向上。如果height
是负数,但文件中的第一行颜色是 顶部 的图像,从那里向下。
如果你不能做出这些保证,那么事情就会变得更加复杂。
免责声明:我在这里无缘无故地自吹自擂。 几年前,我编写了一个小型(一个源文件)实用程序,以一种可移植(100% ANSI C)的方式完全完成您所说的操作: GLBMP 库文件读取. 。它的来源可能会对您的问题有所帮助——它可以处理任何位深度的未压缩(无 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);
}
您可能会发现它有用来看看一些C代码,我很多年前写的读取和写入BMP文件,位于:
http://david.tribble.com/src/bmp/bmp.html
我相信它处理的各种像素位大小(1/2/4/8/24)以及RLE压缩。