How to save bitmap to file in C++?

Post a reply


In an effort to prevent automatic submissions, we require that you complete the following challenge.
Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :| :mrgreen: :geek: :ugeek: :arrow: :angel: :clap: :crazy: :eh: :lolno: :problem: :shh: :shifty: :sick: :silent: :think: :thumbup: :thumbdown: :salute: :wave: :wtf: :yawn: :facepalm: :bravo: :dance: :beard: :morebeard: :xmas: :HeHe: :trollface: :cookie: :rainbow: :monkeysee: :monkeysay: :happybday: :headwall: :offtopic: :superhappy: :terms: :beer:
View more smilies

BBCode is ON
[img] is OFF
[flash] is OFF
[url] is ON
Smilies are ON

Topic review
   

Expand view Topic review: How to save bitmap to file in C++?

Re: How to save bitmap to file in C++?

Post by joedf » 18 Jun 2014, 00:09

Well, for me, for Bitmaps I used to use QDBMP (Quick n' Dirty BMP). It's really good :)
http://qdbmp.sourceforge.net/

Re: How to save bitmap to file in C++?

Post by brandonhotkey » 21 May 2014, 04:26

I have found some reading which can be useful. It compares differences between basic bitmap or graphics functions in GDI or GDI+:
http://www.jose.it-berater.org/smfforum ... pic=3661.0

Important information to me:
Well, GdipCreateBitmapFromGraphics creates a new, blank, usually solid black bitmap in memory which can be used with GDI+, not a clipped copy of the image.
So the command:

Code: Select all

result = Gdiplus::DllExports::GdipCreateBitmapFromGraphics(60, 60, pG, &pBitmap2);
creates new blank image). So I need to find out how to get the old Bitmap into new Bitmap or rather how to get graphics to the new Bitmap.

Re: How to save bitmap to file in C++?

Post by brandonhotkey » 21 May 2014, 03:32

This is my problem:

Code: Select all

GpGraphics * pG; // pBitmap already contains image/picture
result = Gdiplus::DllExports::GdipGetImageGraphicsContext(pBitmap, &pG);
CLSID pngClsid;	
GetEncoderClsid(L"image/png", &pngClsid);
GpBitmap* pBitmap2;
result = Gdiplus::DllExports::GdipCreateBitmapFromGraphics(60, 60, pG, &pBitmap2);
result = Gdiplus::DllExports::GdipSaveImageToFile(pBitmap2, L"justest.png", &pngClsid, NULL);  // last voluntary? GDIPCONST EncoderParameters* encoderParams
If I comment the line with GdipCreateBitmapFromGraphics, it will save the pucture.
If I use the command GdipCreateBitmapFromGraphics, the image is black, no picture there.
Why the GdipCreateBitmapFromGraphics command does not do what I expect to do?

Re: How to save bitmap to file in C++?

Post by brandonhotkey » 20 May 2014, 09:05

I have solved the saving, but my problem now is that the image file does not contain the picture of the window. Can you help to fix it?

Code: Select all

// CODE 81 and 82 de facto no difference
#define	CODE		85 // 81
#define	WINDOW_MIN_HEIGHT		200
#define	WINDOW_MAX_HEIGHT	700
#define	WINSTYLE		0x14FF0000
#define	ROTATION_ANGLE		45

#define M_PI           3.14159265358979323846

// #define	IS_CHILD	TRUE  // [TRUE | FALSE | 0] ... 0 - deactivates this detection
// GetWindowLong: GWL_HWNDPARENT

#include <windows.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cstring>
#include <string>
#include <tchar.h>
#include <conio.h>
#include <gdiplus.h>
#include <stdlib.h> // abs
#include <math.h> // cos
using namespace std;
using namespace Gdiplus;

int GetEncoderClsid (const WCHAR* format, CLSID* pClsid) 
{ 
   UINT num = 0;//number of image encoders 
   UINT size = 0;//size of the image encoder array in bytes 

   ImageCodecInfo* pImageCodecInfo = NULL; 

   GetImageEncodersSize (&num, &size); 
   if (size == 0) 
      return-1;//Failure 

   pImageCodecInfo = (ImageCodecInfo *) (malloc (size)); 
   if (pImageCodecInfo == NULL) 
      return-1;//Failure 

   GetImageEncoders (num, size, pImageCodecInfo); 

   for (UINT j = 0; j <num; ++ j) 
   { 
      if (wcscmp (pImageCodecInfo [j].MimeType, format) == 0) 
      { 
         *pClsid = pImageCodecInfo [j].Clsid; 
         free (pImageCodecInfo); 
         return j;//Success 
      }    
   }

   free (pImageCodecInfo); 
   return-1;//Failure 
}

