Solved

bmpsize to small??

Posted on 2003-10-31
6
309 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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
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 tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

696 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