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
;
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 /* Allocate the surface (but don't set the bits) */
168 psurf
= SURFACE_AllocSurface(STYPE_BITMAP
,
177 DPRINT1("SURFACE_AllocSurface failed.\n");
181 /* Mark as API and DDB bitmap */
182 psurf
->flags
|= (API_BITMAP
| DDB_SURFACE
);
184 /* Check if we have bits to set */
187 /* Protect with SEH and copy the bits */
190 ProbeForRead(pUnsafeBits
, (SIZE_T
)cjSize
, 1);
191 UnsafeSetBitmapBits(psurf
, 0, pUnsafeBits
);
193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
195 GDIOBJ_vDeleteObject(&psurf
->BaseObject
);
196 _SEH2_YIELD(return NULL
;)
203 RtlZeroMemory(psurf
->SurfObj
.pvBits
, psurf
->SurfObj
.cjBits
);
206 /* Get the handle for the bitmap */
207 hbmp
= (HBITMAP
)psurf
->SurfObj
.hsurf
;
209 /* Unlock the surface */
210 SURFACE_UnlockSurface(psurf
);
217 IntCreateCompatibleBitmap(
227 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
228 if (0 == Width
|| 0 == Height
)
230 return NtGdiGetStockObject(DEFAULT_BITMAP
);
233 if (Dc
->dctype
!= DC_TYPE_MEMORY
)
237 Bmp
= GreCreateBitmap(abs(Width
),
240 Bpp
? Bpp
: Dc
->ppdev
->gdiinfo
.cBitsPixel
,
244 DPRINT1("Failed to allocate a bitmap!\n");
248 psurf
= SURFACE_ShareLockSurface(Bmp
);
251 /* Dereference old palette and set new palette */
252 ppal
= PALETTE_ShareLockPalette(Dc
->ppdev
->devinfo
.hpalDefault
);
254 SURFACE_vSetPalette(psurf
, ppal
);
255 PALETTE_ShareUnlockPalette(ppal
);
258 psurf
->flags
= API_BITMAP
;
259 psurf
->hdc
= NULL
; // FIXME:
260 psurf
->SurfObj
.hdev
= (HDEV
)Dc
->ppdev
;
261 SURFACE_ShareUnlockSurface(psurf
);
267 PSURFACE psurf
= Dc
->dclevel
.pSurface
;
268 if(!psurf
) psurf
= psurfDefaultBitmap
;
269 Count
= BITMAP_GetObject(psurf
, sizeof(dibs
), &dibs
);
271 if (Count
== sizeof(BITMAP
))
275 Bmp
= GreCreateBitmap(abs(Width
),
278 Bpp
? Bpp
: dibs
.dsBm
.bmBitsPixel
,
280 psurfBmp
= SURFACE_ShareLockSurface(Bmp
);
283 /* Dereference old palette and set new palette */
284 SURFACE_vSetPalette(psurfBmp
, psurf
->ppal
);
287 psurfBmp
->flags
= API_BITMAP
;
288 psurfBmp
->hdc
= NULL
; // FIXME:
289 psurf
->SurfObj
.hdev
= (HDEV
)Dc
->ppdev
;
290 SURFACE_ShareUnlockSurface(psurfBmp
);
292 else if (Count
== sizeof(DIBSECTION
))
294 /* A DIB section is selected in the DC */
295 BYTE buf
[sizeof(BITMAPINFOHEADER
) + 256*sizeof(RGBQUAD
)] = {0};
297 BITMAPINFO
* bi
= (BITMAPINFO
*)buf
;
299 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
300 bi
->bmiHeader
.biWidth
= Width
;
301 bi
->bmiHeader
.biHeight
= Height
;
302 bi
->bmiHeader
.biPlanes
= Planes
? Planes
: dibs
.dsBmih
.biPlanes
;
303 bi
->bmiHeader
.biBitCount
= Bpp
? Bpp
: dibs
.dsBmih
.biBitCount
;
304 bi
->bmiHeader
.biCompression
= dibs
.dsBmih
.biCompression
;
305 bi
->bmiHeader
.biSizeImage
= 0;
306 bi
->bmiHeader
.biXPelsPerMeter
= dibs
.dsBmih
.biXPelsPerMeter
;
307 bi
->bmiHeader
.biYPelsPerMeter
= dibs
.dsBmih
.biYPelsPerMeter
;
308 bi
->bmiHeader
.biClrUsed
= dibs
.dsBmih
.biClrUsed
;
309 bi
->bmiHeader
.biClrImportant
= dibs
.dsBmih
.biClrImportant
;
311 if (bi
->bmiHeader
.biCompression
== BI_BITFIELDS
)
313 /* Copy the color masks */
314 RtlCopyMemory(bi
->bmiColors
, dibs
.dsBitfields
, 3*sizeof(RGBQUAD
));
316 else if (bi
->bmiHeader
.biBitCount
<= 8)
318 /* Copy the color table */
324 EngSetLastError(ERROR_INVALID_HANDLE
);
328 PalGDI
= psurf
->ppal
;
331 Index
< 256 && Index
< PalGDI
->NumColors
;
334 bi
->bmiColors
[Index
].rgbRed
= PalGDI
->IndexedColors
[Index
].peRed
;
335 bi
->bmiColors
[Index
].rgbGreen
= PalGDI
->IndexedColors
[Index
].peGreen
;
336 bi
->bmiColors
[Index
].rgbBlue
= PalGDI
->IndexedColors
[Index
].peBlue
;
337 bi
->bmiColors
[Index
].rgbReserved
= 0;
341 Bmp
= DIB_CreateDIBSection(Dc
,
355 NtGdiCreateCompatibleBitmap(
363 /* Check parameters */
364 if ((Width
<= 0) || (Height
<= 0) || ((Width
* Height
) > 0x3FFFFFFF))
366 EngSetLastError(ERROR_INVALID_PARAMETER
);
371 return GreCreateBitmap(Width
, Height
, 1, 1, 0);
375 DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
376 hDC
, Width
, Height
, Dc
->ppdev
->gdiinfo
.cBitsPixel
);
380 EngSetLastError(ERROR_INVALID_HANDLE
);
384 Bmp
= IntCreateCompatibleBitmap(Dc
, Width
, Height
, 0, 0);
392 NtGdiGetBitmapDimension(
402 /* Lock the bitmap */
403 psurfBmp
= SURFACE_ShareLockSurface(hBitmap
);
404 if (psurfBmp
== NULL
)
406 EngSetLastError(ERROR_INVALID_HANDLE
);
410 /* Use SEH to copy the data to the caller */
413 ProbeForWrite(psizDim
, sizeof(SIZE
), 1);
414 *psizDim
= psurfBmp
->sizlDim
;
416 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
422 /* Unlock the bitmap */
423 SURFACE_ShareUnlockSurface(psurfBmp
);
437 LONG lDeltaDst
, lDeltaSrc
;
438 ULONG nWidth
, nHeight
, cBitsPixel
;
440 nWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
441 nHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
442 cBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
445 pjSrc
= psurf
->SurfObj
.pvScan0
;
447 lDeltaSrc
= psurf
->SurfObj
.lDelta
;
448 lDeltaDst
= WIDTH_BYTES_ALIGN16(nWidth
, cBitsPixel
);
453 RtlCopyMemory(pjDst
, pjSrc
, lDeltaDst
);
464 OUT OPTIONAL PBYTE pUnsafeBits
)
470 /* Check parameters */
471 if (pUnsafeBits
!= NULL
&& cjBuffer
== 0)
476 /* Lock the bitmap */
477 psurf
= SURFACE_ShareLockSurface(hBitmap
);
480 EngSetLastError(ERROR_INVALID_HANDLE
);
484 /* Calculate the size of the bitmap in bytes */
485 cjSize
= WIDTH_BYTES_ALIGN16(psurf
->SurfObj
.sizlBitmap
.cx
,
486 BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
)) *
487 abs(psurf
->SurfObj
.sizlBitmap
.cy
);
489 /* If the bits vector is null, the function should return the read size */
490 if (pUnsafeBits
== NULL
)
492 SURFACE_ShareUnlockSurface(psurf
);
496 /* Don't copy more bytes than the buffer has */
497 cjBuffer
= min(cjBuffer
, cjSize
);
499 // FIXME: Use MmSecureVirtualMemory
502 ProbeForWrite(pUnsafeBits
, cjBuffer
, 1);
503 UnsafeGetBitmapBits(psurf
, cjBuffer
, pUnsafeBits
);
506 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
512 SURFACE_ShareUnlockSurface(psurf
);
522 IN PBYTE pUnsafeBits
)
527 if (pUnsafeBits
== NULL
|| Bytes
== 0)
532 psurf
= SURFACE_ShareLockSurface(hBitmap
);
535 EngSetLastError(ERROR_INVALID_HANDLE
);
541 ProbeForRead(pUnsafeBits
, Bytes
, 1);
542 UnsafeSetBitmapBits(psurf
, Bytes
, pUnsafeBits
);
545 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
551 SURFACE_ShareUnlockSurface(psurf
);
557 NtGdiSetBitmapDimension(
569 psurf
= SURFACE_ShareLockSurface(hBitmap
);
572 EngSetLastError(ERROR_INVALID_HANDLE
);
580 ProbeForWrite(Size
, sizeof(SIZE
), 1);
581 *Size
= psurf
->sizlDim
;
583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
590 /* The dimension is changed even if writing the old value failed */
591 psurf
->sizlDim
.cx
= Width
;
592 psurf
->sizlDim
.cy
= Height
;
594 SURFACE_ShareUnlockSurface(psurf
);
599 /* Internal Functions */
603 BITMAP_CopyBitmap(HBITMAP hBitmap
)
606 SURFACE
*psurfSrc
, *psurfNew
;
608 /* Fail, if no source bitmap is given */
609 if (hBitmap
== NULL
) return 0;
611 /* Lock the source bitmap */
612 psurfSrc
= SURFACE_ShareLockSurface(hBitmap
);
613 if (psurfSrc
== NULL
)
618 /* Allocate a new bitmap with the same dimensions as the source bmp */
619 hbmNew
= GreCreateBitmapEx(psurfSrc
->SurfObj
.sizlBitmap
.cx
,
620 psurfSrc
->SurfObj
.sizlBitmap
.cy
,
621 abs(psurfSrc
->SurfObj
.lDelta
),
622 psurfSrc
->SurfObj
.iBitmapFormat
,
623 psurfSrc
->SurfObj
.fjBitmap
& BMF_TOPDOWN
,
624 psurfSrc
->SurfObj
.cjBits
,
630 /* Lock the new bitmap */
631 psurfNew
= SURFACE_ShareLockSurface(hbmNew
);
634 /* Copy the bitmap bits to the new bitmap buffer */
635 RtlCopyMemory(psurfNew
->SurfObj
.pvBits
,
636 psurfSrc
->SurfObj
.pvBits
,
637 psurfNew
->SurfObj
.cjBits
);
640 /* Reference the palette of the source bitmap and use it */
641 SURFACE_vSetPalette(psurfNew
, psurfSrc
->ppal
);
643 /* Unlock the new surface */
644 SURFACE_ShareUnlockSurface(psurfNew
);
648 /* Failed to lock the bitmap, shouldn't happen */
649 GreDeleteObject(hbmNew
);
654 /* Unlock the source bitmap and return the handle of the new bitmap */
655 SURFACE_ShareUnlockSurface(psurfSrc
);
660 BITMAP_GetObject(SURFACE
*psurf
, INT Count
, LPVOID buffer
)
664 if (!buffer
) return sizeof(BITMAP
);
665 if ((UINT
)Count
< sizeof(BITMAP
)) return 0;
667 /* Always fill a basic BITMAP structure */
670 pBitmap
->bmWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
671 pBitmap
->bmHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
672 pBitmap
->bmPlanes
= 1;
673 pBitmap
->bmBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
674 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN16(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
676 /* Check for DIB section */
679 /* Set bmBits in this case */
680 pBitmap
->bmBits
= psurf
->SurfObj
.pvBits
;
681 /* DIBs data are 32 bits aligned */
682 pBitmap
->bmWidthBytes
= WIDTH_BYTES_ALIGN32(pBitmap
->bmWidth
, pBitmap
->bmBitsPixel
);
684 if (Count
>= sizeof(DIBSECTION
))
686 /* Fill rest of DIBSECTION */
687 PDIBSECTION pds
= buffer
;
689 pds
->dsBmih
.biSize
= sizeof(BITMAPINFOHEADER
);
690 pds
->dsBmih
.biWidth
= pds
->dsBm
.bmWidth
;
691 pds
->dsBmih
.biHeight
= pds
->dsBm
.bmHeight
;
692 pds
->dsBmih
.biPlanes
= pds
->dsBm
.bmPlanes
;
693 pds
->dsBmih
.biBitCount
= pds
->dsBm
.bmBitsPixel
;
695 switch (psurf
->SurfObj
.iBitmapFormat
)
700 pds
->dsBmih
.biCompression
= BI_RGB
;
704 if (psurf
->ppal
->flFlags
& PAL_RGB16_555
)
705 pds
->dsBmih
.biCompression
= BI_RGB
;
707 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
712 /* 24/32bpp BI_RGB is actually BGR format */
713 if (psurf
->ppal
->flFlags
& PAL_BGR
)
714 pds
->dsBmih
.biCompression
= BI_RGB
;
716 pds
->dsBmih
.biCompression
= BI_BITFIELDS
;
720 pds
->dsBmih
.biCompression
= BI_RLE4
;
723 pds
->dsBmih
.biCompression
= BI_RLE8
;
726 pds
->dsBmih
.biCompression
= BI_JPEG
;
729 pds
->dsBmih
.biCompression
= BI_PNG
;
732 ASSERT(FALSE
); /* This shouldn't happen */
735 pds
->dsBmih
.biSizeImage
= psurf
->SurfObj
.cjBits
;
736 pds
->dsBmih
.biXPelsPerMeter
= 0;
737 pds
->dsBmih
.biYPelsPerMeter
= 0;
738 pds
->dsBmih
.biClrUsed
= psurf
->ppal
->NumColors
;
739 pds
->dsBmih
.biClrImportant
= psurf
->biClrImportant
;
740 pds
->dsBitfields
[0] = psurf
->ppal
->RedMask
;
741 pds
->dsBitfields
[1] = psurf
->ppal
->GreenMask
;
742 pds
->dsBitfields
[2] = psurf
->ppal
->BlueMask
;
743 pds
->dshSection
= psurf
->hDIBSection
;
744 pds
->dsOffset
= psurf
->dwOffset
;
746 return sizeof(DIBSECTION
);
751 /* Not set according to wine test, confirmed in win2k */
752 pBitmap
->bmBits
= NULL
;
755 return sizeof(BITMAP
);
767 PSURFACE psurf
= SURFACE_ShareLockSurface(hsurf
);
771 SURFACE_ShareUnlockSurface(psurf
);