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