Ir ao conteúdo
  • Cadastre-se

C como compilar um C com libmbp.h e imghelpers.h


matheus.Matta
Ir à solução Resolvido por arfneto,

Posts recomendados

@arfneto o que eu poderia fazer com o fread? para diminuir a carga. tambem me encontro em outro problema uso o imageMagick para coverte para bmp o unico porém e que quando eu passo essa imagem convertida no C o arquivo se corrompe tem ideia do que possa ser ?

 

@arfneto e tambem ainda precisaria usar algo para manipular os arquivos, tipo ler as imagem na pasta uplodas. o que você me recomenda a usar 

?

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

17 horas atrás, arfneto disse:

acho que não me expliquei bem: esses valores já fazem parte da estrutura. Não deve replicar isso de novo e de novo

Esses valores estão na struct bmp_header de libbmp. Criei outra struct o para usar whpix->height (ou width) em vez de image.img_header.biHeight. Mas agora deixei o codigo mais simples, sem struct e a funcao limit que acho desnecessaria ja que os pixels sao unsinged char.

 

O problema do desenquadramento que falei era algo com o formato da imagem. Resolvi isso na hora de converter outro formato para bmp no gimp ativando a opcao Do not write color space information.

 

#include <stdio.h>
#include <stdlib.h>
#include "libbmp.h"

int save_image(
    bmp_header* header, bmp_pixel** pixels,  const char* filename
);

int main(int argc, char* argv[]) {
    const char*	infile = argv[1];
    const char*	outfile = argv[2];
    FILE*		file;
    bmp_img		image;
	
    if(argc != 3){
        fprintf(stderr,
            "Error: argc[%d]. Usage: imagebmp input.bmp output.bmp\n", argc);
        exit(1);
    }
	
    if((file = fopen(infile, "rb")) == NULL){
        fprintf(stderr, "Can't open file: %s\n", infile);
        exit(1);
    }
	
    bmp_img_read(&image, infile);

    for(unsigned int y = 0; y < image.img_header.biHeight; y += 1){
        for(unsigned int x = 0; x < image.img_header.biWidth; x += 1){
            unsigned char* r = &image.img_pixels[y][x].red;
            unsigned char* g = &image.img_pixels[y][x].green;
            unsigned char* b = &image.img_pixels[y][x].blue;			
            unsigned char luma = *r * 0.2999 + *g * 0.587 + *b * 0.114;
            /*
            unsigned char avg = (*r + *g + *b)/3;
            *r = avg;
            *g = avg;
            *b = avg;

            *r = 255 - *r;
            *g = 255 - *g;
            *b = 255 - *b;
            */
			
            *r = luma; 
            *g = luma; 
            *b = luma;
        }
    }	

    if(save_image(&image.img_header, image.img_pixels, outfile)){
        fprintf(stderr, "Failed to save file: %s\n", outfile);
        exit(1);
    }

    return 0;
}

int save_image(
    bmp_header* header, bmp_pixel** pixels, const char* filename
){
    bmp_img image;	
    bmp_img_init_df(&image, header->biWidth, header->biHeight);
	
    for(unsigned int y = 0; y < header->biHeight; y += 1){
        for(unsigned int x = 0; x < header->biWidth; x += 1){
            bmp_pixel_init(
                &image.img_pixels[y][x],
                pixels[y][x].red,
                pixels[y][x].green,
                pixels[y][x].blue);
        }
    }
    if(bmp_img_write(&image, filename) != BMP_OK){
        return 1;
    }
    bmp_img_free(&image);
    return 0;
}

 

Dois metodos para p&b (media e luma output3) e efeito negativo.

 

screen.png.4c811f0c1813157470e9cfd4d1061c03.png

 

1 hora atrás, arfneto disse:

mas essa abaixo é a fórmula clássica que se vê sempre. Não sei a origem para poder creditar o autor, mas essa parece dar resultado mais expressivo na imagem

Encontrei sobre isso nesta pagina, tem outas formulas,

 

