2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Bitmap functions
5 * FILE: subsys/win32k/objects/bitmaps.c
6 * PROGRAMER: Timo Kreuzer <timo.kreuzer@reactos.org>
22 LONG lDeltaDst
, lDeltaSrc
;
23 ULONG nWidth
, nHeight
, cBitsPixel
;
25 nWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
26 nHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
27 cBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
30 pjDst
= psurf
->SurfObj
.pvScan0
;
32 lDeltaDst
= psurf
->SurfObj
.lDelta
;
33 lDeltaSrc
= WIDTH_BYTES_ALIGN16(nWidth
, cBitsPixel
);
38 memcpy(pjDst
, pjSrc
, lDeltaSrc
);
50 _In_ ULONG cjWidthBytes
,
53 _In_ ULONG cjSizeImage
,
54 _In_opt_ PVOID pvBits
,
59 PVOID pvCompressedBits
= NULL
;
62 if (iFormat
< BMF_1BPP
|| iFormat
> BMF_PNG
) return NULL
;
64 /* The infamous RLE hack */
65 if ((iFormat
== BMF_4RLE
) || (iFormat
== BMF_8RLE
))
67 pvCompressedBits
= pvBits
;
69 iFormat
= (iFormat
== BMF_4RLE
) ? BMF_4BPP
: BMF_8BPP
;
72 /* Allocate a surface */
73 psurf
= SURFACE_AllocSurface(STYPE_BITMAP
,
82 DPRINT1("SURFACE_AllocSurface failed.\n");
86 /* The infamous RLE hack */
94 lDelta
= WIDTH_BYTES_ALIGN32(nWidth
, gajBitsPerFormat
[iFormat
]);
96 pvBits
= psurf
->SurfObj
.pvBits
;
97 DecompressBitmap(sizl
, pvCompressedBits
, pvBits
, lDelta
, iFormat
);
100 /* Get the handle for the bitmap */
101 hbmp
= (HBITMAP
)psurf
->SurfObj
.hsurf
;
103 /* Mark as API bitmap */
104 psurf
->flags
|= (flags
| API_BITMAP
);
106 /* Unlock the surface and return */
107 SURFACE_UnlockSurface(psurf
);
111 /* Creates a DDB surface,
112 * as in CreateCompatibleBitmap or CreateBitmap.
113 * Note that each scanline must be 32bit aligned!
121 _In_ ULONG cBitsPixel
,
122 _In_opt_ PVOID pvBits
)
124 /* Call the extended function */
125 return GreCreateBitmapEx(nWidth
,
128 BitmapFormat(cBitsPixel
* cPlanes
, BI_RGB
),
129 0, /* No bitmap flags */
132 DDB_SURFACE
/* DDB */);
142 IN OPTIONAL LPBYTE pUnsafeBits
)
145 ULONG cRealBpp
, cjWidthBytes
, iFormat
, fjBitmap
;
149 /* Calculate bitmap format and real bits per pixel. */
150 iFormat
= BitmapFormat(cBitsPixel
* cPlanes
, BI_RGB
);
151 cRealBpp
= gajBitsPerFormat
[iFormat
];
153 /* Calculate width and image size in bytes */
154 cjWidthBytes
= WIDTH_BYTES_ALIGN16(nWidth
, cRealBpp
);
155 cjSize
= (ULONGLONG
)cjWidthBytes
* nHeight
;
157 /* Check parameters (possible overflow of cjSize!) */
158 if ((iFormat
== 0) || (nWidth
<= 0) || (nWidth
>= 0x8000000) || (nHeight
<= 0) ||
159 (cBitsPixel
> 32) || (cPlanes
> 32) || (cjSize
>= 0x100000000ULL
))
161 DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n",
162 nWidth
, nHeight
, cBitsPixel
, cPlanes
);
163 EngSetLastError(ERROR_INVALID_PARAMETER
);
167 /* Allocations larger than PAGE_SIZE go into user mem */
168 fjBitmap
= (cjSize
> PAGE_SIZE
) ? BMF_USERMEM
: 0;
170 /* Allocate the surface (but don't set the bits) */
171 psurf
= SURFACE_AllocSurface(STYPE_BITMAP
,
180 DPRINT1("SURFACE_AllocSurface failed.\n");
184 /* Mark as API and DDB bitmap */
185 psurf
->flags
|= (API_BITMAP
| DDB_SURFACE
);
187 /* Check if we have bits to set */
190 /* Protect with SEH and copy the bits */
193 ProbeForRead(pUnsafeBits
, (SIZE_T
)cjSize
, 1);
194 UnsafeSetBitmapBits(psurf
, 0, pUnsafeBits
);
196 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
198 GDIOBJ_vDeleteObject(&psurf
->BaseObject
);
199 _SEH2_YIELD(return NULL
;)
206 RtlZeroMemory(psurf
->SurfObj
.pvBits
, psurf
->SurfObj
.cjBits
);
209 /* Get the handle for the bitmap */
210 hbmp
= (HBITMAP
)psurf
->SurfObj
.hsurf
;
212 /* Unlock the surface */
213 SURFACE_UnlockSurface(psurf
);
220 IntCreateCompatibleBitmap(
228 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
229 if (0 == Width
|| 0 == Height
)
231 return NtGdiGetStockObject(DEFAULT_BITMAP
);
234 if (Dc
->dctype
!= DC_TYPE_MEMORY
)
238 Bmp
= GreCreateBitmap(abs(Width
),
241 Dc
->ppdev
->gdiinfo
.cBitsPixel
,
243 psurf
= SURFACE_ShareLockSurface(Bmp
);
246 /* Dereference old palette and set new palette */
247 ppal
= PALETTE_ShareLockPalette(Dc
->ppdev
->devinfo
.hpalDefault
);
249 SURFACE_vSetPalette(psurf
, ppal
);
250 PALETTE_ShareUnlockPalette(ppal
);
253 psurf
->flags
= API_BITMAP
;
254 psurf
->hdc
= NULL
; // FIXME:
255 SURFACE_ShareUnlockSurface(psurf
);
261 PSURFACE psurf
= Dc
->dclevel
.pSurface
;
262 if(!psurf
) psurf
= psurfDefaultBitmap
;
263 Count
= BITMAP_GetObject(psurf
, sizeof(dibs
), &dibs
);
265 if (Count
== sizeof(BITMAP
))
269 Bmp
= GreCreateBitmap(abs(Width
),
272 dibs
.dsBm
.bmBitsPixel
,
274 psurfBmp
= SURFACE_ShareLockSurface(Bmp
);
277 /* Dereference old palette and set new palette */
278 SURFACE_vSetPalette(psurfBmp
, psurf
->ppal
);
281 psurfBmp
->flags
= API_BITMAP
;
282 psurfBmp
->hdc
= NULL
; // FIXME:
283 SURFACE_ShareUnlockSurface(psurfBmp
);
285 else if (Count
== sizeof(DIBSECTION
))
287 /* A DIB section is selected in the DC */
288 BYTE buf
[sizeof(BITMAPINFOHEADER
) + 256*sizeof(RGBQUAD
)] = {0};
290 BITMAPINFO
* bi
= (BITMAPINFO
*)buf
;
292 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
293 bi
->bmiHeader
.biWidth
= Width
;
294 bi
->bmiHeader
.biHeight
= Height
;
295 bi
->bmiHeader
.biPlanes
= dibs
.dsBmih
.biPlanes
;
296 bi
->bmiHeader
.biBitCount
= dibs
.dsBmih
.biBitCount
;
297 bi
->bmiHeader
.biCompression
= dibs
.dsBmih
.biCompression
;
298 bi
->bmiHeader
.biSizeImage
= 0;
299 bi
->bmiHeader
.biXPelsPerMeter
= dibs
.dsBmih
.biXPelsPerMeter
;
300 bi
->bmiHeader
.biYPelsPerMeter
= dibs
.dsBmih
.biYPelsPerMeter
;
301 bi
->bmiHeader
.biClrUsed
= dibs
.dsBmih
.biClrUsed
;
302 bi
->bmiHeader
.biClrImportant
= dibs
.dsBmih
.biClrImportant
;
304 if (bi
->bmiHeader
.biCompression
== BI_BITFIELDS
)
306 /* Copy the color masks */
307 RtlCopyMemory(bi
->bmiColors
, dibs
.dsBitfields
, 3*sizeof(RGBQUAD
));
309 else if (bi
->bmiHeader
.biBitCount
<= 8)
311 /* Copy the color table */
317 EngSetLastError(ERROR_INVALID_HANDLE
);
321 PalGDI
= psurf
->ppal
;
324 Index
< 256 && Index
< PalGDI
->NumColors
;
327 bi
->bmiColors
[Index
].rgbRed
= PalGDI
->IndexedColors
[Index
].peRed
;
328 bi
->bmiColors
[Index
].rgbGreen
= PalGDI
->IndexedColors
[Index
].peGreen
;
329 bi
->bmiColors
[Index
].rgbBlue
= PalGDI
->IndexedColors
[Index
].peBlue
;
330 bi
->bmiColors
[Index
].rgbReserved
= 0;
334 Bmp
= DIB_CreateDIBSection(Dc
,
348 NtGdiCreateCompatibleBitmap(
356 /* Check parameters */
357 if ((Width
<= 0) || (Height
<= 0) || ((Width
* Height
) > 0x3FFFFFFF))
359 EngSetLastError(ERROR_INVALID_PARAMETER
);
364 return GreCreateBitmap(Width
, Height
, 1, 1, 0);
368 DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
369 hDC
, Width
, Height
, Dc
->ppdev
->gdiinfo
.cBitsPixel
);
373 EngSetLastError(ERROR_INVALID_HANDLE
);
377 Bmp
= IntCreateCompatibleBitmap(Dc
, Width
, Height
);
385 NtGdiGetBitmapDimension(
395 /* Lock the bitmap */
396 psurfBmp
= SURFACE_ShareLockSurface(hBitmap
);
397 if (psurfBmp
== NULL
)
399 EngSetLastError(ERROR_INVALID_HANDLE
);
403 /* Use SEH to copy the data to the caller */
406 ProbeForWrite(psizDim
, sizeof(SIZE
), 1);
407 *psizDim
= psurfBmp
->sizlDim
;
409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
415 /* Unlock the bitmap */
416 SURFACE_ShareUnlockSurface(psurfBmp
);
430 LONG lDeltaDst
, lDeltaSrc
;
431 ULONG nWidth
, nHeight
, cBitsPixel
;
433 nWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
434 nHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
435 cBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
438 pjSrc
= psurf
->SurfObj
.pvScan0
;
440 lDeltaSrc
= psurf
->SurfObj
.lDelta
;
441 lDeltaDst
= WIDTH_BYTES_ALIGN16(nWidth
, cBitsPixel
);
446 RtlCopyMemory(pjDst
, pjSrc
, lDeltaDst
);
457 OUT OPTIONAL PBYTE pUnsafeBits
)
463 /* Check parameters */
464 if (pUnsafeBits
!= NULL
&& cjBuffer
== 0)
469 /* Lock the bitmap */
470 psurf
= SURFACE_ShareLockSurface(hBitmap
);
473 EngSetLastError(ERROR_INVALID_HANDLE
);
477 /* Calculate the size of the bitmap in bytes */
478 cjSize
= WIDTH_BYTES_ALIGN16(psurf
->SurfObj
.sizlBitmap
.cx
,
479 BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
)) *
480 abs(psurf
->SurfObj
.sizlBitmap
.cy
);
482 /* If the bits vector is null, the function should return the read size */
483 if (pUnsafeBits
== NULL
)
485 SURFACE_ShareUnlockSurface(psurf
);
489 /* Don't copy more bytes than the buffer has */
490 cjBuffer
= min(cjBuffer
, cjSize
);
492 // FIXME: Use MmSecureVirtualMemory
495 ProbeForWrite(pUnsafeBits
, cjBuffer
, 1);
496 UnsafeGetBitmapBits(psurf
, cjBuffer
, pUnsafeBits
);
499 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
505 SURFACE_ShareUnlockSurface(psurf
);
515 IN PBYTE pUnsafeBits
)
520 if (pUnsafeBits
== NULL
|| Bytes
== 0)
525 psurf
= SURFACE_ShareLockSurface(hBitmap
);
528 EngSetLastError(ERROR_INVALID_HANDLE
);
534 ProbeForRead(pUnsafeBits
, Bytes
, 1);
535 UnsafeSetBitmapBits(psurf
, Bytes
, pUnsafeBits
);
538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
544 SURFACE_ShareUnlockSurface(psurf
);
550 NtGdiSetBitmapDimension(
562 psurf
= SURFACE_ShareLockSurface(hBitmap
);
565 EngSetLastError(ERROR_INVALID_HANDLE
);
573 ProbeForWrite(Size
, sizeof(SIZE
), 1);
574 *Size
= psurf
->sizlDim
;
576 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
583 /* The dimension is changed even if writing the old value failed */
584 psurf
->sizlDim
.cx
= Width
;
585 psurf
->sizlDim
.cy
= Height
;
587 SURFACE_ShareUnlockSurface(psurf
);
592 /* Internal Functions */
596 BITMAP_CopyBitmap(HBITMAP hBitmap
)
599 SURFACE
*psurfSrc
, *psurfNew
;
601 /* Fail, if no source bitmap is given */
602 if (hBitmap
== NULL
) return 0;
604 /* Lock the source bitmap */
605 psurfSrc
= SURFACE_ShareLockSurface(hBitmap
);
606 if (psurfSrc
== NULL
)
611 /* Allocate a new bitmap with the same dimensions as the source bmp */
612 hbmNew
= GreCreateBitmapEx(psurfSrc
->SurfObj
.sizlBitmap
.cx
,
613 psurfSrc
->SurfObj
.sizlBitmap
.cy
,
614 abs(psurfSrc
->SurfObj
.lDelta
),
615 psurfSrc
->SurfObj
.iBitmapFormat
,
616 psurfSrc
->SurfObj
.fjBitmap
& BMF_TOPDOWN
,
617 psurfSrc
->SurfObj
.cjBits
,
623 /* Lock the new bitmap */
624 psurfNew
= SURFACE_ShareLockSurface(hbmNew
);
627 /* Copy the bitmap bits to the new bitmap buffer */
628 RtlCopyMemory(psurfNew
->SurfObj
.pvBits
,
629 psurfSrc
->SurfObj
.pvBits
,
630 psurfNew
->SurfObj
.cjBits
);
633 /* Reference the palette of the source bitmap and use it */
634 SURFACE_vSetPalette(psurfNew
, psurfSrc
->ppal
);
636 /* Unlock the new surface */
637 SURFACE_ShareUnlockSurface(psurfNew
);
641 /* Failed to lock the bitmap, shouldn't happen */
642 GreDeleteObject(hbmNew
);
647 /* Unlock the source bitmap and return the handle of the new bitmap */
648 SURFACE_ShareUnlockSurface(psurfSrc
);
653 BITMAP_GetObject(SURFACE
*psurf
, INT Count
, LPVOID buffer
)
657 if (!buffer
) return sizeof(BITMAP
);
658 if ((UINT
)Count
< sizeof(BITMAP
)) return 0;
660 /* Always fill a basic BITMAP structure */
663 pBitmap
->bmWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
664 pBitmap
->bmHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
665 pBitmap
->bmPlanes
= 1;
666 pBitmap
->bmBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
667 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN16(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
669 /* Check for DIB section */
672 /* Set bmBits in this case */
673 pBitmap
->bmBits
= psurf
->SurfObj
.pvBits
;
674 /* DIBs data are 32 bits aligned */
675 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN32(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
677 if (Count
>= sizeof(DIBSECTION
))
679 /* Fill rest of DIBSECTION */
680 PDIBSECTION pds
= buffer
;
682 pds
->dsBmih
.biSize
= sizeof(BITMAPINFOHEADER
);
683 pds
->dsBmih
.biWidth
= pds
->dsBm
.bmWidth
;
684 pds
->dsBmih
.biHeight
= pds
->dsBm
.bmHeight
;
685 pds
->dsBmih
.biPlanes
= pds
->dsBm
.bmPlanes
;
686 pds
->dsBmih
.biBitCount
= pds
->dsBm
.bmBitsPixel
;
688 switch (psurf
->SurfObj
.iBitmapFormat
)
693 pds
->dsBmih
.biCompression
= BI_RGB
;
697 if (psurf
->ppal
->flFlags
& PAL_RGB16_555
)
698 pds
->dsBmih
.biCompression
= BI_RGB
;
700 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
705 /* 24/32bpp BI_RGB is actually BGR format */
706 if (psurf
->ppal
->flFlags
& PAL_BGR
)
707 pds
->dsBmih
.biCompression
= BI_RGB
;
709 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
713 pds
->dsBmih
.biCompression
= BI_RLE4
;
716 pds
->dsBmih
.biCompression
= BI_RLE8
;
719 pds
->dsBmih
.biCompression
= BI_JPEG
;
722 pds
->dsBmih
.biCompression
= BI_PNG
;
725 ASSERT(FALSE
); /* This shouldn't happen */
728 pds
->dsBmih
.biSizeImage
= psurf
->SurfObj
.cjBits
;
729 pds
->dsBmih
.biXPelsPerMeter
= 0;
730 pds
->dsBmih
.biYPelsPerMeter
= 0;
731 pds
->dsBmih
.biClrUsed
= psurf
->ppal
->NumColors
;
732 pds
->dsBmih
.biClrImportant
= psurf
->biClrImportant
;
733 pds
->dsBitfields
[0] = psurf
->ppal
->RedMask
;
734 pds
->dsBitfields
[1] = psurf
->ppal
->GreenMask
;
735 pds
->dsBitfields
[2] = psurf
->ppal
->BlueMask
;
736 pds
->dshSection
= psurf
->hDIBSection
;
737 pds
->dsOffset
= psurf
->dwOffset
;
739 return sizeof(DIBSECTION
);
744 /* Not set according to wine test, confirmed in win2k */
745 pBitmap
->bmBits
= NULL
;
748 return sizeof(BITMAP
);
760 PSURFACE psurf
= SURFACE_ShareLockSurface(hsurf
);
764 SURFACE_ShareUnlockSurface(psurf
);