Solved

bmpsize to small??

Posted on 2003-10-31
6
305 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
  • 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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Handling string inputs in C/Linux 23 179
Fast, free, private online code repository / editor 7 90
Safe conversion? 4 58
What is sub-make ? 2 39
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…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
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 viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

896 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now