gdi32: Add a flag to request a default color table from init_dib_info.
[wine.git] / dlls / gdi32 / dib.c
blobd97b30fbbf317fe86c0b60ca5452f61c074c9c60
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 stanitized 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 (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
184 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
186 src_colors = (char *)info + info->bmiHeader.biSize;
188 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
190 /* bitfields are always at bmiColors even in larger structures */
191 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
192 dst->bmiHeader.biClrUsed = 0;
194 else if (dst->bmiHeader.biBitCount <= 8)
196 unsigned int colors = dst->bmiHeader.biClrUsed;
197 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
199 if (!colors) colors = max_colors;
200 else colors = min( colors, max_colors );
202 if (coloruse == DIB_PAL_COLORS)
204 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
205 max_colors = colors;
207 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
209 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
211 else
213 unsigned int i;
214 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
215 for (i = 0; i < colors; i++)
217 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
218 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
219 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
220 dst->bmiColors[i].rgbReserved = 0;
223 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
224 dst->bmiHeader.biClrUsed = max_colors;
226 else dst->bmiHeader.biClrUsed = 0;
228 return TRUE;
231 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
233 PALETTEENTRY palEntry[256];
234 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
235 int i, colors = 1 << info->bmiHeader.biBitCount;
237 info->bmiHeader.biClrUsed = colors;
239 if (!palette) return 0;
241 memset( palEntry, 0, sizeof(palEntry) );
242 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
243 return 0;
245 for (i = 0; i < colors; i++)
247 info->bmiColors[i].rgbRed = palEntry[i].peRed;
248 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
249 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
250 info->bmiColors[i].rgbReserved = 0;
253 return colors;
256 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
258 PALETTEENTRY entries[256];
259 RGBQUAD table[256];
260 HPALETTE palette;
261 const WORD *index = (const WORD *)info->bmiColors;
262 int i, count, colors = info->bmiHeader.biClrUsed;
264 if (!colors) return TRUE;
265 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
266 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
268 for (i = 0; i < colors; i++, index++)
270 table[i].rgbRed = entries[*index % count].peRed;
271 table[i].rgbGreen = entries[*index % count].peGreen;
272 table[i].rgbBlue = entries[*index % count].peBlue;
273 table[i].rgbReserved = 0;
275 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
276 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
277 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
278 return TRUE;
281 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
283 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
284 const int bpp = info->bmiHeader.biBitCount;
286 if (height > 0)
287 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
288 else
289 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
292 static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
294 int i = 0;
295 int left, right;
296 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
297 HRGN run = NULL;
298 BYTE skip, num, data;
299 BYTE *out_bits, *in_bits = bits->ptr;
301 if (clip) *clip = NULL;
303 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
305 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
306 if (!out_bits) goto fail;
308 if (clip)
310 *clip = CreateRectRgn( 0, 0, 0, 0 );
311 run = CreateRectRgn( 0, 0, 0, 0 );
312 if (!*clip || !run) goto fail;
315 x = left = right = 0;
316 y = height - 1;
318 while (i < info->bmiHeader.biSizeImage - 1)
320 num = in_bits[i];
321 data = in_bits[i + 1];
322 i += 2;
324 if (num)
326 if (x + num > width) num = width - x;
327 if (num)
329 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
330 if (info->bmiHeader.biBitCount == 8)
331 memset( out_ptr, s, num );
332 else
334 if(x & 1)
336 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
337 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
338 out_ptr++;
339 x++;
340 num--;
342 /* this will write one too many if num is odd, but that doesn't matter */
343 if (num) memset( out_ptr, s, (num + 1) / 2 );
346 x += num;
347 right = x;
349 else
351 if (data < 3)
353 if(left != right && clip)
355 SetRectRgn( run, left, y, right, y + 1 );
356 CombineRgn( *clip, run, *clip, RGN_OR );
358 switch (data)
360 case 0: /* eol */
361 left = right = x = 0;
362 y--;
363 if(y < 0) goto done;
364 break;
366 case 1: /* eod */
367 goto done;
369 case 2: /* delta */
370 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
371 x += in_bits[i];
372 if (x > width) x = width;
373 left = right = x;
374 y -= in_bits[i + 1];
375 if(y < 0) goto done;
376 i += 2;
379 else /* data bytes of data */
381 num = data;
382 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
383 if (skip > info->bmiHeader.biSizeImage - i) goto done;
384 skip = (skip + 1) & ~1;
385 if (x + num > width) num = width - x;
386 if (num)
388 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
389 if (info->bmiHeader.biBitCount == 8)
390 memcpy( out_ptr, in_bits + i, num );
391 else
393 if(x & 1)
395 const BYTE *in_ptr = in_bits + i;
396 for ( ; num; num--, x++)
398 if (x & 1)
400 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
401 out_ptr++;
403 else
404 *out_ptr = (*in_ptr++ << 4) & 0xf0;
407 else
408 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
411 x += num;
412 right = x;
413 i += skip;
418 done:
419 if (run) DeleteObject( run );
420 if (bits->free) bits->free( bits );
422 bits->ptr = out_bits;
423 bits->is_copy = TRUE;
424 bits->free = free_heap_bits;
426 return TRUE;
428 fail:
429 if (run) DeleteObject( run );
430 if (clip && *clip) DeleteObject( *clip );
431 HeapFree( GetProcessHeap(), 0, out_bits );
432 return FALSE;
437 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
438 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
439 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
441 DC *dc = get_nulldrv_dc( dev );
442 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
443 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
444 struct bitblt_coords src, dst;
445 struct gdi_image_bits src_bits;
446 DWORD err;
447 HRGN clip = NULL;
448 INT ret = 0;
449 INT height = abs( src_info->bmiHeader.biHeight );
450 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
451 RECT rect;
453 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
454 xSrc, ySrc, widthSrc, heightSrc, rop);
456 src_bits.ptr = (void*)bits;
457 src_bits.is_copy = FALSE;
458 src_bits.free = NULL;
460 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
462 rect.left = xDst;
463 rect.top = yDst;
464 rect.right = xDst + widthDst;
465 rect.bottom = yDst + heightDst;
466 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
467 dst.x = rect.left;
468 dst.y = rect.top;
469 dst.width = rect.right - rect.left;
470 dst.height = rect.bottom - rect.top;
472 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
474 dst.x += dst.width;
475 dst.width = -dst.width;
477 rop &= ~NOMIRRORBITMAP;
479 src.x = xSrc;
480 src.width = widthSrc;
481 src.y = ySrc;
482 src.height = heightSrc;
484 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
485 non_stretch_from_origin = TRUE;
487 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
489 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
490 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
493 if (rop != SRCCOPY || non_stretch_from_origin)
495 if (dst.width == 1 && src.width > 1) src.width--;
496 if (dst.height == 1 && src.height > 1) src.height--;
499 if (rop != SRCCOPY)
501 if (dst.width < 0 && dst.width == src.width)
503 /* This is off-by-one, but that's what Windows does */
504 dst.x += dst.width;
505 src.x += src.width;
506 dst.width = -dst.width;
507 src.width = -src.width;
509 if (dst.height < 0 && dst.height == src.height)
511 dst.y += dst.height;
512 src.y += src.height;
513 dst.height = -dst.height;
514 src.height = -src.height;
518 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
520 if (src.y >= height && src.y + src.height + 1 < height)
521 src.y = height - 1;
522 else if (src.y > 0 && src.y + src.height + 1 < 0)
523 src.y = -src.height - 1;
525 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
527 src.visrect.left = 0;
528 src.visrect.right = src_info->bmiHeader.biWidth;
529 src.visrect.top = 0;
530 src.visrect.bottom = height;
531 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
533 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
535 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
537 if (!intersect_vis_rectangles( &dst, &src )) goto done;
539 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
541 dev = GET_DC_PHYSDEV( dc, pPutImage );
542 copy_bitmapinfo( dst_info, src_info );
543 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
544 if (err == ERROR_BAD_FORMAT)
546 /* 1-bpp destination without a color table requires a fake 1-entry table
547 * that contains only the background color */
548 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
550 COLORREF color = GetBkColor( dev->hdc );
551 dst_info->bmiColors[0].rgbRed = GetRValue( color );
552 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
553 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
554 dst_info->bmiColors[0].rgbReserved = 0;
555 dst_info->bmiHeader.biClrUsed = 1;
558 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE )))
560 /* get rid of the fake 1-bpp table */
561 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
562 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
566 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
568 copy_bitmapinfo( src_info, dst_info );
569 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
570 if (!err) err = dev->funcs->pPutImage( dev, 0, NULL, dst_info, &src_bits, &src, &dst, rop );
572 if (err) ret = 0;
573 else if (rop == SRCCOPY) ret = height;
574 else ret = src_info->bmiHeader.biHeight;
576 done:
577 if (src_bits.free) src_bits.free( &src_bits );
578 if (clip) DeleteObject( clip );
579 return ret;
582 /***********************************************************************
583 * StretchDIBits (GDI32.@)
585 INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
586 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
587 const BITMAPINFO *bmi, UINT coloruse, DWORD rop )
589 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
590 BITMAPINFO *info = (BITMAPINFO *)buffer;
591 DC *dc;
592 INT ret = 0;
594 if (!bits) return 0;
595 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
597 SetLastError( ERROR_INVALID_PARAMETER );
598 return 0;
601 if ((dc = get_dc_ptr( hdc )))
603 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
604 update_dc( dc );
605 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
606 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
607 release_dc_ptr( dc );
609 return ret;
613 /******************************************************************************
614 * SetDIBits [GDI32.@]
616 * Sets pixels in a bitmap using colors from DIB.
618 * PARAMS
619 * hdc [I] Handle to device context
620 * hbitmap [I] Handle to bitmap
621 * startscan [I] Starting scan line
622 * lines [I] Number of scan lines
623 * bits [I] Array of bitmap bits
624 * info [I] Address of structure with data
625 * coloruse [I] Type of color indexes to use
627 * RETURNS
628 * Success: Number of scan lines copied
629 * Failure: 0
631 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
632 UINT lines, LPCVOID bits, const BITMAPINFO *info,
633 UINT coloruse )
635 BITMAPOBJ *bitmap;
636 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
637 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
638 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
639 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
640 INT result = 0;
641 DWORD err;
642 struct gdi_image_bits src_bits;
643 struct bitblt_coords src, dst;
644 INT src_to_dst_offset;
645 HRGN clip = 0;
646 const struct gdi_dc_funcs *funcs;
648 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ))
650 SetLastError( ERROR_INVALID_PARAMETER );
651 return 0;
653 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
655 DWORD *masks = (DWORD *)src_info->bmiColors;
656 if (!masks[0] || !masks[1] || !masks[2])
658 SetLastError( ERROR_INVALID_PARAMETER );
659 return 0;
663 src_bits.ptr = (void *)bits;
664 src_bits.is_copy = FALSE;
665 src_bits.free = NULL;
666 src_bits.param = NULL;
668 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
670 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
672 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
674 if (lines == 0) goto done;
675 else lines = src_info->bmiHeader.biHeight;
676 startscan = 0;
678 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
681 dst.visrect.left = 0;
682 dst.visrect.top = 0;
683 dst.visrect.right = bitmap->bitmap.bmWidth;
684 dst.visrect.bottom = bitmap->bitmap.bmHeight;
686 src.visrect.left = 0;
687 src.visrect.top = 0;
688 src.visrect.right = src_info->bmiHeader.biWidth;
689 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
691 if (src_info->bmiHeader.biHeight > 0)
693 src_to_dst_offset = -startscan;
694 lines = min( lines, src.visrect.bottom - startscan );
695 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
697 else
699 src_to_dst_offset = src.visrect.bottom - lines - startscan;
700 /* Unlike the bottom-up case, Windows doesn't limit lines. */
701 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
704 funcs = get_bitmap_funcs( bitmap );
706 result = lines;
708 offset_rect( &src.visrect, 0, src_to_dst_offset );
709 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
710 src.visrect = dst.visrect;
711 offset_rect( &src.visrect, 0, -src_to_dst_offset );
713 src.x = src.visrect.left;
714 src.y = src.visrect.top;
715 src.width = src.visrect.right - src.visrect.left;
716 src.height = src.visrect.bottom - src.visrect.top;
718 dst.x = dst.visrect.left;
719 dst.y = dst.visrect.top;
720 dst.width = dst.visrect.right - dst.visrect.left;
721 dst.height = dst.visrect.bottom - dst.visrect.top;
723 copy_bitmapinfo( dst_info, src_info );
725 err = funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
726 if (err == ERROR_BAD_FORMAT)
728 err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE );
729 if (!err) err = funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
731 if(err) result = 0;
733 done:
734 if (src_bits.free) src_bits.free( &src_bits );
735 if (clip) DeleteObject( clip );
736 GDI_ReleaseObj( hbitmap );
737 return result;
741 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
742 INT x_src, INT y_src, UINT startscan, UINT lines,
743 const void *bits, BITMAPINFO *src_info, UINT coloruse )
745 DC *dc = get_nulldrv_dc( dev );
746 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
747 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
748 struct bitblt_coords src, dst;
749 struct gdi_image_bits src_bits;
750 HRGN clip = 0;
751 DWORD err;
752 UINT height;
753 BOOL top_down;
754 POINT pt;
755 RECT rect;
757 top_down = (src_info->bmiHeader.biHeight < 0);
758 height = abs( src_info->bmiHeader.biHeight );
760 src_bits.ptr = (void *)bits;
761 src_bits.is_copy = FALSE;
762 src_bits.free = NULL;
764 if (!lines) return 0;
765 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
767 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
769 startscan = 0;
770 lines = height;
771 src_info->bmiHeader.biWidth = x_src + cx;
772 src_info->bmiHeader.biHeight = y_src + cy;
773 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
774 src.x = x_src;
775 src.y = 0;
776 src.width = cx;
777 src.height = cy;
778 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
780 else
782 if (startscan >= height) return 0;
783 if (!top_down && lines > height - startscan) lines = height - startscan;
785 /* map src to top-down coordinates with startscan as origin */
786 src.x = x_src;
787 src.y = startscan + lines - (y_src + cy);
788 src.width = cx;
789 src.height = cy;
790 if (src.y > 0)
792 if (!top_down)
794 /* get rid of unnecessary lines */
795 if (src.y >= lines) return 0;
796 lines -= src.y;
797 src.y = 0;
799 else if (src.y >= lines) return lines;
801 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
804 src.visrect.left = src.x;
805 src.visrect.top = src.y;
806 src.visrect.right = src.x + cx;
807 src.visrect.bottom = src.y + cy;
808 rect.left = 0;
809 rect.top = 0;
810 rect.right = src_info->bmiHeader.biWidth;
811 rect.bottom = abs( src_info->bmiHeader.biHeight );
812 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
814 lines = 0;
815 goto done;
818 pt.x = x_dst;
819 pt.y = y_dst;
820 LPtoDP( dev->hdc, &pt, 1 );
821 dst.x = pt.x;
822 dst.y = pt.y;
823 dst.width = cx;
824 dst.height = cy;
825 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
827 rect.left = dst.x;
828 rect.top = dst.y;
829 rect.right = dst.x + cx;
830 rect.bottom = dst.y + cy;
831 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
833 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
834 intersect_rect( &rect, &src.visrect, &dst.visrect );
835 src.visrect = dst.visrect = rect;
836 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
837 if (is_rect_empty( &dst.visrect )) goto done;
838 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
840 dev = GET_DC_PHYSDEV( dc, pPutImage );
841 copy_bitmapinfo( dst_info, src_info );
842 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
843 if (err == ERROR_BAD_FORMAT)
845 err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE );
846 if (!err) err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
848 if (err) lines = 0;
850 done:
851 if (src_bits.free) src_bits.free( &src_bits );
852 if (clip) DeleteObject( clip );
853 return lines;
856 /***********************************************************************
857 * SetDIBitsToDevice (GDI32.@)
859 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
860 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
861 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
862 UINT coloruse )
864 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
865 BITMAPINFO *info = (BITMAPINFO *)buffer;
866 INT ret = 0;
867 DC *dc;
869 if (!bits) return 0;
870 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
872 SetLastError( ERROR_INVALID_PARAMETER );
873 return 0;
876 if ((dc = get_dc_ptr( hdc )))
878 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
879 update_dc( dc );
880 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
881 ySrc, startscan, lines, bits, info, coloruse );
882 release_dc_ptr( dc );
884 return ret;
887 /***********************************************************************
888 * SetDIBColorTable (GDI32.@)
890 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, CONST RGBQUAD *colors )
892 DC * dc;
893 UINT result = 0;
894 BITMAPOBJ * bitmap;
896 if (!(dc = get_dc_ptr( hdc ))) return 0;
898 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
900 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBColorTable );
902 /* Check if currently selected bitmap is a DIB */
903 if (bitmap->color_table)
905 if (startpos < bitmap->dib->dsBmih.biClrUsed)
907 result = min( entries, bitmap->dib->dsBmih.biClrUsed - startpos );
908 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
911 GDI_ReleaseObj( dc->hBitmap );
912 physdev->funcs->pSetDIBColorTable( physdev, startpos, entries, colors );
914 release_dc_ptr( dc );
915 return result;
919 /***********************************************************************
920 * GetDIBColorTable (GDI32.@)
922 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
924 DC * dc;
925 BITMAPOBJ *bitmap;
926 UINT result = 0;
928 if (!(dc = get_dc_ptr( hdc ))) return 0;
930 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
932 /* Check if currently selected bitmap is a DIB */
933 if (bitmap->color_table)
935 if (startpos < bitmap->dib->dsBmih.biClrUsed)
937 result = min( entries, bitmap->dib->dsBmih.biClrUsed - startpos );
938 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
941 GDI_ReleaseObj( dc->hBitmap );
943 release_dc_ptr( dc );
944 return result;
947 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
948 static const DWORD bit_fields_565[3] = {0xf800, 0x07e0, 0x001f};
949 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
951 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
953 BITMAPINFOHEADER header;
955 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
956 header.biWidth = bmp->bitmap.bmWidth;
957 header.biHeight = bmp->bitmap.bmHeight;
958 header.biPlanes = 1;
960 if (bmp->dib)
962 header.biBitCount = bmp->dib->dsBm.bmBitsPixel;
963 switch (bmp->dib->dsBm.bmBitsPixel)
965 case 16:
966 case 32:
967 header.biCompression = BI_BITFIELDS;
968 break;
969 default:
970 header.biCompression = BI_RGB;
971 break;
974 else
976 header.biCompression = (bmp->bitmap.bmBitsPixel > 8) ? BI_BITFIELDS : BI_RGB;
977 header.biBitCount = bmp->bitmap.bmBitsPixel;
980 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
981 header.biXPelsPerMeter = 0;
982 header.biYPelsPerMeter = 0;
983 header.biClrUsed = 0;
984 header.biClrImportant = 0;
986 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
988 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
990 coreheader->bcWidth = header.biWidth;
991 coreheader->bcHeight = header.biHeight;
992 coreheader->bcPlanes = header.biPlanes;
993 coreheader->bcBitCount = header.biBitCount;
995 else
996 info->bmiHeader = header;
998 return abs(bmp->bitmap.bmHeight);
1001 /************************************************************************
1002 * copy_color_info
1004 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1006 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1008 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1010 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1012 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1013 if (coloruse == DIB_PAL_COLORS)
1014 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1015 else
1017 unsigned int i;
1018 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1020 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1021 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1022 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1026 else
1028 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1029 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1031 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1032 /* bitfields are always at bmiColors even in larger structures */
1033 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1034 else if (src->bmiHeader.biClrUsed)
1036 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1037 unsigned int size;
1039 if (coloruse == DIB_PAL_COLORS)
1040 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1041 else
1042 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1043 memcpy( colorptr, src->bmiColors, size );
1048 const RGBQUAD *get_default_color_table( int bpp )
1050 static const RGBQUAD table_1[2] =
1052 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1054 static const RGBQUAD table_4[16] =
1056 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1057 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1058 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1059 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1061 static const RGBQUAD table_8[256] =
1063 /* first and last 10 entries are the default system palette entries */
1064 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1065 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1066 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1067 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1068 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1069 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1070 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1071 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1072 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1073 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1074 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1075 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1076 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1077 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1078 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1079 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1080 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1081 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1082 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1083 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1084 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1085 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1086 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1087 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1088 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1089 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1090 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1091 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1092 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1093 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1094 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1095 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1096 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1097 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1098 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1099 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1100 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1101 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1102 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1103 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1104 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1105 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1106 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1107 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1108 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1109 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1110 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1111 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1112 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1113 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1114 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1115 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1116 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1117 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1118 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1119 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1120 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1121 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1122 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1123 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1124 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1125 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1126 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1127 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1130 switch (bpp)
1132 case 1: return table_1;
1133 case 4: return table_4;
1134 case 8: return table_8;
1135 default: return NULL;
1139 void fill_default_color_table( BITMAPINFO *info )
1141 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1142 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1143 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1146 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1148 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1149 info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
1150 info->bmiHeader.biHeight = -bmp->bitmap.bmHeight;
1151 info->bmiHeader.biPlanes = 1;
1152 info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
1153 info->bmiHeader.biCompression = BI_RGB;
1154 info->bmiHeader.biXPelsPerMeter = 0;
1155 info->bmiHeader.biYPelsPerMeter = 0;
1156 info->bmiHeader.biClrUsed = 0;
1157 info->bmiHeader.biClrImportant = 0;
1160 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1162 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1163 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1164 unsigned int info_size;
1166 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1168 info_size = get_dib_info_size( info, usage );
1169 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1171 memcpy( ret, info, info_size );
1172 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1173 info->bmiHeader.biSizeImage );
1175 return ret;
1178 /******************************************************************************
1179 * GetDIBits [GDI32.@]
1181 * Retrieves bits of bitmap and copies to buffer.
1183 * RETURNS
1184 * Success: Number of scan lines copied from bitmap
1185 * Failure: 0
1187 INT WINAPI GetDIBits(
1188 HDC hdc, /* [in] Handle to device context */
1189 HBITMAP hbitmap, /* [in] Handle to bitmap */
1190 UINT startscan, /* [in] First scan line to set in dest bitmap */
1191 UINT lines, /* [in] Number of scan lines to copy */
1192 LPVOID bits, /* [out] Address of array for bitmap bits */
1193 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1194 UINT coloruse) /* [in] RGB or palette index */
1196 DC * dc;
1197 BITMAPOBJ * bmp;
1198 int i, dst_to_src_offset, ret = 0;
1199 DWORD err;
1200 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1201 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1202 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1203 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1204 const struct gdi_dc_funcs *funcs;
1205 struct gdi_image_bits src_bits;
1206 struct bitblt_coords src, dst;
1207 BOOL empty_rect = FALSE;
1209 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1210 own copy and transfer the colour info back at the end */
1211 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1212 if (bits &&
1213 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1214 return 0;
1215 dst_info->bmiHeader.biClrUsed = 0;
1216 dst_info->bmiHeader.biClrImportant = 0;
1218 if (!(dc = get_dc_ptr( hdc )))
1220 SetLastError( ERROR_INVALID_PARAMETER );
1221 return 0;
1223 update_dc( dc );
1224 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1226 release_dc_ptr( dc );
1227 return 0;
1230 funcs = get_bitmap_funcs( bmp );
1232 src.visrect.left = 0;
1233 src.visrect.top = 0;
1234 src.visrect.right = bmp->bitmap.bmWidth;
1235 src.visrect.bottom = bmp->bitmap.bmHeight;
1237 dst.visrect.left = 0;
1238 dst.visrect.top = 0;
1239 dst.visrect.right = dst_info->bmiHeader.biWidth;
1240 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1242 if (lines == 0 || startscan >= dst.visrect.bottom)
1243 bits = NULL;
1245 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1247 ret = fill_query_info( info, bmp );
1248 goto done;
1251 /* validate parameters */
1253 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1254 if (dst_info->bmiHeader.biHeight == 0) goto done;
1256 switch (dst_info->bmiHeader.biCompression)
1258 case BI_RLE4:
1259 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1260 if (dst_info->bmiHeader.biHeight < 0) goto done;
1261 if (bits) goto done; /* can't retrieve compressed bits */
1262 break;
1263 case BI_RLE8:
1264 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1265 if (dst_info->bmiHeader.biHeight < 0) goto done;
1266 if (bits) goto done; /* can't retrieve compressed bits */
1267 break;
1268 case BI_BITFIELDS:
1269 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1270 /* fall through */
1271 case BI_RGB:
1272 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1273 if (dst_info->bmiHeader.biBitCount == 1) break;
1274 if (dst_info->bmiHeader.biBitCount == 4) break;
1275 if (dst_info->bmiHeader.biBitCount == 8) break;
1276 if (dst_info->bmiHeader.biBitCount == 16) break;
1277 if (dst_info->bmiHeader.biBitCount == 24) break;
1278 if (dst_info->bmiHeader.biBitCount == 32) break;
1279 /* fall through */
1280 default:
1281 goto done;
1284 if (bits)
1286 if (dst_info->bmiHeader.biHeight > 0)
1288 dst_to_src_offset = -startscan;
1289 lines = min( lines, dst.visrect.bottom - startscan );
1290 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1292 else
1294 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1295 if (dst_to_src_offset < 0)
1297 dst_to_src_offset = 0;
1298 lines = dst.visrect.bottom - startscan;
1300 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1303 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1304 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1305 dst.visrect = src.visrect;
1306 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1308 if (dst_info->bmiHeader.biHeight > 0)
1310 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1312 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1313 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1314 memset( bits, 0, pad_bytes );
1315 bits = (char *)bits + pad_bytes;
1318 else
1320 if (dst.visrect.bottom < lines)
1322 int pad_lines = lines - dst.visrect.bottom;
1323 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1324 int pad_bytes = pad_lines * stride;
1325 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1329 if (empty_rect) bits = NULL;
1331 src.x = src.visrect.left;
1332 src.y = src.visrect.top;
1333 src.width = src.visrect.right - src.visrect.left;
1334 src.height = src.visrect.bottom - src.visrect.top;
1336 lines = src.height;
1339 err = funcs->pGetImage( NULL, hbitmap, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1341 if (err) goto done;
1343 /* fill out the src colour table, if it needs one */
1344 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1345 fill_default_color_table( src_info );
1347 /* if the src and dst are the same depth, copy the colour info across */
1348 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1350 switch (src_info->bmiHeader.biBitCount)
1352 case 16:
1353 if (src_info->bmiHeader.biCompression == BI_RGB)
1355 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1356 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1358 break;
1359 case 32:
1360 if (src_info->bmiHeader.biCompression == BI_RGB)
1362 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1363 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1365 break;
1367 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1368 copy_color_info( dst_info, src_info, coloruse );
1370 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1372 if( coloruse == DIB_PAL_COLORS )
1374 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1376 else
1378 fill_default_color_table( dst_info );
1382 if (bits)
1384 if(dst_info->bmiHeader.biHeight > 0)
1385 dst_info->bmiHeader.biHeight = src.height;
1386 else
1387 dst_info->bmiHeader.biHeight = -src.height;
1389 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits, FALSE );
1390 if (src_bits.free) src_bits.free( &src_bits );
1391 ret = lines;
1393 else
1394 ret = empty_rect ? FALSE : TRUE;
1396 if (coloruse == DIB_PAL_COLORS)
1398 WORD *index = (WORD *)dst_info->bmiColors;
1399 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1400 *index = i;
1403 copy_color_info( info, dst_info, coloruse );
1404 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1406 done:
1407 release_dc_ptr( dc );
1408 GDI_ReleaseObj( hbitmap );
1409 return ret;
1413 /***********************************************************************
1414 * CreateDIBitmap (GDI32.@)
1416 * Creates a DDB (device dependent bitmap) from a DIB.
1417 * The DDB will have the same color depth as the reference DC.
1419 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1420 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1421 UINT coloruse )
1423 BITMAPINFOHEADER info;
1424 HBITMAP handle;
1425 LONG height;
1427 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1428 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1429 if (info.biWidth < 0) return 0;
1431 /* Top-down DIBs have a negative height */
1432 height = abs( info.biHeight );
1434 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1435 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1436 info.biBitCount, info.biCompression);
1438 if (hdc == NULL)
1439 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1440 else
1441 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1443 if (handle)
1445 if (init & CBM_INIT)
1447 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1449 DeleteObject( handle );
1450 handle = 0;
1455 return handle;
1459 /***********************************************************************
1460 * CreateDIBSection (GDI32.@)
1462 HBITMAP WINAPI CreateDIBSection(HDC hdc, CONST BITMAPINFO *bmi, UINT usage,
1463 VOID **bits, HANDLE section, DWORD offset)
1465 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1466 BITMAPINFO *info = (BITMAPINFO *)buffer;
1467 HBITMAP ret = 0;
1468 DC *dc;
1469 BOOL bDesktopDC = FALSE;
1470 DIBSECTION *dib;
1471 BITMAPOBJ *bmp;
1472 RGBQUAD *color_table = NULL;
1473 void *mapBits = NULL;
1475 if (bits) *bits = NULL;
1476 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1477 if (info->bmiHeader.biPlanes != 1)
1479 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1480 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1483 if (!(dib = HeapAlloc( GetProcessHeap(), 0, sizeof(*dib) ))) return 0;
1485 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1486 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1487 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1488 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1489 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1491 dib->dsBm.bmType = 0;
1492 dib->dsBm.bmWidth = info->bmiHeader.biWidth;
1493 dib->dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1494 dib->dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1495 dib->dsBm.bmPlanes = info->bmiHeader.biPlanes;
1496 dib->dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1497 dib->dsBm.bmBits = NULL;
1498 dib->dsBmih = info->bmiHeader;
1500 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1502 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1503 goto error;
1504 dib->dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1505 if (!(color_table = HeapAlloc( GetProcessHeap(), 0, dib->dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1506 goto error;
1507 memcpy( color_table, info->bmiColors, dib->dsBmih.biClrUsed * sizeof(RGBQUAD) );
1510 /* set dsBitfields values */
1511 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1513 dib->dsBmih.biCompression = BI_BITFIELDS;
1514 dib->dsBitfields[0] = 0x7c00;
1515 dib->dsBitfields[1] = 0x03e0;
1516 dib->dsBitfields[2] = 0x001f;
1518 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1520 if (usage == DIB_PAL_COLORS) goto error;
1521 dib->dsBitfields[0] = *(const DWORD *)info->bmiColors;
1522 dib->dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1523 dib->dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1524 if (!dib->dsBitfields[0] || !dib->dsBitfields[1] || !dib->dsBitfields[2]) goto error;
1526 else dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
1528 /* get storage location for DIB bits */
1530 if (section)
1532 SYSTEM_INFO SystemInfo;
1533 DWORD mapOffset;
1534 INT mapSize;
1536 GetSystemInfo( &SystemInfo );
1537 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1538 mapSize = dib->dsBmih.biSizeImage + (offset - mapOffset);
1539 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1540 if (mapBits) dib->dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1542 else
1544 offset = 0;
1545 dib->dsBm.bmBits = VirtualAlloc( NULL, dib->dsBmih.biSizeImage,
1546 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1548 dib->dshSection = section;
1549 dib->dsOffset = offset;
1551 if (!dib->dsBm.bmBits) goto error;
1553 /* If the reference hdc is null, take the desktop dc */
1554 if (hdc == 0)
1556 hdc = CreateCompatibleDC(0);
1557 bDesktopDC = TRUE;
1560 if (!(dc = get_dc_ptr( hdc ))) goto error;
1562 /* create Device Dependent Bitmap and add DIB pointer */
1563 ret = CreateBitmap( dib->dsBm.bmWidth, dib->dsBm.bmHeight, 1,
1564 (info->bmiHeader.biBitCount == 1) ? 1 : GetDeviceCaps(hdc, BITSPIXEL), NULL );
1566 if (ret && ((bmp = GDI_GetObjPtr(ret, OBJ_BITMAP))))
1568 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pCreateDIBSection );
1569 bmp->dib = dib;
1570 bmp->funcs = physdev->funcs;
1571 bmp->color_table = color_table;
1572 GDI_ReleaseObj( ret );
1574 if (!physdev->funcs->pCreateDIBSection( physdev, ret, info, usage ))
1576 DeleteObject( ret );
1577 ret = 0;
1581 release_dc_ptr( dc );
1582 if (bDesktopDC) DeleteDC( hdc );
1583 if (ret && bits) *bits = dib->dsBm.bmBits;
1584 return ret;
1586 error:
1587 if (bDesktopDC) DeleteDC( hdc );
1588 if (section) UnmapViewOfFile( mapBits );
1589 else if (!offset) VirtualFree( dib->dsBm.bmBits, 0, MEM_RELEASE );
1590 HeapFree( GetProcessHeap(), 0, color_table );
1591 HeapFree( GetProcessHeap(), 0, dib );
1592 return 0;