Reactos
1/*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Some DIB related functions
5 * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net>
6 */
7
8#include "precomp.h"
9
10INT g_fileSize = 0;
11float g_xDpi = 96;
12float g_yDpi = 96;
13SYSTEMTIME g_fileTime;
14
15#define WIDTHBYTES(i) (((i) + 31) / 32 * 4)
16
17struct BITMAPINFOEX : BITMAPINFO
18{
19 RGBQUAD bmiColorsExtra[256 - 1];
20};
21
22/* FUNCTIONS ********************************************************/
23
24// Convert DPI (dots per inch) into PPCM (pixels per centimeter)
25float PpcmFromDpi(float dpi)
26{
27 // 1 DPI is 0.0254 meter. 1 centimeter is 1/100 meter.
28 return dpi / (0.0254f * 100.0f);
29}
30
31HBITMAP
32CreateDIBWithProperties(int width, int height)
33{
34 BITMAPINFO bmi;
35 ZeroMemory(&bmi, sizeof(BITMAPINFO));
36 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
37 bmi.bmiHeader.biWidth = width;
38 bmi.bmiHeader.biHeight = height;
39 bmi.bmiHeader.biPlanes = 1;
40 bmi.bmiHeader.biBitCount = 24;
41 return CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
42}
43
44HBITMAP
45CreateMonoBitmap(int width, int height, BOOL bWhite)
46{
47 HBITMAP hbm = CreateBitmap(width, height, 1, 1, NULL);
48 if (hbm == NULL)
49 return NULL;
50
51 if (bWhite)
52 {
53 HDC hdc = CreateCompatibleDC(NULL);
54 HGDIOBJ hbmOld = SelectObject(hdc, hbm);
55 RECT rc = { 0, 0, width, height };
56 FillRect(hdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH));
57 SelectObject(hdc, hbmOld);
58 DeleteDC(hdc);
59 }
60
61 return hbm;
62}
63
64HBITMAP
65CreateColorDIB(int width, int height, COLORREF rgb)
66{
67 HBITMAP ret = CreateDIBWithProperties(width, height);
68 if (!ret)
69 return NULL;
70
71 if (rgb)
72 {
73 HDC hdc = CreateCompatibleDC(NULL);
74 HGDIOBJ hbmOld = SelectObject(hdc, ret);
75 RECT rc;
76 SetRect(&rc, 0, 0, width, height);
77 HBRUSH hbr = CreateSolidBrush(rgb);
78 FillRect(hdc, &rc, hbr);
79 DeleteObject(hbr);
80 SelectObject(hdc, hbmOld);
81 DeleteDC(hdc);
82 }
83
84 return ret;
85}
86
87HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy)
88{
89 BITMAP bm;
90 if (!::GetObjectW(hbm, sizeof(bm), &bm))
91 return NULL;
92
93 if (cx == 0 || cy == 0)
94 {
95 cx = bm.bmWidth;
96 cy = bm.bmHeight;
97 }
98
99 HBITMAP hbmNew = ::CreateBitmap(cx, cy, 1, 1, NULL);
100 if (!hbmNew)
101 return NULL;
102
103 HDC hdc1 = ::CreateCompatibleDC(NULL);
104 HDC hdc2 = ::CreateCompatibleDC(NULL);
105 HGDIOBJ hbm1Old = ::SelectObject(hdc1, hbm);
106 HGDIOBJ hbm2Old = ::SelectObject(hdc2, hbmNew);
107 ::StretchBlt(hdc2, 0, 0, cx, cy, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
108 ::SelectObject(hdc1, hbm1Old);
109 ::SelectObject(hdc2, hbm2Old);
110 ::DeleteDC(hdc1);
111 ::DeleteDC(hdc2);
112 return hbmNew;
113}
114
115HBITMAP CachedBufferDIB(HBITMAP hbm, int minimalWidth, int minimalHeight)
116{
117 if (minimalWidth <= 0)
118 minimalWidth = 1;
119 if (minimalHeight <= 0)
120 minimalHeight = 1;
121
122 BITMAP bm;
123 if (!GetObjectW(hbm, sizeof(bm), &bm))
124 hbm = NULL;
125
126 if (hbm && minimalWidth <= bm.bmWidth && minimalHeight <= bm.bmHeight)
127 return hbm;
128
129 if (hbm)
130 DeleteObject(hbm);
131
132 return CreateDIBWithProperties((minimalWidth * 3) / 2, (minimalHeight * 3) / 2);
133}
134
135int
136GetDIBWidth(HBITMAP hBitmap)
137{
138 BITMAP bm;
139 ::GetObjectW(hBitmap, sizeof(BITMAP), &bm);
140 return bm.bmWidth;
141}
142
143int
144GetDIBHeight(HBITMAP hBitmap)
145{
146 BITMAP bm;
147 ::GetObjectW(hBitmap, sizeof(BITMAP), &bm);
148 return bm.bmHeight;
149}
150
151BOOL SaveDIBToFile(HBITMAP hBitmap, LPCWSTR FileName, BOOL fIsMainFile, REFGUID guidFileType)
152{
153 CWaitCursor waitCursor;
154
155 CImageDx img;
156 img.Attach(hBitmap);
157 HRESULT hr = img.SaveDx(FileName, guidFileType, g_xDpi, g_yDpi);
158 img.Detach();
159
160 if (FAILED(hr))
161 {
162 ShowError(IDS_SAVEERROR, FileName);
163 return FALSE;
164 }
165
166 if (!fIsMainFile)
167 return TRUE;
168
169 WIN32_FIND_DATAW find;
170 HANDLE hFind = ::FindFirstFileW(FileName, &find);
171 if (hFind == INVALID_HANDLE_VALUE)
172 {
173 ShowError(IDS_SAVEERROR, FileName);
174 return FALSE;
175 }
176 ::FindClose(hFind);
177
178 SetFileInfo(FileName, &find, TRUE);
179 g_imageSaved = TRUE;
180 return TRUE;
181}
182
183void SetFileInfo(LPCWSTR name, LPWIN32_FIND_DATAW pFound, BOOL isAFile)
184{
185 // update file time and size
186 if (pFound)
187 {
188 FILETIME ft;
189 ::FileTimeToLocalFileTime(&pFound->ftLastWriteTime, &ft);
190 ::FileTimeToSystemTime(&ft, &g_fileTime);
191
192 g_fileSize = pFound->nFileSizeLow;
193 }
194 else
195 {
196 ZeroMemory(&g_fileTime, sizeof(g_fileTime));
197 g_fileSize = 0;
198 }
199
200 // update g_szFileName
201 if (name && name[0])
202 {
203 CStringW strName = name;
204 ::GetFullPathNameW(strName, _countof(g_szFileName), g_szFileName, NULL);
205 // The following code won't work correctly when (name == g_szFileName):
206 // ::GetFullPathNameW(name, _countof(g_szFileName), g_szFileName, NULL);
207 }
208 else
209 {
210 ::LoadStringW(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, _countof(g_szFileName));
211 }
212
213 // set title
214 CStringW strTitle;
215 strTitle.Format(IDS_WINDOWTITLE, PathFindFileNameW(g_szFileName));
216 mainWindow.SetWindowText(strTitle);
217
218 // update file info and recent
219 g_isAFile = isAFile;
220 if (g_isAFile)
221 registrySettings.SetMostRecentFile(g_szFileName);
222
223 g_imageSaved = TRUE;
224}
225
226HBITMAP InitializeImage(LPCWSTR name, LPWIN32_FIND_DATAW pFound, BOOL isFile)
227{
228 COLORREF white = RGB(255, 255, 255);
229 HBITMAP hBitmap = CreateColorDIB(registrySettings.BMPWidth, registrySettings.BMPHeight, white);
230 if (hBitmap == NULL)
231 {
232 ShowOutOfMemory();
233 imageModel.ClearHistory();
234 return NULL;
235 }
236
237 HDC hScreenDC = ::GetDC(NULL);
238 g_xDpi = (float)::GetDeviceCaps(hScreenDC, LOGPIXELSX);
239 g_yDpi = (float)::GetDeviceCaps(hScreenDC, LOGPIXELSY);
240 ::ReleaseDC(NULL, hScreenDC);
241
242 return SetBitmapAndInfo(hBitmap, name, pFound, isFile);
243}
244
245HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCWSTR name, LPWIN32_FIND_DATAW pFound, BOOL isFile)
246{
247 // update image
248 canvasWindow.updateScrollPos();
249 imageModel.PushImageForUndo(hBitmap);
250 imageModel.ClearHistory();
251
252 SetFileInfo(name, pFound, isFile);
253 g_imageSaved = TRUE;
254 return hBitmap;
255}
256
257HBITMAP DoLoadImageFile(HWND hwnd, LPCWSTR name, BOOL fIsMainFile)
258{
259 CWaitCursor waitCursor;
260
261 // find the file
262 WIN32_FIND_DATAW find;
263 HANDLE hFind = ::FindFirstFileW(name, &find);
264 if (hFind == INVALID_HANDLE_VALUE) // does not exist
265 {
266 ShowError(IDS_LOADERRORTEXT, name);
267 return NULL;
268 }
269 ::FindClose(hFind);
270
271 // is file empty?
272 if (find.nFileSizeLow == 0 && find.nFileSizeHigh == 0)
273 {
274 if (fIsMainFile)
275 return InitializeImage(name, &find, TRUE);
276 }
277
278 // load the image
279 CImageDx img;
280 float xDpi = 0, yDpi = 0;
281 HRESULT hr = img.LoadDx(name, &xDpi, &yDpi);
282 if (FAILED(hr) && fIsMainFile)
283 {
284 imageModel.ClearHistory();
285 hr = img.LoadDx(name, &xDpi, &yDpi);
286 }
287 if (FAILED(hr))
288 {
289 ATLTRACE("hr: 0x%08lX\n", hr);
290 ShowError(IDS_LOADERRORTEXT, name);
291 return NULL;
292 }
293
294 HBITMAP hBitmap = img.Detach();
295 if (!fIsMainFile)
296 return hBitmap;
297
298 if (xDpi <= 0 || yDpi <= 0)
299 {
300 HDC hDC = ::GetDC(NULL);
301 xDpi = (float)::GetDeviceCaps(hDC, LOGPIXELSX);
302 yDpi = (float)::GetDeviceCaps(hDC, LOGPIXELSY);
303 ::ReleaseDC(NULL, hDC);
304 }
305
306 g_xDpi = xDpi;
307 g_yDpi = yDpi;
308
309 SetBitmapAndInfo(hBitmap, name, &find, TRUE);
310 return hBitmap;
311}
312
313HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight, BOOL bMono)
314{
315 HBITMAP hbm2;
316 if (bMono)
317 hbm2 = ::CreateBitmap(cy, cx, 1, 1, NULL);
318 else
319 hbm2 = CreateDIBWithProperties(cy, cx);
320 if (!hbm2)
321 return NULL;
322
323 HDC hDC2 = CreateCompatibleDC(NULL);
324 HGDIOBJ hbm2Old = SelectObject(hDC2, hbm2);
325 if (bRight)
326 {
327 for (INT y = 0; y < cy; ++y)
328 {
329 for (INT x = 0; x < cx; ++x)
330 {
331 COLORREF rgb = GetPixel(hDC1, x, y);
332 SetPixelV(hDC2, cy - (y + 1), x, rgb);
333 }
334 }
335 }
336 else
337 {
338 for (INT y = 0; y < cy; ++y)
339 {
340 for (INT x = 0; x < cx; ++x)
341 {
342 COLORREF rgb = GetPixel(hDC1, x, y);
343 SetPixelV(hDC2, y, cx - (x + 1), rgb);
344 }
345 }
346 }
347 SelectObject(hDC2, hbm2Old);
348 DeleteDC(hDC2);
349 return hbm2;
350}
351
352HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical, BOOL bMono)
353{
354 CWaitCursor waitCursor;
355
356 if (nDegree == 0)
357 return CopyDIBImage(hbm);
358
359 const double eTan = tan(abs(nDegree) * M_PI / 180);
360
361 BITMAP bm;
362 ::GetObjectW(hbm, sizeof(bm), &bm);
363 INT cx = bm.bmWidth, cy = bm.bmHeight, dx = 0, dy = 0;
364 if (bVertical)
365 dy = INT(cx * eTan);
366 else
367 dx = INT(cy * eTan);
368
369 if (dx == 0 && dy == 0)
370 return CopyDIBImage(hbm);
371
372 HBITMAP hbmNew;
373 if (bMono)
374 hbmNew = CreateMonoBitmap(cx + dx, cy + dy, FALSE);
375 else
376 hbmNew = CreateColorDIB(cx + dx, cy + dy, RGB(255, 255, 255));
377 if (!hbmNew)
378 return NULL;
379
380 HDC hDC2 = CreateCompatibleDC(NULL);
381 HGDIOBJ hbm2Old = SelectObject(hDC2, hbmNew);
382 if (bVertical)
383 {
384 for (INT x = 0; x < cx; ++x)
385 {
386 INT delta = INT(x * eTan);
387 if (nDegree > 0)
388 ::BitBlt(hDC2, x, (dy - delta), 1, cy, hDC1, x, 0, SRCCOPY);
389 else
390 ::BitBlt(hDC2, x, delta, 1, cy, hDC1, x, 0, SRCCOPY);
391 }
392 }
393 else
394 {
395 for (INT y = 0; y < cy; ++y)
396 {
397 INT delta = INT(y * eTan);
398 if (nDegree > 0)
399 ::BitBlt(hDC2, (dx - delta), y, cx, 1, hDC1, 0, y, SRCCOPY);
400 else
401 ::BitBlt(hDC2, delta, y, cx, 1, hDC1, 0, y, SRCCOPY);
402 }
403 }
404
405 SelectObject(hDC2, hbm2Old);
406 DeleteDC(hDC2);
407 return hbmNew;
408}
409
410HBITMAP getSubImage(HBITMAP hbmWhole, const RECT& rcPartial)
411{
412 CRect rc = rcPartial;
413 HBITMAP hbmPart = CreateDIBWithProperties(rc.Width(), rc.Height());
414 if (!hbmPart)
415 return NULL;
416
417 HDC hDC1 = ::CreateCompatibleDC(NULL);
418 HDC hDC2 = ::CreateCompatibleDC(NULL);
419 HGDIOBJ hbm1Old = ::SelectObject(hDC1, hbmWhole);
420 HGDIOBJ hbm2Old = ::SelectObject(hDC2, hbmPart);
421 ::BitBlt(hDC2, 0, 0, rc.Width(), rc.Height(), hDC1, rc.left, rc.top, SRCCOPY);
422 ::SelectObject(hDC1, hbm1Old);
423 ::SelectObject(hDC2, hbm2Old);
424 ::DeleteDC(hDC1);
425 ::DeleteDC(hDC2);
426 return hbmPart;
427}
428
429void putSubImage(HBITMAP hbmWhole, const RECT& rcPartial, HBITMAP hbmPart)
430{
431 CRect rc = rcPartial;
432 HDC hDC1 = ::CreateCompatibleDC(NULL);
433 HDC hDC2 = ::CreateCompatibleDC(NULL);
434 HGDIOBJ hbm1Old = ::SelectObject(hDC1, hbmWhole);
435 HGDIOBJ hbm2Old = ::SelectObject(hDC2, hbmPart);
436 ::BitBlt(hDC1, rc.left, rc.top, rc.Width(), rc.Height(), hDC2, 0, 0, SRCCOPY);
437 ::SelectObject(hDC1, hbm1Old);
438 ::SelectObject(hDC2, hbm2Old);
439 ::DeleteDC(hDC1);
440 ::DeleteDC(hDC2);
441}
442
443struct BITMAPINFODX : BITMAPINFO
444{
445 RGBQUAD bmiColorsAdditional[256 - 1];
446};
447
448HGLOBAL BitmapToClipboardDIB(HBITMAP hBitmap)
449{
450 CWaitCursor waitCursor;
451
452 BITMAP bm;
453 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
454 return NULL;
455
456 BITMAPINFODX bmi;
457 ZeroMemory(&bmi, sizeof(bmi));
458 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
459 bmi.bmiHeader.biWidth = bm.bmWidth;
460 bmi.bmiHeader.biHeight = bm.bmHeight;
461 bmi.bmiHeader.biPlanes = 1;
462 bmi.bmiHeader.biBitCount = bm.bmBitsPixel;
463 bmi.bmiHeader.biCompression = BI_RGB;
464 bmi.bmiHeader.biSizeImage = bm.bmWidthBytes * bm.bmHeight;
465
466 INT cColors;
467 if (bm.bmBitsPixel < 16)
468 cColors = 1 << bm.bmBitsPixel;
469 else
470 cColors = 0;
471
472 HDC hDC = CreateCompatibleDC(NULL);
473
474 if (cColors)
475 {
476 HGDIOBJ hbmOld = SelectObject(hDC, hBitmap);
477 cColors = GetDIBColorTable(hDC, 0, cColors, bmi.bmiColors);
478 SelectObject(hDC, hbmOld);
479 }
480
481 DWORD cbColors = cColors * sizeof(RGBQUAD);
482 DWORD dwSize = sizeof(BITMAPINFOHEADER) + cbColors + bmi.bmiHeader.biSizeImage;
483 HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE, dwSize);
484 if (hGlobal)
485 {
486 LPBYTE pb = (LPBYTE)GlobalLock(hGlobal);
487 if (pb)
488 {
489 CopyMemory(pb, &bmi, sizeof(BITMAPINFOHEADER));
490 pb += sizeof(BITMAPINFOHEADER);
491
492 CopyMemory(pb, bmi.bmiColors, cbColors);
493 pb += cbColors;
494
495 GetDIBits(hDC, hBitmap, 0, bm.bmHeight, pb, &bmi, DIB_RGB_COLORS);
496
497 GlobalUnlock(hGlobal);
498 }
499 else
500 {
501 GlobalFree(hGlobal);
502 hGlobal = NULL;
503 }
504 }
505
506 DeleteDC(hDC);
507
508 return hGlobal;
509}
510
511HBITMAP BitmapFromClipboardDIB(HGLOBAL hGlobal)
512{
513 CWaitCursor waitCursor;
514
515 LPBYTE pb = (LPBYTE)GlobalLock(hGlobal);
516 if (!pb)
517 return NULL;
518
519 LPBITMAPINFO pbmi = (LPBITMAPINFO)pb;
520 pb += pbmi->bmiHeader.biSize;
521
522 INT cColors = 0, cbColors = 0;
523 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
524 {
525 LPBITMAPCOREINFO pbmci = (LPBITMAPCOREINFO)pbmi;
526 WORD BitCount = pbmci->bmciHeader.bcBitCount;
527 if (BitCount < 16)
528 {
529 cColors = (1 << BitCount);
530 cbColors = cColors * sizeof(RGBTRIPLE);
531 pb += cbColors;
532 }
533 }
534 else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
535 {
536 WORD BitCount = pbmi->bmiHeader.biBitCount;
537 if (BitCount < 16)
538 {
539 cColors = (1 << BitCount);
540 cbColors = cColors * sizeof(RGBQUAD);
541 pb += cbColors;
542 }
543 }
544
545 HDC hDC = CreateCompatibleDC(NULL);
546 HBITMAP hBitmap = CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, NULL, NULL, 0);
547 if (hBitmap)
548 {
549 SetDIBits(hDC, hBitmap, 0, labs(pbmi->bmiHeader.biHeight), pb, pbmi, DIB_RGB_COLORS);
550 }
551 DeleteDC(hDC);
552
553 GlobalUnlock(hGlobal);
554
555 return hBitmap;
556}
557
558HBITMAP BitmapFromHEMF(HENHMETAFILE hEMF)
559{
560 CWaitCursor waitCursor;
561
562 ENHMETAHEADER header;
563 if (!GetEnhMetaFileHeader(hEMF, sizeof(header), &header))
564 return NULL;
565
566 CRect rc = *(LPRECT)&header.rclBounds;
567 INT cx = rc.Width(), cy = rc.Height();
568 HBITMAP hbm = CreateColorDIB(cx, cy, RGB(255, 255, 255));
569 if (!hbm)
570 return NULL;
571
572 HDC hDC = CreateCompatibleDC(NULL);
573 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
574 PlayEnhMetaFile(hDC, hEMF, &rc);
575 SelectObject(hDC, hbmOld);
576 DeleteDC(hDC);
577
578 return hbm;
579}
580
581BOOL IsBitmapBlackAndWhite(HBITMAP hbm)
582{
583 CWaitCursor waitCursor;
584
585 BITMAP bm;
586 if (!::GetObjectW(hbm, sizeof(bm), &bm))
587 return FALSE;
588
589 if (bm.bmBitsPixel == 1)
590 return TRUE;
591
592 BITMAPINFOEX bmi;
593 ZeroMemory(&bmi, sizeof(bmi));
594 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
595 bmi.bmiHeader.biWidth = bm.bmWidth;
596 bmi.bmiHeader.biHeight = bm.bmHeight;
597 bmi.bmiHeader.biPlanes = 1;
598 bmi.bmiHeader.biBitCount = 24;
599
600 DWORD widthbytes = WIDTHBYTES(24 * bm.bmWidth);
601 DWORD cbBits = widthbytes * bm.bmHeight;
602 LPBYTE pbBits = new BYTE[cbBits];
603
604 HDC hdc = ::CreateCompatibleDC(NULL);
605 ::GetDIBits(hdc, hbm, 0, bm.bmHeight, pbBits, &bmi, DIB_RGB_COLORS);
606 ::DeleteDC(hdc);
607
608 BOOL bBlackAndWhite = TRUE;
609 for (LONG y = 0; y < bm.bmHeight; ++y)
610 {
611 LPBYTE pbLine = &pbBits[widthbytes * y];
612 for (LONG x = 0; x < bm.bmWidth; ++x)
613 {
614 BYTE Blue = *pbLine++;
615 BYTE Green = *pbLine++;
616 BYTE Red = *pbLine++;
617 COLORREF rgbColor = RGB(Red, Green, Blue);
618 if (rgbColor != RGB(0, 0, 0) && rgbColor != RGB(255, 255, 255))
619 {
620 bBlackAndWhite = FALSE;
621 goto Finish;
622 }
623 }
624 }
625
626Finish:
627 delete[] pbBits;
628
629 return bBlackAndWhite;
630}
631
632HBITMAP ConvertToBlackAndWhite(HBITMAP hbm)
633{
634 CWaitCursor waitCursor;
635
636 BITMAP bm;
637 if (!::GetObjectW(hbm, sizeof(bm), &bm))
638 return NULL;
639
640 BITMAPINFOEX bmi;
641 ZeroMemory(&bmi, sizeof(bmi));
642 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
643 bmi.bmiHeader.biWidth = bm.bmWidth;
644 bmi.bmiHeader.biHeight = bm.bmHeight;
645 bmi.bmiHeader.biPlanes = 1;
646 bmi.bmiHeader.biBitCount = 1;
647 bmi.bmiColors[1].rgbBlue = 255;
648 bmi.bmiColors[1].rgbGreen = 255;
649 bmi.bmiColors[1].rgbRed = 255;
650 HDC hdc = ::CreateCompatibleDC(NULL);
651 LPVOID pvMonoBits;
652 HBITMAP hMonoBitmap = ::CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvMonoBits, NULL, 0);
653 if (!hMonoBitmap)
654 {
655 ::DeleteDC(hdc);
656 return NULL;
657 }
658
659 HBITMAP hNewBitmap = CreateDIBWithProperties(bm.bmWidth, bm.bmHeight);
660 if (hNewBitmap)
661 {
662 ::GetDIBits(hdc, hbm, 0, bm.bmHeight, pvMonoBits, &bmi, DIB_RGB_COLORS);
663 ::SetDIBits(hdc, hNewBitmap, 0, bm.bmHeight, pvMonoBits, &bmi, DIB_RGB_COLORS);
664 }
665 ::DeleteObject(hMonoBitmap);
666 ::DeleteDC(hdc);
667
668 return hNewBitmap;
669}