Reading a bitmap image

1

Hello, I have a college work on steganography and one of the requirements is to read an image in bitmap (bmp) format, but I have already looked for a lot on the internet and the information that exists is the same on this subject, I do not know sure what I put in to read the image correctly, I'm needing help to understand. Below is a part of what has already been done

NOTE: This is the file "readImageBMP.h" 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);
}
    
asked by anonymous 07.06.2017 / 10:27

1 answer

3

Ok - basically leave "fscanf" there - it's an auxiliary function mainly penalized for reading files whose content is text, and in that case can be more disruptive than helping. This answer gives some general guidelines with the example of how you can start getting the code in C.

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

On almost all "real-life" projects when we have to read or write an image in a specific file format, we do not reimplement all the code for this: we use a well-defined, well-defined library that can handle the image in all its types and subtypes - there are usually calls in the libraries for which you pass a file name, and get a pointer back to a memory region where all data type is: width, image height, bytes per pixel and for the pixels themselves.

That said, it is clear that 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 down would do a lot of work." Formats like .PNG, .PCX and others are much simpler, but still have compression algorithms involved. The most common type of BMP files, on the other hand, does not have any compression - which means that after extracting the data from the header, you have the data directly from the image - this makes the format legal for a first approach in such jobs (and unfeasible for everyday use because 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 .BMP file 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, colors, etc ... I believe that for this work you will only need RGB images with 24 bits (3 bytes) per pixel, which are easier still to move.

The next step is to look for the file format specification (and within that, filter on the file type we want) - and the documents found try to create a struct in C - I search for "bmp file spec" - and let's see - this link looks good: link - even though, in the same tone as I am writing this answer, it says what are the most commonly used variations among headers and field types.

So the first thing we see is that the first bytes are a "File header" - and they immediately reference an "image header" within 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

Siginizing that the first two bytes will be fixed and are the file identifier - 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 read code can check this number if it is different from that, wax the program as it is not a BMP file.

From there you have 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 says where the pixels start, but before the pixels, we will have another struct with the data of the type width and height - you realize that you will need to fill the next one too - giving the hint so far you will be able to read the specification and read the other required fields. To read this header, you will need type code

#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 data struct in the image that follows in the link I passed - although for simplified use, you'll need only the biWidth, biHeight, and biBitCount fields - so you could do a simplified struct that it 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 Header struct above - and read the amount of bytes "biWidth * biHeight * 3" for one allocated memory with malloc. There will be your pixel values.

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

I believe you can get started with this. Good luck.

    
07.06.2017 / 16:00