Solved

bmpsize to small??

Posted on 2003-10-31
6
308 Views
Last Modified: 2008-02-01
I compiled the following code, which produces working bmp's (24bit color;size:1.5 MB), when I take a screenshot and paste it in mspaint, it produces a bmp with size 2.5 MB (also 24 bits color). The bmp's with the compiled code can't be read with certain programs (photoeditor,....).
My question is: how can I adapt my code (without using the libraries from www.smalleranimals.com or sth like this) so that it produces the 2.5 MB screenshots ????

Thanks.
*****


#include "stdafx.h"

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

int CaptureBMP();


/*void main(int argc,char *argv[])
{
int a=CaptureBMP();
}*/

int main(int argc, char* argv[])
{
int a=CaptureBMP();

      return 0;
}




int CaptureBMP()
{
     // Source[1]
     HDC hdcScr, hdcMem;
     HBITMAP hbmScr;
     BITMAP bmp;
     int iXRes, iYRes;
 
     // Create a normal DC and a memory DC for the entire screen. The
     // normal DC provides a "snapshot" of the screen contents. The
     // memory DC keeps a copy of this "snapshot" in the associated
     // bitmap.
     hdcScr = CreateDC("DISPLAY", NULL, NULL, NULL);
     hdcMem = CreateCompatibleDC(hdcScr);
 
     iXRes = GetDeviceCaps(hdcScr, HORZRES);
     iYRes = GetDeviceCaps(hdcScr, VERTRES);
 
     // Create a compatible bitmap for hdcScreen.
  hbmScr = CreateCompatibleBitmap(hdcScr, iXRes, iYRes);
     if (hbmScr == 0) return 0;
 
     // Select the bitmaps into the compatible DC.
     if (!SelectObject(hdcMem, hbmScr)) return 0;
 
     // Copy color data for the entire display into a
     // bitmap that is selected into a compatible DC.
     if (!StretchBlt(hdcMem,
          0, 0, iXRes, iYRes,
          hdcScr,
          0, 0, iXRes, iYRes,
          SRCCOPY))
 
          return 0;
 
     // Source[2]
     PBITMAPINFO pbmi;
    WORD cClrBits;
 
     // Retrieve the bitmap's color format, width, and height.
     if (!GetObject(hbmScr, sizeof(BITMAP), (LPSTR) &bmp)) return 0;
 
     // Convert the color format to a count of bits.
     cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
     if (cClrBits == 1)
          cClrBits = 1;
     else if (cClrBits <= 4)
          cClrBits = 4;
     else if (cClrBits <= 8)
          cClrBits = 8;
     else if (cClrBits <= 16)
          cClrBits = 16;
     else if (cClrBits <= 24)
          cClrBits = 24;
     else cClrBits = 32;
 
     // Allocate memory for the BITMAPINFO structure. (This structure
     // contains a BITMAPINFOHEADER structure and an array of RGBQUAD
     // data structures.)
     if (cClrBits != 24)
          pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER) +
                    sizeof(RGBQUAD) * (1 << cClrBits));
 
     // There is no RGBQUAD array for the 24-bit-per-pixel format.
     else
          pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER));
 
     // Initialize the fields in the BITMAPINFO structure.
     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
     pbmi->bmiHeader.biWidth = bmp.bmWidth;
     pbmi->bmiHeader.biHeight = bmp.bmHeight;
     pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
     pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
     if (cClrBits < 24)
          pbmi->bmiHeader.biClrUsed = (1 << cClrBits);
 
     // If the bitmap is not compressed, set the BI_RGB flag.
     pbmi->bmiHeader.biCompression = BI_RGB;
 
     // Compute the number of bytes in the array of color
     // indices and store the result in biSizeImage.
     pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) / 8
                                   * pbmi->bmiHeader.biHeight * cClrBits;
 
     // Set biClrImportant to 0, indicating that all of the
     // device colors are important.
     pbmi->bmiHeader.biClrImportant = 0;
 
     HANDLE hf;                  // file handle
     BITMAPFILEHEADER hdr;       // bitmap file-header
     PBITMAPINFOHEADER pbih;     // bitmap info-header
     LPBYTE lpBits;              // memory pointer
     DWORD dwTotal;              // total count of bytes
     DWORD cb;                   // incremental count of bytes
     BYTE *hp;                   // byte pointer
     DWORD dwTmp;
 
     pbih = (PBITMAPINFOHEADER) pbmi;
     lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
 
     if (!lpBits) return 0;
 
     // Retrieve the color table (RGBQUAD array) and the bits
     // (array of palette indices) from the DIB.
     if (!GetDIBits(hdcMem, hbmScr, 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS)) return 0;
 
     // Create the .BMP file.
     hf = CreateFile("E:\\2.bmp",
                         GENERIC_READ | GENERIC_WRITE,
                         (DWORD) 0,
                         NULL,
                         CREATE_ALWAYS,
                         FILE_ATTRIBUTE_NORMAL,
                         (HANDLE) NULL);
     if (hf == INVALID_HANDLE_VALUE) return 0;
 
     hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
 
     // Compute the size of the entire file.
     hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
                     pbih->biSize + pbih->biClrUsed *
                     sizeof(RGBQUAD) + pbih->biSizeImage);
     hdr.bfReserved1 = 0;
     hdr.bfReserved2 = 0;
 
     // Compute the offset to the array of color indices.
     hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
                         pbih->biSize + pbih->biClrUsed *
                         sizeof (RGBQUAD);
 
     // Copy the BITMAPFILEHEADER into the .BMP file.
     if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL)) return 0;
 
     // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
     if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
                    + pbih->biClrUsed * sizeof (RGBQUAD),
                    (LPDWORD) &dwTmp, NULL))
          return 0;
 
     // Copy the array of color indices into the .BMP file.
     dwTotal = cb = pbih->biSizeImage;
     hp = lpBits;
     if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp, NULL)) return 0;
 
     // Close the .BMP file.
     if (!CloseHandle(hf)) return 0;
 
     // Free memory.
     GlobalFree((HGLOBAL)lpBits);
     ReleaseDC(0, hdcScr);
     ReleaseDC(0, hdcMem);
 
     return 1;
}
*****
0
Comment
Question by:André123
[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
  • 3
  • 2
6 Comments
 
LVL 2

Accepted Solution

by:
ZedFX earned 120 total points
ID: 9664328
I would advise you to write it to file byte-by-byte. Here is my code for writing bitmaps.

This is how a bitmap is built up

1. The File Header
2. The Info Header
3a. [Optional] The Colour Table
3b. The Bitmap Data

// File header data

member          data type     size in bytes     data it should contain
bfType          short     2          "BM"
bfSize          long     4          File Length (in bytes)
bfReserved1     short     2          two (char 0)
bfReserved2     short     2          two (char 0)
bfOffBits          long     4          File Length - biSizeImage

// Info header data

member          data type     size in bytes     data it should contain
biSize          long     4          sizeof(infoheader)
biWidth          long     4          width of bitmap
biHeight          long     4          height of bitmap
biPlanes          short     2          number of planes (usually 1, unless you are making some hi-tec app)
biBitCount          short     2          number of bits (i will cover using 8 and 24)
biCompression     long     4          0 (unless you are using RLE compression)
biSizeImage     long     4          (Width + 2) * Height (plus 2 for padding)
biXPelsPerMeter     long     4          0 (it is easier to let this be decided automatically, uses standard resolution)
biYPelsPerMeter     long     4          0 (it is easier to let this be decided automatically, uses standard resolution)
biClrUsed          long     4          0 (specifies number of colours used from the table
biClrImportant     long     4          0 (specifies important colours)

that covers the first 54 bytes of the file

// Colour Table [Optional]

if you have an 8 bit bitmap or less then you need a colour table. I shall only tell you about 8 bit bitmaps here because the other types are harder to do.

A colour table specifies the colours you use in your bitmap. In an 8 bit bitmap there will be 256 colours (from 0 to 255)
The next 1024 bytes of the file are the colour table.

format: B,G,R,(char 0) // 4 bytes, 1 colour

// Bitmap Data

In an 8 bit bitmap each pixel of the bitmap will be 1 byte (a reference to the colour table), in a 24 bit bitmap each pixel is 3 bytes (the pure colour).
There are 2 bytes of (char 0) padding following every line of pixels.

eg. imagine a bitmap like so:

red     blue     red
green     green     purple

3 pixels long and 2 pixels high

go along the first row, passing the data, then padding, then the next row

passdata << red
passdata << blue
passdata << red
passdata << (char 0)
passdata << (char 0)
passdata << green
passdata << green
passdata << purple
passdata << (char 0)
passdata << (char 0)

as a 24 bit bitmap it would look something like this:
0  0  255  255  0  0  0  0  255  0  0  0  255  0  0  255  0  255  0  255  0  0

as an 8 bit bitmap it would look somehting like this (assuming colour table where red = 0, blue = 1, green = 2 and purple = 3):
0  1  0  0  0  2  2  3  0  0

i hope there is enough information there for you to do some coding with it becuase it took me ages to come up with that !

(i actually only worked out the code about a week ago for my own uses)

Enjoy ;-)

ZedFX
0
 
LVL 2

Expert Comment

by:ZedFX
ID: 9664329
well its not exactly code is it, eesh. I hope it solves your problem tho.
0
 
LVL 3

Assisted Solution

by:RJSoft
RJSoft earned 80 total points
ID: 9676123
You need to call GetDiBits twice. Once to correctly fill the values in the BITMAPINFOHEADER and another obtain the bits. Then write the file.

In this example I wanted to capture an image and then blur it with a function from a library I purchased. Only thing was it was way too slow.

Have fun!

RJSoft

void Flame::BlurTheFlame(HWND hw,HDC MemDC,HBITMAP hNewBitmap,RECT rr)
{
int WIDE=rr.right-rr.left;
int HIGH=rr.bottom-rr.top;
//
int PaletteColors=(GetDeviceCaps(MemDC,RASTERCAPS) & RC_PALETTE);
//
DWORD Size=sizeof(BITMAPINFOHEADER)+PaletteColors*sizeof(RGBQUAD);
LPBITMAPINFO lpbi=(LPBITMAPINFO)(new char[Size]);
//
BITMAP bmp;::GetObject(hNewBitmap,sizeof(BITMAP),&bmp);
//
lpbi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpbi->bmiHeader.biWidth=bmp.bmWidth;
lpbi->bmiHeader.biHeight=bmp.bmHeight;
lpbi->bmiHeader.biPlanes=bmp.bmPlanes;
lpbi->bmiHeader.biBitCount=bmp.bmPlanes*bmp.bmBitsPixel;
lpbi->bmiHeader.biCompression=BI_RGB;
lpbi->bmiHeader.biSizeImage=0;
lpbi->bmiHeader.biXPelsPerMeter=0;
lpbi->bmiHeader.biYPelsPerMeter=0;
lpbi->bmiHeader.biClrUsed=0;
lpbi->bmiHeader.biClrImportant=0;
//
//Use GetDIBits to Load bi information
int NumberOfScanLines=GetDIBits(
  MemDC,             // handle to device context
  hNewBitmap,        // handle to bitmap
  0,                 // first scan line to set in destination bitmap
  HIGH,              // number of scan lines to copy
  NULL,              // address of array for bitmap bits
  lpbi,              // address of structure with bitmap data
  DIB_RGB_COLORS     // RGB or palette index
);
//
if(NumberOfScanLines==0)
{
::MessageBox(NULL,"GetDiBits Failed 1","ERROR",MB_OK);
delete []lpbi;
return;
}
//
//if (lpbi->bmiHeader.biBitCount <= 1)lpbi->bmiHeader.biBitCount = 1;
//else if (lpbi->bmiHeader.biBitCount <= 4)lpbi->bmiHeader.biBitCount = 4;
//else if (lpbi->bmiHeader.biBitCount <= 8)lpbi->bmiHeader.biBitCount = 8;
//else lpbi->bmiHeader.biBitCount = 24;
//
// Create memory for bits
//
LPVOID lpbvBits = ::GlobalAlloc(GMEM_FIXED,lpbi->bmiHeader.biSizeImage);
//
// Now get actual bits
NumberOfScanLines=GetDIBits(
      MemDC,
      hNewBitmap,
      0,
      HIGH,//lpbi->bmiHeader.biHeight,
      lpbvBits,(LPBITMAPINFO)lpbi,DIB_RGB_COLORS);
if(NumberOfScanLines==0)
{
::MessageBox(NULL,"GetDIBits failed 2","sorry",MB_OK);
delete []lpbi;
::GlobalFree(lpbvBits);
return;
}
//else MessageBox(NULL,"GOOD","GOOD",MB_OK);
//
//reverse the bits for library
char *CharMem = new char[lpbi->bmiHeader.biSize];
::memcpy(CharMem,lpbvBits,lpbi->bmiHeader.biSize);
_strrev( CharMem);//reverse
::memcpy(lpbvBits,CharMem,lpbi->bmiHeader.biSize);
//
delete []CharMem;
//
Image Im;
//const unsigned int WW=rr.right-rr.left;
//const unsigned int HH=rr.bottom-rr.top;
Im.read(WIDE,HIGH,"RGB",CharPixel,lpbvBits);
Im.blur(1,2);
//
delete []lpbi;
::GlobalFree(lpbvBits);

}//endfunc
0
Industry Leaders: 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!

 

Author Comment

by:André123
ID: 9697280
thanks, but it didn't worked.
Do you happen to know how I should adapt the code so that the produced bmp is an 8-bits-colordepth bitmap??
0
 
LVL 2

Expert Comment

by:ZedFX
ID: 9721458
Look at the notes ive written ^^
0
 
LVL 3

Expert Comment

by:RJSoft
ID: 10115617
Also I should have removed the reverse string thing in the code as it was specific to the library. In short dont reverse.

As for your question of how to make an 8 bit color depth just set the biBitCount to 8.

//if (lpbi->bmiHeader.biBitCount <= 1)lpbi->bmiHeader.biBitCount = 1;
//else if (lpbi->bmiHeader.biBitCount <= 4)lpbi->bmiHeader.biBitCount = 4;
//else if (lpbi->bmiHeader.biBitCount <= 8)lpbi->bmiHeader.biBitCount = 8;
//else lpbi->bmiHeader.biBitCount = 24;


RJ
0

Featured Post

Independent Software Vendors: 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

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

726 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