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

发布于 2024-08-07 11:04:03 字数 1242 浏览 10 评论 0原文

我想从 .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 信息写入文件?

I want to read the RGB values for each pixel from a .bmp file, so I can convert the bmp into a format suitable for GBA (GameBoy Advance).

I need to get just the RGB for each pixel and then write this information to a file.

I am trying to use the <windows.h> structures:

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;

but I only need RGB struct. So let's say I read "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);

Is this correct?
How do I write only the RGB information to a file?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

囚你心 2024-08-14 11:04:03

如果您使用的是 Windows,则可以使用 LoadBitmap 来自 win32 的函数

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

If you are on windows you can use the LoadBitmap function from win32

then given the handle convert it to a DIB bitmap and get to the pixels that way

盛装女皇 2024-08-14 11:04:03

我做了一些测试并稍微扩展了帕特里斯的程序。我不是一个优秀的 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 结构)。希望这对您有帮助,但正如我所说,这只是帕特里斯代码的扩展。

这是我的测试文件的示例输出:

$ ./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'oh 忘记写一些东西来保存代码打开的文件,但这留给你作为练习;)。

I did a bit of testing and extended Patrice's program a bit. I'm not a good C programmer, so all credit goes to him and my parts aren't as elegant as his - sorry for that.

Warning: huge source code ahead.

#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;

}

This program reads out the pixel information stored in the file. It takes the padding into account but only works with bmps with a 24 bits per pixel color depth (If you need other depths, you'll have to customize the Rgb struct). Hope this helps you, but as I said, it's just an extension of Patrice's code.

Here's a sample output from my 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

Edit: Yes, my image is displaying a red cross. Note that the image is stored upside-down so row 1 of the file is actually row 5 of the image. D'oh forgot to write something to file the code opens, but this is left as an excercise up to you ;).

¢好甜 2024-08-14 11:04:03

您首先需要获取嵌入调色板中可用的颜色数量。这可以在 DIB 标头中找到。

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

您可以查看所有标头信息(例如偏移量)以了解要查找的位置: http://en.wikipedia.org/wiki /BMP_文件_格式

这应该有效:(编辑:添加代码以写入文件)

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);

You need first to get the number of colors available in the embedded palette. This is available in the DIB Header.

Then you can read all color components that contain the palette.

You can see all header information like offset to know whereto seek : http://en.wikipedia.org/wiki/BMP_file_format.

This should work: (Edit: Add code to write in file)

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);
雨夜星沙 2024-08-14 11:04:03

如果您保证它是未压缩的 24bpp 位图并且其宽度可以被 4 整除,则相对简单:

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

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

免责声明:我在这里无缘无故地自吹自擂。几年前,我编写了一个小型(一个源文件)实用程序,可以在便携式(100% ANSI C)中完全执行您所说的操作方式:glbmp libbmpread。它的来源可能会对您的问题有所帮助——它可以处理任何位深度的未压缩(无 RLE)位图,并且应该在 GBA 上运行良好。

If you're guaranteed that it's an uncompressed 24bpp bitmap and its width is divisible by 4, it's relatively simple:

  1. Read a BmpHeader at the start of the file.
  2. Without seeking, read a BmpImageInfo.
  3. Seek to the BmpHeader's offset bytes from the beginning of the file. Note that there is no palette (at least, not one we care about) in 24-bit bitmaps!
  4. Read BGR triplets (in that order, and there's no reserved unused member here). There will be (BmpImageInfo's members) width * abs(height) triplets. As I recall, if height is positive (the standard case), the first line of color you read will be the bottom line of the image, going up from there. If height is negative, though, the first line of color in the file is the top of the image, going down from there.

If you can't make those guarantees, then things get a good deal more complicated.

Disclaimer: I'm gratuitously tooting my own horn here. Years ago I wrote a tiny (one source file) utility to do exactly what you're talking about, in a portable (100% ANSI C) way: glbmp libbmpread. Its source might shed some light on your problem--it handles uncompresed (no RLE) bitmaps of any bit depth, and should run fine on a GBA.

一萌ing 2024-08-14 11:04:03

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

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

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

See wikipedia page of .bmp file format which provides lots of information about the structure of the file and should help you to parse it.

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

In your code you first have to read the starting address of the data (specified in file header) and the height of the image. Then seek to this position. After that you read in one row pixel by pixel (the header specifies how many bits per pixel) and have to take care of the 32-bit padding at the end of it. Note that in a 24-bit image (RGB) the information is stored in BGR order. Also if the height value is not negative, the image is stored upside down.

你是我的挚爱i 2024-08-14 11:04:03

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

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

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

You might find it useful to look at some C code I wrote many years ago for reading and writing BMP files, located at:

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

I believe it handles the various pixel bit sizes (1/2/4/8/24) as well as RLE compression.

策马西风 2024-08-14 11:04:03

我对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 );

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

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

I'm not familiar with the BMP file format, but wouldn't you need to read in the header information first? Something like:

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

and read in detailed image information, which you'll need:

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

and read in palette information as well.

once you have that you will know the file size and data offset. You could pre-allocate sufficient space and read in all at once, which may be simplest. Alternatively you could read in in chunks and parse as you're going (reduces chance of not having enough memory, but parsing is more complicated).

You'll also know from the info section if compression is enabled, image dimensions etc.

If you're reading in all at once, jump to the offset of the data, and do something like:

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

and so on. Obviously that code isn't checking for errors, end of buffer, and so on, so you'll need to do that. You'll probably also have to read in palette information to make sense of the image data.

Or, as someone else said, look at the format spec on Wikipedia

℉絮湮 2024-08-14 11:04:03

如果 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);
  }

If the BMP file has a palette then the below code should work:

  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);
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文