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:
55 void* colorPtr = (LPBYTE) info + (WORD) info->bmiHeader.biSize;
59 Search for "Bitmap Structures" in MSDN
69 #include "gdi_private.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
75 /***********************************************************************
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)
124 return (info->biCompression == BI_RGB);
127 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
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;
151 dst->biClrImportant = 0;
153 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
159 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
163 dst->biSize = sizeof(*dst);
164 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
165 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
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 )
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) );
208 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
210 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
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;
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 ))
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;
257 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
259 PALETTEENTRY entries[256];
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) );
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;
288 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
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 )
297 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
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;
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;
319 while (i < info->bmiHeader.biSizeImage - 1)
322 data = in_bits[i + 1];
327 if (x + num > width) num = width - x;
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 );
337 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
338 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
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 );
354 if(left != right && clip)
356 SetRectRgn( run, left, y, right, y + 1 );
357 CombineRgn( *clip, run, *clip, RGN_OR );
362 left = right = x = 0;
371 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
373 if (x > width) x = width;
380 else /* data bytes of 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;
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 );
396 const BYTE *in_ptr = in_bits + i;
397 for ( ; num; num--, x++)
401 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
405 *out_ptr = (*in_ptr++ << 4) & 0xf0;
409 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
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;
430 if (run) DeleteObject( run );
431 if (clip && *clip) DeleteObject( *clip );
432 HeapFree( GetProcessHeap(), 0, out_bits );
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;
450 INT height = abs( src_info->bmiHeader.biHeight );
451 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
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;
465 rect.right = xDst + widthDst;
466 rect.bottom = yDst + heightDst;
467 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
470 dst.width = rect.right - rect.left;
471 dst.height = rect.bottom - rect.top;
473 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
476 dst.width = -dst.width;
478 rop &= ~NOMIRRORBITMAP;
481 src.width = widthSrc;
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--;
502 if (dst.width < 0 && dst.width == src.width)
504 /* This is off-by-one, but that's what Windows does */
507 dst.width = -dst.width;
508 src.width = -src.width;
510 if (dst.height < 0 && dst.height == 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)
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;
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 );
574 else if (rop == SRCCOPY) ret = height;
575 else ret = src_info->bmiHeader.biHeight;
578 if (src_bits.free) src_bits.free( &src_bits );
579 if (clip) DeleteObject( clip );
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;
596 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
598 SetLastError( ERROR_INVALID_PARAMETER );
602 if ((dc = get_dc_ptr( hdc )))
604 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
606 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
607 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
608 release_dc_ptr( dc );
614 /******************************************************************************
615 * SetDIBits [GDI32.@]
617 * Sets pixels in a bitmap using colors from DIB.
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
629 * Success: Number of scan lines copied
632 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
633 UINT lines, LPCVOID bits, const BITMAPINFO *info,
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;
643 struct gdi_image_bits src_bits;
644 struct bitblt_coords src, dst;
645 INT src_to_dst_offset;
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 );
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 );
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;
679 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
682 dst.visrect.left = 0;
684 dst.visrect.right = bitmap->bitmap.bmWidth;
685 dst.visrect.bottom = bitmap->bitmap.bmHeight;
687 src.visrect.left = 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;
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 );
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 );
735 if (src_bits.free) src_bits.free( &src_bits );
736 if (clip) DeleteObject( clip );
737 GDI_ReleaseObj( hbitmap );
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;
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)
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;
779 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
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 */
788 src.y = startscan + lines - (y_src + cy);
795 /* get rid of unnecessary lines */
796 if (src.y >= lines) return 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;
811 rect.right = src_info->bmiHeader.biWidth;
812 rect.bottom = abs( src_info->bmiHeader.biHeight );
813 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
821 LPtoDP( dev->hdc, &pt, 1 );
826 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
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 );
852 if (src_bits.free) src_bits.free( &src_bits );
853 if (clip) DeleteObject( clip );
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,
865 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
866 BITMAPINFO *info = (BITMAPINFO *)buffer;
871 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
873 SetLastError( ERROR_INVALID_PARAMETER );
877 if ((dc = get_dc_ptr( hdc )))
879 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
881 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
882 ySrc, startscan, lines, bits, info, coloruse );
883 release_dc_ptr( dc );
888 /***********************************************************************
889 * SetDIBColorTable (GDI32.@)
891 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, CONST RGBQUAD *colors )
897 if (!(dc = get_dc_ptr( hdc ))) return 0;
899 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
901 /* Check if currently selected bitmap is a DIB */
902 if (bitmap->color_table)
904 if (startpos < bitmap->dib->dsBmih.biClrUsed)
906 result = min( entries, bitmap->dib->dsBmih.biClrUsed - startpos );
907 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
910 GDI_ReleaseObj( dc->hBitmap );
912 if (result) /* update colors of selected objects */
914 SetTextColor( hdc, dc->textColor );
915 SetBkColor( hdc, dc->backgroundColor );
916 SelectObject( hdc, dc->hPen );
917 SelectObject( hdc, dc->hBrush );
920 release_dc_ptr( dc );
925 /***********************************************************************
926 * GetDIBColorTable (GDI32.@)
928 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
934 if (!(dc = get_dc_ptr( hdc ))) return 0;
936 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
938 /* Check if currently selected bitmap is a DIB */
939 if (bitmap->color_table)
941 if (startpos < bitmap->dib->dsBmih.biClrUsed)
943 result = min( entries, bitmap->dib->dsBmih.biClrUsed - startpos );
944 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
947 GDI_ReleaseObj( dc->hBitmap );
949 release_dc_ptr( dc );
953 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
954 static const DWORD bit_fields_565[3] = {0xf800, 0x07e0, 0x001f};
955 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
957 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
959 BITMAPINFOHEADER header;
961 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
962 header.biWidth = bmp->bitmap.bmWidth;
963 header.biHeight = bmp->bitmap.bmHeight;
968 header.biBitCount = bmp->dib->dsBm.bmBitsPixel;
969 switch (bmp->dib->dsBm.bmBitsPixel)
973 header.biCompression = BI_BITFIELDS;
976 header.biCompression = BI_RGB;
982 header.biCompression = (bmp->bitmap.bmBitsPixel > 8) ? BI_BITFIELDS : BI_RGB;
983 header.biBitCount = bmp->bitmap.bmBitsPixel;
986 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
987 header.biXPelsPerMeter = 0;
988 header.biYPelsPerMeter = 0;
989 header.biClrUsed = 0;
990 header.biClrImportant = 0;
992 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
994 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
996 coreheader->bcWidth = header.biWidth;
997 coreheader->bcHeight = header.biHeight;
998 coreheader->bcPlanes = header.biPlanes;
999 coreheader->bcBitCount = header.biBitCount;
1002 info->bmiHeader = header;
1004 return abs(bmp->bitmap.bmHeight);
1007 /************************************************************************
1010 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1012 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1014 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1016 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1018 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1019 if (coloruse == DIB_PAL_COLORS)
1020 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1024 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1026 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1027 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1028 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1034 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1035 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1037 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1038 /* bitfields are always at bmiColors even in larger structures */
1039 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1040 else if (src->bmiHeader.biClrUsed)
1042 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1045 if (coloruse == DIB_PAL_COLORS)
1046 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1048 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1049 memcpy( colorptr, src->bmiColors, size );
1054 const RGBQUAD *get_default_color_table( int bpp )
1056 static const RGBQUAD table_1[2] =
1058 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1060 static const RGBQUAD table_4[16] =
1062 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1063 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1064 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1065 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1067 static const RGBQUAD table_8[256] =
1069 /* first and last 10 entries are the default system palette entries */
1070 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1071 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1072 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1073 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1074 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1075 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1076 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1077 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1078 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1079 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1080 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1081 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1082 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1083 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1084 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1085 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1086 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1087 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1088 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1089 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1090 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1091 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1092 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1093 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1094 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1095 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1096 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1097 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1098 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1099 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1100 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1101 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1102 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1103 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1104 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1105 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1106 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1107 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1108 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1109 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1110 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1111 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1112 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1113 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1114 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1115 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1116 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1117 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1118 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1119 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1120 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1121 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1122 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1123 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1124 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1125 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1126 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1127 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1128 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1129 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1130 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1131 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1132 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1133 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1138 case 1: return table_1;
1139 case 4: return table_4;
1140 case 8: return table_8;
1141 default: return NULL;
1145 void fill_default_color_table( BITMAPINFO *info )
1147 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1148 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1149 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1152 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1154 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1155 info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
1156 info->bmiHeader.biHeight = -bmp->bitmap.bmHeight;
1157 info->bmiHeader.biPlanes = 1;
1158 info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
1159 info->bmiHeader.biCompression = BI_RGB;
1160 info->bmiHeader.biXPelsPerMeter = 0;
1161 info->bmiHeader.biYPelsPerMeter = 0;
1162 info->bmiHeader.biClrUsed = 0;
1163 info->bmiHeader.biClrImportant = 0;
1166 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1168 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1169 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1170 unsigned int info_size;
1172 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1174 info_size = get_dib_info_size( info, usage );
1175 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1177 memcpy( ret, info, info_size );
1178 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1179 info->bmiHeader.biSizeImage );
1184 /******************************************************************************
1185 * GetDIBits [GDI32.@]
1187 * Retrieves bits of bitmap and copies to buffer.
1190 * Success: Number of scan lines copied from bitmap
1193 INT WINAPI GetDIBits(
1194 HDC hdc, /* [in] Handle to device context */
1195 HBITMAP hbitmap, /* [in] Handle to bitmap */
1196 UINT startscan, /* [in] First scan line to set in dest bitmap */
1197 UINT lines, /* [in] Number of scan lines to copy */
1198 LPVOID bits, /* [out] Address of array for bitmap bits */
1199 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1200 UINT coloruse) /* [in] RGB or palette index */
1204 int i, dst_to_src_offset, ret = 0;
1206 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1207 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1208 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1209 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1210 const struct gdi_dc_funcs *funcs;
1211 struct gdi_image_bits src_bits;
1212 struct bitblt_coords src, dst;
1213 BOOL empty_rect = FALSE;
1215 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1216 own copy and transfer the colour info back at the end */
1217 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1218 if (coloruse > DIB_PAL_COLORS) return 0;
1220 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1222 dst_info->bmiHeader.biClrUsed = 0;
1223 dst_info->bmiHeader.biClrImportant = 0;
1225 if (!(dc = get_dc_ptr( hdc )))
1227 SetLastError( ERROR_INVALID_PARAMETER );
1231 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1233 release_dc_ptr( dc );
1237 funcs = get_bitmap_funcs( bmp );
1239 src.visrect.left = 0;
1240 src.visrect.top = 0;
1241 src.visrect.right = bmp->bitmap.bmWidth;
1242 src.visrect.bottom = bmp->bitmap.bmHeight;
1244 dst.visrect.left = 0;
1245 dst.visrect.top = 0;
1246 dst.visrect.right = dst_info->bmiHeader.biWidth;
1247 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1249 if (lines == 0 || startscan >= dst.visrect.bottom)
1252 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1254 ret = fill_query_info( info, bmp );
1258 /* validate parameters */
1260 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1261 if (dst_info->bmiHeader.biHeight == 0) goto done;
1263 switch (dst_info->bmiHeader.biCompression)
1266 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1267 if (dst_info->bmiHeader.biHeight < 0) goto done;
1268 if (bits) goto done; /* can't retrieve compressed bits */
1271 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1272 if (dst_info->bmiHeader.biHeight < 0) goto done;
1273 if (bits) goto done; /* can't retrieve compressed bits */
1276 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1279 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1280 if (dst_info->bmiHeader.biBitCount == 1) break;
1281 if (dst_info->bmiHeader.biBitCount == 4) break;
1282 if (dst_info->bmiHeader.biBitCount == 8) break;
1283 if (dst_info->bmiHeader.biBitCount == 16) break;
1284 if (dst_info->bmiHeader.biBitCount == 24) break;
1285 if (dst_info->bmiHeader.biBitCount == 32) break;
1293 if (dst_info->bmiHeader.biHeight > 0)
1295 dst_to_src_offset = -startscan;
1296 lines = min( lines, dst.visrect.bottom - startscan );
1297 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1301 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1302 if (dst_to_src_offset < 0)
1304 dst_to_src_offset = 0;
1305 lines = dst.visrect.bottom - startscan;
1307 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1310 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1311 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1312 dst.visrect = src.visrect;
1313 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1315 if (dst_info->bmiHeader.biHeight > 0)
1317 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1319 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1320 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1321 memset( bits, 0, pad_bytes );
1322 bits = (char *)bits + pad_bytes;
1327 if (dst.visrect.bottom < lines)
1329 int pad_lines = lines - dst.visrect.bottom;
1330 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1331 int pad_bytes = pad_lines * stride;
1332 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1336 if (empty_rect) bits = NULL;
1338 src.x = src.visrect.left;
1339 src.y = src.visrect.top;
1340 src.width = src.visrect.right - src.visrect.left;
1341 src.height = src.visrect.bottom - src.visrect.top;
1346 err = funcs->pGetImage( NULL, hbitmap, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1350 /* fill out the src colour table, if it needs one */
1351 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1352 fill_default_color_table( src_info );
1354 /* if the src and dst are the same depth, copy the colour info across */
1355 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1357 switch (src_info->bmiHeader.biBitCount)
1360 if (src_info->bmiHeader.biCompression == BI_RGB)
1362 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1363 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1367 if (src_info->bmiHeader.biCompression == BI_RGB)
1369 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1370 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1374 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1375 copy_color_info( dst_info, src_info, coloruse );
1377 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1379 if( coloruse == DIB_PAL_COLORS )
1381 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1385 fill_default_color_table( dst_info );
1391 if(dst_info->bmiHeader.biHeight > 0)
1392 dst_info->bmiHeader.biHeight = src.height;
1394 dst_info->bmiHeader.biHeight = -src.height;
1396 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits, FALSE );
1397 if (src_bits.free) src_bits.free( &src_bits );
1401 ret = empty_rect ? FALSE : TRUE;
1403 if (coloruse == DIB_PAL_COLORS)
1405 WORD *index = (WORD *)dst_info->bmiColors;
1406 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1410 copy_color_info( info, dst_info, coloruse );
1411 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1414 release_dc_ptr( dc );
1415 GDI_ReleaseObj( hbitmap );
1420 /***********************************************************************
1421 * CreateDIBitmap (GDI32.@)
1423 * Creates a DDB (device dependent bitmap) from a DIB.
1424 * The DDB will have the same color depth as the reference DC.
1426 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1427 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1430 BITMAPINFOHEADER info;
1434 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1435 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1436 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1437 if (info.biWidth < 0) return 0;
1439 /* Top-down DIBs have a negative height */
1440 height = abs( info.biHeight );
1442 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1443 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1444 info.biBitCount, info.biCompression);
1447 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1449 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1453 if (init & CBM_INIT)
1455 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1457 DeleteObject( handle );
1467 /***********************************************************************
1468 * CreateDIBSection (GDI32.@)
1470 HBITMAP WINAPI CreateDIBSection(HDC hdc, CONST BITMAPINFO *bmi, UINT usage,
1471 VOID **bits, HANDLE section, DWORD offset)
1473 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1474 BITMAPINFO *info = (BITMAPINFO *)buffer;
1477 BOOL bDesktopDC = FALSE;
1480 RGBQUAD *color_table = NULL;
1481 void *mapBits = NULL;
1483 if (bits) *bits = NULL;
1484 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1485 if (usage > DIB_PAL_COLORS) return 0;
1486 if (info->bmiHeader.biPlanes != 1)
1488 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1489 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1492 if (!(dib = HeapAlloc( GetProcessHeap(), 0, sizeof(*dib) ))) return 0;
1494 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1495 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1496 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1497 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1498 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1500 dib->dsBm.bmType = 0;
1501 dib->dsBm.bmWidth = info->bmiHeader.biWidth;
1502 dib->dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1503 dib->dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1504 dib->dsBm.bmPlanes = info->bmiHeader.biPlanes;
1505 dib->dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1506 dib->dsBm.bmBits = NULL;
1507 dib->dsBmih = info->bmiHeader;
1509 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1511 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1513 dib->dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1514 if (!(color_table = HeapAlloc( GetProcessHeap(), 0, dib->dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1516 memcpy( color_table, info->bmiColors, dib->dsBmih.biClrUsed * sizeof(RGBQUAD) );
1519 /* set dsBitfields values */
1520 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1522 dib->dsBmih.biCompression = BI_BITFIELDS;
1523 dib->dsBitfields[0] = 0x7c00;
1524 dib->dsBitfields[1] = 0x03e0;
1525 dib->dsBitfields[2] = 0x001f;
1527 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1529 if (usage == DIB_PAL_COLORS) goto error;
1530 dib->dsBitfields[0] = *(const DWORD *)info->bmiColors;
1531 dib->dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1532 dib->dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1533 if (!dib->dsBitfields[0] || !dib->dsBitfields[1] || !dib->dsBitfields[2]) goto error;
1535 else dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
1537 /* get storage location for DIB bits */
1541 SYSTEM_INFO SystemInfo;
1545 GetSystemInfo( &SystemInfo );
1546 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1547 mapSize = dib->dsBmih.biSizeImage + (offset - mapOffset);
1548 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1549 if (mapBits) dib->dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1554 dib->dsBm.bmBits = VirtualAlloc( NULL, dib->dsBmih.biSizeImage,
1555 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1557 dib->dshSection = section;
1558 dib->dsOffset = offset;
1560 if (!dib->dsBm.bmBits) goto error;
1562 /* If the reference hdc is null, take the desktop dc */
1565 hdc = CreateCompatibleDC(0);
1569 if (!(dc = get_dc_ptr( hdc ))) goto error;
1571 /* create Device Dependent Bitmap and add DIB pointer */
1572 ret = CreateBitmap( dib->dsBm.bmWidth, dib->dsBm.bmHeight, 1,
1573 (info->bmiHeader.biBitCount == 1) ? 1 : GetDeviceCaps(hdc, BITSPIXEL), NULL );
1575 if (ret && ((bmp = GDI_GetObjPtr(ret, OBJ_BITMAP))))
1577 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pCreateDIBSection );
1579 bmp->funcs = physdev->funcs;
1580 bmp->color_table = color_table;
1581 GDI_ReleaseObj( ret );
1583 if (!physdev->funcs->pCreateDIBSection( physdev, ret, info, usage ))
1585 DeleteObject( ret );
1590 release_dc_ptr( dc );
1591 if (bDesktopDC) DeleteDC( hdc );
1592 if (ret && bits) *bits = dib->dsBm.bmBits;
1596 if (bDesktopDC) DeleteDC( hdc );
1597 if (section) UnmapViewOfFile( mapBits );
1598 else if (!offset) VirtualFree( dib->dsBm.bmBits, 0, MEM_RELEASE );
1599 HeapFree( GetProcessHeap(), 0, color_table );
1600 HeapFree( GetProcessHeap(), 0, dib );