https://en.wikipedia.org/wiki/Grayscale

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

  • Solução
	salvaImagem("saida.bmp", R, G, B, c, l);

 

1 hora atrás, Midori disse:
if(save_image(&image.img_header, image.img_pixels, outfile)){
        fprintf(stderr, "Failed to save file: %s\n", outfile);
        exit(1);

 

Com seis ou tres parâmetros, não parece bom. O que eu tentava dizer nos outros posts é que é muito mais conveniente usar encapsulamento e escrever em torno dos dados. O simples.

 

O header não existe sem o bitmap. Os RBG lá são os pixels. nenhum deles existe sózinho. E os dados são só o bitmap. Então só se usa o bitmap.

 

1 hora atrás, Midori disse:

Esses valores estão na struct bmp_header de libbmp. Criei outra struct o para usar whpix->height (ou width) em vez de image.img_header.biHeight. Mas agora deixei o codigo mais simples, sem struct e a funcao limit que acho desnecessaria ja que os pixels sao unsinged char.

 

Foi o que eu tentei dizer 🙂 

 

Uma outra solução

 

Vou deixar uma quarta opção, algo que já postei aqui.  

 

Porque outra solução? Para ter exemplo do que estou tentando explicar.

 

Isso é um bitmap:

 

typedef struct
{
    BitmapFileHeader h_bmp;
    BitmapInfoHeader h_info;
    uint8_t*         pixel;
} Bitmap;

 

É isso que seu programa deve ver. E o usuário de sua biblioteca deve ver. E pode ser você mesmo. Não é esperto expor os aspectos internos, coisas que já estão embutidas, coisas que você pode querer mudar depois e vai ter então que mudar as chamadas em 2 mil lugares.

 

Se o bitmap é isso, e ele é isso, então pode escrever

 

typedef struct
{
    char    header[2];
    int32_t fileSize;
    int32_t reserved;
    int32_t dataOffset;
} BitmapFileHeader;

typedef struct
{
    int32_t headerSize;
    int32_t width;
    int32_t height;
    int16_t planes;
    int16_t bitsPerPixel;
    int32_t compression;
    int32_t dataSize;
    int32_t horizontalResolution;
    int32_t verticalResolution;
    int32_t colors;
    int32_t importantColors;
} BitmapInfoHeader;

typedef struct
{
    BitmapFileHeader h_bmp;
    BitmapInfoHeader h_info;
    uint8_t*         pixel;
} Bitmap;

Bitmap* bmp_copy(Bitmap*);
Bitmap* bmp_create(unsigned w, unsigned h);
Bitmap* bmp_destroy(Bitmap* bmp);
int     bmp_fill(Bitmap*, uint8_t, uint8_t, uint8_t);
int     bmp_grad(Bitmap* bmp);
Bitmap* bmp_read(const char* filename);
int     bmp_setPixel(
        Bitmap* bmp, int x, int y, uint8_t red, uint8_t green,
        uint8_t blue);
int bmp_to_bw(Bitmap*);
int bmp_write(Bitmap* bmp, const char* filename);

 

Para ter um mínimo para testar.

 

Bitmaps estão na memória e assim o simples é considerar:

  • quer criar um bitmap? de que tamanho? Só isso.
  • quer apagar um bitmap? Qual o endereço? Só isso.
  • quer copiar um bitmap? De qual? Só isso.
  Bitmap* bmp_copy(Bitmap* origem);
  Bitmap* bmp_create(unsigned w, unsigned h);
  Bitmap* bmp_destroy(Bitmap* bmp);
  • quer colocar uma cor em um pixel? 
	int     bmp_setPixel(
        Bitmap* bmp, int x, int y, uint8_t red, uint8_t green,
        uint8_t blue);

 

Não é só isso? Então a gente não escreve mais que isso.

 

    int     bmp_fill(Bitmap*, uint8_t, uint8_t, uint8_t);
    int     bmp_grad(Bitmap* bmp);
    int     bmp_to_bw(Bitmap*);
  • bmp_fill é o simples para testar e preenche todo o bmp com a cor

  • bmp_grad era pra exemplo. Cria esse bitmap:

image.png.2594674f2a68150d372299c3fef9ec68.png

Escrevi isso só porque é simples e é legal de testar a transição das cores.

 

O código está logo abaixo e é trivial.

 

 

 

 

 

 

  • bmp_to_bw() é a função aqui do tópico. Então o simples seria o que? Pega o endereço do bitmap vai lá e transforma. inline. O gradiente fica assim

image.png.39eb4128303a54f3d780c8175336e98a.png

 

E assim dá para ver os 256 tons de cinza em cada cor e comparar com o de cima...

 

 

 

 

 

 

 

 

Ler / gravar

 

  Bitmap* bmp_read(const char* filename);
  int bmp_write(Bitmap* bmp, const char* filename);

 

Isso é mais simples. Quer ler? De onde? Quer gravar? Para onde?

 

Assim é mais fácil de consumir a API. Veja:

 

    Bitmap* a_test = bmp_create(1024, 768);
    bmp_fill(a_test, 255, 0, 0);  //vermelho
    bmp_write(a_test, "red.bmp");
    bmp_destroy(a_test);

 

Esse trecho cria um bmp 1024x768, pinta de vermelho e grava no disco e apaga o bitmap da memória

 

EXEMPLO

 

Esse programa usa todas as funções e gera vários arquivos

 

#include "bitmap.h"
int main(void)
{
    const int W = 1024;
    const int H = 768;
    // arquivos de teste
    const char* red          = "red.bmp";
    const char* green        = "green.bmp";
    const char* blue         = "blue.bmp";
    const char* blue_copy    = "blueCopy.bmp";
    const char* gradiente    = "gradiente.bmp";
    const char* gradiente_pb = "gradiente-pb.bmp";

    Bitmap*     a_test       = bmp_create(1024, 768);
    if (a_test == NULL)
    {
        fprintf(stderr, "\tErro ao tentar criar bitmap\n");
        return -1;
    }
    fprintf(stderr, "\tCriado BMP %dx%d\n", W, H);
    int res = 0;

    res = bmp_fill(a_test, 255, 0, 0);  // red
    fprintf(stderr, "\tbmp_fill retornou %d\n", res);
    res = bmp_write(a_test, red);
    fprintf(
        stderr, "\tbmp_write() retornou %d ao criar %s\n",
        res, red);

    res = bmp_fill(a_test, 0, 255, 0);  // green
    fprintf(stderr, "\tbmp_fill() retornou %d\n", res);
    res = bmp_write(a_test, green);
    fprintf(
        stderr, "\tbmp_write() retornou %d ao criar %s\n",
        res, green);

    res = bmp_fill(a_test, 0, 0, 255);  // blue
    fprintf(stderr, "\tbmp_fill() retornou %d\n", res);
    res = bmp_write(a_test, blue);
    fprintf(
        stderr,
        "\tbmp_write() retornou %d ao criar %s\n",
        res,blue);

    Bitmap* a_copy = bmp_copy(a_test);
    fprintf(
        stderr,
        "\tbmp_copy() %s [%dx%d], size is %d, para %s\n",
        blue, a_copy->h_info.width, a_copy->h_info.height,
        a_copy->h_bmp.fileSize, blue_copy);
    res            = bmp_write(a_copy, blue_copy);
    fprintf(
        stderr,
        "\tbmp_write() retornou %d ao gravar %s\n",
        res, blue_copy);

    res = bmp_grad(a_copy);
    fprintf(stderr, "\tbmp_grad() retornou %d\n", res);
    res = bmp_write(a_copy, gradiente);
    fprintf(
        stderr, "\tbmp_write() retornou %d ao criar %s\n",
        res, gradiente);

    res = bmp_to_bw(a_copy);
    fprintf(stderr, "\tbmp_to_bw() retornou %d\n", res);
    res = bmp_write(a_copy, gradiente_pb);
    fprintf(
        stderr, "\tbmp_write() retornou %d ao criar %s\n",
        res, gradiente_pb);

    a_test = bmp_destroy(a_test);
    a_copy = bmp_destroy(a_copy);
    fprintf(stderr, "\t[  F I M  ]\n");
    return 0;
}

 

Saída

 

        Criado BMP 1024x768
        bmp_fill retornou 0
        bmp_write() retornou 0 ao criar red.bmp
        bmp_fill() retornou 0
        bmp_write() retornou 0 ao criar green.bmp
        bmp_fill() retornou 0
        bmp_write() retornou 0 ao criar blue.bmp
        bmp_copy() blue.bmp [1024x768], size is 3145782, para blueCopy.bmp
        bmp_write() retornou 0 ao gravar blueCopy.bmp
        bmp_grad() retornou 0
        bmp_write() retornou 0 ao criar gradiente.bmp
        bmp_to_bw() retornou 0
        bmp_write() retornou 0 ao criar gradiente-pb.bmp
        bitmap APAGADO
        bitmap APAGADO
        [  F I M  ]

 

Uma implementação mínima

 

#pragma pack(push, 2)
#pragma pack(show)
#include "bitmap.h"

Bitmap* bmp_copy(Bitmap* orig )
{
    if (orig == NULL) return NULL; // sem origem
    // cria a copia
    Bitmap* cp =
        bmp_create(orig->h_info.width, orig->h_info.height);
    if ( cp == NULL ) return NULL; // deu pau
    // copia os headers, claro
    cp->h_bmp   = orig->h_bmp;
    cp->h_info  = orig->h_info;
    //copia os pixels
    uint8_t* de = orig->pixel;
    uint8_t* para = cp->pixel; 
    // nesse exemplo sao 4 bytes por pixel, 32bpp, certo?
    for (int32_t i = 0; 
         i < orig->h_info.width * orig->h_info.height * 4; i += 1)
        *para++ = *de++;
    return cp; // so isso: retorna a copia
}

Bitmap* bmp_create(unsigned w, unsigned h)
{
    Bitmap* one = (Bitmap*)calloc(1, sizeof(Bitmap));

    one->h_bmp.dataOffset =
        sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader);
    one->h_bmp.fileSize =
        one->h_bmp.dataOffset + (w * h * 4);
    one->h_bmp.header[0] = 'B';
    one->h_bmp.header[1] = 'M';
    one->h_info.bitsPerPixel         = 32;
    one->h_info.headerSize           = 40;
    one->h_info.height               = h;
    one->h_info.horizontalResolution = 2400;
    one->h_info.planes               = 1;
    one->h_info.verticalResolution   = 2400;
    one->h_info.width                = w;
    one->pixel                       = (uint8_t*)calloc(
        1, (size_t)(w * h * 4 * sizeof(uint8_t)));
    if (one->pixel == NULL)
    {
        free(one);
        return NULL;
    }
    return one;
};

