forked from sabrogden/Ditto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BitmapHelper.cpp
392 lines (303 loc) · 9.93 KB
/
BitmapHelper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
// BitmapHelper.cpp: implementation of the CBitmapHelper class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "cp_main.h"
#include "BitmapHelper.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CBitmapHelper::CBitmapHelper()
{
}
CBitmapHelper::~CBitmapHelper()
{
}
int CBitmapHelper::GetCBitmapWidth(const CBitmap & cbm)
{
BITMAP bm;
cbm.GetObject(sizeof(BITMAP),&bm);
return bm.bmWidth;
}
int CBitmapHelper::GetCBitmapHeight(const CBitmap & cbm)
{
BITMAP bm;
cbm.GetObject(sizeof(BITMAP),&bm);
return bm.bmHeight;
}
BOOL CBitmapHelper::GetCBitmap(void *pClip2, CDC *pDC, CBitmap *pBitMap, int nMaxHeight)
{
CClipFormat *pClip = (CClipFormat *)pClip2;
if(pClip->m_cfType != CF_DIB &&
pClip->m_cfType != theApp.m_PNG_Format)
return false;
if(!pBitMap)
return false;
if (nMaxHeight < 0)
return false;
Gdiplus::Bitmap *gdipBitmap = pClip->CreateGdiplusBitmap();
if (gdipBitmap == NULL)
{
return false;
}
const UINT gdipHeight = gdipBitmap->GetHeight();
const UINT gdipWidth = gdipBitmap->GetWidth();
if (gdipHeight == 0 || gdipWidth == 0)
{
delete gdipBitmap;
return false;
}
const int nHeight = min(nMaxHeight, (int)gdipHeight);
const int nWidth = (nHeight * gdipWidth) / gdipHeight;
//do the resize
pBitMap->CreateCompatibleBitmap(pDC, nWidth, nHeight);
ASSERT(pBitMap->m_hObject != NULL);
CDC MemDc2;
MemDc2.CreateCompatibleDC(pDC);
CBitmap* oldBitmap2 = MemDc2.SelectObject(pBitMap);
Gdiplus::Rect dest(0, 0, nWidth, nHeight);
Gdiplus::ImageAttributes attrs;
Gdiplus::Graphics graphics(MemDc2);
Gdiplus::InterpolationMode interpolationMode = Gdiplus::InterpolationModeHighQualityBicubic;
if (CGetSetOptions::GetFastThumbnailMode())
{
interpolationMode = Gdiplus::InterpolationModeBicubic;
}
graphics.SetInterpolationMode(interpolationMode);
graphics.SetCompositingMode(Gdiplus::CompositingModeSourceOver);
graphics.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHalf);
graphics.DrawImage(gdipBitmap, dest, 0, 0, gdipWidth, gdipHeight, Gdiplus::UnitPixel, &attrs);
MemDc2.SelectObject(oldBitmap2);
delete gdipBitmap;
return true;
}
BOOL CBitmapHelper::GetCBitmap(CClipFormats &clips, CDC* pDC, CBitmap* pBitMap, BOOL horizontal)
{
BOOL bRet = FALSE;
if (!pBitMap)
return bRet;
int count = clips.GetCount();
int width = 0;
int height = 0;
for (int i = 0; i < count; i++)
{
CClipFormat clip = clips[i];
Gdiplus::Bitmap* gdipBitmap = clip.CreateGdiplusBitmap();
if (horizontal)
{
width += (int)gdipBitmap->GetWidth();
height = max((int)gdipBitmap->GetHeight(), height);
}
else
{
width = max((int)gdipBitmap->GetWidth(), width);
height += (int)gdipBitmap->GetHeight();
}
delete gdipBitmap;
}
pBitMap->CreateCompatibleBitmap(pDC, width, height);
ASSERT(pBitMap->m_hObject != NULL);
CDC MemDc2;
MemDc2.CreateCompatibleDC(pDC);
CBitmap* oldBitmap2 = MemDc2.SelectObject(pBitMap);
Gdiplus::Graphics graphics(MemDc2);
graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
graphics.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHalf);
graphics.Clear(Gdiplus::Color::White);
int destX = 0;
int destY = 0;
for (int i = 0; i < count; i++)
{
CClipFormat clip = clips[i];
if (clip.m_cfType != CF_DIB &&
clip.m_cfType != theApp.m_PNG_Format)
continue;
Gdiplus::Bitmap* gdipBitmap = clip.CreateGdiplusBitmap();
if (gdipBitmap == NULL)
continue;
const UINT gdipHeight = gdipBitmap->GetHeight();
const UINT gdipWidth = gdipBitmap->GetWidth();
if (gdipHeight == 0 || gdipWidth == 0)
{
delete gdipBitmap;
continue;
}
Gdiplus::Rect dest(destX, destY, gdipBitmap->GetWidth(), gdipBitmap->GetHeight());
Gdiplus::ImageAttributes attrs;
graphics.DrawImage(gdipBitmap, dest, 0, 0, gdipBitmap->GetWidth(), gdipBitmap->GetHeight(), Gdiplus::UnitPixel, &attrs);
if (horizontal)
destX += gdipBitmap->GetWidth();
else
destY += gdipBitmap->GetHeight();
delete gdipBitmap;
bRet = TRUE;
}
MemDc2.SelectObject(oldBitmap2);
return bRet;
}
WORD CBitmapHelper::PaletteSize(LPSTR lpDIB)
{
// calculate the size required by the palette
if (IS_WIN30_DIB (lpDIB))
return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
else
return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
}
WORD CBitmapHelper::DIBNumColors(LPSTR lpDIB)
{
WORD wBitCount; // DIB bit count
// If this is a Windows-style DIB, the number of colors in the
// color table can be less than the number of bits per pixel
// allows for (i.e. lpbi->biClrUsed can be set to some value).
// If this is the case, return the appropriate value.
if (IS_WIN30_DIB(lpDIB))
{
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
if (dwClrUsed)
return (WORD)dwClrUsed;
}
// Calculate the number of colors in the color table based on
// the number of bits per pixel for the DIB.
if (IS_WIN30_DIB(lpDIB))
wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
else
wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
// return number of colors based on bits per pixel
switch (wBitCount)
{
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
return 0;
}
}
HANDLE CBitmapHelper::hBitmapToDIB(HBITMAP hBitmap, DWORD dwCompression, HPALETTE hPal)
{
BITMAP bm;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen;
HANDLE hDIB;
HANDLE handle;
HDC hDC;
// The function has no arg for bitfields
if( dwCompression == BI_BITFIELDS )
return NULL;
// If a palette has not been supplied use defaul palette
if (hPal==NULL)
hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
// Get bitmap information
(void)GetObject( hBitmap, sizeof(bm), (LPSTR)&bm );
// Initialize the bitmapinfoheader
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = static_cast<USHORT>( bm.bmPlanes * bm.bmBitsPixel );
bi.biCompression = dwCompression;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwLen = bi.biSize + PaletteSize((LPSTR)&bi);
// We need a device context to get the DIB from
hDC = GetDC(NULL);
hPal = SelectPalette(hDC, hPal, FALSE);
(void)RealizePalette(hDC);
// Allocate enough memory to hold bitmapinfoheader and color table
hDIB = GlobalAlloc(GMEM_FIXED, dwLen);
if (!hDIB)
{
(void)SelectPalette(hDC, hPal, FALSE);
ReleaseDC(NULL, hDC);
return NULL;
}
lpbi = (LPBITMAPINFOHEADER)hDIB;
*lpbi = bi;
// Call GetDIBits with a NULL lpBits param, so the device driver
// will calculate the biSizeImage field
(void)GetDIBits(hDC, hBitmap, 0L, (DWORD)bi.biHeight,
(LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);
bi = *lpbi;
// If the driver did not fill in the biSizeImage field, then compute it
// Each scan line of the image is aligned on a DWORD (32bit) boundary
if (bi.biSizeImage == 0)
{
bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
* bi.biHeight;
// If a compression scheme is used the result may infact be larger
// Increase the size to account for this.
if (dwCompression != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}
// Realloc the buffer so that it can hold all the bits
dwLen += bi.biSizeImage;
handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE);
if(!handle)
{
GlobalFree(hDIB);
// Reselect the original palette
(void)SelectPalette(hDC, hPal, FALSE);
ReleaseDC(NULL, hDC);
return NULL;
}
hDIB = handle;
// Get the bitmap bits
lpbi = (LPBITMAPINFOHEADER)hDIB;
// FINALLY get the DIB
BOOL bGotBits = GetDIBits(hDC, hBitmap,
0L, // Start scan line
(DWORD)bi.biHeight, // # of scan lines
(LPBYTE)lpbi // address for bitmap bits
+ (bi.biSize + PaletteSize((LPSTR)&bi)),
(LPBITMAPINFO)lpbi, // address of bitmapinfo
(DWORD)DIB_RGB_COLORS); // Use RGB for color table
if( !bGotBits )
{
GlobalFree(hDIB);
(void)SelectPalette(hDC, hPal, FALSE);
ReleaseDC(NULL,hDC);
return NULL;
}
(void)SelectPalette(hDC, hPal, FALSE);
ReleaseDC(NULL, hDC);
return hDIB;
}
bool CBitmapHelper::DrawDIB(CDC *pDC, HANDLE hData, int nLeft, int nRight, int &nWidth)
{
LPBITMAPINFO lpBI ;
void* pDIBBits;
lpBI = (LPBITMAPINFO)GlobalLock(hData);
if (!lpBI)
return false;
int nColors = lpBI->bmiHeader.biClrUsed ? lpBI->bmiHeader.biClrUsed : 1 << lpBI->bmiHeader.biBitCount;
if( lpBI->bmiHeader.biBitCount > 8 )
{
pDIBBits = (LPVOID)((LPDWORD)(lpBI->bmiColors + lpBI->bmiHeader.biClrUsed) +
((lpBI->bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
}
else
{
pDIBBits = (LPVOID)(lpBI->bmiColors + nColors);
}
::StretchDIBits(pDC->m_hDC,
nLeft, nRight,
lpBI->bmiHeader.biWidth, lpBI->bmiHeader.biHeight,
0, 0, lpBI->bmiHeader.biWidth,
lpBI->bmiHeader.biHeight,
pDIBBits, lpBI, DIB_PAL_COLORS, SRCCOPY);
nWidth = lpBI->bmiHeader.biWidth;
GlobalUnlock(hData);
return true;
}