Reading uncompressed 24bit bitmaps

AceInfinity

Emeritus, Contributor
Joined
Feb 21, 2012
Posts
1,728
Location
Canada
I understand that this can be done by finding the fixed offset of the image data through stream seek functions, and then read into a byte array, and removing all the padding from there, but this is more of an introduction code to a side project I have, so I have the full structures in place for future things.

This example code will read an uncompressed (non RLE-encoded) 24-bit BMP and output the raw image data in BGR format in a similar hex table format to stdout along with some other information parsed from the information header. With some modification you can write this data to a file...

I take the raw data and remove all of the bitmap padding until I get an array of BGR structs. This will enable me to re-write the bitmap into different dimensions while maintaining the image size (in terms of # of pixels) if I wanted.

I really want to use this and combine it with an algorithm for sharp and clean upscaling -- for higher resolutions. I still have to implement an algorithm for this but I have something in my head currently to do this.

Anyways here's the code. Thought I'd post it to help others out. Compiled with GCC:

Code:
[NO-PARSE]#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define OFFSET_HEX_FMT "%.8X | "

#pragma pack(1)
typedef struct
{
  /* 0x00 */ short signature;    /* BMP signature (must be 0x4D42) */
  /* 0x02 */ int   filesize;     /* BMP filesize - unreliable */
  /* 0x06 */ short reserved_1;   /* reserved (must be 0) */
  /* 0x08 */ short reserved_2;   /* reserved (must be 0) */
  /* 0x0A */ int   image_offset; /* offset of image data (in bytes) */
} BMP_HEADER;

#pragma pack(1)
typedef struct
{
  /* 0x0E */ int   size;                   /* sizeof BMPINFOHEADER (40) */
  /* 0x12 */ int   img_width;              /* image width */
  /* 0x16 */ int   img_height;             /* image height */
  /* 0x1A */ short planes;                 /* number of image planes (1) */
  /* 0x1C */ short bits;                   /* bits per pixel (1, 4, 8, or 24) */
  /* 0x1E */ int   compression;            /* compression type (0 = none, 1 = RLE-8, 2 = RLE-4) */
  /* 0x22 */ int   img_size;               /* sizeof image data in bytes (including padding) */
  /* 0x26 */ int   horizontal_resolution;  /* horizontal resolution (pixels per meter) - unreliable */
  /* 0x2A */ int   vertical_resolution;    /* vertical resolution (pixels per meter) - unreliable */
  /* 0x2E */ int   bgr_colors;             /* number of bgr_colors in image (or zero) */
  /* 0x32 */ int   important_bgr_colors;   /* number of important bgr_colors (or zero) */
} BMP_INFO_HEADER;

typedef struct
{
  unsigned char blue;
  unsigned char green;
  unsigned char red;
} BGR;


int main(void)
{
  int ret = 0;
  int i, offset, num_pixels, pad_len;

  unsigned char *raw_data = NULL;
  BGR *bgr_colors = NULL;

  BMP_HEADER header = { 0 };
  BMP_INFO_HEADER info_header = { 0 };

  FILE *fp = fopen("untitled.bmp", "rb");
  if (!fp)
  {
    ret = -1;
    goto end;
  }

  fread(&header, 1, sizeof(BMP_HEADER), fp);
  fread(&info_header, 1, sizeof(BMP_INFO_HEADER), fp);

  if (info_header.bits != 24)
  {
    fputs("Error: Not a 24bit bitmap.\n", stderr);
    ret = -1;
    goto end;
  }

  printf("Image dimensions: %d x %d\n", info_header.img_width, info_header.img_height);
  printf("Image size: %d bytes\n", info_header.img_size);
  fputs("\n", stdout);

  /* -----------------------------------
   *    Read RAW image data from file
   * ----------------------------------- */
  raw_data = malloc(info_header.img_size);
  fread(raw_data, 1, info_header.img_size, fp);

  /* ----------------------------------------------------
   *    Copy pixel data to BGR array (without padding)
   * ---------------------------------------------------- */
  pad_len = info_header.img_width % 4;
  num_pixels = info_header.img_size / 3;
  bgr_colors = malloc(sizeof(BGR) * num_pixels);
  for (i = 0; i < num_pixels; ++i)
  {
    memcpy(&bgr_colors[i],
           (raw_data + i) + (pad_len * (i / info_header.img_width)),
           sizeof(BGR));
  }

  /* ------------------------------
   *    Display RAW image data
   * ------------------------------ */
  offset = 0;

  printf("RAW Image Data:\n");
  printf("%*c00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n", 11, ' ');
  printf("%*c-----------------------------------------------\n", 11, ' ');
  printf(OFFSET_HEX_FMT, offset);

  for (i = 0; i < info_header.img_size; ++i)
  {
    printf("%.2X ", raw_data[i]);

    if ((i + 1) % 16 == 0)
    {
      fputs("\n", stdout);
      printf(OFFSET_HEX_FMT, (offset += 16));
    }

  }

  /*for (i = 0; i < num_pixels; ++i)
  {
    printf("%.2X %.2X %.2X ",
           bgr_colors[i].blue,
           bgr_colors[i].green,
           bgr_colors[i].red);
  }*/

end:
  if (fp) fclose(fp);
  if (raw_data) free(raw_data);
  if (bgr_colors) free(bgr_colors);
  exit(ret);
}[/NO-PARSE]

ANSI C (C89) standard compliant code :thumbsup2:
 
Last edited:
Example output:
rqqmwwN.png
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top