Bitmap* bmp_destroy(Bitmap* bmp)
{
    if (bmp == NULL) return NULL;
    if (bmp->pixel != NULL) free(bmp->pixel);
    free(bmp);
    fprintf(stderr, "\tbitmap APAGADO\n");
    return NULL;
}

int bmp_fill(
    Bitmap* bmp, uint8_t red, uint8_t green, uint8_t blue)
{
    if (bmp == NULL) return -1;
    uint8_t* p = bmp->pixel;
    for (int32_t i = 0;
         i < bmp->h_info.width * bmp->h_info.height; i += 1)
    {  // 32bpp
        *p++ = blue;
        *p++ = green;
        *p++ = red;
        *p++ = 0xFF;  // alpha
    }
    return 0;
}

int bmp_grad(Bitmap* bmp)
{
    // preenche a imagem com 3 faixas verticais
    // em vermelho verde e azul, mas mudando a intensidade
    //  da cor de 0 a 255 a cada linha
    if (bmp == NULL) return -1;
    uint8_t  red   = 0;
    uint8_t  green = 0;
    uint8_t  blue  = 0;
    uint8_t* p     = bmp->pixel;
    for (int y = 0; y < bmp->h_info.height; y++)
    {
        uint8_t color_value =
            (uint8_t)(255 * (double)y / bmp->h_info.height);
        for (int x = 0; x < bmp->h_info.width; x++)
        {
            switch (x / (bmp->h_info.width / 3))
            {
                case 0:
                    red   = color_value;
                    green = 0;
                    blue  = 0;
                    break;
                case 1:
                    red   = 0;
                    green = color_value;
                    blue  = 0;
                    break;
                default:
                    red   = 0;
                    green = 0;
                    blue  = color_value;
                    break;
            }
            *p++ = blue;
            *p++ = green;
            *p++ = red;
            *p++ = 0XFF;
        }
    };
    return 0;
}