// Old way to save file
int FileWriteSaveImage(BYTE*	memory, LONG dx, LONG dy, int fudgex)
{
	char *buffer = new char[50];
	sprintf(buffer, "capture%d%d.bmp", dx, dy);
	ofstream file(buffer, ios::binary);
	if (!file) return 1;

// initialize bitmap file headers

	BITMAPFILEHEADER fileHeader = {0};
	BITMAPINFOHEADER infoHeader = {0};

	fileHeader.bfType      = 0x4d42;
	fileHeader.bfSize      = 0;
	fileHeader.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

	infoHeader.biSize          = sizeof(infoHeader);
	infoHeader.biWidth         = dx + fudgex;
	infoHeader.biHeight        = dy;
	infoHeader.biPlanes        = 1;
	infoHeader.biBitCount      = 24;
	infoHeader.biCompression   = BI_RGB;

	// save file headers
	file.write((char*)&fileHeader, sizeof(fileHeader));
	file.write((char*)&infoHeader, sizeof(infoHeader));

	// save 24-bit bitmap data
	int wbytes = (((24 * (dx) + 31) & (~31)) / 8);
	int tbytes = wbytes * dy;
	file.write((char*)(memory), tbytes);
	file.close();
	return 0;
}

const int maxstr = 200;
// const char wndtitle[] = "AOK";
RECT rect, wrect;
int fudgex, fudgey;
struct windata {
	static const string titles[]; // only static const integral data members can be initialized within a class
	static const string default;
	string choose;
	HWND hfnd; // Found destination window handler
};
const string windata::titles[] = {"learn", "dialog", "aok", "map" };
const string windata::default = "learn"; // windata.default = ... will produce syntax error : missing ';' before '.'

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lparam)
{
char title[maxstr + 1];
char *ch = title;

GetWindowRect(hwnd, &wrect); // Calculate window height
int winHeight = wrect.bottom-wrect.top;

if ( (WINDOW_MIN_HEIGHT && winHeight<WINDOW_MIN_HEIGHT) || 
	 (WINDOW_MAX_HEIGHT && winHeight>WINDOW_MAX_HEIGHT))
		return TRUE; // skip window

if ( GetWindowLong(hwnd, GWL_STYLE) & WINSTYLE 	!= TRUE )
		return TRUE;

	/*	GetWindowTextA - copies the text of the specified window's 
	title bar (if it has one) into a buffer. If the specified window is a
	control, the text of the control is copied. However, it
	can't retrieve the text of a control in another application. */
	
if (GetWindowTextA(hwnd, title, maxstr)) {
		for (char *ch = title; *ch; ++ch) // was ch++)
			*ch = (char)tolower(*ch);		
		 // strstr - finds the first occurrence of a substring within a string. The comparison is case-sensitive.
		 // c_str - converts the contents of a string as a C-style, null-terminated string.
		if (strstr(title, ((windata*)lparam)->choose.c_str())) {
			((windata*)lparam)->hfnd = hwnd;
			SetLastError(ERROR_NO_MATCH);
			cout << "Found matching window - " << title << endl;
			return FALSE;
		}		
	}
	return TRUE;
} // Press F5 to continue debug, not F10. Otherwise "error" occurs.

int main()
{
// HWND HCapture = GetForegroundWindow();
/* HWND HCapture = FindWindow(NULL, _T("Learning WInAPI")); // get window handle
*/
windata wd;
cout << "Partial window title: ";
getline(cin, wd.choose);
wd.choose.erase(wd.choose.find_last_not_of(" \n\r\t")+1); // trim string
if ( wd.choose == "" )  // select default window
	wd.choose = wd.default;


/* EnumWindows(in,in) - Enumerates all top-level windows on the
screen by passing the handle to each window, in turn, to 
callback function. EnumWindows continues until the last top-level
window is enumerated or the callback function returns FALSE. 
The EnumWindows function does not enumerate child windows.
*/

	if (EnumWindows(EnumWindowsProc, (LPARAM)&wd) || (GetLastError() != ERROR_NO_MATCH)) {
		cout << "Cannot find window\n";
		_getch();
		return 1;
	}

	HWND HCapture = wd.hfnd;

	if (!IsWindow(HCapture)) {
		cout << "Bad find! Cannot find window\n";_getch();return 2;
	}

#if CODE<85
	fudgey = (GetMenu(HCapture)?GetSystemMetrics(SM_CYMENU):0) 
					+ GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYSIZEFRAME);
	fudgex = 0;
