January 26, 2023, 10:03:32 PM


Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........

Snapshot class

Started by sapero, August 12, 2006, 12:23:05 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


August 12, 2006, 12:23:05 PM Last Edit: August 12, 2006, 12:27:14 PM by sapero
Here is a small class for making snapshots from your games ;D
It uses microsoft redistributable library gdiplus.dll (free for download), on windows XP included by default.
Works for file-images, windows, dialogs, 2d and 3d screens. All you need is HDC and RECT.
The gdi+ library is loaded dynamically by LoadLibrary.
-> Attached a zip with complilled .o file (just copy it to /aurora/libs)

Restriction for 2D screen: initialize/create this class before opening the screen. Found a bug in gdi+ : in fireworks example the custom color palette has been destroyed while calling GdiplusStartup...

To create a jpg from window:
#include "CGdiPlus.inc"

CGdiPlus gdi;
// inside CWindow method ...
RECT rc = GetClientRect();
int dc = GetHDC();
gdi.LoadFromHDC(dc, 0,0,rc.right,rc.bottom);

from 2D screen:
C2DScreen screen;
// ...
int dc = screen.GetHDC();
// ...

from 3D screen:
C3DScreen screen;
// ...
int dc = screen.GetHDC();
// ...

from file: gdi.LoadFromFile(L"c:\image.tiff");
from HBITMAP: gdi.LoadFromHBitmap(hBitmap);
from dialog: GetHDC does not correctly work, you must use api GetDC(hwnd) / ReleaseDC(hwnd,dc)

to save as bitmap, gif or tiff - just replace the default jpeg encoder GUID before saving (CGdiPlus.m_encoder) as shown here:
#include "CGdiPlus.inc"

import int GetDC(int hwnd);
import int ReleaseDC(int hwnd,int dc);
import int GetClientRect(int hwnd, RECT *rc);
import int GetDesktopWindow();
import int ShellExecute alias ShellExecuteA(int hwnd,string *verb,string *file,string *params,string *dir, int show);

class CDlg:CDialog
CButtonÂÃ,  ÂÃ, *m_button;
CEditÂÃ,  ÂÃ,  ÂÃ, *m_quality;
CTabCtrlÂÃ,  *m_tab;
CComboBox *m_encoder;
CListView *m_list;
CButtonÂÃ,  ÂÃ, *m_capScreen;
CButtonÂÃ,  ÂÃ, *m_capWindow;