Bitmap* bmp_read(const char* filename)
{
    FILE* in = fopen(filename, "rb");
    if (in == NULL) return NULL;
    Bitmap* one = bmp_create(800, 600);
    if (one == NULL)
    {
        fclose(in);
        return NULL;
    }
    size_t size =
        sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader);
    size_t res = fread((void*)one, (size_t)(1), size, in);
    if (res != size) return NULL;
    // agora calcula o que falta ler
    size = one->h_info.height * one->h_info.width *
           4;  // 32bpp
    uint8_t* area = (uint8_t*)realloc(one->pixel, size);
    if (area == NULL)
    {
        fclose(in);
        bmp_destroy(one);
        return (NULL);
    };
    one->pixel = area;
    res = fread((void*)one->pixel, (size_t)(1), size, in);
    return one;
}

int bmp_setPixel(
    Bitmap* bmp, int x, int y, uint8_t red, uint8_t green,
    uint8_t blue)
{
    if (bmp == NULL) return -1;
    uint8_t* pPixel = bmp->pixel;
    // get address of coordinates of x,y
    pPixel += (y * 4) * bmp->h_info.width + (x * 4);
    pPixel[0] = blue;
    pPixel[1] = green;
    pPixel[2] = red;
    pPixel[3] = 0xFF;
    return 0;
}