#endif

GetClientRect(HCapture, &rect);
LONG dx = rect.right - rect.left;
LONG dy = rect.bottom - rect.top;


if (CODE>82)	{
					/*
const int fudgey = (GetMenu(HCapture)?GetSystemMetrics(SM_CYMENU):0) 
					+ GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYSIZEFRAME);
					*/
	// Height should be 26 not 22
					fudgey = (wrect.bottom - wrect.top) - dy +4 - 2 * GetSystemMetrics(SM_CYSIZEFRAME);
					fudgex = 0;
}

/*
int test =  GetSystemMetrics(SM_CYSIZEFRAME); // 4
int test2 =  GetSystemMetrics(SM_CYMENU); // 24
int test3 =  wrect.bottom - wrect.top; 
*/

// create BITMAPINFO structure
// used by CreateDIBSection
BITMAPINFO info = {0};

	info.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
	info.bmiHeader.biWidth         = dx + fudgex;
	info.bmiHeader.biHeight        = dy + fudgey;
	info.bmiHeader.biPlanes        = 1;
	info.bmiHeader.biBitCount      = 24;
	info.bmiHeader.biCompression   = BI_RGB;

HDC	HDevice = CreateCompatibleDC(NULL);
//HDC HDevice = GetDC(HCapture);
 
BYTE*	memory = 0;
 
