1 /* 2 * PROJECT: PAINT for ReactOS 3 * LICENSE: LGPL 4 * FILE: base/applications/mspaint/dib.cpp 5 * PURPOSE: Some DIB related functions 6 * PROGRAMMERS: Benedikt Freisen 7 */ 8 9 #include "precomp.h" 10 #include <math.h> 11 12 INT g_fileSize = 0; 13 float g_xDpi = 96; 14 float g_yDpi = 96; 15 SYSTEMTIME g_fileTime; 16 17 /* FUNCTIONS ********************************************************/ 18 19 // Convert DPI (dots per inch) into PPCM (pixels per centimeter) 20 float PpcmFromDpi(float dpi) 21 { 22 // 1 DPI is 0.0254 meter. 1 centimeter is 1/100 meter. 23 return dpi / (0.0254f * 100.0f); 24 } 25 26 HBITMAP 27 CreateDIBWithProperties(int width, int height) 28 { 29 BITMAPINFO bmi; 30 ZeroMemory(&bmi, sizeof(BITMAPINFO)); 31 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 32 bmi.bmiHeader.biWidth = width; 33 bmi.bmiHeader.biHeight = height; 34 bmi.bmiHeader.biPlanes = 1; 35 bmi.bmiHeader.biBitCount = 24; 36 return CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); 37 } 38 39 HBITMAP 40 CreateMonoBitmap(int width, int height, BOOL bWhite) 41 { 42 HBITMAP hbm = CreateBitmap(width, height, 1, 1, NULL); 43 if (hbm == NULL) 44 return NULL; 45 46 if (bWhite) 47 { 48 HDC hdc = CreateCompatibleDC(NULL); 49 HGDIOBJ hbmOld = SelectObject(hdc, hbm); 50 RECT rc = { 0, 0, width, height }; 51 FillRect(hdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH)); 52 SelectObject(hdc, hbmOld); 53 DeleteDC(hdc); 54 } 55 56 return hbm; 57 } 58 59 HBITMAP 60 CreateColorDIB(int width, int height, COLORREF rgb) 61 { 62 HBITMAP ret = CreateDIBWithProperties(width, height); 63 if (!ret) 64 return NULL; 65 66 if (rgb) 67 { 68 HDC hdc = CreateCompatibleDC(NULL); 69 HGDIOBJ hbmOld = SelectObject(hdc, ret); 70 RECT rc; 71 SetRect(&rc, 0, 0, width, height); 72 HBRUSH hbr = CreateSolidBrush(rgb); 73 FillRect(hdc, &rc, hbr); 74 DeleteObject(hbr); 75 SelectObject(hdc, hbmOld); 76 DeleteDC(hdc); 77 } 78 79 return ret; 80 } 81 82 HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy) 83 { 84 BITMAP bm; 85 if (!GetObject(hbm, sizeof(bm), &bm)) 86 return NULL; 87 88 if (cx == 0 || cy == 0) 89 { 90 cx = bm.bmWidth; 91 cy = bm.bmHeight; 92 } 93 94 HBITMAP hbmNew = CreateBitmap(cx, cy, 1, 1, NULL); 95 if (!hbmNew) 96 return NULL; 97 98 HDC hdc1 = CreateCompatibleDC(NULL); 99 HDC hdc2 = CreateCompatibleDC(NULL); 100 HGDIOBJ hbm1Old = SelectObject(hdc1, hbm); 101 HGDIOBJ hbm2Old = SelectObject(hdc2, hbmNew); 102 StretchBlt(hdc2, 0, 0, cx, cy, hdc1, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); 103 SelectObject(hdc1, hbm1Old); 104 SelectObject(hdc1, hbm2Old); 105 DeleteDC(hdc1); 106 DeleteDC(hdc2); 107 return hbmNew; 108 } 109 110 HBITMAP CachedBufferDIB(HBITMAP hbm, int minimalWidth, int minimalHeight) 111 { 112 if (minimalWidth <= 0) 113 minimalWidth = 1; 114 if (minimalHeight <= 0) 115 minimalHeight = 1; 116 117 BITMAP bm; 118 if (!GetObject(hbm, sizeof(bm), &bm)) 119 hbm = NULL; 120 121 if (hbm && minimalWidth <= bm.bmWidth && minimalHeight <= bm.bmHeight) 122 return hbm; 123 124 if (hbm) 125 DeleteObject(hbm); 126 127 return CreateDIBWithProperties((minimalWidth * 3) / 2, (minimalHeight * 3) / 2); 128 } 129 130 int 131 GetDIBWidth(HBITMAP hBitmap) 132 { 133 BITMAP bm; 134 GetObject(hBitmap, sizeof(BITMAP), &bm); 135 return bm.bmWidth; 136 } 137 138 int 139 GetDIBHeight(HBITMAP hBitmap) 140 { 141 BITMAP bm; 142 GetObject(hBitmap, sizeof(BITMAP), &bm); 143 return bm.bmHeight; 144 } 145 146 BOOL SaveDIBToFile(HBITMAP hBitmap, LPCTSTR FileName, HDC hDC) 147 { 148 CImageDx img; 149 img.Attach(hBitmap); 150 img.SaveDx(FileName, GUID_NULL, g_xDpi, g_yDpi); // TODO: error handling 151 img.Detach(); 152 153 WIN32_FIND_DATA find; 154 HANDLE hFind = FindFirstFile(FileName, &find); 155 if (hFind == INVALID_HANDLE_VALUE) 156 { 157 ShowFileLoadError(FileName); 158 return FALSE; 159 } 160 FindClose(hFind); 161 162 // update time and size 163 FILETIME ft; 164 FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft); 165 FileTimeToSystemTime(&ft, &g_fileTime); 166 g_fileSize = find.nFileSizeLow; 167 168 // TODO: update hRes and vRes 169 170 registrySettings.SetMostRecentFile(FileName); 171 172 g_isAFile = TRUE; 173 g_imageSaved = TRUE; 174 return TRUE; 175 } 176 177 void ShowFileLoadError(LPCTSTR name) 178 { 179 CString strText; 180 strText.Format(IDS_LOADERRORTEXT, (LPCTSTR) name); 181 CString strProgramName; 182 strProgramName.LoadString(IDS_PROGRAMNAME); 183 mainWindow.MessageBox(strText, strProgramName, MB_OK | MB_ICONEXCLAMATION); 184 } 185 186 HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, DWORD dwFileSize, BOOL isFile) 187 { 188 if (hBitmap == NULL) 189 { 190 COLORREF white = RGB(255, 255, 255); 191 hBitmap = CreateColorDIB(registrySettings.BMPWidth, 192 registrySettings.BMPHeight, white); 193 if (hBitmap == NULL) 194 return FALSE; 195 196 HDC hScreenDC = GetDC(NULL); 197 g_xDpi = GetDeviceCaps(hScreenDC, LOGPIXELSX); 198 g_yDpi = GetDeviceCaps(hScreenDC, LOGPIXELSY); 199 ReleaseDC(NULL, hScreenDC); 200 201 ZeroMemory(&g_fileTime, sizeof(g_fileTime)); 202 } 203 204 // update image 205 imageModel.PushImageForUndo(hBitmap); 206 imageModel.ClearHistory(); 207 208 // update g_fileSize 209 g_fileSize = dwFileSize; 210 211 // update g_szFileName 212 if (name && name[0]) 213 GetFullPathName(name, _countof(g_szFileName), g_szFileName, NULL); 214 else 215 LoadString(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, _countof(g_szFileName)); 216 217 // set title 218 CString strTitle; 219 strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName)); 220 mainWindow.SetWindowText(strTitle); 221 222 // update file info and recent 223 g_isAFile = isFile; 224 if (g_isAFile) 225 registrySettings.SetMostRecentFile(g_szFileName); 226 227 g_imageSaved = TRUE; 228 229 return hBitmap; 230 } 231 232 HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL fIsMainFile) 233 { 234 // find the file 235 WIN32_FIND_DATA find; 236 HANDLE hFind = FindFirstFile(name, &find); 237 if (hFind == INVALID_HANDLE_VALUE) 238 { 239 // does not exist 240 CStringW strText; 241 strText.Format(IDS_LOADERRORTEXT, name); 242 MessageBoxW(hwnd, strText, NULL, MB_ICONERROR); 243 return NULL; 244 } 245 DWORD dwFileSize = find.nFileSizeLow; // get file size 246 FindClose(hFind); 247 248 // is file empty? 249 if (dwFileSize == 0) 250 { 251 if (fIsMainFile) 252 { 253 FILETIME ft; 254 FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft); 255 FileTimeToSystemTime(&ft, &g_fileTime); 256 return SetBitmapAndInfo(NULL, name, dwFileSize, TRUE); 257 } 258 } 259 260 // load the image 261 CImageDx img; 262 img.LoadDx(name, &g_xDpi, &g_yDpi); 263 264 if (g_xDpi <= 0) 265 g_xDpi = 96; 266 if (g_yDpi <= 0) 267 g_yDpi = 96; 268 269 HBITMAP hBitmap = img.Detach(); 270 271 if (hBitmap == NULL) 272 { 273 // cannot open 274 CStringW strText; 275 strText.Format(IDS_LOADERRORTEXT, name); 276 MessageBoxW(hwnd, strText, NULL, MB_ICONERROR); 277 return NULL; 278 } 279 280 if (fIsMainFile) 281 { 282 FILETIME ft; 283 FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft); 284 FileTimeToSystemTime(&ft, &g_fileTime); 285 SetBitmapAndInfo(hBitmap, name, dwFileSize, TRUE); 286 } 287 288 return hBitmap; 289 } 290 291 HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight, BOOL bMono) 292 { 293 HBITMAP hbm2; 294 if (bMono) 295 hbm2 = ::CreateBitmap(cy, cx, 1, 1, NULL); 296 else 297 hbm2 = CreateDIBWithProperties(cy, cx); 298 if (!hbm2) 299 return NULL; 300 301 HDC hDC2 = CreateCompatibleDC(NULL); 302 HGDIOBJ hbm2Old = SelectObject(hDC2, hbm2); 303 if (bRight) 304 { 305 for (INT y = 0; y < cy; ++y) 306 { 307 for (INT x = 0; x < cx; ++x) 308 { 309 COLORREF rgb = GetPixel(hDC1, x, y); 310 SetPixelV(hDC2, cy - (y + 1), x, rgb); 311 } 312 } 313 } 314 else 315 { 316 for (INT y = 0; y < cy; ++y) 317 { 318 for (INT x = 0; x < cx; ++x) 319 { 320 COLORREF rgb = GetPixel(hDC1, x, y); 321 SetPixelV(hDC2, y, cx - (x + 1), rgb); 322 } 323 } 324 } 325 SelectObject(hDC2, hbm2Old); 326 DeleteDC(hDC2); 327 return hbm2; 328 } 329 330 #ifndef M_PI 331 #define M_PI 3.14159265 332 #endif 333 334 HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical, BOOL bMono) 335 { 336 if (nDegree == 0) 337 return CopyDIBImage(hbm); 338 339 const double eTan = tan(abs(nDegree) * M_PI / 180); 340 341 BITMAP bm; 342 GetObjectW(hbm, sizeof(bm), &bm); 343 INT cx = bm.bmWidth, cy = bm.bmHeight, dx = 0, dy = 0; 344 if (bVertical) 345 dy = INT(cx * eTan); 346 else 347 dx = INT(cy * eTan); 348 349 if (dx == 0 && dy == 0) 350 return CopyDIBImage(hbm); 351 352 HBITMAP hbmNew; 353 if (bMono) 354 hbmNew = CreateMonoBitmap(cx + dx, cy + dy, FALSE); 355 else 356 hbmNew = CreateColorDIB(cx + dx, cy + dy, RGB(255, 255, 255)); 357 if (!hbmNew) 358 return NULL; 359 360 HDC hDC2 = CreateCompatibleDC(NULL); 361 HGDIOBJ hbm2Old = SelectObject(hDC2, hbmNew); 362 if (bVertical) 363 { 364 for (INT x = 0; x < cx; ++x) 365 { 366 INT delta = INT(x * eTan); 367 if (nDegree > 0) 368 BitBlt(hDC2, x, (dy - delta), 1, cy, hDC1, x, 0, SRCCOPY); 369 else 370 BitBlt(hDC2, x, delta, 1, cy, hDC1, x, 0, SRCCOPY); 371 } 372 } 373 else 374 { 375 for (INT y = 0; y < cy; ++y) 376 { 377 INT delta = INT(y * eTan); 378 if (nDegree > 0) 379 BitBlt(hDC2, (dx - delta), y, cx, 1, hDC1, 0, y, SRCCOPY); 380 else 381 BitBlt(hDC2, delta, y, cx, 1, hDC1, 0, y, SRCCOPY); 382 } 383 } 384 385 SelectObject(hDC2, hbm2Old); 386 DeleteDC(hDC2); 387 return hbmNew; 388 } 389 390 struct BITMAPINFODX : BITMAPINFO 391 { 392 RGBQUAD bmiColorsAdditional[256 - 1]; 393 }; 394 395 HGLOBAL BitmapToClipboardDIB(HBITMAP hBitmap) 396 { 397 BITMAP bm; 398 if (!GetObject(hBitmap, sizeof(BITMAP), &bm)) 399 return NULL; 400 401 BITMAPINFODX bmi; 402 ZeroMemory(&bmi, sizeof(bmi)); 403 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 404 bmi.bmiHeader.biWidth = bm.bmWidth; 405 bmi.bmiHeader.biHeight = bm.bmHeight; 406 bmi.bmiHeader.biPlanes = 1; 407 bmi.bmiHeader.biBitCount = bm.bmBitsPixel; 408 bmi.bmiHeader.biCompression = BI_RGB; 409 bmi.bmiHeader.biSizeImage = bm.bmWidthBytes * bm.bmHeight; 410 411 INT cColors; 412 if (bm.bmBitsPixel < 16) 413 cColors = 1 << bm.bmBitsPixel; 414 else 415 cColors = 0; 416 417 HDC hDC = CreateCompatibleDC(NULL); 418 419 if (cColors) 420 { 421 HGDIOBJ hbmOld = SelectObject(hDC, hBitmap); 422 cColors = GetDIBColorTable(hDC, 0, cColors, bmi.bmiColors); 423 SelectObject(hDC, hbmOld); 424 } 425 426 DWORD cbColors = cColors * sizeof(RGBQUAD); 427 DWORD dwSize = sizeof(BITMAPINFOHEADER) + cbColors + bmi.bmiHeader.biSizeImage; 428 HGLOBAL hGlobal = GlobalAlloc(GHND | GMEM_SHARE, dwSize); 429 if (hGlobal) 430 { 431 LPBYTE pb = (LPBYTE)GlobalLock(hGlobal); 432 if (pb) 433 { 434 CopyMemory(pb, &bmi, sizeof(BITMAPINFOHEADER)); 435 pb += sizeof(BITMAPINFOHEADER); 436 437 CopyMemory(pb, bmi.bmiColors, cbColors); 438 pb += cbColors; 439 440 GetDIBits(hDC, hBitmap, 0, bm.bmHeight, pb, &bmi, DIB_RGB_COLORS); 441 442 GlobalUnlock(hGlobal); 443 } 444 else 445 { 446 GlobalFree(hGlobal); 447 hGlobal = NULL; 448 } 449 } 450 451 DeleteDC(hDC); 452 453 return hGlobal; 454 } 455 456 HBITMAP BitmapFromClipboardDIB(HGLOBAL hGlobal) 457 { 458 LPBYTE pb = (LPBYTE)GlobalLock(hGlobal); 459 if (!pb) 460 return NULL; 461 462 LPBITMAPINFO pbmi = (LPBITMAPINFO)pb; 463 pb += pbmi->bmiHeader.biSize; 464 465 INT cColors = 0, cbColors = 0; 466 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 467 { 468 LPBITMAPCOREINFO pbmci = (LPBITMAPCOREINFO)pbmi; 469 WORD BitCount = pbmci->bmciHeader.bcBitCount; 470 if (BitCount < 16) 471 { 472 cColors = (1 << BitCount); 473 cbColors = cColors * sizeof(RGBTRIPLE); 474 pb += cbColors; 475 } 476 } 477 else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) 478 { 479 WORD BitCount = pbmi->bmiHeader.biBitCount; 480 if (BitCount < 16) 481 { 482 cColors = (1 << BitCount); 483 cbColors = cColors * sizeof(RGBQUAD); 484 pb += cbColors; 485 } 486 } 487 488 HDC hDC = CreateCompatibleDC(NULL); 489 HBITMAP hBitmap = CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, NULL, NULL, 0); 490 if (hBitmap) 491 { 492 SetDIBits(hDC, hBitmap, 0, labs(pbmi->bmiHeader.biHeight), pb, pbmi, DIB_RGB_COLORS); 493 } 494 DeleteDC(hDC); 495 496 GlobalUnlock(hGlobal); 497 498 return hBitmap; 499 } 500 501 HBITMAP BitmapFromHEMF(HENHMETAFILE hEMF) 502 { 503 ENHMETAHEADER header; 504 if (!GetEnhMetaFileHeader(hEMF, sizeof(header), &header)) 505 return NULL; 506 507 CRect rc = *(LPRECT)&header.rclBounds; 508 INT cx = rc.Width(), cy = rc.Height(); 509 HBITMAP hbm = CreateColorDIB(cx, cy, RGB(255, 255, 255)); 510 if (!hbm) 511 return NULL; 512 513 HDC hDC = CreateCompatibleDC(NULL); 514 HGDIOBJ hbmOld = SelectObject(hDC, hbm); 515 PlayEnhMetaFile(hDC, hEMF, &rc); 516 SelectObject(hDC, hbmOld); 517 DeleteDC(hDC); 518 519 return hbm; 520 } 521