?
Solved

BMP Images

Posted on 2003-03-20
10
Medium Priority
?
1,556 Views
Last Modified: 2013-11-19
I have two dimensional array of 8 bit values of dimensions 512 x 512 which stores the pixel information of a 8 bit monochrome image.

I need to do two things with this data, firstly I need to display it on screen as an image and secondly I need to save it to disk as a BMP image (so similar standard).

Many thanks,

Alex Baskeyfield
0
Comment
Question by:Alex_Baskeyfield
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
10 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 8173336
That is OS-specific.  What OS?
0
 
LVL 22

Expert Comment

by:nietod
ID: 8173358
For windows this can get very complicated.   You woudl really need to learn windows programming, which is well beyond the scope of a single question.  There are whole books (1000s of them) on the subject.

But here is some annotated code used to display a bitmap in windows.  I suspect it won't make any sense to you at all.  You woudl have to learn a lot first.

***********************************************
You can copy a bitmap, or a portion of a bitmap between two compaible DC's using BitBlt.  So to copy a bitmap to the screen you need to create a DC that is compatible with the screen and copy the source bitmap from it to the screen.

First you need to have a Source DC, this is a memory DC for the source bitmap, that is the image to be copied to the display.  This DC must be compatible with the source bitmap and (since the source bitmap is compatible with the display) also compatible with the display.  You can use

HDC SrcDC = CreateCompatibleDC(DspDC);

to create a memory DC (SrcDC) that is compatible with the display DC (DspDC).  (The display DC may be a window's DC or a DC for the screen (display) obtaned with CreateDC().)

Next you need to select the source bitmap into the source DC.  Now this works like selecting any other tool, you must save the previous tool so you can select it back in before the DC is returned to the OS.  So you would do

HBITMAP OldSrcBmp = SelectObject(SrcDC,SrcBmp);

Now the memory DC contains the bitmap to be copied.  You can copy the source DC's image to the destination DC using BitBlt().

Next you need to clean up.  You do this by selecting the original bitmap back into the memory DC and then deleting the DC.  Like

SelectObject(SrcDC,OldSrcBmp);
DeleteDC(ScrDC);

Let me know if you have any questions.

***********************************************
0
 
LVL 22

Expert Comment

by:nietod
ID: 8173381
When it comes to creating the bitmap   I think your best bet is to use CreateDIBSection  (Again this is for windows only).  This will create a bitmap whose memory you can "write" to directly.   so you could then use memcopy() or a similar operation to copy your bitmal data to this bitmap.

I hope this helps some.   I think you've got a lot to learn.   (And you'll need to create a windows program in order to have a window in which to display it....)
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 5

Expert Comment

by:Kocil
ID: 8173528
It's easy on Borland :)


// array = the 2D data, width x height
HPALLETE CreateBWPallete()
{
   TLogPallete* pal;
   HPALETTE hpal;
   int i;

    pal = malloc(sizeof(TLogPalette) + sizeof(TPaletteEntry) * 256);
    pal->palVersion := 0x300;
    pal->palNumEntries := 256;
    for(i=0; i<=255; i++) {
      pal->palPalEntry[i].peRed := i;
      pal->palPalEntry[i].peGreen := i;
      pal->palPalEntry[i].peBlue := i;
    }
    hpal := CreatePalette(pal);
    free(pal);
    return hpal;
}


ConvertAndSave(char *array, int width, int height, char *fname)
{
    int x,y;
    unsigned char *p;
    TBitmap* bitmap;

    bitMap = new TBitMap();
    bitmap->PixelFormat := pf8bit;
    bitmap->Height = height;
    bitmap->Width = width;
    for (y = 0; y<height; y++) {
      p = bitmap->ScanLine(y);
      for (x = 0; x<width; x++) {
        *p := array++; p++;
      }
    }
   
    // change the pallete
    bitmap->Pallete = CreateBWPallete();
   
    // save to file
    bitmap->SaveToFile(fname);

    // free the bitmap
    bitMap->Free();
}

Note: I converted my Delphi source code for this. The VCL objects is the same, but I can't guarentee it.
Please crosscheck it with the BCB's help.

0
 
LVL 22

Expert Comment

by:nietod
ID: 8173652
easy?  

I don't think that word means what you think it means -- The Princess bride
0
 
LVL 12

Accepted Solution

by:
Salte earned 480 total points
ID: 8173745
I would believe your best bet is to learn the BMP format and then simply write the data to a BMP file. If you want to display it you can then either display the BMP data from memory or you can tell windows to open the BMP file and display it.

In either case, the displaying is system specific.

The creation of the BMP file is just making a file and as such isn't system specific at all - you can easily write a utility that creates bmp files on unix. If you want to dispaly them you probably have to take them to a windows machine first but that's a different story.

The short story of the bmp format is this:

The .bmp file has first a BMP file header immediately followed by a BMP header immediately followed by a palette if the file format uses palette immediately followed by image data. If the file has no palette the image data will be just after the BMP header.

The BMP file header and BMP header is defined in Win32 and inspecting any help file on Win32 or include file in windows will show you what those headers look like. They are fixed size records. On other machines you must make sure you pick the right sizes for the fields and also that you get correct padding etc.

The headers will have info about the size of the image in height and width (number of lines and number of pixels per line) as well as how many bits per pixel. Bits per pixel can only take the values 8, 24 and 32. Palette is only used for the 8 bit per pixel version while the 24 and 32 do not use palette. There's no specific entry saying if you use palette or not, it is the bits per pixel value that implicitely indicates the presence or absence of the palette. If you use palette it is also important to know how many colors are present and so there's a field for that too. If you don't use palette such info are rather useless and that member is not defined for formats without palette.

