Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading pattern from file and create a bmp image of that in C

I want to read an text file Using C Language.Here's the file:-

enter image description here

You see there is some pattern in the text content on the file. 0 means nothing. 9 means black. so there is coloring scheme from 0 to 9.

I have to create a bitmap image of this and the color are according to the values in the pattern. You have to adjust it with the 0-256 color scheme. And the final output for this is shown below

enter image description here

Now see the pattern in the content of the text file is opposite to the final output bitmap file (not necessary). The darkness of the colors in bitmap image is according to the values in the pattern of the text content.

Anyone will tell me how I achieve this in C language.

I am able to create a BMP file but not according to the pattern in text file.

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

int main()
{

char bitmap[1900];

    // -- FILE HEADER -- //

    // bitmap signature
    bitmap[0] = 0x42;
    bitmap[1] = 0x4d;

    // file size
    bitmap[2] = 58; // 40 + 14 + 12
    bitmap[3] = 0;
    bitmap[4] = 0;
    bitmap[5] = 0;
    int i=0;
    // reserved field (in hex. 00 00 00 00)
    for(i = 6; i < 10; i++) bitmap[i] = 0;

    // offset of pixel data inside the image
    for(i = 10; i < 14; i++) bitmap[i] = 0;

    // -- BITMAP HEADER -- //

    // header size
    bitmap[14] = 40;
    for(i = 15; i < 18; i++) bitmap[i] = 0;

    // width of the image
    bitmap[18] = 4;
    for(i = 19; i < 22; i++) bitmap[i] = 0;

    // height of the image
    bitmap[22] = 1;
    for(i = 23; i < 26; i++) bitmap[i] = 0;

    // reserved field
    bitmap[26] = 1;
    bitmap[27] = 0;

    // number of bits per pixel
    bitmap[28] = 24; // 3 byte
    bitmap[29] = 0;

    // compression method (no compression here)
    for(i = 30; i < 34; i++) bitmap[i] = 0;

    // size of pixel data
    bitmap[34] = 12; // 12 bits => 4 pixels
    bitmap[35] = 0;
    bitmap[36] = 0;
    bitmap[37] = 0;

    // horizontal resolution of the image - pixels per meter (2835)
    bitmap[38] = 0;
    bitmap[39] = 0;
    bitmap[40] = 0b00110000;
    bitmap[41] = 0b10110001;

    // vertical resolution of the image - pixels per meter (2835)
    bitmap[42] = 0;
    bitmap[43] = 0;
    bitmap[44] = 0b00110000;
    bitmap[45] = 0b10110001;

    // color pallette information
    for(i = 46; i < 50; i++) bitmap[i] = 0;

    // number of important colors
    for(i = 50; i < 54; i++) bitmap[i] = 0;

    // -- PIXEL DATA -- //
    for(i = 54; i < 66; i++) bitmap[i] = 255;


    FILE *file;
    file = fopen("bitmap.bmp", "w+");
    for(i = 0; i < 66; i++)
    {
        fputc(bitmap[i], file);
    }
    fclose(file);
    return 0;
}
like image 391
Muhammad Hashim Shafiq Avatar asked May 25 '16 05:05

Muhammad Hashim Shafiq


2 Answers

Here is a working code. I do not check some case of error (input file badly formatted, for example). I put some commentaries, though the code itself is not difficult to understand.

#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <ctype.h>

#define BMP_ASSERT(condition, message) \
    do { \
        if (! (condition)) { \
            fprintf(stderr, __FILE__ ":%d: %s: Assertion `" #condition \
                "` failed.\n\t: %s\n", __LINE__, __func__, message); \
            exit(EXIT_FAILURE); \
        } \
    } while (false)

#define BMP_COLORMAP_SIZE   10

////////////////////////////////////////////////////////////////////////////////
// STRUCTS

typedef struct __attribute__((__packed__))
bmp_color 
{
    uint8_t             r,
                        g,
                        b;
    uint8_t             :8;
}                       bmp_color_t;

typedef struct __attribute__((__packed__))
bmp_header_infos
{
    uint32_t const      info_size;
    uint32_t            width;
    uint32_t            height;
    uint16_t const      planes;
    uint16_t const      bpp;
    uint32_t const      compression;
    uint32_t            img_size;
    uint32_t const      horz_resolution;
    uint32_t const      vert_resolution;
    uint32_t const      n_colors;
    uint32_t const      n_important_colors;
}                       bmp_header_infos_t;

typedef struct __attribute__((__packed__))
bmp_header
{
    /* Header */
    char const          signature[2];
    uint32_t            file_size;
    uint32_t const      :32; // reserved
    uint32_t const      img_offset;
    /* Infos */
    bmp_header_infos_t  infos;
    /* Color map */
    bmp_color_t         colormap[BMP_COLORMAP_SIZE];
}                       bmp_header_t;

typedef struct          bmp_file_datas
{
    size_t              width;
    size_t              height;
    /* Bit map */
    uint8_t             *bitmap;
}                       bmp_file_datas_t;


////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS

