26996 total geeks with 3514 solutions
Recent challengers:
 Welcome, you are an anonymous user! [register] [login] Get a yourname@osix.net email address 

Articles

GEEK

User's box
Username:
Password:

Forgot password?
New account

Shoutbox
ewheregoose
<ul><li><str ong><a href="http:/ /www.nikeck. com/">cheap nike shoes</a></s trong> </li> <li> <a href="http:/ /NikeStore30 2.webs.com"> cheap nike shoes</a></l i><li><stron g><a href="http:/ /www.nikeck. com/">nike cheap nike</a></st rong> </li>< li> <a href="http:/ /Ni
ewheregoose
[b]<a href="http:/ /www.cheapbe atsbydretop. com/">best beats<strong ><a href="http:/ /www.cheapbe atsbydretop. com/">best beats by dre outlet</a></ strong> <br> <strong><a href="http:/ /www.cheapbe atsbydretop. com/">Best Headphones Beats By Dre Outlet</a></ strong>
ewheregoose
[b][url=http ://www.seama steromega.co m/]1000 omega <strong><a href="http:/ /www.seamast eromega.com/ ">1000 omega watches</a>< /strong> <br > <strong><a href="http:/ /www.seamast eromega.com/ omega-basel- c-1.html">om ega 2013</a></st rong> <br>
ewheregoose
[b][url=http ://www.jewel leryfans.com /bracelets-a nd-bangles-c -1.h<strong> <a href="http:/ /www.jewelle ryfans.com/b racelets-and -bangles-c-1 .html">Cryst al Bracelets</a ></strong> < br> <strong><a href="http:/ /www.jewelle ryfans.com/b racelets-and -bangles-c-1 .html"
ewheregoose
<strong><a href="http:/ /www.jewelle ryfans.com/n ecklace-c-3. html">Crysta l Necklace</a> </strong> | <strong><a href="http:/ /www.jewelle ryfans.com/" >Crystal jewellery</a ></strong> | <strong><a href="http:/ /www.jewelle ryfans.com/" >jewelry</a> </strong> <b r>

Donate
Donate and help us fund new challenges
Donate!
Due Date: Aug 31
August Goal: $40.00
Gross: $0.00
Net Balance: $0.00
Left to go: $40.00
Contributors


News Feeds
The Register
Discovery BATTLED
2-foot-long WEE
ICICLE on first
mission - 30 years
ago today
Facebook to let
stalkers unearth
buried posts with
mobe search
Christmas comes
late for fanbois as
Apple wearable
release slips into
early 2015
Alienware inserts
EVEN MORE ALIEN
into redesigned
Area-51 gaming PC
Love XKCD? Love
science? You"ll
love a book about
science from
Randall Munroe
EE fails to
apologise for HUGE
T-Mobile outage
that hit Brits on
Friday
Britain"s housing
crisis: What are we
going to do about
it?
Are we there yet,
are we there yet?
Ballmer "like a
small child" upon
buying basketball<
Buh bye, MSN
Messenger.
Microsoft finally
flicks on KILL
SWITCH in China
Vulture News anchor
Regina Eggbert is
(sort of) LIVE from
London
Slashdot
RAYA: Real-time
Audio Engine
Simulation In Quake
Anand Lal Shimpi
Retires From
AnandTech
Microsoft Defies
Court Order, Will
Not Give Emails To
US Government
Wi-Fi Router Attack
Only Requires a
Single PIN Guess
Google"s Megan
Smith Would Be
First US CTO Worthy
of the Title
States Allowing
Medical Marijuana
Have Fewer
Painkiller Deaths
NASA"s Competition
For Dollars
Ask Slashdot: Best
Phone Apps?
Hidden Obstacles
For Google"s
Self-Driving Cars
Reformatting a
Machine 125 Million
Miles Away
Article viewer

A 24-bit v.3 BMP Primer



Written by:Christophe
Published by:Nightscript
Published on:2007-11-19 23:33:43
Topic:C
Search OSI about C.More articles by Christophe.
 viewed 10869 times send this article printer friendly

Digg this!
    Rate this article :
Where we will learn how to read in a Bitmap file, process it and write it back to file.

As I was working on the design of a new challenge for this website, I was looking for some cookbook on low-level image processing in C and couldn't find what I was looking for. So I decided to write this article, which sums up my findings on the subject.
I'll illustrate it with a portion of C code that reads in an image from a file, performs a 90 degree rotation on it, and writes the rotated image out to another file.

First of all, it looks like the 24-bit uncompressed BMP file format is one of the simplest image formats around, although not the more efficient. After an identification block and a short header containing some meta-data about the image (number of rows, number of columns, etc.), pixels in the image are stored sequentially in RGB format.

Although the BMP format is the native bitmap format of Windows, it is free of patents and thus widely used in image processing programs from many other operating systems.

Identification Block & Header
The format of the identification block looks like this:
  (bytes)    (field)

0 - 1 : Magical number used to identify the file type: 0x424D i.e. 'BM' for BitMap
2 - 5 : The size of the file (in bytes)
6 - 7 : Reserved (zero)
8 - 9 : Reserved (zero)
10 - 13 : Offset (starting address of the byte where the bitmap data can be found): 54 in our case

In the commonly used BMP Version 3 format, the format of the header looks like this:
  (bytes)     (field)

14 - 17 : The size of the header (40 bytes!)
18 - 21 : The width of the image (in pixels)
22 - 25 : The height of the image (in pixels)
26 - 27 : The number of color planes (1)
28 - 29 : The color depth of the image (number of bits per pixel): 24 in our case
30 - 33 : The compression method: 0 in our case (no compression)
34 - 37 : The size of the raw image data following the header (in bytes)
38 - 41 : The horizontal resolution (in pixels per meter)
42 - 45 : The vertical resolution (in pixels per meter)
46 - 49 : The number of colors used in the image (0 for all)
50 - 53 : The number of important colors used in the image (0 for all)

In the example below, we'll read in and write out these fields one at a time.
This is not necessary, of course, as we will be only interested in the width & height of the image.
As the BMP format originated on Intel-based machines, multibyte fields are stored in little-endian order. This is fine if (like me) you are using an x86 processor; however, you will need to adapt the code below if you want to run it on a big-endian architecture like the PowerPC!

Image Data
Now let's have a look at the encoding of the pixels themselves:

Pixels are stored from left to right starting from the bottom row of the picture, and ending with the top row.
In the 24-bit BMP format, the color of each pixel is represented by 3 bytes (remember there are 8 bits in 1 byte): 1 byte for Blue, 1 byte for Green, 1 byte for Red, in that order. So when I wrote that pixels were stored in RGB format, I would rather have written "BGR" !

Also, I should mention that for some unclear reason, each row of the image is padded to be a multiple of 4 bytes.

Let's look at the example below. We'll read from a file called "in.bmp" and write to a file called "out.bmp". Pixels will be stored in a multidimensional array:

/*
 * Read in an image from file "in.bmp"
 * Perform a 90 degree rotation on it
 * Write the rotated image out to file "out.bmp".
 *
 * Author: Christophe
 */

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

typedef unsigned short WORD;
typedef unsigned long DWORD;

/* Identification Block: */
   WORD FileType;
  DWORD FileSize;
   WORD Reserved1;
   WORD Reserved2;
  DWORD OffBits;

/* Header: */
  DWORD Size;
  DWORD Width;
  DWORD Height;
   WORD Planes;
   WORD BitCount;
  DWORD Compression;
  DWORD ImageSize;
  DWORD XPelsPerMeter;
  DWORD YPelsPerMeter;
  DWORD ClrUsed;
  DWORD ClrImportant;

typedef struct _RGB { unsigned char R,G,B; } RGB;
  RGB **pixel;

int main(int argc, char **argv) {
  FILE *f_in, *f_out;
  char zero=0;
  int i,j;

  /* Open input and output files: */
  if ( (f_in=(FILE *)fopen("in.bmp","r"))==NULL ) { perror("in.bmp"); exit(1); }
  if ( (f_out=(FILE *)fopen("out.bmp","w"))==NULL ) { perror("out.bmp"); exit(1); }

  /* Read & Write Identification Block: */
  fread(&FileType,2,1,f_in); fwrite(&FileType,2,1,f_out);
  if ( FileType != 0x4d42 ) { fprintf(stderr,"Not a BITMAP file!\n"); exit(1); }
  fread(&FileSize,4,1,f_in); fwrite(&FileSize,4,1,f_out);
  fread(&Reserved1,2,1,f_in); fwrite(&Reserved1,2,1,f_out);
  fread(&Reserved2,2,1,f_in); fwrite(&Reserved2,2,1,f_out);
  fread(&OffBits,4,1,f_in); fwrite(&OffBits,4,1,f_out);

  /* Read & Write Header: */
  fread(&Size,4,1,f_in); fwrite(&Size,4,1,f_out);
  fread(&Width,4,1,f_in);
  fread(&Height,4,1,f_in); /* Here we swap width and height for the rotation ! */
                           fwrite(&Height,4,1,f_out);
                           fwrite(&Width,4,1,f_out);
  fread(&Planes,2,1,f_in); fwrite(&Planes,2,1,f_out);
  fread(&BitCount,2,1,f_in); fwrite(&BitCount,2,1,f_out);
  fread(&Compression,4,1,f_in); fwrite(&Compression,4,1,f_out);
  fread(&ImageSize,4,1,f_in); fwrite(&ImageSize,4,1,f_out);
  fread(&XPelsPerMeter,4,1,f_in); fwrite(&XPelsPerMeter,4,1,f_out);
  fread(&YPelsPerMeter,4,1,f_in); fwrite(&YPelsPerMeter,4,1,f_out);
  fread(&ClrUsed,4,1,f_in); fwrite(&ClrUsed,4,1,f_out);
  fread(&ClrImportant,4,1,f_in); fwrite(&ClrImportant,4,1,f_out);

  /* Allocate memory to store the Bitmap Data: */
  pixel = (RGB **)malloc(Height*sizeof(RGB *))
  if (pixel == NULL) { fprintf(stderr,"Not enough memory!\n"); exit(1); }
  for(i=0; i<Height; i++) {
    pixel[i] = (RGB *)malloc(Width*sizeof(RGB))
    if (pixel[i] == NULL) { fprintf(stderr,"Not enough memory!\n"); exit(1); }
  }

  /* Read Bitmap Data: */
  for(i=0; i<Height; i++) {
    for(j=0; j<Width; j++) {
      pixel[i][j].B = fgetc(f_in);
      pixel[i][j].G = fgetc(f_in);
      pixel[i][j].R = fgetc(f_in);
    }
    for(j*=3; j%4!=0; j++) fgetc(f_in); // Padding row to 4-byte multiple!
  }

  /* The pixels are now stored in a multidimentional array. */
  /* To perform the rotation, we'll just write them out in a different order... */

  /* Write Bitmap data: */
  for(j=Width-1; j>=0; j--) {
    for(i=0; i<Height; i++) {
      fwrite(&pixel[i][j].B,1,1,f_out);
      fwrite(&pixel[i][j].G,1,1,f_out);
      fwrite(&pixel[i][j].R,1,1,f_out);
    }
    for(i*=3; i%4!=0; i++) fwrite(&zero,1,1,f_out); // Padding row to 4-byte multiple!
  }

  /* Free memory used to store the Bitmap Data: */
  for(i=0; i<Height; i++) free(pixel[i]);
  free(pixel);

  /* Close files: */
  fclose(f_in); fclose(f_out);
}

Of course, there are variants in the format that are not covered here.
Versions 4 and 5 of the BMP format have more fields in the header.
Also, things get a bit more complicated with lower color depths as colors get coded using a palette.
However, this article should give you a nice start for some basic image manipulation.

References:
Wikipedia: BMP file format
FileFormat.info: Microsoft Windows Bitmap File Format Summary


Did you like this article? There are hundreds more.

Comments:
Anonymous
2007-11-25 08:35:33
actually as i understand, the padding bytes are also stored in file...
One disadvantage of your program: why don't you read image data using offset?
Anonymous
2008-01-24 17:28:59
good but what to do for compresed (jpeg)
Anonymous
2008-03-30 21:03:30
"for some unclear reason, each row of the image is padded to be a multiple of 4 bytes"
I believe this is to speed up drawing operations, but I don't know that much about it.
IceDane
2008-10-16 02:03:34
Holy shit, that is some crappy code with some exceptionally useless statements. Creating a struct with the required fields, and perhaps __attribute__((packed)) to make sure it's exactly the size that is the sum of the parts, and then reading the file into a char buffer and making a pointer to such a struct point to the char buffer would be so, so much easier.


Anonymous
2008-11-14 01:23:04
Icedane you are full of ****. You have written no code, yet you spout tons of foolishness about another man's efforts. If you are an actual programmer at all, let's see your code. Bloody !%$&*@?$! Thanx Christophe for your efforts - it's definitely something I can analyse to write my own code.
alaniane
2009-06-05 19:56:50
The extra padding deals with aligning data on word boundaries for the older 8086/88 family of processors. Basically, a word in assembly on the 8086/8088 processors is 2 bytes. Registers for the processors were also 2 byte (16 bit) registers. By aligning your data on word boundaries you could speed up the transfering of data from memory to the register for processing.
Anonymous
2009-11-18 10:40:10
your code doesn't work for any othe bmp files for example the bmp files in mypictures folder in WindowsXP
Anonymously add a comment: (or register here)
(registration is really fast and we send you no spam)
BB Code is enabled.
Captcha Number:


Blogs: (People who have posted blogs on this subject..)
amisauv
Creating a Lexical Analyzer in C on Tue 9th Dec 11am
#include<stdio.h> #include<string.h> #include<conio.h> #include<ctype.h> /*************************************** ************************* Functions prototype. **************************************** *************************/ void Open_File(
amisauv
Controling digital circuit through computer on Tue 9th Dec 10am
this code access the lpt port.here only 4 of the total 8 pins are used but can be modified for full 8 pins.it has a complete GUI with mouse & keyboard interactive control panel.works well in win98, but not in winxp. #include<stdio.h> #include<conio.
amisauv
/* Computerised Electrical Equipment Control */ /* PC BASED DEVICE CONTROLLER * on Tue 9th Dec 10am
#include<stdio.h> #include<conio.h> #include<dos.h> void main() { void tone(void); int p=0x0378; char ex={"Created By Mrc"}; int j; char ex1={"For Further Details & Improvements"}; int k; char ex2={"Contact : E-mail : anbudan
amisauv
Calendar Program on Tue 9th Dec 10am
This program prints Weekdays of specified date. It even prints calendar of a given year too. /*Ccalendar library*/ #include<stdio.h> #include<string.h> #include<conio.h> int getNumberOfDays(int month,int year) { switch(month) { case
amisauv
Calculator: on Tue 9th Dec 10am
#include"graphics.h" #include"dos.h" #include"stdio.h" #include"math.h" union REGS i,o; char text={ "7","8","9","*","4","5","6","/","1","2", "3","+","0","00",".","-","M","M+", "M-","+/-","MR","MC","x^2","sr","OFF","A C","CE","="}; int s=0,k=0,pass
amisauv
INFECTED CODES WRITTEN IN C\C++ on Tue 9th Dec 10am
This is a simple code that changes system time and date. It is written using c/c++ but can be easily converted to java. #include "stdio.h" #include "process.h" #include "dos.h" int main(void) { struct date new_date; struct date old_date; s
amisauv
A C programme which can print the file name it is kept in on Tue 9th Dec 9am
amisauv
BOOTSECTOR EDITOR: on Tue 9th Dec 9am
Code : /*program to save the partion table of your hard disk for future use. it will save your partition table in a file partition.dat */ #include<stdio.h> #include<bios.h> #include<conio.h> #include<stdlib.h> #include<ctype.h> void main () {
amisauv
BLINKING STAR : on Tue 9th Dec 9am
#include<conio.h> #include<graphics.h> #include<stdlib.h> #include<dos.h> void main() { int gdriver=DETECT,gmode; int i,x,y; initgraph(&gdriver,&gmode,"e: cgi"); while(!kbhit()) { x=random(640); y=random(480); setcolor
amisauv
// To print semicolons using C programming without using semicolons any where i on Tue 9th Dec 9am
// To print semicolons using C programming without using semicolons any where in the C code in program. // #include<stdio.h> #include<conio.h> void main() { char a; a=59; if(printf("%c",a)){} getch();

Test Yourself: (why not try testing your skill on this subject? Clicking the link will start the test.)
BSD sockets API by skrye

This is a test of your knowledge of the BSD socket interface
C Programming by keoki

This test is aimed at a C programmer that is at an intermediate level.


     
Your Ad Here
 
Copyright Open Source Institute, 2006