Solved

bmpsize to small??

Posted on 2003-10-31
6
304 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:André123
Comment Utility
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
Comment Utility
Look at the notes ive written ^^
0
 
LVL 3

Expert Comment

by:RJSoft
Comment Utility
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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
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…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

762 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

11 Experts available now in Live!

Get 1:1 Help Now