3
#include "simsys_w32_png.h"
8
#error "Only Windows has GDI+!"
11
// windows Bibliotheken DirectDraw 5.x
12
// windows.h defines min and max macros which we don't want
16
// structures, since we use the C-interface
21
const WCHAR* CodecName;
23
const WCHAR* FormatDescription;
24
const WCHAR* FilenameExtension;
25
const WCHAR* MimeType;
30
const BYTE* SigPattern;
34
#define PixelFormatIndexed 0x00010000 // Indexes into a palette
35
#define PixelFormatGDI 0x00020000 // Is a GDI-supported format
36
#define PixelFormat8bppIndexed (3 | ( 8 << 8) | PixelFormatIndexed | PixelFormatGDI)
37
#define PixelFormat16bppRGB555 (5 | (16 << 8) | PixelFormatGDI)
38
#define PixelFormat16bppRGB565 (6 | (16 << 8) | PixelFormatGDI)
39
#define PixelFormat24bppRGB (8 | (24 << 8) | PixelFormatGDI)
41
struct EncoderParameters;
43
struct GdiplusStartupInput
45
UINT32 GdiplusVersion; // Must be 1
46
void *DebugEventCallback; // Ignored on free builds
47
BOOL SuppressBackgroundThread; // FALSE unless you're prepared to call
48
// the hook/unhook functions properly
49
BOOL SuppressExternalCodecs; // FALSE unless you want GDI+ only to use
50
// its internal image codecs.
53
// and the functions from the library
54
static int (WINAPI* GdiplusStartup)(ULONG_PTR* token, GdiplusStartupInput* size, void*);
55
static int (WINAPI* GdiplusShutdown)(ULONG_PTR token);
56
static int (WINAPI* GdipGetImageEncodersSize)(UINT* numEncoders, UINT* size);
57
static int (WINAPI* GdipGetImageEncoders)(UINT numEncoders, UINT size, ImageCodecInfo* encoders);
58
static int (WINAPI* GdipCreateBitmapFromScan0)(INT width, INT height, INT stride, INT PixelFormat, BYTE* scan0, ULONG** bitmap);
59
static int (WINAPI* GdipDeleteCachedBitmap)(ULONG* image);
60
static int (WINAPI* GdipSaveImageToFile)(ULONG* image, WCHAR const* filename, CLSID const* clsidEncoder, EncoderParameters const* encoderParams);
63
// Die GetEncoderClsid() Funktion wurde einfach aus der MSDN/PSDK Doku kopiert.
64
// Zu finden mit dem Suchstring "Retrieving the Class Identifier for an Encoder"
65
// Sucht zu z.B. 'image/jpeg' den passenden Encoder und liefert dessen CLSID...
66
static int GetEncoderClsid(wchar_t const* const format, CLSID* const pClsid)
68
UINT num = 0; // number of image encoders
69
UINT size = 0; // size of the image encoder array in bytes
71
ImageCodecInfo* pImageCodecInfo = NULL;
73
GdipGetImageEncodersSize(&num, &size);
75
if(size == 0) return -1; // Failure
77
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
78
if(pImageCodecInfo == NULL) return -1; // Failure
80
GdipGetImageEncoders(num, size, pImageCodecInfo);
82
for( j = 0; j < num; ++j ) {
83
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) {
84
*pClsid = pImageCodecInfo[j].Clsid;
85
free(pImageCodecInfo);
90
free(pImageCodecInfo);
95
template<typename T> static void GetProcAddress(T& dst, HMODULE const module, char const* const procname)
97
dst = reinterpret_cast<T>(GetProcAddress(module, procname));
101
/* this works only, if gdiplus.dll is there.
102
* It should be there on
103
* Windows XP and newer
104
* On Win98 and up, if .NET is installed
106
int dr_screenshot_png(const char *filename, int w, int h, int maxwidth, unsigned short *data, int bitdepth )
108
// first we try as PNG
111
ULONG *myImage = NULL;
112
GdiplusStartupInput gdiplusStartupInput;
113
ULONG_PTR gdiplusToken;
115
HMODULE hGDIplus = LoadLibraryA( "gdiplus.dll" );
120
// retrieve names ...
121
GetProcAddress(GdiplusStartup, hGDIplus, "GdiplusStartup");
122
GetProcAddress(GdiplusShutdown, hGDIplus, "GdiplusShutdown");
123
GetProcAddress(GdipGetImageEncodersSize, hGDIplus, "GdipGetImageEncodersSize");
124
GetProcAddress(GdipGetImageEncoders, hGDIplus, "GdipGetImageEncoders");
125
GetProcAddress(GdipCreateBitmapFromScan0, hGDIplus, "GdipCreateBitmapFromScan0");
126
GetProcAddress(GdipDeleteCachedBitmap, hGDIplus, "GdipDeleteCachedBitmap");
127
GetProcAddress(GdipSaveImageToFile, hGDIplus, "GdipSaveImageToFile");
129
/* Win2k can do without init, WinXP not ... */
130
gdiplusStartupInput.GdiplusVersion = 1;
131
gdiplusStartupInput.DebugEventCallback = NULL;
132
gdiplusStartupInput.SuppressBackgroundThread = FALSE;
133
gdiplusStartupInput.SuppressExternalCodecs = FALSE;
134
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
137
GdipCreateBitmapFromScan0(w, h, maxwidth, PixelFormat8bppIndexed , (BYTE*)data, &myImage);
140
GdipCreateBitmapFromScan0(w, h, maxwidth * 2, bitdepth == 16 ? PixelFormat16bppRGB565 : PixelFormat16bppRGB555, (BYTE*)data, &myImage);
142
if( myImage==NULL && bitdepth>8 ) {
143
/* we may have XP or newer => have to convert them to 32 first to save them ... Grrrr */
144
BYTE* const newdata = MALLOCN(BYTE, w * h * 4);
145
BYTE *dest = newdata;
146
unsigned short *src = data;
150
for( y=0; y<h; y++ ) {
151
for( x=0; x<w; x++ ) {
152
unsigned short color = src[x];
153
*dest++ = (color & 0xF800)>>8;
154
*dest++ = (color & 0x07E0)>>3;
155
*dest++ = (color & 0x001F)<<5;
160
GdipCreateBitmapFromScan0(w, h, w * 4, PixelFormat24bppRGB, newdata, &myImage);
164
// Passenden Encoder f�r jpegs suchen:
165
// Genausogut kann man auch image/png benutzen um png's zu speichern ;D
166
// ...oder image/gif um gif's zu speichern, ...
167
if(myImage!=NULL && GetEncoderClsid(L"image/png", &encoderClsid)!=-1) {
168
char cfilename[1024];
169
sprintf(cfilename, "%.*s.png", (int)(strlen(filename) - 4), filename);
171
WCHAR wfilename[1024];
172
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cfilename, -1, wfilename, lengthof(wfilename));
174
if (GdipSaveImageToFile(myImage, wfilename, &encoderClsid, 0) == 0) {
178
//printf( filename, "Save() for png failed!\n");
182
//printf( filename, "No encoder for 'image/jpeg' found!\n");
186
GdipDeleteCachedBitmap(myImage);
187
GdiplusShutdown(gdiplusToken);
188
FreeLibrary( hGDIplus );