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 colors = get_dib_num_of_colors( info );
94 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
95 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
96 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
100 /*******************************************************************************************
101 * Verify that the DIB parameters are valid.
103 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
105 if (info->biWidth <= 0) return FALSE;
106 if (info->biHeight == 0) return FALSE;
108 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
110 if (info->biHeight < 0) return FALSE;
111 if (!info->biSizeImage) return FALSE;
112 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
115 if (!info->biPlanes) return FALSE;
117 switch (info->biBitCount)
123 return (info->biCompression == BI_RGB);
126 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
132 /*******************************************************************************************
133 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
135 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
137 if (!info) return FALSE;
139 if (info->biSize == sizeof(BITMAPCOREHEADER))
141 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
142 dst->biWidth = core->bcWidth;
143 dst->biHeight = core->bcHeight;
144 dst->biPlanes = core->bcPlanes;
145 dst->biBitCount = core->bcBitCount;
146 dst->biCompression = BI_RGB;
147 dst->biXPelsPerMeter = 0;
148 dst->biYPelsPerMeter = 0;
150 dst->biClrImportant = 0;
152 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
158 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
162 dst->biSize = sizeof(*dst);
163 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
164 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
168 /*******************************************************************************************
169 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
171 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
172 UINT coloruse, BOOL allow_compression )
177 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
178 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
180 src_colors = (char *)info + info->bmiHeader.biSize;
181 colors = get_dib_num_of_colors( dst );
183 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
185 /* bitfields are always at bmiColors even in larger structures */
186 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
187 dst->bmiHeader.biClrUsed = 0;
191 if (coloruse == DIB_PAL_COLORS)
192 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
193 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
194 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
198 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
199 for (i = 0; i < colors; i++)
201 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
202 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
203 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
204 dst->bmiColors[i].rgbReserved = 0;
207 dst->bmiHeader.biClrUsed = colors;
212 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
214 PALETTEENTRY palEntry[256];
215 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
216 int i, colors = get_dib_num_of_colors( info );
218 if (!palette) return 0;
219 if (!colors) return 0;
221 memset( palEntry, 0, sizeof(palEntry) );
222 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
225 for (i = 0; i < colors; i++)
227 info->bmiColors[i].rgbRed = palEntry[i].peRed;
228 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
229 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
230 info->bmiColors[i].rgbReserved = 0;
236 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
238 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
239 const int bpp = info->bmiHeader.biBitCount;
242 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
244 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
247 static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
251 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
253 BYTE skip, num, data;
254 BYTE *out_bits, *in_bits = bits->ptr;
256 if (clip) *clip = NULL;
258 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
260 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
261 if (!out_bits) goto fail;
265 *clip = CreateRectRgn( 0, 0, 0, 0 );
266 run = CreateRectRgn( 0, 0, 0, 0 );
267 if (!*clip || !run) goto fail;
270 x = left = right = 0;
273 while (i < info->bmiHeader.biSizeImage - 1)
276 data = in_bits[i + 1];
281 if (x + num > width) num = width - x;
284 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
285 if (info->bmiHeader.biBitCount == 8)
286 memset( out_ptr, s, num );
291 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
292 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
297 /* this will write one too many if num is odd, but that doesn't matter */
298 if (num) memset( out_ptr, s, (num + 1) / 2 );
308 if(left != right && clip)
310 SetRectRgn( run, left, y, right, y + 1 );
311 CombineRgn( *clip, run, *clip, RGN_OR );
316 left = right = x = 0;
325 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
327 if (x > width) x = width;
334 else /* data bytes of data */
337 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
338 if (skip > info->bmiHeader.biSizeImage - i) goto done;
339 skip = (skip + 1) & ~1;
340 if (x + num > width) num = width - x;
343 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
344 if (info->bmiHeader.biBitCount == 8)
345 memcpy( out_ptr, in_bits + i, num );
350 const BYTE *in_ptr = in_bits + i;
351 for ( ; num; num--, x++)
355 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
359 *out_ptr = (*in_ptr++ << 4) & 0xf0;
363 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
374 if (run) DeleteObject( run );
375 if (bits->free) bits->free( bits );
377 bits->ptr = out_bits;
378 bits->is_copy = TRUE;
379 bits->free = free_heap_bits;
384 if (run) DeleteObject( run );
385 if (clip && *clip) DeleteObject( *clip );
386 HeapFree( GetProcessHeap(), 0, out_bits );
392 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
393 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
394 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
396 DC *dc = get_nulldrv_dc( dev );
397 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
398 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
399 struct bitblt_coords src, dst;
400 struct gdi_image_bits src_bits;
404 INT height = abs( src_info->bmiHeader.biHeight );
405 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
408 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
409 xSrc, ySrc, widthSrc, heightSrc, rop);
411 src_bits.ptr = (void*)bits;
412 src_bits.is_copy = FALSE;
413 src_bits.free = NULL;
415 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_palette( src_info, dev->hdc )) return 0;
419 rect.right = xDst + widthDst;
420 rect.bottom = yDst + heightDst;
421 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
424 dst.width = rect.right - rect.left;
425 dst.height = rect.bottom - rect.top;
427 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
430 dst.width = -dst.width;
432 rop &= ~NOMIRRORBITMAP;
435 src.width = widthSrc;
437 src.height = heightSrc;
439 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
440 non_stretch_from_origin = TRUE;
442 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
444 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
445 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
448 if (rop != SRCCOPY || non_stretch_from_origin)
450 if (dst.width == 1 && src.width > 1) src.width--;
451 if (dst.height == 1 && src.height > 1) src.height--;
456 if (dst.width < 0 && dst.width == src.width)
458 /* This is off-by-one, but that's what Windows does */
461 dst.width = -dst.width;
462 src.width = -src.width;
464 if (dst.height < 0 && dst.height == src.height)
468 dst.height = -dst.height;
469 src.height = -src.height;
473 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
475 if (src.y >= height && src.y + src.height + 1 < height)
477 else if (src.y > 0 && src.y + src.height + 1 < 0)
478 src.y = -src.height - 1;
480 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
482 src.visrect.left = 0;
483 src.visrect.right = src_info->bmiHeader.biWidth;
485 src.visrect.bottom = height;
486 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
488 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
490 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
492 if (!intersect_vis_rectangles( &dst, &src )) goto done;
494 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
496 dev = GET_DC_PHYSDEV( dc, pPutImage );
497 copy_bitmapinfo( dst_info, src_info );
498 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
499 if (err == ERROR_BAD_FORMAT)
501 /* 1-bpp destination without a color table requires a fake 1-entry table
502 * that contains only the background color */
503 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
505 COLORREF color = GetBkColor( dev->hdc );
506 dst_info->bmiColors[0].rgbRed = GetRValue( color );
507 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
508 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
509 dst_info->bmiColors[0].rgbReserved = 0;
510 dst_info->bmiHeader.biClrUsed = 1;
513 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits, FALSE )))
515 /* get rid of the fake 1-bpp table */
516 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
517 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, rop );
521 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
523 copy_bitmapinfo( src_info, dst_info );
524 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
525 if (!err) err = dev->funcs->pPutImage( dev, 0, NULL, dst_info, &src_bits, &src, &dst, rop );
528 else if (rop == SRCCOPY) ret = height;
529 else ret = src_info->bmiHeader.biHeight;
532 if (src_bits.free) src_bits.free( &src_bits );
533 if (clip) DeleteObject( clip );
537 /***********************************************************************
538 * StretchDIBits (GDI32.@)
540 INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
541 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
542 const BITMAPINFO *bmi, UINT coloruse, DWORD rop )
544 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
545 BITMAPINFO *info = (BITMAPINFO *)buffer;
550 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
552 SetLastError( ERROR_INVALID_PARAMETER );
556 if ((dc = get_dc_ptr( hdc )))
558 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
560 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
561 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
562 release_dc_ptr( dc );
568 /******************************************************************************
569 * SetDIBits [GDI32.@]
571 * Sets pixels in a bitmap using colors from DIB.
574 * hdc [I] Handle to device context
575 * hbitmap [I] Handle to bitmap
576 * startscan [I] Starting scan line
577 * lines [I] Number of scan lines
578 * bits [I] Array of bitmap bits
579 * info [I] Address of structure with data
580 * coloruse [I] Type of color indexes to use
583 * Success: Number of scan lines copied
586 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
587 UINT lines, LPCVOID bits, const BITMAPINFO *info,
591 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
592 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
593 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
594 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
597 struct gdi_image_bits src_bits;
598 struct bitblt_coords src, dst;
599 INT src_to_dst_offset;
601 const struct gdi_dc_funcs *funcs;
603 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ))
605 SetLastError( ERROR_INVALID_PARAMETER );
608 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
610 DWORD *masks = (DWORD *)src_info->bmiColors;
611 if (!masks[0] || !masks[1] || !masks[2])
613 SetLastError( ERROR_INVALID_PARAMETER );
618 src_bits.ptr = (void *)bits;
619 src_bits.is_copy = FALSE;
620 src_bits.free = NULL;
621 src_bits.param = NULL;
623 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_palette( src_info, hdc )) return 0;
625 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
627 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
629 if (lines == 0) goto done;
630 else lines = src_info->bmiHeader.biHeight;
633 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
636 dst.visrect.left = 0;
638 dst.visrect.right = bitmap->bitmap.bmWidth;
639 dst.visrect.bottom = bitmap->bitmap.bmHeight;
641 src.visrect.left = 0;
643 src.visrect.right = src_info->bmiHeader.biWidth;
644 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
646 if (src_info->bmiHeader.biHeight > 0)
648 src_to_dst_offset = -startscan;
649 lines = min( lines, src.visrect.bottom - startscan );
650 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
654 src_to_dst_offset = src.visrect.bottom - lines - startscan;
655 /* Unlike the bottom-up case, Windows doesn't limit lines. */
656 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
659 funcs = get_bitmap_funcs( bitmap );
663 offset_rect( &src.visrect, 0, src_to_dst_offset );
664 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
665 src.visrect = dst.visrect;
666 offset_rect( &src.visrect, 0, -src_to_dst_offset );
668 src.x = src.visrect.left;
669 src.y = src.visrect.top;
670 src.width = src.visrect.right - src.visrect.left;
671 src.height = src.visrect.bottom - src.visrect.top;
673 dst.x = dst.visrect.left;
674 dst.y = dst.visrect.top;
675 dst.width = dst.visrect.right - dst.visrect.left;
676 dst.height = dst.visrect.bottom - dst.visrect.top;
678 copy_bitmapinfo( dst_info, src_info );
680 err = funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
681 if (err == ERROR_BAD_FORMAT)
685 dst_info->bmiHeader.biWidth = dst.width;
686 ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ));
689 err = convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, ptr, FALSE );
690 if (src_bits.free) src_bits.free( &src_bits );
692 src_bits.is_copy = TRUE;
693 src_bits.free = free_heap_bits;
695 err = funcs->pPutImage( NULL, hbitmap, clip, dst_info, &src_bits, &src, &dst, 0 );
697 else err = ERROR_OUTOFMEMORY;
702 if (src_bits.free) src_bits.free( &src_bits );
703 if (clip) DeleteObject( clip );
704 GDI_ReleaseObj( hbitmap );
709 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
710 INT x_src, INT y_src, UINT startscan, UINT lines,
711 const void *bits, BITMAPINFO *src_info, UINT coloruse )
713 DC *dc = get_nulldrv_dc( dev );
714 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
715 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
716 struct bitblt_coords src, dst;
717 struct gdi_image_bits src_bits;
725 top_down = (src_info->bmiHeader.biHeight < 0);
726 height = abs( src_info->bmiHeader.biHeight );
728 src_bits.ptr = (void *)bits;
729 src_bits.is_copy = FALSE;
730 src_bits.free = NULL;
732 if (!lines) return 0;
733 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_palette( src_info, dev->hdc )) return 0;
735 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
739 src_info->bmiHeader.biWidth = x_src + cx;
740 src_info->bmiHeader.biHeight = y_src + cy;
741 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
746 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
750 if (startscan >= height) return 0;
751 if (!top_down && lines > height - startscan) lines = height - startscan;
753 /* map src to top-down coordinates with startscan as origin */
755 src.y = startscan + lines - (y_src + cy);
762 /* get rid of unnecessary lines */
763 if (src.y >= lines) return 0;
767 else if (src.y >= lines) return lines;
769 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
772 src.visrect.left = src.x;
773 src.visrect.top = src.y;
774 src.visrect.right = src.x + cx;
775 src.visrect.bottom = src.y + cy;
778 rect.right = src_info->bmiHeader.biWidth;
779 rect.bottom = abs( src_info->bmiHeader.biHeight );
780 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
788 LPtoDP( dev->hdc, &pt, 1 );
793 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
797 rect.right = dst.x + cx;
798 rect.bottom = dst.y + cy;
799 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
801 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
802 intersect_rect( &rect, &src.visrect, &dst.visrect );
803 src.visrect = dst.visrect = rect;
804 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
805 if (is_rect_empty( &dst.visrect )) goto done;
806 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
808 dev = GET_DC_PHYSDEV( dc, pPutImage );
809 copy_bitmapinfo( dst_info, src_info );
810 err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
811 if (err == ERROR_BAD_FORMAT)
815 dst_info->bmiHeader.biWidth = src.visrect.right - src.visrect.left;
816 ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ));
819 err = convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, ptr, FALSE );
820 if (src_bits.free) src_bits.free( &src_bits );
822 src_bits.is_copy = TRUE;
823 src_bits.free = free_heap_bits;
824 if (!err) err = dev->funcs->pPutImage( dev, 0, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
826 else err = ERROR_OUTOFMEMORY;
831 if (src_bits.free) src_bits.free( &src_bits );
832 if (clip) DeleteObject( clip );
836 /***********************************************************************
837 * SetDIBitsToDevice (GDI32.@)
839 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
840 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
841 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
844 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
845 BITMAPINFO *info = (BITMAPINFO *)buffer;
850 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
852 SetLastError( ERROR_INVALID_PARAMETER );
856 if ((dc = get_dc_ptr( hdc )))
858 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
860 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
861 ySrc, startscan, lines, bits, info, coloruse );
862 release_dc_ptr( dc );
867 /***********************************************************************
868 * SetDIBColorTable (GDI32.@)
870 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, CONST RGBQUAD *colors )
876 if (!(dc = get_dc_ptr( hdc ))) return 0;
878 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
880 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetDIBColorTable );
882 /* Check if currently selected bitmap is a DIB */
883 if (bitmap->color_table)
885 if (startpos < bitmap->nb_colors)
887 if (startpos + entries > bitmap->nb_colors) entries = bitmap->nb_colors - startpos;
888 memcpy(bitmap->color_table + startpos, colors, entries * sizeof(RGBQUAD));
892 GDI_ReleaseObj( dc->hBitmap );
893 physdev->funcs->pSetDIBColorTable( physdev, startpos, entries, colors );
895 release_dc_ptr( dc );
900 /***********************************************************************
901 * GetDIBColorTable (GDI32.@)
903 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
909 if (!(dc = get_dc_ptr( hdc ))) return 0;
911 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
913 /* Check if currently selected bitmap is a DIB */
914 if (bitmap->color_table)
916 if (startpos < bitmap->nb_colors)
918 if (startpos + entries > bitmap->nb_colors) entries = bitmap->nb_colors - startpos;
919 memcpy(colors, bitmap->color_table + startpos, entries * sizeof(RGBQUAD));
923 GDI_ReleaseObj( dc->hBitmap );
925 release_dc_ptr( dc );
929 static const RGBQUAD DefLogPaletteQuads[20] = { /* Copy of Default Logical Palette */
930 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */
931 { 0x00, 0x00, 0x00, 0x00 },
932 { 0x00, 0x00, 0x80, 0x00 },
933 { 0x00, 0x80, 0x00, 0x00 },
934 { 0x00, 0x80, 0x80, 0x00 },
935 { 0x80, 0x00, 0x00, 0x00 },
936 { 0x80, 0x00, 0x80, 0x00 },
937 { 0x80, 0x80, 0x00, 0x00 },
938 { 0xc0, 0xc0, 0xc0, 0x00 },
939 { 0xc0, 0xdc, 0xc0, 0x00 },
940 { 0xf0, 0xca, 0xa6, 0x00 },
941 { 0xf0, 0xfb, 0xff, 0x00 },
942 { 0xa4, 0xa0, 0xa0, 0x00 },
943 { 0x80, 0x80, 0x80, 0x00 },
944 { 0x00, 0x00, 0xff, 0x00 },
945 { 0x00, 0xff, 0x00, 0x00 },
946 { 0x00, 0xff, 0xff, 0x00 },
947 { 0xff, 0x00, 0x00, 0x00 },
948 { 0xff, 0x00, 0xff, 0x00 },
949 { 0xff, 0xff, 0x00, 0x00 },
950 { 0xff, 0xff, 0xff, 0x00 }
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 unsigned int colors = get_dib_num_of_colors( src );
1015 RGBQUAD *src_colors = (RGBQUAD *)((char *)src + src->bmiHeader.biSize);
1017 assert( src->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER) );
1019 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1021 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1022 if (coloruse == DIB_PAL_COLORS)
1023 memcpy( core->bmciColors, src_colors, colors * sizeof(WORD) );
1027 for (i = 0; i < colors; i++)
1029 core->bmciColors[i].rgbtRed = src_colors[i].rgbRed;
1030 core->bmciColors[i].rgbtGreen = src_colors[i].rgbGreen;
1031 core->bmciColors[i].rgbtBlue = src_colors[i].rgbBlue;
1037 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1038 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1040 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1041 /* bitfields are always at bmiColors even in larger structures */
1042 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1045 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1048 if (coloruse == DIB_PAL_COLORS)
1049 size = colors * sizeof(WORD);
1051 size = colors * sizeof(RGBQUAD);
1052 memcpy( colorptr, src_colors, size );
1057 void fill_default_color_table( BITMAPINFO *info )
1061 switch (info->bmiHeader.biBitCount)
1064 info->bmiColors[0].rgbRed = info->bmiColors[0].rgbGreen = info->bmiColors[0].rgbBlue = 0;
1065 info->bmiColors[0].rgbReserved = 0;
1066 info->bmiColors[1].rgbRed = info->bmiColors[1].rgbGreen = info->bmiColors[1].rgbBlue = 0xff;
1067 info->bmiColors[1].rgbReserved = 0;
1071 /* The EGA palette is the first and last 8 colours of the default palette
1072 with the innermost pair swapped */
1073 memcpy(info->bmiColors, DefLogPaletteQuads, 7 * sizeof(RGBQUAD));
1074 memcpy(info->bmiColors + 7, DefLogPaletteQuads + 12, 1 * sizeof(RGBQUAD));
1075 memcpy(info->bmiColors + 8, DefLogPaletteQuads + 7, 1 * sizeof(RGBQUAD));
1076 memcpy(info->bmiColors + 9, DefLogPaletteQuads + 13, 7 * sizeof(RGBQUAD));
1080 memcpy(info->bmiColors, DefLogPaletteQuads, 10 * sizeof(RGBQUAD));
1081 memcpy(info->bmiColors + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD));
1082 for (i = 10; i < 246; i++)
1084 info->bmiColors[i].rgbRed = (i & 0x07) << 5;
1085 info->bmiColors[i].rgbGreen = (i & 0x38) << 2;
1086 info->bmiColors[i].rgbBlue = i & 0xc0;
1087 info->bmiColors[i].rgbReserved = 0;
1092 ERR("called with bitcount %d\n", info->bmiHeader.biBitCount);
1094 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1097 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1099 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1100 info->bmiHeader.biWidth = bmp->bitmap.bmWidth;
1101 info->bmiHeader.biHeight = -bmp->bitmap.bmHeight;
1102 info->bmiHeader.biPlanes = 1;
1103 info->bmiHeader.biBitCount = bmp->bitmap.bmBitsPixel;
1104 info->bmiHeader.biCompression = BI_RGB;
1105 info->bmiHeader.biXPelsPerMeter = 0;
1106 info->bmiHeader.biYPelsPerMeter = 0;
1107 info->bmiHeader.biClrUsed = 0;
1108 info->bmiHeader.biClrImportant = 0;
1109 if (info->bmiHeader.biBitCount <= 8) fill_default_color_table( info );
1112 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1114 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1115 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1116 int info_size, image_size;
1118 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1120 info_size = bitmap_info_size( info, usage );
1121 image_size = get_dib_image_size( info );
1122 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + image_size )))
1124 memcpy( ret, info, info_size );
1125 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size(src_info,usage), image_size );
1130 /******************************************************************************
1131 * GetDIBits [GDI32.@]
1133 * Retrieves bits of bitmap and copies to buffer.
1136 * Success: Number of scan lines copied from bitmap
1139 INT WINAPI GetDIBits(
1140 HDC hdc, /* [in] Handle to device context */
1141 HBITMAP hbitmap, /* [in] Handle to bitmap */
1142 UINT startscan, /* [in] First scan line to set in dest bitmap */
1143 UINT lines, /* [in] Number of scan lines to copy */
1144 LPVOID bits, /* [out] Address of array for bitmap bits */
1145 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1146 UINT coloruse) /* [in] RGB or palette index */
1150 int i, dst_to_src_offset, ret = 0;
1152 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1153 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1154 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1155 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1156 const struct gdi_dc_funcs *funcs;
1157 struct gdi_image_bits src_bits;
1158 struct bitblt_coords src, dst;
1159 BOOL empty_rect = FALSE;
1161 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1162 own copy and transfer the colour info back at the end */
1163 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1165 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1167 dst_info->bmiHeader.biClrUsed = 0;
1168 dst_info->bmiHeader.biClrImportant = 0;
1170 if (!(dc = get_dc_ptr( hdc )))
1172 SetLastError( ERROR_INVALID_PARAMETER );
1176 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1178 release_dc_ptr( dc );
1182 funcs = get_bitmap_funcs( bmp );
1184 src.visrect.left = 0;
1185 src.visrect.top = 0;
1186 src.visrect.right = bmp->bitmap.bmWidth;
1187 src.visrect.bottom = bmp->bitmap.bmHeight;
1189 dst.visrect.left = 0;
1190 dst.visrect.top = 0;
1191 dst.visrect.right = dst_info->bmiHeader.biWidth;
1192 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1194 if (lines == 0 || startscan >= dst.visrect.bottom)
1197 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1199 ret = fill_query_info( info, bmp );
1203 /* validate parameters */
1205 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1206 if (dst_info->bmiHeader.biHeight == 0) goto done;
1208 switch (dst_info->bmiHeader.biCompression)
1211 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1212 if (dst_info->bmiHeader.biHeight < 0) goto done;
1213 if (bits) goto done; /* can't retrieve compressed bits */
1216 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1217 if (dst_info->bmiHeader.biHeight < 0) goto done;
1218 if (bits) goto done; /* can't retrieve compressed bits */
1221 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1224 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1225 if (dst_info->bmiHeader.biBitCount == 1) break;
1226 if (dst_info->bmiHeader.biBitCount == 4) break;
1227 if (dst_info->bmiHeader.biBitCount == 8) break;
1228 if (dst_info->bmiHeader.biBitCount == 16) break;
1229 if (dst_info->bmiHeader.biBitCount == 24) break;
1230 if (dst_info->bmiHeader.biBitCount == 32) break;
1238 if (dst_info->bmiHeader.biHeight > 0)
1240 dst_to_src_offset = -startscan;
1241 lines = min( lines, dst.visrect.bottom - startscan );
1242 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1246 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1247 if (dst_to_src_offset < 0)
1249 dst_to_src_offset = 0;
1250 lines = dst.visrect.bottom - startscan;
1252 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1255 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1256 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1257 dst.visrect = src.visrect;
1258 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1260 if (dst_info->bmiHeader.biHeight > 0)
1262 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1264 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1265 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1266 memset( bits, 0, pad_bytes );
1267 bits = (char *)bits + pad_bytes;
1272 if (dst.visrect.bottom < lines)
1274 int pad_lines = lines - dst.visrect.bottom;
1275 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1276 int pad_bytes = pad_lines * stride;
1277 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1281 if (empty_rect) bits = NULL;
1283 src.x = src.visrect.left;
1284 src.y = src.visrect.top;
1285 src.width = src.visrect.right - src.visrect.left;
1286 src.height = src.visrect.bottom - src.visrect.top;
1291 err = funcs->pGetImage( NULL, hbitmap, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1295 /* fill out the src colour table, if it needs one */
1296 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1297 fill_default_color_table( src_info );
1299 /* if the src and dst are the same depth, copy the colour info across */
1300 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1302 switch (src_info->bmiHeader.biBitCount)
1305 if (src_info->bmiHeader.biCompression == BI_RGB)
1307 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1308 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1312 if (src_info->bmiHeader.biCompression == BI_RGB)
1314 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1315 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1319 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1320 copy_color_info( dst_info, src_info, coloruse );
1322 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1324 if( coloruse == DIB_PAL_COLORS )
1326 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1330 fill_default_color_table( dst_info );
1336 if(dst_info->bmiHeader.biHeight > 0)
1337 dst_info->bmiHeader.biHeight = src.height;
1339 dst_info->bmiHeader.biHeight = -src.height;
1341 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits, FALSE );
1342 if (src_bits.free) src_bits.free( &src_bits );
1346 ret = empty_rect ? FALSE : TRUE;
1348 if (coloruse == DIB_PAL_COLORS)
1350 WORD *index = (WORD *)dst_info->bmiColors;
1351 int colors = get_dib_num_of_colors( dst_info );
1352 for (i = 0; i < colors; i++, index++)
1356 copy_color_info( info, dst_info, coloruse );
1359 release_dc_ptr( dc );
1360 GDI_ReleaseObj( hbitmap );
1365 /***********************************************************************
1366 * CreateDIBitmap (GDI32.@)
1368 * Creates a DDB (device dependent bitmap) from a DIB.
1369 * The DDB will have the same color depth as the reference DC.
1371 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1372 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1375 BITMAPINFOHEADER info;
1379 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1380 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1381 if (info.biWidth < 0) return 0;
1383 /* Top-down DIBs have a negative height */
1384 height = abs( info.biHeight );
1386 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1387 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1388 info.biBitCount, info.biCompression);
1391 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1393 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1397 if (init & CBM_INIT)
1399 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1401 DeleteObject( handle );
1410 /* Copy/synthesize RGB palette from BITMAPINFO */
1411 static void DIB_CopyColorTable( DC *dc, BITMAPOBJ *bmp, WORD coloruse, const BITMAPINFO *info )
1413 unsigned int colors, i;
1415 colors = get_dib_num_of_colors( info );
1416 if (!(bmp->color_table = HeapAlloc(GetProcessHeap(), 0, colors * sizeof(RGBQUAD) ))) return;
1417 bmp->nb_colors = colors;
1419 if (coloruse == DIB_RGB_COLORS)
1421 memcpy( bmp->color_table, info->bmiColors, colors * sizeof(RGBQUAD));
1425 PALETTEENTRY entries[256];
1426 const WORD *index = (const WORD *)info->bmiColors;
1427 UINT count = GetPaletteEntries( dc->hPalette, 0, colors, entries );
1429 for (i = 0; i < colors; i++, index++)
1431 PALETTEENTRY *entry = &entries[*index % count];
1432 bmp->color_table[i].rgbRed = entry->peRed;
1433 bmp->color_table[i].rgbGreen = entry->peGreen;
1434 bmp->color_table[i].rgbBlue = entry->peBlue;
1435 bmp->color_table[i].rgbReserved = 0;
1440 /***********************************************************************
1441 * CreateDIBSection (GDI32.@)
1443 HBITMAP WINAPI CreateDIBSection(HDC hdc, CONST BITMAPINFO *bmi, UINT usage,
1444 VOID **bits, HANDLE section, DWORD offset)
1446 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1447 BITMAPINFO *info = (BITMAPINFO *)buffer;
1450 BOOL bDesktopDC = FALSE;
1453 void *mapBits = NULL;
1455 if (bits) *bits = NULL;
1456 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1457 if (info->bmiHeader.biPlanes != 1)
1459 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1460 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1463 if (!(dib = HeapAlloc( GetProcessHeap(), 0, sizeof(*dib) ))) return 0;
1465 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1466 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1467 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1468 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1469 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1471 dib->dsBm.bmType = 0;
1472 dib->dsBm.bmWidth = info->bmiHeader.biWidth;
1473 dib->dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1474 dib->dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1475 dib->dsBm.bmPlanes = info->bmiHeader.biPlanes;
1476 dib->dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1477 dib->dsBm.bmBits = NULL;
1478 dib->dsBmih = info->bmiHeader;
1480 /* set number of entries in bmi.bmiColors table */
1481 if( info->bmiHeader.biBitCount <= 8 )
1482 dib->dsBmih.biClrUsed = 1 << info->bmiHeader.biBitCount;
1484 /* set dsBitfields values */
1485 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1487 dib->dsBmih.biCompression = BI_BITFIELDS;
1488 dib->dsBitfields[0] = 0x7c00;
1489 dib->dsBitfields[1] = 0x03e0;
1490 dib->dsBitfields[2] = 0x001f;
1492 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1494 dib->dsBitfields[0] = *(const DWORD *)bmi->bmiColors;
1495 dib->dsBitfields[1] = *((const DWORD *)bmi->bmiColors + 1);
1496 dib->dsBitfields[2] = *((const DWORD *)bmi->bmiColors + 2);
1497 if (!dib->dsBitfields[0] || !dib->dsBitfields[1] || !dib->dsBitfields[2]) goto error;
1499 else dib->dsBitfields[0] = dib->dsBitfields[1] = dib->dsBitfields[2] = 0;
1501 /* get storage location for DIB bits */
1505 SYSTEM_INFO SystemInfo;
1509 GetSystemInfo( &SystemInfo );
1510 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1511 mapSize = dib->dsBmih.biSizeImage + (offset - mapOffset);
1512 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1513 if (mapBits) dib->dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1518 dib->dsBm.bmBits = VirtualAlloc( NULL, dib->dsBmih.biSizeImage,
1519 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1521 dib->dshSection = section;
1522 dib->dsOffset = offset;
1524 if (!dib->dsBm.bmBits)
1526 HeapFree( GetProcessHeap(), 0, dib );
1530 /* If the reference hdc is null, take the desktop dc */
1533 hdc = CreateCompatibleDC(0);
1537 if (!(dc = get_dc_ptr( hdc ))) goto error;
1539 /* create Device Dependent Bitmap and add DIB pointer */
1540 ret = CreateBitmap( dib->dsBm.bmWidth, dib->dsBm.bmHeight, 1,
1541 (info->bmiHeader.biBitCount == 1) ? 1 : GetDeviceCaps(hdc, BITSPIXEL), NULL );
1543 if (ret && ((bmp = GDI_GetObjPtr(ret, OBJ_BITMAP))))
1545 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pCreateDIBSection );
1547 bmp->funcs = physdev->funcs;
1548 /* create local copy of DIB palette */
1549 if (info->bmiHeader.biBitCount <= 8) DIB_CopyColorTable( dc, bmp, usage, info );
1550 GDI_ReleaseObj( ret );
1552 if (!physdev->funcs->pCreateDIBSection( physdev, ret, info, usage ))
1554 DeleteObject( ret );
1559 release_dc_ptr( dc );
1560 if (bDesktopDC) DeleteDC( hdc );
1561 if (ret && bits) *bits = dib->dsBm.bmBits;
1565 if (bDesktopDC) DeleteDC( hdc );
1566 if (section) UnmapViewOfFile( mapBits );
1567 else if (!offset) VirtualFree( dib->dsBm.bmBits, 0, MEM_RELEASE );
1568 HeapFree( GetProcessHeap(), 0, dib );