Reading a bitmap image

Asked

Viewed 2,487 times

0

Hello, I am with a work of the faculty on steganography and one of the requirements is to read an image in the format bitmap (bmp), however, I have already searched a lot in the internet and the information that exist are the same on this subject, I’m not sure what I should put on to read the image correctly, I’m in need of help to understand. Below is a part of what has already been done

NOTE: This is the "readImagemBMP. h" file of the code

#ifndef LERIMAGEMBMP__
#define LERIMAGEMBMP__

/*Define o cabeçalho da imagem com o formato BMP*/
typedef struct { 
    char formato[2]; //Especifica o formato da imagem bmp
    int tambytes; //Define o tamanho em Bytes da imagem
    short int reservado1;
    short int reservado2;
    int numbytesdeslocado;

} HEADERARQUIVO;

 /*Estrutura que define as propriedades da imagem BMP*/ 
typedef struct{
    int tamanhoCabecalho; 
    int largura; // Define a largura da imagem
    int altura; // Define a altura da imagem
    short int qualiPlanos;
    short int bitsPixel;
    int compressao;
    int tamanhoImagem;
    int horizontal;
    int vertical;
    int numPaletaCores;
    int numCoresImportantes;

} HEADERIMAGEM;


typedef struct {
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char reservado;

} PALETA;


/*Cabeçalho da função que será
responsável por ler a imagem no formato BMP*/
void ler_imagem_bmp(FILE *img_orig, FILE *img_copia_bmp); 

#endif


**OBS: ESSE É O arquivo .c do código**


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lerImagemBMP.h"


void ler_imagem_bmp(FILE *img_orig, FILE *img_copia_bmp){

    char *nomeArquivobmp;
    char *copiaArquivobmp;
    nomeArquivobmp = malloc(25 * sizeof(char));
    copiaArquivobmp = malloc(25 * sizeof(char));
    PALETA **Matriz;
    int i, j;


    printf("Informe o nome do arquivo a ser lido:\n");
        scanf("%s", nomeArquivobmp);

    img_orig = fopen(nomeArquivobmp, "rb");


    if(img_orig == NULL){
        fprintf(stderr, "ERRO AO TENTAR ABRIR O ARQUIVO %s\n", nomeArquivobmp);
    }


    HEADERARQUIVO cabecalho;
    HEADERIMAGEM imagem;


    fscanf(img_orig, "%s", cabecalho.formato);

    if(strcmp(cabecalho.formato, "BM") != 0){
        fprintf(stderr, "O FORMATO DA IMAGEM NÃO É BMP\n");
        fclose(img_orig);
    }

    fscanf(img_orig, "%d", &cabecalho.tambytes);
    fscanf(img_orig, "%hu", &cabecalho.reservado1);
    fscanf(img_orig, "%hu", &cabecalho.reservado2);
    fscanf(img_orig, "%d", &cabecalho.numbytesdeslocado);
    fscanf(img_orig, "%d", &imagem.tamanhoCabecalho);
    fscanf(img_orig, "%d", &imagem.largura);
    fscanf(img_orig, "%d", &imagem.altura);
    fscanf(img_orig, "%hu", &imagem.bitsPixel);
    fscanf(img_orig, "%d", &imagem.tamanhoImagem);
    fscanf(img_orig, "%d", &imagem.horizontal);
    fscanf(img_orig, "%d", &imagem.vertical);
    fscanf(img_orig, "%d", &imagem.numPaletaCores);
    fscanf(img_orig, "%d", &imagem.numCoresImportantes);



    fprintf(img_copia_bmp, "%s%d%d%d", cabecalho.formato, cabecalho.tambytes, cabecalho.reservado1, cabecalho.reservado2);
    fprintf(img_copia_bmp, "%d%d%d%d%d", cabecalho.numbytesdeslocado, imagem.tamanhoCabecalho, imagem.largura, imagem.altura, imagem.bitsPixel);
    fprintf(img_copia_bmp, "%d%d%d%d%d", imagem.tamanhoImagem, imagem.horizontal, imagem.vertical, imagem.numPaletaCores, imagem.numCoresImportantes);


    Matriz = (PALETA**) malloc(imagem.largura * sizeof(PALETA*));
    for(i=0; i<imagem.largura; i++){

        Matriz[i] = (PALETA*) malloc(imagem.altura * sizeof(PALETA));
        for(j=0; j<imagem.altura; j++){
            fscanf(img_orig, "%c%c%c", &Matriz[i][j].r, &Matriz[i][j].g, &Matriz[i][j].b);
        }
    }


    for(i=imagem.largura; i<=0; i--){
        for(j=0; j<imagem.altura; j++){
            fprintf(img_copia_bmp, "%c%c%c", Matriz[i][j].r, Matriz[i][j].g, Matriz[i][j].b);
        }
    }

    fclose(img_orig);
    fclose(img_copia_bmp);
}
  • Friend, you need to be more specific about what exactly you don’t understand. This makes it difficult to understand how to help you. It will be difficult for someone to post a tutorial explaining step by step how to do it, as it is not the purpose of the site. I’ll leave you one more tip, however you need to start your code and point out where you don’t understand or what your specific difficulty is. https://stackoverflow.com/questions/14279242/read-bitmap-file-into-structure