int bmp_to_bw(Bitmap* bmp)
{
    if (bmp == NULL) return -1;
    uint8_t* p = bmp->pixel;
    for (int32_t i = 0;
         i < bmp->h_info.width * bmp->h_info.height; i += 1)
    {                                   // 32bpp
        double value = (*p * 0.114) + *(p + 1) * 0.587 +
                     *(p + 2) * 0.299;  // isso e antigo
        // não e ideia minha, mas e uma mistura das cores
        // e fica ok como branco e preto
        *p++ = (int)(value);  // r
        *p++ = (int)(value);  // g
        *p++ = (int)(value);  // b
        p++;  // alfa não vai mexer, ja que e transparencia
    }
    return 0;
}

int bmp_write(Bitmap* bmp, const char* filename)
{
    FILE* out = fopen(filename, "wb");
    if (out == NULL) return -1;
    size_t res = 0;
    res        = fwrite(
        &bmp->h_bmp, (size_t)1, sizeof(BitmapFileHeader),
        out);
    res = fwrite(
        &bmp->h_info, (size_t)1, sizeof(BitmapInfoHeader),
        out);
    size_t size =
        (bmp->h_info.width * bmp->h_info.height * 4);
    res = fwrite(
        (const void*)bmp->pixel, (size_t)(1), size, out);
    if (size != res)
    {
        fclose(out);
        fprintf(
            stderr,
            "\tbmp_write() write %zd. %zd expected\n", res,
            size);
        fclose(out);
        return -2;
    }
    res = fclose(out);
    return 0;
}

#pragma pack(pop)

 

Sugiro comparar e entender a razão de escrever em torno dos dados, usar encapsulamento e manter apenas ponteiros como argumentos e retorno. É muito mais simples de ler e de usar. E não expõe coisas internas. Não é vantagem usar 3 ponteiros para cada cor. Mas se usar e colocar como argumento e depois mudar de ideia vai ter que mexer em todas as chamadas em todos os programas que usam isso. 

 

 

