gdi32: Add checks for invalid color usage values.
[wine/multimedia.git] / dlls / gdi32 / dib.c
blobb9ffbbe65e8b8fb39f50a1d9afea0ca76d6e7ae2
1 /*
2 * GDI device-independent bitmaps
4 * Copyright 1993,1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 Important information:
24 * Current Windows versions support two different DIB structures:
26 - BITMAPCOREINFO / BITMAPCOREHEADER (legacy structures; used in OS/2)
27 - BITMAPINFO / BITMAPINFOHEADER
29 Most Windows API functions taking a BITMAPINFO* / BITMAPINFOHEADER* also
30 accept the old "core" structures, and so must WINE.
31 You can distinguish them by looking at the first member (bcSize/biSize).
34 * The palettes are stored in different formats:
36 - BITMAPCOREINFO: Array of RGBTRIPLE
37 - BITMAPINFO: Array of RGBQUAD
40 * There are even more DIB headers, but they all extend BITMAPINFOHEADER:
42 - BITMAPV4HEADER: Introduced in Windows 95 / NT 4.0
43 - BITMAPV5HEADER: Introduced in Windows 98 / 2000
45 If biCompression is BI_BITFIELDS, the color masks are at the same position
46 in all the headers (they start at bmiColors of BITMAPINFOHEADER), because
47 the new headers have structure members for the masks.
50 * You should never access the color table using the bmiColors member,
51 because the passed structure may have one of the extended headers
52 mentioned above. Use this to calculate the location:
54 BITMAPINFO* info;
55 void* colorPtr = (LPBYTE) info + (WORD) info->bmiHeader.biSize;
58 * More information:
59 Search for "Bitmap Structures" in MSDN
62 #include <stdarg.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <assert.h>
67 #include "windef.h"
68 #include "winbase.h"
69 #include "gdi_private.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
75 /***********************************************************************
76 * bitmap_info_size
78 * Return the size of the bitmap info structure including color table.
80 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
82 unsigned int colors, size, masks = 0;
84 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
86 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
87 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
88 return sizeof(BITMAPCOREHEADER) + colors *
89 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
91 else /* assume BITMAPINFOHEADER */
93 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
94 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
95 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
96 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
97 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
101 /*******************************************************************************************
102 * Verify that the DIB parameters are valid.
104 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
106 if (info->biWidth <= 0) return FALSE;
107 if (info->biHeight == 0) return FALSE;
109 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
111 if (info->biHeight < 0) return FALSE;
112 if (!info->biSizeImage) return FALSE;
113 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
116 if (!info->biPlanes) return FALSE;
118 switch (info->biBitCount)
120 case 1:
121 case 4:
122 case 8:
123 case 24:
124 return (info->biCompression == BI_RGB);
125 case 16:
126 case 32:
127 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
128 default:
129 return FALSE;
133 /*******************************************************************************************
134 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
136 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
138 if (!info) return FALSE;
140 if (info->biSize == sizeof(BITMAPCOREHEADER))
142 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
143 dst->biWidth = core->bcWidth;
144 dst->biHeight = core->bcHeight;
145 dst->biPlanes = core->bcPlanes;
146 dst->biBitCount = core->bcBitCount;
147 dst->biCompression = BI_RGB;
148 dst->biXPelsPerMeter = 0;
149 dst->biYPelsPerMeter = 0;
150 dst->biClrUsed = 0;
151 dst->biClrImportant = 0;
153 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
155 *dst = *info;
157 else
159 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
160 return FALSE;
163 dst->biSize = sizeof(*dst);
164 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
165 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
166 return TRUE;
169 /*******************************************************************************************
170 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
172 * The resulting sanitized BITMAPINFO is guaranteed to have:
173 * - biSize set to sizeof(BITMAPINFOHEADER)
174 * - biSizeImage set to the actual image size even for non-compressed DIB
175 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
176 * - color table present only for <= 8 bpp, always starts at info->bmiColors
178 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
179 UINT coloruse, BOOL allow_compression )
181 void *src_colors;
183 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
184 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
185 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
187 src_colors = (char *)info + info->bmiHeader.biSize;
189 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
191 /* bitfields are always at bmiColors even in larger structures */
192 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
193 dst->bmiHeader.biClrUsed = 0;
195 else if (dst->bmiHeader.biBitCount <= 8)
197 unsigned int colors = dst->bmiHeader.biClrUsed;
198 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
200 if (!colors) colors = max_colors;
201 else colors = min( colors, max_colors );
203 if (coloruse == DIB_PAL_COLORS)
205 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
206 max_colors = colors;
208 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
210 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
212 else
214 unsigned int i;
215 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
216 for (i = 0; i < colors; i++)
218 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
219 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
220 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
221 dst->bmiColors[i].rgbReserved = 0;
224 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
225 dst->bmiHeader.biClrUsed = max_colors;
227 else dst->bmiHeader.biClrUsed = 0;
229 return TRUE;
232 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
234 PALETTEENTRY palEntry[256];
235 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
236 int i, colors = 1 << info->bmiHeader.biBitCount;
238 info->bmiHeader.biClrUsed = colors;
240 if (!palette) return 0;
242 memset( palEntry, 0, sizeof(palEntry) );
243 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
244 return 0;
246 for (i = 0; i < colors; i++)
248 info->bmiColors[i].rgbRed = palEntry[i].peRed;
249 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
250 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
251 info->bmiColors[i].rgbReserved = 0;
254 return colors;
257 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
259 PALETTEENTRY entries[256];
260 RGBQUAD table[256];
261 HPALETTE palette;
262 const WORD *index = (const WORD *)info->bmiColors;
263 int i, count, colors = info->bmiHeader.biClrUsed;
265 if (!colors) return TRUE;
266 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
267 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
269 for (i = 0; i < colors; i++, index++)
271 table[i].rgbRed = entries[*index % count].peRed;
272 table[i].rgbGreen = entries[*index % count].peGreen;
273 table[i].rgbBlue = entries[*index % count].peBlue;
274 table[i].rgbReserved = 0;
276 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
277 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
278 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
279 return TRUE;
282 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
284 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
285 const int bpp = info->bmiHeader.biBitCount;
287 if (height > 0)
288 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
289 else
290 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
293 static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
295 int i = 0;
296 int left, right;
297 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
298 HRGN run = NULL;
299 BYTE skip, num, data;
300 BYTE *out_bits, *in_bits = bits->ptr;
302 if (clip) *clip = NULL;
304 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
306 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
307 if (!out_bits) goto fail;
309 if (clip)
311 *clip = CreateRectRgn( 0, 0, 0, 0 );
312 run = CreateRectRgn( 0, 0, 0, 0 );
313 if (!*clip || !run) goto fail;
316 x = left = right = 0;
317 y = height - 1;
319 while (i < info->bmiHeader.biSizeImage - 1)
321 num = in_bits[i];
322 data = in_bits[i + 1];
323 i += 2;
325 if (num)
327 if (x + num > width) num = width - x;
328 if (num)
330 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
331 if (info->bmiHeader.biBitCount == 8)
332 memset( out_ptr, s, num );
333 else
335 if(x & 1)
337 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
338 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
339 out_ptr++;
340 x++;
341 num--;
343 /* this will write one too many if num is odd, but that doesn't matter */
344 if (num) memset( out_ptr, s, (num + 1) / 2 );
347 x += num;
348 right = x;
350 else
352 if (data < 3)
354 if(left != right && clip)
356 SetRectRgn( run, left, y, right, y + 1 );
357 CombineRgn( *clip, run, *clip, RGN_OR );
359 switch (data)
361 case 0: /* eol */
362 left = right = x = 0;
363 y--;
364 if(y < 0) goto done;
365 break;
367 case 1: /* eod */
368 goto done;
370 case 2: /* delta */
371 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
372 x += in_bits[i];
373 if (x > width) x = width;
374 left = right = x;
375 y -= in_bits[i + 1];
376 if(y < 0) goto done;
377 i += 2;
380 else /* data bytes of data */
382 num = data;
383 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
384 if (skip > info->bmiHeader.biSizeImage - i) goto done;
385 skip = (skip + 1) & ~1;
386 if (x + num > width) num = width - x;
387 if (num)
389 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
390 if (info->bmiHeader.biBitCount == 8)
391 memcpy( out_ptr, in_bits + i, num );
392 else
394 if(x & 1)
396 const BYTE *in_ptr = in_bits + i;
397 for ( ; num; num--, x++)
399 if (x & 1)
401 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
402 out_ptr++;
404 else
405 *out_ptr = (*in_ptr++ << 4) & 0xf0;
408 else
409 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
412 x += num;
413 right = x;
414 i += skip;
419 done:
420 if (run) DeleteObject( run );
421 if (bits->free) bits->free( bits );
423 bits->ptr = out_bits;
424 bits->is_copy = TRUE;
425 bits->free = free_heap_bits;
427 return TRUE;
429 fail:
430 if (run) DeleteObject( run );
431 if (clip && *clip) DeleteObject( *clip );
432 HeapFree( GetProcessHeap(), 0, out_bits );
433 return FALSE;
438 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
439 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
440 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
442 DC *dc = get_nulldrv_dc( dev );
443 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
444 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
445 struct bitblt_coords src, dst;
446 struct gdi_image_bits src_bits;
447 DWORD err;
448 HRGN clip = NULL;
449 INT ret = 0;
450 INT height = abs( src_info->bmiHeader.biHeight );
451 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
452 RECT rect;
454 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
455 xSrc, ySrc, widthSrc, heightSrc, rop);
457 src_bits.ptr = (void*)bits;
458 src_bits.is_copy = FALSE;
459 src_bits.free = NULL;
461 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
463 rect.left = xDst;
464 rect.top = yDst;
465 rect.right = xDst + widthDst;
466 rect.bottom = yDst + heightDst;
467 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
468 dst.x = rect.left;
469 dst.y = rect.top;
470 dst.width = rect.right - rect.left;
471 dst.height = rect.bottom - rect.top;
473 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
475 dst.x += dst.width;
476 dst.width = -dst.width;
478 rop &= ~NOMIRRORBITMAP;
480 src.x = xSrc;
481 src.width = widthSrc;
482 src.y = ySrc;
483 src.height = heightSrc;
485 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
486 non_stretch_from_origin = TRUE;
488 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
490 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
491 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
494 if (rop != SRCCOPY || non_stretch_from_origin)
496 if (dst.width == 1 && src.width > 1) src.width--;
497 if (dst.height == 1 && src.height > 1) src.height--;
500 if (rop != SRCCOPY)
502 if (dst.width < 0 && dst.width == src.width)
504 /* This is off-by-one, but that's what Windows does */
505 dst.x += dst.width;
506 src.x += src.width;
507 dst.width = -dst.width;
508 src.width = -src.width;
510 if (dst.height < 0 && dst.height == src.height)
512 dst.y += dst.height;
513 src.y += src.height;
514 dst.height = -dst.height;
515 src.height = -src.height;
519 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
521 if (src.y >= height && src.y + src.height + 1 < height)
522 src.y = height - 1;
523 else if (src.y > 0 && src.y + src.height + 1 < 0)
524 src.y = -src.height - 1;
526 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
528 src.visrect.left = 0;
529 src.visrect.right = src_info->bmiHeader.biWidth;
530 src.visrect.top = 0;
531 src.visrect.bottom = height;
532 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
534 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
536 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
538 if (!intersect_vis_rectangles( &dst, &src )) goto done;
540 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
542 dev = GET_DC_PHYSDEV( dc, pPutImage );
543 copy_bitmapinfo( dst_info, src_info );
544 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
545 if (err == ERROR_BAD_FORMAT)
547 /* 1-bpp destination without a color table requires a fake 1-entry table
548 * that contains only the background color */
549 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
551 COLORREF color = GetBkColor( dev->hdc );
552 dst_info->bmiColors[0].rgbRed = GetRValue( color );
553 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
554 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
555 dst_info->bmiColors[0].rgbReserved = 0;
556 dst_info->bmiHeader.biClrUsed = 1;
559 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE )))
561 /* get rid of the fake 1-bpp table */
562 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
563 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
567 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
569 copy_bitmapinfo( src_info, dst_info );
570 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
571 if (!err) err = dev->funcs->pPutImage( dev, 0, NULL, dst_info, &src_bits, &src, &dst, rop );
573 if (err) ret = 0;
574 else if (rop == SRCCOPY) ret = height;
575 else ret = src_info->bmiHeader.biHeight;
577 done:
578 if (src_bits.free) src_bits.free( &src_bits );
579 if (clip) DeleteObject( clip );
580 return ret;
583 /***********************************************************************
584 * StretchDIBits (GDI32.@)
586 INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
587 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
588 const BITMAPINFO *bmi, UINT coloruse, DWORD rop )
590 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
591 BITMAPINFO *info = (BITMAPINFO *)buffer;
592 DC *dc;
593 INT ret = 0;
595 if (!bits) return 0;
596 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
598 SetLastError( ERROR_INVALID_PARAMETER );
599 return 0;
602 if ((dc = get_dc_ptr( hdc )))
604 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
605 update_dc( dc );
606 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
607 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
608 release_dc_ptr( dc );
610 return ret;
614 /******************************************************************************
615 * SetDIBits [GDI32.@]
617 * Sets pixels in a bitmap using colors from DIB.
619 * PARAMS
620 * hdc [I] Handle to device context
621 * hbitmap [I] Handle to bitmap
622 * startscan [I] Starting scan line
623 * lines [I] Number of scan lines
624 * bits [I] Array of bitmap bits
625 * info [I] Address of structure with data
626 * coloruse [I] Type of color indexes to use
628 * RETURNS
629 * Success: Number of scan lines copied
630 * Failure: 0
632 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
633 UINT lines, LPCVOID bits, const BITMAPINFO *info,
634 UINT coloruse )
636 BITMAPOBJ *bitmap;
637 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
638 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
639 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
640 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
641 INT result = 0;
642 DWORD err;
643 struct gdi_image_bits src_bits;
644 struct bitblt_coords src, dst;
645 INT src_to_dst_offset;
646 HRGN clip = 0;
647 const struct gdi_dc_funcs *funcs;
649 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
651 SetLastError( ERROR_INVALID_PARAMETER );
652 return 0;
654 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
656 DWORD *masks = (DWORD *)src_info->bmiColors;
657 if (!masks[0] || !masks[1] || !masks[2])
659 SetLastError( ERROR_INVALID_PARAMETER );
660 return 0;
664 src_bits.ptr = (void *)bits;
665 src_bits.is_copy = FALSE;
666 src_bits.free = NULL;
667 src_bits.param = NULL;
669 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
671 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
673 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
675 if (lines == 0) goto done;
676 else lines = src_info->bmiHeader.biHeight;
677 startscan = 0;
679 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
682 dst.visrect.left = 0;
683 dst.visrect.top = 0;
684 dst.visrect.right = bitmap->bitmap.bmWidth;
685 dst.visrect.bottom = bitmap->bitmap.bmHeight;
687 src.visrect.left = 0;
688 src.visrect.top = 0;
689 src.visrect.right = src_info->bmiHeader.biWidth;
690 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
692 if (src_info->bmiHeader.biHeight > 0)
694 src_to_dst_offset = -startscan;
695 lines = min( lines, src.visrect.bottom - startscan );
696 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
698 else
700 src_to_dst_offset = src.visrect.bottom - lines - startscan;
701 /* Unlike the bottom-up case, Windows doesn't limit lines. */
702 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
705 funcs = get_bitmap_funcs( bitmap );
707 result = lines;
709 offset_rect( &src.visrect, 0, src_to_dst_offset );
710 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
711 src.visrect = dst.visrect;
712 offset_rect( &src.visrect, 0, -src_to_dst_offset );
714 src.x = src.visrect.left;
715 src.y = src.visrect.top;
716 src.width = src.visrect.right - src.visrect.left;
717 src.height = src.visrect.bottom - src.visrect.top;
719 dst.x = dst.visrect.left;
720 dst.y = dst.visrect.top;
721 dst.width = dst.visrect.right - dst.visrect.left;
722 dst.height = dst.visrect.bottom - dst.visrect.top;
724 copy_bitmapinfo( dst_info, src_info );
726 err = funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
727 if (err == ERROR_BAD_FORMAT)
729 err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE );
730 if (!err) err = funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
732 if(err) result = 0;
734 done:
735 if (src_bits.free) src_bits.free( &src_bits );
736 if (clip) DeleteObject( clip );
737 GDI_ReleaseObj( hbitmap );
738 return result;
742 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
743 INT x_src, INT y_src, UINT startscan, UINT lines,
744 const void *bits, BITMAPINFO *src_info, UINT coloruse )
746 DC *dc = get_nulldrv_dc( dev );
747 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
748 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
749 struct bitblt_coords src, dst;
750 struct gdi_image_bits src_bits;
751 HRGN clip = 0;
752 DWORD err;
753 UINT height;
754 BOOL top_down;
755 POINT pt;
756 RECT rect;
758 top_down = (src_info->bmiHeader.biHeight < 0);
759 height = abs( src_info->bmiHeader.biHeight );
761 src_bits.ptr = (void *)bits;
762 src_bits.is_copy = FALSE;
763 src_bits.free = NULL;
765 if (!lines) return 0;
766 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
768 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
770 startscan = 0;
771 lines = height;
772 src_info->bmiHeader.biWidth = x_src + cx;
773 src_info->bmiHeader.biHeight = y_src + cy;
774 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
775 src.x = x_src;
776 src.y = 0;
777 src.width = cx;
778 src.height = cy;
779 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
781 else
783 if (startscan >= height) return 0;
784 if (!top_down && lines > height - startscan) lines = height - startscan;
786 /* map src to top-down coordinates with startscan as origin */
787 src.x = x_src;
788 src.y = startscan + lines - (y_src + cy);
789 src.width = cx;
790 src.height = cy;
791 if (src.y > 0)
793 if (!top_down)
795 /* get rid of unnecessary lines */
796 if (src.y >= lines) return 0;
797 lines -= src.y;
798 src.y = 0;
800 else if (src.y >= lines) return lines;
802 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
805 src.visrect.left = src.x;
806 src.visrect.top = src.y;
807 src.visrect.right = src.x + cx;
808 src.visrect.bottom = src.y + cy;
809 rect.left = 0;
810 rect.top = 0;
811 rect.right = src_info->bmiHeader.biWidth;
812 rect.bottom = abs( src_info->bmiHeader.biHeight );
813 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
815 lines = 0;
816 goto done;
819 pt.x = x_dst;
820 pt.y = y_dst;
821 LPtoDP( dev->hdc, &pt, 1 );
822 dst.x = pt.x;
823 dst.y = pt.y;
824 dst.width = cx;
825 dst.height = cy;
826 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
828 rect.left = dst.x;
829 rect.top = dst.y;
830 rect.right = dst.x + cx;
831 rect.bottom = dst.y + cy;
832 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
834 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
835 intersect_rect( &rect, &src.visrect, &dst.visrect );
836 src.visrect = dst.visrect = rect;
837 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
838 if (is_rect_empty( &dst.visrect )) goto done;
839 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
841 dev = GET_DC_PHYSDEV( dc, pPutImage );
842 copy_bitmapinfo( dst_info, src_info );
843 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
844 if (err == ERROR_BAD_FORMAT)
846 err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE );
847 if (!err) err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
849 if (err) lines = 0;
851 done:
852 if (src_bits.free) src_bits.free( &src_bits );
853 if (clip) DeleteObject( clip );
854 return lines;
857 /***********************************************************************
858 * SetDIBitsToDevice (GDI32.@)
860 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
861 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
862 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
863 UINT coloruse )
865 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
866 BITMAPINFO *info = (BITMAPINFO *)buffer;
867 INT ret = 0;
868 DC *dc;
870 if (!bits) return 0;
871 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
873 SetLastError( ERROR_INVALID_PARAMETER );
874 return 0;
877 if ((dc = get_dc_ptr( hdc )))
879 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
880 update_dc( dc );
881 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
882 ySrc, startscan, lines, bits, info, coloruse );
883 release_dc_ptr( dc );
885 return ret;
888 /***********************************************************************
889 * SetDIBColorTable (GDI32.@)
891 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, CONST RGBQUAD *colors )
893 DC * dc;
894 UINT result = 0;
895 BITMAPOBJ * bitmap;
897 if (!(dc = get_dc_ptr( hdc ))) return 0;
899 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
901 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBColorTable );
903 /* Check if currently selected bitmap is a DIB */
904 if (bitmap->color_table)
906 if (startpos < bitmap->dib->dsBmih.biClrUsed)
908 result = min( entries, bitmap->dib->dsBmih.biClrUsed - startpos );
909 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
912 GDI_ReleaseObj( dc->hBitmap );
913 physdev->funcs->pSetDIBColorTable( physdev, startpos, entries, colors );
915 release_dc_ptr( dc );
916 return result;
920 /***********************************************************************
921 * GetDIBColorTable (GDI32.@)
923 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
925 DC * dc;
926 BITMAPOBJ *bitmap;
927 UINT result = 0;
929 if (!(dc = get_dc_ptr( hdc ))) return 0;
931 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
933 /* Check if currently selected bitmap is a DIB */
934 if (bitmap->color_table)
936 if (startpos < bitmap->dib->dsBmih.biClrUsed)
938 result = min( entries, bitmap->dib->dsBmih.biClrUsed - startpos );
939 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
942 GDI_ReleaseObj( dc->hBitmap );
944 release_dc_ptr( dc );
945 return result;
948 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
949 static const DWORD bit_fields_565[3] = {0xf800, 0x07e0, 0x001f};
950 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
952 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
954 BITMAPINFOHEADER header;
956 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
957 header.biWidth = bmp->bitmap.bmWidth;
958 header.biHeight = bmp->bitmap.bmHeight;
959 header.biPlanes = 1;
961 if (bmp->dib)
963 header.biBitCount = bmp->dib->dsBm.bmBitsPixel;
964 switch (bmp->dib->dsBm.bmBitsPixel)
966 case 16:
967 case 32:
968 header.biCompression = BI_BITFIELDS;
969 break;
970 default:
971 header.biCompression = BI_RGB;
972 break;
975 else
977 header.biCompression = (bmp->bitmap.bmBitsPixel > 8) ? BI_BITFIELDS : BI_RGB;
978 header.biBitCount = bmp->bitmap.bmBitsPixel;
981 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
982 header.biXPelsPerMeter = 0;
983 header.biYPelsPerMeter = 0;
984 header.biClrUsed = 0;
985 header.biClrImportant = 0;
987 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
989 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
991 coreheader->bcWidth = header.biWidth;
992 coreheader->bcHeight = header.biHeight;
993 coreheader->bcPlanes = header.biPlanes;
994 coreheader->bcBitCount = header.biBitCount;
996 else
997 info->bmiHeader = header;
999 return abs(bmp->bitmap.bmHeight);
1002 /************************************************************************
1003 * copy_color_info
1005 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1007 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1009 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1011 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1013 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1014 if (coloruse == DIB_PAL_COLORS)
1015 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1016 else
1018 unsigned int i;
1019 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1021 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1022 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1023 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1027 else
1029 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1030 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1032 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1033 /* bitfields are always at bmiColors even in larger structures */
1034 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1035 else if (src->bmiHeader.biClrUsed)
1037 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1038 unsigned int size;
1040 if (coloruse == DIB_PAL_COLORS)
1041 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1042 else
1043 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1044 memcpy( colorptr, src->bmiColors, size );
1049 const RGBQUAD *get_default_color_table( int bpp )
1051 static const RGBQUAD table_1[2] =
1053 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1055 static const RGBQUAD table_4[16] =
1057 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1058 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1059 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1060 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1062 static const RGBQUAD table_8[256] =
1064 /* first and last 10 entries are the default system palette entries */
1065 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1066 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1067 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1068 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1069 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1070 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1071 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1072 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1073 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1074 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1075 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1076 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1077 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1078 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1079 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1080 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1081 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1082 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1083 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1084 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1085 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1086 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1087 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1088 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1089 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1090 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1091 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1092 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1093 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1094 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1095 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1096 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1097 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1098 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1099 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1100 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1101 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1102 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1103 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1104 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1105 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1106 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1107 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1108 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1109 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1110 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1111 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1112 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1113 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1114 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1115 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1116 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1117 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1118 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1119 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1120 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1121 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1122 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1123 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1124 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1125 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1126 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1127 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1128 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1131 switch (bpp)
1133 case 1: return table_1;
1134 case 4: return table_4;
1135 case 8: return table_8;
1136 default: return NULL;
1140 void fill_default_color_table( BITMAPINFO *info )
1142 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1143 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1144 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1147 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1149 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1150 info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
1151 info->bmiHeader.biHeight = -bmp->bitmap.bmHeight;
1152 info->bmiHeader.biPlanes = 1;
1153 info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
1154 info->bmiHeader.biCompression = BI_RGB;
1155 info->bmiHeader.biXPelsPerMeter = 0;
1156 info->bmiHeader.biYPelsPerMeter = 0;
1157 info->bmiHeader.biClrUsed = 0;
1158 info->bmiHeader.biClrImportant = 0;
1161 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1163 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1164 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1165 unsigned int info_size;
1167 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1169 info_size = get_dib_info_size( info, usage );
1170 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1172 memcpy( ret, info, info_size );
1173 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1174 info->bmiHeader.biSizeImage );
1176 return ret;
1179 /******************************************************************************
1180 * GetDIBits [GDI32.@]
1182 * Retrieves bits of bitmap and copies to buffer.
1184 * RETURNS
1185 * Success: Number of scan lines copied from bitmap
1186 * Failure: 0
1188 INT WINAPI GetDIBits(
1189 HDC hdc, /* [in] Handle to device context */
1190 HBITMAP hbitmap, /* [in] Handle to bitmap */
1191 UINT startscan, /* [in] First scan line to set in dest bitmap */
1192 UINT lines, /* [in] Number of scan lines to copy */
1193 LPVOID bits, /* [out] Address of array for bitmap bits */
1194 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1195 UINT coloruse) /* [in] RGB or palette index */
1197 DC * dc;
1198 BITMAPOBJ * bmp;
1199 int i, dst_to_src_offset, ret = 0;
1200 DWORD err;
1201 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1202 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1203 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1204 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1205 const struct gdi_dc_funcs *funcs;
1206 struct gdi_image_bits src_bits;
1207 struct bitblt_coords src, dst;
1208 BOOL empty_rect = FALSE;
1210 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1211 own copy and transfer the colour info back at the end */
1212 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1213 if (coloruse > DIB_PAL_COLORS) return 0;
1214 if (bits &&
1215 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1216 return 0;
1217 dst_info->bmiHeader.biClrUsed = 0;
1218 dst_info->bmiHeader.biClrImportant = 0;
1220 if (!(dc = get_dc_ptr( hdc )))
1222 SetLastError( ERROR_INVALID_PARAMETER );
1223 return 0;
1225 update_dc( dc );
1226 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1228 release_dc_ptr( dc );
1229 return 0;
1232 funcs = get_bitmap_funcs( bmp );
1234 src.visrect.left = 0;
1235 src.visrect.top = 0;
1236 src.visrect.right = bmp->bitmap.bmWidth;
1237 src.visrect.bottom = bmp->bitmap.bmHeight;
1239 dst.visrect.left = 0;
1240 dst.visrect.top = 0;
1241 dst.visrect.right = dst_info->bmiHeader.biWidth;
1242 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1244 if (lines == 0 || startscan >= dst.visrect.bottom)
1245 bits = NULL;
1247 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1249 ret = fill_query_info( info, bmp );
1250 goto done;
1253 /* validate parameters */
1255 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1256 if (dst_info->bmiHeader.biHeight == 0) goto done;
1258 switch (dst_info->bmiHeader.biCompression)
1260 case BI_RLE4:
1261 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1262 if (dst_info->bmiHeader.biHeight < 0) goto done;
1263 if (bits) goto done; /* can't retrieve compressed bits */
1264 break;
1265 case BI_RLE8:
1266 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1267 if (dst_info->bmiHeader.biHeight < 0) goto done;
1268 if (bits) goto done; /* can't retrieve compressed bits */
1269 break;
1270 case BI_BITFIELDS:
1271 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1272 /* fall through */
1273 case BI_RGB:
1274 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1275 if (dst_info->bmiHeader.biBitCount == 1) break;
1276 if (dst_info->bmiHeader.biBitCount == 4) break;
1277 if (dst_info->bmiHeader.biBitCount == 8) break;
1278 if (dst_info->bmiHeader.biBitCount == 16) break;
1279 if (dst_info->bmiHeader.biBitCount == 24) break;
1280 if (dst_info->bmiHeader.biBitCount == 32) break;
1281 /* fall through */
1282 default:
1283 goto done;
1286 if (bits)
1288 if (dst_info->bmiHeader.biHeight > 0)
1290 dst_to_src_offset = -startscan;
1291 lines = min( lines, dst.visrect.bottom - startscan );
1292 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1294 else
1296 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1297 if (dst_to_src_offset < 0)
1299 dst_to_src_offset = 0;
1300 lines = dst.visrect.bottom - startscan;
1302 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1305 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1306 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1307 dst.visrect = src.visrect;
1308 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1310 if (dst_info->bmiHeader.biHeight > 0)
1312 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1314 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1315 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1316 memset( bits, 0, pad_bytes );
1317 bits = (char *)bits + pad_bytes;
1320 else
1322 if (dst.visrect.bottom < lines)
1324 int pad_lines = lines - dst.visrect.bottom;
1325 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1326 int pad_bytes = pad_lines * stride;
1327 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1331 if (empty_rect) bits = NULL;
1333 src.x = src.visrect.left;
1334 src.y = src.visrect.top;
1335 src.width = src.visrect.right - src.visrect.left;
1336 src.height = src.visrect.bottom - src.visrect.top;
1338 lines = src.height;
1341 err = funcs->pGetImage( NULL, hbitmap, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1343 if (err) goto done;
1345 /* fill out the src colour table, if it needs one */
1346 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1347 fill_default_color_table( src_info );
1349 /* if the src and dst are the same depth, copy the colour info across */
1350 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1352 switch (src_info->bmiHeader.biBitCount)
1354 case 16:
1355 if (src_info->bmiHeader.biCompression == BI_RGB)
1357 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1358 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1360 break;
1361 case 32:
1362 if (src_info->bmiHeader.biCompression == BI_RGB)
1364 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1365 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1367 break;
1369 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1370 copy_color_info( dst_info, src_info, coloruse );
1372 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1374 if( coloruse == DIB_PAL_COLORS )
1376 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1378 else
1380 fill_default_color_table( dst_info );
1384 if (bits)
1386 if(dst_info->bmiHeader.biHeight > 0)
1387 dst_info->bmiHeader.biHeight = src.height;
1388 else
1389 dst_info->bmiHeader.biHeight = -src.height;
1391 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits, FALSE );
1392 if (src_bits.free) src_bits.free( &src_bits );
1393 ret = lines;
1395 else
1396 ret = empty_rect ? FALSE : TRUE;
1398 if (coloruse == DIB_PAL_COLORS)
1400 WORD *index = (WORD *)dst_info->bmiColors;
1401 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1402 *index = i;
1405 copy_color_info( info, dst_info, coloruse );
1406 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1408 done:
1409 release_dc_ptr( dc );
1410 GDI_ReleaseObj( hbitmap );
1411 return ret;
1415 /***********************************************************************
1416 * CreateDIBitmap (GDI32.@)
1418 * Creates a DDB (device dependent bitmap) from a DIB.
1419 * The DDB will have the same color depth as the reference DC.
1421 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1422 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1423 UINT coloruse )
1425 BITMAPINFOHEADER info;
1426 HBITMAP handle;
1427 LONG height;
1429 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1430 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1431 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1432 if (info.biWidth < 0) return 0;
1434 /* Top-down DIBs have a negative height */
1435 height = abs( info.biHeight );
1437 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1438 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1439 info.biBitCount, info.biCompression);
1441 if (hdc == NULL)
1442 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1443 else
1444 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1446 if (handle)
1448 if (init & CBM_INIT)
1450 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1452 DeleteObject( handle );
1453 handle = 0;
1458 return handle;
1462 /***********************************************************************
1463 * CreateDIBSection (GDI32.@)
1465 HBITMAP WINAPI CreateDIBSection(HDC hdc, CONST BITMAPINFO *bmi, UINT usage,
1466 VOID **bits, HANDLE section, DWORD offset)
1468 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1469 BITMAPINFO *info = (BITMAPINFO *)buffer;
1470 HBITMAP ret = 0;
1471 DC *dc;
1472 BOOL bDesktopDC = FALSE;
1473 DIBSECTION *dib;
1474 BITMAPOBJ *bmp;
1475 RGBQUAD *color_table = NULL;
1476 void *mapBits = NULL;
1478 if (bits) *bits = NULL;
1479 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1480 if (usage > DIB_PAL_COLORS) return 0;
1481 if (info->bmiHeader.biPlanes != 1)
1483 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1484 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1487 if (!(dib = HeapAlloc( GetProcessHeap(), 0, sizeof(*dib) ))) return 0;
1489 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1490 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1491 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1492 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1493 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1495 dib->dsBm.bmType = 0;
1496 dib->dsBm.bmWidth = info->bmiHeader.biWidth;
1497 dib->dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1498 dib->dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1499 dib->dsBm.bmPlanes = info->bmiHeader.biPlanes;
1500 dib->dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1501 dib->dsBm.bmBits = NULL;
1502 dib->dsBmih = info->bmiHeader;
1504 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1506 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1507 goto error;
1508 dib->dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1509 if (!(color_table = HeapAlloc( GetProcessHeap(), 0, dib->dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1510 goto error;
1511 memcpy( color_table, info->bmiColors, dib->dsBmih.biClrUsed * sizeof(RGBQUAD) );
1514 /* set dsBitfields values */
1515 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1517 dib->dsBmih.biCompression = BI_BITFIELDS;
1518 dib->dsBitfields[0] = 0x7c00;
1519 dib->dsBitfields[1] = 0x03e0;
1520 dib->dsBitfields[2] = 0x001f;
1522 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1524 if (usage == DIB_PAL_COLORS) goto error;
1525 dib->dsBitfields[0] = *(const DWORD *)info->bmiColors;
1526 dib->dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1527 dib->dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1528 if (!dib->dsBitfields[0] || !dib->dsBitfields[1] || !dib->dsBitfields[2]) goto error;
1530 else dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
1532 /* get storage location for DIB bits */
1534 if (section)
1536 SYSTEM_INFO SystemInfo;
1537 DWORD mapOffset;
1538 INT mapSize;
1540 GetSystemInfo( &SystemInfo );
1541 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1542 mapSize = dib->dsBmih.biSizeImage + (offset - mapOffset);
1543 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1544 if (mapBits) dib->dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1546 else
1548 offset = 0;
1549 dib->dsBm.bmBits = VirtualAlloc( NULL, dib->dsBmih.biSizeImage,
1550 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1552 dib->dshSection = section;
1553 dib->dsOffset = offset;
1555 if (!dib->dsBm.bmBits) goto error;
1557 /* If the reference hdc is null, take the desktop dc */
1558 if (hdc == 0)
1560 hdc = CreateCompatibleDC(0);
1561 bDesktopDC = TRUE;
1564 if (!(dc = get_dc_ptr( hdc ))) goto error;
1566 /* create Device Dependent Bitmap and add DIB pointer */
1567 ret = CreateBitmap( dib->dsBm.bmWidth, dib->dsBm.bmHeight, 1,
1568 (info->bmiHeader.biBitCount == 1) ? 1 : GetDeviceCaps(hdc, BITSPIXEL), NULL );
1570 if (ret && ((bmp = GDI_GetObjPtr(ret, OBJ_BITMAP))))
1572 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pCreateDIBSection );
1573 bmp->dib = dib;
1574 bmp->funcs = physdev->funcs;
1575 bmp->color_table = color_table;
1576 GDI_ReleaseObj( ret );
1578 if (!physdev->funcs->pCreateDIBSection( physdev, ret, info, usage ))
1580 DeleteObject( ret );
1581 ret = 0;
1585 release_dc_ptr( dc );
1586 if (bDesktopDC) DeleteDC( hdc );
1587 if (ret && bits) *bits = dib->dsBm.bmBits;
1588 return ret;
1590 error:
1591 if (bDesktopDC) DeleteDC( hdc );
1592 if (section) UnmapViewOfFile( mapBits );
1593 else if (!offset) VirtualFree( dib->dsBm.bmBits, 0, MEM_RELEASE );
1594 HeapFree( GetProcessHeap(), 0, color_table );
1595 HeapFree( GetProcessHeap(), 0, dib );
1596 return 0;