BUGFIX: Missing error handling in IntSetDIBits()
[reactos.git] / reactos / subsys / win32k / objects / dib.c
1 /*
2 * $Id: dib.c,v 1.58 2004/12/18 17:15:10 royce Exp $
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 #include <w32k.h>
22
23 UINT STDCALL
24 NtGdiSetDIBColorTable(HDC hDC, UINT StartIndex, UINT Entries, CONST RGBQUAD *Colors)
25 {
26 PDC dc;
27 PBITMAPOBJ BitmapObj;
28
29 if (!(dc = DC_LockDc(hDC))) return 0;
30
31 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
32 if (BitmapObj == NULL)
33 {
34 DC_UnlockDc(hDC);
35 SetLastWin32Error(ERROR_INVALID_PARAMETER);
36 return 0;
37 }
38
39 if (BitmapObj->dib == NULL)
40 {
41 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
42 DC_UnlockDc(hDC);
43 SetLastWin32Error(ERROR_INVALID_PARAMETER);
44 return 0;
45 }
46
47 if (BitmapObj->dib->dsBmih.biBitCount <= 8 &&
48 StartIndex < (1 << BitmapObj->dib->dsBmih.biBitCount))
49 {
50 if (StartIndex + Entries > (1 << BitmapObj->dib->dsBmih.biBitCount))
51 Entries = (1 << BitmapObj->dib->dsBmih.biBitCount) - StartIndex;
52
53 MmCopyFromCaller(BitmapObj->ColorMap + StartIndex, Colors, Entries * sizeof(RGBQUAD));
54
55 /* Rebuild the palette. */
56 NtGdiDeleteObject(dc->w.hPalette);
57 dc->w.hPalette = PALETTE_AllocPaletteIndexedRGB(1 << BitmapObj->dib->dsBmih.biBitCount,
58 BitmapObj->ColorMap);
59 }
60 else
61 Entries = 0;
62
63 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
64 DC_UnlockDc(hDC);
65
66 return Entries;
67 }
68
69 UINT STDCALL
70 NtGdiGetDIBColorTable(HDC hDC, UINT StartIndex, UINT Entries, RGBQUAD *Colors)
71 {
72 PDC dc;
73 PBITMAPOBJ BitmapObj;
74
75 if (!(dc = DC_LockDc(hDC))) return 0;
76
77 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
78 if (BitmapObj == NULL)
79 {
80 DC_UnlockDc(hDC);
81 SetLastWin32Error(ERROR_INVALID_PARAMETER);
82 return 0;
83 }
84
85 if (BitmapObj->dib == NULL)
86 {
87 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
88 DC_UnlockDc(hDC);
89 SetLastWin32Error(ERROR_INVALID_PARAMETER);
90 return 0;
91 }
92
93 if (BitmapObj->dib->dsBmih.biBitCount <= 8 &&
94 StartIndex < (1 << BitmapObj->dib->dsBmih.biBitCount))
95 {
96 if (StartIndex + Entries > (1 << BitmapObj->dib->dsBmih.biBitCount))
97 Entries = (1 << BitmapObj->dib->dsBmih.biBitCount) - StartIndex;
98
99 MmCopyToCaller(Colors, BitmapObj->ColorMap + StartIndex, Entries * sizeof(RGBQUAD));
100 }
101 else
102 Entries = 0;
103
104 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
105 DC_UnlockDc(hDC);
106
107 return Entries;
108 }
109
110 // Converts a DIB to a device-dependent bitmap
111 static INT FASTCALL
112 IntSetDIBits(
113 PDC DC,
114 HBITMAP hBitmap,
115 UINT StartScan,
116 UINT ScanLines,
117 CONST VOID *Bits,
118 CONST BITMAPINFO *bmi,
119 UINT ColorUse)
120 {
121 BITMAPOBJ *bitmap;
122 HBITMAP SourceBitmap;
123 INT result = 0;
124 BOOL copyBitsResult;
125 SURFOBJ *DestSurf, *SourceSurf;
126 SIZEL SourceSize;
127 POINTL ZeroPoint;
128 RECTL DestRect;
129 XLATEOBJ *XlateObj;
130 PPALGDI hDCPalette;
131 //RGBQUAD *lpRGB;
132 HPALETTE DDB_Palette, DIB_Palette;
133 ULONG DDB_Palette_Type, DIB_Palette_Type;
134 INT DIBWidth;
135
136 // Check parameters
137 if (!(bitmap = BITMAPOBJ_LockBitmap(hBitmap)))
138 {
139 return 0;
140 }
141
142 // Get RGB values
143 //if (ColorUse == DIB_PAL_COLORS)
144 // lpRGB = DIB_MapPaletteColors(hDC, bmi);
145 //else
146 // lpRGB = &bmi->bmiColors[0];
147
148 DestSurf = &bitmap->SurfObj;
149
150 // Create source surface
151 SourceSize.cx = bmi->bmiHeader.biWidth;
152 SourceSize.cy = abs(bmi->bmiHeader.biHeight);
153
154 // Determine width of DIB
155 DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
156
157 SourceBitmap = EngCreateBitmap(SourceSize,
158 DIBWidth,
159 BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
160 0 < bmi->bmiHeader.biHeight ? 0 : BMF_TOPDOWN,
161 (PVOID) Bits);
162 if (0 == SourceBitmap)
163 {
164 BITMAPOBJ_UnlockBitmap(hBitmap);
165 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
166 return 0;
167 }
168
169 SourceSurf = EngLockSurface((HSURF)SourceBitmap);
170 if (NULL == SourceSurf)
171 {
172 EngDeleteSurface((HSURF)SourceBitmap);
173 BITMAPOBJ_UnlockBitmap(hBitmap);
174 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
175 return 0;
176 }
177
178 // Destination palette obtained from the hDC
179 hDCPalette = PALETTE_LockPalette(DC->DevInfo->hpalDefault);
180 if (NULL == hDCPalette)
181 {
182 EngUnlockSurface(SourceSurf);
183 EngDeleteSurface((HSURF)SourceBitmap);
184 BITMAPOBJ_UnlockBitmap(hBitmap);
185 SetLastWin32Error(ERROR_INVALID_HANDLE);
186 return 0;
187 }
188 DDB_Palette_Type = hDCPalette->Mode;
189 DDB_Palette = DC->DevInfo->hpalDefault;
190 PALETTE_UnlockPalette(DC->DevInfo->hpalDefault);
191
192 // Source palette obtained from the BITMAPINFO
193 DIB_Palette = BuildDIBPalette ( (PBITMAPINFO)bmi, (PINT)&DIB_Palette_Type );
194 if (NULL == DIB_Palette)
195 {
196 EngUnlockSurface(SourceSurf);
197 EngDeleteSurface((HSURF)SourceBitmap);
198 BITMAPOBJ_UnlockBitmap(hBitmap);
199 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
200 return 0;
201 }
202
203 // Determine XLATEOBJ for color translation
204 XlateObj = IntEngCreateXlate(DDB_Palette_Type, DIB_Palette_Type, DDB_Palette, DIB_Palette);
205 if (NULL == XlateObj)
206 {
207 PALETTE_FreePalette(DIB_Palette);
208 EngUnlockSurface(SourceSurf);
209 EngDeleteSurface((HSURF)SourceBitmap);
210 BITMAPOBJ_UnlockBitmap(hBitmap);
211 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
212 return 0;
213 }
214
215 // Zero point
216 ZeroPoint.x = 0;
217 ZeroPoint.y = 0;
218
219 // Determine destination rectangle
220 DestRect.top = 0;
221 DestRect.left = 0;
222 DestRect.right = SourceSize.cx;
223 DestRect.bottom = SourceSize.cy;
224
225 copyBitsResult = EngCopyBits(DestSurf, SourceSurf, NULL, XlateObj, &DestRect, &ZeroPoint);
226
227 // If it succeeded, return number of scanlines copies
228 if(copyBitsResult == TRUE)
229 {
230 result = SourceSize.cy - 1;
231 }
232
233 // Clean up
234 EngDeleteXlate(XlateObj);
235 PALETTE_FreePalette(DIB_Palette);
236 EngUnlockSurface(SourceSurf);
237 EngDeleteSurface((HSURF)SourceBitmap);
238
239 // if (ColorUse == DIB_PAL_COLORS)
240 // WinFree((LPSTR)lpRGB);
241
242 BITMAPOBJ_UnlockBitmap(hBitmap);
243
244 return result;
245 }
246
247 // Converts a DIB to a device-dependent bitmap
248 INT STDCALL
249 NtGdiSetDIBits(
250 HDC hDC,
251 HBITMAP hBitmap,
252 UINT StartScan,
253 UINT ScanLines,
254 CONST VOID *Bits,
255 CONST BITMAPINFO *bmi,
256 UINT ColorUse)
257 {
258 PDC Dc;
259 INT Ret;
260
261 Dc = DC_LockDc(hDC);
262 if (NULL == Dc)
263 {
264 SetLastWin32Error(ERROR_INVALID_HANDLE);
265 return 0;
266 }
267
268 Ret = IntSetDIBits(Dc, hBitmap, StartScan, ScanLines, Bits, bmi, ColorUse);
269
270 DC_UnlockDc(hDC);
271
272 return Ret;
273 }
274
275 INT STDCALL
276 NtGdiSetDIBitsToDevice(
277 HDC hDC,
278 INT XDest,
279 INT YDest,
280 DWORD Width,
281 DWORD Height,
282 INT XSrc,
283 INT YSrc,
284 UINT StartScan,
285 UINT ScanLines,
286 CONST VOID *Bits,
287 CONST BITMAPINFO *bmi,
288 UINT ColorUse)
289 {
290 UNIMPLEMENTED;
291 return 0;
292 }
293
294 /* Converts a device-dependent bitmap to a DIB */
295 INT STDCALL
296 NtGdiGetDIBits(HDC hDC,
297 HBITMAP hBitmap,
298 UINT StartScan,
299 UINT ScanLines,
300 LPVOID Bits,
301 LPBITMAPINFO Info,
302 UINT Usage)
303 {
304 BITMAPOBJ *BitmapObj;
305 SURFOBJ *DestSurfObj;
306 XLATEOBJ *XlateObj;
307 HBITMAP DestBitmap;
308 SIZEL DestSize;
309 HPALETTE hSourcePalette;
310 HPALETTE hDestPalette;
311 PPALGDI SourcePalette;
312 PPALGDI DestPalette;
313 ULONG SourcePaletteType;
314 ULONG DestPaletteType;
315 PDC Dc;
316 POINTL SourcePoint;
317 RECTL DestRect;
318 ULONG Result = 0;
319 ULONG Index;
320
321 /* Get handle for the palette in DC. */
322 Dc = DC_LockDc(hDC);
323 if (Dc == NULL)
324 {
325 SetLastWin32Error(ERROR_INVALID_HANDLE);
326 return 0;
327 }
328 hSourcePalette = Dc->w.hPalette;
329 /* FIXME: This is incorrect. hDestPalette should be something other. */
330 hDestPalette = Dc->DevInfo->hpalDefault;
331 DC_UnlockDc(hDC);
332
333 /* Get pointer to the source bitmap object. */
334 BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
335 if (BitmapObj == NULL)
336 {
337 SetLastWin32Error(ERROR_INVALID_HANDLE);
338 return 0;
339 }
340
341 if (Bits == NULL)
342 {
343 if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) ||
344 Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
345 {
346 Info->bmiHeader.biWidth = BitmapObj->SurfObj.sizlBitmap.cx;
347 Info->bmiHeader.biHeight = BitmapObj->SurfObj.sizlBitmap.cy;
348 /* Report negtive height for top-down bitmaps. */
349 if (BitmapObj->SurfObj.lDelta > 0)
350 Info->bmiHeader.biHeight = -Info->bmiHeader.biHeight;
351 Info->bmiHeader.biPlanes = 1;
352 Info->bmiHeader.biBitCount = BitsPerFormat(BitmapObj->SurfObj.iBitmapFormat);
353 if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
354 {
355 switch (BitmapObj->SurfObj.iBitmapFormat)
356 {
357 case BMF_1BPP: case BMF_4BPP: case BMF_8BPP:
358 case BMF_16BPP: case BMF_24BPP: case BMF_32BPP:
359 Info->bmiHeader.biCompression = BI_RGB;
360 break;
361 case BMF_4RLE:
362 Info->bmiHeader.biCompression = BI_RLE4;
363 break;
364 case BMF_8RLE:
365 Info->bmiHeader.biCompression = BI_RLE8;
366 break;
367 case BMF_JPEG:
368 Info->bmiHeader.biCompression = BI_JPEG;
369 break;
370 case BMF_PNG:
371 Info->bmiHeader.biCompression = BI_PNG;
372 break;
373 }
374 Info->bmiHeader.biSizeImage = BitmapObj->SurfObj.cjBits;
375 Info->bmiHeader.biXPelsPerMeter = 0; /* FIXME */
376 Info->bmiHeader.biYPelsPerMeter = 0; /* FIXME */
377 Info->bmiHeader.biClrUsed =
378 Info->bmiHeader.biClrImportant = 1 << Info->bmiHeader.biBitCount; /* FIXME */
379 Result = BitmapObj->SurfObj.sizlBitmap.cy;
380 }
381 }
382 }
383 else
384 {
385 if (StartScan > BitmapObj->SurfObj.sizlBitmap.cy)
386 {
387 Result = 0;
388 }
389 else
390 {
391 ScanLines = min(ScanLines, BitmapObj->SurfObj.sizlBitmap.cy - StartScan);
392 DestSize.cx = BitmapObj->SurfObj.sizlBitmap.cx;
393 DestSize.cy = ScanLines;
394 DestBitmap = EngCreateBitmap(
395 DestSize, BitmapObj->SurfObj.lDelta,
396 BitmapFormat(Info->bmiHeader.biBitCount, Info->bmiHeader.biCompression),
397 0 < Info->bmiHeader.biHeight ? 0 : BMF_TOPDOWN,
398 Bits);
399 DestSurfObj = EngLockSurface((HSURF)DestBitmap);
400
401 SourcePalette = PALETTE_LockPalette(hSourcePalette);
402 /* FIXME - SourcePalette can be NULL!!! Don't assert here! */
403 ASSERT(SourcePalette);
404 SourcePaletteType = SourcePalette->Mode;
405 PALETTE_UnlockPalette(hSourcePalette);
406
407 DestPalette = PALETTE_LockPalette(hDestPalette);
408 /* FIXME - DestPalette can be NULL!!!! Don't assert here!!! */
409 ASSERT(DestPalette);
410 DestPaletteType = DestPalette->Mode;
411
412 /* Copy palette. */
413 /* FIXME: This is largely incomplete. */
414 if (Info->bmiHeader.biBitCount <= 8)
415 {
416 if (Usage == DIB_RGB_COLORS)
417 {
418 for (Index = 0;
419 Index < (1 << Info->bmiHeader.biBitCount) &&
420 Index < DestPalette->NumColors;
421 Index++)
422 {
423 Info->bmiColors[Index].rgbRed =
424 DestPalette->IndexedColors[Index].peRed;
425 Info->bmiColors[Index].rgbGreen =
426 DestPalette->IndexedColors[Index].peGreen;
427 Info->bmiColors[Index].rgbBlue =
428 DestPalette->IndexedColors[Index].peBlue;
429 }
430 }
431 if (Usage == DIB_PAL_COLORS)
432 {
433 DbgPrint("GetDIBits with DIB_PAL_COLORS isn't implemented yet.");
434 }
435 }
436
437 PALETTE_UnlockPalette(hDestPalette);
438
439 XlateObj = IntEngCreateXlate(
440 DestPaletteType, SourcePaletteType, hDestPalette, hSourcePalette);
441
442 SourcePoint.x = 0;
443 SourcePoint.y = StartScan;
444
445 /* Determine destination rectangle */
446 DestRect.top = 0;
447 DestRect.left = 0;
448 DestRect.right = DestSize.cx;
449 DestRect.bottom = DestSize.cy;
450
451 if (EngCopyBits(DestSurfObj, &BitmapObj->SurfObj,
452 NULL, XlateObj, &DestRect, &SourcePoint))
453 {
454 Result = ScanLines;
455 }
456
457 EngDeleteXlate(XlateObj);
458 EngUnlockSurface(DestSurfObj);
459 }
460 }
461
462 BITMAPOBJ_UnlockBitmap(hBitmap);
463
464 return Result;
465 }
466
467 INT STDCALL NtGdiStretchDIBits(HDC hDC,
468 INT XDest,
469 INT YDest,
470 INT DestWidth,
471 INT DestHeight,
472 INT XSrc,
473 INT YSrc,
474 INT SrcWidth,
475 INT SrcHeight,
476 CONST VOID *Bits,
477 CONST BITMAPINFO *BitsInfo,
478 UINT Usage,
479 DWORD ROP)
480 {
481 HBITMAP hBitmap, hOldBitmap;
482 HDC hdcMem;
483
484 if (!Bits || !BitsInfo)
485 {
486 SetLastWin32Error(ERROR_INVALID_PARAMETER);
487 return 0;
488 }
489
490 hdcMem = NtGdiCreateCompatableDC(hDC);
491 hBitmap = NtGdiCreateCompatibleBitmap(hDC, BitsInfo->bmiHeader.biWidth,
492 BitsInfo->bmiHeader.biHeight);
493 hOldBitmap = NtGdiSelectObject(hdcMem, hBitmap);
494
495 if (BitsInfo->bmiHeader.biCompression == BI_RLE4 ||
496 BitsInfo->bmiHeader.biCompression == BI_RLE8)
497 {
498 /* copy existing bitmap from destination dc */
499 if (SrcWidth == DestWidth && SrcHeight == DestHeight)
500 NtGdiBitBlt(hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
501 SrcWidth, SrcHeight, hDC, XDest, YDest, ROP);
502 else
503 NtGdiStretchBlt(hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
504 SrcWidth, SrcHeight, hDC, XDest, YDest, DestWidth, DestHeight,
505 ROP);
506 }
507
508 NtGdiSetDIBits(hdcMem, hBitmap, 0, BitsInfo->bmiHeader.biHeight, Bits,
509 BitsInfo, Usage);
510
511 /* Origin for DIBitmap may be bottom left (positive biHeight) or top
512 left (negative biHeight) */
513 if (SrcWidth == DestWidth && SrcHeight == DestHeight)
514 NtGdiBitBlt(hDC, XDest, YDest, DestWidth, DestHeight,
515 hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
516 ROP);
517 else
518 NtGdiStretchBlt(hDC, XDest, YDest, DestWidth, DestHeight,
519 hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
520 SrcWidth, SrcHeight, ROP);
521
522 NtGdiSelectObject(hdcMem, hOldBitmap);
523 NtGdiDeleteDC(hdcMem);
524 NtGdiDeleteObject(hBitmap);
525
526 return SrcHeight;
527 }
528
529 LONG STDCALL NtGdiGetBitmapBits(HBITMAP hBitmap,
530 LONG Count,
531 LPVOID Bits)
532 {
533 PBITMAPOBJ bmp;
534 LONG height, ret;
535
536 bmp = BITMAPOBJ_LockBitmap (hBitmap);
537 if (!bmp)
538 {
539 return 0;
540 }
541
542 /* If the bits vector is null, the function should return the read size */
543 if (Bits == NULL)
544 {
545 ret = bmp->SurfObj.cjBits;
546 BITMAPOBJ_UnlockBitmap (hBitmap);
547 return ret;
548 }
549
550 if (Count < 0)
551 {
552 DPRINT ("(%ld): Negative number of bytes passed???\n", Count);
553 Count = -Count;
554 }
555
556 /* Only get entire lines */
557 height = Count / abs(bmp->SurfObj.lDelta);
558 if (height > bmp->SurfObj.sizlBitmap.cy)
559 {
560 height = bmp->SurfObj.sizlBitmap.cy;
561 }
562 Count = height * abs(bmp->SurfObj.lDelta);
563 if (Count == 0)
564 {
565 DPRINT("Less then one entire line requested\n");
566 BITMAPOBJ_UnlockBitmap (hBitmap);
567 return 0;
568 }
569
570 DPRINT("(%08x, %ld, %p) %dx%d %d colors fetched height: %ld\n",
571 hBitmap, Count, Bits, bmp->SurfObj.sizlBitmap.cx,
572 bmp->SurfObj.sizlBitmap.cy,
573 1 << BitsPerFormat(bmp->SurfObj.iBitmapFormat), height );
574 #if 0
575 /* FIXME: Call DDI CopyBits here if available */
576 if(bmp->DDBitmap)
577 {
578 DPRINT("Calling device specific BitmapBits\n");
579 if(bmp->DDBitmap->funcs->pBitmapBits)
580 {
581 ret = bmp->DDBitmap->funcs->pBitmapBits(hbitmap, bits, count,
582 DDB_GET);
583 }
584 else
585 {
586 ERR_(bitmap)("BitmapBits == NULL??\n");
587 ret = 0;
588 }
589 }
590 else
591 #endif
592 {
593 memcpy(Bits, bmp->SurfObj.pvBits, Count);
594 ret = Count;
595 }
596
597 BITMAPOBJ_UnlockBitmap (hBitmap);
598
599 return ret;
600 }
601
602 static HBITMAP FASTCALL
603 IntCreateDIBitmap(PDC Dc, const BITMAPINFOHEADER *header,
604 DWORD init, LPCVOID bits, const BITMAPINFO *data,
605 UINT coloruse)
606 {
607 HBITMAP handle;
608 BOOL fColor;
609 DWORD width;
610 int height;
611 WORD bpp;
612 WORD compr;
613
614 if (DIB_GetBitmapInfo( header, &width, &height, &bpp, &compr ) == -1) return 0;
615
616 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
617 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
618
619 if (bpp != 1) fColor = TRUE;
620 else if ((coloruse != DIB_RGB_COLORS) ||
621 (init != CBM_INIT) || !data) fColor = FALSE;
622 else
623 {
624 if (data->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
625 {
626 RGBQUAD *rgb = data->bmiColors;
627 DWORD col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
628
629 // Check if the first color of the colormap is black
630 if ((col == RGB(0, 0, 0)))
631 {
632 rgb++;
633 col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue );
634
635 // If the second color is white, create a monochrome bitmap
636 fColor = (col != RGB(0xff,0xff,0xff));
637 }
638 else fColor = TRUE;
639 }
640 else if (data->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
641 {
642 RGBTRIPLE *rgb = ((BITMAPCOREINFO *)data)->bmciColors;
643 DWORD col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue);
644
645 if ((col == RGB(0,0,0)))
646 {
647 rgb++;
648 col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue );
649 fColor = (col != RGB(0xff,0xff,0xff));
650 }
651 else fColor = TRUE;
652 }
653 else
654 {
655 DPRINT("(%ld): wrong size for data\n", data->bmiHeader.biSize );
656 return 0;
657 }
658 }
659
660 // Now create the bitmap
661 if (fColor)
662 {
663 handle = IntCreateCompatibleBitmap(Dc, width, height);
664 }
665 else
666 {
667 handle = NtGdiCreateBitmap( width, height, 1, 1, NULL);
668 }
669
670 if (height < 0)
671 height = -height;
672
673 if (NULL != handle && CBM_INIT == init)
674 {
675 IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
676 }
677
678 return handle;
679 }
680
681 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
682 // The DDB that is created will be whatever bit depth your reference DC is
683 HBITMAP STDCALL NtGdiCreateDIBitmap(HDC hDc, const BITMAPINFOHEADER *Header,
684 DWORD Init, LPCVOID Bits, const BITMAPINFO *Data,
685 UINT ColorUse)
686 {
687 PDC Dc;
688 HBITMAP Bmp;
689
690 Dc = DC_LockDc(hDc);
691 if (NULL == Dc)
692 {
693 SetLastWin32Error(ERROR_INVALID_HANDLE);
694 return NULL;
695 }
696
697 Bmp = IntCreateDIBitmap(Dc, Header, Init, Bits, Data, ColorUse);
698
699 DC_UnlockDc(hDc);
700
701 return Bmp;
702 }
703
704 HBITMAP STDCALL NtGdiCreateDIBSection(HDC hDC,
705 CONST BITMAPINFO *bmi,
706 UINT Usage,
707 VOID *Bits,
708 HANDLE hSection,
709 DWORD dwOffset)
710 {
711 HBITMAP hbitmap = 0;
712 DC *dc;
713 BOOL bDesktopDC = FALSE;
714
715 // If the reference hdc is null, take the desktop dc
716 if (hDC == 0)
717 {
718 hDC = NtGdiCreateCompatableDC(0);
719 bDesktopDC = TRUE;
720 }
721
722 if ((dc = DC_LockDc(hDC)))
723 {
724 hbitmap = DIB_CreateDIBSection ( dc, (BITMAPINFO*)bmi, Usage, Bits,
725 hSection, dwOffset, 0);
726 DC_UnlockDc(hDC);
727 }
728
729 if (bDesktopDC)
730 NtGdiDeleteDC(hDC);
731
732 return hbitmap;
733 }
734
735 HBITMAP STDCALL
736 DIB_CreateDIBSection(
737 PDC dc, BITMAPINFO *bmi, UINT usage,
738 LPVOID *bits, HANDLE section,
739 DWORD offset, DWORD ovr_pitch)
740 {
741 HBITMAP res = 0;
742 BITMAPOBJ *bmp = NULL;
743 DIBSECTION *dib = NULL;
744
745 // Fill BITMAP32 structure with DIB data
746 BITMAPINFOHEADER *bi = &bmi->bmiHeader;
747 INT effHeight;
748 ULONG totalSize;
749 UINT Entries = 0;
750 BITMAP bm;
751 SIZEL Size;
752
753 DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
754 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
755 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
756
757 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
758 bm.bmType = 0;
759 bm.bmWidth = bi->biWidth;
760 bm.bmHeight = effHeight;
761 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : (ULONG) DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
762
763 bm.bmPlanes = bi->biPlanes;
764 bm.bmBitsPixel = bi->biBitCount;
765 bm.bmBits = NULL;
766
767 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
768 // we're dealing with a compressed bitmap. Otherwise, use width * height.
769 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
770 ? bi->biSizeImage : (ULONG) (bm.bmWidthBytes * effHeight);
771
772 if (section)
773 {
774 /* bm.bmBits = MapViewOfFile(section, FILE_MAP_ALL_ACCESS,
775 0L, offset, totalSize); */
776 DbgPrint("DIB_CreateDIBSection: Cannot yet handle section DIBs\n");
777 return 0;
778 }
779 else if (ovr_pitch && offset)
780 bm.bmBits = (LPVOID) offset;
781 else {
782 offset = 0;
783 bm.bmBits = EngAllocUserMem(totalSize, 0);
784 }
785
786 if(usage == DIB_PAL_COLORS)
787 memcpy(bmi->bmiColors, (UINT *)DIB_MapPaletteColors(dc, bmi), sizeof(UINT *));
788
789 // Allocate Memory for DIB and fill structure
790 if (bm.bmBits)
791 {
792 dib = ExAllocatePoolWithTag(PagedPool, sizeof(DIBSECTION), TAG_DIB);
793 RtlZeroMemory(dib, sizeof(DIBSECTION));
794 }
795
796 if (dib)
797 {
798 dib->dsBm = bm;
799 dib->dsBmih = *bi;
800 dib->dsBmih.biSizeImage = totalSize;
801
802 /* Set dsBitfields values */
803 if ( usage == DIB_PAL_COLORS || bi->biBitCount <= 8)
804 {
805 dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
806 }
807 else switch(bi->biBitCount)
808 {
809 case 16:
810 dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0x7c00;
811 dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0x03e0;
812 dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0x001f; break;
813
814 case 24:
815 dib->dsBitfields[0] = 0xff0000;
816 dib->dsBitfields[1] = 0x00ff00;
817 dib->dsBitfields[2] = 0x0000ff;
818 break;
819
820 case 32:
821 dib->dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)bmi->bmiColors : 0xff0000;
822 dib->dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 1) : 0x00ff00;
823 dib->dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)bmi->bmiColors + 2) : 0x0000ff;
824 break;
825 }
826 dib->dshSection = section;
827 dib->dsOffset = offset;
828 }
829
830 // Create Device Dependent Bitmap and add DIB pointer
831 if (dib)
832 {
833 Size.cx = bm.bmWidth;
834 Size.cy = bm.bmHeight;
835 res = IntCreateBitmap(Size, bm.bmWidthBytes,
836 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
837 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
838 (bi->biHeight > 0 ? 0 : BMF_TOPDOWN),
839 bm.bmBits);
840 if (! res)
841 {
842 return NULL;
843 }
844 bmp = BITMAPOBJ_LockBitmap(res);
845 if (NULL == bmp)
846 {
847 NtGdiDeleteObject(bmp);
848 return NULL;
849 }
850 bmp->dib = (DIBSECTION *) dib;
851
852 /* WINE NOTE: WINE makes use of a colormap, which is a color translation table between the DIB and the X physical
853 device. Obviously, this is left out of the ReactOS implementation. Instead, we call
854 NtGdiSetDIBColorTable. */
855 if(bi->biBitCount == 1) { Entries = 2; } else
856 if(bi->biBitCount == 4) { Entries = 16; } else
857 if(bi->biBitCount == 8) { Entries = 256; }
858
859 bmp->ColorMap = ExAllocatePoolWithTag(PagedPool, sizeof(RGBQUAD)*Entries, TAG_COLORMAP);
860 RtlCopyMemory(bmp->ColorMap, bmi->bmiColors, sizeof(RGBQUAD)*Entries);
861 }
862
863 // Clean up in case of errors
864 if (!res || !bmp || !dib || !bm.bmBits)
865 {
866 DPRINT("got an error res=%08x, bmp=%p, dib=%p, bm.bmBits=%p\n", res, bmp, dib, bm.bmBits);
867 /* if (bm.bmBits)
868 {
869 if (section)
870 UnmapViewOfFile(bm.bmBits), bm.bmBits = NULL;
871 else if (!offset)
872 VirtualFree(bm.bmBits, 0L, MEM_RELEASE), bm.bmBits = NULL;
873 } */
874
875 if (dib) { ExFreePool(dib); dib = NULL; }
876 if (bmp) { bmp = NULL; }
877 if (res) { BITMAPOBJ_FreeBitmap(res); res = 0; }
878 }
879
880 if (bmp)
881 {
882 BITMAPOBJ_UnlockBitmap(res);
883 }
884
885 // Return BITMAP handle and storage location
886 if (NULL != bm.bmBits && NULL != bits)
887 {
888 *bits = bm.bmBits;
889 }
890
891 return res;
892 }
893
894 /***********************************************************************
895 * DIB_GetDIBWidthBytes
896 *
897 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
898 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
899 * 11/16/1999 (RJJ) lifted from wine
900 */
901 INT FASTCALL DIB_GetDIBWidthBytes (INT width, INT depth)
902 {
903 int words;
904
905 switch(depth)
906 {
907 case 1: words = (width + 31) >> 5; break;
908 case 4: words = (width + 7) >> 3; break;
909 case 8: words = (width + 3) >> 2; break;
910 case 15:
911 case 16: words = (width + 1) >> 1; break;
912 case 24: words = (width * 3 + 3) >> 2; break;
913
914 default:
915 DPRINT("(%d): Unsupported depth\n", depth );
916 /* fall through */
917 case 32:
918 words = width;
919 }
920 return words << 2;
921 }
922
923 /***********************************************************************
924 * DIB_GetDIBImageBytes
925 *
926 * Return the number of bytes used to hold the image in a DIB bitmap.
927 * 11/16/1999 (RJJ) lifted from wine
928 */
929
930 INT STDCALL DIB_GetDIBImageBytes (INT width, INT height, INT depth)
931 {
932 return DIB_GetDIBWidthBytes( width, depth ) * (height < 0 ? -height : height);
933 }
934
935 /***********************************************************************
936 * DIB_BitmapInfoSize
937 *
938 * Return the size of the bitmap info structure including color table.
939 * 11/16/1999 (RJJ) lifted from wine
940 */
941
942 INT FASTCALL DIB_BitmapInfoSize (const BITMAPINFO * info, WORD coloruse)
943 {
944 int colors;
945
946 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
947 {
948 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)info;
949 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
950 return sizeof(BITMAPCOREHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
951 }
952 else /* assume BITMAPINFOHEADER */
953 {
954 colors = info->bmiHeader.biClrUsed;
955 if (!colors && (info->bmiHeader.biBitCount <= 8)) colors = 1 << info->bmiHeader.biBitCount;
956 return sizeof(BITMAPINFOHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
957 }
958 }
959
960 INT STDCALL DIB_GetBitmapInfo (const BITMAPINFOHEADER *header,
961 PDWORD width,
962 PINT height,
963 PWORD bpp,
964 PWORD compr)
965 {
966 if (header->biSize == sizeof(BITMAPINFOHEADER))
967 {
968 *width = header->biWidth;
969 *height = header->biHeight;
970 *bpp = header->biBitCount;
971 *compr = header->biCompression;
972 return 1;
973 }
974 if (header->biSize == sizeof(BITMAPCOREHEADER))
975 {
976 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)header;
977 *width = core->bcWidth;
978 *height = core->bcHeight;
979 *bpp = core->bcBitCount;
980 *compr = 0;
981 return 0;
982 }
983 DPRINT("(%ld): wrong size for header\n", header->biSize );
984 return -1;
985 }
986
987 // Converts a Device Independent Bitmap (DIB) to a Device Dependant Bitmap (DDB)
988 // The specified Device Context (DC) defines what the DIB should be converted to
989 PBITMAPOBJ FASTCALL DIBtoDDB(HGLOBAL hPackedDIB, HDC hdc) // FIXME: This should be removed. All references to this function should
990 // change to NtGdiSetDIBits
991 {
992 HBITMAP hBmp = 0;
993 PBITMAPOBJ pBmp = NULL;
994 DIBSECTION *dib;
995 LPBYTE pbits = NULL;
996
997 // Get a pointer to the packed DIB's data
998 // pPackedDIB = (LPBYTE)GlobalLock(hPackedDIB);
999 dib = hPackedDIB;
1000
1001 pbits = (LPBYTE)(dib + DIB_BitmapInfoSize((BITMAPINFO*)&dib->dsBmih, DIB_RGB_COLORS));
1002
1003 // Create a DDB from the DIB
1004 hBmp = NtGdiCreateDIBitmap ( hdc, &dib->dsBmih, CBM_INIT,
1005 (LPVOID)pbits, (BITMAPINFO*)&dib->dsBmih, DIB_RGB_COLORS);
1006
1007 // GlobalUnlock(hPackedDIB);
1008
1009 // Retrieve the internal Pixmap from the DDB
1010 pBmp = BITMAPOBJ_LockBitmap(hBmp);
1011
1012 return pBmp;
1013 }
1014
1015 RGBQUAD * FASTCALL
1016 DIB_MapPaletteColors(PDC dc, CONST BITMAPINFO* lpbmi)
1017 {
1018 RGBQUAD *lpRGB;
1019 ULONG nNumColors,i;
1020 USHORT *lpIndex;
1021 PPALGDI palGDI;
1022
1023 palGDI = PALETTE_LockPalette(dc->w.hPalette);
1024
1025 if (NULL == palGDI)
1026 {
1027 // RELEASEDCINFO(hDC);
1028 return NULL;
1029 }
1030
1031 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
1032 if (lpbmi->bmiHeader.biClrUsed)
1033 {
1034 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
1035 }
1036
1037 lpRGB = (RGBQUAD *)ExAllocatePoolWithTag(PagedPool, sizeof(RGBQUAD) * nNumColors, TAG_COLORMAP);
1038 lpIndex = (USHORT *)&lpbmi->bmiColors[0];
1039
1040 for (i = 0; i < nNumColors; i++)
1041 {
1042 lpRGB[i].rgbRed = palGDI->IndexedColors[*lpIndex].peRed;
1043 lpRGB[i].rgbGreen = palGDI->IndexedColors[*lpIndex].peGreen;
1044 lpRGB[i].rgbBlue = palGDI->IndexedColors[*lpIndex].peBlue;
1045 lpIndex++;
1046 }
1047 // RELEASEDCINFO(hDC);
1048 PALETTE_UnlockPalette(dc->w.hPalette);
1049
1050 return lpRGB;
1051 }
1052
1053 HPALETTE FASTCALL
1054 BuildDIBPalette (PBITMAPINFO bmi, PINT paletteType)
1055 {
1056 BYTE bits;
1057 ULONG ColorCount;
1058 PALETTEENTRY *palEntries = NULL;
1059 HPALETTE hPal;
1060
1061 // Determine Bits Per Pixel
1062 bits = bmi->bmiHeader.biBitCount;
1063
1064 // Determine paletteType from Bits Per Pixel
1065 if (bits <= 8)
1066 {
1067 *paletteType = PAL_INDEXED;
1068 }
1069 else if(bits < 24)
1070 {
1071 *paletteType = PAL_BITFIELDS;
1072 }
1073 else
1074 {
1075 *paletteType = PAL_BGR;
1076 }
1077
1078 if (bmi->bmiHeader.biClrUsed == 0)
1079 {
1080 ColorCount = 1 << bmi->bmiHeader.biBitCount;
1081 }
1082 else
1083 {
1084 ColorCount = bmi->bmiHeader.biClrUsed;
1085 }
1086
1087 if (PAL_INDEXED == *paletteType)
1088 {
1089 hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)bmi->bmiColors);
1090 }
1091 else
1092 {
1093 hPal = PALETTE_AllocPalette( *paletteType, ColorCount, (ULONG*)palEntries, 0, 0, 0 );
1094 }
1095
1096 return hPal;
1097 }
1098
1099 /* EOF */