explorer: Don't worry about desktop launchers in non-desktop mode.
[wine/multimedia.git] / dlls / gdi32 / dib.c
blobad2a4dc6b23f89a66debb35c49857d5168979971
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 switch (info->biBitCount)
133 case 1:
134 case 4:
135 case 8:
136 case 24:
137 return (info->biCompression == BI_RGB);
138 case 16:
139 case 32:
140 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
141 default:
142 return FALSE;
146 /*******************************************************************************************
147 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
149 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
151 if (!info) return FALSE;
153 if (info->biSize == sizeof(BITMAPCOREHEADER))
155 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
156 dst->biWidth = core->bcWidth;
157 dst->biHeight = core->bcHeight;
158 dst->biPlanes = core->bcPlanes;
159 dst->biBitCount = core->bcBitCount;
160 dst->biCompression = BI_RGB;
161 dst->biXPelsPerMeter = 0;
162 dst->biYPelsPerMeter = 0;
163 dst->biClrUsed = 0;
164 dst->biClrImportant = 0;
166 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
168 *dst = *info;
170 else
172 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
173 return FALSE;
176 dst->biSize = sizeof(*dst);
177 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
178 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
179 return TRUE;
182 /*******************************************************************************************
183 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
185 * The resulting sanitized BITMAPINFO is guaranteed to have:
186 * - biSize set to sizeof(BITMAPINFOHEADER)
187 * - biSizeImage set to the actual image size even for non-compressed DIB
188 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
189 * - color table present only for <= 8 bpp, always starts at info->bmiColors
191 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
192 UINT coloruse, BOOL allow_compression )
194 void *src_colors;
196 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
197 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
198 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
200 src_colors = (char *)info + info->bmiHeader.biSize;
202 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
204 /* bitfields are always at bmiColors even in larger structures */
205 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
206 dst->bmiHeader.biClrUsed = 0;
208 else if (dst->bmiHeader.biBitCount <= 8)
210 unsigned int colors = dst->bmiHeader.biClrUsed;
211 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
213 if (!colors) colors = max_colors;
214 else colors = min( colors, max_colors );
216 if (coloruse == DIB_PAL_COLORS)
218 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
219 max_colors = colors;
221 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
223 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
225 else
227 unsigned int i;
228 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
229 for (i = 0; i < colors; i++)
231 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
232 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
233 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
234 dst->bmiColors[i].rgbReserved = 0;
237 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
238 dst->bmiHeader.biClrUsed = max_colors;
240 else dst->bmiHeader.biClrUsed = 0;
242 return TRUE;
245 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
247 PALETTEENTRY palEntry[256];
248 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
249 int i, colors = 1 << info->bmiHeader.biBitCount;
251 info->bmiHeader.biClrUsed = colors;
253 if (!palette) return 0;
255 memset( palEntry, 0, sizeof(palEntry) );
256 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
257 return 0;
259 for (i = 0; i < colors; i++)
261 info->bmiColors[i].rgbRed = palEntry[i].peRed;
262 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
263 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
264 info->bmiColors[i].rgbReserved = 0;
267 return colors;
270 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
272 PALETTEENTRY entries[256];
273 RGBQUAD table[256];
274 HPALETTE palette;
275 const WORD *index = (const WORD *)info->bmiColors;
276 int i, count, colors = info->bmiHeader.biClrUsed;
278 if (!colors) return TRUE;
279 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
280 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
282 for (i = 0; i < colors; i++, index++)
284 table[i].rgbRed = entries[*index % count].peRed;
285 table[i].rgbGreen = entries[*index % count].peGreen;
286 table[i].rgbBlue = entries[*index % count].peBlue;
287 table[i].rgbReserved = 0;
289 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
290 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
291 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
292 return TRUE;
295 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
297 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
298 const int bpp = info->bmiHeader.biBitCount;
300 if (height > 0)
301 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
302 else
303 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
306 static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
308 DWORD i = 0;
309 int left, right;
310 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
311 HRGN run = NULL;
312 BYTE skip, num, data;
313 BYTE *out_bits, *in_bits = bits->ptr;
315 if (clip) *clip = NULL;
317 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
319 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
320 if (!out_bits) goto fail;
322 if (clip)
324 *clip = CreateRectRgn( 0, 0, 0, 0 );
325 run = CreateRectRgn( 0, 0, 0, 0 );
326 if (!*clip || !run) goto fail;
329 x = left = right = 0;
330 y = height - 1;
332 while (i < info->bmiHeader.biSizeImage - 1)
334 num = in_bits[i];
335 data = in_bits[i + 1];
336 i += 2;
338 if (num)
340 if (x + num > width) num = width - x;
341 if (num)
343 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
344 if (info->bmiHeader.biBitCount == 8)
345 memset( out_ptr, s, num );
346 else
348 if(x & 1)
350 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
351 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
352 out_ptr++;
353 x++;
354 num--;
356 /* this will write one too many if num is odd, but that doesn't matter */
357 if (num) memset( out_ptr, s, (num + 1) / 2 );
360 x += num;
361 right = x;
363 else
365 if (data < 3)
367 if(left != right && clip)
369 SetRectRgn( run, left, y, right, y + 1 );
370 CombineRgn( *clip, run, *clip, RGN_OR );
372 switch (data)
374 case 0: /* eol */
375 left = right = x = 0;
376 y--;
377 if(y < 0) goto done;
378 break;
380 case 1: /* eod */
381 goto done;
383 case 2: /* delta */
384 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
385 x += in_bits[i];
386 if (x > width) x = width;
387 left = right = x;
388 y -= in_bits[i + 1];
389 if(y < 0) goto done;
390 i += 2;
393 else /* data bytes of data */
395 num = data;
396 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
397 if (skip > info->bmiHeader.biSizeImage - i) goto done;
398 skip = (skip + 1) & ~1;
399 if (x + num > width) num = width - x;
400 if (num)
402 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
403 if (info->bmiHeader.biBitCount == 8)
404 memcpy( out_ptr, in_bits + i, num );
405 else
407 if(x & 1)
409 const BYTE *in_ptr = in_bits + i;
410 for ( ; num; num--, x++)
412 if (x & 1)
414 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
415 out_ptr++;
417 else
418 *out_ptr = (*in_ptr++ << 4) & 0xf0;
421 else
422 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
425 x += num;
426 right = x;
427 i += skip;
432 done:
433 if (run) DeleteObject( run );
434 if (bits->free) bits->free( bits );
436 bits->ptr = out_bits;
437 bits->is_copy = TRUE;
438 bits->free = free_heap_bits;
440 return TRUE;
442 fail:
443 if (run) DeleteObject( run );
444 if (clip && *clip) DeleteObject( *clip );
445 HeapFree( GetProcessHeap(), 0, out_bits );
446 return FALSE;
451 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
452 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
453 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
455 DC *dc = get_nulldrv_dc( dev );
456 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
457 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
458 struct bitblt_coords src, dst;
459 struct gdi_image_bits src_bits;
460 DWORD err;
461 HRGN clip = NULL;
462 INT ret = 0;
463 INT height = abs( src_info->bmiHeader.biHeight );
464 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
465 RECT rect;
467 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
468 xSrc, ySrc, widthSrc, heightSrc, rop);
470 src_bits.ptr = (void*)bits;
471 src_bits.is_copy = FALSE;
472 src_bits.free = NULL;
474 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
476 rect.left = xDst;
477 rect.top = yDst;
478 rect.right = xDst + widthDst;
479 rect.bottom = yDst + heightDst;
480 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
481 dst.x = rect.left;
482 dst.y = rect.top;
483 dst.width = rect.right - rect.left;
484 dst.height = rect.bottom - rect.top;
486 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
488 dst.x += dst.width;
489 dst.width = -dst.width;
491 rop &= ~NOMIRRORBITMAP;
493 src.x = xSrc;
494 src.width = widthSrc;
495 src.y = ySrc;
496 src.height = heightSrc;
498 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
499 non_stretch_from_origin = TRUE;
501 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
503 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
504 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
507 if (rop != SRCCOPY || non_stretch_from_origin)
509 if (dst.width == 1 && src.width > 1) src.width--;
510 if (dst.height == 1 && src.height > 1) src.height--;
513 if (rop != SRCCOPY)
515 if (dst.width < 0 && dst.width == src.width)
517 /* This is off-by-one, but that's what Windows does */
518 dst.x += dst.width;
519 src.x += src.width;
520 dst.width = -dst.width;
521 src.width = -src.width;
523 if (dst.height < 0 && dst.height == src.height)
525 dst.y += dst.height;
526 src.y += src.height;
527 dst.height = -dst.height;
528 src.height = -src.height;
532 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
534 if (src.y >= height && src.y + src.height + 1 < height)
535 src.y = height - 1;
536 else if (src.y > 0 && src.y + src.height + 1 < 0)
537 src.y = -src.height - 1;
539 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
541 src.visrect.left = 0;
542 src.visrect.right = src_info->bmiHeader.biWidth;
543 src.visrect.top = 0;
544 src.visrect.bottom = height;
545 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
547 if (rop == SRCCOPY) ret = height;
548 else ret = src_info->bmiHeader.biHeight;
550 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
552 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
554 if (!intersect_vis_rectangles( &dst, &src )) goto done;
556 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
558 dev = GET_DC_PHYSDEV( dc, pPutImage );
559 copy_bitmapinfo( dst_info, src_info );
560 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
561 if (err == ERROR_BAD_FORMAT)
563 /* 1-bpp destination without a color table requires a fake 1-entry table
564 * that contains only the background color */
565 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
567 COLORREF color = GetBkColor( dev->hdc );
568 dst_info->bmiColors[0].rgbRed = GetRValue( color );
569 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
570 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
571 dst_info->bmiColors[0].rgbReserved = 0;
572 dst_info->bmiHeader.biClrUsed = 1;
575 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
577 /* get rid of the fake 1-bpp table */
578 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
579 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
583 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
585 copy_bitmapinfo( src_info, dst_info );
586 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
587 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
589 if (err) ret = 0;
591 done:
592 if (src_bits.free) src_bits.free( &src_bits );
593 if (clip) DeleteObject( clip );
594 return ret;
597 /***********************************************************************
598 * StretchDIBits (GDI32.@)
600 INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
601 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
602 const BITMAPINFO *bmi, UINT coloruse, DWORD rop )
604 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
605 BITMAPINFO *info = (BITMAPINFO *)buffer;
606 PHYSDEV physdev;
607 DC *dc;
608 INT ret = 0;
610 if (!bits) return 0;
611 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
613 SetLastError( ERROR_INVALID_PARAMETER );
614 return 0;
617 if ((dc = get_dc_ptr( hdc )))
619 update_dc( dc );
620 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
621 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
622 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
623 release_dc_ptr( dc );
625 return ret;
629 /******************************************************************************
630 * SetDIBits [GDI32.@]
632 * Sets pixels in a bitmap using colors from DIB.
634 * PARAMS
635 * hdc [I] Handle to device context
636 * hbitmap [I] Handle to bitmap
637 * startscan [I] Starting scan line
638 * lines [I] Number of scan lines
639 * bits [I] Array of bitmap bits
640 * info [I] Address of structure with data
641 * coloruse [I] Type of color indexes to use
643 * RETURNS
644 * Success: Number of scan lines copied
645 * Failure: 0
647 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
648 UINT lines, LPCVOID bits, const BITMAPINFO *info,
649 UINT coloruse )
651 BITMAPOBJ *bitmap;
652 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
653 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
654 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
655 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
656 INT result = 0;
657 DWORD err;
658 struct gdi_image_bits src_bits;
659 struct bitblt_coords src, dst;
660 INT src_to_dst_offset;
661 HRGN clip = 0;
663 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
665 SetLastError( ERROR_INVALID_PARAMETER );
666 return 0;
668 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
670 DWORD *masks = (DWORD *)src_info->bmiColors;
671 if (!masks[0] || !masks[1] || !masks[2])
673 SetLastError( ERROR_INVALID_PARAMETER );
674 return 0;
678 src_bits.ptr = (void *)bits;
679 src_bits.is_copy = FALSE;
680 src_bits.free = NULL;
681 src_bits.param = NULL;
683 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
685 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
687 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
689 if (lines == 0) goto done;
690 else lines = src_info->bmiHeader.biHeight;
691 startscan = 0;
693 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
696 dst.visrect.left = 0;
697 dst.visrect.top = 0;
698 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
699 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
701 src.visrect.left = 0;
702 src.visrect.top = 0;
703 src.visrect.right = src_info->bmiHeader.biWidth;
704 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
706 if (src_info->bmiHeader.biHeight > 0)
708 src_to_dst_offset = -startscan;
709 lines = min( lines, src.visrect.bottom - startscan );
710 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
712 else
714 src_to_dst_offset = src.visrect.bottom - lines - startscan;
715 /* Unlike the bottom-up case, Windows doesn't limit lines. */
716 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
719 result = lines;
721 offset_rect( &src.visrect, 0, src_to_dst_offset );
722 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
723 src.visrect = dst.visrect;
724 offset_rect( &src.visrect, 0, -src_to_dst_offset );
726 src.x = src.visrect.left;
727 src.y = src.visrect.top;
728 src.width = src.visrect.right - src.visrect.left;
729 src.height = src.visrect.bottom - src.visrect.top;
731 dst.x = dst.visrect.left;
732 dst.y = dst.visrect.top;
733 dst.width = dst.visrect.right - dst.visrect.left;
734 dst.height = dst.visrect.bottom - dst.visrect.top;
736 copy_bitmapinfo( dst_info, src_info );
738 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
739 if (err == ERROR_BAD_FORMAT)
741 err = convert_bits( src_info, &src, dst_info, &src_bits );
742 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
744 if(err) result = 0;
746 done:
747 if (src_bits.free) src_bits.free( &src_bits );
748 if (clip) DeleteObject( clip );
749 GDI_ReleaseObj( hbitmap );
750 return result;
754 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
755 INT x_src, INT y_src, UINT startscan, UINT lines,
756 const void *bits, BITMAPINFO *src_info, UINT coloruse )
758 DC *dc = get_nulldrv_dc( dev );
759 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
760 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
761 struct bitblt_coords src, dst;
762 struct gdi_image_bits src_bits;
763 HRGN clip = 0;
764 DWORD err;
765 UINT height;
766 BOOL top_down;
767 POINT pt;
768 RECT rect;
770 top_down = (src_info->bmiHeader.biHeight < 0);
771 height = abs( src_info->bmiHeader.biHeight );
773 src_bits.ptr = (void *)bits;
774 src_bits.is_copy = FALSE;
775 src_bits.free = NULL;
777 if (!lines) return 0;
778 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
780 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
782 startscan = 0;
783 lines = height;
784 src_info->bmiHeader.biWidth = x_src + cx;
785 src_info->bmiHeader.biHeight = y_src + cy;
786 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
787 src.x = x_src;
788 src.y = 0;
789 src.width = cx;
790 src.height = cy;
791 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
793 else
795 if (startscan >= height) return 0;
796 if (!top_down && lines > height - startscan) lines = height - startscan;
798 /* map src to top-down coordinates with startscan as origin */
799 src.x = x_src;
800 src.y = startscan + lines - (y_src + cy);
801 src.width = cx;
802 src.height = cy;
803 if (src.y > 0)
805 if (!top_down)
807 /* get rid of unnecessary lines */
808 if (src.y >= lines) return 0;
809 lines -= src.y;
810 src.y = 0;
812 else if (src.y >= lines) return lines;
814 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
817 src.visrect.left = src.x;
818 src.visrect.top = src.y;
819 src.visrect.right = src.x + cx;
820 src.visrect.bottom = src.y + cy;
821 rect.left = 0;
822 rect.top = 0;
823 rect.right = src_info->bmiHeader.biWidth;
824 rect.bottom = abs( src_info->bmiHeader.biHeight );
825 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
827 lines = 0;
828 goto done;
831 pt.x = x_dst;
832 pt.y = y_dst;
833 LPtoDP( dev->hdc, &pt, 1 );
834 dst.x = pt.x;
835 dst.y = pt.y;
836 dst.width = cx;
837 dst.height = cy;
838 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
840 rect.left = dst.x;
841 rect.top = dst.y;
842 rect.right = dst.x + cx;
843 rect.bottom = dst.y + cy;
844 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
846 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
847 intersect_rect( &rect, &src.visrect, &dst.visrect );
848 src.visrect = dst.visrect = rect;
849 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
850 if (is_rect_empty( &dst.visrect )) goto done;
851 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
853 dev = GET_DC_PHYSDEV( dc, pPutImage );
854 copy_bitmapinfo( dst_info, src_info );
855 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
856 if (err == ERROR_BAD_FORMAT)
858 err = convert_bits( src_info, &src, dst_info, &src_bits );
859 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
861 if (err) lines = 0;
863 done:
864 if (src_bits.free) src_bits.free( &src_bits );
865 if (clip) DeleteObject( clip );
866 return lines;
869 /***********************************************************************
870 * SetDIBitsToDevice (GDI32.@)
872 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
873 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
874 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
875 UINT coloruse )
877 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
878 BITMAPINFO *info = (BITMAPINFO *)buffer;
879 PHYSDEV physdev;
880 INT ret = 0;
881 DC *dc;
883 if (!bits) return 0;
884 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
886 SetLastError( ERROR_INVALID_PARAMETER );
887 return 0;
890 if ((dc = get_dc_ptr( hdc )))
892 update_dc( dc );
893 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
894 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
895 ySrc, startscan, lines, bits, info, coloruse );
896 release_dc_ptr( dc );
898 return ret;
901 /***********************************************************************
902 * SetDIBColorTable (GDI32.@)
904 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, CONST RGBQUAD *colors )
906 DC * dc;
907 UINT result = 0;
908 BITMAPOBJ * bitmap;
910 if (!(dc = get_dc_ptr( hdc ))) return 0;
912 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
914 if (startpos < bitmap->dib.dsBmih.biClrUsed)
916 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
917 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
919 GDI_ReleaseObj( dc->hBitmap );
921 if (result) /* update colors of selected objects */
923 SetTextColor( hdc, dc->textColor );
924 SetBkColor( hdc, dc->backgroundColor );
925 SelectObject( hdc, dc->hPen );
926 SelectObject( hdc, dc->hBrush );
929 release_dc_ptr( dc );
930 return result;
934 /***********************************************************************
935 * GetDIBColorTable (GDI32.@)
937 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
939 DC * dc;
940 BITMAPOBJ *bitmap;
941 UINT result = 0;
943 if (!(dc = get_dc_ptr( hdc ))) return 0;
945 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
947 if (startpos < bitmap->dib.dsBmih.biClrUsed)
949 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
950 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
952 GDI_ReleaseObj( dc->hBitmap );
954 release_dc_ptr( dc );
955 return result;
958 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
959 static const DWORD bit_fields_565[3] = {0xf800, 0x07e0, 0x001f};
960 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
962 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
964 BITMAPINFOHEADER header;
966 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
967 header.biWidth = bmp->dib.dsBm.bmWidth;
968 header.biHeight = bmp->dib.dsBm.bmHeight;
969 header.biPlanes = 1;
970 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
972 switch (header.biBitCount)
974 case 16:
975 case 32:
976 header.biCompression = BI_BITFIELDS;
977 break;
978 default:
979 header.biCompression = BI_RGB;
980 break;
983 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
984 header.biXPelsPerMeter = 0;
985 header.biYPelsPerMeter = 0;
986 header.biClrUsed = 0;
987 header.biClrImportant = 0;
989 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
991 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
993 coreheader->bcWidth = header.biWidth;
994 coreheader->bcHeight = header.biHeight;
995 coreheader->bcPlanes = header.biPlanes;
996 coreheader->bcBitCount = header.biBitCount;
998 else
999 info->bmiHeader = header;
1001 return bmp->dib.dsBm.bmHeight;
1004 /************************************************************************
1005 * copy_color_info
1007 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1009 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1011 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1013 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1015 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1016 if (coloruse == DIB_PAL_COLORS)
1017 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1018 else
1020 unsigned int i;
1021 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1023 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1024 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1025 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1029 else
1031 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1032 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1034 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1035 /* bitfields are always at bmiColors even in larger structures */
1036 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1037 else if (src->bmiHeader.biClrUsed)
1039 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1040 unsigned int size;
1042 if (coloruse == DIB_PAL_COLORS)
1043 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1044 else
1045 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1046 memcpy( colorptr, src->bmiColors, size );
1051 const RGBQUAD *get_default_color_table( int bpp )
1053 static const RGBQUAD table_1[2] =
1055 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1057 static const RGBQUAD table_4[16] =
1059 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1060 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1061 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1062 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1064 static const RGBQUAD table_8[256] =
1066 /* first and last 10 entries are the default system palette entries */
1067 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1068 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1069 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1070 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1071 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1072 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1073 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1074 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1075 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1076 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1077 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1078 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1079 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1080 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1081 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1082 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1083 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1084 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1085 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1086 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1087 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1088 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1089 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1090 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1091 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1092 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1093 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1094 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1095 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1096 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1097 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1098 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1099 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1100 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1101 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1102 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1103 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1104 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1105 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1106 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1107 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1108 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1109 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1110 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1111 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1112 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1113 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1114 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1115 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1116 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1117 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1118 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1119 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1120 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1121 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1122 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1123 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1124 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1125 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1126 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1127 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1128 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1129 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1130 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1133 switch (bpp)
1135 case 1: return table_1;
1136 case 4: return table_4;
1137 case 8: return table_8;
1138 default: return NULL;
1142 void fill_default_color_table( BITMAPINFO *info )
1144 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1145 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1146 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1149 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1151 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1152 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1153 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1154 info->bmiHeader.biPlanes = 1;
1155 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1156 info->bmiHeader.biCompression = BI_RGB;
1157 info->bmiHeader.biXPelsPerMeter = 0;
1158 info->bmiHeader.biYPelsPerMeter = 0;
1159 info->bmiHeader.biClrUsed = 0;
1160 info->bmiHeader.biClrImportant = 0;
1163 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1165 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1166 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1167 unsigned int info_size;
1169 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1171 info_size = get_dib_info_size( info, usage );
1172 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1174 memcpy( ret, info, info_size );
1175 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1176 info->bmiHeader.biSizeImage );
1178 return ret;
1181 /******************************************************************************
1182 * GetDIBits [GDI32.@]
1184 * Retrieves bits of bitmap and copies to buffer.
1186 * RETURNS
1187 * Success: Number of scan lines copied from bitmap
1188 * Failure: 0
1190 INT WINAPI GetDIBits(
1191 HDC hdc, /* [in] Handle to device context */
1192 HBITMAP hbitmap, /* [in] Handle to bitmap */
1193 UINT startscan, /* [in] First scan line to set in dest bitmap */
1194 UINT lines, /* [in] Number of scan lines to copy */
1195 LPVOID bits, /* [out] Address of array for bitmap bits */
1196 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1197 UINT coloruse) /* [in] RGB or palette index */
1199 DC * dc;
1200 BITMAPOBJ * bmp;
1201 int i, dst_to_src_offset, ret = 0;
1202 DWORD err;
1203 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1204 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1205 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1206 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1207 struct gdi_image_bits src_bits;
1208 struct bitblt_coords src, dst;
1209 BOOL empty_rect = FALSE;
1211 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1212 own copy and transfer the colour info back at the end */
1213 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1214 if (coloruse > DIB_PAL_COLORS) return 0;
1215 if (bits &&
1216 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1217 return 0;
1218 dst_info->bmiHeader.biClrUsed = 0;
1219 dst_info->bmiHeader.biClrImportant = 0;
1221 if (!(dc = get_dc_ptr( hdc )))
1223 SetLastError( ERROR_INVALID_PARAMETER );
1224 return 0;
1226 update_dc( dc );
1227 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1229 release_dc_ptr( dc );
1230 return 0;
1233 src.visrect.left = 0;
1234 src.visrect.top = 0;
1235 src.visrect.right = bmp->dib.dsBm.bmWidth;
1236 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1238 dst.visrect.left = 0;
1239 dst.visrect.top = 0;
1240 dst.visrect.right = dst_info->bmiHeader.biWidth;
1241 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1243 if (lines == 0 || startscan >= dst.visrect.bottom)
1244 bits = NULL;
1246 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1248 ret = fill_query_info( info, bmp );
1249 goto done;
1252 /* validate parameters */
1254 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1255 if (dst_info->bmiHeader.biHeight == 0) goto done;
1257 switch (dst_info->bmiHeader.biCompression)
1259 case BI_RLE4:
1260 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1261 if (dst_info->bmiHeader.biHeight < 0) goto done;
1262 if (bits) goto done; /* can't retrieve compressed bits */
1263 break;
1264 case BI_RLE8:
1265 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1266 if (dst_info->bmiHeader.biHeight < 0) goto done;
1267 if (bits) goto done; /* can't retrieve compressed bits */
1268 break;
1269 case BI_BITFIELDS:
1270 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1271 /* fall through */
1272 case BI_RGB:
1273 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1274 if (dst_info->bmiHeader.biBitCount == 1) break;
1275 if (dst_info->bmiHeader.biBitCount == 4) break;
1276 if (dst_info->bmiHeader.biBitCount == 8) break;
1277 if (dst_info->bmiHeader.biBitCount == 16) break;
1278 if (dst_info->bmiHeader.biBitCount == 24) break;
1279 if (dst_info->bmiHeader.biBitCount == 32) break;
1280 /* fall through */
1281 default:
1282 goto done;
1285 if (bits)
1287 if (dst_info->bmiHeader.biHeight > 0)
1289 dst_to_src_offset = -startscan;
1290 lines = min( lines, dst.visrect.bottom - startscan );
1291 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1293 else
1295 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1296 if (dst_to_src_offset < 0)
1298 dst_to_src_offset = 0;
1299 lines = dst.visrect.bottom - startscan;
1301 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1304 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1305 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1306 dst.visrect = src.visrect;
1307 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1309 if (dst_info->bmiHeader.biHeight > 0)
1311 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1313 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1314 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1315 memset( bits, 0, pad_bytes );
1316 bits = (char *)bits + pad_bytes;
1319 else
1321 if (dst.visrect.bottom < lines)
1323 int pad_lines = lines - dst.visrect.bottom;
1324 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1325 int pad_bytes = pad_lines * stride;
1326 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1330 if (empty_rect) bits = NULL;
1332 src.x = src.visrect.left;
1333 src.y = src.visrect.top;
1334 src.width = src.visrect.right - src.visrect.left;
1335 src.height = src.visrect.bottom - src.visrect.top;
1337 lines = src.height;
1340 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1342 if (err) goto done;
1344 /* fill out the src colour table, if it needs one */
1345 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1346 fill_default_color_table( src_info );
1348 /* if the src and dst are the same depth, copy the colour info across */
1349 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1351 switch (src_info->bmiHeader.biBitCount)
1353 case 16:
1354 if (src_info->bmiHeader.biCompression == BI_RGB)
1356 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1357 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1359 break;
1360 case 32:
1361 if (src_info->bmiHeader.biCompression == BI_RGB)
1363 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1364 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1366 break;
1368 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1369 copy_color_info( dst_info, src_info, coloruse );
1371 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1373 if( coloruse == DIB_PAL_COLORS )
1375 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1377 else
1379 fill_default_color_table( dst_info );
1383 if (bits)
1385 if(dst_info->bmiHeader.biHeight > 0)
1386 dst_info->bmiHeader.biHeight = src.height;
1387 else
1388 dst_info->bmiHeader.biHeight = -src.height;
1390 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1391 if (src_bits.free) src_bits.free( &src_bits );
1392 ret = lines;
1394 else
1395 ret = !empty_rect;
1397 if (coloruse == DIB_PAL_COLORS)
1399 WORD *index = (WORD *)dst_info->bmiColors;
1400 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1401 *index = i;
1404 copy_color_info( info, dst_info, coloruse );
1405 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1407 done:
1408 release_dc_ptr( dc );
1409 GDI_ReleaseObj( hbitmap );
1410 return ret;
1414 /***********************************************************************
1415 * CreateDIBitmap (GDI32.@)
1417 * Creates a DDB (device dependent bitmap) from a DIB.
1418 * The DDB will have the same color depth as the reference DC.
1420 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1421 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1422 UINT coloruse )
1424 BITMAPINFOHEADER info;
1425 HBITMAP handle;
1426 LONG height;
1428 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1429 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1430 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1431 if (info.biWidth < 0) return 0;
1433 /* Top-down DIBs have a negative height */
1434 height = abs( info.biHeight );
1436 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1437 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1438 info.biBitCount, info.biCompression);
1440 if (hdc == NULL)
1441 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1442 else
1443 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1445 if (handle)
1447 if (init & CBM_INIT)
1449 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1451 DeleteObject( handle );
1452 handle = 0;
1457 return handle;
1461 /***********************************************************************
1462 * CreateDIBSection (GDI32.@)
1464 HBITMAP WINAPI CreateDIBSection(HDC hdc, CONST BITMAPINFO *bmi, UINT usage,
1465 VOID **bits, HANDLE section, DWORD offset)
1467 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1468 BITMAPINFO *info = (BITMAPINFO *)buffer;
1469 HBITMAP ret = 0;
1470 BITMAPOBJ *bmp;
1471 void *mapBits = NULL;
1473 if (bits) *bits = NULL;
1474 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1475 if (usage > DIB_PAL_COLORS) return 0;
1476 if (info->bmiHeader.biPlanes != 1)
1478 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1479 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1482 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1484 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1485 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1486 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1487 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1488 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1490 bmp->dib.dsBm.bmType = 0;
1491 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1492 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1493 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1494 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1495 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1496 bmp->dib.dsBmih = info->bmiHeader;
1498 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1500 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1501 goto error;
1502 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1503 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1504 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1505 goto error;
1506 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1509 /* set dsBitfields values */
1510 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1512 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1513 bmp->dib.dsBitfields[0] = 0x7c00;
1514 bmp->dib.dsBitfields[1] = 0x03e0;
1515 bmp->dib.dsBitfields[2] = 0x001f;
1517 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1519 if (usage == DIB_PAL_COLORS) goto error;
1520 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1521 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1522 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1523 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1525 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1527 /* get storage location for DIB bits */
1529 if (section)
1531 SYSTEM_INFO SystemInfo;
1532 DWORD mapOffset;
1533 INT mapSize;
1535 GetSystemInfo( &SystemInfo );
1536 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1537 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1538 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1539 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1541 else
1543 offset = 0;
1544 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1545 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1547 bmp->dib.dshSection = section;
1548 bmp->dib.dsOffset = offset;
1550 if (!bmp->dib.dsBm.bmBits) goto error;
1552 if (!(ret = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1554 if (bits) *bits = bmp->dib.dsBm.bmBits;
1555 return ret;
1557 error:
1558 if (section) UnmapViewOfFile( mapBits );
1559 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1560 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1561 HeapFree( GetProcessHeap(), 0, bmp );
1562 return 0;
1566 /***********************************************************************
1567 * DIB_SelectObject
1569 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc )
1571 HGDIOBJ ret;
1572 BITMAPOBJ *bitmap;
1573 DC *dc;
1574 PHYSDEV physdev;
1576 if (!(dc = get_dc_ptr( hdc ))) return 0;
1578 if (GetObjectType( hdc ) != OBJ_MEMDC)
1580 ret = 0;
1581 goto done;
1583 ret = dc->hBitmap;
1584 if (handle == dc->hBitmap) goto done; /* nothing to do */
1586 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
1588 ret = 0;
1589 goto done;
1592 if (GDI_get_ref_count( handle ))
1594 WARN( "Bitmap already selected in another DC\n" );
1595 GDI_ReleaseObj( handle );
1596 ret = 0;
1597 goto done;
1600 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
1601 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
1603 GDI_ReleaseObj( handle );
1604 ret = 0;
1606 else
1608 dc->hBitmap = handle;
1609 GDI_inc_ref_count( handle );
1610 dc->dirty = 0;
1611 dc->vis_rect.left = 0;
1612 dc->vis_rect.top = 0;
1613 dc->vis_rect.right = bitmap->dib.dsBm.bmWidth;
1614 dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
1615 dc->device_rect = dc->vis_rect;
1616 GDI_ReleaseObj( handle );
1617 DC_InitDC( dc );
1618 GDI_dec_ref_count( ret );
1621 done:
1622 release_dc_ptr( dc );
1623 return ret;
1627 /***********************************************************************
1628 * DIB_GetObject
1630 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1632 INT ret = 0;
1633 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1635 if (!bmp) return 0;
1637 if (!buffer) ret = sizeof(BITMAP);
1638 else if (count >= sizeof(DIBSECTION))
1640 DIBSECTION *dib = buffer;
1641 *dib = bmp->dib;
1642 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1643 ret = sizeof(DIBSECTION);
1645 else if (count >= sizeof(BITMAP))
1647 BITMAP *bitmap = buffer;
1648 *bitmap = bmp->dib.dsBm;
1649 ret = sizeof(BITMAP);
1652 GDI_ReleaseObj( handle );
1653 return ret;
1657 /***********************************************************************
1658 * DIB_DeleteObject
1660 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1662 BITMAPOBJ *bmp;
1664 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1666 if (bmp->dib.dshSection)
1668 SYSTEM_INFO SystemInfo;
1669 GetSystemInfo( &SystemInfo );
1670 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1671 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1673 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1675 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1676 return HeapFree( GetProcessHeap(), 0, bmp );