2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Bitmap functions
5 * FILE: win32ss/gdi/ntgdi/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
);
48 _Inout_ PSURFACE psurf
,
50 _In_
const VOID
*pvBits
)
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
;
112 /* Allocate a surface */
113 psurf
= SURFACE_AllocSurface(STYPE_BITMAP
,
119 pvCompressedBits
? 0 : cjSizeImage
,
123 DPRINT1("SURFACE_AllocSurface failed.\n");
127 /* The infamous RLE hack */
128 if (pvCompressedBits
)
135 lDelta
= WIDTH_BYTES_ALIGN32(nWidth
, gajBitsPerFormat
[iFormat
]);
137 pvBits
= psurf
->SurfObj
.pvBits
;
138 DecompressBitmap(sizl
, pvCompressedBits
, pvBits
, lDelta
, iFormat
, cjSizeImage
);
141 /* Get the handle for the bitmap */
142 hbmp
= (HBITMAP
)psurf
->SurfObj
.hsurf
;
144 /* Mark as API bitmap */
145 psurf
->flags
|= (flags
| API_BITMAP
);
147 /* Unlock the surface and return */
148 SURFACE_UnlockSurface(psurf
);
152 /* Creates a DDB surface,
153 * as in CreateCompatibleBitmap or CreateBitmap.
154 * Note that each scanline must be 32bit aligned!
162 _In_ ULONG cBitsPixel
,
163 _In_opt_ PVOID pvBits
)
165 /* Call the extended function */
166 return GreCreateBitmapEx(nWidth
,
169 BitmapFormat(cBitsPixel
* cPlanes
, BI_RGB
),
170 0, /* No bitmap flags */
173 DDB_SURFACE
/* DDB */);
183 IN OPTIONAL LPBYTE pUnsafeBits
)
186 ULONG cRealBpp
, cjWidthBytes
, iFormat
;
190 /* Calculate bitmap format and real bits per pixel. */
191 iFormat
= BitmapFormat(cBitsPixel
* cPlanes
, BI_RGB
);
192 cRealBpp
= gajBitsPerFormat
[iFormat
];
194 /* Calculate width and image size in bytes */
195 cjWidthBytes
= WIDTH_BYTES_ALIGN16(nWidth
, cRealBpp
);
196 cjSize
= (ULONGLONG
)cjWidthBytes
* nHeight
;
198 /* Check parameters (possible overflow of cjSize!) */
199 if ((iFormat
== 0) || (nWidth
<= 0) || (nWidth
>= 0x8000000) || (nHeight
<= 0) ||
200 (cBitsPixel
> 32) || (cPlanes
> 32) || (cjSize
>= 0x100000000ULL
))
202 DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n",
203 nWidth
, nHeight
, cBitsPixel
, cPlanes
);
204 EngSetLastError(ERROR_INVALID_PARAMETER
);
208 /* Allocate the surface (but don't set the bits) */
209 psurf
= SURFACE_AllocSurface(STYPE_BITMAP
,
219 DPRINT1("SURFACE_AllocSurface failed.\n");
223 /* Mark as API and DDB bitmap */
224 psurf
->flags
|= (API_BITMAP
| DDB_SURFACE
);
226 /* Check if we have bits to set */
229 /* Protect with SEH and copy the bits */
232 ProbeForRead(pUnsafeBits
, (SIZE_T
)cjSize
, 1);
233 UnsafeSetBitmapBits(psurf
, cjSize
, pUnsafeBits
);
235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
237 GDIOBJ_vDeleteObject(&psurf
->BaseObject
);
238 _SEH2_YIELD(return NULL
;)
245 RtlZeroMemory(psurf
->SurfObj
.pvBits
, psurf
->SurfObj
.cjBits
);
248 /* Get the handle for the bitmap */
249 hbmp
= (HBITMAP
)psurf
->SurfObj
.hsurf
;
251 /* Unlock the surface */
252 SURFACE_UnlockSurface(psurf
);
259 IntCreateCompatibleBitmap(
269 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
270 if (0 == Width
|| 0 == Height
)
272 return NtGdiGetStockObject(DEFAULT_BITMAP
);
275 if (Dc
->dctype
!= DC_TYPE_MEMORY
)
279 Bmp
= GreCreateBitmap(abs(Width
),
282 Bpp
? Bpp
: Dc
->ppdev
->gdiinfo
.cBitsPixel
,
286 DPRINT1("Failed to allocate a bitmap!\n");
290 psurf
= SURFACE_ShareLockSurface(Bmp
);
293 /* Dereference old palette and set new palette */
294 ppal
= PALETTE_ShareLockPalette(Dc
->ppdev
->devinfo
.hpalDefault
);
296 SURFACE_vSetPalette(psurf
, ppal
);
297 PALETTE_ShareUnlockPalette(ppal
);
300 psurf
->flags
= API_BITMAP
;
301 psurf
->hdc
= NULL
; // FIXME:
302 psurf
->SurfObj
.hdev
= (HDEV
)Dc
->ppdev
;
303 SURFACE_ShareUnlockSurface(psurf
);
309 PSURFACE psurf
= Dc
->dclevel
.pSurface
;
310 if(!psurf
) psurf
= psurfDefaultBitmap
;
311 Count
= BITMAP_GetObject(psurf
, sizeof(dibs
), &dibs
);
313 if (Count
== sizeof(BITMAP
))
317 Bmp
= GreCreateBitmap(abs(Width
),
320 Bpp
? Bpp
: dibs
.dsBm
.bmBitsPixel
,
322 psurfBmp
= SURFACE_ShareLockSurface(Bmp
);
325 /* Dereference old palette and set new palette */
326 SURFACE_vSetPalette(psurfBmp
, psurf
->ppal
);
329 psurfBmp
->flags
= API_BITMAP
;
330 psurfBmp
->hdc
= NULL
; // FIXME:
331 psurf
->SurfObj
.hdev
= (HDEV
)Dc
->ppdev
;
332 SURFACE_ShareUnlockSurface(psurfBmp
);
334 else if (Count
== sizeof(DIBSECTION
))
336 /* A DIB section is selected in the DC */
337 BYTE buf
[sizeof(BITMAPINFOHEADER
) + 256*sizeof(RGBQUAD
)] = {0};
339 BITMAPINFO
* bi
= (BITMAPINFO
*)buf
;
341 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
342 bi
->bmiHeader
.biWidth
= Width
;
343 bi
->bmiHeader
.biHeight
= Height
;
344 bi
->bmiHeader
.biPlanes
= Planes
? Planes
: dibs
.dsBmih
.biPlanes
;
345 bi
->bmiHeader
.biBitCount
= Bpp
? Bpp
: dibs
.dsBmih
.biBitCount
;
346 bi
->bmiHeader
.biCompression
= dibs
.dsBmih
.biCompression
;
347 bi
->bmiHeader
.biSizeImage
= 0;
348 bi
->bmiHeader
.biXPelsPerMeter
= dibs
.dsBmih
.biXPelsPerMeter
;
349 bi
->bmiHeader
.biYPelsPerMeter
= dibs
.dsBmih
.biYPelsPerMeter
;
350 bi
->bmiHeader
.biClrUsed
= dibs
.dsBmih
.biClrUsed
;
351 bi
->bmiHeader
.biClrImportant
= dibs
.dsBmih
.biClrImportant
;
353 if (bi
->bmiHeader
.biCompression
== BI_BITFIELDS
)
355 /* Copy the color masks */
356 RtlCopyMemory(bi
->bmiColors
, dibs
.dsBitfields
, 3*sizeof(RGBQUAD
));
358 else if (bi
->bmiHeader
.biBitCount
<= 8)
360 /* Copy the color table */
366 EngSetLastError(ERROR_INVALID_HANDLE
);
370 PalGDI
= psurf
->ppal
;
373 Index
< 256 && Index
< PalGDI
->NumColors
;
376 bi
->bmiColors
[Index
].rgbRed
= PalGDI
->IndexedColors
[Index
].peRed
;
377 bi
->bmiColors
[Index
].rgbGreen
= PalGDI
->IndexedColors
[Index
].peGreen
;
378 bi
->bmiColors
[Index
].rgbBlue
= PalGDI
->IndexedColors
[Index
].peBlue
;
379 bi
->bmiColors
[Index
].rgbReserved
= 0;
383 Bmp
= DIB_CreateDIBSection(Dc
,
397 NtGdiCreateCompatibleBitmap(
405 /* Check parameters */
406 if ((Width
<= 0) || (Height
<= 0) || ((Width
* Height
) > 0x3FFFFFFF))
408 EngSetLastError(ERROR_INVALID_PARAMETER
);
413 return GreCreateBitmap(Width
, Height
, 1, 1, 0);
417 DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
418 hDC
, Width
, Height
, Dc
->ppdev
->gdiinfo
.cBitsPixel
);
422 EngSetLastError(ERROR_INVALID_HANDLE
);
426 Bmp
= IntCreateCompatibleBitmap(Dc
, Width
, Height
, 0, 0);
434 NtGdiGetBitmapDimension(
444 /* Lock the bitmap */
445 psurfBmp
= SURFACE_ShareLockSurface(hBitmap
);
446 if (psurfBmp
== NULL
)
448 EngSetLastError(ERROR_INVALID_HANDLE
);
452 /* Use SEH to copy the data to the caller */
455 ProbeForWrite(psizDim
, sizeof(SIZE
), 1);
456 *psizDim
= psurfBmp
->sizlDim
;
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
464 /* Unlock the bitmap */
465 SURFACE_ShareUnlockSurface(psurfBmp
);
479 LONG lDeltaDst
, lDeltaSrc
;
480 ULONG nWidth
, nHeight
, cBitsPixel
;
482 nWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
483 nHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
484 cBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
487 pjSrc
= psurf
->SurfObj
.pvScan0
;
489 lDeltaSrc
= psurf
->SurfObj
.lDelta
;
490 lDeltaDst
= WIDTH_BYTES_ALIGN16(nWidth
, cBitsPixel
);
495 RtlCopyMemory(pjDst
, pjSrc
, lDeltaDst
);
506 OUT OPTIONAL PBYTE pUnsafeBits
)
512 /* Check parameters */
513 if (pUnsafeBits
!= NULL
&& cjBuffer
== 0)
518 /* Lock the bitmap */
519 psurf
= SURFACE_ShareLockSurface(hBitmap
);
522 EngSetLastError(ERROR_INVALID_HANDLE
);
526 /* Calculate the size of the bitmap in bytes */
527 cjSize
= WIDTH_BYTES_ALIGN16(psurf
->SurfObj
.sizlBitmap
.cx
,
528 BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
)) *
529 abs(psurf
->SurfObj
.sizlBitmap
.cy
);
531 /* If the bits vector is null, the function should return the read size */
532 if (pUnsafeBits
== NULL
)
534 SURFACE_ShareUnlockSurface(psurf
);
538 /* Don't copy more bytes than the buffer has */
539 cjBuffer
= min(cjBuffer
, cjSize
);
541 // FIXME: Use MmSecureVirtualMemory
544 ProbeForWrite(pUnsafeBits
, cjBuffer
, 1);
545 UnsafeGetBitmapBits(psurf
, cjBuffer
, pUnsafeBits
);
548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
554 SURFACE_ShareUnlockSurface(psurf
);
564 IN PBYTE pUnsafeBits
)
569 if (pUnsafeBits
== NULL
|| Bytes
== 0)
574 if (GDI_HANDLE_IS_STOCKOBJ(hBitmap
))
579 psurf
= SURFACE_ShareLockSurface(hBitmap
);
582 EngSetLastError(ERROR_INVALID_HANDLE
);
586 if (((psurf
->flags
& API_BITMAP
) == 0) ||
587 (psurf
->SurfObj
.iBitmapFormat
> BMF_32BPP
))
589 DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
590 psurf
->SurfObj
.iBitmapFormat
,
592 EngSetLastError(ERROR_INVALID_HANDLE
);
593 SURFACE_ShareUnlockSurface(psurf
);
599 ProbeForRead(pUnsafeBits
, Bytes
, sizeof(WORD
));
600 ret
= UnsafeSetBitmapBits(psurf
, Bytes
, pUnsafeBits
);
602 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
608 SURFACE_ShareUnlockSurface(psurf
);
614 NtGdiSetBitmapDimension(
626 psurf
= SURFACE_ShareLockSurface(hBitmap
);
629 EngSetLastError(ERROR_INVALID_HANDLE
);
637 ProbeForWrite(Size
, sizeof(SIZE
), 1);
638 *Size
= psurf
->sizlDim
;
640 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
647 /* The dimension is changed even if writing the old value failed */
648 psurf
->sizlDim
.cx
= Width
;
649 psurf
->sizlDim
.cy
= Height
;
651 SURFACE_ShareUnlockSurface(psurf
);
656 /* Internal Functions */
660 BITMAP_CopyBitmap(HBITMAP hBitmap
)
663 SURFACE
*psurfSrc
, *psurfNew
;
665 /* Fail, if no source bitmap is given */
666 if (hBitmap
== NULL
) return 0;
668 /* Lock the source bitmap */
669 psurfSrc
= SURFACE_ShareLockSurface(hBitmap
);
670 if (psurfSrc
== NULL
)
675 /* Allocate a new bitmap with the same dimensions as the source bmp */
676 hbmNew
= GreCreateBitmapEx(psurfSrc
->SurfObj
.sizlBitmap
.cx
,
677 psurfSrc
->SurfObj
.sizlBitmap
.cy
,
678 abs(psurfSrc
->SurfObj
.lDelta
),
679 psurfSrc
->SurfObj
.iBitmapFormat
,
680 psurfSrc
->SurfObj
.fjBitmap
& BMF_TOPDOWN
,
681 psurfSrc
->SurfObj
.cjBits
,
687 /* Lock the new bitmap */
688 psurfNew
= SURFACE_ShareLockSurface(hbmNew
);
691 /* Copy the bitmap bits to the new bitmap buffer */
692 RtlCopyMemory(psurfNew
->SurfObj
.pvBits
,
693 psurfSrc
->SurfObj
.pvBits
,
694 psurfNew
->SurfObj
.cjBits
);
697 /* Reference the palette of the source bitmap and use it */
698 SURFACE_vSetPalette(psurfNew
, psurfSrc
->ppal
);
700 /* Unlock the new surface */
701 SURFACE_ShareUnlockSurface(psurfNew
);
705 /* Failed to lock the bitmap, shouldn't happen */
706 GreDeleteObject(hbmNew
);
711 /* Unlock the source bitmap and return the handle of the new bitmap */
712 SURFACE_ShareUnlockSurface(psurfSrc
);
717 BITMAP_GetObject(SURFACE
*psurf
, INT Count
, LPVOID buffer
)
721 if (!buffer
) return sizeof(BITMAP
);
722 if ((UINT
)Count
< sizeof(BITMAP
)) return 0;
724 /* Always fill a basic BITMAP structure */
727 pBitmap
->bmWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
728 pBitmap
->bmHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
729 pBitmap
->bmPlanes
= 1;
730 pBitmap
->bmBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
731 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN16(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
733 /* Check for DIB section */
736 /* Set bmBits in this case */
737 pBitmap
->bmBits
= psurf
->SurfObj
.pvBits
;
738 /* DIBs data are 32 bits aligned */
739 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN32(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
741 if (Count
>= sizeof(DIBSECTION
))
743 /* Fill rest of DIBSECTION */
744 PDIBSECTION pds
= buffer
;
746 pds
->dsBmih
.biSize
= sizeof(BITMAPINFOHEADER
);
747 pds
->dsBmih
.biWidth
= pds
->dsBm
.bmWidth
;
748 pds
->dsBmih
.biHeight
= pds
->dsBm
.bmHeight
;
749 pds
->dsBmih
.biPlanes
= pds
->dsBm
.bmPlanes
;
750 pds
->dsBmih
.biBitCount
= pds
->dsBm
.bmBitsPixel
;
752 switch (psurf
->SurfObj
.iBitmapFormat
)
757 pds
->dsBmih
.biCompression
= BI_RGB
;
761 if (psurf
->ppal
->flFlags
& PAL_RGB16_555
)
762 pds
->dsBmih
.biCompression
= BI_RGB
;
764 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
769 /* 24/32bpp BI_RGB is actually BGR format */
770 if (psurf
->ppal
->flFlags
& PAL_BGR
)
771 pds
->dsBmih
.biCompression
= BI_RGB
;
773 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
777 pds
->dsBmih
.biCompression
= BI_RLE4
;
780 pds
->dsBmih
.biCompression
= BI_RLE8
;
783 pds
->dsBmih
.biCompression
= BI_JPEG
;
786 pds
->dsBmih
.biCompression
= BI_PNG
;
789 ASSERT(FALSE
); /* This shouldn't happen */
792 pds
->dsBmih
.biSizeImage
= psurf
->SurfObj
.cjBits
;
793 pds
->dsBmih
.biXPelsPerMeter
= 0;
794 pds
->dsBmih
.biYPelsPerMeter
= 0;
795 pds
->dsBmih
.biClrUsed
= psurf
->ppal
->NumColors
;
796 pds
->dsBmih
.biClrImportant
= psurf
->biClrImportant
;
797 pds
->dsBitfields
[0] = psurf
->ppal
->RedMask
;
798 pds
->dsBitfields
[1] = psurf
->ppal
->GreenMask
;
799 pds
->dsBitfields
[2] = psurf
->ppal
->BlueMask
;
800 pds
->dshSection
= psurf
->hDIBSection
;
801 pds
->dsOffset
= psurf
->dwOffset
;
803 return sizeof(DIBSECTION
);
808 /* Not set according to wine test, confirmed in win2k */
809 pBitmap
->bmBits
= NULL
;
812 return sizeof(BITMAP
);
824 PSURFACE psurf
= SURFACE_ShareLockSurface(hsurf
);
828 SURFACE_ShareUnlockSurface(psurf
);