1 hora atrás, matheus.Matta disse:

o que eu poderia fazer com o fread? para diminuir a carga

 

Entenda que ao ler precisa de DOIS fread só. E para gravar UM. E não de 2,4 milhões para um bmp de 1024x768....

 

Um bitmap é um mapa. Vem um pixel atrás do outro.

 

Veja o exemplo que deixei acima

O header "bitmap.h" no exemplo seria 

 

#pragma once
#pragma pack(push, 2)
#pragma pack(show)

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    char    header[2];
    int32_t fileSize;
    int32_t reserved;
    int32_t dataOffset;
} BitmapFileHeader;

typedef struct
{
    int32_t headerSize;
    int32_t width;
    int32_t height;
    int16_t planes;
    int16_t bitsPerPixel;
    int32_t compression;
    int32_t dataSize;
    int32_t horizontalResolution;
    int32_t verticalResolution;
    int32_t colors;
    int32_t importantColors;
} BitmapInfoHeader;

typedef struct
{
    BitmapFileHeader h_bmp;
    BitmapInfoHeader h_info;
    uint8_t*         pixel;
} Bitmap;

Bitmap* bmp_copy(Bitmap* origem);
Bitmap* bmp_create(unsigned w, unsigned h);
Bitmap* bmp_destroy(Bitmap* bmp);
int     bmp_fill(Bitmap*, uint8_t, uint8_t, uint8_t);
int     bmp_grad(Bitmap* bmp);
Bitmap* bmp_read(const char* filename);
int     bmp_setPixel(
        Bitmap* bmp, int x, int y, uint8_t red, uint8_t green,
        uint8_t blue);
int     bmp_to_bw(Bitmap*);
int     bmp_write(Bitmap* bmp, const char* filename);

#pragma pack(pop)

 

  • Curtir 1
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@arfneto marquei como solução sua ultima resposta, acho que n precisamos mais de nada so apenas o bom estudo.

vou procurar entender cada aspecto e imprimenta no meu codigo.


você gostaria de receber o resultado ? ja aviso que deve demorar kkkk, ja que você me ensinou tanto gostaria de receber o seu feedback no final. 

o projeto consiste em criar um servidor em C com curl ou algo do tipo para criamos um site de edição. por que o C ? porque e difícil.
acredito que fazendo algo desse nivel no C eu poderei fazer em qualquer lugar. n e para criar nada usavel ou super eficiente e apenas estudo, gosto de usar o C porque eu consigo entender a a origem da algo e isso e muito bom.
 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@matheus.Matta Sim! mostre como está ficando. Pode ajudar também muita gente por ter vários exemplos para um trem que não é assim comum, como gerar e gravar bitmaps/

 

Entendeu a diferença entre escrever de uma maneira e de outra? Entendeu o que significa encapsulamento e porque é melhor escrever em termos mais simples, de "entidades" arquivo e bitmap somente? 

E o lance dos milhões de chamadas (mesmo) a fread ao invés de uma ou duas ficou claro para você?

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@arfneto Tentei carregar a estrutura dos headers numa única chamada de fread, porém os dados não vem da forma correta.

 

Este é o hexdump de uma parte dele,

 

42 4D DA D3 05 00 00 00 00 00 36 00 00 00 28 00

 

O código só para pegar os valores dos primeiros campos, Signature 2 bytes e os outros de 4 bytes,

 

#include <stdio.h>

typedef struct {
    unsigned short	signature;
    unsigned int	size;
    unsigned int	reserved;
    unsigned int	offset;
}BmpHeader;

int main(int argc, char* argv[]) {
    FILE*       infile = fopen("bitmap.bmp", "rb");
    BmpHeader   header;
	
    fread(&header, sizeof(BmpHeader), 1, infile);

    printf(
        "Signature: %x\n"
        "Size: %x\n"
        "Reserved: %x\n"
        "Offset: %x\n",
        header.signature,
        header.size,
        header.reserved,
        header.offset
    );

    fclose(infile);
    return 0;
}

 