HBITMAP	HBitmap = CreateDIBSection(HDevice, &info, DIB_RGB_COLORS, (void**)&memory, NULL, NULL);

	SelectObject(HDevice, HBitmap);
 
	//SendMessage(HCapture, WM_PRINTCLIENT, 0, 0);
	// SendMessage(HCapture, WM_PRINTCLIENT,(WPARAM) HDevice, 0);
	if (!PrintWindow(HCapture, HDevice, /*PW_CLIENTONLY*/0))
		return 2;	
	// SendMessage(HCapture, WM_PRINTCLIENT, 0, 0);
	ReleaseDC(HCapture, HDevice);

	 // INIT GDI
	ULONG_PTR gdiplusToken;
	GdiplusStartupInput gdiplusStartupInput;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
	if (!gdiplusToken) return 3;

	// Gdip_GetRotatedDimensions:
	GpBitmap* pBitmap;
	int result = Gdiplus::DllExports::GdipCreateBitmapFromHBITMAP(HBitmap, 0, &pBitmap);
	// SelectObject(HDevice, obm); DeleteObject(hbm); DeleteDC(hdc)	
	unsigned int w; unsigned int h;
	//GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
	Gdiplus::DllExports::GdipGetImageWidth(pBitmap, &w);
	Gdiplus::DllExports::GdipGetImageHeight(pBitmap, &h);
	REAL TAngle = ROTATION_ANGLE*(M_PI/180);
	if ( !w && !h )
		return -1;
	REAL RWidth = ceil(abs(w*cos(TAngle))+abs(h*sin(TAngle)));
	REAL RHeight = ceil(abs(w*sin(TAngle))+abs(h*cos(TAngle)));

	// gdip_getrotatedtranslation:
	REAL xTranslation, yTranslation;
	REAL bound = (ROTATION_ANGLE >= 0) ? ROTATION_ANGLE%360 : 360-(-ROTATION_ANGLE%-360);
	if ((bound >= 0) && (bound <= 90))
		{ xTranslation = h*sin(TAngle); yTranslation = 0; }
	else if ((bound > 90) && (bound <= 180))
		{ xTranslation = (h*sin(TAngle))-(w*cos(TAngle)); yTranslation = -1*h*cos(TAngle); }
	else if ((bound > 180) && (bound <= 270))
		{ xTranslation = -(w*cos(TAngle)); yTranslation = -(h*cos(TAngle))-(w*sin(TAngle)); }
	else if ((bound > 270) && (bound <= 360))
		{ xTranslation = 0; yTranslation = -1*w*sin(TAngle); }
	
	// Gdip_GraphicsFromImage:
	// GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image, GpGraphics **graphics)
	GpGraphics * pG;
	result = Gdiplus::DllExports::GdipGetImageGraphicsContext(pBitmap, &pG);
	
	// GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode)
	// smooth = 4; See http://msdn.microsoft.com/en-us/library/windows/desktop/ms534173%28v=vs.85%29.aspx
	Gdiplus::SmoothingMode smooth = SmoothingModeHighQuality;
	result = Gdiplus::DllExports::GdipSetSmoothingMode(pG, smooth);
	
	// ; Best interpolation is 5 - it's like no antialias
	// Gdip_SetInterpolationMode(G, 7)
	// Gdip_SetInterpolationMode(pGraphics, InterpolationMode)
	// GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics, InterpolationMode interpolationMode)
	// Gdiplus::InterpolationMode interpolation = 7; // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms534141%28v=vs.85%29.aspx
	Gdiplus::InterpolationMode interpolation = InterpolationModeNearestNeighbor;
	result = Gdiplus::DllExports::GdipSetInterpolationMode(pG, interpolation);

	// Gdip_TranslateWorldTransform(pGraphics, x, y, MatrixOrder=0)
    // GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx, REAL dy, GpMatrixOrder order)
	/*
	enum MatrixOrder
	{
		MatrixOrderPrepend    = 0,
		MatrixOrderAppend     = 1
	};
	*/
	MatrixOrder MatrixOrder_ = MatrixOrderPrepend;
	result = Gdiplus::DllExports::GdipTranslateWorldTransform(pG, xTranslation, yTranslation, MatrixOrder_);

	// Gdip_RotateWorldTransform(G, Angle)
	// Gdip_RotateWorldTransform(pGraphics, Angle, MatrixOrder=0)
	// GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle, GpMatrixOrder order)
	MatrixOrder_ = MatrixOrderPrepend;
	result = Gdiplus::DllExports::GdipRotateWorldTransform(pG, ROTATION_ANGLE, MatrixOrder_);
	
	// GpStatus WINGDIPAPI GdipCreateImageAttributes(GpImageAttributes **imageattr)
	GpImageAttributes * ImgAttributes;
	// from 'Gdiplus::GpImageAttributes' to 'Gdiplus::GpImageAttributes **'
	result = Gdiplus::DllExports::GdipCreateImageAttributes(&ImgAttributes); // create an ImageAttribute object

	int sx(0), sy(0);
	// Gdip_DrawImage
	// http://msdn.microsoft.com/en-us/library/windows/desktop/ms536044%28v=vs.85%29.aspx
	//	GpStatus WINGDIPAPI GdipDrawImageRectRect(
	//	   GpGraphics *graphics, GpImage *image, REAL dstx, REAL dsty, REAL dstwidth, REAL dstheight, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, 
	//	   GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback, VOID * callbackData)
	result = Gdiplus::DllExports::GdipDrawImageRectRect(pG,pBitmap,0,0,w,h,0,0,w,h,UnitPixel,ImgAttributes,0,0);  // Draw the original image onto the new bitmap
	result = Gdiplus::DllExports::GdipDisposeImageAttributes(ImgAttributes);
		
	CLSID pngClsid;	
	GetEncoderClsid(L"image/png", &pngClsid);
	// GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height, GpGraphics* target, GpBitmap** bitmap)
	result = Gdiplus::DllExports::GdipCreateBitmapFromGraphics(w, h, pG, &pBitmap);
    result = Gdiplus::DllExports::GdipSaveImageToFile(pBitmap, L"justest.png", &pngClsid, NULL);  // last voluntary? GDIPCONST EncoderParameters* encoderParams
    DeleteObject(HBitmap);

	// FileWriteSaveImage(memory, dx, dy, fudgex);	 
	return 0;
}
I did this test:

Code: Select all

GpGraphics * pG;
result = Gdiplus::DllExports::GdipGetImageGraphicsContext(pBitmap, &pG);

CLSID pngClsid;	
GetEncoderClsid(L"image/png", &pngClsid);
result = Gdiplus::DllExports::GdipCreateBitmapFromGraphics(600, 600, pG, &pBitmap);
result = Gdiplus::DllExports::GdipSaveImageToFile(pBitmap, L"justest.png", &pngClsid, NULL);
And it fails to get the picture to the file. In the png just created, there are no pixels (I see black image only). Tested on several windows.

How to save bitmap to file in C++?

Post by brandonhotkey » 19 May 2014, 06:27

Do you have experience how to save bitmap to file? Is it possible to do it with image.save()?

I have bitmap in memory and would like to save it with image::save, but I cannot find how to do it. The example on MSDN uses image object created from file.

http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Is it even possible, or it is useless for the bitmap?

Code: Select all

CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
// some code to initiate Image object and get the bitmap there
// then to save it
Image.Save(L"Mosaic2.png", &pngClsid, NULL);
I know AHK uses GdipSaveImageToFile

so theoretically it should be possible...

Top