psapi: Implement semi-stub for K32EnumProcessModulesEx.
[wine.git] / dlls / gdi32 / dib.c
blob708a9a8b1935c7b0951431b91e10d109291d47d5
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 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc );
76 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
77 static BOOL DIB_DeleteObject( HGDIOBJ handle );
79 static const struct gdi_obj_funcs dib_funcs =
81 DIB_SelectObject, /* pSelectObject */
82 DIB_GetObject, /* pGetObjectA */
83 DIB_GetObject, /* pGetObjectW */
84 NULL, /* pUnrealizeObject */
85 DIB_DeleteObject /* pDeleteObject */
88 /***********************************************************************
89 * bitmap_info_size
91 * Return the size of the bitmap info structure including color table.
93 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
95 unsigned int colors, size, masks = 0;
97 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
99 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
100 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
101 return sizeof(BITMAPCOREHEADER) + colors *
102 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
104 else /* assume BITMAPINFOHEADER */
106 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
107 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
108 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
109 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
110 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
114 /*******************************************************************************************
115 * Verify that the DIB parameters are valid.
117 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
119 if (info->biWidth <= 0) return FALSE;
120 if (info->biHeight == 0) return FALSE;
122 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
124 if (info->biHeight < 0) return FALSE;
125 if (!info->biSizeImage) return FALSE;
126 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
129 if (!info->biPlanes) return FALSE;
131 /* check for size overflow */
132 if (!info->biBitCount) return FALSE;
133 if (UINT_MAX / info->biBitCount < info->biWidth) return FALSE;
134 if (UINT_MAX / get_dib_stride( info->biWidth, info->biBitCount ) < abs( info->biHeight )) return FALSE;
136 switch (info->biBitCount)
138 case 1:
139 case 4:
140 case 8:
141 case 24:
142 return (info->biCompression == BI_RGB);
143 case 16:
144 case 32:
145 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
146 default:
147 return FALSE;
151 /*******************************************************************************************
152 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
154 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
156 if (!info) return FALSE;
158 if (info->biSize == sizeof(BITMAPCOREHEADER))
160 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
161 dst->biWidth = core->bcWidth;
162 dst->biHeight = core->bcHeight;
163 dst->biPlanes = core->bcPlanes;
164 dst->biBitCount = core->bcBitCount;
165 dst->biCompression = BI_RGB;
166 dst->biXPelsPerMeter = 0;
167 dst->biYPelsPerMeter = 0;
168 dst->biClrUsed = 0;
169 dst->biClrImportant = 0;
171 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
173 *dst = *info;
175 else
177 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
178 return FALSE;
181 dst->biSize = sizeof(*dst);
182 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
183 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
184 return TRUE;
187 /*******************************************************************************************
188 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
190 * The resulting sanitized BITMAPINFO is guaranteed to have:
191 * - biSize set to sizeof(BITMAPINFOHEADER)
192 * - biSizeImage set to the actual image size even for non-compressed DIB
193 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
194 * - color table present only for <= 8 bpp, always starts at info->bmiColors
196 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
197 UINT coloruse, BOOL allow_compression )
199 void *src_colors;
201 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
202 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
203 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
205 src_colors = (char *)info + info->bmiHeader.biSize;
207 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
209 /* bitfields are always at bmiColors even in larger structures */
210 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
211 dst->bmiHeader.biClrUsed = 0;
213 else if (dst->bmiHeader.biBitCount <= 8)
215 unsigned int colors = dst->bmiHeader.biClrUsed;
216 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
218 if (!colors) colors = max_colors;
219 else colors = min( colors, max_colors );
221 if (coloruse == DIB_PAL_COLORS)
223 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
224 max_colors = colors;
226 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
228 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
230 else
232 unsigned int i;
233 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
234 for (i = 0; i < colors; i++)
236 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
237 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
238 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
239 dst->bmiColors[i].rgbReserved = 0;
242 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
243 dst->bmiHeader.biClrUsed = max_colors;
245 else dst->bmiHeader.biClrUsed = 0;
247 return TRUE;
250 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
252 PALETTEENTRY palEntry[256];
253 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
254 int i, colors = 1 << info->bmiHeader.biBitCount;
256 info->bmiHeader.biClrUsed = colors;
258 if (!palette) return 0;
260 memset( palEntry, 0, sizeof(palEntry) );
261 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
262 return 0;
264 for (i = 0; i < colors; i++)
266 info->bmiColors[i].rgbRed = palEntry[i].peRed;
267 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
268 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
269 info->bmiColors[i].rgbReserved = 0;
272 return colors;
275 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
277 PALETTEENTRY entries[256];
278 RGBQUAD table[256];
279 HPALETTE palette;
280 const WORD *index = (const WORD *)info->bmiColors;
281 int i, count, colors = info->bmiHeader.biClrUsed;
283 if (!colors) return TRUE;
284 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
285 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
287 for (i = 0; i < colors; i++, index++)
289 table[i].rgbRed = entries[*index % count].peRed;
290 table[i].rgbGreen = entries[*index % count].peGreen;
291 table[i].rgbBlue = entries[*index % count].peBlue;
292 table[i].rgbReserved = 0;
294 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
295 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
296 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
297 return TRUE;
300 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
302 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
303 const int bpp = info->bmiHeader.biBitCount;
305 if (height > 0)
306 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
307 else
308 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
311 static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
313 DWORD i = 0;
314 int left, right;
315 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
316 HRGN run = NULL;
317 BYTE skip, num, data;
318 BYTE *out_bits, *in_bits = bits->ptr;
320 if (clip) *clip = NULL;
322 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
324 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
325 if (!out_bits) goto fail;
327 if (clip)
329 *clip = CreateRectRgn( 0, 0, 0, 0 );
330 run = CreateRectRgn( 0, 0, 0, 0 );
331 if (!*clip || !run) goto fail;
334 x = left = right = 0;
335 y = height - 1;
337 while (i < info->bmiHeader.biSizeImage - 1)
339 num = in_bits[i];
340 data = in_bits[i + 1];
341 i += 2;
343 if (num)
345 if (x + num > width) num = width - x;
346 if (num)
348 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
349 if (info->bmiHeader.biBitCount == 8)
350 memset( out_ptr, s, num );
351 else
353 if(x & 1)
355 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
356 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
357 out_ptr++;
358 x++;
359 num--;
361 /* this will write one too many if num is odd, but that doesn't matter */
362 if (num) memset( out_ptr, s, (num + 1) / 2 );
365 x += num;
366 right = x;
368 else
370 if (data < 3)
372 if(left != right && clip)
374 SetRectRgn( run, left, y, right, y + 1 );
375 CombineRgn( *clip, run, *clip, RGN_OR );
377 switch (data)
379 case 0: /* eol */
380 left = right = x = 0;
381 y--;
382 if(y < 0) goto done;
383 break;
385 case 1: /* eod */
386 goto done;
388 case 2: /* delta */
389 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
390 x += in_bits[i];
391 if (x > width) x = width;
392 left = right = x;
393 y -= in_bits[i + 1];
394 if(y < 0) goto done;
395 i += 2;
398 else /* data bytes of data */
400 num = data;
401 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
402 if (skip > info->bmiHeader.biSizeImage - i) goto done;
403 skip = (skip + 1) & ~1;
404 if (x + num > width) num = width - x;
405 if (num)
407 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
408 if (info->bmiHeader.biBitCount == 8)
409 memcpy( out_ptr, in_bits + i, num );
410 else
412 if(x & 1)
414 const BYTE *in_ptr = in_bits + i;
415 for ( ; num; num--, x++)
417 if (x & 1)
419 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
420 out_ptr++;
422 else
423 *out_ptr = (*in_ptr++ << 4) & 0xf0;
426 else
427 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
430 x += num;
431 right = x;
432 i += skip;
437 done:
438 if (run) DeleteObject( run );
439 if (bits->free) bits->free( bits );
441 bits->ptr = out_bits;
442 bits->is_copy = TRUE;
443 bits->free = free_heap_bits;
445 return TRUE;
447 fail:
448 if (run) DeleteObject( run );
449 if (clip && *clip) DeleteObject( *clip );
450 HeapFree( GetProcessHeap(), 0, out_bits );
451 return FALSE;
456 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
457 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
458 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
460 DC *dc = get_nulldrv_dc( dev );
461 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
462 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
463 struct bitblt_coords src, dst;
464 struct gdi_image_bits src_bits;
465 DWORD err;
466 HRGN clip = NULL;
467 INT ret = 0;
468 INT height = abs( src_info->bmiHeader.biHeight );
469 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
470 RECT rect;
472 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
473 xSrc, ySrc, widthSrc, heightSrc, rop);
475 src_bits.ptr = (void*)bits;
476 src_bits.is_copy = FALSE;
477 src_bits.free = NULL;
479 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
481 rect.left = xDst;
482 rect.top = yDst;
483 rect.right = xDst + widthDst;
484 rect.bottom = yDst + heightDst;
485 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
486 dst.x = rect.left;
487 dst.y = rect.top;
488 dst.width = rect.right - rect.left;
489 dst.height = rect.bottom - rect.top;
491 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
493 dst.x += dst.width;
494 dst.width = -dst.width;
496 rop &= ~NOMIRRORBITMAP;
498 src.x = xSrc;
499 src.width = widthSrc;
500 src.y = ySrc;
501 src.height = heightSrc;
503 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
504 non_stretch_from_origin = TRUE;
506 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
508 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
509 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
512 if (rop != SRCCOPY || non_stretch_from_origin)
514 if (dst.width == 1 && src.width > 1) src.width--;
515 if (dst.height == 1 && src.height > 1) src.height--;
518 if (rop != SRCCOPY)
520 if (dst.width < 0 && dst.width == src.width)
522 /* This is off-by-one, but that's what Windows does */
523 dst.x += dst.width;
524 src.x += src.width;
525 dst.width = -dst.width;
526 src.width = -src.width;
528 if (dst.height < 0 && dst.height == src.height)
530 dst.y += dst.height;
531 src.y += src.height;
532 dst.height = -dst.height;
533 src.height = -src.height;
537 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
539 if (src.y >= height && src.y + src.height + 1 < height)
540 src.y = height - 1;
541 else if (src.y > 0 && src.y + src.height + 1 < 0)
542 src.y = -src.height - 1;
544 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
546 src.visrect.left = 0;
547 src.visrect.right = src_info->bmiHeader.biWidth;
548 src.visrect.top = 0;
549 src.visrect.bottom = height;
550 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
552 if (rop == SRCCOPY) ret = height;
553 else ret = src_info->bmiHeader.biHeight;
555 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
557 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
559 if (!intersect_vis_rectangles( &dst, &src )) goto done;
561 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
563 dev = GET_DC_PHYSDEV( dc, pPutImage );
564 copy_bitmapinfo( dst_info, src_info );
565 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
566 if (err == ERROR_BAD_FORMAT)
568 /* 1-bpp destination without a color table requires a fake 1-entry table
569 * that contains only the background color */
570 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
572 COLORREF color = GetBkColor( dev->hdc );
573 dst_info->bmiColors[0].rgbRed = GetRValue( color );
574 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
575 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
576 dst_info->bmiColors[0].rgbReserved = 0;
577 dst_info->bmiHeader.biClrUsed = 1;
580 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
582 /* get rid of the fake 1-bpp table */
583 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
584 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
588 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
590 copy_bitmapinfo( src_info, dst_info );
591 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
592 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
594 if (err) ret = 0;
596 done:
597 if (src_bits.free) src_bits.free( &src_bits );
598 if (clip) DeleteObject( clip );
599 return ret;
602 /***********************************************************************
603 * StretchDIBits (GDI32.@)
605 INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
606 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
607 const BITMAPINFO *bmi, UINT coloruse, DWORD rop )
609 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
610 BITMAPINFO *info = (BITMAPINFO *)buffer;
611 PHYSDEV physdev;
612 DC *dc;
613 INT ret = 0;
615 if (!bits) return 0;
616 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
618 SetLastError( ERROR_INVALID_PARAMETER );
619 return 0;
622 if ((dc = get_dc_ptr( hdc )))
624 update_dc( dc );
625 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
626 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
627 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
628 release_dc_ptr( dc );
630 return ret;
634 /******************************************************************************
635 * SetDIBits [GDI32.@]
637 * Sets pixels in a bitmap using colors from DIB.
639 * PARAMS
640 * hdc [I] Handle to device context
641 * hbitmap [I] Handle to bitmap
642 * startscan [I] Starting scan line
643 * lines [I] Number of scan lines
644 * bits [I] Array of bitmap bits
645 * info [I] Address of structure with data
646 * coloruse [I] Type of color indexes to use
648 * RETURNS
649 * Success: Number of scan lines copied
650 * Failure: 0
652 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
653 UINT lines, LPCVOID bits, const BITMAPINFO *info,
654 UINT coloruse )
656 BITMAPOBJ *bitmap;
657 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
658 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
659 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
660 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
661 INT result = 0;
662 DWORD err;
663 struct gdi_image_bits src_bits;
664 struct bitblt_coords src, dst;
665 INT src_to_dst_offset;
666 HRGN clip = 0;
668 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
670 SetLastError( ERROR_INVALID_PARAMETER );
671 return 0;
673 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
675 DWORD *masks = (DWORD *)src_info->bmiColors;
676 if (!masks[0] || !masks[1] || !masks[2])
678 SetLastError( ERROR_INVALID_PARAMETER );
679 return 0;
683 src_bits.ptr = (void *)bits;
684 src_bits.is_copy = FALSE;
685 src_bits.free = NULL;
686 src_bits.param = NULL;
688 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
690 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
692 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
694 if (lines == 0) goto done;
695 else lines = src_info->bmiHeader.biHeight;
696 startscan = 0;
698 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
701 dst.visrect.left = 0;
702 dst.visrect.top = 0;
703 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
704 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
706 src.visrect.left = 0;
707 src.visrect.top = 0;
708 src.visrect.right = src_info->bmiHeader.biWidth;
709 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
711 if (src_info->bmiHeader.biHeight > 0)
713 src_to_dst_offset = -startscan;
714 lines = min( lines, src.visrect.bottom - startscan );
715 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
717 else
719 src_to_dst_offset = src.visrect.bottom - lines - startscan;
720 /* Unlike the bottom-up case, Windows doesn't limit lines. */
721 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
724 result = lines;
726 offset_rect( &src.visrect, 0, src_to_dst_offset );
727 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
728 src.visrect = dst.visrect;
729 offset_rect( &src.visrect, 0, -src_to_dst_offset );
731 src.x = src.visrect.left;
732 src.y = src.visrect.top;
733 src.width = src.visrect.right - src.visrect.left;
734 src.height = src.visrect.bottom - src.visrect.top;
736 dst.x = dst.visrect.left;
737 dst.y = dst.visrect.top;
738 dst.width = dst.visrect.right - dst.visrect.left;
739 dst.height = dst.visrect.bottom - dst.visrect.top;
741 copy_bitmapinfo( dst_info, src_info );
743 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
744 if (err == ERROR_BAD_FORMAT)
746 err = convert_bits( src_info, &src, dst_info, &src_bits );
747 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
749 if(err) result = 0;
751 done:
752 if (src_bits.free) src_bits.free( &src_bits );
753 if (clip) DeleteObject( clip );
754 GDI_ReleaseObj( hbitmap );
755 return result;
759 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
760 INT x_src, INT y_src, UINT startscan, UINT lines,
761 const void *bits, BITMAPINFO *src_info, UINT coloruse )
763 DC *dc = get_nulldrv_dc( dev );
764 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
765 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
766 struct bitblt_coords src, dst;
767 struct gdi_image_bits src_bits;
768 HRGN clip = 0;
769 DWORD err;
770 UINT height;
771 BOOL top_down;
772 POINT pt;
773 RECT rect;
775 top_down = (src_info->bmiHeader.biHeight < 0);
776 height = abs( src_info->bmiHeader.biHeight );
778 src_bits.ptr = (void *)bits;
779 src_bits.is_copy = FALSE;
780 src_bits.free = NULL;
782 if (!lines) return 0;
783 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
785 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
787 startscan = 0;
788 lines = height;
789 src_info->bmiHeader.biWidth = x_src + cx;
790 src_info->bmiHeader.biHeight = y_src + cy;
791 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
792 src.x = x_src;
793 src.y = 0;
794 src.width = cx;
795 src.height = cy;
796 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
798 else
800 if (startscan >= height) return 0;
801 if (!top_down && lines > height - startscan) lines = height - startscan;
803 /* map src to top-down coordinates with startscan as origin */
804 src.x = x_src;
805 src.y = startscan + lines - (y_src + cy);
806 src.width = cx;
807 src.height = cy;
808 if (src.y > 0)
810 if (!top_down)
812 /* get rid of unnecessary lines */
813 if (src.y >= lines) return 0;
814 lines -= src.y;
815 src.y = 0;
817 else if (src.y >= lines) return lines;
819 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
822 src.visrect.left = src.x;
823 src.visrect.top = src.y;
824 src.visrect.right = src.x + cx;
825 src.visrect.bottom = src.y + cy;
826 rect.left = 0;
827 rect.top = 0;
828 rect.right = src_info->bmiHeader.biWidth;
829 rect.bottom = abs( src_info->bmiHeader.biHeight );
830 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
832 lines = 0;
833 goto done;
836 pt.x = x_dst;
837 pt.y = y_dst;
838 LPtoDP( dev->hdc, &pt, 1 );
839 dst.x = pt.x;
840 dst.y = pt.y;
841 dst.width = cx;
842 dst.height = cy;
843 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
845 rect.left = dst.x;
846 rect.top = dst.y;
847 rect.right = dst.x + cx;
848 rect.bottom = dst.y + cy;
849 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
851 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
852 intersect_rect( &rect, &src.visrect, &dst.visrect );
853 src.visrect = dst.visrect = rect;
854 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
855 if (is_rect_empty( &dst.visrect )) goto done;
856 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
858 dev = GET_DC_PHYSDEV( dc, pPutImage );
859 copy_bitmapinfo( dst_info, src_info );
860 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
861 if (err == ERROR_BAD_FORMAT)
863 err = convert_bits( src_info, &src, dst_info, &src_bits );
864 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
866 if (err) lines = 0;
868 done:
869 if (src_bits.free) src_bits.free( &src_bits );
870 if (clip) DeleteObject( clip );
871 return lines;
874 /***********************************************************************
875 * SetDIBitsToDevice (GDI32.@)
877 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
878 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
879 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
880 UINT coloruse )
882 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
883 BITMAPINFO *info = (BITMAPINFO *)buffer;
884 PHYSDEV physdev;
885 INT ret = 0;
886 DC *dc;
888 if (!bits) return 0;
889 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
891 SetLastError( ERROR_INVALID_PARAMETER );
892 return 0;
895 if ((dc = get_dc_ptr( hdc )))
897 update_dc( dc );
898 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
899 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
900 ySrc, startscan, lines, bits, info, coloruse );
901 release_dc_ptr( dc );
903 return ret;
906 /***********************************************************************
907 * SetDIBColorTable (GDI32.@)
909 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
911 DC * dc;
912 UINT result = 0;
913 BITMAPOBJ * bitmap;
915 if (!(dc = get_dc_ptr( hdc ))) return 0;
917 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
919 if (startpos < bitmap->dib.dsBmih.biClrUsed)
921 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
922 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
924 GDI_ReleaseObj( dc->hBitmap );
926 if (result) /* update colors of selected objects */
928 SetTextColor( hdc, dc->textColor );
929 SetBkColor( hdc, dc->backgroundColor );
930 SelectObject( hdc, dc->hPen );
931 SelectObject( hdc, dc->hBrush );
934 release_dc_ptr( dc );
935 return result;
939 /***********************************************************************
940 * GetDIBColorTable (GDI32.@)
942 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
944 DC * dc;
945 BITMAPOBJ *bitmap;
946 UINT result = 0;
948 if (!(dc = get_dc_ptr( hdc ))) return 0;
950 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
952 if (startpos < bitmap->dib.dsBmih.biClrUsed)
954 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
955 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
957 GDI_ReleaseObj( dc->hBitmap );
959 release_dc_ptr( dc );
960 return result;
963 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
964 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
966 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
968 BITMAPINFOHEADER header;
970 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
971 header.biWidth = bmp->dib.dsBm.bmWidth;
972 header.biHeight = bmp->dib.dsBm.bmHeight;
973 header.biPlanes = 1;
974 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
976 switch (header.biBitCount)
978 case 16:
979 case 32:
980 header.biCompression = BI_BITFIELDS;
981 break;
982 default:
983 header.biCompression = BI_RGB;
984 break;
987 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
988 header.biXPelsPerMeter = 0;
989 header.biYPelsPerMeter = 0;
990 header.biClrUsed = 0;
991 header.biClrImportant = 0;
993 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
995 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
997 coreheader->bcWidth = header.biWidth;
998 coreheader->bcHeight = header.biHeight;
999 coreheader->bcPlanes = header.biPlanes;
1000 coreheader->bcBitCount = header.biBitCount;
1002 else
1003 info->bmiHeader = header;
1005 return bmp->dib.dsBm.bmHeight;
1008 /************************************************************************
1009 * copy_color_info
1011 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1013 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1015 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1017 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1019 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1020 if (coloruse == DIB_PAL_COLORS)
1021 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1022 else
1024 unsigned int i;
1025 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1027 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1028 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1029 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1033 else
1035 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1036 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1038 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1039 /* bitfields are always at bmiColors even in larger structures */
1040 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1041 else if (src->bmiHeader.biClrUsed)
1043 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1044 unsigned int size;
1046 if (coloruse == DIB_PAL_COLORS)
1047 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1048 else
1049 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1050 memcpy( colorptr, src->bmiColors, size );
1055 const RGBQUAD *get_default_color_table( int bpp )
1057 static const RGBQUAD table_1[2] =
1059 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1061 static const RGBQUAD table_4[16] =
1063 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1064 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1065 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1066 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1068 static const RGBQUAD table_8[256] =
1070 /* first and last 10 entries are the default system palette entries */
1071 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1072 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1073 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1074 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1075 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1076 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1077 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1078 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1079 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1080 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1081 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1082 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1083 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1084 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1085 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1086 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1087 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1088 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1089 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1090 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1091 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1092 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1093 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1094 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1095 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1096 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1097 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1098 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1099 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1100 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1101 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1102 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1103 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1104 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1105 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1106 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1107 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1108 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1109 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1110 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1111 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1112 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1113 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1114 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1115 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1116 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1117 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1118 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1119 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1120 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1121 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1122 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1123 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1124 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1125 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1126 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1127 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1128 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1129 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1130 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1131 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1132 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1133 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1134 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1137 switch (bpp)
1139 case 1: return table_1;
1140 case 4: return table_4;
1141 case 8: return table_8;
1142 default: return NULL;
1146 void fill_default_color_table( BITMAPINFO *info )
1148 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1149 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1150 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1153 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1155 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1156 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1157 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1158 info->bmiHeader.biPlanes = 1;
1159 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1160 info->bmiHeader.biCompression = BI_RGB;
1161 info->bmiHeader.biXPelsPerMeter = 0;
1162 info->bmiHeader.biYPelsPerMeter = 0;
1163 info->bmiHeader.biClrUsed = 0;
1164 info->bmiHeader.biClrImportant = 0;
1167 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1169 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1170 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1171 unsigned int info_size;
1173 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1175 info_size = get_dib_info_size( info, usage );
1176 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1178 memcpy( ret, info, info_size );
1179 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1180 info->bmiHeader.biSizeImage );
1182 return ret;
1185 /******************************************************************************
1186 * GetDIBits [GDI32.@]
1188 * Retrieves bits of bitmap and copies to buffer.
1190 * RETURNS
1191 * Success: Number of scan lines copied from bitmap
1192 * Failure: 0
1194 INT WINAPI GetDIBits(
1195 HDC hdc, /* [in] Handle to device context */
1196 HBITMAP hbitmap, /* [in] Handle to bitmap */
1197 UINT startscan, /* [in] First scan line to set in dest bitmap */
1198 UINT lines, /* [in] Number of scan lines to copy */
1199 LPVOID bits, /* [out] Address of array for bitmap bits */
1200 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1201 UINT coloruse) /* [in] RGB or palette index */
1203 DC * dc;
1204 BITMAPOBJ * bmp;
1205 int i, dst_to_src_offset, ret = 0;
1206 DWORD err;
1207 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1208 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1209 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1210 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
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;
1219 if (bits &&
1220 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1221 return 0;
1222 dst_info->bmiHeader.biClrUsed = 0;
1223 dst_info->bmiHeader.biClrImportant = 0;
1225 if (!(dc = get_dc_ptr( hdc )))
1227 SetLastError( ERROR_INVALID_PARAMETER );
1228 return 0;
1230 update_dc( dc );
1231 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1233 release_dc_ptr( dc );
1234 return 0;
1237 src.visrect.left = 0;
1238 src.visrect.top = 0;
1239 src.visrect.right = bmp->dib.dsBm.bmWidth;
1240 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1242 dst.visrect.left = 0;
1243 dst.visrect.top = 0;
1244 dst.visrect.right = dst_info->bmiHeader.biWidth;
1245 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1247 if (lines == 0 || startscan >= dst.visrect.bottom)
1248 bits = NULL;
1250 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1252 ret = fill_query_info( info, bmp );
1253 goto done;
1256 /* validate parameters */
1258 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1259 if (dst_info->bmiHeader.biHeight == 0) goto done;
1261 switch (dst_info->bmiHeader.biCompression)
1263 case BI_RLE4:
1264 if (dst_info->bmiHeader.biBitCount != 4) 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_RLE8:
1269 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1270 if (dst_info->bmiHeader.biHeight < 0) goto done;
1271 if (bits) goto done; /* can't retrieve compressed bits */
1272 break;
1273 case BI_BITFIELDS:
1274 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1275 /* fall through */
1276 case BI_RGB:
1277 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1278 if (dst_info->bmiHeader.biBitCount == 1) break;
1279 if (dst_info->bmiHeader.biBitCount == 4) break;
1280 if (dst_info->bmiHeader.biBitCount == 8) break;
1281 if (dst_info->bmiHeader.biBitCount == 16) break;
1282 if (dst_info->bmiHeader.biBitCount == 24) break;
1283 if (dst_info->bmiHeader.biBitCount == 32) break;
1284 /* fall through */
1285 default:
1286 goto done;
1289 if (bits)
1291 if (dst_info->bmiHeader.biHeight > 0)
1293 dst_to_src_offset = -startscan;
1294 lines = min( lines, dst.visrect.bottom - startscan );
1295 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1297 else
1299 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1300 if (dst_to_src_offset < 0)
1302 dst_to_src_offset = 0;
1303 lines = dst.visrect.bottom - startscan;
1305 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1308 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1309 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1310 dst.visrect = src.visrect;
1311 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1313 if (dst_info->bmiHeader.biHeight > 0)
1315 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1317 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1318 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1319 memset( bits, 0, pad_bytes );
1320 bits = (char *)bits + pad_bytes;
1323 else
1325 if (dst.visrect.bottom < lines)
1327 int pad_lines = lines - dst.visrect.bottom;
1328 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1329 int pad_bytes = pad_lines * stride;
1330 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1334 if (empty_rect) bits = NULL;
1336 src.x = src.visrect.left;
1337 src.y = src.visrect.top;
1338 src.width = src.visrect.right - src.visrect.left;
1339 src.height = src.visrect.bottom - src.visrect.top;
1341 lines = src.height;
1344 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1346 if (err) goto done;
1348 /* fill out the src colour table, if it needs one */
1349 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1350 fill_default_color_table( src_info );
1352 /* if the src and dst are the same depth, copy the colour info across */
1353 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1355 switch (src_info->bmiHeader.biBitCount)
1357 case 16:
1358 if (src_info->bmiHeader.biCompression == BI_RGB)
1360 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1361 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1363 break;
1364 case 32:
1365 if (src_info->bmiHeader.biCompression == BI_RGB)
1367 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1368 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1370 break;
1372 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1373 copy_color_info( dst_info, src_info, coloruse );
1375 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1377 if( coloruse == DIB_PAL_COLORS )
1379 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1381 else
1383 fill_default_color_table( dst_info );
1387 if (bits)
1389 if(dst_info->bmiHeader.biHeight > 0)
1390 dst_info->bmiHeader.biHeight = src.height;
1391 else
1392 dst_info->bmiHeader.biHeight = -src.height;
1394 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1395 if (src_bits.free) src_bits.free( &src_bits );
1396 ret = lines;
1398 else
1399 ret = !empty_rect;
1401 if (coloruse == DIB_PAL_COLORS)
1403 WORD *index = (WORD *)dst_info->bmiColors;
1404 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1405 *index = i;
1408 copy_color_info( info, dst_info, coloruse );
1409 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1411 done:
1412 release_dc_ptr( dc );
1413 GDI_ReleaseObj( hbitmap );
1414 return ret;
1418 /***********************************************************************
1419 * CreateDIBitmap (GDI32.@)
1421 * Creates a DDB (device dependent bitmap) from a DIB.
1422 * The DDB will have the same color depth as the reference DC.
1424 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1425 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1426 UINT coloruse )
1428 BITMAPINFOHEADER info;
1429 HBITMAP handle;
1430 LONG height;
1432 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1433 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1434 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1435 if (info.biWidth < 0) return 0;
1437 /* Top-down DIBs have a negative height */
1438 height = abs( info.biHeight );
1440 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1441 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1442 info.biBitCount, info.biCompression);
1444 if (hdc == NULL)
1445 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1446 else
1447 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1449 if (handle)
1451 if (init & CBM_INIT)
1453 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1455 DeleteObject( handle );
1456 handle = 0;
1461 return handle;
1465 /***********************************************************************
1466 * CreateDIBSection (GDI32.@)
1468 HBITMAP WINAPI CreateDIBSection(HDC hdc, const BITMAPINFO *bmi, UINT usage,
1469 VOID **bits, HANDLE section, DWORD offset)
1471 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1472 BITMAPINFO *info = (BITMAPINFO *)buffer;
1473 HBITMAP ret = 0;
1474 BITMAPOBJ *bmp;
1475 void *mapBits = NULL;
1477 if (bits) *bits = NULL;
1478 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1479 if (usage > DIB_PAL_COLORS) return 0;
1480 if (info->bmiHeader.biPlanes != 1)
1482 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1483 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1486 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1488 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1489 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1490 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1491 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1492 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1494 bmp->dib.dsBm.bmType = 0;
1495 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1496 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1497 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1498 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1499 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1500 bmp->dib.dsBmih = info->bmiHeader;
1502 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1504 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1505 goto error;
1506 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1507 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1508 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1509 goto error;
1510 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1513 /* set dsBitfields values */
1514 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1516 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1517 bmp->dib.dsBitfields[0] = 0x7c00;
1518 bmp->dib.dsBitfields[1] = 0x03e0;
1519 bmp->dib.dsBitfields[2] = 0x001f;
1521 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1523 if (usage == DIB_PAL_COLORS) goto error;
1524 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1525 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1526 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1527 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1529 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1531 /* get storage location for DIB bits */
1533 if (section)
1535 SYSTEM_INFO SystemInfo;
1536 DWORD mapOffset;
1537 INT mapSize;
1539 GetSystemInfo( &SystemInfo );
1540 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1541 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1542 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1543 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1545 else
1547 offset = 0;
1548 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1549 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1551 bmp->dib.dshSection = section;
1552 bmp->dib.dsOffset = offset;
1554 if (!bmp->dib.dsBm.bmBits) goto error;
1556 if (!(ret = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1558 if (bits) *bits = bmp->dib.dsBm.bmBits;
1559 return ret;
1561 error:
1562 if (section) UnmapViewOfFile( mapBits );
1563 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1564 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1565 HeapFree( GetProcessHeap(), 0, bmp );
1566 return 0;
1570 /***********************************************************************
1571 * DIB_SelectObject
1573 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc )
1575 HGDIOBJ ret;
1576 BITMAPOBJ *bitmap;
1577 DC *dc;
1578 PHYSDEV physdev;
1580 if (!(dc = get_dc_ptr( hdc ))) return 0;
1582 if (GetObjectType( hdc ) != OBJ_MEMDC)
1584 ret = 0;
1585 goto done;
1587 ret = dc->hBitmap;
1588 if (handle == dc->hBitmap) goto done; /* nothing to do */
1590 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
1592 ret = 0;
1593 goto done;
1596 if (GDI_get_ref_count( handle ))
1598 WARN( "Bitmap already selected in another DC\n" );
1599 GDI_ReleaseObj( handle );
1600 ret = 0;
1601 goto done;
1604 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
1605 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
1607 GDI_ReleaseObj( handle );
1608 ret = 0;
1610 else
1612 dc->hBitmap = handle;
1613 GDI_inc_ref_count( handle );
1614 dc->dirty = 0;
1615 dc->vis_rect.left = 0;
1616 dc->vis_rect.top = 0;
1617 dc->vis_rect.right = bitmap->dib.dsBm.bmWidth;
1618 dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
1619 dc->device_rect = dc->vis_rect;
1620 GDI_ReleaseObj( handle );
1621 DC_InitDC( dc );
1622 GDI_dec_ref_count( ret );
1625 done:
1626 release_dc_ptr( dc );
1627 return ret;
1631 /***********************************************************************
1632 * DIB_GetObject
1634 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1636 INT ret = 0;
1637 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1639 if (!bmp) return 0;
1641 if (!buffer) ret = sizeof(BITMAP);
1642 else if (count >= sizeof(DIBSECTION))
1644 DIBSECTION *dib = buffer;
1645 *dib = bmp->dib;
1646 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1647 ret = sizeof(DIBSECTION);
1649 else if (count >= sizeof(BITMAP))
1651 BITMAP *bitmap = buffer;
1652 *bitmap = bmp->dib.dsBm;
1653 ret = sizeof(BITMAP);
1656 GDI_ReleaseObj( handle );
1657 return ret;
1661 /***********************************************************************
1662 * DIB_DeleteObject
1664 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1666 BITMAPOBJ *bmp;
1668 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1670 if (bmp->dib.dshSection)
1672 SYSTEM_INFO SystemInfo;
1673 GetSystemInfo( &SystemInfo );
1674 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1675 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1677 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1679 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1680 return HeapFree( GetProcessHeap(), 0, bmp );