GetDIBits: destination height may be smaller than the source height, so the image...
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dibobj.c
1 /*
2 * $Id$
3 *
4 * ReactOS W32 Subsystem
5 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <w32k.h>
23
24 #define NDEBUG
25 #include <debug.h>
26
27 UINT STDCALL
28 IntSetDIBColorTable(HDC hDC, UINT StartIndex, UINT Entries, CONST RGBQUAD *Colors)
29 {
30 PDC dc;
31 PBITMAPOBJ BitmapObj;
32 PPALGDI PalGDI;
33 UINT Index;
34
35 if (!(dc = DC_LockDc(hDC))) return 0;
36 if (dc->DC_Type == DC_TYPE_INFO)
37 {
38 DC_UnlockDc(dc);
39 return 0;
40 }
41
42 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
43 if (BitmapObj == NULL)
44 {
45 DC_UnlockDc(dc);
46 SetLastWin32Error(ERROR_INVALID_PARAMETER);
47 return 0;
48 }
49
50 if (BitmapObj->dib == NULL)
51 {
52 BITMAPOBJ_UnlockBitmap(BitmapObj);
53 DC_UnlockDc(dc);
54 SetLastWin32Error(ERROR_INVALID_PARAMETER);
55 return 0;
56 }
57
58 if (BitmapObj->dib->dsBmih.biBitCount <= 8 &&
59 StartIndex < (1 << BitmapObj->dib->dsBmih.biBitCount))
60 {
61 if (StartIndex + Entries > (1 << BitmapObj->dib->dsBmih.biBitCount))
62 Entries = (1 << BitmapObj->dib->dsBmih.biBitCount) - StartIndex;
63
64 PalGDI = PALETTE_LockPalette(BitmapObj->hDIBPalette);
65 if (PalGDI == NULL)
66 {
67 BITMAPOBJ_UnlockBitmap(BitmapObj);
68 DC_UnlockDc(dc);
69 SetLastWin32Error(ERROR_INVALID_HANDLE);
70 return 0;
71 }
72
73 for (Index = StartIndex;
74 Index < StartIndex + Entries && Index < PalGDI->NumColors;
75 Index++)
76 {
77 PalGDI->IndexedColors[Index].peRed = Colors[Index - StartIndex].rgbRed;
78 PalGDI->IndexedColors[Index].peGreen = Colors[Index - StartIndex].rgbGreen;
79 PalGDI->IndexedColors[Index].peBlue = Colors[Index - StartIndex].rgbBlue;
80 }
81 PALETTE_UnlockPalette(PalGDI);
82 }
83 else
84 Entries = 0;
85
86 BITMAPOBJ_UnlockBitmap(BitmapObj);
87 DC_UnlockDc(dc);
88
89 return Entries;
90 }
91
92 UINT STDCALL
93 IntGetDIBColorTable(HDC hDC, UINT StartIndex, UINT Entries, RGBQUAD *Colors)
94 {
95 PDC dc;
96 PBITMAPOBJ BitmapObj;
97 PPALGDI PalGDI;
98 UINT Index;
99
100 if (!(dc = DC_LockDc(hDC))) return 0;
101 if (dc->DC_Type == DC_TYPE_INFO)
102 {
103 DC_UnlockDc(dc);
104 return 0;
105 }
106
107 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
108 if (BitmapObj == NULL)
109 {
110 DC_UnlockDc(dc);
111 SetLastWin32Error(ERROR_INVALID_PARAMETER);
112 return 0;
113 }
114
115 if (BitmapObj->dib == NULL)
116 {
117 BITMAPOBJ_UnlockBitmap(BitmapObj);
118 DC_UnlockDc(dc);
119 SetLastWin32Error(ERROR_INVALID_PARAMETER);
120 return 0;
121 }
122
123 if (BitmapObj->dib->dsBmih.biBitCount <= 8 &&
124 StartIndex < (1 << BitmapObj->dib->dsBmih.biBitCount))
125 {
126 if (StartIndex + Entries > (1 << BitmapObj->dib->dsBmih.biBitCount))
127 Entries = (1 << BitmapObj->dib->dsBmih.biBitCount) - StartIndex;
128
129 PalGDI = PALETTE_LockPalette(BitmapObj->hDIBPalette);
130 if (PalGDI == NULL)
131 {
132 BITMAPOBJ_UnlockBitmap(BitmapObj);
133 DC_UnlockDc(dc);
134 SetLastWin32Error(ERROR_INVALID_HANDLE);
135 return 0;
136 }
137
138 for (Index = StartIndex;
139 Index < StartIndex + Entries && Index < PalGDI->NumColors;
140 Index++)
141 {
142 Colors[Index - StartIndex].rgbRed = PalGDI->IndexedColors[Index].peRed;
143 Colors[Index - StartIndex].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
144 Colors[Index - StartIndex].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
145 }
146 PALETTE_UnlockPalette(PalGDI);
147 }
148 else
149 Entries = 0;
150
151 BITMAPOBJ_UnlockBitmap(BitmapObj);
152 DC_UnlockDc(dc);
153
154 return Entries;
155 }
156
157 // Converts a DIB to a device-dependent bitmap
158 static INT FASTCALL
159 IntSetDIBits(
160 PDC DC,
161 HBITMAP hBitmap,
162 UINT StartScan,
163 UINT ScanLines,
164 CONST VOID *Bits,
165 CONST BITMAPINFO *bmi,
166 UINT ColorUse)
167 {
168 BITMAPOBJ *bitmap;
169 HBITMAP SourceBitmap;
170 INT result = 0;
171 BOOL copyBitsResult;
172 SURFOBJ *DestSurf, *SourceSurf;
173 SIZEL SourceSize;
174 POINTL ZeroPoint;
175 RECTL DestRect;
176 XLATEOBJ *XlateObj;
177 PPALGDI hDCPalette;
178 //RGBQUAD *lpRGB;
179 HPALETTE DDB_Palette, DIB_Palette;
180 ULONG DDB_Palette_Type, DIB_Palette_Type;
181 INT DIBWidth;
182
183 // Check parameters
184 if (!(bitmap = BITMAPOBJ_LockBitmap(hBitmap)))
185 {
186 return 0;
187 }
188
189 // Get RGB values
190 //if (ColorUse == DIB_PAL_COLORS)
191 // lpRGB = DIB_MapPaletteColors(hDC, bmi);
192 //else
193 // lpRGB = &bmi->bmiColors;
194
195 DestSurf = &bitmap->SurfObj;
196
197 // Create source surface
198 SourceSize.cx = bmi->bmiHeader.biWidth;
199 SourceSize.cy = ScanLines;
200
201 // Determine width of DIB
202 DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
203
204 SourceBitmap = EngCreateBitmap(SourceSize,
205 DIBWidth,
206 BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
207 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
208 (PVOID) Bits);
209 if (0 == SourceBitmap)
210 {
211 BITMAPOBJ_UnlockBitmap(bitmap);
212 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
213 return 0;
214 }
215
216 SourceSurf = EngLockSurface((HSURF)SourceBitmap);
217 if (NULL == SourceSurf)
218 {
219 EngDeleteSurface((HSURF)SourceBitmap);
220 BITMAPOBJ_UnlockBitmap(bitmap);
221 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
222 return 0;
223 }
224
225 // Destination palette obtained from the hDC
226 hDCPalette = PALETTE_LockPalette(((GDIDEVICE *)DC->pPDev)->DevInfo.hpalDefault);
227 if (NULL == hDCPalette)
228 {
229 EngUnlockSurface(SourceSurf);
230 EngDeleteSurface((HSURF)SourceBitmap);
231 BITMAPOBJ_UnlockBitmap(bitmap);
232 SetLastWin32Error(ERROR_INVALID_HANDLE);
233 return 0;
234 }
235 DDB_Palette_Type = hDCPalette->Mode;
236 DDB_Palette = ((GDIDEVICE *)DC->pPDev)->DevInfo.hpalDefault;
237 PALETTE_UnlockPalette(hDCPalette);
238
239 // Source palette obtained from the BITMAPINFO
240 DIB_Palette = BuildDIBPalette ( (PBITMAPINFO)bmi, (PINT)&DIB_Palette_Type );
241 if (NULL == DIB_Palette)
242 {
243 EngUnlockSurface(SourceSurf);
244 EngDeleteSurface((HSURF)SourceBitmap);
245 BITMAPOBJ_UnlockBitmap(bitmap);
246 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
247 return 0;
248 }
249
250 // Determine XLATEOBJ for color translation
251 XlateObj = IntEngCreateXlate(DDB_Palette_Type, DIB_Palette_Type, DDB_Palette, DIB_Palette);
252 if (NULL == XlateObj)
253 {
254 PALETTE_FreePaletteByHandle(DIB_Palette);
255 EngUnlockSurface(SourceSurf);
256 EngDeleteSurface((HSURF)SourceBitmap);
257 BITMAPOBJ_UnlockBitmap(bitmap);
258 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
259 return 0;
260 }
261
262 // Zero point
263 ZeroPoint.x = 0;
264 ZeroPoint.y = 0;
265
266 // Determine destination rectangle
267 DestRect.left = 0;
268 DestRect.top = abs(bmi->bmiHeader.biHeight) - StartScan - ScanLines;
269 DestRect.right = SourceSize.cx;
270 DestRect.bottom = DestRect.top + ScanLines;
271
272 copyBitsResult = EngCopyBits(DestSurf, SourceSurf, NULL, XlateObj, &DestRect, &ZeroPoint);
273
274 // If it succeeded, return number of scanlines copies
275 if(copyBitsResult == TRUE)
276 {
277 result = SourceSize.cy - 1;
278 }
279
280 // Clean up
281 EngDeleteXlate(XlateObj);
282 PALETTE_FreePaletteByHandle(DIB_Palette);
283 EngUnlockSurface(SourceSurf);
284 EngDeleteSurface((HSURF)SourceBitmap);
285
286 // if (ColorUse == DIB_PAL_COLORS)
287 // WinFree((LPSTR)lpRGB);
288
289 BITMAPOBJ_UnlockBitmap(bitmap);
290
291 return result;
292 }
293
294 // Converts a DIB to a device-dependent bitmap
295 INT STDCALL
296 NtGdiSetDIBits(
297 HDC hDC,
298 HBITMAP hBitmap,
299 UINT StartScan,
300 UINT ScanLines,
301 CONST VOID *Bits,
302 CONST BITMAPINFO *bmi,
303 UINT ColorUse)
304 {
305 PDC Dc;
306 INT Ret;
307
308 Dc = DC_LockDc(hDC);
309 if (NULL == Dc)
310 {
311 SetLastWin32Error(ERROR_INVALID_HANDLE);
312 return 0;
313 }
314 if (Dc->DC_Type == DC_TYPE_INFO)
315 {
316 DC_UnlockDc(Dc);
317 return 0;
318 }
319
320 Ret = IntSetDIBits(Dc, hBitmap, StartScan, ScanLines, Bits, bmi, ColorUse);
321
322 DC_UnlockDc(Dc);
323
324 return Ret;
325 }
326
327
328
329 W32KAPI
330 INT
331 APIENTRY
332 NtGdiSetDIBitsToDeviceInternal(
333 IN HDC hDC,
334 IN INT XDest,
335 IN INT YDest,
336 IN DWORD Width,
337 IN DWORD Height,
338 IN INT XSrc,
339 IN INT YSrc,
340 IN DWORD StartScan,
341 IN DWORD ScanLines,
342 IN LPBYTE Bits,
343 IN LPBITMAPINFO bmi,
344 IN DWORD ColorUse,
345 IN UINT cjMaxBits,
346 IN UINT cjMaxInfo,
347 IN BOOL bTransformCoordinates,
348 IN OPTIONAL HANDLE hcmXform
349 )
350 {
351 INT ret = 0;
352 NTSTATUS Status = STATUS_SUCCESS;
353 PDC pDC;
354 HBITMAP hSourceBitmap = NULL;
355 SURFOBJ *pDestSurf, *pSourceSurf = NULL;
356 RECTL rcDest;
357 POINTL ptSource;
358 INT DIBWidth;
359 SIZEL SourceSize;
360 XLATEOBJ *XlateObj = NULL;
361 PPALGDI pDCPalette;
362 HPALETTE DDBPalette, DIBPalette = NULL;
363 ULONG DDBPaletteType, DIBPaletteType;
364
365 if (!Bits) return 0;
366
367 pDC = DC_LockDc(hDC);
368 if (!pDC)
369 {
370 SetLastWin32Error(ERROR_INVALID_HANDLE);
371 return 0;
372 }
373 if (pDC->DC_Type == DC_TYPE_INFO)
374 {
375 DC_UnlockDc(pDC);
376 return 0;
377 }
378
379 pDestSurf = EngLockSurface((HSURF)pDC->w.hBitmap);
380 if (!pDestSurf)
381 {
382 /* FIXME: SetLastError ? */
383 DC_UnlockDc(pDC);
384 return 0;
385 }
386
387 rcDest.left = XDest;
388 rcDest.top = YDest;
389 if (bTransformCoordinates)
390 {
391 CoordLPtoDP(pDC, (LPPOINT)&rcDest);
392 }
393 rcDest.left += pDC->ptlDCOrig.x;
394 rcDest.top += pDC->ptlDCOrig.y;
395 rcDest.right = rcDest.left + Width;
396 rcDest.bottom = rcDest.top + Height;
397 ptSource.x = XSrc;
398 ptSource.y = YSrc;
399
400 /* Enter SEH, as the bits are user mode */
401 _SEH_TRY
402 {
403 SourceSize.cx = bmi->bmiHeader.biWidth;
404 SourceSize.cy = ScanLines;
405 DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
406
407 ProbeForRead(Bits, DIBWidth * abs(bmi->bmiHeader.biHeight), 1);
408 hSourceBitmap = EngCreateBitmap(SourceSize,
409 DIBWidth,
410 BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
411 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
412 (PVOID) Bits);
413 if (!hSourceBitmap)
414 {
415 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
416 Status = STATUS_NO_MEMORY;
417 _SEH_LEAVE;
418 }
419
420 pSourceSurf = EngLockSurface((HSURF)hSourceBitmap);
421 if (!pSourceSurf)
422 {
423 Status = STATUS_UNSUCCESSFUL;
424 _SEH_LEAVE;
425 }
426
427
428 /* Obtain destination palette from the DC */
429 pDCPalette = PALETTE_LockPalette(((GDIDEVICE *)pDC->pPDev)->DevInfo.hpalDefault);
430 if (!pDCPalette)
431 {
432 SetLastWin32Error(ERROR_INVALID_HANDLE);
433 Status = STATUS_UNSUCCESSFUL;
434 _SEH_LEAVE;
435 }
436 DDBPaletteType = pDCPalette->Mode;
437 DDBPalette = ((GDIDEVICE *)pDC->pPDev)->DevInfo.hpalDefault;
438 PALETTE_UnlockPalette(pDCPalette);
439
440 DIBPalette = BuildDIBPalette(bmi, (PINT)&DIBPaletteType);
441 if (!DIBPalette)
442 {
443 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
444 Status = STATUS_NO_MEMORY;
445 _SEH_LEAVE;
446 }
447
448 /* Determine XlateObj */
449 XlateObj = IntEngCreateXlate(DDBPaletteType, DIBPaletteType, DDBPalette, DIBPalette);
450 if (!XlateObj)
451 {
452 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
453 Status = STATUS_NO_MEMORY;
454 _SEH_LEAVE;
455 }
456
457 /* Copy the bits */
458 Status = IntEngBitBlt(pDestSurf,
459 pSourceSurf,
460 NULL,
461 pDC->CombinedClip,
462 XlateObj,
463 &rcDest,
464 &ptSource,
465 NULL,
466 NULL,
467 NULL,
468 ROP3_TO_ROP4(SRCCOPY));
469
470 }
471 _SEH_HANDLE
472 {
473 Status = _SEH_GetExceptionCode();
474 }
475 _SEH_END
476
477 if (NT_SUCCESS(Status))
478 {
479 /* FIXME: Should probably be only the number of lines actually copied */
480 ret = ScanLines;
481 }
482
483 if (pSourceSurf) EngUnlockSurface(pSourceSurf);
484 if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
485 if (XlateObj) EngDeleteXlate(XlateObj);
486 if (DIBPalette) PALETTE_FreePaletteByHandle(DIBPalette);
487 EngUnlockSurface(pDestSurf);
488 DC_UnlockDc(pDC);
489
490 return ret;
491 }
492
493
494 /* Converts a device-dependent bitmap to a DIB */
495 INT STDCALL
496 NtGdiGetDIBitsInternal(HDC hDC,
497 HBITMAP hBitmap,
498 UINT StartScan,
499 UINT ScanLines,
500 LPBYTE Bits,
501 LPBITMAPINFO Info,
502 UINT Usage,
503 UINT MaxBits,
504 UINT MaxInfo)
505 {
506 PDC Dc;
507 BITMAPOBJ *BitmapObj = NULL;
508 HBITMAP hDestBitmap = NULL;
509 HPALETTE hSourcePalette = NULL;
510 HPALETTE hDestPalette = NULL;
511 PPALGDI SourcePalette = NULL;
512 PPALGDI DestPalette = NULL;
513 NTSTATUS Status = STATUS_SUCCESS;
514 ULONG Result = 0;
515 BOOL bPaletteMatch = FALSE;
516
517 DPRINT("Entered NtGdiGetDIBitsInternal()\n");
518
519 /* Get handle for the palette in DC. */
520 Dc = DC_LockDc(hDC);
521 if (Dc == NULL) return 0;
522 if (Dc->DC_Type == DC_TYPE_INFO)
523 {
524 DC_UnlockDc(Dc);
525 return 0;
526 }
527 /* Source palette obtained from the windows hdc */
528 hSourcePalette = Dc->DcLevel.hpal;
529 DC_UnlockDc(Dc);
530
531 /* don't do anything if we fail this */
532 if (Usage != DIB_RGB_COLORS && Usage != DIB_PAL_COLORS)
533 return 0;
534
535 /* Get a pointer to the source bitmap object */
536 BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
537 if (BitmapObj == NULL)
538 return 0;
539
540 /* fill out the BITMAPINFO struct */
541 if (Bits == NULL)
542 {
543 _SEH_TRY
544 {
545 if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
546 {
547 BITMAPCOREHEADER* coreheader;
548
549 ProbeForWrite(Info, sizeof(BITMAPINFO), 1);
550
551 coreheader = (BITMAPCOREHEADER*) Info;
552 coreheader->bcWidth = BitmapObj->SurfObj.sizlBitmap.cx;
553 coreheader->bcPlanes = 1;
554 coreheader->bcBitCount = BitsPerFormat(BitmapObj->SurfObj.iBitmapFormat);
555 /* Resulting height may be smaller than original height */
556 coreheader->bcHeight = min(ScanLines, BitmapObj->SurfObj.sizlBitmap.cy - StartScan);
557
558 if (BitmapObj->SurfObj.lDelta > 0)
559 coreheader->bcHeight = -coreheader->bcHeight;
560 }
561
562 if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
563 {
564 ProbeForWrite(Info, sizeof(BITMAPINFO), 1);
565
566 Info->bmiHeader.biWidth = BitmapObj->SurfObj.sizlBitmap.cx;
567 /* Resulting height may be smaller than original height */
568 Info->bmiHeader.biHeight = min(ScanLines, BitmapObj->SurfObj.sizlBitmap.cy - StartScan);
569 /* Report negtive height for top-down bitmaps. */
570 if (BitmapObj->SurfObj.lDelta > 0)
571 Info->bmiHeader.biHeight = -Info->bmiHeader.biHeight;
572 Info->bmiHeader.biPlanes = 1;
573 Info->bmiHeader.biBitCount = BitsPerFormat(BitmapObj->SurfObj.iBitmapFormat);
574 if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
575 {
576 switch (BitmapObj->SurfObj.iBitmapFormat)
577 {
578 case BMF_1BPP:
579 case BMF_4BPP:
580 case BMF_8BPP:
581 case BMF_16BPP:
582 case BMF_24BPP:
583 case BMF_32BPP:
584 Info->bmiHeader.biCompression = BI_RGB;
585 break;
586 case BMF_4RLE:
587 Info->bmiHeader.biCompression = BI_RLE4;
588 break;
589 case BMF_8RLE:
590 Info->bmiHeader.biCompression = BI_RLE8;
591 break;
592 case BMF_JPEG:
593 Info->bmiHeader.biCompression = BI_JPEG;
594 break;
595 case BMF_PNG:
596 Info->bmiHeader.biCompression = BI_PNG;
597 break;
598 }
599 /* Image size has to be calculated */
600 Info->bmiHeader.biSizeImage = DIB_GetDIBWidthBytes(Info->bmiHeader.biWidth,
601 Info->bmiHeader.biBitCount) * Info->bmiHeader.biHeight;
602 Info->bmiHeader.biXPelsPerMeter = 0; /* FIXME */
603 Info->bmiHeader.biYPelsPerMeter = 0; /* FIXME */
604 Info->bmiHeader.biClrUsed = 0;
605 Info->bmiHeader.biClrImportant = 1 << Info->bmiHeader.biBitCount; /* FIXME */
606 }
607 }
608 }
609 _SEH_HANDLE
610 {
611 Status = _SEH_GetExceptionCode();
612 }
613 _SEH_END
614
615 if (NT_SUCCESS(Status))
616 {
617 Result = BitmapObj->SurfObj.sizlBitmap.cy;
618 }
619 }
620 else
621 {
622 SIZEL DestSize;
623 ULONG SourcePaletteType = 0;
624 ULONG DestPaletteType;
625 POINTL SourcePoint;
626 ULONG Index;
627
628 _SEH_TRY
629 {
630 ProbeForRead(Info, sizeof(BITMAPINFO), 1);
631
632 if (Info->bmiHeader.biBitCount == BitsPerFormat(BitmapObj->SurfObj.iBitmapFormat))
633 {
634 hDestPalette = hSourcePalette;
635 bPaletteMatch = TRUE;
636 }
637 else
638 hDestPalette = BuildDIBPalette(Info, (PINT)&DestPaletteType); //hDestPalette = Dc->DevInfo->hpalDefault;
639
640 SourcePalette = PALETTE_LockPalette(hSourcePalette);
641 /* FIXME - SourcePalette can be NULL!!! Don't assert here! */
642 ASSERT(SourcePalette);
643 SourcePaletteType = SourcePalette->Mode;
644 PALETTE_UnlockPalette(SourcePalette);
645
646 if (bPaletteMatch)
647 {
648 DestPalette = PALETTE_LockPalette(hDestPalette);
649 /* FIXME - DestPalette can be NULL!!!! Don't assert here!!! */
650 DPRINT("DestPalette : %p\n", DestPalette);
651 ASSERT(DestPalette);
652 DestPaletteType = DestPalette->Mode;
653 }
654 else
655 {
656 DestPalette = SourcePalette;
657 }
658
659 /* Copy palette. */
660 /* FIXME: This is largely incomplete. */
661 if (Info->bmiHeader.biBitCount <= 8)
662 {
663 if (Usage == DIB_RGB_COLORS)
664 {
665 for (Index = 0;
666 Index < (1 << Info->bmiHeader.biBitCount) && Index < DestPalette->NumColors;
667 Index++)
668 {
669 Info->bmiColors[Index].rgbRed = DestPalette->IndexedColors[Index].peRed;
670 Info->bmiColors[Index].rgbGreen = DestPalette->IndexedColors[Index].peGreen;
671 Info->bmiColors[Index].rgbBlue = DestPalette->IndexedColors[Index].peBlue;
672 }
673 }
674
675 if (Usage == DIB_PAL_COLORS)
676 {
677 DPRINT1("GetDIBits with DIB_PAL_COLORS isn't implemented yet\n");
678 }
679 }
680
681 if (bPaletteMatch)
682 PALETTE_UnlockPalette(DestPalette);
683
684 /* Create the destination bitmap to for the copy operation */
685 if (StartScan > BitmapObj->SurfObj.sizlBitmap.cy)
686 {
687 _SEH_YIELD(goto cleanup);
688 }
689 else
690 {
691 ScanLines = min(ScanLines, BitmapObj->SurfObj.sizlBitmap.cy - StartScan);
692 DestSize.cx = BitmapObj->SurfObj.sizlBitmap.cx;
693 DestSize.cy = ScanLines;
694
695 hDestBitmap = NULL;
696
697 ProbeForWrite(Bits, sizeof(BitmapObj->SurfObj.cjBits), 1);
698
699 if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
700 {
701 BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) Info;
702
703 hDestBitmap = EngCreateBitmap(DestSize,
704 DIB_GetDIBWidthBytes(DestSize.cx, coreheader->bcBitCount),
705 BitmapFormat(coreheader->bcBitCount, BI_RGB),
706 0 < coreheader->bcHeight ? 0 : BMF_TOPDOWN,
707 Bits);
708 }
709
710 if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
711 {
712 hDestBitmap = EngCreateBitmap(DestSize,
713 DIB_GetDIBWidthBytes(DestSize.cx, Info->bmiHeader.biBitCount),
714 BitmapFormat(Info->bmiHeader.biBitCount, Info->bmiHeader.biCompression),
715 0 < Info->bmiHeader.biHeight ? 0 : BMF_TOPDOWN,
716 Bits);
717 }
718
719 if (hDestBitmap == NULL)
720 _SEH_YIELD(goto cleanup);
721 }
722 }
723 _SEH_HANDLE
724 {
725 Status = _SEH_GetExceptionCode();
726 }
727 _SEH_END
728
729 if (NT_SUCCESS(Status))
730 {
731 XLATEOBJ *XlateObj;
732 SURFOBJ *DestSurfObj;
733 RECTL DestRect;
734
735 XlateObj = IntEngCreateXlate(DestPaletteType,
736 SourcePaletteType,
737 hDestPalette,
738 hSourcePalette);
739
740 SourcePoint.x = 0;
741 SourcePoint.y = BitmapObj->SurfObj.sizlBitmap.cy - (StartScan + ScanLines);
742
743 /* Determine destination rectangle */
744 DestRect.top = 0;
745 DestRect.left = 0;
746 DestRect.right = DestSize.cx;
747 DestRect.bottom = DestSize.cy;
748
749 DestSurfObj = EngLockSurface((HSURF)hDestBitmap);
750
751 if (EngCopyBits(DestSurfObj,
752 &BitmapObj->SurfObj,
753 NULL,
754 XlateObj,
755 &DestRect,
756 &SourcePoint))
757 {
758 Result = ScanLines;
759 }
760
761 EngDeleteXlate(XlateObj);
762 EngUnlockSurface(DestSurfObj);
763 }
764 }
765
766 cleanup:
767 if (hDestBitmap != NULL)
768 EngDeleteSurface((HSURF)hDestBitmap);
769
770 if (hDestPalette != NULL && bPaletteMatch == FALSE)
771 PALETTE_FreePaletteByHandle(hDestPalette);
772
773 BITMAPOBJ_UnlockBitmap(BitmapObj);
774
775 DPRINT("leaving NtGdiGetDIBitsInternal\n");
776
777 return Result;
778 }
779
780 INT
781 APIENTRY
782 NtGdiStretchDIBitsInternal(
783 HDC hDC,
784 INT XDest,
785 INT YDest,
786 INT DestWidth,
787 INT DestHeight,
788 INT XSrc,
789 INT YSrc,
790 INT SrcWidth,
791 INT SrcHeight,
792 LPBYTE Bits,
793 LPBITMAPINFO BitsInfo,
794 DWORD Usage,
795 DWORD ROP,
796 UINT cjMaxInfo,
797 UINT cjMaxBits,
798 HANDLE hcmXform)
799 {
800 HBITMAP hBitmap, hOldBitmap = NULL;
801 HDC hdcMem;
802 HPALETTE hPal = NULL;
803 PDC pDC;
804
805 if (!Bits || !BitsInfo)
806 {
807 SetLastWin32Error(ERROR_INVALID_PARAMETER);
808 return 0;
809 }
810
811 hdcMem = NtGdiCreateCompatibleDC(hDC);
812 if (hdcMem == NULL)
813 {
814 DPRINT1("NtGdiCreateCompatibleDC fail create hdc\n");
815 return 0;
816 }
817
818 hBitmap = NtGdiCreateCompatibleBitmap(hDC, BitsInfo->bmiHeader.biWidth,
819 BitsInfo->bmiHeader.biHeight);
820 if (hBitmap == NULL)
821 {
822 DPRINT1("NtGdiCreateCompatibleBitmap fail create bitmap\n");
823 DPRINT1("hDC : 0x%08x \n", hDC);
824 DPRINT1("BitsInfo->bmiHeader.biWidth : 0x%08x \n", BitsInfo->bmiHeader.biWidth);
825 DPRINT1("BitsInfo->bmiHeader.biHeight : 0x%08x \n", BitsInfo->bmiHeader.biHeight);
826 return 0;
827 }
828
829 /* Select the bitmap into hdcMem, and save a handle to the old bitmap */
830 hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
831
832 if(Usage == DIB_PAL_COLORS)
833 {
834 hPal = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_PALETTE);
835 hPal = GdiSelectPalette(hdcMem, hPal, FALSE);
836 }
837
838 if (BitsInfo->bmiHeader.biCompression == BI_RLE4 ||
839 BitsInfo->bmiHeader.biCompression == BI_RLE8)
840 {
841 /* copy existing bitmap from destination dc */
842 if (SrcWidth == DestWidth && SrcHeight == DestHeight)
843 NtGdiBitBlt(hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
844 SrcWidth, SrcHeight, hDC, XDest, YDest, ROP, 0, 0);
845 else
846 NtGdiStretchBlt(hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
847 SrcWidth, SrcHeight, hDC, XDest, YDest, DestWidth, DestHeight,
848 ROP, 0);
849 }
850
851 pDC = DC_LockDc(hdcMem);
852 if (pDC != NULL)
853 {
854 /* Note BitsInfo->bmiHeader.biHeight is the number of scanline,
855 * if it negitve we getting to many scanline for scanline is UINT not
856 * a INT, so we need make the negtive value to positve and that make the
857 * count correct for negtive bitmap, TODO : we need testcase for this api */
858
859 IntSetDIBits(pDC, hBitmap, 0, abs(BitsInfo->bmiHeader.biHeight), Bits,
860 BitsInfo, Usage);
861
862 DC_UnlockDc(pDC);
863 }
864
865
866 /* Origin for DIBitmap may be bottom left (positive biHeight) or top
867 left (negative biHeight) */
868 if (SrcWidth == DestWidth && SrcHeight == DestHeight)
869 NtGdiBitBlt(hDC, XDest, YDest, DestWidth, DestHeight,
870 hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
871 ROP, 0, 0);
872 else
873 NtGdiStretchBlt(hDC, XDest, YDest, DestWidth, DestHeight,
874 hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
875 SrcWidth, SrcHeight, ROP, 0);
876
877 /* cleanup */
878 if(hPal)
879 GdiSelectPalette(hdcMem, hPal, FALSE);
880
881 if (hOldBitmap)
882 NtGdiSelectBitmap(hdcMem, hOldBitmap);
883
884 NtGdiDeleteObjectApp(hdcMem);
885
886 NtGdiDeleteObject(hBitmap);
887
888 return SrcHeight;
889 }
890
891
892 HBITMAP
893 FASTCALL
894 IntCreateDIBitmap(PDC Dc,
895 INT width,
896 INT height,
897 UINT bpp,
898 DWORD init,
899 LPBYTE bits,
900 PBITMAPINFO data,
901 DWORD coloruse)
902 {
903 HBITMAP handle;
904 BOOL fColor;
905
906 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
907 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
908
909 if (bpp != 1) fColor = TRUE;
910 else if ((coloruse != DIB_RGB_COLORS) || (init != CBM_INIT) || !data) fColor = FALSE;
911 else
912 {
913 if (data->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
914 {
915 const RGBQUAD *rgb = data->bmiColors;
916 DWORD col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
917
918 // Check if the first color of the colormap is black
919 if ((col == RGB(0, 0, 0)))
920 {
921 rgb++;
922 col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
923
924 // If the second color is white, create a monochrome bitmap
925 fColor = (col != RGB(0xff,0xff,0xff));
926 }
927 else fColor = TRUE;
928 }
929 else if (data->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
930 {
931 RGBTRIPLE *rgb = ((BITMAPCOREINFO *)data)->bmciColors;
932 DWORD col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue);
933
934 if ((col == RGB(0,0,0)))
935 {
936 rgb++;
937 col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue );
938 fColor = (col != RGB(0xff,0xff,0xff));
939 }
940 else fColor = TRUE;
941 }
942 else
943 {
944 DPRINT("(%ld): wrong size for data\n", data->bmiHeader.biSize );
945 return 0;
946 }
947 }
948
949 // Now create the bitmap
950 if (fColor)
951 {
952 handle = IntCreateCompatibleBitmap(Dc, width, height);
953 }
954 else
955 {
956 handle = IntGdiCreateBitmap(width,
957 height,
958 1,
959 1,
960 NULL);
961 }
962
963 if (height < 0)
964 height = -height;
965
966 if (NULL != handle && CBM_INIT == init)
967 {
968 IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
969 }
970
971 return handle;
972 }
973
974 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
975 // The DDB that is created will be whatever bit depth your reference DC is
976 HBITMAP
977 APIENTRY
978 NtGdiCreateDIBitmapInternal(IN HDC hDc,
979 IN INT cx,
980 IN INT cy,
981 IN DWORD fInit,
982 IN OPTIONAL LPBYTE pjInit,
983 IN OPTIONAL LPBITMAPINFO pbmi,
984 IN DWORD iUsage,
985 IN UINT cjMaxInitInfo,
986 IN UINT cjMaxBits,
987 IN FLONG fl,
988 IN HANDLE hcmXform)
989 {
990 PDC Dc;
991 HBITMAP Bmp;
992
993 if (!hDc)
994 {
995 hDc = IntGdiCreateDC(NULL, NULL, NULL, NULL,FALSE);
996 if (!hDc)
997 {
998 SetLastWin32Error(ERROR_INVALID_HANDLE);
999 return NULL;
1000 }
1001
1002 Dc = DC_LockDc(hDc);
1003 if (!Dc)
1004 {
1005 NtGdiDeleteObjectApp(hDc);
1006 SetLastWin32Error(ERROR_INVALID_HANDLE);
1007 return NULL;
1008 }
1009
1010 cjMaxInitInfo = 1;
1011 Bmp = IntCreateDIBitmap(Dc, cx, cy, cjMaxInitInfo, fInit, pjInit, pbmi, iUsage);
1012
1013 DC_UnlockDc(Dc);
1014 NtGdiDeleteObjectApp(hDc);
1015 }
1016 else
1017 {
1018 Dc = DC_LockDc(hDc);
1019 if (!Dc)
1020 {
1021 SetLastWin32Error(ERROR_INVALID_HANDLE);
1022 return NULL;
1023 }
1024
1025 Bmp = IntCreateDIBitmap(Dc, cx, cy, cjMaxInitInfo, fInit, pjInit, pbmi, iUsage);
1026 DC_UnlockDc(Dc);
1027 }
1028 return Bmp;
1029 }
1030
1031
1032 HBITMAP STDCALL NtGdiCreateDIBSection(HDC hDC,
1033 IN OPTIONAL HANDLE hSection,
1034 IN DWORD dwOffset,
1035 IN LPBITMAPINFO bmi,
1036 DWORD Usage,
1037 IN UINT cjHeader,
1038 IN FLONG fl,
1039 IN ULONG_PTR dwColorSpace,
1040 PVOID *Bits)
1041 {
1042 HBITMAP hbitmap = 0;
1043 DC *dc;
1044 BOOL bDesktopDC = FALSE;
1045
1046 if (!bmi) return hbitmap; // Make sure.
1047
1048 // If the reference hdc is null, take the desktop dc
1049 if (hDC == 0)
1050 {
1051 hDC = NtGdiCreateCompatibleDC(0);
1052 bDesktopDC = TRUE;
1053 }
1054
1055 if ((dc = DC_LockDc(hDC)))
1056 {
1057 hbitmap = DIB_CreateDIBSection ( dc, (BITMAPINFO*)bmi, Usage, Bits,
1058 hSection, dwOffset, 0);
1059 DC_UnlockDc(dc);
1060 }
1061 else
1062 {
1063 SetLastWin32Error(ERROR_INVALID_HANDLE);
1064 }
1065
1066 if (bDesktopDC)
1067 NtGdiDeleteObjectApp(hDC);
1068
1069 return hbitmap;
1070 }
1071
1072 HBITMAP STDCALL
1073 DIB_CreateDIBSection(
1074 PDC dc, BITMAPINFO *bmi, UINT usage,
1075 LPVOID *bits, HANDLE section,
1076 DWORD offset, DWORD ovr_pitch)
1077 {
1078 HBITMAP res = 0;
1079 BITMAPOBJ *bmp = NULL;
1080 DIBSECTION *dib = NULL;
1081
1082 // Fill BITMAP32 structure with DIB data
1083 BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1084 INT effHeight;
1085 ULONG totalSize;
1086 UINT Entries = 0;
1087 BITMAP bm;
1088 SIZEL Size;
1089 RGBQUAD *lpRGB;
1090
1091 DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
1092 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1093 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1094
1095 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1096 bm.bmType = 0;
1097 bm.bmWidth = bi->biWidth;
1098 bm.bmHeight = effHeight;
1099 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : (ULONG) DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
1100
1101 bm.bmPlanes = bi->biPlanes;
1102 bm.bmBitsPixel = bi->biBitCount;
1103 bm.bmBits = NULL;
1104
1105 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
1106 // we're dealing with a compressed bitmap. Otherwise, use width * height.
1107 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
1108 ? bi->biSizeImage : (ULONG) (bm.bmWidthBytes * effHeight);
1109
1110 if (section)
1111 {
1112 /* bm.bmBits = MapViewOfFile(section, FILE_MAP_ALL_ACCESS,
1113 0L, offset, totalSize); */
1114 DbgPrint("DIB_CreateDIBSection: Cannot yet handle section DIBs\n");
1115 SetLastWin32Error(ERROR_CALL_NOT_IMPLEMENTED);
1116 return 0;
1117 }
1118 else if (ovr_pitch && offset)
1119 bm.bmBits = (LPVOID) offset;
1120 else {
1121 offset = 0;
1122 bm.bmBits = EngAllocUserMem(totalSize, 0);
1123 }
1124
1125 if(usage == DIB_PAL_COLORS)
1126 lpRGB = DIB_MapPaletteColors(dc, bmi);
1127 else
1128 lpRGB = bmi->bmiColors;
1129
1130 // Allocate Memory for DIB and fill structure
1131 if (bm.bmBits)
1132 {
1133 dib = ExAllocatePoolWithTag(PagedPool, sizeof(DIBSECTION), TAG_DIB);
1134 if (dib != NULL) RtlZeroMemory(dib, sizeof(DIBSECTION));
1135 }
1136
1137 if (dib)
1138 {
1139 dib->dsBm = bm;
1140 dib->dsBmih = *bi;
1141 dib->dsBmih.biSizeImage = totalSize;
1142
1143 /* Set dsBitfields values */
1144 if ( usage == DIB_PAL_COLORS || bi->biBitCount <= 8)
1145 {
1146 dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
1147 }
1148 else switch(bi->biBitCount)
1149 {
1150 case 16:
1151 dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)lpRGB : 0x7c00;
1152 dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 1) : 0x03e0;
1153 dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 2) : 0x001f;
1154 break;
1155
1156 case 24:
1157 dib->dsBitfields[0] = 0xff0000;
1158 dib->dsBitfields[1] = 0x00ff00;
1159 dib->dsBitfields[2] = 0x0000ff;
1160 break;
1161
1162 case 32:
1163 dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)lpRGB : 0xff0000;
1164 dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 1) : 0x00ff00;
1165 dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 2) : 0x0000ff;
1166 break;
1167 }
1168 dib->dshSection = section;
1169 dib->dsOffset = offset;
1170
1171 // Create Device Dependent Bitmap and add DIB pointer
1172 Size.cx = bm.bmWidth;
1173 Size.cy = abs(bm.bmHeight);
1174 res = IntCreateBitmap(Size, bm.bmWidthBytes,
1175 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
1176 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
1177 (bi->biHeight < 0 ? BMF_TOPDOWN : 0),
1178 bm.bmBits);
1179 if (! res)
1180 {
1181 if (lpRGB != bmi->bmiColors)
1182 {
1183 ExFreePool(lpRGB);
1184 }
1185 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
1186 return NULL;
1187 }
1188 bmp = BITMAPOBJ_LockBitmap(res);
1189 if (NULL == bmp)
1190 {
1191 if (lpRGB != bmi->bmiColors)
1192 {
1193 ExFreePool(lpRGB);
1194 }
1195 SetLastWin32Error(ERROR_INVALID_HANDLE);
1196 NtGdiDeleteObject(bmp);
1197 return NULL;
1198 }
1199 bmp->dib = (DIBSECTION *) dib;
1200 bmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
1201
1202 /* WINE NOTE: WINE makes use of a colormap, which is a color translation table between the DIB and the X physical
1203 device. Obviously, this is left out of the ReactOS implementation. Instead, we call
1204 NtGdiSetDIBColorTable. */
1205 if(bi->biBitCount == 1) { Entries = 2; } else
1206 if(bi->biBitCount == 4) { Entries = 16; } else
1207 if(bi->biBitCount == 8) { Entries = 256; }
1208
1209 if (Entries)
1210 bmp->hDIBPalette = PALETTE_AllocPaletteIndexedRGB(Entries, lpRGB);
1211 else
1212 bmp->hDIBPalette = PALETTE_AllocPalette(PAL_BITFIELDS, 0, NULL,
1213 dib->dsBitfields[0],
1214 dib->dsBitfields[1],
1215 dib->dsBitfields[2]);
1216 }
1217
1218 // Clean up in case of errors
1219 if (!res || !bmp || !dib || !bm.bmBits)
1220 {
1221 DPRINT("got an error res=%08x, bmp=%p, dib=%p, bm.bmBits=%p\n", res, bmp, dib, bm.bmBits);
1222 /* if (bm.bmBits)
1223 {
1224 if (section)
1225 UnmapViewOfFile(bm.bmBits), bm.bmBits = NULL;
1226 else if (!offset)
1227 VirtualFree(bm.bmBits, 0L, MEM_RELEASE), bm.bmBits = NULL;
1228 } */
1229
1230 if (dib) { ExFreePool(dib); dib = NULL; }
1231 if (bmp) { bmp = NULL; }
1232 if (res) { BITMAPOBJ_FreeBitmapByHandle(res); res = 0; }
1233 }
1234
1235 if (lpRGB != bmi->bmiColors)
1236 {
1237 ExFreePool(lpRGB);
1238 }
1239
1240 if (bmp)
1241 {
1242 BITMAPOBJ_UnlockBitmap(bmp);
1243 }
1244
1245 // Return BITMAP handle and storage location
1246 if (NULL != bm.bmBits && NULL != bits)
1247 {
1248 *bits = bm.bmBits;
1249 }
1250
1251 return res;
1252 }
1253
1254 /***********************************************************************
1255 * DIB_GetDIBWidthBytes
1256 *
1257 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
1258 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
1259 * 11/16/1999 (RJJ) lifted from wine
1260 */
1261 INT FASTCALL DIB_GetDIBWidthBytes (INT width, INT depth)
1262 {
1263 return ((width * depth + 31) & ~31) >> 3;
1264 }
1265
1266 /***********************************************************************
1267 * DIB_GetDIBImageBytes
1268 *
1269 * Return the number of bytes used to hold the image in a DIB bitmap.
1270 * 11/16/1999 (RJJ) lifted from wine
1271 */
1272
1273 INT STDCALL DIB_GetDIBImageBytes (INT width, INT height, INT depth)
1274 {
1275 return DIB_GetDIBWidthBytes( width, depth ) * (height < 0 ? -height : height);
1276 }
1277
1278 /***********************************************************************
1279 * DIB_BitmapInfoSize
1280 *
1281 * Return the size of the bitmap info structure including color table.
1282 * 11/16/1999 (RJJ) lifted from wine
1283 */
1284
1285 INT FASTCALL DIB_BitmapInfoSize (const BITMAPINFO * info, WORD coloruse)
1286 {
1287 int colors;
1288
1289 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1290 {
1291 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)info;
1292 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
1293 return sizeof(BITMAPCOREHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
1294 }
1295 else /* assume BITMAPINFOHEADER */
1296 {
1297 colors = info->bmiHeader.biClrUsed;
1298 if (!colors && (info->bmiHeader.biBitCount <= 8)) colors = 1 << info->bmiHeader.biBitCount;
1299 return sizeof(BITMAPINFOHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
1300 }
1301 }
1302
1303 RGBQUAD * FASTCALL
1304 DIB_MapPaletteColors(PDC dc, CONST BITMAPINFO* lpbmi)
1305 {
1306 RGBQUAD *lpRGB;
1307 ULONG nNumColors,i;
1308 USHORT *lpIndex;
1309 PPALGDI palGDI;
1310
1311 palGDI = PALETTE_LockPalette(dc->DcLevel.hpal);
1312
1313 if (NULL == palGDI)
1314 {
1315 return NULL;
1316 }
1317
1318 if (palGDI->Mode != PAL_INDEXED)
1319 {
1320 PALETTE_UnlockPalette(palGDI);
1321 return NULL;
1322 }
1323
1324 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
1325 if (lpbmi->bmiHeader.biClrUsed)
1326 {
1327 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
1328 }
1329
1330 lpRGB = (RGBQUAD *)ExAllocatePoolWithTag(PagedPool, sizeof(RGBQUAD) * nNumColors, TAG_COLORMAP);
1331 if (lpRGB == NULL)
1332 {
1333 PALETTE_UnlockPalette(palGDI);
1334 return NULL;
1335 }
1336
1337 lpIndex = (USHORT *)&lpbmi->bmiColors[0];
1338
1339 for (i = 0; i < nNumColors; i++)
1340 {
1341 lpRGB[i].rgbRed = palGDI->IndexedColors[*lpIndex].peRed;
1342 lpRGB[i].rgbGreen = palGDI->IndexedColors[*lpIndex].peGreen;
1343 lpRGB[i].rgbBlue = palGDI->IndexedColors[*lpIndex].peBlue;
1344 lpIndex++;
1345 }
1346 PALETTE_UnlockPalette(palGDI);
1347
1348 return lpRGB;
1349 }
1350
1351 HPALETTE FASTCALL
1352 BuildDIBPalette (CONST BITMAPINFO *bmi, PINT paletteType)
1353 {
1354 BYTE bits;
1355 ULONG ColorCount;
1356 PALETTEENTRY *palEntries = NULL;
1357 HPALETTE hPal;
1358 ULONG RedMask, GreenMask, BlueMask;
1359
1360 // Determine Bits Per Pixel
1361 bits = bmi->bmiHeader.biBitCount;
1362
1363 // Determine paletteType from Bits Per Pixel
1364 if (bits <= 8)
1365 {
1366 *paletteType = PAL_INDEXED;
1367 RedMask = GreenMask = BlueMask = 0;
1368 }
1369 else if(bmi->bmiHeader.biCompression == BI_BITFIELDS)
1370 {
1371 *paletteType = PAL_BITFIELDS;
1372 RedMask = ((ULONG *)bmi->bmiColors)[0];
1373 GreenMask = ((ULONG *)bmi->bmiColors)[1];
1374 BlueMask = ((ULONG *)bmi->bmiColors)[2];
1375 }
1376 else if(bits < 24)
1377 {
1378 *paletteType = PAL_BITFIELDS;
1379 RedMask = 0x7c00;
1380 GreenMask = 0x03e0;
1381 BlueMask = 0x001f;
1382 }
1383 else
1384 {
1385 *paletteType = PAL_BGR;
1386 RedMask = 0xff0000;
1387 GreenMask = 0x00ff00;
1388 BlueMask = 0x0000ff;
1389 }
1390
1391 if (bmi->bmiHeader.biClrUsed == 0)
1392 {
1393 ColorCount = 1 << bmi->bmiHeader.biBitCount;
1394 }
1395 else
1396 {
1397 ColorCount = bmi->bmiHeader.biClrUsed;
1398 }
1399
1400 if (PAL_INDEXED == *paletteType)
1401 {
1402 hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)bmi->bmiColors);
1403 }
1404 else
1405 {
1406 hPal = PALETTE_AllocPalette(*paletteType, ColorCount,
1407 (ULONG*) palEntries,
1408 RedMask, GreenMask, BlueMask );
1409 }
1410
1411 return hPal;
1412 }
1413
1414 /* EOF */