[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / dibobj.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/dibobj.c
5 * PURPOSE: Dib object functions
6 * PROGRAMMER:
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 static const RGBQUAD EGAColorsQuads[16] =
15 {
16 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */
17 { 0x00, 0x00, 0x00, 0x00 },
18 { 0x00, 0x00, 0x80, 0x00 },
19 { 0x00, 0x80, 0x00, 0x00 },
20 { 0x00, 0x80, 0x80, 0x00 },
21 { 0x80, 0x00, 0x00, 0x00 },
22 { 0x80, 0x00, 0x80, 0x00 },
23 { 0x80, 0x80, 0x00, 0x00 },
24 { 0x80, 0x80, 0x80, 0x00 },
25 { 0xc0, 0xc0, 0xc0, 0x00 },
26 { 0x00, 0x00, 0xff, 0x00 },
27 { 0x00, 0xff, 0x00, 0x00 },
28 { 0x00, 0xff, 0xff, 0x00 },
29 { 0xff, 0x00, 0x00, 0x00 },
30 { 0xff, 0x00, 0xff, 0x00 },
31 { 0xff, 0xff, 0x00, 0x00 },
32 { 0xff, 0xff, 0xff, 0x00 }
33 };
34
35 static const RGBQUAD DefLogPaletteQuads[20] = /* Copy of Default Logical Palette */
36 {
37 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */
38 { 0x00, 0x00, 0x00, 0x00 },
39 { 0x00, 0x00, 0x80, 0x00 },
40 { 0x00, 0x80, 0x00, 0x00 },
41 { 0x00, 0x80, 0x80, 0x00 },
42 { 0x80, 0x00, 0x00, 0x00 },
43 { 0x80, 0x00, 0x80, 0x00 },
44 { 0x80, 0x80, 0x00, 0x00 },
45 { 0xc0, 0xc0, 0xc0, 0x00 },
46 { 0xc0, 0xdc, 0xc0, 0x00 },
47 { 0xf0, 0xca, 0xa6, 0x00 },
48 { 0xf0, 0xfb, 0xff, 0x00 },
49 { 0xa4, 0xa0, 0xa0, 0x00 },
50 { 0x80, 0x80, 0x80, 0x00 },
51 { 0x00, 0x00, 0xf0, 0x00 },
52 { 0x00, 0xff, 0x00, 0x00 },
53 { 0x00, 0xff, 0xff, 0x00 },
54 { 0xff, 0x00, 0x00, 0x00 },
55 { 0xff, 0x00, 0xff, 0x00 },
56 { 0xff, 0xff, 0x00, 0x00 },
57 { 0xff, 0xff, 0xff, 0x00 }
58 };
59
60 PPALETTE
61 NTAPI
62 CreateDIBPalette(
63 _In_ const BITMAPINFO *pbmi,
64 _In_ PDC pdc,
65 _In_ ULONG iUsage)
66 {
67 PPALETTE ppal;
68 ULONG i, cBitsPixel, cColors;
69
70 if (pbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
71 {
72 PBITMAPCOREINFO pbci = (PBITMAPCOREINFO)pbmi;
73 cBitsPixel = pbci->bmciHeader.bcBitCount;
74 }
75 else
76 {
77 cBitsPixel = pbmi->bmiHeader.biBitCount;
78 }
79
80 /* Check if the colors are indexed */
81 if (cBitsPixel <= 8)
82 {
83 /* We create a "full" palette */
84 cColors = 1 << cBitsPixel;
85
86 /* Allocate the palette */
87 ppal = PALETTE_AllocPalette(PAL_INDEXED,
88 cColors,
89 NULL,
90 0,
91 0,
92 0);
93
94 /* Check if the BITMAPINFO specifies how many colors to use */
95 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
96 (pbmi->bmiHeader.biClrUsed != 0))
97 {
98 /* This is how many colors we can actually process */
99 cColors = min(cColors, pbmi->bmiHeader.biClrUsed);
100 }
101
102 /* Check how to use the colors */
103 if (iUsage == DIB_PAL_COLORS)
104 {
105 COLORREF crColor;
106
107 /* The colors are an array of WORD indices into the DC palette */
108 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
109
110 /* Use the DCs palette or, if no DC is given, the default one */
111 PPALETTE ppalDC = pdc ? pdc->dclevel.ppal : gppalDefault;
112
113 /* Loop all color indices in the DIB */
114 for (i = 0; i < cColors; i++)
115 {
116 /* Get the palette index and handle wraparound when exceeding
117 the number of colors in the DC palette */
118 WORD wIndex = pwColors[i] % ppalDC->NumColors;
119
120 /* USe the RGB value from the DC palette */
121 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, wIndex);
122 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
123 }
124 }
125 else if (iUsage == DIB_PAL_BRUSHHACK)
126 {
127 /* The colors are an array of WORD indices into the DC palette */
128 PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
129
130 /* Loop all color indices in the DIB */
131 for (i = 0; i < cColors; i++)
132 {
133 /* Set the index directly as the RGB color, the real palette
134 containing RGB values will be calculated when the brush is
135 realized */
136 PALETTE_vSetRGBColorForIndex(ppal, i, pwColors[i]);
137 }
138
139 /* Mark the palette as a brush hack palette */
140 ppal->flFlags |= PAL_BRUSHHACK;
141 }
142 // else if (iUsage == 2)
143 // {
144 // FIXME: this one is undocumented
145 // ASSERT(FALSE);
146 // }
147 else if (pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
148 {
149 /* The colors are an array of RGBQUAD values */
150 RGBQUAD *prgb = (RGBQUAD*)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
151
152 // FIXME: do we need to handle PALETTEINDEX / PALETTERGB macro?
153
154 /* Loop all color indices in the DIB */
155 for (i = 0; i < cColors; i++)
156 {
157 /* Get the color value and translate it to a COLORREF */
158 RGBQUAD rgb = prgb[i];
159 COLORREF crColor = RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue);
160
161 /* Set the RGB value in the palette */
162 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
163 }
164 }
165 else
166 {
167 /* The colors are an array of RGBTRIPLE values */
168 RGBTRIPLE *prgb = (RGBTRIPLE*)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
169
170 /* Loop all color indices in the DIB */
171 for (i = 0; i < cColors; i++)
172 {
173 /* Get the color value and translate it to a COLORREF */
174 RGBTRIPLE rgb = prgb[i];
175 COLORREF crColor = RGB(rgb.rgbtRed, rgb.rgbtGreen, rgb.rgbtBlue);
176
177 /* Set the RGB value in the palette */
178 PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
179 }
180 }
181 }
182 else
183 {
184 /* This is a bitfield / RGB palette */
185 ULONG flRedMask, flGreenMask, flBlueMask;
186
187 /* Check if the DIB contains bitfield values */
188 if ((pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
189 (pbmi->bmiHeader.biCompression == BI_BITFIELDS))
190 {
191 /* Check if we have a v4/v5 header */
192 if (pbmi->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
193 {
194 /* The masks are dedicated fields in the header */
195 PBITMAPV4HEADER pbmV4Header = (PBITMAPV4HEADER)&pbmi->bmiHeader;
196 flRedMask = pbmV4Header->bV4RedMask;
197 flGreenMask = pbmV4Header->bV4GreenMask;
198 flBlueMask = pbmV4Header->bV4BlueMask;
199 }
200 else
201 {
202 /* The masks are the first 3 values in the DIB color table */
203 PDWORD pdwColors = (PVOID)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
204 flRedMask = pdwColors[0];
205 flGreenMask = pdwColors[1];
206 flBlueMask = pdwColors[2];
207 }
208 }
209 else
210 {
211 /* Check what bit depth we have. Note: optimization flags are
212 calculated in PALETTE_AllocPalette() */
213 if (cBitsPixel == 16)
214 {
215 /* This is an RGB 555 palette */
216 flRedMask = 0x7C00;
217 flGreenMask = 0x03E0;
218 flBlueMask = 0x001F;
219 }
220 else
221 {
222 /* This is an RGB 888 palette */
223 flRedMask = 0xFF0000;
224 flGreenMask = 0x00FF00;
225 flBlueMask = 0x0000FF;
226 }
227 }
228
229 /* Allocate the bitfield palette */
230 ppal = PALETTE_AllocPalette(PAL_BITFIELDS,
231 0,
232 NULL,
233 flRedMask,
234 flGreenMask,
235 flBlueMask);
236 }
237
238 /* We're done, return the palette */
239 return ppal;
240 }
241
242 // Converts a DIB to a device-dependent bitmap
243 static INT
244 FASTCALL
245 IntSetDIBits(
246 PDC DC,
247 HBITMAP hBitmap,
248 UINT StartScan,
249 UINT ScanLines,
250 CONST VOID *Bits,
251 CONST BITMAPINFO *bmi,
252 UINT ColorUse)
253 {
254 HBITMAP SourceBitmap;
255 PSURFACE psurfDst, psurfSrc;
256 INT result = 0;
257 RECT rcDst;
258 POINTL ptSrc;
259 EXLATEOBJ exlo;
260 PPALETTE ppalDIB = 0;
261
262 if (!bmi) return 0;
263
264 SourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth,
265 ScanLines,
266 0,
267 BitmapFormat(bmi->bmiHeader.biBitCount,
268 bmi->bmiHeader.biCompression),
269 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
270 bmi->bmiHeader.biSizeImage,
271 (PVOID)Bits,
272 0);
273 if (!SourceBitmap)
274 {
275 DPRINT1("Error: Could not create a bitmap.\n");
276 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
277 return 0;
278 }
279
280 psurfDst = SURFACE_ShareLockSurface(hBitmap);
281 psurfSrc = SURFACE_ShareLockSurface(SourceBitmap);
282
283 if(!(psurfSrc && psurfDst))
284 {
285 DPRINT1("Error: Could not lock surfaces\n");
286 goto cleanup;
287 }
288
289 /* Create a palette for the DIB */
290 ppalDIB = CreateDIBPalette(bmi, DC, ColorUse);
291 if (!ppalDIB)
292 {
293 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
294 goto cleanup;
295 }
296
297 /* Initialize EXLATEOBJ */
298 EXLATEOBJ_vInitialize(&exlo,
299 ppalDIB,
300 psurfDst->ppal,
301 RGB(0xff, 0xff, 0xff),
302 RGB(0xff, 0xff, 0xff), //DC->pdcattr->crBackgroundClr,
303 0); // DC->pdcattr->crForegroundClr);
304
305 rcDst.top = StartScan;
306 rcDst.left = 0;
307 rcDst.bottom = rcDst.top + ScanLines;
308 rcDst.right = psurfDst->SurfObj.sizlBitmap.cx;
309 ptSrc.x = 0;
310 ptSrc.y = 0;
311
312 result = IntEngCopyBits(&psurfDst->SurfObj,
313 &psurfSrc->SurfObj,
314 NULL,
315 &exlo.xlo,
316 &rcDst,
317 &ptSrc);
318 if(result)
319 result = ScanLines;
320
321 EXLATEOBJ_vCleanup(&exlo);
322
323 cleanup:
324 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
325 if(psurfSrc) SURFACE_ShareUnlockSurface(psurfSrc);
326 if(psurfDst) SURFACE_ShareUnlockSurface(psurfDst);
327 GreDeleteObject(SourceBitmap);
328
329 return result;
330 }
331
332 static
333 HBITMAP
334 IntGdiCreateMaskFromRLE(
335 DWORD Width,
336 DWORD Height,
337 ULONG Compression,
338 const BYTE* Bits,
339 DWORD BitsSize)
340 {
341 HBITMAP Mask;
342 DWORD x, y;
343 SURFOBJ* SurfObj;
344 UINT i = 0;
345 BYTE Data, NumPixels, ToSkip;
346
347 ASSERT((Compression == BI_RLE8) || (Compression == BI_RLE4));
348
349 /* Create the bitmap */
350 Mask = GreCreateBitmapEx(Width, Height, 0, BMF_1BPP, 0, 0, NULL, 0);
351 if (!Mask)
352 return NULL;
353
354 SurfObj = EngLockSurface((HSURF)Mask);
355 if (!SurfObj)
356 {
357 GreDeleteObject(Mask);
358 return NULL;
359 }
360 ASSERT(SurfObj->pvBits != NULL);
361
362 x = y = 0;
363
364 while (i < BitsSize)
365 {
366 NumPixels = Bits[i];
367 Data = Bits[i + 1];
368 i += 2;
369
370 if (NumPixels != 0)
371 {
372 if ((x + NumPixels) > Width)
373 NumPixels = Width - x;
374
375 if (NumPixels == 0)
376 continue;
377
378 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
379 x += NumPixels;
380 continue;
381 }
382
383 if (Data < 3)
384 {
385 switch (Data)
386 {
387 case 0:
388 /* End of line */
389 y++;
390 if (y == Height)
391 goto done;
392 x = 0;
393 break;
394 case 1:
395 /* End of file */
396 goto done;
397 case 2:
398 /* Jump */
399 if (i >= (BitsSize - 1))
400 goto done;
401 x += Bits[i];
402 if (x > Width)
403 x = Width;
404 y += Bits[i + 1];
405 if (y >= Height)
406 goto done;
407 i += 2;
408 break;
409 }
410 /* Done for this run */
411 continue;
412 }
413
414 /* Embedded data into the RLE */
415 NumPixels = Data;
416 if (Compression == BI_RLE8)
417 ToSkip = NumPixels;
418 else
419 ToSkip = (NumPixels / 2) + (NumPixels & 1);
420
421 if ((i + ToSkip) > BitsSize)
422 goto done;
423 ToSkip = (ToSkip + 1) & ~1;
424
425 if ((x + NumPixels) > Width)
426 NumPixels = Width - x;
427
428 if (NumPixels != 0)
429 {
430 DIB_1BPP_HLine(SurfObj, x, x + NumPixels, y, 1);
431 x += NumPixels;
432 }
433 i += ToSkip;
434 }
435
436 done:
437 EngUnlockSurface(SurfObj);
438 return Mask;
439 }
440
441 W32KAPI
442 INT
443 APIENTRY
444 NtGdiSetDIBitsToDeviceInternal(
445 IN HDC hDC,
446 IN INT XDest,
447 IN INT YDest,
448 IN DWORD Width,
449 IN DWORD Height,
450 IN INT XSrc,
451 IN INT YSrc,
452 IN DWORD StartScan,
453 IN DWORD ScanLines,
454 IN LPBYTE Bits,
455 IN LPBITMAPINFO bmi,
456 IN DWORD ColorUse,
457 IN UINT cjMaxBits,
458 IN UINT cjMaxInfo,
459 IN BOOL bTransformCoordinates,
460 IN OPTIONAL HANDLE hcmXform)
461 {
462 INT ret = 0;
463 NTSTATUS Status = STATUS_SUCCESS;
464 PDC pDC;
465 HBITMAP hSourceBitmap = NULL, hMaskBitmap = NULL;
466 SURFOBJ *pDestSurf, *pSourceSurf = NULL, *pMaskSurf = NULL;
467 SURFACE *pSurf;
468 RECTL rcDest;
469 POINTL ptSource;
470 //INT DIBWidth;
471 SIZEL SourceSize;
472 EXLATEOBJ exlo;
473 PPALETTE ppalDIB = NULL;
474 LPBITMAPINFO pbmiSafe;
475
476 if (!Bits) return 0;
477
478 pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjMaxInfo, 'pmTG');
479 if (!pbmiSafe) return 0;
480
481 _SEH2_TRY
482 {
483 ProbeForRead(bmi, cjMaxInfo, 1);
484 ProbeForRead(Bits, cjMaxBits, 1);
485 RtlCopyMemory(pbmiSafe, bmi, cjMaxInfo);
486 bmi = pbmiSafe;
487 }
488 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
489 {
490 Status = _SEH2_GetExceptionCode();
491 }
492 _SEH2_END
493
494 if (!NT_SUCCESS(Status))
495 {
496 goto Exit2;
497 }
498
499 ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan);
500
501 pDC = DC_LockDc(hDC);
502 if (!pDC)
503 {
504 EngSetLastError(ERROR_INVALID_HANDLE);
505 goto Exit2;
506 }
507
508 if (pDC->dctype == DC_TYPE_INFO)
509 {
510 DC_UnlockDc(pDC);
511 goto Exit;
512 }
513
514 rcDest.left = XDest;
515 rcDest.top = YDest;
516 if (bTransformCoordinates)
517 {
518 IntLPtoDP(pDC, (LPPOINT)&rcDest, 2);
519 }
520 rcDest.left += pDC->ptlDCOrig.x;
521 rcDest.top += pDC->ptlDCOrig.y;
522 rcDest.right = rcDest.left + Width;
523 rcDest.bottom = rcDest.top + Height;
524 rcDest.top += StartScan;
525
526 ptSource.x = XSrc;
527 ptSource.y = YSrc;
528
529 SourceSize.cx = bmi->bmiHeader.biWidth;
530 SourceSize.cy = ScanLines;
531
532 //DIBWidth = WIDTH_BYTES_ALIGN32(SourceSize.cx, bmi->bmiHeader.biBitCount);
533
534 hSourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth,
535 ScanLines,
536 0,
537 BitmapFormat(bmi->bmiHeader.biBitCount,
538 bmi->bmiHeader.biCompression),
539 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
540 bmi->bmiHeader.biSizeImage,
541 Bits,
542 0);
543
544 if (!hSourceBitmap)
545 {
546 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
547 Status = STATUS_NO_MEMORY;
548 goto Exit;
549 }
550
551 pSourceSurf = EngLockSurface((HSURF)hSourceBitmap);
552 if (!pSourceSurf)
553 {
554 Status = STATUS_UNSUCCESSFUL;
555 goto Exit;
556 }
557
558 /* HACK: If this is a RLE bitmap, only the relevant pixels must be set. */
559 if ((bmi->bmiHeader.biCompression == BI_RLE8) || (bmi->bmiHeader.biCompression == BI_RLE4))
560 {
561 hMaskBitmap = IntGdiCreateMaskFromRLE(bmi->bmiHeader.biWidth,
562 ScanLines,
563 bmi->bmiHeader.biCompression,
564 Bits,
565 cjMaxBits);
566 if (!hMaskBitmap)
567 {
568 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
569 Status = STATUS_NO_MEMORY;
570 goto Exit;
571 }
572 pMaskSurf = EngLockSurface((HSURF)hMaskBitmap);
573 if (!pMaskSurf)
574 {
575 Status = STATUS_UNSUCCESSFUL;
576 goto Exit;
577 }
578 }
579
580 /* Create a palette for the DIB */
581 ppalDIB = CreateDIBPalette(bmi, pDC, ColorUse);
582 if (!ppalDIB)
583 {
584 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
585 Status = STATUS_NO_MEMORY;
586 goto Exit;
587 }
588
589 /* This is actually a blit */
590 DC_vPrepareDCsForBlit(pDC, &rcDest, NULL, NULL);
591 pSurf = pDC->dclevel.pSurface;
592 if (!pSurf)
593 {
594 DC_vFinishBlit(pDC, NULL);
595 ret = ScanLines;
596 goto Exit;
597 }
598
599 ASSERT(pSurf->ppal);
600
601 /* Initialize EXLATEOBJ */
602 EXLATEOBJ_vInitialize(&exlo,
603 ppalDIB,
604 pSurf->ppal,
605 RGB(0xff, 0xff, 0xff),
606 pDC->pdcattr->crBackgroundClr,
607 pDC->pdcattr->crForegroundClr);
608
609 pDestSurf = &pSurf->SurfObj;
610
611 /* Copy the bits */
612 DPRINT("BitsToDev with dstsurf=(%d|%d) (%d|%d), src=(%d|%d) w=%d h=%d\n",
613 rcDest.left, rcDest.top, rcDest.right, rcDest.bottom,
614 ptSource.x, ptSource.y, SourceSize.cx, SourceSize.cy);
615 Status = IntEngBitBlt(pDestSurf,
616 pSourceSurf,
617 pMaskSurf,
618 &pDC->co.ClipObj,
619 &exlo.xlo,
620 &rcDest,
621 &ptSource,
622 pMaskSurf ? &ptSource : NULL,
623 NULL,
624 NULL,
625 pMaskSurf ? ROP4_MASK : ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
626
627 /* Cleanup EXLATEOBJ */
628 EXLATEOBJ_vCleanup(&exlo);
629
630 /* We're done */
631 DC_vFinishBlit(pDC, NULL);
632
633 Exit:
634 if (NT_SUCCESS(Status))
635 {
636 ret = ScanLines;
637 }
638
639 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
640
641 if (pSourceSurf) EngUnlockSurface(pSourceSurf);
642 if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
643 if (pMaskSurf) EngUnlockSurface(pMaskSurf);
644 if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap);
645 DC_UnlockDc(pDC);
646 Exit2:
647 ExFreePoolWithTag(pbmiSafe, 'pmTG');
648 return ret;
649 }
650
651
652 /* Converts a device-dependent bitmap to a DIB */
653 INT
654 APIENTRY
655 GreGetDIBitsInternal(
656 HDC hDC,
657 HBITMAP hBitmap,
658 UINT StartScan,
659 UINT ScanLines,
660 LPBYTE Bits,
661 LPBITMAPINFO Info,
662 UINT Usage,
663 UINT MaxBits,
664 UINT MaxInfo)
665 {
666 BITMAPCOREINFO* pbmci = NULL;
667 PSURFACE psurf = NULL;
668 PDC pDC;
669 LONG width, height;
670 WORD planes, bpp;
671 DWORD compr, size ;
672 USHORT i;
673 int bitmap_type;
674 RGBQUAD* rgbQuads;
675 VOID* colorPtr;
676
677 DPRINT("Entered NtGdiGetDIBitsInternal()\n");
678
679 if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap)
680 return 0;
681
682 colorPtr = (LPBYTE)Info + Info->bmiHeader.biSize;
683 rgbQuads = colorPtr;
684
685 bitmap_type = DIB_GetBitmapInfo(&Info->bmiHeader,
686 &width,
687 &height,
688 &planes,
689 &bpp,
690 &compr,
691 &size);
692 if(bitmap_type == -1)
693 {
694 DPRINT("Wrong bitmap format\n");
695 EngSetLastError(ERROR_INVALID_PARAMETER);
696 return 0;
697 }
698 else if(bitmap_type == 0)
699 {
700 /* We need a BITMAPINFO to create a DIB, but we have to fill
701 * the BITMAPCOREINFO we're provided */
702 pbmci = (BITMAPCOREINFO*)Info;
703 Info = DIB_ConvertBitmapInfo((BITMAPINFO*)pbmci, Usage);
704 if(Info == NULL)
705 {
706 DPRINT1("Error, could not convert the BITMAPCOREINFO!\n");
707 return 0;
708 }
709 rgbQuads = Info->bmiColors;
710 }
711
712 pDC = DC_LockDc(hDC);
713 if (pDC == NULL || pDC->dctype == DC_TYPE_INFO)
714 {
715 ScanLines = 0;
716 goto done;
717 }
718
719 /* Get a pointer to the source bitmap object */
720 psurf = SURFACE_ShareLockSurface(hBitmap);
721 if (psurf == NULL)
722 {
723 ScanLines = 0;
724 goto done;
725 }
726
727 /* Fill in the structure */
728 switch(bpp)
729 {
730 case 0: /* Only info */
731 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
732 Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ?
733 -psurf->SurfObj.sizlBitmap.cy :
734 psurf->SurfObj.sizlBitmap.cy;;
735 Info->bmiHeader.biPlanes = 1;
736 Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
737 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( Info->bmiHeader.biWidth,
738 Info->bmiHeader.biHeight,
739 Info->bmiHeader.biBitCount);
740 if(psurf->hSecure)
741 {
742 switch(Info->bmiHeader.biBitCount)
743 {
744 case 16:
745 case 32:
746 Info->bmiHeader.biCompression = BI_BITFIELDS;
747 break;
748 default:
749 Info->bmiHeader.biCompression = BI_RGB;
750 break;
751 }
752 }
753 else if(Info->bmiHeader.biBitCount > 8)
754 {
755 Info->bmiHeader.biCompression = BI_BITFIELDS;
756 }
757 else
758 {
759 Info->bmiHeader.biCompression = BI_RGB;
760 }
761 Info->bmiHeader.biXPelsPerMeter = 0;
762 Info->bmiHeader.biYPelsPerMeter = 0;
763 Info->bmiHeader.biClrUsed = 0;
764 Info->bmiHeader.biClrImportant = 0;
765 ScanLines = abs(Info->bmiHeader.biHeight);
766 goto done;
767
768 case 1:
769 case 4:
770 case 8:
771 Info->bmiHeader.biClrUsed = 0;
772
773 /* If the bitmap if a DIB section and has the same format than what
774 * we're asked, go ahead! */
775 if((psurf->hSecure) &&
776 (BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bpp))
777 {
778 if(Usage == DIB_RGB_COLORS)
779 {
780 ULONG colors = min(psurf->ppal->NumColors, 256);
781 if(colors != 256) Info->bmiHeader.biClrUsed = colors;
782 for(i = 0; i < colors; i++)
783 {
784 rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed;
785 rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen;
786 rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue;
787 rgbQuads[i].rgbReserved = 0;
788 }
789 }
790 else
791 {
792 for(i = 0; i < 256; i++)
793 ((WORD*)rgbQuads)[i] = i;
794 }
795 }
796 else
797 {
798 if(Usage == DIB_PAL_COLORS)
799 {
800 for(i = 0; i < 256; i++)
801 {
802 ((WORD*)rgbQuads)[i] = i;
803 }
804 }
805 else if(bpp > 1 && bpp == BitsPerFormat(psurf->SurfObj.iBitmapFormat))
806 {
807 /* For color DDBs in native depth (mono DDBs always have
808 a black/white palette):
809 Generate the color map from the selected palette */
810 PPALETTE pDcPal = PALETTE_ShareLockPalette(pDC->dclevel.hpal);
811 if(!pDcPal)
812 {
813 ScanLines = 0 ;
814 goto done ;
815 }
816 for (i = 0; i < pDcPal->NumColors; i++)
817 {
818 rgbQuads[i].rgbRed = pDcPal->IndexedColors[i].peRed;
819 rgbQuads[i].rgbGreen = pDcPal->IndexedColors[i].peGreen;
820 rgbQuads[i].rgbBlue = pDcPal->IndexedColors[i].peBlue;
821 rgbQuads[i].rgbReserved = 0;
822 }
823 PALETTE_ShareUnlockPalette(pDcPal);
824 }
825 else
826 {
827 switch (bpp)
828 {
829 case 1:
830 rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0;
831 rgbQuads[0].rgbReserved = 0;
832 rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff;
833 rgbQuads[1].rgbReserved = 0;
834 break;
835
836 case 4:
837 RtlCopyMemory(rgbQuads, EGAColorsQuads, sizeof(EGAColorsQuads));
838 break;
839
840 case 8:
841 {
842 INT r, g, b;
843 RGBQUAD *color;
844 memcpy(rgbQuads, DefLogPaletteQuads,
845 10 * sizeof(RGBQUAD));
846 memcpy(rgbQuads + 246, DefLogPaletteQuads + 10,
847 10 * sizeof(RGBQUAD));
848 color = rgbQuads + 10;
849 for(r = 0; r <= 5; r++) /* FIXME */
850 {
851 for(g = 0; g <= 5; g++)
852 {
853 for(b = 0; b <= 5; b++)
854 {
855 color->rgbRed = (r * 0xff) / 5;
856 color->rgbGreen = (g * 0xff) / 5;
857 color->rgbBlue = (b * 0xff) / 5;
858 color->rgbReserved = 0;
859 color++;
860 }
861 }
862 }
863 }
864 }
865 }
866 }
867 break;
868
869 case 15:
870 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
871 {
872 ((PDWORD)Info->bmiColors)[0] = 0x7c00;
873 ((PDWORD)Info->bmiColors)[1] = 0x03e0;
874 ((PDWORD)Info->bmiColors)[2] = 0x001f;
875 }
876 break;
877
878 case 16:
879 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
880 {
881 if (psurf->hSecure)
882 {
883 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
884 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
885 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
886 }
887 else
888 {
889 ((PDWORD)Info->bmiColors)[0] = 0xf800;
890 ((PDWORD)Info->bmiColors)[1] = 0x07e0;
891 ((PDWORD)Info->bmiColors)[2] = 0x001f;
892 }
893 }
894 break;
895
896 case 24:
897 case 32:
898 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
899 {
900 if (psurf->hSecure)
901 {
902 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
903 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
904 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
905 }
906 else
907 {
908 ((PDWORD)Info->bmiColors)[0] = 0xff0000;
909 ((PDWORD)Info->bmiColors)[1] = 0x00ff00;
910 ((PDWORD)Info->bmiColors)[2] = 0x0000ff;
911 }
912 }
913 break;
914 }
915 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(width, height, bpp);
916
917 if(Bits && ScanLines)
918 {
919 /* Create a DIBSECTION, blt it, profit */
920 PVOID pDIBits ;
921 HBITMAP hBmpDest;
922 PSURFACE psurfDest;
923 EXLATEOBJ exlo;
924 RECT rcDest;
925 POINTL srcPoint;
926 BOOL ret ;
927
928 if (StartScan > (ULONG)psurf->SurfObj.sizlBitmap.cy)
929 {
930 ScanLines = 0;
931 goto done;
932 }
933 else
934 {
935 ScanLines = min(ScanLines, psurf->SurfObj.sizlBitmap.cy - StartScan);
936 }
937
938 /* Fixup values */
939 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
940 Info->bmiHeader.biHeight = (height < 0) ?
941 -(LONG)ScanLines : ScanLines;
942 /* Create the DIB */
943 hBmpDest = DIB_CreateDIBSection(pDC, Info, Usage, &pDIBits, NULL, 0, 0);
944 /* Restore them */
945 Info->bmiHeader.biWidth = width;
946 Info->bmiHeader.biHeight = height;
947
948 if(!hBmpDest)
949 {
950 DPRINT1("Unable to create a DIB Section!\n");
951 EngSetLastError(ERROR_INVALID_PARAMETER);
952 ScanLines = 0;
953 goto done ;
954 }
955
956 psurfDest = SURFACE_ShareLockSurface(hBmpDest);
957
958 RECTL_vSetRect(&rcDest, 0, 0, psurf->SurfObj.sizlBitmap.cx, ScanLines);
959
960 srcPoint.x = 0;
961
962 if(height < 0)
963 {
964 srcPoint.y = 0;
965
966 if(ScanLines <= StartScan)
967 {
968 ScanLines = 1;
969 SURFACE_ShareUnlockSurface(psurfDest);
970 GreDeleteObject(hBmpDest);
971 goto done;
972 }
973
974 ScanLines -= StartScan;
975 }
976 else
977 {
978 srcPoint.y = StartScan;
979 }
980
981 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xffffff, 0xffffff, 0);
982
983 ret = IntEngCopyBits(&psurfDest->SurfObj,
984 &psurf->SurfObj,
985 NULL,
986 &exlo.xlo,
987 &rcDest,
988 &srcPoint);
989
990 SURFACE_ShareUnlockSurface(psurfDest);
991
992 if(!ret)
993 ScanLines = 0;
994 else
995 {
996 RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, ScanLines, bpp));
997 }
998
999 GreDeleteObject(hBmpDest);
1000 EXLATEOBJ_vCleanup(&exlo);
1001 }
1002 else ScanLines = abs(height);
1003
1004 done:
1005
1006 if(pDC) DC_UnlockDc(pDC);
1007 if(psurf) SURFACE_ShareUnlockSurface(psurf);
1008 if(pbmci) DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci, Usage);
1009
1010 return ScanLines;
1011 }
1012
1013 INT
1014 APIENTRY
1015 NtGdiGetDIBitsInternal(
1016 _In_ HDC hdc,
1017 _In_ HBITMAP hbm,
1018 _In_ UINT iStartScan,
1019 _In_ UINT cScans,
1020 _Out_opt_ LPBYTE pjBits,
1021 _Inout_ LPBITMAPINFO pbmiUser,
1022 _In_ UINT iUsage,
1023 _In_ UINT cjMaxBits,
1024 _In_ UINT cjMaxInfo)
1025 {
1026 PBITMAPINFO pbmi;
1027 HANDLE hSecure = NULL;
1028 INT iResult = 0;
1029 UINT cjAlloc;
1030
1031 /* Check for bad iUsage */
1032 if (iUsage > 2) return 0;
1033
1034 /* Check if the size of the bitmap info is large enough */
1035 if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
1036 {
1037 return 0;
1038 }
1039
1040 /* Use maximum size */
1041 cjMaxInfo = min(cjMaxInfo, sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD));
1042
1043 // HACK: the underlying code sucks and doesn't care for the size, so we
1044 // give it the maximum ever needed
1045 cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
1046
1047 /* Allocate a buffer the bitmapinfo */
1048 pbmi = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
1049 if (!pbmi)
1050 {
1051 /* Fail */
1052 return 0;
1053 }
1054
1055 /* Use SEH */
1056 _SEH2_TRY
1057 {
1058 /* Probe and copy the BITMAPINFO */
1059 ProbeForRead(pbmiUser, cjMaxInfo, 1);
1060 RtlCopyMemory(pbmi, pbmiUser, cjMaxInfo);
1061 }
1062 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1063 {
1064 _SEH2_YIELD(goto cleanup;)
1065 }
1066 _SEH2_END;
1067
1068 /* Check if the header size is large enough */
1069 if ((pbmi->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
1070 (pbmi->bmiHeader.biSize > cjMaxInfo))
1071 {
1072 goto cleanup;
1073 }
1074
1075 /* Check if the caller provided bitmap bits */
1076 if (pjBits)
1077 {
1078 /* Secure the user mode memory */
1079 hSecure = EngSecureMem(pjBits, cjMaxBits);
1080 if (!hSecure)
1081 {
1082 goto cleanup;
1083 }
1084 }
1085
1086 /* Now call the internal function */
1087 iResult = GreGetDIBitsInternal(hdc,
1088 hbm,
1089 iStartScan,
1090 cScans,
1091 pjBits,
1092 pbmi,
1093 iUsage,
1094 cjMaxBits,
1095 cjMaxInfo);
1096
1097 /* Check for success */
1098 if (iResult)
1099 {
1100 /* Use SEH to copy back to user mode */
1101 _SEH2_TRY
1102 {
1103 /* Copy the data back */
1104 ProbeForWrite(pbmiUser, cjMaxInfo, 1);
1105 RtlCopyMemory(pbmiUser, pbmi, cjMaxInfo);
1106 }
1107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1108 {
1109 /* Ignore */
1110 }
1111 _SEH2_END;
1112 }
1113
1114 cleanup:
1115 if (hSecure) EngUnsecureMem(hSecure);
1116 ExFreePoolWithTag(pbmi, 'imBG');
1117
1118 return iResult;
1119 }
1120
1121
1122 #define ROP_TO_ROP4(Rop) ((Rop) >> 16)
1123
1124 W32KAPI
1125 INT
1126 APIENTRY
1127 NtGdiStretchDIBitsInternal(
1128 IN HDC hdc,
1129 IN INT xDst,
1130 IN INT yDst,
1131 IN INT cxDst,
1132 IN INT cyDst,
1133 IN INT xSrc,
1134 IN INT ySrc,
1135 IN INT cxSrc,
1136 IN INT cySrc,
1137 IN OPTIONAL LPBYTE pjInit,
1138 IN LPBITMAPINFO pbmi,
1139 IN DWORD dwUsage,
1140 IN DWORD dwRop, // MS ntgdi.h says dwRop4(?)
1141 IN UINT cjMaxInfo,
1142 IN UINT cjMaxBits,
1143 IN HANDLE hcmXform)
1144 {
1145 BOOL bResult = FALSE;
1146 SIZEL sizel;
1147 RECTL rcSrc, rcDst;
1148 PDC pdc;
1149 HBITMAP hbmTmp = 0;
1150 PSURFACE psurfTmp = 0, psurfDst = 0;
1151 PPALETTE ppalDIB = 0;
1152 EXLATEOBJ exlo;
1153 PVOID pvBits;
1154
1155 if (!(pdc = DC_LockDc(hdc)))
1156 {
1157 EngSetLastError(ERROR_INVALID_HANDLE);
1158 return 0;
1159 }
1160
1161 /* Check for info / mem DC without surface */
1162 if (!pdc->dclevel.pSurface)
1163 {
1164 DC_UnlockDc(pdc);
1165 // CHECKME
1166 return TRUE;
1167 }
1168
1169 /* Transform dest size */
1170 sizel.cx = cxDst;
1171 sizel.cy = cyDst;
1172 IntLPtoDP(pdc, (POINTL*)&sizel, 1);
1173 DC_UnlockDc(pdc);
1174
1175 /* Check if we can use NtGdiSetDIBitsToDeviceInternal */
1176 if (sizel.cx == cxSrc && sizel.cy == cySrc && dwRop == SRCCOPY)
1177 {
1178 /* Yes, we can! */
1179 return NtGdiSetDIBitsToDeviceInternal(hdc,
1180 xDst,
1181 yDst,
1182 cxDst,
1183 cyDst,
1184 xSrc,
1185 ySrc,
1186 0,
1187 cySrc,
1188 pjInit,
1189 pbmi,
1190 dwUsage,
1191 cjMaxBits,
1192 cjMaxInfo,
1193 TRUE,
1194 hcmXform);
1195 }
1196
1197 if (pjInit && (cjMaxBits > 0))
1198 {
1199 pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT');
1200 if (!pvBits)
1201 {
1202 return 0;
1203 }
1204
1205 _SEH2_TRY
1206 {
1207 ProbeForRead(pjInit, cjMaxBits, 1);
1208 RtlCopyMemory(pvBits, pjInit, cjMaxBits);
1209 }
1210 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1211 {
1212 ExFreePoolWithTag(pvBits, 'pmeT');
1213 _SEH2_YIELD(return 0);
1214 }
1215 _SEH2_END
1216 }
1217 else
1218 {
1219 pvBits = NULL;
1220 }
1221
1222 /* FIXME: Locking twice is cheesy, coord tranlation in UM will fix it */
1223 if (!(pdc = DC_LockDc(hdc)))
1224 {
1225 DPRINT1("Could not lock dc\n");
1226 EngSetLastError(ERROR_INVALID_HANDLE);
1227 goto cleanup;
1228 }
1229
1230 /* Calculate source and destination rect */
1231 rcSrc.left = xSrc;
1232 rcSrc.top = ySrc;
1233 rcSrc.right = xSrc + abs(cxSrc);
1234 rcSrc.bottom = ySrc + abs(cySrc);
1235 rcDst.left = xDst;
1236 rcDst.top = yDst;
1237 rcDst.right = rcDst.left + cxDst;
1238 rcDst.bottom = rcDst.top + cyDst;
1239 IntLPtoDP(pdc, (POINTL*)&rcDst, 2);
1240 RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
1241
1242 hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth,
1243 pbmi->bmiHeader.biHeight,
1244 0,
1245 BitmapFormat(pbmi->bmiHeader.biBitCount,
1246 pbmi->bmiHeader.biCompression),
1247 pbmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
1248 pbmi->bmiHeader.biSizeImage,
1249 pvBits,
1250 0);
1251
1252 if (!hbmTmp)
1253 {
1254 bResult = FALSE;
1255 goto cleanup;
1256 }
1257
1258 psurfTmp = SURFACE_ShareLockSurface(hbmTmp);
1259 if (!psurfTmp)
1260 {
1261 bResult = FALSE;
1262 goto cleanup;
1263 }
1264
1265 /* Create a palette for the DIB */
1266 ppalDIB = CreateDIBPalette(pbmi, pdc, dwUsage);
1267 if (!ppalDIB)
1268 {
1269 bResult = FALSE;
1270 goto cleanup;
1271 }
1272
1273 /* Prepare DC for blit */
1274 DC_vPrepareDCsForBlit(pdc, &rcDst, NULL, NULL);
1275
1276 psurfDst = pdc->dclevel.pSurface;
1277
1278 /* Initialize XLATEOBJ */
1279 EXLATEOBJ_vInitialize(&exlo,
1280 ppalDIB,
1281 psurfDst->ppal,
1282 RGB(0xff, 0xff, 0xff),
1283 pdc->pdcattr->crBackgroundClr,
1284 pdc->pdcattr->crForegroundClr);
1285
1286 /* Perform the stretch operation */
1287 bResult = IntEngStretchBlt(&psurfDst->SurfObj,
1288 &psurfTmp->SurfObj,
1289 NULL,
1290 &pdc->co.ClipObj,
1291 &exlo.xlo,
1292 &pdc->dclevel.ca,
1293 &rcDst,
1294 &rcSrc,
1295 NULL,
1296 &pdc->eboFill.BrushObject,
1297 NULL,
1298 ROP_TO_ROP4(dwRop));
1299
1300 /* Cleanup */
1301 DC_vFinishBlit(pdc, NULL);
1302 EXLATEOBJ_vCleanup(&exlo);
1303 cleanup:
1304 if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
1305 if (psurfTmp) SURFACE_ShareUnlockSurface(psurfTmp);
1306 if (hbmTmp) GreDeleteObject(hbmTmp);
1307 if (pdc) DC_UnlockDc(pdc);
1308 if (pvBits) ExFreePoolWithTag(pvBits, 'pmeT');
1309
1310 return bResult;
1311 }
1312
1313
1314 HBITMAP
1315 FASTCALL
1316 IntCreateDIBitmap(
1317 PDC Dc,
1318 INT width,
1319 INT height,
1320 UINT bpp,
1321 DWORD init,
1322 LPBYTE bits,
1323 PBITMAPINFO data,
1324 DWORD coloruse)
1325 {
1326 HBITMAP handle;
1327 BOOL fColor;
1328
1329 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
1330 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
1331
1332 if (bpp != 1) fColor = TRUE;
1333 else if ((coloruse != DIB_RGB_COLORS) || (init != CBM_INIT) || !data) fColor = FALSE;
1334 else
1335 {
1336 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize);
1337 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1338
1339 // Check if the first color of the colormap is black
1340 if (col == RGB(0, 0, 0))
1341 {
1342 rgb++;
1343 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1344
1345 // If the second color is white, create a monochrome bitmap
1346 fColor = (col != RGB(0xff,0xff,0xff));
1347 }
1348 else fColor = TRUE;
1349 }
1350
1351 // Now create the bitmap
1352 if (fColor)
1353 {
1354 handle = IntCreateCompatibleBitmap(Dc, width, height);
1355 }
1356 else
1357 {
1358 handle = GreCreateBitmap(width,
1359 height,
1360 1,
1361 1,
1362 NULL);
1363 }
1364
1365 if (height < 0)
1366 height = -height;
1367
1368 if (NULL != handle && CBM_INIT == init)
1369 {
1370 IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
1371 }
1372
1373 return handle;
1374 }
1375
1376 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1377 // The DDB that is created will be whatever bit depth your reference DC is
1378 HBITMAP
1379 APIENTRY
1380 NtGdiCreateDIBitmapInternal(
1381 IN HDC hDc,
1382 IN INT cx,
1383 IN INT cy,
1384 IN DWORD fInit,
1385 IN OPTIONAL LPBYTE pjInit,
1386 IN OPTIONAL LPBITMAPINFO pbmi,
1387 IN DWORD iUsage,
1388 IN UINT cjMaxInitInfo,
1389 IN UINT cjMaxBits,
1390 IN FLONG fl,
1391 IN HANDLE hcmXform)
1392 {
1393 NTSTATUS Status = STATUS_SUCCESS;
1394 PBYTE safeBits = NULL;
1395 HBITMAP hbmResult = NULL;
1396
1397 if(pjInit && (fInit == CBM_INIT))
1398 {
1399 if (cjMaxBits == 0) return NULL;
1400 safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1401 if(!safeBits)
1402 {
1403 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1404 return NULL;
1405 }
1406 }
1407
1408 _SEH2_TRY
1409 {
1410 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1);
1411 if(pjInit && (fInit == CBM_INIT))
1412 {
1413 ProbeForRead(pjInit, cjMaxBits, 1);
1414 RtlCopyMemory(safeBits, pjInit, cjMaxBits);
1415 }
1416 }
1417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1418 {
1419 Status = _SEH2_GetExceptionCode();
1420 }
1421 _SEH2_END
1422
1423 if(!NT_SUCCESS(Status))
1424 {
1425 SetLastNtError(Status);
1426 goto cleanup;
1427 }
1428
1429 hbmResult = GreCreateDIBitmapInternal(hDc,
1430 cx,
1431 cy,
1432 fInit,
1433 safeBits,
1434 pbmi,
1435 iUsage,
1436 fl,
1437 cjMaxBits,
1438 hcmXform);
1439
1440 cleanup:
1441 if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB);
1442 return hbmResult;
1443 }
1444
1445 HBITMAP
1446 NTAPI
1447 GreCreateDIBitmapInternal(
1448 IN HDC hDc,
1449 IN INT cx,
1450 IN INT cy,
1451 IN DWORD fInit,
1452 IN OPTIONAL LPBYTE pjInit,
1453 IN OPTIONAL PBITMAPINFO pbmi,
1454 IN DWORD iUsage,
1455 IN FLONG fl,
1456 IN UINT cjMaxBits,
1457 IN HANDLE hcmXform)
1458 {
1459 PDC Dc;
1460 HBITMAP Bmp;
1461 WORD bpp;
1462 HDC hdcDest;
1463
1464 if (!hDc) /* 1bpp monochrome bitmap */
1465 {
1466 // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1467 hdcDest = NtGdiCreateCompatibleDC(0);
1468 if(!hdcDest)
1469 {
1470 return NULL;
1471 }
1472 }
1473 else
1474 {
1475 hdcDest = hDc;
1476 }
1477
1478 Dc = DC_LockDc(hdcDest);
1479 if (!Dc)
1480 {
1481 EngSetLastError(ERROR_INVALID_HANDLE);
1482 return NULL;
1483 }
1484 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
1485 * if bpp != 1 and ignore the real value that was passed */
1486 if (pbmi)
1487 bpp = pbmi->bmiHeader.biBitCount;
1488 else
1489 bpp = 0;
1490 Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, fInit, pjInit, pbmi, iUsage);
1491 DC_UnlockDc(Dc);
1492
1493 if(!hDc)
1494 {
1495 NtGdiDeleteObjectApp(hdcDest);
1496 }
1497 return Bmp;
1498 }
1499
1500
1501 HBITMAP
1502 APIENTRY
1503 NtGdiCreateDIBSection(
1504 IN HDC hDC,
1505 IN OPTIONAL HANDLE hSection,
1506 IN DWORD dwOffset,
1507 IN BITMAPINFO* bmi,
1508 IN DWORD Usage,
1509 IN UINT cjHeader,
1510 IN FLONG fl,
1511 IN ULONG_PTR dwColorSpace,
1512 OUT PVOID *Bits)
1513 {
1514 HBITMAP hbitmap = 0;
1515 DC *dc;
1516 BOOL bDesktopDC = FALSE;
1517 NTSTATUS Status = STATUS_SUCCESS;
1518
1519 if (!bmi) return hbitmap; // Make sure.
1520
1521 _SEH2_TRY
1522 {
1523 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1);
1524 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1);
1525 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, (WORD)Usage), 1);
1526 }
1527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1528 {
1529 Status = _SEH2_GetExceptionCode();
1530 }
1531 _SEH2_END
1532
1533 if(!NT_SUCCESS(Status))
1534 {
1535 SetLastNtError(Status);
1536 return NULL;
1537 }
1538
1539 // If the reference hdc is null, take the desktop dc
1540 if (hDC == 0)
1541 {
1542 hDC = NtGdiCreateCompatibleDC(0);
1543 bDesktopDC = TRUE;
1544 }
1545
1546 if ((dc = DC_LockDc(hDC)))
1547 {
1548 hbitmap = DIB_CreateDIBSection(dc,
1549 bmi,
1550 Usage,
1551 Bits,
1552 hSection,
1553 dwOffset,
1554 0);
1555 DC_UnlockDc(dc);
1556 }
1557 else
1558 {
1559 EngSetLastError(ERROR_INVALID_HANDLE);
1560 }
1561
1562 if (bDesktopDC)
1563 NtGdiDeleteObjectApp(hDC);
1564
1565 return hbitmap;
1566 }
1567
1568 HBITMAP
1569 APIENTRY
1570 DIB_CreateDIBSection(
1571 PDC dc,
1572 CONST BITMAPINFO *bmi,
1573 UINT usage,
1574 LPVOID *bits,
1575 HANDLE section,
1576 DWORD offset,
1577 DWORD ovr_pitch)
1578 {
1579 HBITMAP res = 0;
1580 SURFACE *bmp = NULL;
1581 void *mapBits = NULL;
1582 PPALETTE ppalDIB = NULL;
1583
1584 // Fill BITMAP32 structure with DIB data
1585 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1586 INT effHeight;
1587 ULONG totalSize;
1588 BITMAP bm;
1589 //SIZEL Size;
1590 HANDLE hSecure;
1591
1592 DPRINT("format (%ld,%ld), planes %u, bpp %u, size %lu, colors %lu (%s)\n",
1593 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1594 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1595
1596 /* CreateDIBSection should fail for compressed formats */
1597 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1598 {
1599 DPRINT1("no compressed format allowed\n");
1600 return (HBITMAP)NULL;
1601 }
1602
1603 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1604 bm.bmType = 0;
1605 bm.bmWidth = bi->biWidth;
1606 bm.bmHeight = effHeight;
1607 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount);
1608
1609 bm.bmPlanes = bi->biPlanes;
1610 bm.bmBitsPixel = bi->biBitCount;
1611 bm.bmBits = NULL;
1612
1613 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
1614 // we're dealing with a compressed bitmap. Otherwise, use width * height.
1615 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB && bi->biCompression != BI_BITFIELDS
1616 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1617
1618 if (section)
1619 {
1620 SYSTEM_BASIC_INFORMATION Sbi;
1621 NTSTATUS Status;
1622 DWORD mapOffset;
1623 LARGE_INTEGER SectionOffset;
1624 SIZE_T mapSize;
1625
1626 Status = ZwQuerySystemInformation(SystemBasicInformation,
1627 &Sbi,
1628 sizeof Sbi,
1629 0);
1630 if (!NT_SUCCESS(Status))
1631 {
1632 DPRINT1("ZwQuerySystemInformation failed (0x%lx)\n", Status);
1633 return NULL;
1634 }
1635
1636 mapOffset = offset - (offset % Sbi.AllocationGranularity);
1637 mapSize = bi->biSizeImage + (offset - mapOffset);
1638
1639 SectionOffset.LowPart = mapOffset;
1640 SectionOffset.HighPart = 0;
1641
1642 Status = ZwMapViewOfSection(section,
1643 NtCurrentProcess(),
1644 &mapBits,
1645 0,
1646 0,
1647 &SectionOffset,
1648 &mapSize,
1649 ViewShare,
1650 0,
1651 PAGE_READWRITE);
1652 if (!NT_SUCCESS(Status))
1653 {
1654 DPRINT1("ZwMapViewOfSection failed (0x%lx)\n", Status);
1655 EngSetLastError(ERROR_INVALID_PARAMETER);
1656 return NULL;
1657 }
1658
1659 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
1660 }
1661 else if (ovr_pitch && offset)
1662 bm.bmBits = (LPVOID) offset;
1663 else
1664 {
1665 offset = 0;
1666 bm.bmBits = EngAllocUserMem(totalSize, 0);
1667 if(!bm.bmBits)
1668 {
1669 DPRINT1("Failed to allocate memory\n");
1670 goto cleanup;
1671 }
1672 }
1673
1674 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
1675 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
1676
1677
1678 // Create Device Dependent Bitmap and add DIB pointer
1679 //Size.cx = bm.bmWidth;
1680 //Size.cy = abs(bm.bmHeight);
1681 res = GreCreateBitmapEx(bm.bmWidth,
1682 abs(bm.bmHeight),
1683 bm.bmWidthBytes,
1684 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
1685 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
1686 ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
1687 bi->biSizeImage,
1688 bm.bmBits,
1689 0);
1690 if (!res)
1691 {
1692 DPRINT1("GreCreateBitmapEx failed\n");
1693 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
1694 goto cleanup;
1695 }
1696 bmp = SURFACE_ShareLockSurface(res); // HACK
1697 if (NULL == bmp)
1698 {
1699 DPRINT1("SURFACE_LockSurface failed\n");
1700 EngSetLastError(ERROR_INVALID_HANDLE);
1701 goto cleanup;
1702 }
1703
1704 /* WINE NOTE: WINE makes use of a colormap, which is a color translation
1705 table between the DIB and the X physical device. Obviously,
1706 this is left out of the ReactOS implementation. Instead,
1707 we call NtGdiSetDIBColorTable. */
1708 bmp->hDIBSection = section;
1709 bmp->hSecure = hSecure;
1710 bmp->dwOffset = offset;
1711 bmp->flags = API_BITMAP;
1712 bmp->biClrImportant = bi->biClrImportant;
1713
1714 /* Create a palette for the DIB */
1715 ppalDIB = CreateDIBPalette(bmi, dc, usage);
1716
1717 // Clean up in case of errors
1718 cleanup:
1719 if (!res || !bmp || !bm.bmBits || !ppalDIB)
1720 {
1721 DPRINT("Got an error res=%p, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
1722 if (bm.bmBits)
1723 {
1724 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
1725 if (section)
1726 {
1727 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
1728 bm.bmBits = NULL;
1729 }
1730 else if (!offset)
1731 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
1732 }
1733
1734 if (bmp)
1735 {
1736 SURFACE_ShareUnlockSurface(bmp);
1737 bmp = NULL;
1738 }
1739
1740 if (res)
1741 {
1742 GreDeleteObject(res);
1743 res = 0;
1744 }
1745
1746 if(ppalDIB)
1747 {
1748 PALETTE_ShareUnlockPalette(ppalDIB);
1749 }
1750 }
1751
1752 if (bmp)
1753 {
1754 /* If we're here, everything went fine */
1755 SURFACE_vSetPalette(bmp, ppalDIB);
1756 PALETTE_ShareUnlockPalette(ppalDIB);
1757 SURFACE_ShareUnlockSurface(bmp);
1758 }
1759
1760 // Return BITMAP handle and storage location
1761 if (NULL != bm.bmBits && NULL != bits)
1762 {
1763 *bits = bm.bmBits;
1764 }
1765
1766 return res;
1767 }
1768
1769 /***********************************************************************
1770 * DIB_GetBitmapInfo
1771 *
1772 * Get the info from a bitmap header.
1773 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error.
1774 */
1775 int
1776 FASTCALL
1777 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
1778 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size )
1779 {
1780 if (header->biSize == sizeof(BITMAPCOREHEADER))
1781 {
1782 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
1783 *width = core->bcWidth;
1784 *height = core->bcHeight;
1785 *planes = core->bcPlanes;
1786 *bpp = core->bcBitCount;
1787 *compr = BI_RGB;
1788 *size = 0;
1789 return 0;
1790 }
1791 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* Assume BITMAPINFOHEADER */
1792 {
1793 *width = header->biWidth;
1794 *height = header->biHeight;
1795 *planes = header->biPlanes;
1796 *bpp = header->biBitCount;
1797 *compr = header->biCompression;
1798 *size = header->biSizeImage;
1799 return 1;
1800 }
1801 DPRINT1("(%u): unknown/wrong size for header\n", header->biSize );
1802 return -1;
1803 }
1804
1805 /***********************************************************************
1806 * DIB_GetDIBImageBytes
1807 *
1808 * Return the number of bytes used to hold the image in a DIB bitmap.
1809 * 11/16/1999 (RJJ) lifted from wine
1810 */
1811
1812 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth)
1813 {
1814 return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height);
1815 }
1816
1817 /***********************************************************************
1818 * DIB_BitmapInfoSize
1819 *
1820 * Return the size of the bitmap info structure including color table.
1821 * 11/16/1999 (RJJ) lifted from wine
1822 */
1823
1824 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
1825 {
1826 unsigned int colors, size, masks = 0;
1827
1828 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1829 {
1830 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
1831 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
1832 return sizeof(BITMAPCOREHEADER) + colors *
1833 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
1834 }
1835 else /* Assume BITMAPINFOHEADER */
1836 {
1837 colors = info->bmiHeader.biClrUsed;
1838 if (colors > 256) colors = 256;
1839 if (!colors && (info->bmiHeader.biBitCount <= 8))
1840 colors = 1 << info->bmiHeader.biBitCount;
1841 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
1842 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
1843 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
1844 }
1845 }
1846
1847 HPALETTE
1848 FASTCALL
1849 DIB_MapPaletteColors(PPALETTE ppalDc, CONST BITMAPINFO* lpbmi)
1850 {
1851 PPALETTE ppalNew;
1852 ULONG nNumColors,i;
1853 USHORT *lpIndex;
1854 HPALETTE hpal;
1855
1856 if (!(ppalDc->flFlags & PAL_INDEXED))
1857 {
1858 return NULL;
1859 }
1860
1861 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
1862 if (lpbmi->bmiHeader.biClrUsed)
1863 {
1864 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
1865 }
1866
1867 ppalNew = PALETTE_AllocPalWithHandle(PAL_INDEXED, nNumColors, NULL, 0, 0, 0);
1868 if (ppalNew == NULL)
1869 {
1870 DPRINT1("Could not allocate palette\n");
1871 return NULL;
1872 }
1873
1874 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize);
1875
1876 for (i = 0; i < nNumColors; i++)
1877 {
1878 ULONG iColorIndex = *lpIndex % ppalDc->NumColors;
1879 ppalNew->IndexedColors[i] = ppalDc->IndexedColors[iColorIndex];
1880 lpIndex++;
1881 }
1882
1883 hpal = ppalNew->BaseObject.hHmgr;
1884 PALETTE_UnlockPalette(ppalNew);
1885
1886 return hpal;
1887 }
1888
1889 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure,
1890 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */
1891 BITMAPINFO*
1892 FASTCALL
1893 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
1894 {
1895 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi;
1896 BITMAPINFO* pNewBmi ;
1897 UINT numColors = 0, ColorsSize = 0;
1898
1899 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi;
1900 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL;
1901
1902 if(pbmci->bmciHeader.bcBitCount <= 8)
1903 {
1904 numColors = 1 << pbmci->bmciHeader.bcBitCount;
1905 if(Usage == DIB_PAL_COLORS)
1906 {
1907 ColorsSize = numColors * sizeof(WORD);
1908 }
1909 else
1910 {
1911 ColorsSize = numColors * sizeof(RGBQUAD);
1912 }
1913 }
1914 else if (Usage == DIB_PAL_COLORS)
1915 {
1916 /* Invalid at high-res */
1917 return NULL;
1918 }
1919
1920 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB);
1921 if(!pNewBmi) return NULL;
1922
1923 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize);
1924
1925 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1926 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount;
1927 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth;
1928 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight;
1929 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes;
1930 pNewBmi->bmiHeader.biCompression = BI_RGB ;
1931 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth,
1932 pNewBmi->bmiHeader.biHeight,
1933 pNewBmi->bmiHeader.biBitCount);
1934
1935 if(Usage == DIB_PAL_COLORS)
1936 {
1937 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize);
1938 }
1939 else
1940 {
1941 UINT i;
1942 for(i=0; i<numColors; i++)
1943 {
1944 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed;
1945 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen;
1946 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue;
1947 }
1948 }
1949
1950 return pNewBmi ;
1951 }
1952
1953 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
1954 VOID
1955 FASTCALL
1956 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig, DWORD usage)
1957 {
1958 BITMAPCOREINFO* pbmci;
1959 if(converted == orig)
1960 return;
1961
1962 if(usage == -1)
1963 {
1964 /* Caller don't want any conversion */
1965 ExFreePoolWithTag(converted, TAG_DIB);
1966 return;
1967 }
1968
1969 /* Perform inverse conversion */
1970 pbmci = (BITMAPCOREINFO*)orig;
1971
1972 ASSERT(pbmci->bmciHeader.bcSize == sizeof(BITMAPCOREHEADER));
1973 pbmci->bmciHeader.bcBitCount = converted->bmiHeader.biBitCount;
1974 pbmci->bmciHeader.bcWidth = converted->bmiHeader.biWidth;
1975 pbmci->bmciHeader.bcHeight = converted->bmiHeader.biHeight;
1976 pbmci->bmciHeader.bcPlanes = converted->bmiHeader.biPlanes;
1977
1978 if(pbmci->bmciHeader.bcBitCount <= 8)
1979 {
1980 UINT numColors = converted->bmiHeader.biClrUsed;
1981 if(!numColors) numColors = 1 << pbmci->bmciHeader.bcBitCount;
1982 if(usage == DIB_PAL_COLORS)
1983 {
1984 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(WORD));
1985 RtlCopyMemory(pbmci->bmciColors, converted->bmiColors, numColors * sizeof(WORD));
1986 }
1987 else
1988 {
1989 UINT i;
1990 RtlZeroMemory(pbmci->bmciColors, (1 << pbmci->bmciHeader.bcBitCount) * sizeof(RGBTRIPLE));
1991 for(i=0; i<numColors; i++)
1992 {
1993 pbmci->bmciColors[i].rgbtRed = converted->bmiColors[i].rgbRed;
1994 pbmci->bmciColors[i].rgbtGreen = converted->bmiColors[i].rgbGreen;
1995 pbmci->bmciColors[i].rgbtBlue = converted->bmiColors[i].rgbBlue;
1996 }
1997 }
1998 }
1999 /* Now free it, it's not needed anymore */
2000 ExFreePoolWithTag(converted, TAG_DIB);
2001 }
2002
2003 /* EOF */