CGdiPlus gdi;
declare CDlg();
declare OnInitDialog(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;

global sub main()
CDlg d1;
return 0;

Create(0,0,300,202,0x80CB0880,0,"Gdi plus capture test",0);
AddControl(CTDEFBUTTON,"Create && view",85,133,130,47,0x50010001,0x0,1003);

m_buttonÂÃ,  ÂÃ,  = GetControl(1003);
m_qualityÂÃ,  ÂÃ, = GetControl(1002);
m_tabÂÃ,  ÂÃ,  ÂÃ,  ÂÃ, = GetControl(1000);
m_encoderÂÃ,  ÂÃ, = GetControl(1004);
m_listÂÃ,  ÂÃ,  ÂÃ,  = GetControl(1001);
m_capScreen = GetControl(1006);
m_capWindow = GetControl(1005);

if (!gdi.m_gdipToken)
MessageBox(0,"gdi+ could not be loaded or initialized","",16);

m_encoder->AddString("jpg"); m_encoder->SetCurSel(1);

m_tab->InsertTab(0,"Tab 1");
m_tab->InsertTab(1,"Tab 2");

m_list->InsertColumn(0, "",0,262);
if (gdi.m_hgdiplus) m_list->InsertItem(0, "GDIPlus.dll loaded")
else m_list->InsertItem(0, "failed to load GDIPlus.dll");

if (gdi.m_gdipToken) m_list->InsertItem(1, "GDIPlus initialized")
else m_list->InsertItem(1, "failed to initialize GDIPlus.dll");


CDlg::OnControl(int nID, int nNotifyCode, unsigned int hControl)
// save parameter 'quality' is valid only for jpeg encoder
if (nID == 1004 && nNotifyCode == CBNSELCHANGE)
m_quality->Enable(m_encoder->GetCurSel() == 1);

else if (nID == 1003 && !nNotifyCode)
GUID *encoders[4]; encoders =
"\x00\xF4\x7C\x55\x04\x1A\xD3\x11\x9A\x73\x00\x00\xF8\x1E\xF3\x2E", // bmp
"\x01\xF4\x7C\x55\x04\x1A\xD3\x11\x9A\x73\x00\x00\xF8\x1E\xF3\x2E", // jpg (default)
"\x02\xF4\x7C\x55\x04\x1A\xD3\x11\x9A\x73\x00\x00\xF8\x1E\xF3\x2E", // gif
"\x05\xF4\x7C\x55\x04\x1A\xD3\x11\x9A\x73\x00\x00\xF8\x1E\xF3\x2E"; // tiff

string *extension[4]; extension = "bmp","jpg","gif","tiff";

// capture window of whole screen?
int hwnd = m_hwnd;
RECT rc = GetClientRect();
if (m_capScreen->GetCheck()) {
hwnd = GetDesktopWindow();
::GetClientRect(hwnd, &rc);

// load image to gdiplus
int dc = GetDC(hwnd);
if !gdi.LoadFromHDC(dc, 0,0,rc.right,rc.bottom)
MessageBox(this,"failed to load from HDC","", 16);

// select file extension and replace default jpg encoder in CGdiPlus
int index = m_encoder->GetCurSel();
gdi.m_encoder = encoders[index]; // change encoder GUID pointer
dstring path[260];
path = sprint(GetStartPath(), "ScreenShot.", *(string)(extension[index]));

// save image
if gdi.Save(s2w(path), val(m_quality->GetText()))
MessageBox(this,"failed to save jpg","", 16);

the class definition is:#ifndef __CGdiPlus_inc__
#define __CGdiPlus_inc__

#use "CGdiPlus.o"

sub CGdiPlus
class CGdiPlus
// 1. load image: any methods of ...
declare LoadFromFile(wstring path),BOOL;
declare LoadFromHBitmap(int hBitmap),BOOL;
declare LoadFromHDC(int dc,int l,int t,int w,int h),BOOL;

// 2. save
declare Save(wstring path, opt int quality=75),BOOL;

// private
declare CGdiPlus();
declare _CGdiPlus();
declare DestroyImage();
// creates unicode path in form 0xFF 0xFE wstring null
// and returns pointer to wstring (in heap)
// for details see any unicode text file in hex editor :)
declare CreatePath(wstring path),wstring *;

int m_hgdiplus;ÂÃ,  // dll handle (also image base)
int m_gdipToken; // gdiplus private token
pointer m_image; // gdiplus image/class pointer
GUID *m_encoder; // encoder GUID for save - default ImageEncoderJpeg


class code:#include "windows.inc"
#include "CGdiPlus.inc"

#typedef GpImage pointer

struct GdiplusStartupInput // for snapshot
ÂÃ,  ÂÃ,  int GdiplusVersion;ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ, 
ÂÃ,  ÂÃ,  int DebugEventCallback;
ÂÃ,  ÂÃ,  int SuppressBackgroundThread;
ÂÃ,  ÂÃ,  int SuppressExternalCodecs;

struct MyEncoderParameters
ÂÃ,  ÂÃ,  int Count;ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  // Number of parameters this structure

ÂÃ,  ÂÃ,  GUIDÂÃ,  Guid1;ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ, // GUID of the parameter
ÂÃ,  ÂÃ,  intÂÃ,  ÂÃ, NumberOfValues1;ÂÃ,  ÂÃ,  ÂÃ, // Number of the parameter values
ÂÃ,  ÂÃ,  intÂÃ,  ÂÃ, Type1;ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ, // Value type, like ValueTypeLONGÂÃ,  etc.
ÂÃ,  ÂÃ,  void* Value1;ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  // A pointer to the parameter values

ÂÃ,  ÂÃ,  GUIDÂÃ,  Guid2;
ÂÃ,  ÂÃ,  intÂÃ,  ÂÃ, NumberOfValues2;
ÂÃ,  ÂÃ,  intÂÃ,  ÂÃ, Type2;
ÂÃ,  ÂÃ,  void* Value2;
#define EncoderParameterValueTypeLong 4;

m_hgdiplus = LoadLibrary("gdiplus.dll");
m_gdipToken = 0;
m_image = 0;
m_encoder = "\x01\xF4\x7C\x55\x04\x1A\xD3\x11\x9A\x73\x00\x00\xF8\x1E\xF3\x2E"; // jpeg

if (m_hgdiplus)
declare *GdiplusStartup(int *token, GdiplusStartupInput *input,opt GdiplusStartupOutput *output=null),int;
GdiplusStartup = GetProcAddress(m_hgdiplus, "GdiplusStartup");

if (GdiplusStartup)
GdiplusStartupInput gps;
ZeroMemory(&gps, sizeof(GdiplusStartupInput));
gps.GdiplusVersion = 1;
if GdiplusStartup(&m_gdipToken, &gps, null) m_gdipToken = 0;

if (m_hgdiplus)
if (m_gdipToken)
declare *GdiplusShutdown(int token);
GdiplusShutdown = GetProcAddress(m_hgdiplus, "GdiplusShutdown");
if (GdiplusShutdown) GdiplusShutdown(m_gdipToken);
m_gdipToken = 0;

CGdiPlus::LoadFromFile(wstring path),BOOL
BOOL ok = false;
declare *GdipLoadImageFromFile(wstring *path, GpImage *ppImage),int;
GdipLoadImageFromFile = GetProcAddress(m_hgdiplus, "GdipLoadImageFromFile");

if (m_gdipToken && GdipLoadImageFromFile)
wstring *gdipath = CreatePath(path);
ok = !GdipLoadImageFromFile(gdipath, &m_image);
return ok;

CGdiPlus::CreatePath(wstring path),wstring *
wstring *lpwsz = AllocHeap((len(path)+2)<<1);
*(word)lpwsz = 0xFFFE;
*(wstring)(lpwsz+2) = path;
return lpwsz+2;

CGdiPlus::LoadFromHBitmap(HBITMAP hBitmap),BOOL
BOOL ok = false;
declare *GdipCreateBitmapFromHBITMAP(int hbm, int hpal, GpBitmap *ppBitmap),int;
GdipCreateBitmapFromHBITMAP = GetProcAddress(m_hgdiplus, "GdipCreateBitmapFromHBITMAP");

if (m_gdipToken && GdipCreateBitmapFromHBITMAP)
ok = !GdipCreateBitmapFromHBITMAP(hBitmap, 0, &m_image);
return ok;

CGdiPlus::LoadFromHDC(int dc,int l,int t,int w,int h),BOOL
BOOL ok = false;
if (m_gdipToken)
int cdc = CreateCompatibleDC(dc);
int cbm = CreateCompatibleBitmap(dc, w, h);
int bm = SelectObject(cdc, cbm);
SelectObject(cdc, bm);
ok = LoadFromHBitmap(cbm);
return ok;

CGdiPlus::Save(wstring path, int quality),BOOL
BOOL ok = false;
declare *GdipSaveImageToFile(GpImage *image, wstring* filename, CLSID* clsidEncoder, EncoderParameters* encoderParams),int;
GdipSaveImageToFile = GetProcAddress(m_hgdiplus, "GdipSaveImageToFile");

if (m_image && GdipSaveImageToFile)
MyEncoderParameters ep;
ep.Count = 2;ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ,  ÂÃ, // another GUID definition
//0x557CF401, 0x1A04, 0x11D3, 0x9A, 0x73, 0x0, 0x0, 0xF8, 0x1E, 0xF3, 0x2E
// byte *CLSID_JPGÂÃ,  ÂÃ,  ÂÃ,  ÂÃ, = "\x01\xF4\x7C\x55\x04\x1A\xD3\x11\x9A\x73\x00\x00\xF8\x1E\xF3\x2E";
byte *EncoderQualityÂÃ,  = "\xB5\xE4\x5B\x1D\x4A\xFA\x2D\x45\x9C\xDD\x5D\xB3\x51\x05\xE7\xEB";
byte *EncoderSaveFlag = "\xFC\x66\x22\x29\x40\xAC\xBF\x47\x8C\xFC\xA8\x5B\x89\xA6\x55\xDE";

MoveMemory(ep.Guid1, EncoderQuality, 16);
ep.NumberOfValues1 = 1;
ep.Type1 = EncoderParameterValueTypeLong;
ep.Value1 = &quality;

MoveMemory(ep.Guid2, EncoderSaveFlag, 16);
ep.NumberOfValues2 = 0;
ep.Type2 = EncoderParameterValueTypeLong;

wstring *gdipath = CreatePath(path);
int status = GdipSaveImageToFile(m_image, gdipath, m_encoder, &ep);
ok = !status;
return ok;

declare *GdipDisposeImage(GpImage *pImage),int;
GdipDisposeImage = GetProcAddress(m_hgdiplus, "GdipDisposeImage");

if (m_image && GdipDisposeImage)
m_image = 0;


Thanks that should come in very handy and add to the fun factor!!

Steven Picard

Thanks, Sapero!  You are amazing and really contribute a lot of great stuff!  8)