A saída fica assim,

Signature: 4d42
Size: 5
Reserved: 360000
Offset: 280000

 

Mas devia ser assim,

Signature: 4d42
Size: 5d3da
Reserved: 0
Offset: 36

 

Para resolver isso tive que ler um por um ou tirar signature da estrutura para ler separadamente, p.ex,

unsigned short	signature;

fread(&signature, sizeof(short), 1, infile);
fread(&header, sizeof(BmpHeader), 1, infile);

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@Midori Rodou o programa que mostrei? Comparou os dois? Deve imaginar que o que eu escrevi está certo e funciona, já que alguns dos BMP estão anexos...

 

1 hora atrás, Midori disse:

Para resolver isso tive que ler um por um ou tirar signature da estrutura para ler separadamente, p.ex,

 

Bem, não precisava de um exemplo para eu entender o que seria ler separadamente, já que foi exatamente o que eu disse para não fazer e já tinha em todos os outros programas no tópico. Eu mostrei esse outro programa justamente para ter um exemplo das coisas que  eu tentava explicar...

 

Você não "teve que ler um por um" "para resolver isso". Apenas desistiu e voltou para o que tinha feito antes. Nada resolveu.

 

Sobre o programa que escreveu:

 

Foi esperto comparar com os valores no arquivo para saber o que esperar, mas...

 

typedef struct
{
    unsigned short signature;
    unsigned int   size;
    unsigned int   reserved;
    unsigned int   offset;
} BmpHeader;

 

Seria mais expressivo o simples, como mostrei aqui. A assinatura é "BM" justamente por isso: para ver no DUMP as letrinhas BM para bitmap. Então é melhor preservar isso... Use o simples e mostre os dois char, afinal foi pensado para isso...

 

Veja o início de um bitmap, direto do IDE:

 

