Reactos
at master 669 lines 17 kB view raw
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}