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
10 INT g_fileSize = 0;
11 float g_xDpi = 96;
12 float g_yDpi = 96;
13 SYSTEMTIME g_fileTime;
14
15 #define WIDTHBYTES(i) (((i) + 31) / 32 * 4)
16
17 struct BITMAPINFOEX : BITMAPINFO
18 {
19 RGBQUAD bmiColorsExtra[256 - 1];
20 };
21
22 /* FUNCTIONS ********************************************************/
23
24 // Convert DPI (dots per inch) into PPCM (pixels per centimeter)
PpcmFromDpi(float dpi)25 float 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
31 HBITMAP
CreateDIBWithProperties(int width,int height)32 CreateDIBWithProperties(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
44 HBITMAP
CreateMonoBitmap(int width,int height,BOOL bWhite)45 CreateMonoBitmap(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
64 HBITMAP
CreateColorDIB(int width,int height,COLORREF rgb)65 CreateColorDIB(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
CopyMonoImage(HBITMAP hbm,INT cx,INT cy)87 HBITMAP 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
CachedBufferDIB(HBITMAP hbm,int minimalWidth,int minimalHeight)115 HBITMAP 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
135 int
GetDIBWidth(HBITMAP hBitmap)136 GetDIBWidth(HBITMAP hBitmap)
137 {
138 BITMAP bm;
139 ::GetObjectW(hBitmap, sizeof(BITMAP), &bm);
140 return bm.bmWidth;
141 }
142
143 int
GetDIBHeight(HBITMAP hBitmap)144 GetDIBHeight(HBITMAP hBitmap)
145 {
146 BITMAP bm;
147 ::GetObjectW(hBitmap, sizeof(BITMAP), &bm);
148 return bm.bmHeight;
149 }
150
SaveDIBToFile(HBITMAP hBitmap,LPCWSTR FileName,BOOL fIsMainFile,REFGUID guidFileType)151 BOOL 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
SetFileInfo(LPCWSTR name,LPWIN32_FIND_DATAW pFound,BOOL isAFile)183 void 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
InitializeImage(LPCWSTR name,LPWIN32_FIND_DATAW pFound,BOOL isFile)226 HBITMAP 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 return NULL;
234 }
235
236 HDC hScreenDC = ::GetDC(NULL);
237 g_xDpi = (float)::GetDeviceCaps(hScreenDC, LOGPIXELSX);
238 g_yDpi = (float)::GetDeviceCaps(hScreenDC, LOGPIXELSY);
239 ::ReleaseDC(NULL, hScreenDC);
240
241 return SetBitmapAndInfo(hBitmap, name, pFound, isFile);
242 }
243
SetBitmapAndInfo(HBITMAP hBitmap,LPCWSTR name,LPWIN32_FIND_DATAW pFound,BOOL isFile)244 HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCWSTR name, LPWIN32_FIND_DATAW pFound, BOOL isFile)
245 {
246 // update image
247 canvasWindow.updateScrollPos();
248 imageModel.PushImageForUndo(hBitmap);
249 imageModel.ClearHistory();
250
251 SetFileInfo(name, pFound, isFile);
252 g_imageSaved = TRUE;
253 return hBitmap;
254 }
255
DoLoadImageFile(HWND hwnd,LPCWSTR name,BOOL fIsMainFile)256 HBITMAP DoLoadImageFile(HWND hwnd, LPCWSTR name, BOOL fIsMainFile)
257 {
258 CWaitCursor waitCursor;
259
260 // find the file
261 WIN32_FIND_DATAW find;
262 HANDLE hFind = ::FindFirstFileW(name, &find);
263 if (hFind == INVALID_HANDLE_VALUE) // does not exist
264 {
265 ShowError(IDS_LOADERRORTEXT, name);
266 return NULL;
267 }
268 ::FindClose(hFind);
269
270 // is file empty?
271 if (find.nFileSizeLow == 0 && find.nFileSizeHigh == 0)
272 {
273 if (fIsMainFile)
274 return InitializeImage(name, &find, TRUE);
275 }
276
277 // load the image
278 CImageDx img;
279 float xDpi = 0, yDpi = 0;
280 HRESULT hr = img.LoadDx(name, &xDpi, &yDpi);
281 if (FAILED(hr) && fIsMainFile)
282 {
283 imageModel.ClearHistory();
284 hr = img.LoadDx(name, &xDpi, &yDpi);
285 }
286 if (FAILED(hr))
287 {
288 ATLTRACE("hr: 0x%08lX\n", hr);
289 ShowError(IDS_LOADERRORTEXT, name);
290 return NULL;
291 }
292
293 HBITMAP hBitmap = img.Detach();
294 if (!fIsMainFile)
295 return hBitmap;
296
297 if (xDpi <= 0 || yDpi <= 0)
298 {
299 HDC hDC = ::GetDC(NULL);
300 xDpi = (float)::GetDeviceCaps(hDC, LOGPIXELSX);
301 yDpi = (float)::GetDeviceCaps(hDC, LOGPIXELSY);
302 ::ReleaseDC(NULL, hDC);
303 }
304
305 g_xDpi = xDpi;
306 g_yDpi = yDpi;
307
308 SetBitmapAndInfo(hBitmap, name, &find, TRUE);
309 return hBitmap;
310 }
311
Rotate90DegreeBlt(HDC hDC1,INT cx,INT cy,BOOL bRight,BOOL bMono)312 HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight, BOOL bMono)
313 {
314 HBITMAP hbm2;
315 if (bMono)
316 hbm2 = ::CreateBitmap(cy, cx, 1, 1, NULL);
317 else
318 hbm2 = CreateDIBWithProperties(cy, cx);
319 if (!hbm2)
320 return NULL;
321
322 HDC hDC2 = CreateCompatibleDC(NULL);
323 HGDIOBJ hbm2Old = SelectObject(hDC2, hbm2);
324 if (bRight)
325 {
326 for (INT y = 0; y < cy; ++y)
327 {
328 for (INT x = 0; x < cx; ++x)
329 {
330 COLORREF rgb = GetPixel(hDC1, x, y);
331 SetPixelV(hDC2, cy - (y + 1), x, rgb);
332 }
333 }
334 }
335 else
336 {
337 for (INT y = 0; y < cy; ++y)
338 {
339 for (INT x = 0; x < cx; ++x)
340 {
341 COLORREF rgb = GetPixel(hDC1, x, y);
342 SetPixelV(hDC2, y, cx - (x + 1), rgb);
343 }
344 }
345 }
346 SelectObject(hDC2, hbm2Old);
347 DeleteDC(hDC2);
348 return hbm2;
349 }
350
SkewDIB(HDC hDC1,HBITMAP hbm,INT nDegree,BOOL bVertical,BOOL bMono)351 HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical, BOOL bMono)
352 {
353 CWaitCursor waitCursor;
354
355 if (nDegree == 0)
356 return CopyDIBImage(hbm);
357
358 const double eTan = tan(abs(nDegree) * M_PI / 180);
359
360 BITMAP bm;
361 ::GetObjectW(hbm, sizeof(bm), &bm);
362 INT cx = bm.bmWidth, cy = bm.bmHeight, dx = 0, dy = 0;
363 if (bVertical)
364 dy = INT(cx * eTan);
365 else
366 dx = INT(cy * eTan);
367
368 if (dx == 0 && dy == 0)
369 return CopyDIBImage(hbm);
370
371 HBITMAP hbmNew;
372 if (bMono)
373 hbmNew = CreateMonoBitmap(cx + dx, cy + dy, FALSE);
374 else
375 hbmNew = CreateColorDIB(cx + dx, cy + dy, RGB(255, 255, 255));
376 if (!hbmNew)
377 return NULL;
378
379 HDC hDC2 = CreateCompatibleDC(NULL);
380 HGDIOBJ hbm2Old = SelectObject(hDC2, hbmNew);
381 if (bVertical)
382 {
383 for (INT x = 0; x < cx; ++x)
384 {
385 INT delta = INT(x * eTan);
386 if (nDegree > 0)
387 ::BitBlt(hDC2, x, (dy - delta), 1, cy, hDC1, x, 0, SRCCOPY);
388 else
389 ::BitBlt(hDC2, x, delta, 1, cy, hDC1, x, 0, SRCCOPY);
390 }
391 }
392 else
393 {
394 for (INT y = 0; y < cy; ++y)
395 {
396 INT delta = INT(y * eTan);
397 if (nDegree > 0)
398 ::BitBlt(hDC2, (dx - delta), y, cx, 1, hDC1, 0, y, SRCCOPY);
399 else
400 ::BitBlt(hDC2, delta, y, cx, 1, hDC1, 0, y, SRCCOPY);
401 }
402 }
403
404 SelectObject(hDC2, hbm2Old);
405 DeleteDC(hDC2);
406 return hbmNew;
407 }
408
getSubImage(HBITMAP hbmWhole,const RECT & rcPartial)409 HBITMAP getSubImage(HBITMAP hbmWhole, const RECT& rcPartial)
410 {
411 CRect rc = rcPartial;
412 HBITMAP hbmPart = CreateDIBWithProperties(rc.Width(), rc.Height());
413 if (!hbmPart)
414 return NULL;
415
416 HDC hDC1 = ::CreateCompatibleDC(NULL);
417 HDC hDC2 = ::CreateCompatibleDC(NULL);
418 HGDIOBJ hbm1Old = ::SelectObject(hDC1, hbmWhole);
419 HGDIOBJ hbm2Old = ::SelectObject(hDC2, hbmPart);
420 ::BitBlt(hDC2, 0, 0, rc.Width(), rc.Height(), hDC1, rc.left, rc.top, SRCCOPY);
421 ::SelectObject(hDC1, hbm1Old);
422 ::SelectObject(hDC2, hbm2Old);
423 ::DeleteDC(hDC1);
424 ::DeleteDC(hDC2);
425 return hbmPart;
426 }
427
putSubImage(HBITMAP hbmWhole,const RECT & rcPartial,HBITMAP hbmPart)428 void putSubImage(HBITMAP hbmWhole, const RECT& rcPartial, HBITMAP hbmPart)
429 {
430 CRect rc = rcPartial;
431 HDC hDC1 = ::CreateCompatibleDC(NULL);
432 HDC hDC2 = ::CreateCompatibleDC(NULL);
433 HGDIOBJ hbm1Old = ::SelectObject(hDC1, hbmWhole);
434 HGDIOBJ hbm2Old = ::SelectObject(hDC2, hbmPart);
435 ::BitBlt(hDC1, rc.left, rc.top, rc.Width(), rc.Height(), hDC2, 0, 0, SRCCOPY);
436 ::SelectObject(hDC1, hbm1Old);
437 ::SelectObject(hDC2, hbm2Old);
438 ::DeleteDC(hDC1);
439 ::DeleteDC(hDC2);
440 }
441
442 struct BITMAPINFODX : BITMAPINFO
443 {
444 RGBQUAD bmiColorsAdditional[256 - 1];
445 };
446
BitmapToClipboardDIB(HBITMAP hBitmap)447 HGLOBAL BitmapToClipboardDIB(HBITMAP hBitmap)
448 {
449 CWaitCursor waitCursor;
450
451 BITMAP bm;
452 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
453 return NULL;
454
455 BITMAPINFODX bmi;
456 ZeroMemory(&bmi, sizeof(bmi));
457 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
458 bmi.bmiHeader.biWidth = bm.bmWidth;
459 bmi.bmiHeader.biHeight = bm.bmHeight;
460 bmi.bmiHeader.biPlanes = 1;
461 bmi.bmiHeader.biBitCount = bm.bmBitsPixel;
462 bmi.bmiHeader.biCompression = BI_RGB;
463 bmi.bmiHeader.biSizeImage = bm.bmWidthBytes * bm.bmHeight;
464
465 INT cColors;
466 if (bm.bmBitsPixel < 16)
467 cColors = 1 << bm.bmBitsPixel;
468 else
469 cColors = 0;
470
471 HDC hDC = CreateCompatibleDC(NULL);
472
473 if (cColors)
474 {
475 HGDIOBJ hbmOld = SelectObject(hDC, hBitmap);
476 cColors = GetDIBColorTable(hDC, 0, cColors, bmi.bmiColors);
477 SelectObject(hDC, hbmOld);
478 }
479
480 DWORD cbColors = cColors * sizeof(RGBQUAD);
481 DWORD dwSize = sizeof(BITMAPINFOHEADER) + cbColors + bmi.bmiHeader.biSizeImage;
482 HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE, dwSize);
483 if (hGlobal)
484 {
485 LPBYTE pb = (LPBYTE)GlobalLock(hGlobal);
486 if (pb)
487 {
488 CopyMemory(pb, &bmi, sizeof(BITMAPINFOHEADER));
489 pb += sizeof(BITMAPINFOHEADER);
490
491 CopyMemory(pb, bmi.bmiColors, cbColors);
492 pb += cbColors;
493
494 GetDIBits(hDC, hBitmap, 0, bm.bmHeight, pb, &bmi, DIB_RGB_COLORS);
495
496 GlobalUnlock(hGlobal);
497 }
498 else
499 {
500 GlobalFree(hGlobal);
501 hGlobal = NULL;
502 }
503 }
504
505 DeleteDC(hDC);
506
507 return hGlobal;
508 }
509
BitmapFromClipboardDIB(HGLOBAL hGlobal)510 HBITMAP BitmapFromClipboardDIB(HGLOBAL hGlobal)
511 {
512 CWaitCursor waitCursor;
513
514 LPBYTE pb = (LPBYTE)GlobalLock(hGlobal);
515 if (!pb)
516 return NULL;
517
518 LPBITMAPINFO pbmi = (LPBITMAPINFO)pb;
519 pb += pbmi->bmiHeader.biSize;
520
521 INT cColors = 0, cbColors = 0;
522 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
523 {
524 LPBITMAPCOREINFO pbmci = (LPBITMAPCOREINFO)pbmi;
525 WORD BitCount = pbmci->bmciHeader.bcBitCount;
526 if (BitCount < 16)
527 {
528 cColors = (1 << BitCount);
529 cbColors = cColors * sizeof(RGBTRIPLE);
530 pb += cbColors;
531 }
532 }
533 else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
534 {
535 WORD BitCount = pbmi->bmiHeader.biBitCount;
536 if (BitCount < 16)
537 {
538 cColors = (1 << BitCount);
539 cbColors = cColors * sizeof(RGBQUAD);
540 pb += cbColors;
541 }
542 }
543
544 HDC hDC = CreateCompatibleDC(NULL);
545 HBITMAP hBitmap = CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, NULL, NULL, 0);
546 if (hBitmap)
547 {
548 SetDIBits(hDC, hBitmap, 0, labs(pbmi->bmiHeader.biHeight), pb, pbmi, DIB_RGB_COLORS);
549 }
550 DeleteDC(hDC);
551
552 GlobalUnlock(hGlobal);
553
554 return hBitmap;
555 }
556
BitmapFromHEMF(HENHMETAFILE hEMF)557 HBITMAP BitmapFromHEMF(HENHMETAFILE hEMF)
558 {
559 CWaitCursor waitCursor;
560
561 ENHMETAHEADER header;
562 if (!GetEnhMetaFileHeader(hEMF, sizeof(header), &header))
563 return NULL;
564
565 CRect rc = *(LPRECT)&header.rclBounds;
566 INT cx = rc.Width(), cy = rc.Height();
567 HBITMAP hbm = CreateColorDIB(cx, cy, RGB(255, 255, 255));
568 if (!hbm)
569 return NULL;
570
571 HDC hDC = CreateCompatibleDC(NULL);
572 HGDIOBJ hbmOld = SelectObject(hDC, hbm);
573 PlayEnhMetaFile(hDC, hEMF, &rc);
574 SelectObject(hDC, hbmOld);
575 DeleteDC(hDC);
576
577 return hbm;
578 }
579
IsBitmapBlackAndWhite(HBITMAP hbm)580 BOOL IsBitmapBlackAndWhite(HBITMAP hbm)
581 {
582 CWaitCursor waitCursor;
583
584 BITMAP bm;
585 if (!::GetObjectW(hbm, sizeof(bm), &bm))
586 return FALSE;
587
588 if (bm.bmBitsPixel == 1)
589 return TRUE;
590
591 BITMAPINFOEX bmi;
592 ZeroMemory(&bmi, sizeof(bmi));
593 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
594 bmi.bmiHeader.biWidth = bm.bmWidth;
595 bmi.bmiHeader.biHeight = bm.bmHeight;
596 bmi.bmiHeader.biPlanes = 1;
597 bmi.bmiHeader.biBitCount = 24;
598
599 DWORD widthbytes = WIDTHBYTES(24 * bm.bmWidth);
600 DWORD cbBits = widthbytes * bm.bmHeight;
601 LPBYTE pbBits = new BYTE[cbBits];
602
603 HDC hdc = ::CreateCompatibleDC(NULL);
604 ::GetDIBits(hdc, hbm, 0, bm.bmHeight, pbBits, &bmi, DIB_RGB_COLORS);
605 ::DeleteDC(hdc);
606
607 BOOL bBlackAndWhite = TRUE;
608 for (LONG y = 0; y < bm.bmHeight; ++y)
609 {
610 LPBYTE pbLine = &pbBits[widthbytes * y];
611 for (LONG x = 0; x < bm.bmWidth; ++x)
612 {
613 BYTE Blue = *pbLine++;
614 BYTE Green = *pbLine++;
615 BYTE Red = *pbLine++;
616 COLORREF rgbColor = RGB(Red, Green, Blue);
617 if (rgbColor != RGB(0, 0, 0) && rgbColor != RGB(255, 255, 255))
618 {
619 bBlackAndWhite = FALSE;
620 goto Finish;
621 }
622 }
623 }
624
625 Finish:
626 delete[] pbBits;
627
628 return bBlackAndWhite;
629 }
630
ConvertToBlackAndWhite(HBITMAP hbm)631 HBITMAP ConvertToBlackAndWhite(HBITMAP hbm)
632 {
633 CWaitCursor waitCursor;
634
635 BITMAP bm;
636 if (!::GetObjectW(hbm, sizeof(bm), &bm))
637 return NULL;
638
639 BITMAPINFOEX bmi;
640 ZeroMemory(&bmi, sizeof(bmi));
641 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
642 bmi.bmiHeader.biWidth = bm.bmWidth;
643 bmi.bmiHeader.biHeight = bm.bmHeight;
644 bmi.bmiHeader.biPlanes = 1;
645 bmi.bmiHeader.biBitCount = 1;
646 bmi.bmiColors[1].rgbBlue = 255;
647 bmi.bmiColors[1].rgbGreen = 255;
648 bmi.bmiColors[1].rgbRed = 255;
649 HDC hdc = ::CreateCompatibleDC(NULL);
650 LPVOID pvMonoBits;
651 HBITMAP hMonoBitmap = ::CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvMonoBits, NULL, 0);
652 if (!hMonoBitmap)
653 {
654 ::DeleteDC(hdc);
655 return NULL;
656 }
657
658 HBITMAP hNewBitmap = CreateDIBWithProperties(bm.bmWidth, bm.bmHeight);
659 if (hNewBitmap)
660 {
661 ::GetDIBits(hdc, hbm, 0, bm.bmHeight, pvMonoBits, &bmi, DIB_RGB_COLORS);
662 ::SetDIBits(hdc, hNewBitmap, 0, bm.bmHeight, pvMonoBits, &bmi, DIB_RGB_COLORS);
663 }
664 ::DeleteObject(hMonoBitmap);
665 ::DeleteDC(hdc);
666
667 return hNewBitmap;
668 }
669