So, there are the following important info stored in the headers that are required to interpret the rest of the image properly:

W = width == number of pixels per line.
H = height == number of lines of the image.
C = number of colors (only defined if palette is used).
bpp == bits per pixel == 8, 24 or 32.

There is also the important info indicating size of palette entry. I am not sure if that size is fixed and is always 32 bits or if the size can be either 24 or 32. If it can vary I am sure the header have a member giving the size.

The size of the headers are fixed. THe offset for the file header is at offset 0. The BMP header is at offset immediately after the file header and so has offset: sizeof(file_header)

The palette if present has offset sizeof(file_header) + sizeof(bmp_header).

The image data has offset equal to sizeof(file_header) + sizeof(bmp_header) + sizeof(palette_entry) * C.

If palette is not used C == 0 and so the image data start immediately after the bmp_header.

IF palette is used there is some extra padding between the end of the palette and the beginning of the image data. The point is that image data always start at an offset that is a multiple of 4. So if you get an offset like 503 from the above then the image data start at 504 and there's a byte of padding.

To add padding to a value to make it divisible by 4 you can use this formula:

off = (off + 3) & ~3;

I believe the headers also have this offset to the image data stored directly in the header so you don't have to compute it.

sizeof(palette_entry) == 3 if the palette entry is 24 bits (RGB) and 4 if the palette entry has 32 bits (RGBA).

The image data is an array of line data. There's one line data for each line so the image data is simply an array of H line_data objects.

The line data is an array of pixel data followed by padding so that the size of line_data is always a multiple of 4. Each line_data always start at an offset in the file that is a multiple of 4. Each line is padded with 0-3 bytes to ensure that the next line comes at a 4 byte boundary.

I don't remember right now if the lines are stored top down or bottom up, but that is easy enough to fix if you get it wrong so I wouldn't worry too much about that.

The line data is then just an array of W pixel data entries, read from left to right. so the left most pixel is stored in the first entry and the right most pixel is stored in the last entry (the one with higher offset).

Each pixel data is either 1 byte (if 8 bit per pixel using palette) or 3 bytes (if 24 bits per pixel using RGB) or 4 bytes (if 32 bits per pixel using RGBA).

In your case you will most likely just store each pixel byte as one byte of pixel data. So you can probably just do a memcpy() to copy the original pixel data to the bmp line_data. If your original format also have such padding between lines you can even just do a raw copy of the whole image:

memcpy(bmp_image_data_ptr,raw_image_ptr,line_size * H);

where line_size is:

line_size = (W + 3) & ~3; // if bits per pixel is 8.
line_size = (3*W + 3) & ~3; // if bits per pixel is 24
line_size = 4*W; // if bits per pixel is 32.

The palette must be set to the greyscale tones, for an 8 bit grey scale image the obvious setting is:

palette index x is set to the value R=x, G=x, B=x.
A if present is set to 0.
The palette is also just a simple array of palette entries. The palette entry is either RGB for a 24 bit palette entry size or RGBA for a 32 bit palette entry size.

The A is the "alpha channel" or transparency.

A = 0 means opaque, the pixel's value is the value of the destination pixel displayed.

A = 255 means transparent, the pixel's RGB value is ignored and the underlying pixel is shown through.

Any value between those two extremes menas that the displayed pixel's RGB value is a mix of the pixel's RGB value and the underlying RGB value.

In your case I assume you want a non-transparent image so you set the A value to 0 if it is present.

Hope this is of help.

Alf
0
 
LVL 22

Expert Comment

by:nietod
ID: 8173827
>> The creation of the BMP file is just making a file and as such isn't
>> system specific at all
Yes and no.  It still depends on what OS the bitmap file is for.  Mac bitmaps are definitely different than Windows, for example.   And dislaying the bitmap is very OS-specific.
0
 
LVL 12

Expert Comment

by:Salte
ID: 8173917
Well, with BMP file I meant the specific Windows BMP file format. I am not familiar with any MAC BMP format.

However, it is not system specific in the sense that the format is well documented and if you can read/write bytes on a machine you can produce a BMP file on that system. You can convert GIF, JPG etc images to BMP format and you can convert BMP format to other such image formats.

If you want to DISPLAY the image it is of course system specific in that you have to use a system that support displaying such images - as far as I know only windows and similar PC systems does that (OS/2 etc).

However, you can still display it indirectly if you can convert it to GIF or JPEG and display that file, but then you have changed the format and it isn't a BMP file anymore.

Alf
0
 
LVL 22

Expert Comment

by:nietod
ID: 8238346
Giveing Salte a C for that seems a bit unfair!   It may not answer all your questions completely, but it wasn't intended to either.  You'ved asked a very very big question (one that involves some intensive programming and a lot of study), you aren't going to get a complete, detailed answer from a single expert.   If you are not satisfied with what experts have posted, you can ask additional questions to understand soecific portions of such a large answer.  
0
 

Author Comment

by:Alex_Baskeyfield
ID: 8241740
Salte,

My appologies for giving you a grade C, I thought that I gave you a grade A as I found your answer very helpful and am currently using your advice. again, my appologies
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
Learn how to set up basic frames and paths in Prezi and understand the open space that Prezi allows you to create presentations in.
It’s easy to embed any of your public Prezi presentations on your website or social network to share with others. Learn how simple it is in this tutorial.
Suggested Courses
Course of the Month14 days, 4 hours left to enroll

801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question