0x00000233EC183A40  42 4d 22 50 01 00 00 00 00 00 36 04 00  BM"P......6..
0x00000233EC183A4D  00 28 00 00 00 83 01 00 00 db 00 00 00  .(...ƒ...Û...
0x00000233EC183A5A  01 00 08 00 00 00 00 00 ec 4b 01 00 c4  ........ìK..Ä
0x00000233EC183A67  0e 00 00 c4 0e 00 00 00 00 00 00 00 00  ...Ä.........
0x00000233EC183A74  00 00 70 c0 28 ec 33 02 00 00 fd fd fd  ..pÀ(ì3...ýýý
0x00000233EC183A81  fd 62 00 69 00 74 00 6b dc 32 0d 76 ad  ýb.i.t.kÜ2.v.

 

E já vê as letrinhas logo no início: B e M. Outro ponto é o próximo campo, que é o tamanho do arquivo. O sistema sempre mostra o tamanho do arquivo. Em decimal. 

 

image.png.401bd95bd35fa89a2ebd0096cd8a78b9.png

 

E veja só: 86050 que é... 0x15022 em hexadecimal. E é o que vê lá na memória logo depois da assinatura

 

Então é melhor fazer o simples e mostrar as letras, que sabe que devem ser B e M, e o tamanho. porque vai ler um arquivo que já existe então o sistema já te disse o tamanho, ao invés de mostrar valores em hexadecimal.

 

Use o computador a seu favor

 

 

Esse é o oficial para essa estrutura:

 

typedef struct tagBITMAPFILEHEADER {
  WORD  bfType;
  DWORD bfSize;
  WORD  bfReserved1;
  WORD  bfReserved2;
  DWORD bfOffBits;
} BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

 

Documentada pelos donos da bola, em https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapfileheader 

 

Então uma pequena mudança em seu programa

 

  typedef struct
  {
      char signature[2];
      unsigned int   size;
      unsigned int   reserved;
      unsigned int   offset;
  } BmpHeader;

 

E isso:

 

#include <stdio.h>
#include <windows.h>
#include <wingdi.h>

typedef struct
{
    char signature[2];
    unsigned int   size;
    unsigned int   reserved;
    unsigned int   offset;
} BmpHeader;

int main(void)
{
    FILE*     infile = fopen("bitmap.bmp", "rb");
    BmpHeader header;

    fprintf(stderr, "    Tamanho do Header: %llu\n", sizeof(header));
    fread(&header, sizeof(BmpHeader), 1, infile);
    printf(
        "\
    Signature: '%c' '%c'\n\
    Size: %d\n\
    Reserved: %x\n\
    Offset: %d\n",
        header.signature[0],
        header.signature[1],
        header.size,
        header.reserved,
        header.offset);

    fclose(infile);
    return 0;
}

 

Então vai ver algo assim

 

    Tamanho do Header: 16
    Signature: 'B' 'M'
    Size: 1
    Reserved: 4360000
    Offset: 2621440

 

Não acha estranho?

 

Sabe que o campo offset é isso? Um offset. Veja na documentação em português

 

image.png.663e786298d7cdf2e0207e7988aa5df8.png

 

 

Então como eu já expliquei tudo está alinhadinho: os headers e os pixels. É um mapa afinal

 

Só que o header tem só 14 bytes. Está claro aí: 2 + 4 + 4 + 4 ...

 

E seu programa leu 16 e daí pra frente nada mais vai funcionar.

 

Porque leu errado? Notou as diretivas #pragma nos programas que mostrei? Nada perguntou. é só comparar.

 

Umas novas linhas no programa

 

#pragma pack(show)
#pragma pack(push, 2)
#pragma pack(show)

#include <stdio.h>

typedef struct
{
    char signature[2];
    unsigned int   size;
    unsigned int   reserved;
    unsigned int   offset;
} BmpHeader;

int main(void)
{
    FILE*     infile = fopen("bitmap.bmp", "rb");
    BmpHeader header;

    fprintf(stderr, "    Tamanho do Header: %llu\n", sizeof(header));
    fread(&header, sizeof(BmpHeader), 1, infile);
    printf(
        "\
    Signature: '%c' '%c'\n\
    Size: %d\n\
    Reserved: 0x%x\n\
    Offset: %d\n",
        header.signature[0],
        header.signature[1],
        header.size,
        header.reserved,
        header.offset);

    fclose(infile);
    return 0;
}
#pragma pack(pop)
#pragma pack(show)

 

Ao compilar já vai ver o problema

 

(1,9): warning C4810: value of pragma pack(show) == 16
(3,9): warning C4810: value of pragma pack(show) == 2
(38,9): warning C4810: value of pragma pack(show) == 16

 

Então precisa saber SEMPRE o padrão de seu compilador quando vai ler coisas que podem vir de outras fontes que não o seu próprio programa. No meu compilador e provavelmente no seu o alinhamento padrão é 16 e não dá pra manipular bitmaps assim.

 

Veja a saída

 

    Tamanho do Header: 14
    Signature: 'B' 'M'
    Size: 86050
    Reserved: 0x0
    Offset: 1078

 

Assim é

 

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@matheus.Matta porque não aproveita esse programa , esse tópico e a oportunidade, se por acaso não entendeu algo que foi usado nesses 4 programas?

 

Pergunte algo objetivo. Teve algo aqui em relação a alocação de memória que não entendeu?

 

E o forum permite ajudar mais gente. Essa discussão aqui já tem mais de 1000 visualizações. Então pode ser útil pra mais gente.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Em 23/10/2023 às 13:56, arfneto disse:

Rodou o programa que mostrei?

Rodei sim e vi que esta funcionando.

 

Em 23/10/2023 às 13:56, arfneto disse:

ao invés de mostrar valores em hexadecimal.

So mostrei os valores em hexadecimal poque estava comparando visualmente com a saida de hexdump.

 

Em 23/10/2023 às 13:56, arfneto disse:

Porque leu errado? Notou as diretivas #pragma nos programas que mostrei? Nada perguntou. é só comparar.

Era isso, com a diretiva a estrutura ficou com os dados corretos.

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!