1 /* 2 * PROJECT: ReactOS win32 kernel mode subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/dibobj.c 5 * PURPOSE: Dib object functions 6 * PROGRAMMER: 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 static const RGBQUAD DefLogPaletteQuads[20] = /* Copy of Default Logical Palette */ 15 { 16 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */ 17 { 0x00, 0x00, 0x00, 0x00 }, 18 { 0x00, 0x00, 0x80, 0x00 }, 19 { 0x00, 0x80, 0x00, 0x00 }, 20 { 0x00, 0x80, 0x80, 0x00 }, 21 { 0x80, 0x00, 0x00, 0x00 }, 22 { 0x80, 0x00, 0x80, 0x00 }, 23 { 0x80, 0x80, 0x00, 0x00 }, 24 { 0xc0, 0xc0, 0xc0, 0x00 }, 25 { 0xc0, 0xdc, 0xc0, 0x00 }, 26 { 0xf0, 0xca, 0xa6, 0x00 }, 27 { 0xf0, 0xfb, 0xff, 0x00 }, 28 { 0xa4, 0xa0, 0xa0, 0x00 }, 29 { 0x80, 0x80, 0x80, 0x00 }, 30 { 0x00, 0x00, 0xff, 0x00 }, 31 { 0x00, 0xff, 0x00, 0x00 }, 32 { 0x00, 0xff, 0xff, 0x00 }, 33 { 0xff, 0x00, 0x00, 0x00 }, 34 { 0xff, 0x00, 0xff, 0x00 }, 35 { 0xff, 0xff, 0x00, 0x00 }, 36 { 0xff, 0xff, 0xff, 0x00 } 37 }; 38 39 PPALETTE 40 NTAPI 41 CreateDIBPalette( 42 _In_ const BITMAPINFO *pbmi, 43 _In_ PDC pdc, 44 _In_ ULONG iUsage) 45 { 46 PPALETTE ppal; 47 ULONG i, cBitsPixel, cColors; 48 49 if (pbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER)) 50 { 51 PBITMAPCOREINFO pbci = (PBITMAPCOREINFO)pbmi; 52 cBitsPixel = pbci->bmciHeader.bcBitCount; 53 } 54 else 55 { 56 cBitsPixel = pbmi->bmiHeader.biBitCount; 57 } 58 59 /* Check if the colors are indexed */ 60 if (cBitsPixel <= 8) 61 { 62 /* We create a "full" palette */ 63 cColors = 1 << cBitsPixel; 64 65 /* Allocate the palette */ 66 ppal = PALETTE_AllocPalette(PAL_INDEXED, 67 cColors, 68 NULL, 69 0, 70 0, 71 0); 72 73 /* Check if the BITMAPINFO specifies how many colors to use */ 74 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && 75 (pbmi->bmiHeader.biClrUsed != 0)) 76 { 77 /* This is how many colors we can actually process */ 78 cColors = min(cColors, pbmi->bmiHeader.biClrUsed); 79 } 80 81 /* Check how to use the colors */ 82 if (iUsage == DIB_PAL_COLORS) 83 { 84 COLORREF crColor; 85 86 /* The colors are an array of WORD indices into the DC palette */ 87 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 88 89 /* Use the DCs palette or, if no DC is given, the default one */ 90 PPALETTE ppalDC = pdc ? pdc->dclevel.ppal : gppalDefault; 91 92 /* Loop all color indices in the DIB */ 93 for (i = 0; i < cColors; i++) 94 { 95 /* Get the palette index and handle wraparound when exceeding 96 the number of colors in the DC palette */ 97 WORD wIndex = pwColors[i] % ppalDC->NumColors; 98 99 /* USe the RGB value from the DC palette */ 100 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, wIndex); 101 PALETTE_vSetRGBColorForIndex(ppal, i, crColor); 102 } 103 } 104 else if (iUsage == DIB_PAL_BRUSHHACK) 105 { 106 /* The colors are an array of WORD indices into the DC palette */ 107 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 108 109 /* Loop all color indices in the DIB */ 110 for (i = 0; i < cColors; i++) 111 { 112 /* Set the index directly as the RGB color, the real palette 113 containing RGB values will be calculated when the brush is 114 realized */ 115 PALETTE_vSetRGBColorForIndex(ppal, i, pwColors[i]); 116 } 117 118 /* Mark the palette as a brush hack palette */ 119 ppal->flFlags |= PAL_BRUSHHACK; 120 } 121 // else if (iUsage == 2) 122 // { 123 // FIXME: this one is undocumented 124 // ASSERT(FALSE); 125 // } 126 else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) 127 { 128 /* The colors are an array of RGBQUAD values */ 129 RGBQUAD *prgb = (RGBQUAD*)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 130 131 // FIXME: do we need to handle PALETTEINDEX / PALETTERGB macro? 132 133 /* Loop all color indices in the DIB */ 134 for (i = 0; i < cColors; i++) 135 { 136 /* Get the color value and translate it to a COLORREF */ 137 RGBQUAD rgb = prgb[i]; 138 COLORREF crColor = RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue); 139 140 /* Set the RGB value in the palette */ 141 PALETTE_vSetRGBColorForIndex(ppal, i, crColor); 142 } 143 } 144 else 145 { 146 /* The colors are an array of RGBTRIPLE values */ 147 RGBTRIPLE *prgb = (RGBTRIPLE*)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 148 149 /* Loop all color indices in the DIB */ 150 for (i = 0; i < cColors; i++) 151 { 152 /* Get the color value and translate it to a COLORREF */ 153 RGBTRIPLE rgb = prgb[i]; 154 COLORREF crColor = RGB(rgb.rgbtRed, rgb.rgbtGreen, rgb.rgbtBlue); 155 156 /* Set the RGB value in the palette */ 157 PALETTE_vSetRGBColorForIndex(ppal, i, crColor); 158 } 159 } 160 } 161 else 162 { 163 /* This is a bitfield / RGB palette */ 164 ULONG flRedMask, flGreenMask, flBlueMask; 165 166 /* Check if the DIB contains bitfield values */ 167 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && 168 (pbmi->bmiHeader.biCompression == BI_BITFIELDS)) 169 { 170 /* Check if we have a v4/v5 header */ 171 if (pbmi->bmiHeader.biSize >= sizeof(BITMAPV4HEADER)) 172 { 173 /* The masks are dedicated fields in the header */ 174 PBITMAPV4HEADER pbmV4Header = (PBITMAPV4HEADER)&pbmi->bmiHeader; 175 flRedMask = pbmV4Header->bV4RedMask; 176 flGreenMask = pbmV4Header->bV4GreenMask; 177 flBlueMask = pbmV4Header->bV4BlueMask; 178 } 179 else 180 { 181 /* The masks are the first 3 values in the DIB color table */ 182 PDWORD pdwColors = (PVOID)((PCHAR)pbmi + pbmi->bmiHeader.biSize); 183 flRedMask = pdwColors[0]; 184 flGreenMask = pdwColors[1]; 185 flBlueMask = pdwColors[2]; 186 } 187 } 188 else 189 { 190 /* Check what bit depth we have. Note: optimization flags are 191 calculated in PALETTE_AllocPalette() */ 192 if (cBitsPixel == 16) 193 { 194 /* This is an RGB 555 palette */ 195 flRedMask = 0x7C00; 196 flGreenMask = 0x03E0; 197 flBlueMask = 0x001F; 198 } 199 else 200 { 201 /* This is an RGB 888 palette */ 202 flRedMask = 0xFF0000; 203 flGreenMask = 0x00FF00; 204 flBlueMask = 0x0000FF; 205 } 206 } 207 208 /* Allocate the bitfield palette */ 209 ppal = PALETTE_AllocPalette(PAL_BITFIELDS, 210 0, 211 NULL, 212 flRedMask, 213 flGreenMask, 214 flBlueMask); 215 } 216 217 /* We're done, return the palette */ 218 return ppal; 219 } 220 221 // Converts a DIB to a device-dependent bitmap 222 static INT 223 FASTCALL 224 IntSetDIBits( 225 PDC DC, 226 HBITMAP hBitmap, 227 UINT StartScan, 228 UINT ScanLines, 229 CONST VOID *Bits, 230 ULONG cjMaxBits, 231 CONST BITMAPINFO *bmi, 232 UINT ColorUse) 233 { 234 HBITMAP SourceBitmap; 235 PSURFACE psurfDst, psurfSrc; 236 INT result = 0; 237 RECT rcDst; 238 POINTL ptSrc; 239 EXLATEOBJ exlo; 240 PPALETTE ppalDIB = 0; 241 ULONG cjSizeImage; 242 243 if (!bmi || !Bits) return 0; 244 245 /* Check for uncompressed formats */ 246 if ((bmi->bmiHeader.biCompression == BI_RGB) || 247 (bmi->bmiHeader.biCompression == BI_BITFIELDS)) 248 { 249 /* Calculate the image size */ 250 cjSizeImage = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth, 251 ScanLines, 252 bmi->bmiHeader.biBitCount); 253 } 254 /* Check if the header provided an image size */ 255 else if (bmi->bmiHeader.biSizeImage != 0) 256 { 257 /* Use the given size */ 258 cjSizeImage = bmi->bmiHeader.biSizeImage; 259 } 260 else 261 { 262 /* Compressed format without a size. This is invalid. */ 263 DPRINT1("Compressed format without a size!"); 264 return 0; 265 } 266 267 /* Check if the size that we have is ok */ 268 if ((cjSizeImage > cjMaxBits) || (cjSizeImage == 0)) 269 { 270 DPRINT1("Invalid bitmap size! cjSizeImage = %lu, cjMaxBits = %lu\n", 271 cjSizeImage, cjMaxBits); 272 return 0; 273 } 274 275 SourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth, 276 ScanLines, 277 0, 278 BitmapFormat(bmi->bmiHeader.biBitCount, 279 bmi->bmiHeader.biCompression), 280 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 281 cjSizeImage, 282 (PVOID)Bits, 283 0); 284 if (!SourceBitmap) 285 { 286 DPRINT1("Error: Could not create a bitmap.\n"); 287 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 288 return 0; 289 } 290 291 psurfDst = SURFACE_ShareLockSurface(hBitmap); 292 psurfSrc = SURFACE_ShareLockSurface(SourceBitmap); 293 294 if(!(psurfSrc && psurfDst)) 295 { 296 DPRINT1("Error: Could not lock surfaces\n"); 297 goto cleanup; 298 } 299 300 /* Create a palette for the DIB */ 301 ppalDIB = CreateDIBPalette(bmi, DC, ColorUse); 302 if (!ppalDIB) 303 { 304 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 305 goto cleanup; 306 } 307 308 /* Initialize EXLATEOBJ */ 309 EXLATEOBJ_vInitialize(&exlo, 310 ppalDIB, 311 psurfDst->ppal, 312 RGB(0xff, 0xff, 0xff), 313 RGB(0xff, 0xff, 0xff), //DC->pdcattr->crBackgroundClr, 314 0); // DC->pdcattr->crForegroundClr); 315 316 rcDst.top = StartScan; 317 rcDst.left = 0; 318 rcDst.bottom = rcDst.top + ScanLines; 319 rcDst.right = psurfDst->SurfObj.sizlBitmap.cx; 320 ptSrc.x = 0; 321 ptSrc.y = 0; 322 323 result = IntEngCopyBits(&psurfDst->SurfObj, 324 &psurfSrc->SurfObj, 325 NULL, 326 &exlo.xlo, 327 &rcDst, 328 &ptSrc); 329 if(result) 330 result = ScanLines; 331 332 EXLATEOBJ_vCleanup(&exlo); 333 334 cleanup: 335 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 336 if(psurfSrc) SURFACE_ShareUnlockSurface(psurfSrc); 337 if(psurfDst) SURFACE_ShareUnlockSurface(psurfDst); 338 GreDeleteObject(SourceBitmap); 339 340 return result; 341 } 342 343 static 344 HBITMAP 345 IntGdiCreateMaskFromRLE( 346 DWORD Width, 347 DWORD Height, 348 ULONG Compression, 349 const BYTE* Bits, 350 DWORD BitsSize) 351 { 352 HBITMAP Mask; 353 DWORD x, y; 354 SURFOBJ* SurfObj; 355 UINT i = 0; 356 BYTE Data, NumPixels, ToSkip; 357 358 ASSERT((Compression == BI_RLE8) || (Compression == BI_RLE4)); 359 360 /* Create the bitmap */ 361 Mask = GreCreateBitmapEx(Width, Height, 0, BMF_1BPP, 0, 0, NULL, 0); 362 if (!Mask) 363 return NULL; 364 365 SurfObj = EngLockSurface((HSURF)Mask); 366 if (!SurfObj) 367 { 368 GreDeleteObject(Mask); 369 return NULL; 370 } 371 ASSERT(SurfObj->pvBits != NULL); 372 373 x = y = 0; 374 375 while (i < BitsSize) 376 { 377 NumPixels = Bits[i]; 378 Data = Bits[i + 1]; 379 i += 2; 380 381 if (NumPixels != 0) 382 { 383 if ((x + NumPixels) > Width) 384 NumPixels = Width - x; 385 386 if (NumPixels == 0) 387 continue; 388 389 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1); 390 x += NumPixels; 391 continue; 392 } 393 394 if (Data < 3) 395 { 396 switch (Data) 397 { 398 case 0: 399 /* End of line */ 400 y++; 401 if (y == Height) 402 goto done; 403 x = 0; 404 break; 405 case 1: 406 /* End of file */ 407 goto done; 408 case 2: 409 /* Jump */ 410 if (i >= (BitsSize - 1)) 411 goto done; 412 x += Bits[i]; 413 if (x > Width) 414 x = Width; 415 y += Bits[i + 1]; 416 if (y >= Height) 417 goto done; 418 i += 2; 419 break; 420 } 421 /* Done for this run */ 422 continue; 423 } 424 425 /* Embedded data into the RLE */ 426 NumPixels = Data; 427 if (Compression == BI_RLE8) 428 ToSkip = NumPixels; 429 else 430 ToSkip = (NumPixels / 2) + (NumPixels & 1); 431 432 if ((i + ToSkip) > BitsSize) 433 goto done; 434 ToSkip = (ToSkip + 1) & ~1; 435 436 if ((x + NumPixels) > Width) 437 NumPixels = Width - x; 438 439 if (NumPixels != 0) 440 { 441 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1); 442 x += NumPixels; 443 } 444 i += ToSkip; 445 } 446 447 done: 448 EngUnlockSurface(SurfObj); 449 return Mask; 450 } 451 452 W32KAPI 453 INT 454 APIENTRY 455 NtGdiSetDIBitsToDeviceInternal( 456 IN HDC hDC, 457 IN INT XDest, 458 IN INT YDest, 459 IN DWORD Width, 460 IN DWORD Height, 461 IN INT XSrc, 462 IN INT YSrc, 463 IN DWORD StartScan, 464 IN DWORD ScanLines, 465 IN LPBYTE Bits, 466 IN LPBITMAPINFO bmi, 467 IN DWORD ColorUse, 468 IN UINT cjMaxBits, 469 IN UINT cjMaxInfo, 470 IN BOOL bTransformCoordinates, 471 IN OPTIONAL HANDLE hcmXform) 472 { 473 INT ret; 474 PDC pDC = NULL; 475 HBITMAP hSourceBitmap = NULL, hMaskBitmap = NULL; 476 SURFOBJ *pDestSurf, *pSourceSurf = NULL, *pMaskSurf = NULL; 477 SURFACE *pSurf; 478 RECTL rcDest; 479 POINTL ptSource; 480 //INT DIBWidth; 481 SIZEL SourceSize; 482 EXLATEOBJ exlo; 483 PPALETTE ppalDIB = NULL; 484 LPBITMAPINFO pbmiSafe; 485 BOOL bResult; 486 487 if (!Bits) return 0; 488 489 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjMaxInfo, 'pmTG'); 490 if (!pbmiSafe) return 0; 491 492 _SEH2_TRY 493 { 494 ProbeForRead(bmi, cjMaxInfo, 1); 495 ProbeForRead(Bits, cjMaxBits, 1); 496 RtlCopyMemory(pbmiSafe, bmi, cjMaxInfo); 497 bmi = pbmiSafe; 498 } 499 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 500 { 501 ret = 0; 502 goto Exit; 503 } 504 _SEH2_END 505 506 ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan); 507 if (ScanLines == 0) 508 { 509 DPRINT1("ScanLines == 0\n"); 510 ret = 0; 511 goto Exit; 512 } 513 514 pDC = DC_LockDc(hDC); 515 if (!pDC) 516 { 517 EngSetLastError(ERROR_INVALID_HANDLE); 518 ret = 0; 519 goto Exit; 520 } 521 522 if (pDC->dctype == DC_TYPE_INFO) 523 { 524 ret = 0; 525 goto Exit; 526 } 527 528 rcDest.left = XDest; 529 rcDest.top = YDest; 530 if (bTransformCoordinates) 531 { 532 IntLPtoDP(pDC, (LPPOINT)&rcDest, 2); 533 } 534 rcDest.left += pDC->ptlDCOrig.x; 535 rcDest.top += pDC->ptlDCOrig.y; 536 rcDest.right = rcDest.left + Width; 537 rcDest.bottom = rcDest.top + Height; 538 rcDest.top += StartScan; 539 540 if (pDC->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 541 { 542 IntUpdateBoundsRect(pDC, &rcDest); 543 } 544 545 ptSource.x = XSrc; 546 ptSource.y = YSrc; 547 548 SourceSize.cx = bmi->bmiHeader.biWidth; 549 SourceSize.cy = ScanLines; 550 551 //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount); 552 553 hSourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth, 554 ScanLines, 555 0, 556 BitmapFormat(bmi->bmiHeader.biBitCount, 557 bmi->bmiHeader.biCompression), 558 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 559 bmi->bmiHeader.biSizeImage, 560 Bits, 561 0); 562 563 if (!hSourceBitmap) 564 { 565 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 566 ret = 0; 567 goto Exit; 568 } 569 570 pSourceSurf = EngLockSurface((HSURF)hSourceBitmap); 571 if (!pSourceSurf) 572 { 573 ret = 0; 574 goto Exit; 575 } 576 577 /* HACK: If this is a RLE bitmap, only the relevant pixels must be set. */ 578 if ((bmi->bmiHeader.biCompression == BI_RLE8) || (bmi->bmiHeader.biCompression == BI_RLE4)) 579 { 580 hMaskBitmap = IntGdiCreateMaskFromRLE(bmi->bmiHeader.biWidth, 581 ScanLines, 582 bmi->bmiHeader.biCompression, 583 Bits, 584 cjMaxBits); 585 if (!hMaskBitmap) 586 { 587 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 588 ret = 0; 589 goto Exit; 590 } 591 pMaskSurf = EngLockSurface((HSURF)hMaskBitmap); 592 if (!pMaskSurf) 593 { 594 ret = 0; 595 goto Exit; 596 } 597 } 598 599 /* Create a palette for the DIB */ 600 ppalDIB = CreateDIBPalette(bmi, pDC, ColorUse); 601 if (!ppalDIB) 602 { 603 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 604 ret = 0; 605 goto Exit; 606 } 607 608 /* This is actually a blit */ 609 DC_vPrepareDCsForBlit(pDC, &rcDest, NULL, NULL); 610 pSurf = pDC->dclevel.pSurface; 611 if (!pSurf) 612 { 613 DC_vFinishBlit(pDC, NULL); 614 ret = ScanLines; 615 goto Exit; 616 } 617 618 ASSERT(pSurf->ppal); 619 620 /* Initialize EXLATEOBJ */ 621 EXLATEOBJ_vInitialize(&exlo, 622 ppalDIB, 623 pSurf->ppal, 624 RGB(0xff, 0xff, 0xff), 625 pDC->pdcattr->crBackgroundClr, 626 pDC->pdcattr->crForegroundClr); 627 628 pDestSurf = &pSurf->SurfObj; 629 630 /* Copy the bits */ 631 DPRINT("BitsToDev with dstsurf=(%d|%d) (%d|%d), src=(%d|%d) w=%d h=%d\n", 632 rcDest.left, rcDest.top, rcDest.right, rcDest.bottom, 633 ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy); 634 bResult = IntEngBitBlt(pDestSurf, 635 pSourceSurf, 636 pMaskSurf, 637 (CLIPOBJ *)&pDC->co, 638 &exlo.xlo, 639 &rcDest, 640 &ptSource, 641 pMaskSurf ? &ptSource : NULL, 642 NULL, 643 NULL, 644 pMaskSurf ? ROP4_MASK : ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY)); 645 646 /* Cleanup EXLATEOBJ */ 647 EXLATEOBJ_vCleanup(&exlo); 648 649 /* We're done */ 650 DC_vFinishBlit(pDC, NULL); 651 652 ret = bResult ? ScanLines : 0; 653 654 Exit: 655 656 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 657 if (pSourceSurf) EngUnlockSurface(pSourceSurf); 658 if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap); 659 if (pMaskSurf) EngUnlockSurface(pMaskSurf); 660 if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap); 661 if (pDC) DC_UnlockDc(pDC); 662 ExFreePoolWithTag(pbmiSafe, 'pmTG'); 663 664 return ret; 665 } 666 667 668 /* Converts a device-dependent bitmap to a DIB */ 669 INT 670 APIENTRY 671 GreGetDIBitsInternal( 672 HDC hDC, 673 HBITMAP hBitmap, 674 UINT StartScan, 675 UINT ScanLines, 676 LPBYTE Bits, 677 LPBITMAPINFO Info, 678 UINT Usage, 679 UINT MaxBits, 680 UINT MaxInfo) 681 { 682 BITMAPCOREINFO* pbmci = NULL; 683 PSURFACE psurf = NULL; 684 PDC pDC; 685 LONG width, height; 686 WORD planes, bpp; 687 DWORD compr, size ; 688 USHORT i; 689 int bitmap_type; 690 RGBQUAD* rgbQuads; 691 VOID* colorPtr; 692 693 DPRINT("Entered GreGetDIBitsInternal()\n"); 694 695 if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap) 696 return 0; 697 698 pDC = DC_LockDc(hDC); 699 if (pDC == NULL || pDC->dctype == DC_TYPE_INFO) 700 { 701 ScanLines = 0; 702 goto done; 703 } 704 705 /* Get a pointer to the source bitmap object */ 706 psurf = SURFACE_ShareLockSurface(hBitmap); 707 if (psurf == NULL) 708 { 709 ScanLines = 0; 710 goto done; 711 } 712 713 colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize; 714 rgbQuads = colorPtr; 715 716 bitmap_type = DIB_GetBitmapInfo(&Info->bmiHeader, 717 &width, 718 &height, 719 &planes, 720 &bpp, 721 &compr, 722 &size); 723 if(bitmap_type == -1) 724 { 725 DPRINT("Wrong bitmap format\n"); 726 EngSetLastError(ERROR_INVALID_PARAMETER); 727 ScanLines = 0; 728 goto done; 729 } 730 else if(bitmap_type == 0) 731 { 732 /* We need a BITMAPINFO to create a DIB, but we have to fill 733 * the BITMAPCOREINFO we're provided */ 734 pbmci = (BITMAPCOREINFO*)Info; 735 /* fill in the the bit count, so we can calculate the right ColorsSize during the conversion */ 736 pbmci->bmciHeader.bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat); 737 Info = DIB_ConvertBitmapInfo((BITMAPINFO*)pbmci, Usage); 738 if(Info == NULL) 739 { 740 DPRINT1("Error, could not convert the BITMAPCOREINFO!\n"); 741 ScanLines = 0; 742 goto done; 743 } 744 rgbQuads = Info->bmiColors; 745 } 746 747 /* Validate input: 748 - negative width is always an invalid value 749 - non-null Bits and zero bpp is an invalid combination 750 - only check the rest of the input params if either bpp is non-zero or Bits are set */ 751 if (width < 0 || (bpp == 0 && Bits)) 752 { 753 ScanLines = 0; 754 goto done; 755 } 756 757 if (Bits || bpp) 758 { 759 if ((height == 0 || width == 0) || (compr && compr != BI_BITFIELDS && compr != BI_RGB)) 760 { 761 ScanLines = 0; 762 goto done; 763 } 764 } 765 766 Info->bmiHeader.biClrUsed = 0; 767 Info->bmiHeader.biClrImportant = 0; 768 769 /* Fill in the structure */ 770 switch(bpp) 771 { 772 case 0: /* Only info */ 773 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx; 774 Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ? 775 -psurf->SurfObj.sizlBitmap.cy : 776 psurf->SurfObj.sizlBitmap.cy; 777 Info->bmiHeader.biPlanes = 1; 778 Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat); 779 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( Info->bmiHeader.biWidth, 780 Info->bmiHeader.biHeight, 781 Info->bmiHeader.biBitCount); 782 Info->bmiHeader.biCompression = (Info->bmiHeader.biBitCount == 16 || Info->bmiHeader.biBitCount == 32) ? 783 BI_BITFIELDS : BI_RGB; 784 Info->bmiHeader.biXPelsPerMeter = 0; 785 Info->bmiHeader.biYPelsPerMeter = 0; 786 787 if (Info->bmiHeader.biBitCount <= 8 && Info->bmiHeader.biClrUsed == 0) 788 Info->bmiHeader.biClrUsed = 1 << Info->bmiHeader.biBitCount; 789 790 ScanLines = 1; 791 goto done; 792 793 case 1: 794 case 4: 795 case 8: 796 Info->bmiHeader.biClrUsed = 1 << bpp; 797 798 /* If the bitmap is a DIB section and has the same format as what 799 * is requested, go ahead! */ 800 if((psurf->hSecure) && 801 (BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bpp)) 802 { 803 if(Usage == DIB_RGB_COLORS) 804 { 805 ULONG colors = min(psurf->ppal->NumColors, 256); 806 if(colors != 256) Info->bmiHeader.biClrUsed = colors; 807 for(i = 0; i < colors; i++) 808 { 809 rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed; 810 rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen; 811 rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue; 812 rgbQuads[i].rgbReserved = 0; 813 } 814 } 815 else 816 { 817 for(i = 0; i < 256; i++) 818 ((WORD*)rgbQuads)[i] = i; 819 } 820 } 821 else 822 { 823 if(Usage == DIB_PAL_COLORS) 824 { 825 for(i = 0; i < 256; i++) 826 { 827 ((WORD*)rgbQuads)[i] = i; 828 } 829 } 830 else if(bpp > 1 && bpp == BitsPerFormat(psurf->SurfObj.iBitmapFormat)) 831 { 832 /* For color DDBs in native depth (mono DDBs always have 833 a black/white palette): 834 Generate the color map from the selected palette */ 835 PPALETTE pDcPal = PALETTE_ShareLockPalette(pDC->dclevel.hpal); 836 if(!pDcPal) 837 { 838 ScanLines = 0 ; 839 goto done ; 840 } 841 for (i = 0; i < pDcPal->NumColors; i++) 842 { 843 rgbQuads[i].rgbRed = pDcPal->IndexedColors[i].peRed; 844 rgbQuads[i].rgbGreen = pDcPal->IndexedColors[i].peGreen; 845 rgbQuads[i].rgbBlue = pDcPal->IndexedColors[i].peBlue; 846 rgbQuads[i].rgbReserved = 0; 847 } 848 PALETTE_ShareUnlockPalette(pDcPal); 849 } 850 else 851 { 852 switch (bpp) 853 { 854 case 1: 855 rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0; 856 rgbQuads[0].rgbReserved = 0; 857 rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff; 858 rgbQuads[1].rgbReserved = 0; 859 break; 860 861 case 4: 862 /* The EGA palette is the first and last 8 colours of the default palette 863 with the innermost pair swapped */ 864 RtlCopyMemory(rgbQuads, DefLogPaletteQuads, 7 * sizeof(RGBQUAD)); 865 RtlCopyMemory(rgbQuads + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD)); 866 RtlCopyMemory(rgbQuads + 8, DefLogPaletteQuads + 7, 1 * sizeof(RGBQUAD)); 867 RtlCopyMemory(rgbQuads + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD)); 868 break; 869 870 case 8: 871 { 872 INT i; 873 874 memcpy(rgbQuads, DefLogPaletteQuads, 10 * sizeof(RGBQUAD)); 875 memcpy(rgbQuads + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD)); 876 877 for (i = 10; i < 246; i++) 878 { 879 rgbQuads[i].rgbRed = (i & 0x07) << 5; 880 rgbQuads[i].rgbGreen = (i & 0x38) << 2; 881 rgbQuads[i].rgbBlue = i & 0xc0; 882 rgbQuads[i].rgbReserved = 0; 883 } 884 } 885 } 886 } 887 } 888 break; 889 890 case 15: 891 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 892 { 893 ((PDWORD)Info->bmiColors)[0] = 0x7c00; 894 ((PDWORD)Info->bmiColors)[1] = 0x03e0; 895 ((PDWORD)Info->bmiColors)[2] = 0x001f; 896 } 897 break; 898 899 case 16: 900 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 901 { 902 if (psurf->hSecure) 903 { 904 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask; 905 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask; 906 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask; 907 } 908 else 909 { 910 ((PDWORD)Info->bmiColors)[0] = 0xf800; 911 ((PDWORD)Info->bmiColors)[1] = 0x07e0; 912 ((PDWORD)Info->bmiColors)[2] = 0x001f; 913 } 914 } 915 break; 916 917 case 24: 918 case 32: 919 if (Info->bmiHeader.biCompression == BI_BITFIELDS) 920 { 921 if (psurf->hSecure) 922 { 923 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask; 924 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask; 925 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask; 926 } 927 else 928 { 929 ((PDWORD)Info->bmiColors)[0] = 0xff0000; 930 ((PDWORD)Info->bmiColors)[1] = 0x00ff00; 931 ((PDWORD)Info->bmiColors)[2] = 0x0000ff; 932 } 933 } 934 break; 935 936 default: 937 ScanLines = 0; 938 goto done; 939 } 940 941 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(width, height, bpp); 942 Info->bmiHeader.biPlanes = 1; 943 944 if(Bits && ScanLines) 945 { 946 /* Create a DIBSECTION, blt it, profit */ 947 PVOID pDIBits ; 948 HBITMAP hBmpDest; 949 PSURFACE psurfDest; 950 EXLATEOBJ exlo; 951 RECT rcDest; 952 POINTL srcPoint; 953 BOOL ret ; 954 955 if (StartScan > (ULONG)psurf->SurfObj.sizlBitmap.cy) 956 { 957 ScanLines = 0; 958 goto done; 959 } 960 else 961 { 962 ScanLines = min(ScanLines, psurf->SurfObj.sizlBitmap.cy - StartScan); 963 } 964 965 /* Fixup values */ 966 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx; 967 Info->bmiHeader.biHeight = (height < 0) ? 968 -(LONG)ScanLines : ScanLines; 969 /* Create the DIB */ 970 hBmpDest = DIB_CreateDIBSection(pDC, Info, Usage, &pDIBits, NULL, 0, 0); 971 /* Restore them */ 972 Info->bmiHeader.biWidth = width; 973 Info->bmiHeader.biHeight = height; 974 975 if(!hBmpDest) 976 { 977 DPRINT1("Unable to create a DIB Section!\n"); 978 EngSetLastError(ERROR_INVALID_PARAMETER); 979 ScanLines = 0; 980 goto done ; 981 } 982 983 psurfDest = SURFACE_ShareLockSurface(hBmpDest); 984 985 RECTL_vSetRect(&rcDest, 0, 0, psurf->SurfObj.sizlBitmap.cx, ScanLines); 986 987 srcPoint.x = 0; 988 989 if(height < 0) 990 { 991 srcPoint.y = 0; 992 993 if(ScanLines <= StartScan) 994 { 995 ScanLines = 1; 996 SURFACE_ShareUnlockSurface(psurfDest); 997 GreDeleteObject(hBmpDest); 998 goto done; 999 } 1000 1001 ScanLines -= StartScan; 1002 } 1003 else 1004 { 1005 srcPoint.y = StartScan; 1006 } 1007 1008 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xffffff, 0xffffff, 0); 1009 1010 ret = IntEngCopyBits(&psurfDest->SurfObj, 1011 &psurf->SurfObj, 1012 NULL, 1013 &exlo.xlo, 1014 &rcDest, 1015 &srcPoint); 1016 1017 SURFACE_ShareUnlockSurface(psurfDest); 1018 1019 if(!ret) 1020 ScanLines = 0; 1021 else 1022 { 1023 RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp)); 1024 } 1025 1026 GreDeleteObject(hBmpDest); 1027 EXLATEOBJ_vCleanup(&exlo); 1028 } 1029 else 1030 { 1031 /* Signals success and not the actual number of scan lines*/ 1032 ScanLines = 1; 1033 } 1034 1035 done: 1036 1037 if (pbmci) 1038 DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci, Usage); 1039 1040 if (psurf) 1041 SURFACE_ShareUnlockSurface(psurf); 1042 1043 if (pDC) 1044 DC_UnlockDc(pDC); 1045 1046 return ScanLines; 1047 } 1048 1049 _Success_(return!=0) 1050 __kernel_entry 1051 INT 1052 APIENTRY 1053 NtGdiGetDIBitsInternal( 1054 _In_ HDC hdc, 1055 _In_ HBITMAP hbm, 1056 _In_ UINT iStartScan, 1057 _In_ UINT cScans, 1058 _Out_writes_bytes_opt_(cjMaxBits) LPBYTE pjBits, 1059 _Inout_ LPBITMAPINFO pbmi, 1060 _In_ UINT iUsage, 1061 _In_ UINT cjMaxBits, 1062 _In_ UINT cjMaxInfo) 1063 { 1064 PBITMAPINFO pbmiSafe; 1065 HANDLE hSecure = NULL; 1066 INT iResult = 0; 1067 UINT cjAlloc; 1068 1069 /* Check for bad iUsage */ 1070 if (iUsage > 2) return 0; 1071 1072 /* Check if the size of the bitmap info is large enough */ 1073 if (cjMaxInfo < sizeof(BITMAPCOREHEADER)) 1074 { 1075 return 0; 1076 } 1077 1078 /* Use maximum size */ 1079 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD)); 1080 1081 // HACK: the underlying code sucks and doesn't care for the size, so we 1082 // give it the maximum ever needed 1083 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD); 1084 1085 /* Allocate a buffer the bitmapinfo */ 1086 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG'); 1087 if (!pbmiSafe) 1088 { 1089 /* Fail */ 1090 return 0; 1091 } 1092 1093 /* Use SEH */ 1094 _SEH2_TRY 1095 { 1096 /* Probe and copy the BITMAPINFO */ 1097 ProbeForRead(pbmi, cjMaxInfo, 1); 1098 RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo); 1099 } 1100 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1101 { 1102 _SEH2_YIELD(goto cleanup;) 1103 } 1104 _SEH2_END; 1105 1106 /* Check if the header size is large enough */ 1107 if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) || 1108 (pbmiSafe->bmiHeader.biSize > cjMaxInfo)) 1109 { 1110 goto cleanup; 1111 } 1112 1113 /* Check if the caller provided bitmap bits */ 1114 if (pjBits) 1115 { 1116 /* Secure the user mode memory */ 1117 hSecure = EngSecureMem(pjBits, cjMaxBits); 1118 if (!hSecure) 1119 { 1120 goto cleanup; 1121 } 1122 } 1123 1124 /* Now call the internal function */ 1125 iResult = GreGetDIBitsInternal(hdc, 1126 hbm, 1127 iStartScan, 1128 cScans, 1129 pjBits, 1130 pbmiSafe, 1131 iUsage, 1132 cjMaxBits, 1133 cjMaxInfo); 1134 1135 /* Check for success */ 1136 if (iResult) 1137 { 1138 /* Use SEH to copy back to user mode */ 1139 _SEH2_TRY 1140 { 1141 /* Copy the data back */ 1142 cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmiSafe, (WORD)iUsage)); 1143 ProbeForWrite(pbmi, cjMaxInfo, 1); 1144 RtlCopyMemory(pbmi, pbmiSafe, cjMaxInfo); 1145 } 1146 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1147 { 1148 /* Ignore */ 1149 (VOID)0; 1150 } 1151 _SEH2_END; 1152 } 1153 1154 cleanup: 1155 if (hSecure) EngUnsecureMem(hSecure); 1156 ExFreePoolWithTag(pbmiSafe, 'imBG'); 1157 1158 return iResult; 1159 } 1160 1161 1162 W32KAPI 1163 INT 1164 APIENTRY 1165 NtGdiStretchDIBitsInternal( 1166 IN HDC hdc, 1167 IN INT xDst, 1168 IN INT yDst, 1169 IN INT cxDst, 1170 IN INT cyDst, 1171 IN INT xSrc, 1172 IN INT ySrc, 1173 IN INT cxSrc, 1174 IN INT cySrc, 1175 IN OPTIONAL LPBYTE pjInit, 1176 IN LPBITMAPINFO pbmi, 1177 IN DWORD dwUsage, 1178 IN DWORD dwRop, // MS ntgdi.h says dwRop4(?) 1179 IN UINT cjMaxInfo, 1180 IN UINT cjMaxBits, 1181 IN HANDLE hcmXform) 1182 { 1183 BOOL bResult = FALSE; 1184 SIZEL sizel; 1185 RECTL rcSrc, rcDst; 1186 PDC pdc; 1187 HBITMAP hbmTmp = 0; 1188 PSURFACE psurfTmp = 0, psurfDst = 0; 1189 PPALETTE ppalDIB = 0; 1190 EXLATEOBJ exlo; 1191 PVOID pvBits; 1192 1193 if (!(pdc = DC_LockDc(hdc))) 1194 { 1195 EngSetLastError(ERROR_INVALID_HANDLE); 1196 return 0; 1197 } 1198 1199 /* Check for info / mem DC without surface */ 1200 if (!pdc->dclevel.pSurface) 1201 { 1202 DC_UnlockDc(pdc); 1203 // CHECKME 1204 return TRUE; 1205 } 1206 1207 /* Transform dest size */ 1208 sizel.cx = cxDst; 1209 sizel.cy = cyDst; 1210 IntLPtoDP(pdc, (POINTL*)&sizel, 1); 1211 DC_UnlockDc(pdc); 1212 1213 /* Check if we can use NtGdiSetDIBitsToDeviceInternal */ 1214 if ((sizel.cx == cxSrc) && (sizel.cy == cySrc) && (dwRop == SRCCOPY)) 1215 { 1216 /* Yes, we can! */ 1217 return NtGdiSetDIBitsToDeviceInternal(hdc, 1218 xDst, 1219 yDst, 1220 cxDst, 1221 cyDst, 1222 xSrc, 1223 ySrc, 1224 0, 1225 cySrc, 1226 pjInit, 1227 pbmi, 1228 dwUsage, 1229 cjMaxBits, 1230 cjMaxInfo, 1231 TRUE, 1232 hcmXform); 1233 } 1234 1235 if (pjInit && (cjMaxBits > 0)) 1236 { 1237 pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT'); 1238 if (!pvBits) 1239 { 1240 return 0; 1241 } 1242 1243 _SEH2_TRY 1244 { 1245 ProbeForRead(pjInit, cjMaxBits, 1); 1246 RtlCopyMemory(pvBits, pjInit, cjMaxBits); 1247 } 1248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1249 { 1250 ExFreePoolWithTag(pvBits, 'pmeT'); 1251 _SEH2_YIELD(return 0); 1252 } 1253 _SEH2_END 1254 } 1255 else 1256 { 1257 pvBits = NULL; 1258 } 1259 1260 /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */ 1261 if (!(pdc = DC_LockDc(hdc))) 1262 { 1263 DPRINT1("Could not lock dc\n"); 1264 EngSetLastError(ERROR_INVALID_HANDLE); 1265 goto cleanup; 1266 } 1267 1268 /* Calculate source and destination rect */ 1269 rcSrc.left = xSrc; 1270 rcSrc.top = ySrc; 1271 rcSrc.right = xSrc + abs(cxSrc); 1272 rcSrc.bottom = ySrc + abs(cySrc); 1273 rcDst.left = xDst; 1274 rcDst.top = yDst; 1275 rcDst.right = rcDst.left + cxDst; 1276 rcDst.bottom = rcDst.top + cyDst; 1277 IntLPtoDP(pdc, (POINTL*)&rcDst, 2); 1278 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); 1279 1280 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 1281 { 1282 IntUpdateBoundsRect(pdc, &rcDst); 1283 } 1284 1285 hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth, 1286 abs(pbmi->bmiHeader.biHeight), 1287 0, 1288 BitmapFormat(pbmi->bmiHeader.biBitCount, 1289 pbmi->bmiHeader.biCompression), 1290 pbmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0, 1291 cjMaxBits, 1292 pvBits, 1293 0); 1294 1295 if (!hbmTmp) 1296 { 1297 bResult = FALSE; 1298 goto cleanup; 1299 } 1300 1301 psurfTmp = SURFACE_ShareLockSurface(hbmTmp); 1302 if (!psurfTmp) 1303 { 1304 bResult = FALSE; 1305 goto cleanup; 1306 } 1307 1308 /* Create a palette for the DIB */ 1309 ppalDIB = CreateDIBPalette(pbmi, pdc, dwUsage); 1310 if (!ppalDIB) 1311 { 1312 bResult = FALSE; 1313 goto cleanup; 1314 } 1315 1316 /* Prepare DC for blit */ 1317 DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL); 1318 1319 psurfDst = pdc->dclevel.pSurface; 1320 1321 /* Initialize XLATEOBJ */ 1322 EXLATEOBJ_vInitialize(&exlo, 1323 ppalDIB, 1324 psurfDst->ppal, 1325 RGB(0xff, 0xff, 0xff), 1326 pdc->pdcattr->crBackgroundClr, 1327 pdc->pdcattr->crForegroundClr); 1328 1329 /* Perform the stretch operation */ 1330 bResult = IntEngStretchBlt(&psurfDst->SurfObj, 1331 &psurfTmp->SurfObj, 1332 NULL, 1333 (CLIPOBJ *)&pdc->co, 1334 &exlo.xlo, 1335 &pdc->dclevel.ca, 1336 &rcDst, 1337 &rcSrc, 1338 NULL, 1339 &pdc->eboFill.BrushObject, 1340 NULL, 1341 WIN32_ROP3_TO_ENG_ROP4(dwRop)); 1342 1343 /* Cleanup */ 1344 DC_vFinishBlit(pdc, NULL); 1345 EXLATEOBJ_vCleanup(&exlo); 1346 cleanup: 1347 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB); 1348 if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp); 1349 if (hbmTmp) GreDeleteObject(hbmTmp); 1350 if (pdc) DC_UnlockDc(pdc); 1351 if (pvBits) ExFreePoolWithTag(pvBits, 'pmeT'); 1352 1353 return bResult; 1354 } 1355 1356 1357 HBITMAP 1358 FASTCALL 1359 IntCreateDIBitmap( 1360 PDC Dc, 1361 INT width, 1362 INT height, 1363 UINT planes, 1364 UINT bpp, 1365 ULONG compression, 1366 DWORD init, 1367 LPBYTE bits, 1368 ULONG cjMaxBits, 1369 PBITMAPINFO data, 1370 DWORD coloruse) 1371 { 1372 HBITMAP handle; 1373 BOOL fColor; 1374 ULONG BmpFormat = 0; 1375 1376 if (planes && bpp) 1377 BmpFormat = BitmapFormat(planes * bpp, compression); 1378 1379 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2 1380 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap. 1381 1382 if (BmpFormat != BMF_1BPP) fColor = TRUE; 1383 else if ((coloruse > DIB_RGB_COLORS) || ((init & CBM_INIT) == 0) || !data) fColor = FALSE; 1384 else 1385 { 1386 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize); 1387 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue); 1388 1389 // Check if the first color of the colormap is black 1390 if (col == RGB(0, 0, 0)) 1391 { 1392 rgb++; 1393 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue); 1394 1395 // If the second color is white, create a monochrome bitmap 1396 fColor = (col != RGB(0xff,0xff,0xff)); 1397 } 1398 else fColor = TRUE; 1399 } 1400 1401 // Now create the bitmap 1402 if (fColor) 1403 { 1404 if (init & CBM_CREATDIB) 1405 { 1406 PSURFACE Surface; 1407 PPALETTE Palette; 1408 1409 /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */ 1410 handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp); 1411 if (!handle) 1412 { 1413 DPRINT1("IntCreateCompatibleBitmap() failed!\n"); 1414 return NULL; 1415 } 1416 1417 /* The palette must also match the given data */ 1418 Surface = SURFACE_ShareLockSurface(handle); 1419 ASSERT(Surface); 1420 Palette = CreateDIBPalette(data, Dc, coloruse); 1421 ASSERT(Palette); 1422 SURFACE_vSetPalette(Surface, Palette); 1423 1424 PALETTE_ShareUnlockPalette(Palette); 1425 SURFACE_ShareUnlockSurface(Surface); 1426 } 1427 else 1428 { 1429 /* Create a regular compatible bitmap, in the same format as the device */ 1430 handle = IntCreateCompatibleBitmap(Dc, width, height, 0, 0); 1431 } 1432 } 1433 else 1434 { 1435 handle = GreCreateBitmap(width, 1436 abs(height), 1437 1, 1438 1, 1439 NULL); 1440 } 1441 1442 if (height < 0) 1443 height = -height; 1444 1445 if ((NULL != handle) && (CBM_INIT & init)) 1446 { 1447 IntSetDIBits(Dc, handle, 0, height, bits, cjMaxBits, data, coloruse); 1448 } 1449 1450 return handle; 1451 } 1452 1453 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits 1454 // The DDB that is created will be whatever bit depth your reference DC is 1455 HBITMAP 1456 APIENTRY 1457 NtGdiCreateDIBitmapInternal( 1458 IN HDC hDc, 1459 IN INT cx, 1460 IN INT cy, 1461 IN DWORD fInit, 1462 IN OPTIONAL LPBYTE pjInit, 1463 IN OPTIONAL LPBITMAPINFO pbmi, 1464 IN DWORD iUsage, 1465 IN UINT cjMaxInitInfo, 1466 IN UINT cjMaxBits, 1467 IN FLONG fl, 1468 IN HANDLE hcmXform) 1469 { 1470 NTSTATUS Status = STATUS_SUCCESS; 1471 PBYTE safeBits = NULL; 1472 HBITMAP hbmResult = NULL; 1473 1474 if (pjInit == NULL) 1475 { 1476 fInit &= ~CBM_INIT; 1477 } 1478 1479 if(pjInit && (fInit & CBM_INIT)) 1480 { 1481 if (cjMaxBits == 0) return NULL; 1482 safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB); 1483 if(!safeBits) 1484 { 1485 DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits); 1486 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1487 return NULL; 1488 } 1489 } 1490 1491 _SEH2_TRY 1492 { 1493 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1); 1494 if(pjInit && (fInit & CBM_INIT)) 1495 { 1496 ProbeForRead(pjInit, cjMaxBits, 1); 1497 RtlCopyMemory(safeBits, pjInit, cjMaxBits); 1498 } 1499 } 1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1501 { 1502 Status = _SEH2_GetExceptionCode(); 1503 } 1504 _SEH2_END 1505 1506 if(!NT_SUCCESS(Status)) 1507 { 1508 DPRINT1("Got an exception! pjInit = %p\n", pjInit); 1509 SetLastNtError(Status); 1510 goto cleanup; 1511 } 1512 1513 hbmResult = GreCreateDIBitmapInternal(hDc, 1514 cx, 1515 cy, 1516 fInit, 1517 safeBits, 1518 pbmi, 1519 iUsage, 1520 fl, 1521 cjMaxBits, 1522 hcmXform); 1523 1524 cleanup: 1525 if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB); 1526 return hbmResult; 1527 } 1528 1529 HBITMAP 1530 NTAPI 1531 GreCreateDIBitmapInternal( 1532 IN HDC hDc, 1533 IN INT cx, 1534 IN INT cy, 1535 IN DWORD fInit, 1536 IN OPTIONAL LPBYTE pjInit, 1537 IN OPTIONAL PBITMAPINFO pbmi, 1538 IN DWORD iUsage, 1539 IN FLONG fl, 1540 IN UINT cjMaxBits, 1541 IN HANDLE hcmXform) 1542 { 1543 PDC Dc; 1544 HBITMAP Bmp; 1545 USHORT bpp, planes; 1546 DWORD compression; 1547 HDC hdcDest; 1548 1549 if (!hDc) /* 1bpp monochrome bitmap */ 1550 { 1551 // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this. 1552 hdcDest = NtGdiCreateCompatibleDC(0); 1553 if(!hdcDest) 1554 { 1555 DPRINT1("NtGdiCreateCompatibleDC failed\n"); 1556 return NULL; 1557 } 1558 } 1559 else 1560 { 1561 hdcDest = hDc; 1562 } 1563 1564 Dc = DC_LockDc(hdcDest); 1565 if (!Dc) 1566 { 1567 DPRINT1("Failed to lock hdcDest %p\n", hdcDest); 1568 EngSetLastError(ERROR_INVALID_HANDLE); 1569 return NULL; 1570 } 1571 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap 1572 * if bpp != 1 and ignore the real value that was passed */ 1573 if (pbmi) 1574 { 1575 if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 1576 { 1577 BITMAPCOREHEADER* CoreHeader = (BITMAPCOREHEADER*)&pbmi->bmiHeader; 1578 bpp = CoreHeader->bcBitCount; 1579 planes = CoreHeader->bcPlanes ? CoreHeader->bcPlanes : 1; 1580 compression = BI_RGB; 1581 } 1582 else 1583 { 1584 bpp = pbmi->bmiHeader.biBitCount; 1585 planes = pbmi->bmiHeader.biPlanes ? pbmi->bmiHeader.biPlanes : 1; 1586 compression = pbmi->bmiHeader.biCompression; 1587 } 1588 } 1589 else 1590 { 1591 bpp = 0; 1592 planes = 0; 1593 compression = 0; 1594 } 1595 Bmp = IntCreateDIBitmap(Dc, cx, cy, planes, bpp, compression, fInit, pjInit, cjMaxBits, pbmi, iUsage); 1596 DC_UnlockDc(Dc); 1597 1598 if(!hDc) 1599 { 1600 NtGdiDeleteObjectApp(hdcDest); 1601 } 1602 return Bmp; 1603 } 1604 1605 HBITMAP 1606 NTAPI 1607 GreCreateDIBitmapFromPackedDIB( 1608 _In_reads_(cjPackedDIB )PVOID pvPackedDIB, 1609 _In_ UINT cjPackedDIB, 1610 _In_ ULONG uUsage) 1611 { 1612 PBITMAPINFO pbmi; 1613 PBYTE pjBits; 1614 UINT cjInfo, cjBits; 1615 HBITMAP hbm; 1616 1617 /* We only support BITMAPINFOHEADER, make sure the size is ok */ 1618 if (cjPackedDIB < sizeof(BITMAPINFOHEADER)) 1619 { 1620 return NULL; 1621 } 1622 1623 /* The packed DIB starts with the BITMAPINFOHEADER */ 1624 pbmi = pvPackedDIB; 1625 1626 if (cjPackedDIB < pbmi->bmiHeader.biSize) 1627 { 1628 return NULL; 1629 } 1630 1631 /* Calculate the info size and make sure the packed DIB is large enough */ 1632 cjInfo = DIB_BitmapInfoSize(pbmi, uUsage); 1633 if (cjPackedDIB <= cjInfo) 1634 { 1635 return NULL; 1636 } 1637 1638 /* The bitmap bits start after the header */ 1639 pjBits = (PBYTE)pvPackedDIB + cjInfo; 1640 cjBits = cjPackedDIB - cjInfo; 1641 1642 hbm = GreCreateDIBitmapInternal(NULL, 1643 pbmi->bmiHeader.biWidth, 1644 abs(pbmi->bmiHeader.biHeight), 1645 CBM_INIT | CBM_CREATDIB, 1646 pjBits, 1647 pbmi, 1648 uUsage, 1649 0, 1650 cjBits, 1651 NULL); 1652 1653 return hbm; 1654 } 1655 1656 HBITMAP 1657 APIENTRY 1658 NtGdiCreateDIBSection( 1659 IN HDC hDC, 1660 IN OPTIONAL HANDLE hSection, 1661 IN DWORD dwOffset, 1662 IN BITMAPINFO* bmi, 1663 IN DWORD Usage, 1664 IN UINT cjHeader, 1665 IN FLONG fl, 1666 IN ULONG_PTR dwColorSpace, 1667 OUT PVOID *Bits) 1668 { 1669 HBITMAP hbitmap = 0; 1670 DC *dc; 1671 BOOL bDesktopDC = FALSE; 1672 NTSTATUS Status = STATUS_SUCCESS; 1673 1674 if (!bmi) return hbitmap; // Make sure. 1675 1676 _SEH2_TRY 1677 { 1678 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1); 1679 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1); 1680 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1); 1681 } 1682 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1683 { 1684 Status = _SEH2_GetExceptionCode(); 1685 } 1686 _SEH2_END 1687 1688 if(!NT_SUCCESS(Status)) 1689 { 1690 SetLastNtError(Status); 1691 return NULL; 1692 } 1693 1694 // If the reference hdc is null, take the desktop dc 1695 if (hDC == 0) 1696 { 1697 hDC = NtGdiCreateCompatibleDC(0); 1698 bDesktopDC = TRUE; 1699 } 1700 1701 if ((dc = DC_LockDc(hDC))) 1702 { 1703 hbitmap = DIB_CreateDIBSection(dc, 1704 bmi, 1705 Usage, 1706 Bits, 1707 hSection, 1708 dwOffset, 1709 0); 1710 DC_UnlockDc(dc); 1711 } 1712 else 1713 { 1714 EngSetLastError(ERROR_INVALID_HANDLE); 1715 } 1716 1717 if (bDesktopDC) 1718 NtGdiDeleteObjectApp(hDC); 1719 1720 return hbitmap; 1721 } 1722 1723 HBITMAP 1724 APIENTRY 1725 DIB_CreateDIBSection( 1726 PDC dc, 1727 CONST BITMAPINFO *bmi, 1728 UINT usage, 1729 LPVOID *bits, 1730 HANDLE section, 1731 DWORD offset, 1732 DWORD ovr_pitch) 1733 { 1734 HBITMAP res = 0; 1735 SURFACE *bmp = NULL; 1736 void *mapBits = NULL; 1737 PPALETTE ppalDIB = NULL; 1738 1739 // Fill BITMAP32 structure with DIB data 1740 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader; 1741 INT effHeight; 1742 ULONG totalSize; 1743 BITMAP bm; 1744 //SIZEL Size; 1745 HANDLE hSecure; 1746 1747 DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n", 1748 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount, 1749 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB"); 1750 1751 /* CreateDIBSection should fail for compressed formats */ 1752 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8) 1753 { 1754 DPRINT1("no compressed format allowed\n"); 1755 return (HBITMAP)NULL; 1756 } 1757 1758 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight; 1759 bm.bmType = 0; 1760 bm.bmWidth = bi->biWidth; 1761 bm.bmHeight = effHeight; 1762 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount); 1763 1764 bm.bmPlanes = bi->biPlanes; 1765 bm.bmBitsPixel = bi->biBitCount; 1766 bm.bmBits = NULL; 1767 1768 // Get storage location for DIB bits. Only use biSizeImage if it's valid and 1769 // we're dealing with a compressed bitmap. Otherwise, use width * height. 1770 totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS)) 1771 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight); 1772 1773 if (section) 1774 { 1775 SYSTEM_BASIC_INFORMATION Sbi; 1776 NTSTATUS Status; 1777 DWORD mapOffset; 1778 LARGE_INTEGER SectionOffset; 1779 SIZE_T mapSize; 1780 1781 Status = ZwQuerySystemInformation(SystemBasicInformation, 1782 &Sbi, 1783 sizeof Sbi, 1784 0); 1785 if (!NT_SUCCESS(Status)) 1786 { 1787 DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status); 1788 return NULL; 1789 } 1790 1791 mapOffset = offset - (offset % Sbi.AllocationGranularity); 1792 mapSize = totalSize + (offset - mapOffset); 1793 1794 SectionOffset.LowPart = mapOffset; 1795 SectionOffset.HighPart = 0; 1796 1797 Status = ZwMapViewOfSection(section, 1798 NtCurrentProcess(), 1799 &mapBits, 1800 0, 1801 0, 1802 &SectionOffset, 1803 &mapSize, 1804 ViewShare, 1805 0, 1806 PAGE_READWRITE); 1807 if (!NT_SUCCESS(Status)) 1808 { 1809 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status); 1810 EngSetLastError(ERROR_INVALID_PARAMETER); 1811 return NULL; 1812 } 1813 1814 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset); 1815 } 1816 else if (ovr_pitch && offset) 1817 bm.bmBits = UlongToPtr(offset); 1818 else 1819 { 1820 offset = 0; 1821 bm.bmBits = EngAllocUserMem(totalSize, 0); 1822 if(!bm.bmBits) 1823 { 1824 DPRINT1("Failed to allocate memory\n"); 1825 goto cleanup; 1826 } 1827 } 1828 1829 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE); 1830 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!! 1831 1832 1833 // Create Device Dependent Bitmap and add DIB pointer 1834 //Size.cx = bm.bmWidth; 1835 //Size.cy = abs(bm.bmHeight); 1836 res = GreCreateBitmapEx(bm.bmWidth, 1837 abs(bm.bmHeight), 1838 bm.bmWidthBytes, 1839 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression), 1840 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT | 1841 ((bi->biHeight < 0) ? BMF_TOPDOWN : 0), 1842 totalSize, 1843 bm.bmBits, 1844 0); 1845 if (!res) 1846 { 1847 DPRINT1("GreCreateBitmapEx failed\n"); 1848 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); 1849 goto cleanup; 1850 } 1851 bmp = SURFACE_ShareLockSurface(res); // HACK 1852 if (NULL == bmp) 1853 { 1854 DPRINT1("SURFACE_LockSurface failed\n"); 1855 EngSetLastError(ERROR_INVALID_HANDLE); 1856 goto cleanup; 1857 } 1858 1859 /* WINE NOTE: WINE makes use of a colormap, which is a color translation 1860 table between the DIB and the X physical device. Obviously, 1861 this is left out of the ReactOS implementation. Instead, 1862 we call NtGdiSetDIBColorTable. */ 1863 bmp->hDIBSection = section; 1864 bmp->hSecure = hSecure; 1865 bmp->dwOffset = offset; 1866 bmp->flags = API_BITMAP; 1867 bmp->biClrImportant = bi->biClrImportant; 1868 1869 /* Create a palette for the DIB */ 1870 ppalDIB = CreateDIBPalette(bmi, dc, usage); 1871 1872 // Clean up in case of errors 1873 cleanup: 1874 if (!res || !bmp || !bm.bmBits || !ppalDIB) 1875 { 1876 DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits); 1877 if (bm.bmBits) 1878 { 1879 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this! 1880 if (section) 1881 { 1882 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits); 1883 bm.bmBits = NULL; 1884 } 1885 else if (!offset) 1886 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL; 1887 } 1888 1889 if (bmp) 1890 { 1891 SURFACE_ShareUnlockSurface(bmp); 1892 bmp = NULL; 1893 } 1894 1895 if (res) 1896 { 1897 GreDeleteObject(res); 1898 res = 0; 1899 } 1900 1901 if(ppalDIB) 1902 { 1903 PALETTE_ShareUnlockPalette(ppalDIB); 1904 } 1905 } 1906 1907 if (bmp) 1908 { 1909 /* If we're here, everything went fine */ 1910 SURFACE_vSetPalette(bmp, ppalDIB); 1911 PALETTE_ShareUnlockPalette(ppalDIB); 1912 SURFACE_ShareUnlockSurface(bmp); 1913 } 1914 1915 // Return BITMAP handle and storage location 1916 if (NULL != bm.bmBits && NULL != bits) 1917 { 1918 *bits = bm.bmBits; 1919 } 1920 1921 return res; 1922 } 1923 1924 /*********************************************************************** 1925 * DIB_GetBitmapInfo 1926 * 1927 * Get the info from a bitmap header. 1928 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error. 1929 */ 1930 int 1931 FASTCALL 1932 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width, 1933 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size ) 1934 { 1935 if (header->biSize == sizeof(BITMAPCOREHEADER)) 1936 { 1937 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header; 1938 *width = core->bcWidth; 1939 *height = core->bcHeight; 1940 *planes = core->bcPlanes; 1941 *bpp = core->bcBitCount; 1942 *compr = BI_RGB; 1943 *size = 0; 1944 return 0; 1945 } 1946 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */ 1947 { 1948 *width = header->biWidth; 1949 *height = header->biHeight; 1950 *planes = header->biPlanes; 1951 *bpp = header->biBitCount; 1952 *compr = header->biCompression; 1953 *size = header->biSizeImage; 1954 return 1; 1955 } 1956 DPRINT1("(%u): unknown/wrong size for header\n", header->biSize ); 1957 return -1; 1958 } 1959 1960 /*********************************************************************** 1961 * DIB_GetDIBImageBytes 1962 * 1963 * Return the number of bytes used to hold the image in a DIB bitmap. 1964 * 11/16/1999 (RJJ) lifted from wine 1965 */ 1966 1967 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth) 1968 { 1969 return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height); 1970 } 1971 1972 /*********************************************************************** 1973 * DIB_BitmapInfoSize 1974 * 1975 * Return the size of the bitmap info structure including color table. 1976 * 11/16/1999 (RJJ) lifted from wine 1977 */ 1978 1979 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse) 1980 { 1981 unsigned int colors, size, masks = 0; 1982 unsigned int colorsize; 1983 1984 colorsize = (coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : 1985 (coloruse == DIB_PAL_INDICES) ? 0 : 1986 sizeof(WORD); 1987 1988 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 1989 { 1990 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info; 1991 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0; 1992 return sizeof(BITMAPCOREHEADER) + colors * colorsize; 1993 } 1994 else /* Assume BITMAPINFOHEADER */ 1995 { 1996 colors = info->bmiHeader.biClrUsed; 1997 if (colors > 256) colors = 256; 1998 if (!colors && (info->bmiHeader.biBitCount <= 8)) 1999 colors = 1 << info->bmiHeader.biBitCount; 2000 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3; 2001 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ); 2002 return size + colors * colorsize; 2003 } 2004 } 2005 2006 HPALETTE 2007 FASTCALL 2008 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi) 2009 { 2010 PPALETTE ppalNew; 2011 ULONG nNumColors,i; 2012 USHORT *lpIndex; 2013 HPALETTE hpal; 2014 2015 if (!(ppalDc->flFlags & PAL_INDEXED)) 2016 { 2017 return NULL; 2018 } 2019 2020 nNumColors = 1 << lpbmi->bmiHeader.biBitCount; 2021 if (lpbmi->bmiHeader.biClrUsed) 2022 { 2023 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed); 2024 } 2025 2026 ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0); 2027 if (ppalNew == NULL) 2028 { 2029 DPRINT1("Could not allocate palette\n"); 2030 return NULL; 2031 } 2032 2033 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize); 2034 2035 for (i = 0; i < nNumColors; i++) 2036 { 2037 ULONG iColorIndex = *lpIndex % ppalDc->NumColors; 2038 ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex]; 2039 lpIndex++; 2040 } 2041 2042 hpal = ppalNew->BaseObject.hHmgr; 2043 PALETTE_UnlockPalette(ppalNew); 2044 2045 return hpal; 2046 } 2047 2048 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure, 2049 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */ 2050 BITMAPINFO* 2051 FASTCALL 2052 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage) 2053 { 2054 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi; 2055 BITMAPINFO* pNewBmi ; 2056 UINT numColors = 0, ColorsSize = 0; 2057 2058 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi; 2059 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL; 2060 2061 if(pbmci->bmciHeader.bcBitCount <= 8) 2062 { 2063 numColors = 1 << pbmci->bmciHeader.bcBitCount; 2064 if(Usage == DIB_PAL_COLORS) 2065 { 2066 ColorsSize = numColors * sizeof(WORD); 2067 } 2068 else 2069 { 2070 ColorsSize = numColors * sizeof(RGBQUAD); 2071 } 2072 } 2073 else if (Usage == DIB_PAL_COLORS) 2074 { 2075 /* Invalid at high-res */ 2076 return NULL; 2077 } 2078 2079 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB); 2080 if(!pNewBmi) return NULL; 2081 2082 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize); 2083 2084 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 2085 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount; 2086 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth; 2087 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight; 2088 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes; 2089 pNewBmi->bmiHeader.biCompression = BI_RGB ; 2090 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth, 2091 pNewBmi->bmiHeader.biHeight, 2092 pNewBmi->bmiHeader.biBitCount); 2093 pNewBmi->bmiHeader.biClrUsed = numColors; 2094 2095 if(Usage == DIB_PAL_COLORS) 2096 { 2097 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize); 2098 } 2099 else 2100 { 2101 UINT i; 2102 for(i=0; i<numColors; i++) 2103 { 2104 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed; 2105 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen; 2106 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue; 2107 } 2108 } 2109 2110 return pNewBmi ; 2111 } 2112 2113 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */ 2114 VOID 2115 FASTCALL 2116 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage) 2117 { 2118 BITMAPCOREINFO* pbmci; 2119 if(converted == orig) 2120 return; 2121 2122 if(usage == -1) 2123 { 2124 /* Caller don't want any conversion */ 2125 ExFreePoolWithTag(converted, TAG_DIB); 2126 return; 2127 } 2128 2129 /* Perform inverse conversion */ 2130 pbmci = (BITMAPCOREINFO*)orig; 2131 2132 ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER)); 2133 pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount; 2134 pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth; 2135 pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight; 2136 pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes; 2137 2138 if(pbmci->bmciHeader.bcBitCount <= 8) 2139 { 2140 UINT numColors = converted->bmiHeader.biClrUsed; 2141 if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount; 2142 if(usage == DIB_PAL_COLORS) 2143 { 2144 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD)); 2145 RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD)); 2146 } 2147 else 2148 { 2149 UINT i; 2150 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE)); 2151 for(i=0; i<numColors; i++) 2152 { 2153 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed; 2154 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen; 2155 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue; 2156 } 2157 } 2158 } 2159 /* Now free it, it's not needed anymore */ 2160 ExFreePoolWithTag(converted, TAG_DIB); 2161 } 2162 2163 /* EOF */ 2164