April 19, 2024, 03:45:01 PM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Snapshot class

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

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

sapero

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);
ReleaseHDC(dc);
gdi.Save(L"c:\path.jpg");


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


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


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;
}




CDlg::CDlg()
{
Create(0,0,300,202,0x80CB0880,0,"Gdi plus capture test",0);
AddControl(CTTABCTRL,"",23,8,265,25,0x54000040,0x0,1000);
AddControl(CTLISTVIEW,"",23,30,265,60,0x50004001,0x200,1001);
AddControl(CTGROUPBOX,"ScreenShot",23,92,265,93,0x50000007,0x0,5);
AddControl(CTSTATIC,"quality",29,109,32,16,0x5000010B,0x0,6);
AddControl(CTEDIT,"65",61,107,26,20,0x50812000,0x200,1002);
AddControl(CTSTATIC,"encoder",170,109,43,16,0x5000010B,0x0,7);
AddControl(CTCOMBOBOX,"",216,106,70,80,0x50800603,0x0,1004);
AddControl(CTDEFBUTTON,"Create && view",85,133,130,47,0x50010001,0x0,1003);
AddControl(CTRADIOBUTTON,"Window",218,132,65,14,0x50010009,0x0,1005);
AddControl(CTRADIOBUTTON,"Screen",218,149,65,14,0x50010009,0x0,1006);
DoModal();
}


CDlg::OnInitDialog(),int
{
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);
m_button->Enable(gdi.m_gdipToken);
m_capWindow->SetCheck(true);

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

m_encoder->AddString("bmp");
m_encoder->AddString("jpg"); m_encoder->SetCurSel(1);
m_encoder->AddString("gif");
m_encoder->AddString("tiff");

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);
ReleaseDC(hwnd,dc);

// 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()))
ShellExecute(m_hwnd,"open",path,null,null,2)
else
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
}

#endif


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;


CGdiPlus::CGdiPlus()
{
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;
}
}
}


CGdiPlus::_CGdiPlus()
{
if (m_hgdiplus)
{
DestroyImage();
if (m_gdipToken)
{
declare *GdiplusShutdown(int token);
GdiplusShutdown = GetProcAddress(m_hgdiplus, "GdiplusShutdown");
if (GdiplusShutdown) GdiplusShutdown(m_gdipToken);
m_gdipToken = 0;
}
FreeLibrary(m_hgdiplus);
}
}



CGdiPlus::LoadFromFile(wstring path),BOOL
{
DestroyImage();
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);
FreeHeap(gdipath-2);
}
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
{
DestroyImage();
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);
BitBlt(cdc,0,0,w,h,dc,l,t,SRCCOPY);
SelectObject(cdc, bm);
DeleteDC(cdc);
ok = LoadFromHBitmap(cbm);
DeleteObject(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);
FreeHeap(gdipath-2);
ok = !status;
}
return ok;
}



CGdiPlus::DestroyImage()
{
declare *GdipDisposeImage(GpImage *pImage),int;
GdipDisposeImage = GetProcAddress(m_hgdiplus, "GdipDisposeImage");

if (m_image && GdipDisposeImage)
{
GdipDisposeImage(m_image);
m_image = 0;
}
}

kryton9

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)