/* Give a header with the right magic values */
bmp_header_t *
bmp_get_header(void)
{
    static bmp_header_t _header = {
        {'B', 'M'},
        0u,
        sizeof(_header),
        {   // struct info
            sizeof(_header.infos),
            0u, 0u, // width, height
            1u,     // planes
            8u,     // bpp
            0u,     // no compression
            0u,     // img size
            0u, 0u, // resolution
            BMP_COLORMAP_SIZE,
            BMP_COLORMAP_SIZE,      // important colors
        },
        {{0u}}
    };
    bmp_header_t        *header = malloc(sizeof(_header));
    size_t              i,
                        color;

    assert(header != NULL);
    memcpy(header, &_header, sizeof(*header));
    // setting the scale of greys
    for (i = 0 ; i < BMP_COLORMAP_SIZE ; ++i)
    {
        color = (i * 255) / BMP_COLORMAP_SIZE;
        header->colormap[i] = (bmp_color_t){color, color, color};
    }
    return header;
}

/* Take all the file content and store it in a buffer */
char *
get_file_content(char const *filename)
{
    FILE        *file_handler = fopen(filename, "r");
    size_t      file_len;
    char        *buff;

    BMP_ASSERT(file_handler != NULL, strerror(errno));
    fseek(file_handler, 0, SEEK_END);
    file_len = ftell(file_handler);
    fseek(file_handler, 0, SEEK_SET);
    buff = malloc(file_len + 1);
    assert(buff != NULL);
    fread(buff, file_len, 1, file_handler);
    buff[file_len] = '\0';
    fclose(file_handler);
    return buff;
}

/* Get the greatest multiple of 4 that is >= size */
static inline size_t
multiple_of_four(size_t size)
{
    while (size % 4)
        ++size;
    return size;
}

/* Get the informations from buffer: size of line, number of lines */
void
get_file_infos(char *buff, bmp_header_t *header, bmp_file_datas_t *datas)
{
    /* width & height */
    header->infos.width =  strchr(buff, '\n') - buff;
    header->infos.height = strlen(buff) / (header->infos.width + 1);
                                            // + 1 for the terminating '\n'
    datas->width = multiple_of_four(header->infos.width);
    datas->height = header->infos.height;
printf("File size: %u, %u\n", header->infos.width, header->infos.height);
    /* image size & bitmap allocation */
    header->infos.img_size = datas->width * datas->height;
    datas->bitmap = malloc(header->infos.img_size * sizeof(*datas->bitmap));
    assert(datas->bitmap != NULL);
    header->file_size = header->img_offset + header->infos.img_size;
}

/* Take the informations from the buffer and store them in the bitmap */
void
write_bitmap(char *buff, bmp_file_datas_t *datas)
{
    size_t          ibuff,
                    iline = 0,
                    ibitmap = 0;

    for (ibuff = 0 ; buff[ibuff] ; ++ibuff)
    {
        if (isdigit(buff[ibuff]))
        {
            datas->bitmap[ibitmap] = BMP_COLORMAP_SIZE - 1 - (buff[ibuff] - '0');
            ++ibitmap;
        }
        else if (buff[ibuff] == '\n')
        {
            ++iline;
            ibitmap = iline * datas->width;
        }
    }
}

/* Write the datas in the file: the header and the bitmap */
void
write_in_file(bmp_header_t *header,
              bmp_file_datas_t *datas,
              char const *filename)
{
    FILE        *file_handler = fopen(filename, "w");

    BMP_ASSERT(file_handler != NULL, strerror(errno));
    fwrite(header, sizeof(*header), 1, file_handler);
    fwrite(datas->bitmap, header->infos.img_size, 1, file_handler);
    fclose(file_handler);
}


int main(int argc, char **argv)
{
    char                *buff;
    bmp_header_t        *header;
    bmp_file_datas_t    datas;

    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s <input filename> <output filename>\n",
                                argv[0]);
        return EXIT_FAILURE;
    }
    buff = get_file_content(argv[1]);
    header = bmp_get_header();
    get_file_infos(buff, header, &datas);
    write_bitmap(buff, &datas);
    write_in_file(header, &datas, argv[2]);
    free(buff), free(header), free(datas.bitmap);
    return EXIT_SUCCESS;
}
like image 87
Boiethios Avatar answered Sep 22 '22 17:09

Boiethios


A crude method to achieve the required functionality would be: (Not really C, but then it is your homework not mine)

WIDTH = 0, HEIGHT = 0
if(LINE=READ_LINE(fin))
  WIDTH = strlen(LINE)
  ++HEIGHT
else
  ERROR!!!
PUSH(LINE)
while(LINE=READ_LINE(fin))
  if(WIDTH != strlen(LINE))
    ERROR!!!
  else
    ++HEIGHT
    PUSH(LINE)
WRITE_BMP_HEADER(WIDTH, HEIGHT)
for(h = 0; h < HEIGHT; ++h)
  LINE = POP()
  for(w = 0; w < WIDTH; ++w)
    COLOR = (LINE[w] - '0') * 255 / 9;
    WRITE_BMP_COLOR(COLOR)
  WRITE_BMP_PADDING(W)
like image 33
Mohit Jain Avatar answered Sep 22 '22 17:09

Mohit Jain