TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / gdi32 / dib.c
blobcf1ebe4241ffa80bede158ea768ce5fa7c303c7a
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 "config.h"
64 #include <stdarg.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <assert.h>
69 #include "windef.h"
70 #include "winbase.h"
71 #include "gdi_private.h"
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
77 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc );
78 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
79 static BOOL DIB_DeleteObject( HGDIOBJ handle );
81 static const struct gdi_obj_funcs dib_funcs =
83 DIB_SelectObject, /* pSelectObject */
84 DIB_GetObject, /* pGetObjectA */
85 DIB_GetObject, /* pGetObjectW */
86 NULL, /* pUnrealizeObject */
87 DIB_DeleteObject /* pDeleteObject */
90 /***********************************************************************
91 * bitmap_info_size
93 * Return the size of the bitmap info structure including color table.
95 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
97 unsigned int colors, size, masks = 0;
99 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
101 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
102 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
103 return sizeof(BITMAPCOREHEADER) + colors *
104 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
106 else /* assume BITMAPINFOHEADER */
108 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
109 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
110 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
111 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
112 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
116 /*******************************************************************************************
117 * Verify that the DIB parameters are valid.
119 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
121 if (info->biWidth <= 0) return FALSE;
122 if (info->biHeight == 0) return FALSE;
124 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
126 if (info->biHeight < 0) return FALSE;
127 if (!info->biSizeImage) return FALSE;
128 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
131 if (!info->biPlanes) return FALSE;
133 /* check for size overflow */
134 if (!info->biBitCount) return FALSE;
135 if (UINT_MAX / info->biBitCount < info->biWidth) return FALSE;
136 if (UINT_MAX / get_dib_stride( info->biWidth, info->biBitCount ) < abs( info->biHeight )) return FALSE;
138 switch (info->biBitCount)
140 case 1:
141 case 4:
142 case 8:
143 case 24:
144 return (info->biCompression == BI_RGB);
145 case 16:
146 case 32:
147 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
148 default:
149 return FALSE;
153 /*******************************************************************************************
154 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
156 static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
158 if (!info) return FALSE;
160 if (info->biSize == sizeof(BITMAPCOREHEADER))
162 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
163 dst->biWidth = core->bcWidth;
164 dst->biHeight = core->bcHeight;
165 dst->biPlanes = core->bcPlanes;
166 dst->biBitCount = core->bcBitCount;
167 dst->biCompression = BI_RGB;
168 dst->biXPelsPerMeter = 0;
169 dst->biYPelsPerMeter = 0;
170 dst->biClrUsed = 0;
171 dst->biClrImportant = 0;
173 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
175 *dst = *info;
177 else
179 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
180 return FALSE;
183 dst->biSize = sizeof(*dst);
184 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
185 dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
186 return TRUE;
189 /*******************************************************************************************
190 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
192 * The resulting sanitized BITMAPINFO is guaranteed to have:
193 * - biSize set to sizeof(BITMAPINFOHEADER)
194 * - biSizeImage set to the actual image size even for non-compressed DIB
195 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
196 * - color table present only for <= 8 bpp, always starts at info->bmiColors
198 static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info,
199 UINT coloruse, BOOL allow_compression )
201 void *src_colors;
203 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
204 if (!bitmapinfoheader_from_user_bitmapinfo( &dst->bmiHeader, &info->bmiHeader )) return FALSE;
205 if (!is_valid_dib_format( &dst->bmiHeader, allow_compression )) return FALSE;
207 src_colors = (char *)info + info->bmiHeader.biSize;
209 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
211 /* bitfields are always at bmiColors even in larger structures */
212 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
213 dst->bmiHeader.biClrUsed = 0;
215 else if (dst->bmiHeader.biBitCount <= 8)
217 unsigned int colors = dst->bmiHeader.biClrUsed;
218 unsigned int max_colors = 1 << dst->bmiHeader.biBitCount;
220 if (!colors) colors = max_colors;
221 else colors = min( colors, max_colors );
223 if (coloruse == DIB_PAL_COLORS)
225 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
226 max_colors = colors;
228 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
230 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
232 else
234 unsigned int i;
235 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
236 for (i = 0; i < colors; i++)
238 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
239 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
240 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
241 dst->bmiColors[i].rgbReserved = 0;
244 memset( dst->bmiColors + colors, 0, (max_colors - colors) * sizeof(RGBQUAD) );
245 dst->bmiHeader.biClrUsed = max_colors;
247 else dst->bmiHeader.biClrUsed = 0;
249 return TRUE;
252 static int fill_color_table_from_palette( BITMAPINFO *info, HDC hdc )
254 PALETTEENTRY palEntry[256];
255 HPALETTE palette = GetCurrentObject( hdc, OBJ_PAL );
256 int i, colors = 1 << info->bmiHeader.biBitCount;
258 info->bmiHeader.biClrUsed = colors;
260 if (!palette) return 0;
262 memset( palEntry, 0, sizeof(palEntry) );
263 if (!GetPaletteEntries( palette, 0, colors, palEntry ))
264 return 0;
266 for (i = 0; i < colors; i++)
268 info->bmiColors[i].rgbRed = palEntry[i].peRed;
269 info->bmiColors[i].rgbGreen = palEntry[i].peGreen;
270 info->bmiColors[i].rgbBlue = palEntry[i].peBlue;
271 info->bmiColors[i].rgbReserved = 0;
274 return colors;
277 BOOL fill_color_table_from_pal_colors( BITMAPINFO *info, HDC hdc )
279 PALETTEENTRY entries[256];
280 RGBQUAD table[256];
281 HPALETTE palette;
282 const WORD *index = (const WORD *)info->bmiColors;
283 int i, count, colors = info->bmiHeader.biClrUsed;
285 if (!colors) return TRUE;
286 if (!(palette = GetCurrentObject( hdc, OBJ_PAL ))) return FALSE;
287 if (!(count = GetPaletteEntries( palette, 0, colors, entries ))) return FALSE;
289 for (i = 0; i < colors; i++, index++)
291 table[i].rgbRed = entries[*index % count].peRed;
292 table[i].rgbGreen = entries[*index % count].peGreen;
293 table[i].rgbBlue = entries[*index % count].peBlue;
294 table[i].rgbReserved = 0;
296 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
297 memcpy( info->bmiColors, table, colors * sizeof(RGBQUAD) );
298 memset( info->bmiColors + colors, 0, (info->bmiHeader.biClrUsed - colors) * sizeof(RGBQUAD) );
299 return TRUE;
302 static void *get_pixel_ptr( const BITMAPINFO *info, void *bits, int x, int y )
304 const int width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
305 const int bpp = info->bmiHeader.biBitCount;
307 if (height > 0)
308 return (char *)bits + (height - y - 1) * get_dib_stride( width, bpp ) + x * bpp / 8;
309 else
310 return (char *)bits + y * get_dib_stride( width, bpp ) + x * bpp / 8;
313 static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
315 DWORD i = 0;
316 int left, right;
317 int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
318 HRGN run = NULL;
319 BYTE skip, num, data;
320 BYTE *out_bits, *in_bits = bits->ptr;
322 if (clip) *clip = NULL;
324 assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );
326 out_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ) );
327 if (!out_bits) goto fail;
329 if (clip)
331 *clip = CreateRectRgn( 0, 0, 0, 0 );
332 run = CreateRectRgn( 0, 0, 0, 0 );
333 if (!*clip || !run) goto fail;
336 x = left = right = 0;
337 y = height - 1;
339 while (i < info->bmiHeader.biSizeImage - 1)
341 num = in_bits[i];
342 data = in_bits[i + 1];
343 i += 2;
345 if (num)
347 if (x + num > width) num = width - x;
348 if (num)
350 BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
351 if (info->bmiHeader.biBitCount == 8)
352 memset( out_ptr, s, num );
353 else
355 if(x & 1)
357 s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
358 *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
359 out_ptr++;
360 x++;
361 num--;
363 /* this will write one too many if num is odd, but that doesn't matter */
364 if (num) memset( out_ptr, s, (num + 1) / 2 );
367 x += num;
368 right = x;
370 else
372 if (data < 3)
374 if(left != right && clip)
376 SetRectRgn( run, left, y, right, y + 1 );
377 CombineRgn( *clip, run, *clip, RGN_OR );
379 switch (data)
381 case 0: /* eol */
382 left = right = x = 0;
383 y--;
384 if(y < 0) goto done;
385 break;
387 case 1: /* eod */
388 goto done;
390 case 2: /* delta */
391 if (i >= info->bmiHeader.biSizeImage - 1) goto done;
392 x += in_bits[i];
393 if (x > width) x = width;
394 left = right = x;
395 y -= in_bits[i + 1];
396 if(y < 0) goto done;
397 i += 2;
400 else /* data bytes of data */
402 num = data;
403 skip = (num * info->bmiHeader.biBitCount + 7) / 8;
404 if (skip > info->bmiHeader.biSizeImage - i) goto done;
405 skip = (skip + 1) & ~1;
406 if (x + num > width) num = width - x;
407 if (num)
409 BYTE *out_ptr = get_pixel_ptr( info, out_bits, x, y );
410 if (info->bmiHeader.biBitCount == 8)
411 memcpy( out_ptr, in_bits + i, num );
412 else
414 if(x & 1)
416 const BYTE *in_ptr = in_bits + i;
417 for ( ; num; num--, x++)
419 if (x & 1)
421 *out_ptr = (*out_ptr & 0xf0) | ((*in_ptr >> 4) & 0x0f);
422 out_ptr++;
424 else
425 *out_ptr = (*in_ptr++ << 4) & 0xf0;
428 else
429 memcpy( out_ptr, in_bits + i, (num + 1) / 2);
432 x += num;
433 right = x;
434 i += skip;
439 done:
440 if (run) DeleteObject( run );
441 if (bits->free) bits->free( bits );
443 bits->ptr = out_bits;
444 bits->is_copy = TRUE;
445 bits->free = free_heap_bits;
447 return TRUE;
449 fail:
450 if (run) DeleteObject( run );
451 if (clip && *clip) DeleteObject( *clip );
452 HeapFree( GetProcessHeap(), 0, out_bits );
453 return FALSE;
458 INT nulldrv_StretchDIBits( PHYSDEV dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
459 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
460 BITMAPINFO *src_info, UINT coloruse, DWORD rop )
462 DC *dc = get_nulldrv_dc( dev );
463 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
464 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
465 struct bitblt_coords src, dst;
466 struct gdi_image_bits src_bits;
467 DWORD err;
468 HRGN clip = NULL;
469 INT ret = 0;
470 INT height = abs( src_info->bmiHeader.biHeight );
471 BOOL top_down = src_info->bmiHeader.biHeight < 0, non_stretch_from_origin = FALSE;
472 RECT rect;
474 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst, yDst, widthDst, heightDst,
475 xSrc, ySrc, widthSrc, heightSrc, rop);
477 src_bits.ptr = (void*)bits;
478 src_bits.is_copy = FALSE;
479 src_bits.free = NULL;
481 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
483 rect.left = xDst;
484 rect.top = yDst;
485 rect.right = xDst + widthDst;
486 rect.bottom = yDst + heightDst;
487 LPtoDP( dc->hSelf, (POINT *)&rect, 2 );
488 dst.x = rect.left;
489 dst.y = rect.top;
490 dst.width = rect.right - rect.left;
491 dst.height = rect.bottom - rect.top;
493 if (dc->layout & LAYOUT_RTL && rop & NOMIRRORBITMAP)
495 dst.x += dst.width;
496 dst.width = -dst.width;
498 rop &= ~NOMIRRORBITMAP;
500 src.x = xSrc;
501 src.width = widthSrc;
502 src.y = ySrc;
503 src.height = heightSrc;
505 if (src.x == 0 && src.y == 0 && src.width == dst.width && src.height == dst.height)
506 non_stretch_from_origin = TRUE;
508 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
510 BOOL want_clip = non_stretch_from_origin && (rop == SRCCOPY);
511 if (!build_rle_bitmap( src_info, &src_bits, want_clip ? &clip : NULL )) return 0;
514 if (rop != SRCCOPY || non_stretch_from_origin)
516 if (dst.width == 1 && src.width > 1) src.width--;
517 if (dst.height == 1 && src.height > 1) src.height--;
520 if (rop != SRCCOPY)
522 if (dst.width < 0 && dst.width == src.width)
524 /* This is off-by-one, but that's what Windows does */
525 dst.x += dst.width;
526 src.x += src.width;
527 dst.width = -dst.width;
528 src.width = -src.width;
530 if (dst.height < 0 && dst.height == src.height)
532 dst.y += dst.height;
533 src.y += src.height;
534 dst.height = -dst.height;
535 src.height = -src.height;
539 if (!top_down || (rop == SRCCOPY && !non_stretch_from_origin)) src.y = height - src.y - src.height;
541 if (src.y >= height && src.y + src.height + 1 < height)
542 src.y = height - 1;
543 else if (src.y > 0 && src.y + src.height + 1 < 0)
544 src.y = -src.height - 1;
546 get_bounding_rect( &rect, src.x, src.y, src.width, src.height );
548 src.visrect.left = 0;
549 src.visrect.right = src_info->bmiHeader.biWidth;
550 src.visrect.top = 0;
551 src.visrect.bottom = height;
552 if (!intersect_rect( &src.visrect, &src.visrect, &rect )) goto done;
554 if (rop == SRCCOPY) ret = height;
555 else ret = src_info->bmiHeader.biHeight;
557 get_bounding_rect( &rect, dst.x, dst.y, dst.width, dst.height );
559 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
561 if (!intersect_vis_rectangles( &dst, &src )) goto done;
563 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
565 dev = GET_DC_PHYSDEV( dc, pPutImage );
566 copy_bitmapinfo( dst_info, src_info );
567 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
568 if (err == ERROR_BAD_FORMAT)
570 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
572 /* 1-bpp destination without a color table requires a fake 1-entry table
573 * that contains only the background color; except with a 1-bpp source,
574 * in which case it uses the source colors */
575 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
577 if (src_info->bmiHeader.biBitCount > 1)
579 COLORREF color = GetBkColor( dev->hdc );
580 dst_info->bmiColors[0].rgbRed = GetRValue( color );
581 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
582 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
583 dst_info->bmiColors[0].rgbReserved = 0;
584 dst_info->bmiHeader.biClrUsed = 1;
586 else
588 memcpy( dst_info->bmiColors, src_info->bmiColors, 2 * sizeof(dst_info->bmiColors[0]) );
589 dst_info->bmiHeader.biClrUsed = 2;
593 if (!(err = convert_bits( src_info, &src, dst_info, &src_bits )))
595 /* get rid of the fake 1-bpp table */
596 dst_info->bmiHeader.biClrUsed = dst_colors;
597 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, rop );
601 if (err == ERROR_TRANSFORM_NOT_SUPPORTED)
603 copy_bitmapinfo( src_info, dst_info );
604 err = stretch_bits( src_info, &src, dst_info, &dst, &src_bits, GetStretchBltMode( dev->hdc ) );
605 if (!err) err = dev->funcs->pPutImage( dev, NULL, dst_info, &src_bits, &src, &dst, rop );
607 if (err) ret = 0;
609 done:
610 if (src_bits.free) src_bits.free( &src_bits );
611 if (clip) DeleteObject( clip );
612 return ret;
615 /***********************************************************************
616 * StretchDIBits (GDI32.@)
618 INT WINAPI DECLSPEC_HOTPATCH StretchDIBits( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
619 INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
620 const void *bits, const BITMAPINFO *bmi, UINT coloruse,
621 DWORD rop )
623 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
624 BITMAPINFO *info = (BITMAPINFO *)buffer;
625 PHYSDEV physdev;
626 DC *dc;
627 INT ret = 0;
629 if (!bits) return 0;
630 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
632 SetLastError( ERROR_INVALID_PARAMETER );
633 return 0;
636 if ((dc = get_dc_ptr( hdc )))
638 update_dc( dc );
639 physdev = GET_DC_PHYSDEV( dc, pStretchDIBits );
640 ret = physdev->funcs->pStretchDIBits( physdev, xDst, yDst, widthDst, heightDst,
641 xSrc, ySrc, widthSrc, heightSrc, bits, info, coloruse, rop );
642 release_dc_ptr( dc );
644 return ret;
648 /******************************************************************************
649 * SetDIBits [GDI32.@]
651 * Sets pixels in a bitmap using colors from DIB.
653 * PARAMS
654 * hdc [I] Handle to device context
655 * hbitmap [I] Handle to bitmap
656 * startscan [I] Starting scan line
657 * lines [I] Number of scan lines
658 * bits [I] Array of bitmap bits
659 * info [I] Address of structure with data
660 * coloruse [I] Type of color indexes to use
662 * RETURNS
663 * Success: Number of scan lines copied
664 * Failure: 0
666 INT WINAPI SetDIBits( HDC hdc, HBITMAP hbitmap, UINT startscan,
667 UINT lines, LPCVOID bits, const BITMAPINFO *info,
668 UINT coloruse )
670 BITMAPOBJ *bitmap;
671 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
672 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
673 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
674 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
675 INT result = 0;
676 DWORD err;
677 struct gdi_image_bits src_bits;
678 struct bitblt_coords src, dst;
679 INT src_to_dst_offset;
680 HRGN clip = 0;
682 if (!bitmapinfo_from_user_bitmapinfo( src_info, info, coloruse, TRUE ) || coloruse > DIB_PAL_COLORS)
684 SetLastError( ERROR_INVALID_PARAMETER );
685 return 0;
687 if (src_info->bmiHeader.biCompression == BI_BITFIELDS)
689 DWORD *masks = (DWORD *)src_info->bmiColors;
690 if (!masks[0] || !masks[1] || !masks[2])
692 SetLastError( ERROR_INVALID_PARAMETER );
693 return 0;
697 src_bits.ptr = (void *)bits;
698 src_bits.is_copy = FALSE;
699 src_bits.free = NULL;
700 src_bits.param = NULL;
702 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, hdc )) return 0;
704 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return 0;
706 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
708 if (lines == 0) goto done;
709 else lines = src_info->bmiHeader.biHeight;
710 startscan = 0;
712 if (!build_rle_bitmap( src_info, &src_bits, &clip )) goto done;
715 dst.visrect.left = 0;
716 dst.visrect.top = 0;
717 dst.visrect.right = bitmap->dib.dsBm.bmWidth;
718 dst.visrect.bottom = bitmap->dib.dsBm.bmHeight;
720 src.visrect.left = 0;
721 src.visrect.top = 0;
722 src.visrect.right = src_info->bmiHeader.biWidth;
723 src.visrect.bottom = abs( src_info->bmiHeader.biHeight );
725 if (src_info->bmiHeader.biHeight > 0)
727 src_to_dst_offset = -startscan;
728 lines = min( lines, src.visrect.bottom - startscan );
729 if (lines < src.visrect.bottom) src.visrect.top = src.visrect.bottom - lines;
731 else
733 src_to_dst_offset = src.visrect.bottom - lines - startscan;
734 /* Unlike the bottom-up case, Windows doesn't limit lines. */
735 if (lines < src.visrect.bottom) src.visrect.bottom = lines;
738 result = lines;
740 offset_rect( &src.visrect, 0, src_to_dst_offset );
741 if (!intersect_rect( &dst.visrect, &src.visrect, &dst.visrect )) goto done;
742 src.visrect = dst.visrect;
743 offset_rect( &src.visrect, 0, -src_to_dst_offset );
745 src.x = src.visrect.left;
746 src.y = src.visrect.top;
747 src.width = src.visrect.right - src.visrect.left;
748 src.height = src.visrect.bottom - src.visrect.top;
750 dst.x = dst.visrect.left;
751 dst.y = dst.visrect.top;
752 dst.width = dst.visrect.right - dst.visrect.left;
753 dst.height = dst.visrect.bottom - dst.visrect.top;
755 copy_bitmapinfo( dst_info, src_info );
757 err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
758 if (err == ERROR_BAD_FORMAT)
760 err = convert_bits( src_info, &src, dst_info, &src_bits );
761 if (!err) err = put_image_into_bitmap( bitmap, clip, dst_info, &src_bits, &src, &dst );
763 if(err) result = 0;
765 done:
766 if (src_bits.free) src_bits.free( &src_bits );
767 if (clip) DeleteObject( clip );
768 GDI_ReleaseObj( hbitmap );
769 return result;
773 INT nulldrv_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD cx, DWORD cy,
774 INT x_src, INT y_src, UINT startscan, UINT lines,
775 const void *bits, BITMAPINFO *src_info, UINT coloruse )
777 DC *dc = get_nulldrv_dc( dev );
778 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
779 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
780 struct bitblt_coords src, dst;
781 struct gdi_image_bits src_bits;
782 HRGN clip = 0;
783 DWORD err;
784 UINT height;
785 BOOL top_down;
786 POINT pt;
787 RECT rect;
789 top_down = (src_info->bmiHeader.biHeight < 0);
790 height = abs( src_info->bmiHeader.biHeight );
792 src_bits.ptr = (void *)bits;
793 src_bits.is_copy = FALSE;
794 src_bits.free = NULL;
796 if (!lines) return 0;
797 if (coloruse == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( src_info, dev->hdc )) return 0;
799 if (src_info->bmiHeader.biCompression == BI_RLE4 || src_info->bmiHeader.biCompression == BI_RLE8)
801 startscan = 0;
802 lines = height;
803 src_info->bmiHeader.biWidth = x_src + cx;
804 src_info->bmiHeader.biHeight = y_src + cy;
805 if (src_info->bmiHeader.biWidth <= 0 || src_info->bmiHeader.biHeight <= 0) return 0;
806 src.x = x_src;
807 src.y = 0;
808 src.width = cx;
809 src.height = cy;
810 if (!build_rle_bitmap( src_info, &src_bits, &clip )) return 0;
812 else
814 if (startscan >= height) return 0;
815 if (!top_down && lines > height - startscan) lines = height - startscan;
817 /* map src to top-down coordinates with startscan as origin */
818 src.x = x_src;
819 src.y = startscan + lines - (y_src + cy);
820 src.width = cx;
821 src.height = cy;
822 if (src.y > 0)
824 if (!top_down)
826 /* get rid of unnecessary lines */
827 if (src.y >= lines) return 0;
828 lines -= src.y;
829 src.y = 0;
831 else if (src.y >= lines) return lines;
833 src_info->bmiHeader.biHeight = top_down ? -lines : lines;
836 src.visrect.left = src.x;
837 src.visrect.top = src.y;
838 src.visrect.right = src.x + cx;
839 src.visrect.bottom = src.y + cy;
840 rect.left = 0;
841 rect.top = 0;
842 rect.right = src_info->bmiHeader.biWidth;
843 rect.bottom = abs( src_info->bmiHeader.biHeight );
844 if (!intersect_rect( &src.visrect, &src.visrect, &rect ))
846 lines = 0;
847 goto done;
850 pt.x = x_dst;
851 pt.y = y_dst;
852 LPtoDP( dev->hdc, &pt, 1 );
853 dst.x = pt.x;
854 dst.y = pt.y;
855 dst.width = cx;
856 dst.height = cy;
857 if (GetLayout( dev->hdc ) & LAYOUT_RTL) dst.x -= cx - 1;
859 rect.left = dst.x;
860 rect.top = dst.y;
861 rect.right = dst.x + cx;
862 rect.bottom = dst.y + cy;
863 if (!clip_visrect( dc, &dst.visrect, &rect )) goto done;
865 offset_rect( &src.visrect, dst.x - src.x, dst.y - src.y );
866 intersect_rect( &rect, &src.visrect, &dst.visrect );
867 src.visrect = dst.visrect = rect;
868 offset_rect( &src.visrect, src.x - dst.x, src.y - dst.y );
869 if (is_rect_empty( &dst.visrect )) goto done;
870 if (clip) OffsetRgn( clip, dst.x - src.x, dst.y - src.y );
872 dev = GET_DC_PHYSDEV( dc, pPutImage );
873 copy_bitmapinfo( dst_info, src_info );
874 err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
875 if (err == ERROR_BAD_FORMAT)
877 err = convert_bits( src_info, &src, dst_info, &src_bits );
878 if (!err) err = dev->funcs->pPutImage( dev, clip, dst_info, &src_bits, &src, &dst, SRCCOPY );
880 if (err) lines = 0;
882 done:
883 if (src_bits.free) src_bits.free( &src_bits );
884 if (clip) DeleteObject( clip );
885 return lines;
888 /***********************************************************************
889 * SetDIBitsToDevice (GDI32.@)
891 INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx,
892 DWORD cy, INT xSrc, INT ySrc, UINT startscan,
893 UINT lines, LPCVOID bits, const BITMAPINFO *bmi,
894 UINT coloruse )
896 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
897 BITMAPINFO *info = (BITMAPINFO *)buffer;
898 PHYSDEV physdev;
899 INT ret = 0;
900 DC *dc;
902 if (!bits) return 0;
903 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, coloruse, TRUE ))
905 SetLastError( ERROR_INVALID_PARAMETER );
906 return 0;
909 if ((dc = get_dc_ptr( hdc )))
911 update_dc( dc );
912 physdev = GET_DC_PHYSDEV( dc, pSetDIBitsToDevice );
913 ret = physdev->funcs->pSetDIBitsToDevice( physdev, xDest, yDest, cx, cy, xSrc,
914 ySrc, startscan, lines, bits, info, coloruse );
915 release_dc_ptr( dc );
917 return ret;
920 /***********************************************************************
921 * SetDIBColorTable (GDI32.@)
923 UINT WINAPI SetDIBColorTable( HDC hdc, UINT startpos, UINT entries, const RGBQUAD *colors )
925 DC * dc;
926 UINT result = 0;
927 BITMAPOBJ * bitmap;
929 if (!(dc = get_dc_ptr( hdc ))) return 0;
931 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
933 if (startpos < bitmap->dib.dsBmih.biClrUsed)
935 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
936 memcpy(bitmap->color_table + startpos, colors, result * sizeof(RGBQUAD));
938 GDI_ReleaseObj( dc->hBitmap );
940 if (result) /* update colors of selected objects */
942 SetTextColor( hdc, dc->textColor );
943 SetBkColor( hdc, dc->backgroundColor );
944 SelectObject( hdc, dc->hPen );
945 SelectObject( hdc, dc->hBrush );
948 release_dc_ptr( dc );
949 return result;
953 /***********************************************************************
954 * GetDIBColorTable (GDI32.@)
956 UINT WINAPI GetDIBColorTable( HDC hdc, UINT startpos, UINT entries, RGBQUAD *colors )
958 DC * dc;
959 BITMAPOBJ *bitmap;
960 UINT result = 0;
962 if (!(dc = get_dc_ptr( hdc ))) return 0;
964 if ((bitmap = GDI_GetObjPtr( dc->hBitmap, OBJ_BITMAP )))
966 if (startpos < bitmap->dib.dsBmih.biClrUsed)
968 result = min( entries, bitmap->dib.dsBmih.biClrUsed - startpos );
969 memcpy(colors, bitmap->color_table + startpos, result * sizeof(RGBQUAD));
971 GDI_ReleaseObj( dc->hBitmap );
973 release_dc_ptr( dc );
974 return result;
977 static const DWORD bit_fields_888[3] = {0xff0000, 0x00ff00, 0x0000ff};
978 static const DWORD bit_fields_555[3] = {0x7c00, 0x03e0, 0x001f};
980 static int fill_query_info( BITMAPINFO *info, BITMAPOBJ *bmp )
982 BITMAPINFOHEADER header;
984 header.biSize = info->bmiHeader.biSize; /* Ensure we don't overwrite the original size when we copy back */
985 header.biWidth = bmp->dib.dsBm.bmWidth;
986 header.biHeight = bmp->dib.dsBm.bmHeight;
987 header.biPlanes = 1;
988 header.biBitCount = bmp->dib.dsBm.bmBitsPixel;
990 switch (header.biBitCount)
992 case 16:
993 case 32:
994 header.biCompression = BI_BITFIELDS;
995 break;
996 default:
997 header.biCompression = BI_RGB;
998 break;
1001 header.biSizeImage = get_dib_image_size( (BITMAPINFO *)&header );
1002 header.biXPelsPerMeter = 0;
1003 header.biYPelsPerMeter = 0;
1004 header.biClrUsed = 0;
1005 header.biClrImportant = 0;
1007 if ( info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER) )
1009 BITMAPCOREHEADER *coreheader = (BITMAPCOREHEADER *)info;
1011 coreheader->bcWidth = header.biWidth;
1012 coreheader->bcHeight = header.biHeight;
1013 coreheader->bcPlanes = header.biPlanes;
1014 coreheader->bcBitCount = header.biBitCount;
1016 else
1017 info->bmiHeader = header;
1019 return bmp->dib.dsBm.bmHeight;
1022 /************************************************************************
1023 * copy_color_info
1025 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1027 static void copy_color_info(BITMAPINFO *dst, const BITMAPINFO *src, UINT coloruse)
1029 assert( src->bmiHeader.biSize == sizeof(BITMAPINFOHEADER) );
1031 if (dst->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1033 BITMAPCOREINFO *core = (BITMAPCOREINFO *)dst;
1034 if (coloruse == DIB_PAL_COLORS)
1035 memcpy( core->bmciColors, src->bmiColors, src->bmiHeader.biClrUsed * sizeof(WORD) );
1036 else
1038 unsigned int i;
1039 for (i = 0; i < src->bmiHeader.biClrUsed; i++)
1041 core->bmciColors[i].rgbtRed = src->bmiColors[i].rgbRed;
1042 core->bmciColors[i].rgbtGreen = src->bmiColors[i].rgbGreen;
1043 core->bmciColors[i].rgbtBlue = src->bmiColors[i].rgbBlue;
1047 else
1049 dst->bmiHeader.biClrUsed = src->bmiHeader.biClrUsed;
1050 dst->bmiHeader.biSizeImage = src->bmiHeader.biSizeImage;
1052 if (src->bmiHeader.biCompression == BI_BITFIELDS)
1053 /* bitfields are always at bmiColors even in larger structures */
1054 memcpy( dst->bmiColors, src->bmiColors, 3 * sizeof(DWORD) );
1055 else if (src->bmiHeader.biClrUsed)
1057 void *colorptr = (char *)dst + dst->bmiHeader.biSize;
1058 unsigned int size;
1060 if (coloruse == DIB_PAL_COLORS)
1061 size = src->bmiHeader.biClrUsed * sizeof(WORD);
1062 else
1063 size = src->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1064 memcpy( colorptr, src->bmiColors, size );
1069 const RGBQUAD *get_default_color_table( int bpp )
1071 static const RGBQUAD table_1[2] =
1073 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1075 static const RGBQUAD table_4[16] =
1077 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1078 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1079 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1080 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1082 static const RGBQUAD table_8[256] =
1084 /* first and last 10 entries are the default system palette entries */
1085 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1086 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1087 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1088 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1089 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1090 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1091 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1092 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1093 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1094 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1095 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1096 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1097 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1098 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1099 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1100 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1101 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1102 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1103 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1104 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1105 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1106 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1107 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1108 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1109 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1110 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1111 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1112 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1113 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1114 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1115 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1116 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1117 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1118 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1119 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1120 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1121 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1122 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1123 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1124 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1125 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1126 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1127 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1128 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1129 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1130 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1131 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1132 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1133 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1134 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1135 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1136 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1137 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1138 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1139 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1140 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1141 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1142 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1143 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1144 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1145 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1146 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1147 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1148 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1151 switch (bpp)
1153 case 1: return table_1;
1154 case 4: return table_4;
1155 case 8: return table_8;
1156 default: return NULL;
1160 void fill_default_color_table( BITMAPINFO *info )
1162 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1163 memcpy( info->bmiColors, get_default_color_table( info->bmiHeader.biBitCount ),
1164 info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
1167 void get_ddb_bitmapinfo( BITMAPOBJ *bmp, BITMAPINFO *info )
1169 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1170 info->bmiHeader.biWidth = bmp->dib.dsBm.bmWidth;
1171 info->bmiHeader.biHeight = -bmp->dib.dsBm.bmHeight;
1172 info->bmiHeader.biPlanes = 1;
1173 info->bmiHeader.biBitCount = bmp->dib.dsBm.bmBitsPixel;
1174 info->bmiHeader.biCompression = BI_RGB;
1175 info->bmiHeader.biXPelsPerMeter = 0;
1176 info->bmiHeader.biYPelsPerMeter = 0;
1177 info->bmiHeader.biClrUsed = 0;
1178 info->bmiHeader.biClrImportant = 0;
1181 BITMAPINFO *copy_packed_dib( const BITMAPINFO *src_info, UINT usage )
1183 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1184 BITMAPINFO *ret, *info = (BITMAPINFO *)buffer;
1185 unsigned int info_size;
1187 if (!bitmapinfo_from_user_bitmapinfo( info, src_info, usage, FALSE )) return NULL;
1189 info_size = get_dib_info_size( info, usage );
1190 if ((ret = HeapAlloc( GetProcessHeap(), 0, info_size + info->bmiHeader.biSizeImage )))
1192 memcpy( ret, info, info_size );
1193 memcpy( (char *)ret + info_size, (char *)src_info + bitmap_info_size( src_info, usage ),
1194 info->bmiHeader.biSizeImage );
1196 return ret;
1199 /******************************************************************************
1200 * GetDIBits [GDI32.@]
1202 * Retrieves bits of bitmap and copies to buffer.
1204 * RETURNS
1205 * Success: Number of scan lines copied from bitmap
1206 * Failure: 0
1208 INT WINAPI GetDIBits(
1209 HDC hdc, /* [in] Handle to device context */
1210 HBITMAP hbitmap, /* [in] Handle to bitmap */
1211 UINT startscan, /* [in] First scan line to set in dest bitmap */
1212 UINT lines, /* [in] Number of scan lines to copy */
1213 LPVOID bits, /* [out] Address of array for bitmap bits */
1214 BITMAPINFO * info, /* [out] Address of structure with bitmap data */
1215 UINT coloruse) /* [in] RGB or palette index */
1217 DC * dc;
1218 BITMAPOBJ * bmp;
1219 int i, dst_to_src_offset, ret = 0;
1220 DWORD err;
1221 char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1222 BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
1223 char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1224 BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
1225 struct gdi_image_bits src_bits;
1226 struct bitblt_coords src, dst;
1227 BOOL empty_rect = FALSE;
1229 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1230 own copy and transfer the colour info back at the end */
1231 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0;
1232 if (coloruse > DIB_PAL_COLORS) return 0;
1233 if (bits &&
1234 (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG))
1235 return 0;
1236 dst_info->bmiHeader.biClrUsed = 0;
1237 dst_info->bmiHeader.biClrImportant = 0;
1239 if (!(dc = get_dc_ptr( hdc )))
1241 SetLastError( ERROR_INVALID_PARAMETER );
1242 return 0;
1244 update_dc( dc );
1245 if (!(bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP )))
1247 release_dc_ptr( dc );
1248 return 0;
1251 src.visrect.left = 0;
1252 src.visrect.top = 0;
1253 src.visrect.right = bmp->dib.dsBm.bmWidth;
1254 src.visrect.bottom = bmp->dib.dsBm.bmHeight;
1256 dst.visrect.left = 0;
1257 dst.visrect.top = 0;
1258 dst.visrect.right = dst_info->bmiHeader.biWidth;
1259 dst.visrect.bottom = abs( dst_info->bmiHeader.biHeight );
1261 if (lines == 0 || startscan >= dst.visrect.bottom)
1262 bits = NULL;
1264 if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */
1266 ret = fill_query_info( info, bmp );
1267 goto done;
1270 /* validate parameters */
1272 if (dst_info->bmiHeader.biWidth <= 0) goto done;
1273 if (dst_info->bmiHeader.biHeight == 0) goto done;
1275 switch (dst_info->bmiHeader.biCompression)
1277 case BI_RLE4:
1278 if (dst_info->bmiHeader.biBitCount != 4) goto done;
1279 if (dst_info->bmiHeader.biHeight < 0) goto done;
1280 if (bits) goto done; /* can't retrieve compressed bits */
1281 break;
1282 case BI_RLE8:
1283 if (dst_info->bmiHeader.biBitCount != 8) goto done;
1284 if (dst_info->bmiHeader.biHeight < 0) goto done;
1285 if (bits) goto done; /* can't retrieve compressed bits */
1286 break;
1287 case BI_BITFIELDS:
1288 if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done;
1289 /* fall through */
1290 case BI_RGB:
1291 if (lines && !dst_info->bmiHeader.biPlanes) goto done;
1292 if (dst_info->bmiHeader.biBitCount == 1) break;
1293 if (dst_info->bmiHeader.biBitCount == 4) break;
1294 if (dst_info->bmiHeader.biBitCount == 8) break;
1295 if (dst_info->bmiHeader.biBitCount == 16) break;
1296 if (dst_info->bmiHeader.biBitCount == 24) break;
1297 if (dst_info->bmiHeader.biBitCount == 32) break;
1298 /* fall through */
1299 default:
1300 goto done;
1303 if (bits)
1305 if (dst_info->bmiHeader.biHeight > 0)
1307 dst_to_src_offset = -startscan;
1308 lines = min( lines, dst.visrect.bottom - startscan );
1309 if (lines < dst.visrect.bottom) dst.visrect.top = dst.visrect.bottom - lines;
1311 else
1313 dst_to_src_offset = dst.visrect.bottom - lines - startscan;
1314 if (dst_to_src_offset < 0)
1316 dst_to_src_offset = 0;
1317 lines = dst.visrect.bottom - startscan;
1319 if (lines < dst.visrect.bottom) dst.visrect.bottom = lines;
1322 offset_rect( &dst.visrect, 0, dst_to_src_offset );
1323 empty_rect = !intersect_rect( &src.visrect, &src.visrect, &dst.visrect );
1324 dst.visrect = src.visrect;
1325 offset_rect( &dst.visrect, 0, -dst_to_src_offset );
1327 if (dst_info->bmiHeader.biHeight > 0)
1329 if (dst.visrect.bottom < dst_info->bmiHeader.biHeight)
1331 int pad_lines = min( dst_info->bmiHeader.biHeight - dst.visrect.bottom, lines );
1332 int pad_bytes = pad_lines * get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1333 memset( bits, 0, pad_bytes );
1334 bits = (char *)bits + pad_bytes;
1337 else
1339 if (dst.visrect.bottom < lines)
1341 int pad_lines = lines - dst.visrect.bottom;
1342 int stride = get_dib_stride( dst_info->bmiHeader.biWidth, dst_info->bmiHeader.biBitCount );
1343 int pad_bytes = pad_lines * stride;
1344 memset( (char *)bits + dst.visrect.bottom * stride, 0, pad_bytes );
1348 if (empty_rect) bits = NULL;
1350 src.x = src.visrect.left;
1351 src.y = src.visrect.top;
1352 src.width = src.visrect.right - src.visrect.left;
1353 src.height = src.visrect.bottom - src.visrect.top;
1355 lines = src.height;
1358 err = get_image_from_bitmap( bmp, src_info, bits ? &src_bits : NULL, bits ? &src : NULL );
1360 if (err) goto done;
1362 /* fill out the src colour table, if it needs one */
1363 if (src_info->bmiHeader.biBitCount <= 8 && src_info->bmiHeader.biClrUsed == 0)
1364 fill_default_color_table( src_info );
1366 /* if the src and dst are the same depth, copy the colour info across */
1367 if (dst_info->bmiHeader.biBitCount == src_info->bmiHeader.biBitCount && coloruse == DIB_RGB_COLORS )
1369 switch (src_info->bmiHeader.biBitCount)
1371 case 16:
1372 if (src_info->bmiHeader.biCompression == BI_RGB)
1374 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1375 memcpy( src_info->bmiColors, bit_fields_555, sizeof(bit_fields_555) );
1377 break;
1378 case 32:
1379 if (src_info->bmiHeader.biCompression == BI_RGB)
1381 src_info->bmiHeader.biCompression = BI_BITFIELDS;
1382 memcpy( src_info->bmiColors, bit_fields_888, sizeof(bit_fields_888) );
1384 break;
1386 src_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
1387 copy_color_info( dst_info, src_info, coloruse );
1389 else if (dst_info->bmiHeader.biBitCount <= 8) /* otherwise construct a default colour table for the dst, if needed */
1391 if( coloruse == DIB_PAL_COLORS )
1393 if (!fill_color_table_from_palette( dst_info, hdc )) goto done;
1395 else
1397 fill_default_color_table( dst_info );
1401 if (bits)
1403 if(dst_info->bmiHeader.biHeight > 0)
1404 dst_info->bmiHeader.biHeight = src.height;
1405 else
1406 dst_info->bmiHeader.biHeight = -src.height;
1408 convert_bitmapinfo( src_info, src_bits.ptr, &src, dst_info, bits );
1409 if (src_bits.free) src_bits.free( &src_bits );
1410 ret = lines;
1412 else
1413 ret = !empty_rect;
1415 if (coloruse == DIB_PAL_COLORS)
1417 WORD *index = (WORD *)dst_info->bmiColors;
1418 for (i = 0; i < dst_info->bmiHeader.biClrUsed; i++, index++)
1419 *index = i;
1422 copy_color_info( info, dst_info, coloruse );
1423 if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) info->bmiHeader.biClrUsed = 0;
1425 done:
1426 release_dc_ptr( dc );
1427 GDI_ReleaseObj( hbitmap );
1428 return ret;
1432 /***********************************************************************
1433 * CreateDIBitmap (GDI32.@)
1435 * Creates a DDB (device dependent bitmap) from a DIB.
1436 * The DDB will have the same color depth as the reference DC.
1438 HBITMAP WINAPI CreateDIBitmap( HDC hdc, const BITMAPINFOHEADER *header,
1439 DWORD init, LPCVOID bits, const BITMAPINFO *data,
1440 UINT coloruse )
1442 BITMAPINFOHEADER info;
1443 HBITMAP handle;
1444 LONG height;
1446 if (!bitmapinfoheader_from_user_bitmapinfo( &info, header )) return 0;
1447 if (info.biCompression == BI_JPEG || info.biCompression == BI_PNG) return 0;
1448 if (coloruse > DIB_PAL_COLORS + 1) return 0;
1449 if (info.biWidth < 0) return 0;
1451 /* Top-down DIBs have a negative height */
1452 height = abs( info.biHeight );
1454 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1455 hdc, header, init, bits, data, coloruse, info.biWidth, info.biHeight,
1456 info.biBitCount, info.biCompression);
1458 if (hdc == NULL)
1459 handle = CreateBitmap( info.biWidth, height, 1, 1, NULL );
1460 else
1461 handle = CreateCompatibleBitmap( hdc, info.biWidth, height );
1463 if (handle)
1465 if (init & CBM_INIT)
1467 if (SetDIBits( hdc, handle, 0, height, bits, data, coloruse ) == 0)
1469 DeleteObject( handle );
1470 handle = 0;
1475 return handle;
1479 /***********************************************************************
1480 * CreateDIBSection (GDI32.@)
1482 HBITMAP WINAPI CreateDIBSection(HDC hdc, const BITMAPINFO *bmi, UINT usage,
1483 VOID **bits, HANDLE section, DWORD offset)
1485 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1486 BITMAPINFO *info = (BITMAPINFO *)buffer;
1487 HBITMAP ret = 0;
1488 BITMAPOBJ *bmp;
1489 void *mapBits = NULL;
1491 if (bits) *bits = NULL;
1492 if (!bitmapinfo_from_user_bitmapinfo( info, bmi, usage, FALSE )) return 0;
1493 if (usage > DIB_PAL_COLORS) return 0;
1494 if (info->bmiHeader.biPlanes != 1)
1496 if (info->bmiHeader.biPlanes * info->bmiHeader.biBitCount > 16) return 0;
1497 WARN( "%u planes not properly supported\n", info->bmiHeader.biPlanes );
1500 if (!(bmp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmp) ))) return 0;
1502 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1503 info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1504 info->bmiHeader.biPlanes, info->bmiHeader.biBitCount,
1505 info->bmiHeader.biCompression == BI_BITFIELDS? "BI_BITFIELDS" : "BI_RGB",
1506 info->bmiHeader.biSizeImage, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1508 bmp->dib.dsBm.bmType = 0;
1509 bmp->dib.dsBm.bmWidth = info->bmiHeader.biWidth;
1510 bmp->dib.dsBm.bmHeight = abs( info->bmiHeader.biHeight );
1511 bmp->dib.dsBm.bmWidthBytes = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
1512 bmp->dib.dsBm.bmPlanes = info->bmiHeader.biPlanes;
1513 bmp->dib.dsBm.bmBitsPixel = info->bmiHeader.biBitCount;
1514 bmp->dib.dsBmih = info->bmiHeader;
1516 if (info->bmiHeader.biBitCount <= 8) /* build the color table */
1518 if (usage == DIB_PAL_COLORS && !fill_color_table_from_pal_colors( info, hdc ))
1519 goto error;
1520 bmp->dib.dsBmih.biClrUsed = info->bmiHeader.biClrUsed;
1521 if (!(bmp->color_table = HeapAlloc( GetProcessHeap(), 0,
1522 bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) )))
1523 goto error;
1524 memcpy( bmp->color_table, info->bmiColors, bmp->dib.dsBmih.biClrUsed * sizeof(RGBQUAD) );
1527 /* set dsBitfields values */
1528 if (info->bmiHeader.biBitCount == 16 && info->bmiHeader.biCompression == BI_RGB)
1530 bmp->dib.dsBmih.biCompression = BI_BITFIELDS;
1531 bmp->dib.dsBitfields[0] = 0x7c00;
1532 bmp->dib.dsBitfields[1] = 0x03e0;
1533 bmp->dib.dsBitfields[2] = 0x001f;
1535 else if (info->bmiHeader.biCompression == BI_BITFIELDS)
1537 if (usage == DIB_PAL_COLORS) goto error;
1538 bmp->dib.dsBitfields[0] = *(const DWORD *)info->bmiColors;
1539 bmp->dib.dsBitfields[1] = *((const DWORD *)info->bmiColors + 1);
1540 bmp->dib.dsBitfields[2] = *((const DWORD *)info->bmiColors + 2);
1541 if (!bmp->dib.dsBitfields[0] || !bmp->dib.dsBitfields[1] || !bmp->dib.dsBitfields[2]) goto error;
1543 else bmp->dib.dsBitfields[0] = bmp->dib.dsBitfields[1] = bmp->dib.dsBitfields[2] = 0;
1545 /* get storage location for DIB bits */
1547 if (section)
1549 SYSTEM_INFO SystemInfo;
1550 DWORD mapOffset;
1551 INT mapSize;
1553 GetSystemInfo( &SystemInfo );
1554 mapOffset = offset - (offset % SystemInfo.dwAllocationGranularity);
1555 mapSize = bmp->dib.dsBmih.biSizeImage + (offset - mapOffset);
1556 mapBits = MapViewOfFile( section, FILE_MAP_ALL_ACCESS, 0, mapOffset, mapSize );
1557 if (mapBits) bmp->dib.dsBm.bmBits = (char *)mapBits + (offset - mapOffset);
1559 else
1561 offset = 0;
1562 bmp->dib.dsBm.bmBits = VirtualAlloc( NULL, bmp->dib.dsBmih.biSizeImage,
1563 MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
1565 bmp->dib.dshSection = section;
1566 bmp->dib.dsOffset = offset;
1568 if (!bmp->dib.dsBm.bmBits) goto error;
1570 if (!(ret = alloc_gdi_handle( bmp, OBJ_BITMAP, &dib_funcs ))) goto error;
1572 if (bits) *bits = bmp->dib.dsBm.bmBits;
1573 return ret;
1575 error:
1576 if (section) UnmapViewOfFile( mapBits );
1577 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1578 HeapFree( GetProcessHeap(), 0, bmp->color_table );
1579 HeapFree( GetProcessHeap(), 0, bmp );
1580 return 0;
1584 /***********************************************************************
1585 * DIB_SelectObject
1587 static HGDIOBJ DIB_SelectObject( HGDIOBJ handle, HDC hdc )
1589 HGDIOBJ ret;
1590 BITMAPOBJ *bitmap;
1591 DC *dc;
1592 PHYSDEV physdev;
1594 if (!(dc = get_dc_ptr( hdc ))) return 0;
1596 if (GetObjectType( hdc ) != OBJ_MEMDC)
1598 ret = 0;
1599 goto done;
1601 ret = dc->hBitmap;
1602 if (handle == dc->hBitmap) goto done; /* nothing to do */
1604 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
1606 ret = 0;
1607 goto done;
1610 if (GDI_get_ref_count( handle ))
1612 WARN( "Bitmap already selected in another DC\n" );
1613 GDI_ReleaseObj( handle );
1614 ret = 0;
1615 goto done;
1618 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
1619 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
1621 GDI_ReleaseObj( handle );
1622 ret = 0;
1624 else
1626 dc->hBitmap = handle;
1627 GDI_inc_ref_count( handle );
1628 dc->dirty = 0;
1629 dc->vis_rect.left = 0;
1630 dc->vis_rect.top = 0;
1631 dc->vis_rect.right = bitmap->dib.dsBm.bmWidth;
1632 dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
1633 dc->device_rect = dc->vis_rect;
1634 GDI_ReleaseObj( handle );
1635 DC_InitDC( dc );
1636 GDI_dec_ref_count( ret );
1639 done:
1640 release_dc_ptr( dc );
1641 return ret;
1645 /***********************************************************************
1646 * DIB_GetObject
1648 static INT DIB_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
1650 INT ret = 0;
1651 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
1653 if (!bmp) return 0;
1655 if (!buffer) ret = sizeof(BITMAP);
1656 else if (count >= sizeof(DIBSECTION))
1658 DIBSECTION *dib = buffer;
1659 *dib = bmp->dib;
1660 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
1661 ret = sizeof(DIBSECTION);
1663 else if (count >= sizeof(BITMAP))
1665 BITMAP *bitmap = buffer;
1666 *bitmap = bmp->dib.dsBm;
1667 ret = sizeof(BITMAP);
1670 GDI_ReleaseObj( handle );
1671 return ret;
1675 /***********************************************************************
1676 * DIB_DeleteObject
1678 static BOOL DIB_DeleteObject( HGDIOBJ handle )
1680 BITMAPOBJ *bmp;
1682 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
1684 if (bmp->dib.dshSection)
1686 SYSTEM_INFO SystemInfo;
1687 GetSystemInfo( &SystemInfo );
1688 UnmapViewOfFile( (char *)bmp->dib.dsBm.bmBits -
1689 (bmp->dib.dsOffset % SystemInfo.dwAllocationGranularity) );
1691 else VirtualFree( bmp->dib.dsBm.bmBits, 0, MEM_RELEASE );
1693 HeapFree(GetProcessHeap(), 0, bmp->color_table);
1694 return HeapFree( GetProcessHeap(), 0, bmp );