1 answer

2

Ok - basically, let the "fscanf" go - it’s a penada auxiliary function mainly to read files cuj content be text, and in this case can more mess than help. This answer gives a general outline with the example of how you can start to get the code in C.

Reading and writing file formats already set manually is one of the coolest things to do in C or other language - but also something we have to keep in mind where it’s important not to re-invent the wheel.

In almost all "real-life" projects when we have to read or write an image in a specific file format, we don’t reimplement all the code for that: we use a ready-made, well-defined library that can handle the image in all its types and subtypes - in general there are calls in the libraries to which you pass a filename, and you get back a pointer to a memory region where all the data are like: width, image height, bytes per pixel and to the pixels themselves.

That said, of course it is possible to read and write image files without having the libraries ready, but the difficulty varies according to the type of file: JPEG for example, has very complicated and specific compression algorithms, and re-writing them would take a lot of work. Formats like . PNG, . PCX and others are much simpler, but still have compression algorithms involved. Already the most common type of BMP files on the other hand has no compression at all - which means that after extracting the header data, you have the data directly from the image- this makes the format legal for a first approach in such jobs (and impracticable for everyday use since without any compression these files may be 10 times the size of equivalent PNG files)

So - one of the cool things is that the header of a file. BMP can be mapped almost directly, if not directly, to a struct in C. The various fields of the struct will have the width and height of the image, number of colors, etc... I believe for this job you will need only 24-bit (3-byte) RGB images per pixel, which are even easier to move.

The next step is to look for the file format specification (and within that, filter in the file type we want) - and the found documents try to create a struct in C - I do the search for "bmp file spec" - and let’s see - this link looks good: http://www.dragonwins.com/domains/getteched/bmp/bmpfileformat.htm - even why, in the same tone as I am writing this answer, he goes on to say what are the most used variations among the headers and field types.

So la the first thing we see is that the first bytes are a "File header" - and they then reference an "image header" inside that file. It says the size of each field, so the business is to create in C a struct that has fields of the same size - you will see in the specification:

Field Name  Size in Bytes   Description
bfType  2   The characters "BM"
bfSize  4   The size of the file in bytes
bfReserved1 2   Unused - must be zero
bfReserved2 2   Unused - must be zero
bfOffBits   4   Offset to start of Pixel Data

Meaning that the first two bytes will be fixed and are the file identifier - it is a 16-bit value that represents the ASCII of the letter B in the first byte and the letter M in the second byte. Your reading code can check this number if it is different from that, close the program saying it is not a BMP file.

From then on there are other fields that could be something like

struct BMPFileHeader {
short unsigned int bfType;
unsigned long int  bfSize;
unsigned short int bfReserved1;
unsigned short int bfReserved2;
unsigned long int brOffbits;

};

Notice that it already has a field that tells where the pixels themselves start - but before the pixels, we will have another struct with the data of type width and height - you realize that you will need to fill the next also - I believe that by giving the tip so far you will be able to read the specification and read the other required fields. To read this header, you will need code of the type

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

int main(int argc, char *argv[]) {
    FILE *file
    struct BMPFileHeader header;
    file = fopen(argv[1], "rb");
    if ( !file ){printf("Problema ao abrir o arquivo %s ", argv[1]); exit(1);}
    fread(*file, *header, sizeof(BMPFileHeader);
    if (header.bfType != ('B' << 8 + 'M')) {{printf("O arquivo %s não é um BMP válido", argv[1] ); exit(1);}
    ...
}

Similarly, you describe the struct for data in the image that comes next in the link I passed - although for simplified use, you will only need the fields biWidth, biHeight, and biBitCount - then you could make a simplified struct that reads only the bytes up to that point - With "if"s you check if the value of "biBitCount" is 24 - otherwise it comes out with an error too (image != RGB with 8 bits per pixel). And the Width and Height fields will have the width and height of the image at that point, you can make a fseek for the value that is in the bfOffBits field of the above Header struct - and read the amount of bytes "biWidth * biHeight * 3 " for a memory area allocated with malloc. There will be your pixel values.

To rewrite the file you can follow an analogous technique - reusing the structs for the headers already used in reading (but in this case, you have to create the entire struct for Image Header).

I believe that this will get you started. Good luck.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.