xref: /reactos/win32ss/gdi/gdi32/objects/bitmap.c (revision afb953ae)
1 #include <precomp.h>
2 
3 #include <pseh/pseh2.h>
4 
5 #define NDEBUG
6 #include <debug.h>
7 
8 // From Yuan, ScanLineSize = (Width * bitcount + 31)/32
9 #define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3)
10 
11 /*
12  *           DIB_BitmapInfoSize
13  *
14  * Return the size of the bitmap info structure including color table.
15  * 11/16/1999 (RJJ) lifted from wine
16  */
17 
18 INT
19 FASTCALL DIB_BitmapInfoSize(
20     const BITMAPINFO * info,
21     WORD coloruse,
22     BOOL max)
23 {
24     unsigned int colors, size, masks = 0;
25 
26     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
27     {
28         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *) info;
29         size = sizeof(BITMAPCOREHEADER);
30         if (core->bcBitCount <= 8)
31         {
32             colors = 1 << core->bcBitCount;
33             if (coloruse == DIB_RGB_COLORS)
34                 size += colors * sizeof(RGBTRIPLE);
35             else
36                 size += colors * sizeof(WORD);
37         }
38         return size;
39     }
40     else /* assume BITMAPINFOHEADER */
41     {
42         colors = max ? (1 << info->bmiHeader.biBitCount) : info->bmiHeader.biClrUsed;
43         if (colors > 256)
44             colors = 256;
45         if (!colors && (info->bmiHeader.biBitCount <= 8))
46             colors = 1 << info->bmiHeader.biBitCount;
47         if (info->bmiHeader.biCompression == BI_BITFIELDS)
48             masks = 3;
49         size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
50         return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
51     }
52 }
53 
54 /*
55  * Return the full scan size for a bitmap.
56  *
57  * Based on Wine, Utils.c and Windows Graphics Prog pg 595, SDK amvideo.h.
58  */
59 UINT
60 FASTCALL
61 DIB_BitmapMaxBitsSize(
62     PBITMAPINFO Info,
63     UINT ScanLines)
64 {
65     UINT Ret;
66 
67     if (!Info)
68         return 0;
69 
70     if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
71     {
72         PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) Info;
73         Ret = WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes,
74                 Core->bcBitCount) * ScanLines;
75     }
76     else /* assume BITMAPINFOHEADER */
77     {
78         if ((Info->bmiHeader.biCompression == BI_RGB) || (Info->bmiHeader.biCompression == BI_BITFIELDS))
79         {
80             Ret = WIDTH_BYTES_ALIGN32(
81                     Info->bmiHeader.biWidth * Info->bmiHeader.biPlanes,
82                     Info->bmiHeader.biBitCount) * ScanLines;
83         }
84         else
85         {
86             Ret = Info->bmiHeader.biSizeImage;
87         }
88     }
89     return Ret;
90 }
91 
92 /*
93  * DIB_GetBitmapInfo is complete copy of wine cvs 2/9-2006
94  * from file dib.c from gdi32.dll or orginal version
95  * did not calc the info right for some headers.
96  */
97 INT
98 WINAPI
99 DIB_GetBitmapInfo(
100     const BITMAPINFOHEADER *header,
101     PLONG width,
102     PLONG height,
103     PWORD planes,
104     PWORD bpp,
105     PLONG compr,
106     PLONG size)
107 {
108     if (header->biSize == sizeof(BITMAPCOREHEADER))
109     {
110         BITMAPCOREHEADER *core = (BITMAPCOREHEADER *) header;
111         *width = core->bcWidth;
112         *height = core->bcHeight;
113         *planes = core->bcPlanes;
114         *bpp = core->bcBitCount;
115         *compr = 0;
116         *size = 0;
117         return 0;
118     }
119 
120     if (header->biSize == sizeof(BITMAPINFOHEADER))
121     {
122         *width = header->biWidth;
123         *height = header->biHeight;
124         *planes = header->biPlanes;
125         *bpp = header->biBitCount;
126         *compr = header->biCompression;
127         *size = header->biSizeImage;
128         return 1;
129     }
130 
131     if (header->biSize == sizeof(BITMAPV4HEADER))
132     {
133         BITMAPV4HEADER *v4hdr = (BITMAPV4HEADER *) header;
134         *width = v4hdr->bV4Width;
135         *height = v4hdr->bV4Height;
136         *planes = v4hdr->bV4Planes;
137         *bpp = v4hdr->bV4BitCount;
138         *compr = v4hdr->bV4V4Compression;
139         *size = v4hdr->bV4SizeImage;
140         return 4;
141     }
142 
143     if (header->biSize == sizeof(BITMAPV5HEADER))
144     {
145         BITMAPV5HEADER *v5hdr = (BITMAPV5HEADER *) header;
146         *width = v5hdr->bV5Width;
147         *height = v5hdr->bV5Height;
148         *planes = v5hdr->bV5Planes;
149         *bpp = v5hdr->bV5BitCount;
150         *compr = v5hdr->bV5Compression;
151         *size = v5hdr->bV5SizeImage;
152         return 5;
153     }
154     DPRINT("(%lu): wrong size for header\n", header->biSize);
155     return -1;
156 }
157 
158 /*
159  * @implemented
160  */
161 int
162 WINAPI
163 GdiGetBitmapBitsSize(
164     BITMAPINFO *lpbmi)
165 {
166     UINT Ret;
167 
168     if (!lpbmi)
169         return 0;
170 
171     if (lpbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
172     {
173         PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) lpbmi;
174         Ret =
175         WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes,
176                 Core->bcBitCount) * Core->bcHeight;
177     }
178     else /* assume BITMAPINFOHEADER */
179     {
180         if (!(lpbmi->bmiHeader.biCompression) || (lpbmi->bmiHeader.biCompression == BI_BITFIELDS))
181         {
182             Ret = WIDTH_BYTES_ALIGN32(
183                     lpbmi->bmiHeader.biWidth * lpbmi->bmiHeader.biPlanes,
184                     lpbmi->bmiHeader.biBitCount) * abs(lpbmi->bmiHeader.biHeight);
185         }
186         else
187         {
188             Ret = lpbmi->bmiHeader.biSizeImage;
189         }
190     }
191     return Ret;
192 }
193 
194 /*
195  * @implemented
196  */
197 HBITMAP
198 WINAPI
199 CreateDIBSection(
200     HDC hDC,
201     CONST BITMAPINFO *BitmapInfo,
202     UINT Usage,
203     VOID **Bits,
204     HANDLE hSection,
205     DWORD dwOffset)
206 {
207     PBITMAPINFO pConvertedInfo;
208     UINT ConvertedInfoSize;
209     HBITMAP hBitmap = NULL;
210     PVOID bmBits = NULL;
211 
212     pConvertedInfo = ConvertBitmapInfo(BitmapInfo, Usage, &ConvertedInfoSize,
213     FALSE);
214 
215     if (pConvertedInfo)
216     {
217         // Verify header due to converted may == info.
218         if (pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
219         {
220             if (pConvertedInfo->bmiHeader.biCompression == BI_JPEG
221                 || pConvertedInfo->bmiHeader.biCompression == BI_PNG)
222             {
223                 SetLastError(ERROR_INVALID_PARAMETER);
224                 return NULL;
225             }
226         }
227         bmBits = Bits;
228         hBitmap = NtGdiCreateDIBSection(hDC, hSection, dwOffset, pConvertedInfo, Usage,
229             ConvertedInfoSize, 0, // fl
230             0, // dwColorSpace
231             &bmBits);
232 
233         if (BitmapInfo != pConvertedInfo)
234             RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
235 
236         if (!hBitmap)
237         {
238             bmBits = NULL;
239         }
240     }
241 
242     if (Bits)
243         *Bits = bmBits;
244 
245     return hBitmap;
246 }
247 
248 
249 /*
250  * @implemented
251  */
252 HBITMAP
253 WINAPI
254 CreateBitmap(
255     INT Width,
256     INT Height,
257     UINT Planes,
258     UINT BitsPixel,
259     CONST VOID* pUnsafeBits)
260 {
261     if (Width && Height)
262     {
263         return NtGdiCreateBitmap(Width, Height, Planes, BitsPixel, (LPBYTE) pUnsafeBits);
264     }
265     else
266     {
267         /* Return 1x1 bitmap */
268         return GetStockObject(DEFAULT_BITMAP);
269     }
270 }
271 
272 /*
273  * @implemented
274  */
275 HBITMAP
276 WINAPI
277 CreateBitmapIndirect(
278     const BITMAP *pbm)
279 {
280     HBITMAP bitmap = NULL;
281 
282     /* Note windows xp/2003 does not check if pbm is NULL or not */
283     if ((pbm->bmWidthBytes != 0) && (!(pbm->bmWidthBytes & 1)))
284 
285     {
286         bitmap = CreateBitmap(pbm->bmWidth, pbm->bmHeight, pbm->bmPlanes, pbm->bmBitsPixel,
287             pbm->bmBits);
288     }
289     else
290     {
291         SetLastError(ERROR_INVALID_PARAMETER);
292     }
293 
294     return bitmap;
295 }
296 
297 HBITMAP
298 WINAPI
299 CreateDiscardableBitmap(
300     HDC hDC,
301     INT Width,
302     INT Height)
303 {
304     return CreateCompatibleBitmap(hDC, Width, Height);
305 }
306 
307 HBITMAP
308 WINAPI
309 CreateCompatibleBitmap(
310     HDC hDC,
311     INT Width,
312     INT Height)
313 {
314     PDC_ATTR pDc_Attr;
315 
316     if (!GdiGetHandleUserData(hDC, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr))
317         return NULL;
318 
319     if (!Width || !Height)
320         return GetStockObject(DEFAULT_BITMAP);
321 
322     if (!(pDc_Attr->ulDirty_ & DC_DIBSECTION))
323     {
324         return NtGdiCreateCompatibleBitmap(hDC, Width, Height);
325     }
326     else
327     {
328         HBITMAP hBmp = NULL;
329         struct
330         {
331             BITMAP bitmap;
332             BITMAPINFOHEADER bmih;
333             RGBQUAD rgbquad[256];
334         } buffer;
335         DIBSECTION* pDIBs = (DIBSECTION*) &buffer;
336         BITMAPINFO* pbmi = (BITMAPINFO*) &buffer.bmih;
337 
338         hBmp = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_BITMAP);
339 
340         if (GetObjectA(hBmp, sizeof(DIBSECTION), pDIBs) != sizeof(DIBSECTION))
341             return NULL;
342 
343         if (pDIBs->dsBm.bmBitsPixel <= 8)
344             GetDIBColorTable(hDC, 0, 256, buffer.rgbquad);
345 
346         pDIBs->dsBmih.biWidth = Width;
347         pDIBs->dsBmih.biHeight = Height;
348 
349         return CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, NULL, NULL, 0);
350     }
351     return NULL;
352 }
353 
354 INT
355 WINAPI
356 GetDIBits(
357     HDC hDC,
358     HBITMAP hbmp,
359     UINT uStartScan,
360     UINT cScanLines,
361     LPVOID lpvBits,
362     LPBITMAPINFO lpbmi,
363     UINT uUsage)
364 {
365     UINT cjBmpScanSize;
366     UINT cjInfoSize;
367 
368     if (!hDC || !GdiValidateHandle((HGDIOBJ) hDC) || !lpbmi)
369     {
370         GdiSetLastError(ERROR_INVALID_PARAMETER);
371         return 0;
372     }
373 
374     cjBmpScanSize = DIB_BitmapMaxBitsSize(lpbmi, cScanLines);
375     /* Caller must provide maximum size possible */
376     cjInfoSize = DIB_BitmapInfoSize(lpbmi, uUsage, TRUE);
377 
378     if (lpvBits)
379     {
380         if (lpbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
381         {
382             if (lpbmi->bmiHeader.biCompression == BI_JPEG
383                 || lpbmi->bmiHeader.biCompression == BI_PNG)
384             {
385                 SetLastError(ERROR_INVALID_PARAMETER);
386                 return 0;
387             }
388         }
389     }
390 
391     return NtGdiGetDIBitsInternal(hDC, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, uUsage,
392         cjBmpScanSize, cjInfoSize);
393 }
394 
395 /*
396  * @implemented
397  */
398 HBITMAP
399 WINAPI
400 CreateDIBitmap(
401     HDC hDC,
402     const BITMAPINFOHEADER *Header,
403     DWORD Init,
404     LPCVOID Bits,
405     const BITMAPINFO *Data,
406     UINT ColorUse)
407 {
408     LONG Width, Height, Compression, DibSize;
409     WORD Planes, BitsPerPixel;
410 //  PDC_ATTR pDc_Attr;
411     UINT cjBmpScanSize = 0;
412     HBITMAP hBitmap = NULL;
413     PBITMAPINFO pbmiConverted;
414     UINT cjInfoSize;
415 
416     /* Convert the BITMAPINFO if it is a COREINFO */
417     pbmiConverted = ConvertBitmapInfo(Data, ColorUse, &cjInfoSize, FALSE);
418 
419     /* Check for CBM_CREATDIB */
420     if (Init & CBM_CREATDIB)
421     {
422         if (cjInfoSize == 0)
423         {
424             goto Exit;
425         }
426         else if (Init & CBM_INIT)
427         {
428             if (Bits == NULL)
429             {
430                 goto Exit;
431             }
432         }
433         else
434         {
435             Bits = NULL;
436         }
437 
438         /* CBM_CREATDIB needs Data. */
439         if (pbmiConverted == NULL)
440         {
441             DPRINT1("CBM_CREATDIB needs a BITMAPINFO!\n");
442             goto Exit;
443         }
444 
445         /* It only works with PAL or RGB */
446         if (ColorUse > DIB_PAL_COLORS)
447         {
448             DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
449             GdiSetLastError(ERROR_INVALID_PARAMETER);
450             goto Exit;
451         }
452 
453         /* Use the header from the data */
454         Header = &Data->bmiHeader;
455     }
456     else
457     {
458         if (Init & CBM_INIT)
459         {
460             if (Bits != NULL)
461             {
462                 if (cjInfoSize == 0)
463                 {
464                     goto Exit;
465                 }
466             }
467             else
468             {
469                 Init &= ~CBM_INIT;
470             }
471         }
472     }
473 
474     /* Header is required */
475     if (!Header)
476     {
477         DPRINT1("Header is NULL\n");
478         GdiSetLastError(ERROR_INVALID_PARAMETER);
479         goto Exit;
480     }
481 
482     /* Get the bitmap format and dimensions */
483     if (DIB_GetBitmapInfo(Header, &Width, &Height, &Planes, &BitsPerPixel, &Compression, &DibSize) == -1)
484     {
485         DPRINT1("DIB_GetBitmapInfo failed!\n");
486         GdiSetLastError(ERROR_INVALID_PARAMETER);
487         goto Exit;
488     }
489 
490     /* Check if the Compr is incompatible */
491     if ((Compression == BI_JPEG) || (Compression == BI_PNG))
492     {
493         DPRINT1("Invalid compression: %lu!\n", Compression);
494         goto Exit;
495     }
496 
497     /* Only DIB_RGB_COLORS (0), DIB_PAL_COLORS (1) and 2 are valid. */
498     if (ColorUse > DIB_PAL_COLORS + 1)
499     {
500         DPRINT1("Invalid compression: %lu!\n", Compression);
501         GdiSetLastError(ERROR_INVALID_PARAMETER);
502         goto Exit;
503     }
504 
505     /* If some Bits are given, only DIB_PAL_COLORS and DIB_RGB_COLORS are valid */
506     if (Bits && (ColorUse > DIB_PAL_COLORS))
507     {
508         DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
509         GdiSetLastError(ERROR_INVALID_PARAMETER);
510         goto Exit;
511     }
512 
513     /* Negative width is not allowed */
514     if (Width < 0)
515     {
516         DPRINT1("Negative width: %li\n", Width);
517         goto Exit;
518     }
519 
520     /* Top-down DIBs have a negative height. */
521     Height = abs(Height);
522 
523 // For Icm support.
524 // GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr))
525 
526     cjBmpScanSize = GdiGetBitmapBitsSize(pbmiConverted);
527 
528     DPRINT("pBMI %p, Size bpp %u, dibsize %d, Conv %u, BSS %u\n",
529            Data, BitsPerPixel, DibSize, cjInfoSize, cjBmpScanSize);
530 
531     if (!Width || !Height)
532     {
533         hBitmap = GetStockObject(DEFAULT_BITMAP);
534     }
535     else
536     {
537         hBitmap = NtGdiCreateDIBitmapInternal(hDC,
538                                               Width,
539                                               Height,
540                                               Init,
541                                               (LPBYTE)Bits,
542                                               (LPBITMAPINFO)pbmiConverted,
543                                               ColorUse,
544                                               cjInfoSize,
545                                               cjBmpScanSize,
546                                               0, 0);
547     }
548 
549 Exit:
550     /* Cleanup converted BITMAPINFO */
551     if ((pbmiConverted != NULL) && (pbmiConverted != Data))
552     {
553         RtlFreeHeap(RtlGetProcessHeap(), 0, pbmiConverted);
554     }
555 
556     return hBitmap;
557 }
558 
559 /*
560  * @implemented
561  */
562 INT
563 WINAPI
564 SetDIBits(
565     HDC hDC,
566     HBITMAP hBitmap,
567     UINT uStartScan,
568     UINT cScanLines,
569     CONST VOID *lpvBits,
570     CONST BITMAPINFO *lpbmi,
571     UINT fuColorUse)
572 {
573     HDC hDCc, SavehDC, nhDC;
574     DWORD dwWidth, dwHeight;
575     HGDIOBJ hOldBitmap;
576     HPALETTE hPal = NULL;
577     INT LinesCopied = 0;
578     BOOL newDC = FALSE;
579 
580     if (!lpvBits || (GDI_HANDLE_GET_TYPE(hBitmap) != GDI_OBJECT_TYPE_BITMAP))
581         return 0;
582 
583     if (lpbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
584     {
585         if (lpbmi->bmiHeader.biCompression == BI_JPEG
586             || lpbmi->bmiHeader.biCompression == BI_PNG)
587         {
588             SetLastError(ERROR_INVALID_PARAMETER);
589             return 0;
590         }
591     }
592 
593     hDCc = NtGdiGetDCforBitmap(hBitmap); // hDC can be NULL, so, get it from the bitmap.
594     SavehDC = hDCc;
595     if (!hDCc) // No DC associated with bitmap, Clone or Create one.
596     {
597         nhDC = CreateCompatibleDC(hDC);
598         if (!nhDC)
599             return 0;
600         newDC = TRUE;
601         SavehDC = nhDC;
602     }
603     else if (!SaveDC(hDCc))
604         return 0;
605 
606     hOldBitmap = SelectObject(SavehDC, hBitmap);
607 
608     if (hOldBitmap)
609     {
610         if (hDC)
611             hPal = SelectPalette(SavehDC, (HPALETTE) GetCurrentObject(hDC, OBJ_PAL), FALSE);
612 
613         if (lpbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
614         {
615             PBITMAPCOREINFO pbci = (PBITMAPCOREINFO) lpbmi;
616             dwWidth = pbci->bmciHeader.bcWidth;
617             dwHeight = pbci->bmciHeader.bcHeight;
618         }
619         else
620         {
621             dwWidth = lpbmi->bmiHeader.biWidth;
622             dwHeight = abs(lpbmi->bmiHeader.biHeight);
623         }
624 
625         LinesCopied = SetDIBitsToDevice(SavehDC, 0, 0, dwWidth, dwHeight, 0, 0, uStartScan,
626             cScanLines, (void *) lpvBits, (LPBITMAPINFO) lpbmi, fuColorUse);
627 
628         if (hDC)
629             SelectPalette(SavehDC, hPal, FALSE);
630 
631         SelectObject(SavehDC, hOldBitmap);
632     }
633 
634     if (newDC)
635         DeleteDC(SavehDC);
636     else
637         RestoreDC(SavehDC, -1);
638 
639     return LinesCopied;
640 }
641 
642 /*
643  * @implemented
644  *
645  */
646 INT
647 WINAPI
648 SetDIBitsToDevice(
649     HDC hdc,
650     int XDest,
651     int YDest,
652     DWORD Width,
653     DWORD Height,
654     int XSrc,
655     int YSrc,
656     UINT StartScan,
657     UINT ScanLines,
658     CONST VOID *Bits,
659     CONST BITMAPINFO *lpbmi,
660     UINT ColorUse)
661 {
662     PDC_ATTR pDc_Attr;
663     PBITMAPINFO pConvertedInfo;
664     UINT ConvertedInfoSize;
665     INT LinesCopied = 0;
666     UINT cjBmpScanSize = 0;
667     BOOL Hit = FALSE;
668     PVOID pvSafeBits = (PVOID) Bits;
669 
670     if (!ScanLines || !lpbmi || !Bits)
671         return 0;
672 
673     if (ColorUse && ColorUse != DIB_PAL_COLORS && ColorUse != DIB_PAL_COLORS + 1)
674         return 0;
675 
676     pConvertedInfo = ConvertBitmapInfo(lpbmi, ColorUse, &ConvertedInfoSize, FALSE);
677     if (!pConvertedInfo)
678         return 0;
679 
680     HANDLE_METADC(INT,
681                   SetDIBitsToDevice,
682                   0,
683                   hdc,
684                   XDest,
685                   YDest,
686                   Width,
687                   Height,
688                   XSrc,
689                   YSrc,
690                   StartScan,
691                   ScanLines,
692                   Bits,
693                   lpbmi,
694                   ColorUse);
695 
696     // Handle the "Special Case"!
697     {
698         PLDC pldc;
699         ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
700         if (hType != GDILoObjType_LO_DC_TYPE && hType != GDILoObjType_LO_METADC16_TYPE)
701         {
702             pldc = GdiGetLDC(hdc);
703             if (pldc)
704             {
705                 if (pldc->Flags & LDC_STARTPAGE) StartPage(hdc);
706 
707                 if (pldc->Flags & LDC_SAPCALLBACK) GdiSAPCallback(pldc);
708 
709                 if (pldc->Flags & LDC_KILL_DOCUMENT)
710                 {
711                     LinesCopied = 0;
712                     goto Exit;
713                 }
714             }
715             else
716             {
717                 SetLastError(ERROR_INVALID_HANDLE);
718                 LinesCopied = 0;
719                 goto Exit;
720             }
721         }
722     }
723 
724     if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) ||
725             (pConvertedInfo->bmiHeader.biCompression == BI_RLE4))
726     {
727         /* For compressed data, we must set the whole thing */
728         StartScan = 0;
729         ScanLines = pConvertedInfo->bmiHeader.biHeight;
730     }
731 
732     cjBmpScanSize = DIB_BitmapMaxBitsSize((LPBITMAPINFO) lpbmi, ScanLines);
733 
734     pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize);
735     if (pvSafeBits)
736     {
737         _SEH2_TRY
738         {
739             RtlCopyMemory(pvSafeBits, Bits, cjBmpScanSize);
740         }
741         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
742         {
743             Hit = TRUE;
744         }
745         _SEH2_END
746 
747         if (Hit)
748         {
749             // We don't die, we continue on with a allocated safe pointer to kernel
750             // space.....
751             DPRINT1("SetDIBitsToDevice fail to read BitMapInfo: %p or Bits: %p & Size: %u\n",
752                 pConvertedInfo, Bits, cjBmpScanSize);
753         }
754         DPRINT("SetDIBitsToDevice Allocate Bits %u!!!\n", cjBmpScanSize);
755     }
756 
757     if (!GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr))
758     {
759         DPRINT1("SetDIBitsToDevice called on invalid DC %p (not owned?)\n", hdc);
760         SetLastError(ERROR_INVALID_PARAMETER);
761         LinesCopied = 0;
762         goto Exit;
763     }
764     /*
765      if ( !pDc_Attr || // DC is Public
766      ColorUse == DIB_PAL_COLORS ||
767      ((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
768      (pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
769      pConvertedInfo->bmiHeader.biCompression  == BI_PNG )) )*/
770     {
771         LinesCopied = NtGdiSetDIBitsToDeviceInternal(hdc, XDest, YDest, Width, Height, XSrc, YSrc,
772             StartScan, ScanLines, (LPBYTE) pvSafeBits, (LPBITMAPINFO) pConvertedInfo, ColorUse,
773             cjBmpScanSize, ConvertedInfoSize,
774             TRUE,
775             NULL);
776     }
777 Exit:
778     if (Bits != pvSafeBits)
779         RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits);
780     if (lpbmi != pConvertedInfo)
781         RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
782 
783     return LinesCopied;
784 }
785 
786 /*
787  * @unimplemented
788  */
789 int
790 WINAPI
791 StretchDIBits(
792     HDC hdc,
793     int XDest,
794     int YDest,
795     int nDestWidth,
796     int nDestHeight,
797     int XSrc,
798     int YSrc,
799     int nSrcWidth,
800     int nSrcHeight,
801     CONST VOID *lpBits,
802     CONST BITMAPINFO *lpBitsInfo,
803     UINT iUsage,
804     DWORD dwRop)
805 
806 {
807     PDC_ATTR pDc_Attr;
808     PBITMAPINFO pConvertedInfo = NULL;
809     UINT ConvertedInfoSize = 0;
810     INT LinesCopied = 0;
811     UINT cjBmpScanSize = 0;
812     PVOID pvSafeBits = NULL;
813     BOOL Hit = FALSE;
814 
815     DPRINT("StretchDIBits %p : %p : %u\n", lpBits, lpBitsInfo, iUsage);
816 
817     HANDLE_METADC( int,
818                    StretchDIBits,
819                    0,
820                    hdc,
821                    XDest,
822                    YDest,
823                    nDestWidth,
824                    nDestHeight,
825                    XSrc,
826                    YSrc,
827                    nSrcWidth,
828                    nSrcHeight,
829                    lpBits,
830                    lpBitsInfo,
831                    iUsage,
832                    dwRop );
833 
834     if ( GdiConvertAndCheckDC(hdc) == NULL ) return 0;
835 
836     pConvertedInfo = ConvertBitmapInfo(lpBitsInfo, iUsage, &ConvertedInfoSize, FALSE);
837     if (!pConvertedInfo)
838     {
839         return 0;
840     }
841 
842     cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *) pConvertedInfo);
843 
844     if (lpBits)
845     {
846         pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize);
847         if (pvSafeBits)
848         {
849             _SEH2_TRY
850             {
851                 RtlCopyMemory(pvSafeBits, lpBits, cjBmpScanSize);
852             }
853             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
854             {
855                 Hit = TRUE;
856             }
857             _SEH2_END
858 
859             if (Hit)
860             {
861                 // We don't die, we continue on with a allocated safe pointer to kernel
862                 // space.....
863                 DPRINT1("StretchDIBits fail to read BitMapInfo: %p or Bits: %p & Size: %u\n",
864                     pConvertedInfo, lpBits, cjBmpScanSize);
865             }
866             DPRINT("StretchDIBits Allocate Bits %u!!!\n", cjBmpScanSize);
867         }
868     }
869 
870     if (!GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr))
871     {
872         DPRINT1("StretchDIBits called on invalid DC %p (not owned?)\n", hdc);
873         SetLastError(ERROR_INVALID_PARAMETER);
874         LinesCopied = 0;
875         goto Exit;
876     }
877     /*
878      if ( !pDc_Attr ||
879      iUsage == DIB_PAL_COLORS ||
880      ((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
881      (pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
882      pConvertedInfo->bmiHeader.biCompression  == BI_PNG )) )*/
883     {
884         LinesCopied = NtGdiStretchDIBitsInternal( hdc,
885                                                   XDest,
886                                                   YDest,
887                                                   nDestWidth,
888                                                   nDestHeight,
889                                                   XSrc,
890                                                   YSrc,
891                                                   nSrcWidth,
892                                                   nSrcHeight,
893                                                   pvSafeBits,
894                                                   pConvertedInfo,
895                                                   (DWORD) iUsage,
896                                                   dwRop,
897                                                   ConvertedInfoSize,
898                                                   cjBmpScanSize,
899                                                   NULL );
900     }
901 Exit:
902     if (pvSafeBits)
903         RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits);
904     if (lpBitsInfo != pConvertedInfo)
905         RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
906 
907     return LinesCopied;
908 }
909 
910 /*
911  * @implemented
912  */
913 DWORD
914 WINAPI
915 GetBitmapAttributes(HBITMAP hbm)
916 {
917     if ( GDI_HANDLE_IS_STOCKOBJ(hbm) )
918     {
919         return SC_BB_STOCKOBJ;
920     }
921     return 0;
922 }
923 
924 /*
925  * @implemented
926  */
927 HBITMAP
928 WINAPI
929 SetBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
930 {
931     if ( dwFlags & ~SC_BB_STOCKOBJ )
932     {
933         return NULL;
934     }
935     return NtGdiSetBitmapAttributes( hbm, dwFlags );
936 }
937 
938 /*
939  * @implemented
940  */
941 HBITMAP
942 WINAPI
943 ClearBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
944 {
945     if ( dwFlags & ~SC_BB_STOCKOBJ )
946     {
947         return NULL;
948     }
949     return NtGdiClearBitmapAttributes( hbm, dwFlags );;
950 }
951 
952 
953