Obtendo valores de RGB para cada pixel de um bitmap de 24bpp para conversão em formato GBA em C

StackOverflow https://stackoverflow.com/questions/1531268

  •  20-09-2019
  •  | 
  •  

Pergunta

Eu quero ler os valores RGB para cada pixel de um .bmp arquivo, para que eu possa converter o bmp em um formato adequado para o GBA (Gameboy Advance).

Preciso obter apenas o RGB para cada pixel e, em seguida, escrever essas informações em um arquivo.

Estou tentando usar o <windows.h> Estruturas:

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;

Mas eu só preciso de RGB Struct. Então, digamos que eu li "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);

Isso está correto? Como escrevo apenas as informações RGB em um arquivo?

Foi útil?

Solução

Você precisa primeiro obter o número de cores disponíveis na paleta incorporada. Isso está disponível no cabeçalho DIB.

Em seguida, você pode ler todos os componentes coloridos que contêm a paleta.

Você pode ver todas as informações do cabeçalho como deslocamento para saber onde procurar: http://en.wikipedia.org/wiki/bmp_file_format.

Isso deve funcionar: (Editar: Adicionar código para gravar no arquivo)

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

Outras dicas

Se você estiver no Windows, pode usar o LoadBitmap função do Win32

Então, dada a alça, converta -a em um bitmap dib e chegue aos pixels dessa maneira

Fiz um pouco de teste e estendi um pouco o programa de Patrice. Não sou um bom programador C, então todo o crédito vai para ele e minhas partes não são tão elegantes quanto as dele - desculpe por isso.

Aviso: enorme código fonte à frente.

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

}

Este programa lê as informações de pixels armazenadas no arquivo. Ele leva em consideração o preenchimento, mas funciona apenas com BMPs com uma profundidade de cor de 24 bits por pixels (se você precisar de outras profundidades, precisará personalizar a estrutura RGB). Espero que isso ajude você, mas como eu disse, é apenas uma extensão do código de Patrice.

Aqui está uma saída de amostra do meu arquivo test:

$ ./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: Sim, minha imagem está exibindo uma cruz vermelha. Observe que a imagem é armazenada de cabeça para baixo, então a linha 1 do arquivo é na verdade a linha 5 da imagem. Esqueci de escrever algo para arquivar o código, mas isso é deixado como um exercício para você;).

Se você tem garantia de que é um bitmap 24bpp não compactado e sua largura é divisível por 4, é relativamente simples:

  1. Leia um BmpHeader No início do arquivo.
  2. Sem procurar, leia um BmpImageInfo.
  3. Procure o BmpHeader's offset bytes de o início do arquivo. Observe que não há paleta (pelo menos, nem uma com quem nos importamos) em bitmaps de 24 bits!
  4. Leia trigêmeos BGR (nessa ordem, e não há reserved membro não utilizado aqui). Haverá (BmpImageInfomembros dos membros) width * abs(height) Tripletos. Pelo que me lembro, se height é positivo (o caso padrão), a primeira linha de cor que você leu será a fundo linha da imagem, subindo a partir daí. Se height é negativo, porém, a primeira linha de cor no arquivo é o topo da imagem, descendo a partir daí.

Se você não pode fazer essas garantias, as coisas ficam muito mais complicadas.

Isenção de responsabilidade: Estou gratuitamente no meu próprio chifre aqui. Anos atrás, escrevi um pequeno utilitário (um arquivo de origem) para fazer exatamente o que você está falando, de uma maneira portátil (100% Ansi C): Glbmp libbmpread. Sua fonte pode lançar alguma luz sobre o seu problema-ele lida com bitmaps de bits sem profundidade (sem rle) e deve funcionar bem em um GBA.

Consulte a página da Wikipedia do formato de arquivo .bmp, que fornece muitas informações sobre a estrutura do arquivo e deve ajudá -lo a analisá -lo.

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

No seu código, você primeiro deve ler o endereço inicial dos dados (especificado no cabeçalho do arquivo) e a altura da imagem. Em seguida, procure esta posição. Depois disso, você lê em uma linha pixel por pixel (o cabeçalho especifica quantos bits por pixel) e precisa cuidar do estofamento de 32 bits no final. Observe que, em uma imagem de 24 bits (RGB), as informações são armazenadas na ordem BGR. Além disso, se o valor da altura não for negativo, a imagem será armazenada de cabeça para baixo.

Não estou familiarizado com o formato de arquivo BMP, mas você não precisaria ler primeiro as informações do cabeçalho? Algo como:

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

e leia com informações detalhadas da imagem, que você precisará:

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

e leia as informações da paleta também.

Depois de ter, você saberá o tamanho do arquivo e o deslocamento dos dados. Você pode pré-alocar espaço suficiente e ler de uma só vez, o que pode ser mais simples. Como alternativa, você pode ler em pedaços e analisar enquanto está indo (reduz a chance de não ter memória suficiente, mas a análise é mais complicada).

Você também saberá na seção de informações se a compactação estiver ativada, dimensões da imagem etc.

Se você estiver lendo de uma só vez, pule para o deslocamento dos dados e faça algo como:

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

e assim por diante. Obviamente, esse código não está checando erros, fim do buffer e assim por diante, então você precisará fazer isso. Você provavelmente também terá que ler as informações da paleta para entender os dados da imagem.

Ou, como alguém disse, olhe para a especificação do formato na Wikipedia

Se o arquivo BMP tiver uma paleta, o código abaixo deve trabalhar:

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

Você pode achar útil olhar para algum código C que escrevi há muitos anos para ler e escrever arquivos BMP, localizados em:

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

Acredito que ele lida com os vários tamanhos de bits de pixel (1/2/4/8/24), bem como a compressão RLE.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top