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>
20 /* Check if we have the correct object type */
21 if (GDI_HANDLE_GET_TYPE(hbmp
) != GDILoObjType_LO_BITMAP_TYPE
)
23 DPRINT1("Incorrect type for hbmp: %p\n", hbmp
);
27 /// FIXME: this is a hack and doesn't handle a race condition properly.
28 /// It needs to be done in GDIOBJ_vSetObjectOwner atomically.
30 /* Check if we set public or none */
31 if ((ulOwner
== GDI_OBJ_HMGR_PUBLIC
) ||
32 (ulOwner
== GDI_OBJ_HMGR_NONE
))
34 /* Only allow this for owned objects */
35 if (GreGetObjectOwner(hbmp
) != GDI_OBJ_HMGR_POWNED
)
37 DPRINT1("Cannot change owner for non-powned hbmp\n");
42 return GreSetObjectOwner(hbmp
, ulOwner
);
54 LONG lDeltaDst
, lDeltaSrc
;
55 ULONG nWidth
, nHeight
, cBitsPixel
;
56 NT_ASSERT(psurf
->flags
& API_BITMAP
);
57 NT_ASSERT(psurf
->SurfObj
.iBitmapFormat
<= BMF_32BPP
);
59 nWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
60 nHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
61 cBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
64 pjDst
= psurf
->SurfObj
.pvScan0
;
66 lDeltaDst
= psurf
->SurfObj
.lDelta
;
67 lDeltaSrc
= WIDTH_BYTES_ALIGN16(nWidth
, cBitsPixel
);
68 NT_ASSERT(lDeltaSrc
<= abs(lDeltaDst
));
70 /* Make sure the buffer is large enough*/
71 if (cjBits
< (lDeltaSrc
* nHeight
))
77 memcpy(pjDst
, pjSrc
, lDeltaSrc
);
90 _In_ ULONG cjWidthBytes
,
93 _In_ ULONG cjSizeImage
,
94 _In_opt_ PVOID pvBits
,
99 PVOID pvCompressedBits
= NULL
;
102 if (iFormat
< BMF_1BPP
|| iFormat
> BMF_PNG
) return NULL
;
104 /* The infamous RLE hack */
105 if ((iFormat
== BMF_4RLE
) || (iFormat
== BMF_8RLE
))
107 pvCompressedBits
= pvBits
;
109 iFormat
= (iFormat
== BMF_4RLE
) ? BMF_4BPP
: BMF_8BPP
;
113 /* Allocate a surface */
114 psurf
= SURFACE_AllocSurface(STYPE_BITMAP
,
124 DPRINT1("SURFACE_AllocSurface failed.\n");
128 /* The infamous RLE hack */
129 if (pvCompressedBits
)
136 lDelta
= WIDTH_BYTES_ALIGN32(nWidth
, gajBitsPerFormat
[iFormat
]);
138 pvBits
= psurf
->SurfObj
.pvBits
;
139 DecompressBitmap(sizl
, pvCompressedBits
, pvBits
, lDelta
, iFormat
);
142 /* Get the handle for the bitmap */
143 hbmp
= (HBITMAP
)psurf
->SurfObj
.hsurf
;
145 /* Mark as API bitmap */
146 psurf
->flags
|= (flags
| API_BITMAP
);
148 /* Unlock the surface and return */
149 SURFACE_UnlockSurface(psurf
);
153 /* Creates a DDB surface,
154 * as in CreateCompatibleBitmap or CreateBitmap.
155 * Note that each scanline must be 32bit aligned!
163 _In_ ULONG cBitsPixel
,
164 _In_opt_ PVOID pvBits
)
166 /* Call the extended function */
167 return GreCreateBitmapEx(nWidth
,
170 BitmapFormat(cBitsPixel
* cPlanes
, BI_RGB
),
171 0, /* No bitmap flags */
174 DDB_SURFACE
/* DDB */);
184 IN OPTIONAL LPBYTE pUnsafeBits
)
187 ULONG cRealBpp
, cjWidthBytes
, iFormat
;
191 /* Calculate bitmap format and real bits per pixel. */
192 iFormat
= BitmapFormat(cBitsPixel
* cPlanes
, BI_RGB
);
193 cRealBpp
= gajBitsPerFormat
[iFormat
];
195 /* Calculate width and image size in bytes */
196 cjWidthBytes
= WIDTH_BYTES_ALIGN16(nWidth
, cRealBpp
);
197 cjSize
= (ULONGLONG
)cjWidthBytes
* nHeight
;
199 /* Check parameters (possible overflow of cjSize!) */
200 if ((iFormat
== 0) || (nWidth
<= 0) || (nWidth
>= 0x8000000) || (nHeight
<= 0) ||
201 (cBitsPixel
> 32) || (cPlanes
> 32) || (cjSize
>= 0x100000000ULL
))
203 DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n",
204 nWidth
, nHeight
, cBitsPixel
, cPlanes
);
205 EngSetLastError(ERROR_INVALID_PARAMETER
);
209 /* Allocate the surface (but don't set the bits) */
210 psurf
= SURFACE_AllocSurface(STYPE_BITMAP
,
220 DPRINT1("SURFACE_AllocSurface failed.\n");
224 /* Mark as API and DDB bitmap */
225 psurf
->flags
|= (API_BITMAP
| DDB_SURFACE
);
227 /* Check if we have bits to set */
230 /* Protect with SEH and copy the bits */
233 ProbeForRead(pUnsafeBits
, (SIZE_T
)cjSize
, 1);
234 UnsafeSetBitmapBits(psurf
, cjSize
, pUnsafeBits
);
236 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
238 GDIOBJ_vDeleteObject(&psurf
->BaseObject
);
239 _SEH2_YIELD(return NULL
;)
246 RtlZeroMemory(psurf
->SurfObj
.pvBits
, psurf
->SurfObj
.cjBits
);
249 /* Get the handle for the bitmap */
250 hbmp
= (HBITMAP
)psurf
->SurfObj
.hsurf
;
252 /* Unlock the surface */
253 SURFACE_UnlockSurface(psurf
);
260 IntCreateCompatibleBitmap(
270 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
271 if (0 == Width
|| 0 == Height
)
273 return NtGdiGetStockObject(DEFAULT_BITMAP
);
276 if (Dc
->dctype
!= DC_TYPE_MEMORY
)
280 Bmp
= GreCreateBitmap(abs(Width
),
283 Bpp
? Bpp
: Dc
->ppdev
->gdiinfo
.cBitsPixel
,
287 DPRINT1("Failed to allocate a bitmap!\n");
291 psurf
= SURFACE_ShareLockSurface(Bmp
);
294 /* Dereference old palette and set new palette */
295 ppal
= PALETTE_ShareLockPalette(Dc
->ppdev
->devinfo
.hpalDefault
);
297 SURFACE_vSetPalette(psurf
, ppal
);
298 PALETTE_ShareUnlockPalette(ppal
);
301 psurf
->flags
= API_BITMAP
;
302 psurf
->hdc
= NULL
; // FIXME:
303 psurf
->SurfObj
.hdev
= (HDEV
)Dc
->ppdev
;
304 SURFACE_ShareUnlockSurface(psurf
);
310 PSURFACE psurf
= Dc
->dclevel
.pSurface
;
311 if(!psurf
) psurf
= psurfDefaultBitmap
;
312 Count
= BITMAP_GetObject(psurf
, sizeof(dibs
), &dibs
);
314 if (Count
== sizeof(BITMAP
))
318 Bmp
= GreCreateBitmap(abs(Width
),
321 Bpp
? Bpp
: dibs
.dsBm
.bmBitsPixel
,
323 psurfBmp
= SURFACE_ShareLockSurface(Bmp
);
326 /* Dereference old palette and set new palette */
327 SURFACE_vSetPalette(psurfBmp
, psurf
->ppal
);
330 psurfBmp
->flags
= API_BITMAP
;
331 psurfBmp
->hdc
= NULL
; // FIXME:
332 psurf
->SurfObj
.hdev
= (HDEV
)Dc
->ppdev
;
333 SURFACE_ShareUnlockSurface(psurfBmp
);
335 else if (Count
== sizeof(DIBSECTION
))
337 /* A DIB section is selected in the DC */
338 BYTE buf
[sizeof(BITMAPINFOHEADER
) + 256*sizeof(RGBQUAD
)] = {0};
340 BITMAPINFO
* bi
= (BITMAPINFO
*)buf
;
342 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
343 bi
->bmiHeader
.biWidth
= Width
;
344 bi
->bmiHeader
.biHeight
= Height
;
345 bi
->bmiHeader
.biPlanes
= Planes
? Planes
: dibs
.dsBmih
.biPlanes
;
346 bi
->bmiHeader
.biBitCount
= Bpp
? Bpp
: dibs
.dsBmih
.biBitCount
;
347 bi
->bmiHeader
.biCompression
= dibs
.dsBmih
.biCompression
;
348 bi
->bmiHeader
.biSizeImage
= 0;
349 bi
->bmiHeader
.biXPelsPerMeter
= dibs
.dsBmih
.biXPelsPerMeter
;
350 bi
->bmiHeader
.biYPelsPerMeter
= dibs
.dsBmih
.biYPelsPerMeter
;
351 bi
->bmiHeader
.biClrUsed
= dibs
.dsBmih
.biClrUsed
;
352 bi
->bmiHeader
.biClrImportant
= dibs
.dsBmih
.biClrImportant
;
354 if (bi
->bmiHeader
.biCompression
== BI_BITFIELDS
)
356 /* Copy the color masks */
357 RtlCopyMemory(bi
->bmiColors
, dibs
.dsBitfields
, 3*sizeof(RGBQUAD
));
359 else if (bi
->bmiHeader
.biBitCount
<= 8)
361 /* Copy the color table */
367 EngSetLastError(ERROR_INVALID_HANDLE
);
371 PalGDI
= psurf
->ppal
;
374 Index
< 256 && Index
< PalGDI
->NumColors
;
377 bi
->bmiColors
[Index
].rgbRed
= PalGDI
->IndexedColors
[Index
].peRed
;
378 bi
->bmiColors
[Index
].rgbGreen
= PalGDI
->IndexedColors
[Index
].peGreen
;
379 bi
->bmiColors
[Index
].rgbBlue
= PalGDI
->IndexedColors
[Index
].peBlue
;
380 bi
->bmiColors
[Index
].rgbReserved
= 0;
384 Bmp
= DIB_CreateDIBSection(Dc
,
398 NtGdiCreateCompatibleBitmap(
406 /* Check parameters */
407 if ((Width
<= 0) || (Height
<= 0) || ((Width
* Height
) > 0x3FFFFFFF))
409 EngSetLastError(ERROR_INVALID_PARAMETER
);
414 return GreCreateBitmap(Width
, Height
, 1, 1, 0);
418 DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
419 hDC
, Width
, Height
, Dc
->ppdev
->gdiinfo
.cBitsPixel
);
423 EngSetLastError(ERROR_INVALID_HANDLE
);
427 Bmp
= IntCreateCompatibleBitmap(Dc
, Width
, Height
, 0, 0);
435 NtGdiGetBitmapDimension(
445 /* Lock the bitmap */
446 psurfBmp
= SURFACE_ShareLockSurface(hBitmap
);
447 if (psurfBmp
== NULL
)
449 EngSetLastError(ERROR_INVALID_HANDLE
);
453 /* Use SEH to copy the data to the caller */
456 ProbeForWrite(psizDim
, sizeof(SIZE
), 1);
457 *psizDim
= psurfBmp
->sizlDim
;
459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
465 /* Unlock the bitmap */
466 SURFACE_ShareUnlockSurface(psurfBmp
);
480 LONG lDeltaDst
, lDeltaSrc
;
481 ULONG nWidth
, nHeight
, cBitsPixel
;
483 nWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
484 nHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
485 cBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
488 pjSrc
= psurf
->SurfObj
.pvScan0
;
490 lDeltaSrc
= psurf
->SurfObj
.lDelta
;
491 lDeltaDst
= WIDTH_BYTES_ALIGN16(nWidth
, cBitsPixel
);
496 RtlCopyMemory(pjDst
, pjSrc
, lDeltaDst
);
507 OUT OPTIONAL PBYTE pUnsafeBits
)
513 /* Check parameters */
514 if (pUnsafeBits
!= NULL
&& cjBuffer
== 0)
519 /* Lock the bitmap */
520 psurf
= SURFACE_ShareLockSurface(hBitmap
);
523 EngSetLastError(ERROR_INVALID_HANDLE
);
527 /* Calculate the size of the bitmap in bytes */
528 cjSize
= WIDTH_BYTES_ALIGN16(psurf
->SurfObj
.sizlBitmap
.cx
,
529 BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
)) *
530 abs(psurf
->SurfObj
.sizlBitmap
.cy
);
532 /* If the bits vector is null, the function should return the read size */
533 if (pUnsafeBits
== NULL
)
535 SURFACE_ShareUnlockSurface(psurf
);
539 /* Don't copy more bytes than the buffer has */
540 cjBuffer
= min(cjBuffer
, cjSize
);
542 // FIXME: Use MmSecureVirtualMemory
545 ProbeForWrite(pUnsafeBits
, cjBuffer
, 1);
546 UnsafeGetBitmapBits(psurf
, cjBuffer
, pUnsafeBits
);
549 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
555 SURFACE_ShareUnlockSurface(psurf
);
565 IN PBYTE pUnsafeBits
)
570 if (pUnsafeBits
== NULL
|| Bytes
== 0)
575 if (GDI_HANDLE_IS_STOCKOBJ(hBitmap
))
580 psurf
= SURFACE_ShareLockSurface(hBitmap
);
583 EngSetLastError(ERROR_INVALID_HANDLE
);
587 if (((psurf
->flags
& API_BITMAP
) == 0) ||
588 (psurf
->SurfObj
.iBitmapFormat
> BMF_32BPP
))
590 DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
591 psurf
->SurfObj
.iBitmapFormat
,
593 EngSetLastError(ERROR_INVALID_HANDLE
);
594 SURFACE_ShareUnlockSurface(psurf
);
600 ProbeForRead(pUnsafeBits
, Bytes
, sizeof(WORD
));
601 ret
= UnsafeSetBitmapBits(psurf
, Bytes
, pUnsafeBits
);
603 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
609 SURFACE_ShareUnlockSurface(psurf
);
615 NtGdiSetBitmapDimension(
627 psurf
= SURFACE_ShareLockSurface(hBitmap
);
630 EngSetLastError(ERROR_INVALID_HANDLE
);
638 ProbeForWrite(Size
, sizeof(SIZE
), 1);
639 *Size
= psurf
->sizlDim
;
641 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
648 /* The dimension is changed even if writing the old value failed */
649 psurf
->sizlDim
.cx
= Width
;
650 psurf
->sizlDim
.cy
= Height
;
652 SURFACE_ShareUnlockSurface(psurf
);
657 /* Internal Functions */
661 BITMAP_CopyBitmap(HBITMAP hBitmap
)
664 SURFACE
*psurfSrc
, *psurfNew
;
666 /* Fail, if no source bitmap is given */
667 if (hBitmap
== NULL
) return 0;
669 /* Lock the source bitmap */
670 psurfSrc
= SURFACE_ShareLockSurface(hBitmap
);
671 if (psurfSrc
== NULL
)
676 /* Allocate a new bitmap with the same dimensions as the source bmp */
677 hbmNew
= GreCreateBitmapEx(psurfSrc
->SurfObj
.sizlBitmap
.cx
,
678 psurfSrc
->SurfObj
.sizlBitmap
.cy
,
679 abs(psurfSrc
->SurfObj
.lDelta
),
680 psurfSrc
->SurfObj
.iBitmapFormat
,
681 psurfSrc
->SurfObj
.fjBitmap
& BMF_TOPDOWN
,
682 psurfSrc
->SurfObj
.cjBits
,
688 /* Lock the new bitmap */
689 psurfNew
= SURFACE_ShareLockSurface(hbmNew
);
692 /* Copy the bitmap bits to the new bitmap buffer */
693 RtlCopyMemory(psurfNew
->SurfObj
.pvBits
,
694 psurfSrc
->SurfObj
.pvBits
,
695 psurfNew
->SurfObj
.cjBits
);
698 /* Reference the palette of the source bitmap and use it */
699 SURFACE_vSetPalette(psurfNew
, psurfSrc
->ppal
);
701 /* Unlock the new surface */
702 SURFACE_ShareUnlockSurface(psurfNew
);
706 /* Failed to lock the bitmap, shouldn't happen */
707 GreDeleteObject(hbmNew
);
712 /* Unlock the source bitmap and return the handle of the new bitmap */
713 SURFACE_ShareUnlockSurface(psurfSrc
);
718 BITMAP_GetObject(SURFACE
*psurf
, INT Count
, LPVOID buffer
)
722 if (!buffer
) return sizeof(BITMAP
);
723 if ((UINT
)Count
< sizeof(BITMAP
)) return 0;
725 /* Always fill a basic BITMAP structure */
728 pBitmap
->bmWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
729 pBitmap
->bmHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
730 pBitmap
->bmPlanes
= 1;
731 pBitmap
->bmBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
732 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN16(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
734 /* Check for DIB section */
737 /* Set bmBits in this case */
738 pBitmap
->bmBits
= psurf
->SurfObj
.pvBits
;
739 /* DIBs data are 32 bits aligned */
740 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN32(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
742 if (Count
>= sizeof(DIBSECTION
))
744 /* Fill rest of DIBSECTION */
745 PDIBSECTION pds
= buffer
;
747 pds
->dsBmih
.biSize
= sizeof(BITMAPINFOHEADER
);
748 pds
->dsBmih
.biWidth
= pds
->dsBm
.bmWidth
;
749 pds
->dsBmih
.biHeight
= pds
->dsBm
.bmHeight
;
750 pds
->dsBmih
.biPlanes
= pds
->dsBm
.bmPlanes
;
751 pds
->dsBmih
.biBitCount
= pds
->dsBm
.bmBitsPixel
;
753 switch (psurf
->SurfObj
.iBitmapFormat
)
758 pds
->dsBmih
.biCompression
= BI_RGB
;
762 if (psurf
->ppal
->flFlags
& PAL_RGB16_555
)
763 pds
->dsBmih
.biCompression
= BI_RGB
;
765 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
770 /* 24/32bpp BI_RGB is actually BGR format */
771 if (psurf
->ppal
->flFlags
& PAL_BGR
)
772 pds
->dsBmih
.biCompression
= BI_RGB
;
774 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
778 pds
->dsBmih
.biCompression
= BI_RLE4
;
781 pds
->dsBmih
.biCompression
= BI_RLE8
;
784 pds
->dsBmih
.biCompression
= BI_JPEG
;
787 pds
->dsBmih
.biCompression
= BI_PNG
;
790 ASSERT(FALSE
); /* This shouldn't happen */
793 pds
->dsBmih
.biSizeImage
= psurf
->SurfObj
.cjBits
;
794 pds
->dsBmih
.biXPelsPerMeter
= 0;
795 pds
->dsBmih
.biYPelsPerMeter
= 0;
796 pds
->dsBmih
.biClrUsed
= psurf
->ppal
->NumColors
;
797 pds
->dsBmih
.biClrImportant
= psurf
->biClrImportant
;
798 pds
->dsBitfields
[0] = psurf
->ppal
->RedMask
;
799 pds
->dsBitfields
[1] = psurf
->ppal
->GreenMask
;
800 pds
->dsBitfields
[2] = psurf
->ppal
->BlueMask
;
801 pds
->dshSection
= psurf
->hDIBSection
;
802 pds
->dsOffset
= psurf
->dwOffset
;
804 return sizeof(DIBSECTION
);
809 /* Not set according to wine test, confirmed in win2k */
810 pBitmap
->bmBits
= NULL
;
813 return sizeof(BITMAP
);
825 PSURFACE psurf
= SURFACE_ShareLockSurface(hsurf
);
829 SURFACE_ShareUnlockSurface(psurf
);