2 * GDI device-independent bitmaps
4 * Copyright 1993,1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 Important information:
24 * Current Windows versions support two different DIB structures:
26 - BITMAPCOREINFO / BITMAPCOREHEADER (legacy structures; used in OS/2)
27 - BITMAPINFO / BITMAPINFOHEADER
29 Most Windows API functions taking a BITMAPINFO* / BITMAPINFOHEADER* also
30 accept the old "core" structures, and so must WINE.
31 You can distinguish them by looking at the first member (bcSize/biSize).
34 * The palettes are stored in different formats:
36 - BITMAPCOREINFO: Array of RGBTRIPLE
37 - BITMAPINFO: Array of RGBQUAD
40 * There are even more DIB headers, but they all extend BITMAPINFOHEADER:
42 - BITMAPV4HEADER: Introduced in Windows 95 / NT 4.0
43 - BITMAPV5HEADER: Introduced in Windows 98 / 2000
45 If biCompression is BI_BITFIELDS, the color masks are at the same position
46 in all the headers (they start at bmiColors of BITMAPINFOHEADER), because
47 the new headers have structure members for the masks.
50 * You should never access the color table using the bmiColors member,
51 because the passed structure may have one of the extended headers
52 mentioned above. Use this to calculate the location:
55 void* colorPtr = (LPBYTE) info + (WORD) info->bmiHeader.biSize;
59 Search for "Bitmap Structures" in MSDN
69 #include "gdi_private.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(bitmap
);
75 /***********************************************************************
78 * Return the size of the bitmap info structure including color table.
80 int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
82 unsigned int colors
, size
, masks
= 0;
84 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
86 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
87 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
88 return sizeof(BITMAPCOREHEADER
) + colors
*
89 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
91 else /* assume BITMAPINFOHEADER */
93 if (info
->bmiHeader
.biClrUsed
) colors
= min( info
->bmiHeader
.biClrUsed
, 256 );
94 else colors
= info
->bmiHeader
.biBitCount
> 8 ? 0 : 1 << info
->bmiHeader
.biBitCount
;
95 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
96 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
97 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
101 /*******************************************************************************************
102 * Verify that the DIB parameters are valid.
104 static BOOL
is_valid_dib_format( const BITMAPINFOHEADER
*info
, BOOL allow_compression
)
106 if (info
->biWidth
<= 0) return FALSE
;
107 if (info
->biHeight
== 0) return FALSE
;
109 if (allow_compression
&& (info
->biCompression
== BI_RLE4
|| info
->biCompression
== BI_RLE8
))
111 if (info
->biHeight
< 0) return FALSE
;
112 if (!info
->biSizeImage
) return FALSE
;
113 return info
->biBitCount
== (info
->biCompression
== BI_RLE4
? 4 : 8);
116 if (!info
->biPlanes
) return FALSE
;
118 switch (info
->biBitCount
)
124 return (info
->biCompression
== BI_RGB
);
127 return (info
->biCompression
== BI_BITFIELDS
|| info
->biCompression
== BI_RGB
);
133 /*******************************************************************************************
134 * Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
136 static BOOL
bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER
*dst
, const BITMAPINFOHEADER
*info
)
138 if (!info
) return FALSE
;
140 if (info
->biSize
== sizeof(BITMAPCOREHEADER
))
142 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
143 dst
->biWidth
= core
->bcWidth
;
144 dst
->biHeight
= core
->bcHeight
;
145 dst
->biPlanes
= core
->bcPlanes
;
146 dst
->biBitCount
= core
->bcBitCount
;
147 dst
->biCompression
= BI_RGB
;
148 dst
->biXPelsPerMeter
= 0;
149 dst
->biYPelsPerMeter
= 0;
151 dst
->biClrImportant
= 0;
153 else if (info
->biSize
>= sizeof(BITMAPINFOHEADER
)) /* assume BITMAPINFOHEADER */
159 WARN( "(%u): unknown/wrong size for header\n", info
->biSize
);
163 dst
->biSize
= sizeof(*dst
);
164 if (dst
->biCompression
== BI_RGB
|| dst
->biCompression
== BI_BITFIELDS
)
165 dst
->biSizeImage
= get_dib_image_size( (BITMAPINFO
*)dst
);
169 /*******************************************************************************************
170 * Fill out a true BITMAPINFO from a variable sized BITMAPINFO / BITMAPCOREINFO.
172 * The resulting sanitized BITMAPINFO is guaranteed to have:
173 * - biSize set to sizeof(BITMAPINFOHEADER)
174 * - biSizeImage set to the actual image size even for non-compressed DIB
175 * - biClrUsed set to the size of the color table, and 0 only when there is no color table
176 * - color table present only for <= 8 bpp, always starts at info->bmiColors
178 static BOOL
bitmapinfo_from_user_bitmapinfo( BITMAPINFO
*dst
, const BITMAPINFO
*info
,
179 UINT coloruse
, BOOL allow_compression
)
183 if (coloruse
> DIB_PAL_COLORS
+ 1) return FALSE
; /* FIXME: handle DIB_PAL_COLORS+1 format */
184 if (!bitmapinfoheader_from_user_bitmapinfo( &dst
->bmiHeader
, &info
->bmiHeader
)) return FALSE
;
185 if (!is_valid_dib_format( &dst
->bmiHeader
, allow_compression
)) return FALSE
;
187 src_colors
= (char *)info
+ info
->bmiHeader
.biSize
;
189 if (dst
->bmiHeader
.biCompression
== BI_BITFIELDS
)
191 /* bitfields are always at bmiColors even in larger structures */
192 memcpy( dst
->bmiColors
, info
->bmiColors
, 3 * sizeof(DWORD
) );
193 dst
->bmiHeader
.biClrUsed
= 0;
195 else if (dst
->bmiHeader
.biBitCount
<= 8)
197 unsigned int colors
= dst
->bmiHeader
.biClrUsed
;
198 unsigned int max_colors
= 1 << dst
->bmiHeader
.biBitCount
;
200 if (!colors
) colors
= max_colors
;
201 else colors
= min( colors
, max_colors
);
203 if (coloruse
== DIB_PAL_COLORS
)
205 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(WORD
) );
208 else if (info
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
210 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(RGBQUAD
) );
215 RGBTRIPLE
*triple
= (RGBTRIPLE
*)src_colors
;
216 for (i
= 0; i
< colors
; i
++)
218 dst
->bmiColors
[i
].rgbRed
= triple
[i
].rgbtRed
;
219 dst
->bmiColors
[i
].rgbGreen
= triple
[i
].rgbtGreen
;
220 dst
->bmiColors
[i
].rgbBlue
= triple
[i
].rgbtBlue
;
221 dst
->bmiColors
[i
].rgbReserved
= 0;
224 memset( dst
->bmiColors
+ colors
, 0, (max_colors
- colors
) * sizeof(RGBQUAD
) );
225 dst
->bmiHeader
.biClrUsed
= max_colors
;
227 else dst
->bmiHeader
.biClrUsed
= 0;
232 static int fill_color_table_from_palette( BITMAPINFO
*info
, HDC hdc
)
234 PALETTEENTRY palEntry
[256];
235 HPALETTE palette
= GetCurrentObject( hdc
, OBJ_PAL
);
236 int i
, colors
= 1 << info
->bmiHeader
.biBitCount
;
238 info
->bmiHeader
.biClrUsed
= colors
;
240 if (!palette
) return 0;
242 memset( palEntry
, 0, sizeof(palEntry
) );
243 if (!GetPaletteEntries( palette
, 0, colors
, palEntry
))
246 for (i
= 0; i
< colors
; i
++)
248 info
->bmiColors
[i
].rgbRed
= palEntry
[i
].peRed
;
249 info
->bmiColors
[i
].rgbGreen
= palEntry
[i
].peGreen
;
250 info
->bmiColors
[i
].rgbBlue
= palEntry
[i
].peBlue
;
251 info
->bmiColors
[i
].rgbReserved
= 0;
257 BOOL
fill_color_table_from_pal_colors( BITMAPINFO
*info
, HDC hdc
)
259 PALETTEENTRY entries
[256];
262 const WORD
*index
= (const WORD
*)info
->bmiColors
;
263 int i
, count
, colors
= info
->bmiHeader
.biClrUsed
;
265 if (!colors
) return TRUE
;
266 if (!(palette
= GetCurrentObject( hdc
, OBJ_PAL
))) return FALSE
;
267 if (!(count
= GetPaletteEntries( palette
, 0, colors
, entries
))) return FALSE
;
269 for (i
= 0; i
< colors
; i
++, index
++)
271 table
[i
].rgbRed
= entries
[*index
% count
].peRed
;
272 table
[i
].rgbGreen
= entries
[*index
% count
].peGreen
;
273 table
[i
].rgbBlue
= entries
[*index
% count
].peBlue
;
274 table
[i
].rgbReserved
= 0;
276 info
->bmiHeader
.biClrUsed
= 1 << info
->bmiHeader
.biBitCount
;
277 memcpy( info
->bmiColors
, table
, colors
* sizeof(RGBQUAD
) );
278 memset( info
->bmiColors
+ colors
, 0, (info
->bmiHeader
.biClrUsed
- colors
) * sizeof(RGBQUAD
) );
282 static void *get_pixel_ptr( const BITMAPINFO
*info
, void *bits
, int x
, int y
)
284 const int width
= info
->bmiHeader
.biWidth
, height
= info
->bmiHeader
.biHeight
;
285 const int bpp
= info
->bmiHeader
.biBitCount
;
288 return (char *)bits
+ (height
- y
- 1) * get_dib_stride( width
, bpp
) + x
* bpp
/ 8;
290 return (char *)bits
+ y
* get_dib_stride( width
, bpp
) + x
* bpp
/ 8;
293 static BOOL
build_rle_bitmap( const BITMAPINFO
*info
, struct gdi_image_bits
*bits
, HRGN
*clip
)
297 int x
, y
, width
= info
->bmiHeader
.biWidth
, height
= info
->bmiHeader
.biHeight
;
299 BYTE skip
, num
, data
;
300 BYTE
*out_bits
, *in_bits
= bits
->ptr
;
302 if (clip
) *clip
= NULL
;
304 assert( info
->bmiHeader
.biBitCount
== 4 || info
->bmiHeader
.biBitCount
== 8 );
306 out_bits
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, get_dib_image_size( info
) );
307 if (!out_bits
) goto fail
;
311 *clip
= CreateRectRgn( 0, 0, 0, 0 );
312 run
= CreateRectRgn( 0, 0, 0, 0 );
313 if (!*clip
|| !run
) goto fail
;
316 x
= left
= right
= 0;
319 while (i
< info
->bmiHeader
.biSizeImage
- 1)
322 data
= in_bits
[i
+ 1];
327 if (x
+ num
> width
) num
= width
- x
;
330 BYTE s
= data
, *out_ptr
= get_pixel_ptr( info
, out_bits
, x
, y
);
331 if (info
->bmiHeader
.biBitCount
== 8)
332 memset( out_ptr
, s
, num
);
337 s
= ((s
>> 4) & 0x0f) | ((s
<< 4) & 0xf0);
338 *out_ptr
= (*out_ptr
& 0xf0) | (s
& 0x0f);
343 /* this will write one too many if num is odd, but that doesn't matter */
344 if (num
) memset( out_ptr
, s
, (num
+ 1) / 2 );
354 if(left
!= right
&& clip
)
356 SetRectRgn( run
, left
, y
, right
, y
+ 1 );
357 CombineRgn( *clip
, run
, *clip
, RGN_OR
);
362 left
= right
= x
= 0;
371 if (i
>= info
->bmiHeader
.biSizeImage
- 1) goto done
;
373 if (x
> width
) x
= width
;
380 else /* data bytes of data */
383 skip
= (num
* info
->bmiHeader
.biBitCount
+ 7) / 8;
384 if (skip
> info
->bmiHeader
.biSizeImage
- i
) goto done
;
385 skip
= (skip
+ 1) & ~1;
386 if (x
+ num
> width
) num
= width
- x
;
389 BYTE
*out_ptr
= get_pixel_ptr( info
, out_bits
, x
, y
);
390 if (info
->bmiHeader
.biBitCount
== 8)
391 memcpy( out_ptr
, in_bits
+ i
, num
);
396 const BYTE
*in_ptr
= in_bits
+ i
;
397 for ( ; num
; num
--, x
++)
401 *out_ptr
= (*out_ptr
& 0xf0) | ((*in_ptr
>> 4) & 0x0f);
405 *out_ptr
= (*in_ptr
++ << 4) & 0xf0;
409 memcpy( out_ptr
, in_bits
+ i
, (num
+ 1) / 2);
420 if (run
) DeleteObject( run
);
421 if (bits
->free
) bits
->free( bits
);
423 bits
->ptr
= out_bits
;
424 bits
->is_copy
= TRUE
;
425 bits
->free
= free_heap_bits
;
430 if (run
) DeleteObject( run
);
431 if (clip
&& *clip
) DeleteObject( *clip
);
432 HeapFree( GetProcessHeap(), 0, out_bits
);
438 INT
nulldrv_StretchDIBits( PHYSDEV dev
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
439 INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
, const void *bits
,
440 BITMAPINFO
*src_info
, UINT coloruse
, DWORD rop
)
442 DC
*dc
= get_nulldrv_dc( dev
);
443 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
444 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
445 struct bitblt_coords src
, dst
;
446 struct gdi_image_bits src_bits
;
450 INT height
= abs( src_info
->bmiHeader
.biHeight
);
451 BOOL top_down
= src_info
->bmiHeader
.biHeight
< 0, non_stretch_from_origin
= FALSE
;
454 TRACE("%d %d %d %d <- %d %d %d %d rop %08x\n", xDst
, yDst
, widthDst
, heightDst
,
455 xSrc
, ySrc
, widthSrc
, heightSrc
, rop
);
457 src_bits
.ptr
= (void*)bits
;
458 src_bits
.is_copy
= FALSE
;
459 src_bits
.free
= NULL
;
461 if (coloruse
== DIB_PAL_COLORS
&& !fill_color_table_from_pal_colors( src_info
, dev
->hdc
)) return 0;
465 rect
.right
= xDst
+ widthDst
;
466 rect
.bottom
= yDst
+ heightDst
;
467 LPtoDP( dc
->hSelf
, (POINT
*)&rect
, 2 );
470 dst
.width
= rect
.right
- rect
.left
;
471 dst
.height
= rect
.bottom
- rect
.top
;
473 if (dc
->layout
& LAYOUT_RTL
&& rop
& NOMIRRORBITMAP
)
476 dst
.width
= -dst
.width
;
478 rop
&= ~NOMIRRORBITMAP
;
481 src
.width
= widthSrc
;
483 src
.height
= heightSrc
;
485 if (src
.x
== 0 && src
.y
== 0 && src
.width
== dst
.width
&& src
.height
== dst
.height
)
486 non_stretch_from_origin
= TRUE
;
488 if (src_info
->bmiHeader
.biCompression
== BI_RLE4
|| src_info
->bmiHeader
.biCompression
== BI_RLE8
)
490 BOOL want_clip
= non_stretch_from_origin
&& (rop
== SRCCOPY
);
491 if (!build_rle_bitmap( src_info
, &src_bits
, want_clip
? &clip
: NULL
)) return 0;
494 if (rop
!= SRCCOPY
|| non_stretch_from_origin
)
496 if (dst
.width
== 1 && src
.width
> 1) src
.width
--;
497 if (dst
.height
== 1 && src
.height
> 1) src
.height
--;
502 if (dst
.width
< 0 && dst
.width
== src
.width
)
504 /* This is off-by-one, but that's what Windows does */
507 dst
.width
= -dst
.width
;
508 src
.width
= -src
.width
;
510 if (dst
.height
< 0 && dst
.height
== src
.height
)
514 dst
.height
= -dst
.height
;
515 src
.height
= -src
.height
;
519 if (!top_down
|| (rop
== SRCCOPY
&& !non_stretch_from_origin
)) src
.y
= height
- src
.y
- src
.height
;
521 if (src
.y
>= height
&& src
.y
+ src
.height
+ 1 < height
)
523 else if (src
.y
> 0 && src
.y
+ src
.height
+ 1 < 0)
524 src
.y
= -src
.height
- 1;
526 get_bounding_rect( &rect
, src
.x
, src
.y
, src
.width
, src
.height
);
528 src
.visrect
.left
= 0;
529 src
.visrect
.right
= src_info
->bmiHeader
.biWidth
;
531 src
.visrect
.bottom
= height
;
532 if (!intersect_rect( &src
.visrect
, &src
.visrect
, &rect
)) goto done
;
534 get_bounding_rect( &rect
, dst
.x
, dst
.y
, dst
.width
, dst
.height
);
536 if (!clip_visrect( dc
, &dst
.visrect
, &rect
)) goto done
;
538 if (!intersect_vis_rectangles( &dst
, &src
)) goto done
;
540 if (clip
) OffsetRgn( clip
, dst
.x
- src
.x
, dst
.y
- src
.y
);
542 dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
543 copy_bitmapinfo( dst_info
, src_info
);
544 err
= dev
->funcs
->pPutImage( dev
, 0, clip
, dst_info
, &src_bits
, &src
, &dst
, rop
);
545 if (err
== ERROR_BAD_FORMAT
)
547 /* 1-bpp destination without a color table requires a fake 1-entry table
548 * that contains only the background color */
549 if (dst_info
->bmiHeader
.biBitCount
== 1 && !dst_info
->bmiHeader
.biClrUsed
)
551 COLORREF color
= GetBkColor( dev
->hdc
);
552 dst_info
->bmiColors
[0].rgbRed
= GetRValue( color
);
553 dst_info
->bmiColors
[0].rgbGreen
= GetGValue( color
);
554 dst_info
->bmiColors
[0].rgbBlue
= GetBValue( color
);
555 dst_info
->bmiColors
[0].rgbReserved
= 0;
556 dst_info
->bmiHeader
.biClrUsed
= 1;
559 if (!(err
= convert_bits( src_info
, &src
, dst_info
, &src_bits
, FALSE
)))
561 /* get rid of the fake 1-bpp table */
562 if (dst_info
->bmiHeader
.biClrUsed
== 1) dst_info
->bmiHeader
.biClrUsed
= 0;
563 err
= dev
->funcs
->pPutImage( dev
, 0, clip
, dst_info
, &src_bits
, &src
, &dst
, rop
);
567 if (err
== ERROR_TRANSFORM_NOT_SUPPORTED
)
569 copy_bitmapinfo( src_info
, dst_info
);
570 err
= stretch_bits( src_info
, &src
, dst_info
, &dst
, &src_bits
, GetStretchBltMode( dev
->hdc
) );
571 if (!err
) err
= dev
->funcs
->pPutImage( dev
, 0, NULL
, dst_info
, &src_bits
, &src
, &dst
, rop
);
574 else if (rop
== SRCCOPY
) ret
= height
;
575 else ret
= src_info
->bmiHeader
.biHeight
;
578 if (src_bits
.free
) src_bits
.free( &src_bits
);
579 if (clip
) DeleteObject( clip
);
583 /***********************************************************************
584 * StretchDIBits (GDI32.@)
586 INT WINAPI
StretchDIBits(HDC hdc
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
587 INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
, const void *bits
,
588 const BITMAPINFO
*bmi
, UINT coloruse
, DWORD rop
)
590 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
591 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
596 if (!bitmapinfo_from_user_bitmapinfo( info
, bmi
, coloruse
, TRUE
))
598 SetLastError( ERROR_INVALID_PARAMETER
);
602 if ((dc
= get_dc_ptr( hdc
)))
604 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pStretchDIBits
);
606 ret
= physdev
->funcs
->pStretchDIBits( physdev
, xDst
, yDst
, widthDst
, heightDst
,
607 xSrc
, ySrc
, widthSrc
, heightSrc
, bits
, info
, coloruse
, rop
);
608 release_dc_ptr( dc
);
614 /******************************************************************************
615 * SetDIBits [GDI32.@]
617 * Sets pixels in a bitmap using colors from DIB.
620 * hdc [I] Handle to device context
621 * hbitmap [I] Handle to bitmap
622 * startscan [I] Starting scan line
623 * lines [I] Number of scan lines
624 * bits [I] Array of bitmap bits
625 * info [I] Address of structure with data
626 * coloruse [I] Type of color indexes to use
629 * Success: Number of scan lines copied
632 INT WINAPI
SetDIBits( HDC hdc
, HBITMAP hbitmap
, UINT startscan
,
633 UINT lines
, LPCVOID bits
, const BITMAPINFO
*info
,
637 char src_bmibuf
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
638 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_bmibuf
;
639 char dst_bmibuf
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
640 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_bmibuf
;
643 struct gdi_image_bits src_bits
;
644 struct bitblt_coords src
, dst
;
645 INT src_to_dst_offset
;
647 const struct gdi_dc_funcs
*funcs
;
649 if (!bitmapinfo_from_user_bitmapinfo( src_info
, info
, coloruse
, TRUE
) || coloruse
> DIB_PAL_COLORS
)
651 SetLastError( ERROR_INVALID_PARAMETER
);
654 if (src_info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
656 DWORD
*masks
= (DWORD
*)src_info
->bmiColors
;
657 if (!masks
[0] || !masks
[1] || !masks
[2])
659 SetLastError( ERROR_INVALID_PARAMETER
);
664 src_bits
.ptr
= (void *)bits
;
665 src_bits
.is_copy
= FALSE
;
666 src_bits
.free
= NULL
;
667 src_bits
.param
= NULL
;
669 if (coloruse
== DIB_PAL_COLORS
&& !fill_color_table_from_pal_colors( src_info
, hdc
)) return 0;
671 if (!(bitmap
= GDI_GetObjPtr( hbitmap
, OBJ_BITMAP
))) return 0;
673 if (src_info
->bmiHeader
.biCompression
== BI_RLE4
|| src_info
->bmiHeader
.biCompression
== BI_RLE8
)
675 if (lines
== 0) goto done
;
676 else lines
= src_info
->bmiHeader
.biHeight
;
679 if (!build_rle_bitmap( src_info
, &src_bits
, &clip
)) goto done
;
682 dst
.visrect
.left
= 0;
684 dst
.visrect
.right
= bitmap
->bitmap
.bmWidth
;
685 dst
.visrect
.bottom
= bitmap
->bitmap
.bmHeight
;
687 src
.visrect
.left
= 0;
689 src
.visrect
.right
= src_info
->bmiHeader
.biWidth
;
690 src
.visrect
.bottom
= abs( src_info
->bmiHeader
.biHeight
);
692 if (src_info
->bmiHeader
.biHeight
> 0)
694 src_to_dst_offset
= -startscan
;
695 lines
= min( lines
, src
.visrect
.bottom
- startscan
);
696 if (lines
< src
.visrect
.bottom
) src
.visrect
.top
= src
.visrect
.bottom
- lines
;
700 src_to_dst_offset
= src
.visrect
.bottom
- lines
- startscan
;
701 /* Unlike the bottom-up case, Windows doesn't limit lines. */
702 if (lines
< src
.visrect
.bottom
) src
.visrect
.bottom
= lines
;
705 funcs
= get_bitmap_funcs( bitmap
);
709 offset_rect( &src
.visrect
, 0, src_to_dst_offset
);
710 if (!intersect_rect( &dst
.visrect
, &src
.visrect
, &dst
.visrect
)) goto done
;
711 src
.visrect
= dst
.visrect
;
712 offset_rect( &src
.visrect
, 0, -src_to_dst_offset
);
714 src
.x
= src
.visrect
.left
;
715 src
.y
= src
.visrect
.top
;
716 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
717 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
719 dst
.x
= dst
.visrect
.left
;
720 dst
.y
= dst
.visrect
.top
;
721 dst
.width
= dst
.visrect
.right
- dst
.visrect
.left
;
722 dst
.height
= dst
.visrect
.bottom
- dst
.visrect
.top
;
724 copy_bitmapinfo( dst_info
, src_info
);
726 err
= funcs
->pPutImage( NULL
, hbitmap
, clip
, dst_info
, &src_bits
, &src
, &dst
, 0 );
727 if (err
== ERROR_BAD_FORMAT
)
729 err
= convert_bits( src_info
, &src
, dst_info
, &src_bits
, FALSE
);
730 if (!err
) err
= funcs
->pPutImage( NULL
, hbitmap
, clip
, dst_info
, &src_bits
, &src
, &dst
, 0 );
735 if (src_bits
.free
) src_bits
.free( &src_bits
);
736 if (clip
) DeleteObject( clip
);
737 GDI_ReleaseObj( hbitmap
);
742 INT
nulldrv_SetDIBitsToDevice( PHYSDEV dev
, INT x_dst
, INT y_dst
, DWORD cx
, DWORD cy
,
743 INT x_src
, INT y_src
, UINT startscan
, UINT lines
,
744 const void *bits
, BITMAPINFO
*src_info
, UINT coloruse
)
746 DC
*dc
= get_nulldrv_dc( dev
);
747 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
748 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
749 struct bitblt_coords src
, dst
;
750 struct gdi_image_bits src_bits
;
758 top_down
= (src_info
->bmiHeader
.biHeight
< 0);
759 height
= abs( src_info
->bmiHeader
.biHeight
);
761 src_bits
.ptr
= (void *)bits
;
762 src_bits
.is_copy
= FALSE
;
763 src_bits
.free
= NULL
;
765 if (!lines
) return 0;
766 if (coloruse
== DIB_PAL_COLORS
&& !fill_color_table_from_pal_colors( src_info
, dev
->hdc
)) return 0;
768 if (src_info
->bmiHeader
.biCompression
== BI_RLE4
|| src_info
->bmiHeader
.biCompression
== BI_RLE8
)
772 src_info
->bmiHeader
.biWidth
= x_src
+ cx
;
773 src_info
->bmiHeader
.biHeight
= y_src
+ cy
;
774 if (src_info
->bmiHeader
.biWidth
<= 0 || src_info
->bmiHeader
.biHeight
<= 0) return 0;
779 if (!build_rle_bitmap( src_info
, &src_bits
, &clip
)) return 0;
783 if (startscan
>= height
) return 0;
784 if (!top_down
&& lines
> height
- startscan
) lines
= height
- startscan
;
786 /* map src to top-down coordinates with startscan as origin */
788 src
.y
= startscan
+ lines
- (y_src
+ cy
);
795 /* get rid of unnecessary lines */
796 if (src
.y
>= lines
) return 0;
800 else if (src
.y
>= lines
) return lines
;
802 src_info
->bmiHeader
.biHeight
= top_down
? -lines
: lines
;
805 src
.visrect
.left
= src
.x
;
806 src
.visrect
.top
= src
.y
;
807 src
.visrect
.right
= src
.x
+ cx
;
808 src
.visrect
.bottom
= src
.y
+ cy
;
811 rect
.right
= src_info
->bmiHeader
.biWidth
;
812 rect
.bottom
= abs( src_info
->bmiHeader
.biHeight
);
813 if (!intersect_rect( &src
.visrect
, &src
.visrect
, &rect
))
821 LPtoDP( dev
->hdc
, &pt
, 1 );
826 if (GetLayout( dev
->hdc
) & LAYOUT_RTL
) dst
.x
-= cx
- 1;
830 rect
.right
= dst
.x
+ cx
;
831 rect
.bottom
= dst
.y
+ cy
;
832 if (!clip_visrect( dc
, &dst
.visrect
, &rect
)) goto done
;
834 offset_rect( &src
.visrect
, dst
.x
- src
.x
, dst
.y
- src
.y
);
835 intersect_rect( &rect
, &src
.visrect
, &dst
.visrect
);
836 src
.visrect
= dst
.visrect
= rect
;
837 offset_rect( &src
.visrect
, src
.x
- dst
.x
, src
.y
- dst
.y
);
838 if (is_rect_empty( &dst
.visrect
)) goto done
;
839 if (clip
) OffsetRgn( clip
, dst
.x
- src
.x
, dst
.y
- src
.y
);
841 dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
842 copy_bitmapinfo( dst_info
, src_info
);
843 err
= dev
->funcs
->pPutImage( dev
, 0, clip
, dst_info
, &src_bits
, &src
, &dst
, SRCCOPY
);
844 if (err
== ERROR_BAD_FORMAT
)
846 err
= convert_bits( src_info
, &src
, dst_info
, &src_bits
, FALSE
);
847 if (!err
) err
= dev
->funcs
->pPutImage( dev
, 0, clip
, dst_info
, &src_bits
, &src
, &dst
, SRCCOPY
);
852 if (src_bits
.free
) src_bits
.free( &src_bits
);
853 if (clip
) DeleteObject( clip
);
857 /***********************************************************************
858 * SetDIBitsToDevice (GDI32.@)
860 INT WINAPI
SetDIBitsToDevice(HDC hdc
, INT xDest
, INT yDest
, DWORD cx
,
861 DWORD cy
, INT xSrc
, INT ySrc
, UINT startscan
,
862 UINT lines
, LPCVOID bits
, const BITMAPINFO
*bmi
,
865 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
866 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
871 if (!bitmapinfo_from_user_bitmapinfo( info
, bmi
, coloruse
, TRUE
))
873 SetLastError( ERROR_INVALID_PARAMETER
);
877 if ((dc
= get_dc_ptr( hdc
)))
879 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetDIBitsToDevice
);
881 ret
= physdev
->funcs
->pSetDIBitsToDevice( physdev
, xDest
, yDest
, cx
, cy
, xSrc
,
882 ySrc
, startscan
, lines
, bits
, info
, coloruse
);
883 release_dc_ptr( dc
);
888 /***********************************************************************
889 * SetDIBColorTable (GDI32.@)
891 UINT WINAPI
SetDIBColorTable( HDC hdc
, UINT startpos
, UINT entries
, CONST RGBQUAD
*colors
)
897 if (!(dc
= get_dc_ptr( hdc
))) return 0;
899 if ((bitmap
= GDI_GetObjPtr( dc
->hBitmap
, OBJ_BITMAP
)))
901 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetDIBColorTable
);
903 /* Check if currently selected bitmap is a DIB */
904 if (bitmap
->color_table
)
906 if (startpos
< bitmap
->dib
->dsBmih
.biClrUsed
)
908 result
= min( entries
, bitmap
->dib
->dsBmih
.biClrUsed
- startpos
);
909 memcpy(bitmap
->color_table
+ startpos
, colors
, result
* sizeof(RGBQUAD
));
912 GDI_ReleaseObj( dc
->hBitmap
);
913 physdev
->funcs
->pSetDIBColorTable( physdev
, startpos
, entries
, colors
);
915 release_dc_ptr( dc
);
920 /***********************************************************************
921 * GetDIBColorTable (GDI32.@)
923 UINT WINAPI
GetDIBColorTable( HDC hdc
, UINT startpos
, UINT entries
, RGBQUAD
*colors
)
929 if (!(dc
= get_dc_ptr( hdc
))) return 0;
931 if ((bitmap
= GDI_GetObjPtr( dc
->hBitmap
, OBJ_BITMAP
)))
933 /* Check if currently selected bitmap is a DIB */
934 if (bitmap
->color_table
)
936 if (startpos
< bitmap
->dib
->dsBmih
.biClrUsed
)
938 result
= min( entries
, bitmap
->dib
->dsBmih
.biClrUsed
- startpos
);
939 memcpy(colors
, bitmap
->color_table
+ startpos
, result
* sizeof(RGBQUAD
));
942 GDI_ReleaseObj( dc
->hBitmap
);
944 release_dc_ptr( dc
);
948 static const DWORD bit_fields_888
[3] = {0xff0000, 0x00ff00, 0x0000ff};
949 static const DWORD bit_fields_565
[3] = {0xf800, 0x07e0, 0x001f};
950 static const DWORD bit_fields_555
[3] = {0x7c00, 0x03e0, 0x001f};
952 static int fill_query_info( BITMAPINFO
*info
, BITMAPOBJ
*bmp
)
954 BITMAPINFOHEADER header
;
956 header
.biSize
= info
->bmiHeader
.biSize
; /* Ensure we don't overwrite the original size when we copy back */
957 header
.biWidth
= bmp
->bitmap
.bmWidth
;
958 header
.biHeight
= bmp
->bitmap
.bmHeight
;
963 header
.biBitCount
= bmp
->dib
->dsBm
.bmBitsPixel
;
964 switch (bmp
->dib
->dsBm
.bmBitsPixel
)
968 header
.biCompression
= BI_BITFIELDS
;
971 header
.biCompression
= BI_RGB
;
977 header
.biCompression
= (bmp
->bitmap
.bmBitsPixel
> 8) ? BI_BITFIELDS
: BI_RGB
;
978 header
.biBitCount
= bmp
->bitmap
.bmBitsPixel
;
981 header
.biSizeImage
= get_dib_image_size( (BITMAPINFO
*)&header
);
982 header
.biXPelsPerMeter
= 0;
983 header
.biYPelsPerMeter
= 0;
984 header
.biClrUsed
= 0;
985 header
.biClrImportant
= 0;
987 if ( info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
) )
989 BITMAPCOREHEADER
*coreheader
= (BITMAPCOREHEADER
*)info
;
991 coreheader
->bcWidth
= header
.biWidth
;
992 coreheader
->bcHeight
= header
.biHeight
;
993 coreheader
->bcPlanes
= header
.biPlanes
;
994 coreheader
->bcBitCount
= header
.biBitCount
;
997 info
->bmiHeader
= header
;
999 return abs(bmp
->bitmap
.bmHeight
);
1002 /************************************************************************
1005 * Copy BITMAPINFO color information where dst may be a BITMAPCOREINFO.
1007 static void copy_color_info(BITMAPINFO
*dst
, const BITMAPINFO
*src
, UINT coloruse
)
1009 assert( src
->bmiHeader
.biSize
== sizeof(BITMAPINFOHEADER
) );
1011 if (dst
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1013 BITMAPCOREINFO
*core
= (BITMAPCOREINFO
*)dst
;
1014 if (coloruse
== DIB_PAL_COLORS
)
1015 memcpy( core
->bmciColors
, src
->bmiColors
, src
->bmiHeader
.biClrUsed
* sizeof(WORD
) );
1019 for (i
= 0; i
< src
->bmiHeader
.biClrUsed
; i
++)
1021 core
->bmciColors
[i
].rgbtRed
= src
->bmiColors
[i
].rgbRed
;
1022 core
->bmciColors
[i
].rgbtGreen
= src
->bmiColors
[i
].rgbGreen
;
1023 core
->bmciColors
[i
].rgbtBlue
= src
->bmiColors
[i
].rgbBlue
;
1029 dst
->bmiHeader
.biClrUsed
= src
->bmiHeader
.biClrUsed
;
1030 dst
->bmiHeader
.biSizeImage
= src
->bmiHeader
.biSizeImage
;
1032 if (src
->bmiHeader
.biCompression
== BI_BITFIELDS
)
1033 /* bitfields are always at bmiColors even in larger structures */
1034 memcpy( dst
->bmiColors
, src
->bmiColors
, 3 * sizeof(DWORD
) );
1035 else if (src
->bmiHeader
.biClrUsed
)
1037 void *colorptr
= (char *)dst
+ dst
->bmiHeader
.biSize
;
1040 if (coloruse
== DIB_PAL_COLORS
)
1041 size
= src
->bmiHeader
.biClrUsed
* sizeof(WORD
);
1043 size
= src
->bmiHeader
.biClrUsed
* sizeof(RGBQUAD
);
1044 memcpy( colorptr
, src
->bmiColors
, size
);
1049 const RGBQUAD
*get_default_color_table( int bpp
)
1051 static const RGBQUAD table_1
[2] =
1053 { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff }
1055 static const RGBQUAD table_4
[16] =
1057 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1058 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x80 },
1059 { 0xc0, 0xc0, 0xc0 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1060 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1062 static const RGBQUAD table_8
[256] =
1064 /* first and last 10 entries are the default system palette entries */
1065 { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x80 }, { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x80 },
1066 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x80 }, { 0x80, 0x80, 0x00 }, { 0xc0, 0xc0, 0xc0 },
1067 { 0xc0, 0xdc, 0xc0 }, { 0xf0, 0xca, 0xa6 }, { 0x00, 0x20, 0x40 }, { 0x00, 0x20, 0x60 },
1068 { 0x00, 0x20, 0x80 }, { 0x00, 0x20, 0xa0 }, { 0x00, 0x20, 0xc0 }, { 0x00, 0x20, 0xe0 },
1069 { 0x00, 0x40, 0x00 }, { 0x00, 0x40, 0x20 }, { 0x00, 0x40, 0x40 }, { 0x00, 0x40, 0x60 },
1070 { 0x00, 0x40, 0x80 }, { 0x00, 0x40, 0xa0 }, { 0x00, 0x40, 0xc0 }, { 0x00, 0x40, 0xe0 },
1071 { 0x00, 0x60, 0x00 }, { 0x00, 0x60, 0x20 }, { 0x00, 0x60, 0x40 }, { 0x00, 0x60, 0x60 },
1072 { 0x00, 0x60, 0x80 }, { 0x00, 0x60, 0xa0 }, { 0x00, 0x60, 0xc0 }, { 0x00, 0x60, 0xe0 },
1073 { 0x00, 0x80, 0x00 }, { 0x00, 0x80, 0x20 }, { 0x00, 0x80, 0x40 }, { 0x00, 0x80, 0x60 },
1074 { 0x00, 0x80, 0x80 }, { 0x00, 0x80, 0xa0 }, { 0x00, 0x80, 0xc0 }, { 0x00, 0x80, 0xe0 },
1075 { 0x00, 0xa0, 0x00 }, { 0x00, 0xa0, 0x20 }, { 0x00, 0xa0, 0x40 }, { 0x00, 0xa0, 0x60 },
1076 { 0x00, 0xa0, 0x80 }, { 0x00, 0xa0, 0xa0 }, { 0x00, 0xa0, 0xc0 }, { 0x00, 0xa0, 0xe0 },
1077 { 0x00, 0xc0, 0x00 }, { 0x00, 0xc0, 0x20 }, { 0x00, 0xc0, 0x40 }, { 0x00, 0xc0, 0x60 },
1078 { 0x00, 0xc0, 0x80 }, { 0x00, 0xc0, 0xa0 }, { 0x00, 0xc0, 0xc0 }, { 0x00, 0xc0, 0xe0 },
1079 { 0x00, 0xe0, 0x00 }, { 0x00, 0xe0, 0x20 }, { 0x00, 0xe0, 0x40 }, { 0x00, 0xe0, 0x60 },
1080 { 0x00, 0xe0, 0x80 }, { 0x00, 0xe0, 0xa0 }, { 0x00, 0xe0, 0xc0 }, { 0x00, 0xe0, 0xe0 },
1081 { 0x40, 0x00, 0x00 }, { 0x40, 0x00, 0x20 }, { 0x40, 0x00, 0x40 }, { 0x40, 0x00, 0x60 },
1082 { 0x40, 0x00, 0x80 }, { 0x40, 0x00, 0xa0 }, { 0x40, 0x00, 0xc0 }, { 0x40, 0x00, 0xe0 },
1083 { 0x40, 0x20, 0x00 }, { 0x40, 0x20, 0x20 }, { 0x40, 0x20, 0x40 }, { 0x40, 0x20, 0x60 },
1084 { 0x40, 0x20, 0x80 }, { 0x40, 0x20, 0xa0 }, { 0x40, 0x20, 0xc0 }, { 0x40, 0x20, 0xe0 },
1085 { 0x40, 0x40, 0x00 }, { 0x40, 0x40, 0x20 }, { 0x40, 0x40, 0x40 }, { 0x40, 0x40, 0x60 },
1086 { 0x40, 0x40, 0x80 }, { 0x40, 0x40, 0xa0 }, { 0x40, 0x40, 0xc0 }, { 0x40, 0x40, 0xe0 },
1087 { 0x40, 0x60, 0x00 }, { 0x40, 0x60, 0x20 }, { 0x40, 0x60, 0x40 }, { 0x40, 0x60, 0x60 },
1088 { 0x40, 0x60, 0x80 }, { 0x40, 0x60, 0xa0 }, { 0x40, 0x60, 0xc0 }, { 0x40, 0x60, 0xe0 },
1089 { 0x40, 0x80, 0x00 }, { 0x40, 0x80, 0x20 }, { 0x40, 0x80, 0x40 }, { 0x40, 0x80, 0x60 },
1090 { 0x40, 0x80, 0x80 }, { 0x40, 0x80, 0xa0 }, { 0x40, 0x80, 0xc0 }, { 0x40, 0x80, 0xe0 },
1091 { 0x40, 0xa0, 0x00 }, { 0x40, 0xa0, 0x20 }, { 0x40, 0xa0, 0x40 }, { 0x40, 0xa0, 0x60 },
1092 { 0x40, 0xa0, 0x80 }, { 0x40, 0xa0, 0xa0 }, { 0x40, 0xa0, 0xc0 }, { 0x40, 0xa0, 0xe0 },
1093 { 0x40, 0xc0, 0x00 }, { 0x40, 0xc0, 0x20 }, { 0x40, 0xc0, 0x40 }, { 0x40, 0xc0, 0x60 },
1094 { 0x40, 0xc0, 0x80 }, { 0x40, 0xc0, 0xa0 }, { 0x40, 0xc0, 0xc0 }, { 0x40, 0xc0, 0xe0 },
1095 { 0x40, 0xe0, 0x00 }, { 0x40, 0xe0, 0x20 }, { 0x40, 0xe0, 0x40 }, { 0x40, 0xe0, 0x60 },
1096 { 0x40, 0xe0, 0x80 }, { 0x40, 0xe0, 0xa0 }, { 0x40, 0xe0, 0xc0 }, { 0x40, 0xe0, 0xe0 },
1097 { 0x80, 0x00, 0x00 }, { 0x80, 0x00, 0x20 }, { 0x80, 0x00, 0x40 }, { 0x80, 0x00, 0x60 },
1098 { 0x80, 0x00, 0x80 }, { 0x80, 0x00, 0xa0 }, { 0x80, 0x00, 0xc0 }, { 0x80, 0x00, 0xe0 },
1099 { 0x80, 0x20, 0x00 }, { 0x80, 0x20, 0x20 }, { 0x80, 0x20, 0x40 }, { 0x80, 0x20, 0x60 },
1100 { 0x80, 0x20, 0x80 }, { 0x80, 0x20, 0xa0 }, { 0x80, 0x20, 0xc0 }, { 0x80, 0x20, 0xe0 },
1101 { 0x80, 0x40, 0x00 }, { 0x80, 0x40, 0x20 }, { 0x80, 0x40, 0x40 }, { 0x80, 0x40, 0x60 },
1102 { 0x80, 0x40, 0x80 }, { 0x80, 0x40, 0xa0 }, { 0x80, 0x40, 0xc0 }, { 0x80, 0x40, 0xe0 },
1103 { 0x80, 0x60, 0x00 }, { 0x80, 0x60, 0x20 }, { 0x80, 0x60, 0x40 }, { 0x80, 0x60, 0x60 },
1104 { 0x80, 0x60, 0x80 }, { 0x80, 0x60, 0xa0 }, { 0x80, 0x60, 0xc0 }, { 0x80, 0x60, 0xe0 },
1105 { 0x80, 0x80, 0x00 }, { 0x80, 0x80, 0x20 }, { 0x80, 0x80, 0x40 }, { 0x80, 0x80, 0x60 },
1106 { 0x80, 0x80, 0x80 }, { 0x80, 0x80, 0xa0 }, { 0x80, 0x80, 0xc0 }, { 0x80, 0x80, 0xe0 },
1107 { 0x80, 0xa0, 0x00 }, { 0x80, 0xa0, 0x20 }, { 0x80, 0xa0, 0x40 }, { 0x80, 0xa0, 0x60 },
1108 { 0x80, 0xa0, 0x80 }, { 0x80, 0xa0, 0xa0 }, { 0x80, 0xa0, 0xc0 }, { 0x80, 0xa0, 0xe0 },
1109 { 0x80, 0xc0, 0x00 }, { 0x80, 0xc0, 0x20 }, { 0x80, 0xc0, 0x40 }, { 0x80, 0xc0, 0x60 },
1110 { 0x80, 0xc0, 0x80 }, { 0x80, 0xc0, 0xa0 }, { 0x80, 0xc0, 0xc0 }, { 0x80, 0xc0, 0xe0 },
1111 { 0x80, 0xe0, 0x00 }, { 0x80, 0xe0, 0x20 }, { 0x80, 0xe0, 0x40 }, { 0x80, 0xe0, 0x60 },
1112 { 0x80, 0xe0, 0x80 }, { 0x80, 0xe0, 0xa0 }, { 0x80, 0xe0, 0xc0 }, { 0x80, 0xe0, 0xe0 },
1113 { 0xc0, 0x00, 0x00 }, { 0xc0, 0x00, 0x20 }, { 0xc0, 0x00, 0x40 }, { 0xc0, 0x00, 0x60 },
1114 { 0xc0, 0x00, 0x80 }, { 0xc0, 0x00, 0xa0 }, { 0xc0, 0x00, 0xc0 }, { 0xc0, 0x00, 0xe0 },
1115 { 0xc0, 0x20, 0x00 }, { 0xc0, 0x20, 0x20 }, { 0xc0, 0x20, 0x40 }, { 0xc0, 0x20, 0x60 },
1116 { 0xc0, 0x20, 0x80 }, { 0xc0, 0x20, 0xa0 }, { 0xc0, 0x20, 0xc0 }, { 0xc0, 0x20, 0xe0 },
1117 { 0xc0, 0x40, 0x00 }, { 0xc0, 0x40, 0x20 }, { 0xc0, 0x40, 0x40 }, { 0xc0, 0x40, 0x60 },
1118 { 0xc0, 0x40, 0x80 }, { 0xc0, 0x40, 0xa0 }, { 0xc0, 0x40, 0xc0 }, { 0xc0, 0x40, 0xe0 },
1119 { 0xc0, 0x60, 0x00 }, { 0xc0, 0x60, 0x20 }, { 0xc0, 0x60, 0x40 }, { 0xc0, 0x60, 0x60 },
1120 { 0xc0, 0x60, 0x80 }, { 0xc0, 0x60, 0xa0 }, { 0xc0, 0x60, 0xc0 }, { 0xc0, 0x60, 0xe0 },
1121 { 0xc0, 0x80, 0x00 }, { 0xc0, 0x80, 0x20 }, { 0xc0, 0x80, 0x40 }, { 0xc0, 0x80, 0x60 },
1122 { 0xc0, 0x80, 0x80 }, { 0xc0, 0x80, 0xa0 }, { 0xc0, 0x80, 0xc0 }, { 0xc0, 0x80, 0xe0 },
1123 { 0xc0, 0xa0, 0x00 }, { 0xc0, 0xa0, 0x20 }, { 0xc0, 0xa0, 0x40 }, { 0xc0, 0xa0, 0x60 },
1124 { 0xc0, 0xa0, 0x80 }, { 0xc0, 0xa0, 0xa0 }, { 0xc0, 0xa0, 0xc0 }, { 0xc0, 0xa0, 0xe0 },
1125 { 0xc0, 0xc0, 0x00 }, { 0xc0, 0xc0, 0x20 }, { 0xc0, 0xc0, 0x40 }, { 0xc0, 0xc0, 0x60 },
1126 { 0xc0, 0xc0, 0x80 }, { 0xc0, 0xc0, 0xa0 }, { 0xf0, 0xfb, 0xff }, { 0xa4, 0xa0, 0xa0 },
1127 { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xff }, { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0xff },
1128 { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0xff }, { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff },
1133 case 1: return table_1
;
1134 case 4: return table_4
;
1135 case 8: return table_8
;
1136 default: return NULL
;
1140 void fill_default_color_table( BITMAPINFO
*info
)
1142 info
->bmiHeader
.biClrUsed
= 1 << info
->bmiHeader
.biBitCount
;
1143 memcpy( info
->bmiColors
, get_default_color_table( info
->bmiHeader
.biBitCount
),
1144 info
->bmiHeader
.biClrUsed
* sizeof(RGBQUAD
) );
1147 void get_ddb_bitmapinfo( BITMAPOBJ
*bmp
, BITMAPINFO
*info
)
1149 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
1150 info
->bmiHeader
.biWidth
= bmp
->bitmap
.bmWidth
;
1151 info
->bmiHeader
.biHeight
= -bmp
->bitmap
.bmHeight
;
1152 info
->bmiHeader
.biPlanes
= 1;
1153 info
->bmiHeader
.biBitCount
= bmp
->bitmap
.bmBitsPixel
;
1154 info
->bmiHeader
.biCompression
= BI_RGB
;
1155 info
->bmiHeader
.biXPelsPerMeter
= 0;
1156 info
->bmiHeader
.biYPelsPerMeter
= 0;
1157 info
->bmiHeader
.biClrUsed
= 0;
1158 info
->bmiHeader
.biClrImportant
= 0;
1161 BITMAPINFO
*copy_packed_dib( const BITMAPINFO
*src_info
, UINT usage
)
1163 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
1164 BITMAPINFO
*ret
, *info
= (BITMAPINFO
*)buffer
;
1165 unsigned int info_size
;
1167 if (!bitmapinfo_from_user_bitmapinfo( info
, src_info
, usage
, FALSE
)) return NULL
;
1169 info_size
= get_dib_info_size( info
, usage
);
1170 if ((ret
= HeapAlloc( GetProcessHeap(), 0, info_size
+ info
->bmiHeader
.biSizeImage
)))
1172 memcpy( ret
, info
, info_size
);
1173 memcpy( (char *)ret
+ info_size
, (char *)src_info
+ bitmap_info_size( src_info
, usage
),
1174 info
->bmiHeader
.biSizeImage
);
1179 /******************************************************************************
1180 * GetDIBits [GDI32.@]
1182 * Retrieves bits of bitmap and copies to buffer.
1185 * Success: Number of scan lines copied from bitmap
1188 INT WINAPI
GetDIBits(
1189 HDC hdc
, /* [in] Handle to device context */
1190 HBITMAP hbitmap
, /* [in] Handle to bitmap */
1191 UINT startscan
, /* [in] First scan line to set in dest bitmap */
1192 UINT lines
, /* [in] Number of scan lines to copy */
1193 LPVOID bits
, /* [out] Address of array for bitmap bits */
1194 BITMAPINFO
* info
, /* [out] Address of structure with bitmap data */
1195 UINT coloruse
) /* [in] RGB or palette index */
1199 int i
, dst_to_src_offset
, ret
= 0;
1201 char dst_bmibuf
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
1202 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_bmibuf
;
1203 char src_bmibuf
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
1204 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_bmibuf
;
1205 const struct gdi_dc_funcs
*funcs
;
1206 struct gdi_image_bits src_bits
;
1207 struct bitblt_coords src
, dst
;
1208 BOOL empty_rect
= FALSE
;
1210 /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our
1211 own copy and transfer the colour info back at the end */
1212 if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info
->bmiHeader
, &info
->bmiHeader
)) return 0;
1213 if (coloruse
> DIB_PAL_COLORS
) return 0;
1215 (dst_info
->bmiHeader
.biCompression
== BI_JPEG
|| dst_info
->bmiHeader
.biCompression
== BI_PNG
))
1217 dst_info
->bmiHeader
.biClrUsed
= 0;
1218 dst_info
->bmiHeader
.biClrImportant
= 0;
1220 if (!(dc
= get_dc_ptr( hdc
)))
1222 SetLastError( ERROR_INVALID_PARAMETER
);
1226 if (!(bmp
= GDI_GetObjPtr( hbitmap
, OBJ_BITMAP
)))
1228 release_dc_ptr( dc
);
1232 funcs
= get_bitmap_funcs( bmp
);
1234 src
.visrect
.left
= 0;
1235 src
.visrect
.top
= 0;
1236 src
.visrect
.right
= bmp
->bitmap
.bmWidth
;
1237 src
.visrect
.bottom
= bmp
->bitmap
.bmHeight
;
1239 dst
.visrect
.left
= 0;
1240 dst
.visrect
.top
= 0;
1241 dst
.visrect
.right
= dst_info
->bmiHeader
.biWidth
;
1242 dst
.visrect
.bottom
= abs( dst_info
->bmiHeader
.biHeight
);
1244 if (lines
== 0 || startscan
>= dst
.visrect
.bottom
)
1247 if (!bits
&& dst_info
->bmiHeader
.biBitCount
== 0) /* query bitmap info only */
1249 ret
= fill_query_info( info
, bmp
);
1253 /* validate parameters */
1255 if (dst_info
->bmiHeader
.biWidth
<= 0) goto done
;
1256 if (dst_info
->bmiHeader
.biHeight
== 0) goto done
;
1258 switch (dst_info
->bmiHeader
.biCompression
)
1261 if (dst_info
->bmiHeader
.biBitCount
!= 4) goto done
;
1262 if (dst_info
->bmiHeader
.biHeight
< 0) goto done
;
1263 if (bits
) goto done
; /* can't retrieve compressed bits */
1266 if (dst_info
->bmiHeader
.biBitCount
!= 8) goto done
;
1267 if (dst_info
->bmiHeader
.biHeight
< 0) goto done
;
1268 if (bits
) goto done
; /* can't retrieve compressed bits */
1271 if (dst_info
->bmiHeader
.biBitCount
!= 16 && dst_info
->bmiHeader
.biBitCount
!= 32) goto done
;
1274 if (lines
&& !dst_info
->bmiHeader
.biPlanes
) goto done
;
1275 if (dst_info
->bmiHeader
.biBitCount
== 1) break;
1276 if (dst_info
->bmiHeader
.biBitCount
== 4) break;
1277 if (dst_info
->bmiHeader
.biBitCount
== 8) break;
1278 if (dst_info
->bmiHeader
.biBitCount
== 16) break;
1279 if (dst_info
->bmiHeader
.biBitCount
== 24) break;
1280 if (dst_info
->bmiHeader
.biBitCount
== 32) break;
1288 if (dst_info
->bmiHeader
.biHeight
> 0)
1290 dst_to_src_offset
= -startscan
;
1291 lines
= min( lines
, dst
.visrect
.bottom
- startscan
);
1292 if (lines
< dst
.visrect
.bottom
) dst
.visrect
.top
= dst
.visrect
.bottom
- lines
;
1296 dst_to_src_offset
= dst
.visrect
.bottom
- lines
- startscan
;
1297 if (dst_to_src_offset
< 0)
1299 dst_to_src_offset
= 0;
1300 lines
= dst
.visrect
.bottom
- startscan
;
1302 if (lines
< dst
.visrect
.bottom
) dst
.visrect
.bottom
= lines
;
1305 offset_rect( &dst
.visrect
, 0, dst_to_src_offset
);
1306 empty_rect
= !intersect_rect( &src
.visrect
, &src
.visrect
, &dst
.visrect
);
1307 dst
.visrect
= src
.visrect
;
1308 offset_rect( &dst
.visrect
, 0, -dst_to_src_offset
);
1310 if (dst_info
->bmiHeader
.biHeight
> 0)
1312 if (dst
.visrect
.bottom
< dst_info
->bmiHeader
.biHeight
)
1314 int pad_lines
= min( dst_info
->bmiHeader
.biHeight
- dst
.visrect
.bottom
, lines
);
1315 int pad_bytes
= pad_lines
* get_dib_stride( dst_info
->bmiHeader
.biWidth
, dst_info
->bmiHeader
.biBitCount
);
1316 memset( bits
, 0, pad_bytes
);
1317 bits
= (char *)bits
+ pad_bytes
;
1322 if (dst
.visrect
.bottom
< lines
)
1324 int pad_lines
= lines
- dst
.visrect
.bottom
;
1325 int stride
= get_dib_stride( dst_info
->bmiHeader
.biWidth
, dst_info
->bmiHeader
.biBitCount
);
1326 int pad_bytes
= pad_lines
* stride
;
1327 memset( (char *)bits
+ dst
.visrect
.bottom
* stride
, 0, pad_bytes
);
1331 if (empty_rect
) bits
= NULL
;
1333 src
.x
= src
.visrect
.left
;
1334 src
.y
= src
.visrect
.top
;
1335 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
1336 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
1341 err
= funcs
->pGetImage( NULL
, hbitmap
, src_info
, bits
? &src_bits
: NULL
, bits
? &src
: NULL
);
1345 /* fill out the src colour table, if it needs one */
1346 if (src_info
->bmiHeader
.biBitCount
<= 8 && src_info
->bmiHeader
.biClrUsed
== 0)
1347 fill_default_color_table( src_info
);
1349 /* if the src and dst are the same depth, copy the colour info across */
1350 if (dst_info
->bmiHeader
.biBitCount
== src_info
->bmiHeader
.biBitCount
&& coloruse
== DIB_RGB_COLORS
)
1352 switch (src_info
->bmiHeader
.biBitCount
)
1355 if (src_info
->bmiHeader
.biCompression
== BI_RGB
)
1357 src_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1358 memcpy( src_info
->bmiColors
, bit_fields_555
, sizeof(bit_fields_555
) );
1362 if (src_info
->bmiHeader
.biCompression
== BI_RGB
)
1364 src_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1365 memcpy( src_info
->bmiColors
, bit_fields_888
, sizeof(bit_fields_888
) );
1369 src_info
->bmiHeader
.biSizeImage
= get_dib_image_size( dst_info
);
1370 copy_color_info( dst_info
, src_info
, coloruse
);
1372 else if (dst_info
->bmiHeader
.biBitCount
<= 8) /* otherwise construct a default colour table for the dst, if needed */
1374 if( coloruse
== DIB_PAL_COLORS
)
1376 if (!fill_color_table_from_palette( dst_info
, hdc
)) goto done
;
1380 fill_default_color_table( dst_info
);
1386 if(dst_info
->bmiHeader
.biHeight
> 0)
1387 dst_info
->bmiHeader
.biHeight
= src
.height
;
1389 dst_info
->bmiHeader
.biHeight
= -src
.height
;
1391 convert_bitmapinfo( src_info
, src_bits
.ptr
, &src
, dst_info
, bits
, FALSE
);
1392 if (src_bits
.free
) src_bits
.free( &src_bits
);
1396 ret
= empty_rect
? FALSE
: TRUE
;
1398 if (coloruse
== DIB_PAL_COLORS
)
1400 WORD
*index
= (WORD
*)dst_info
->bmiColors
;
1401 for (i
= 0; i
< dst_info
->bmiHeader
.biClrUsed
; i
++, index
++)
1405 copy_color_info( info
, dst_info
, coloruse
);
1406 if (info
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
)) info
->bmiHeader
.biClrUsed
= 0;
1409 release_dc_ptr( dc
);
1410 GDI_ReleaseObj( hbitmap
);
1415 /***********************************************************************
1416 * CreateDIBitmap (GDI32.@)
1418 * Creates a DDB (device dependent bitmap) from a DIB.
1419 * The DDB will have the same color depth as the reference DC.
1421 HBITMAP WINAPI
CreateDIBitmap( HDC hdc
, const BITMAPINFOHEADER
*header
,
1422 DWORD init
, LPCVOID bits
, const BITMAPINFO
*data
,
1425 BITMAPINFOHEADER info
;
1429 if (!bitmapinfoheader_from_user_bitmapinfo( &info
, header
)) return 0;
1430 if (info
.biCompression
== BI_JPEG
|| info
.biCompression
== BI_PNG
) return 0;
1431 if (coloruse
> DIB_PAL_COLORS
+ 1) return 0;
1432 if (info
.biWidth
< 0) return 0;
1434 /* Top-down DIBs have a negative height */
1435 height
= abs( info
.biHeight
);
1437 TRACE("hdc=%p, header=%p, init=%u, bits=%p, data=%p, coloruse=%u (bitmap: width=%d, height=%d, bpp=%u, compr=%u)\n",
1438 hdc
, header
, init
, bits
, data
, coloruse
, info
.biWidth
, info
.biHeight
,
1439 info
.biBitCount
, info
.biCompression
);
1442 handle
= CreateBitmap( info
.biWidth
, height
, 1, 1, NULL
);
1444 handle
= CreateCompatibleBitmap( hdc
, info
.biWidth
, height
);
1448 if (init
& CBM_INIT
)
1450 if (SetDIBits( hdc
, handle
, 0, height
, bits
, data
, coloruse
) == 0)
1452 DeleteObject( handle
);
1462 /***********************************************************************
1463 * CreateDIBSection (GDI32.@)
1465 HBITMAP WINAPI
CreateDIBSection(HDC hdc
, CONST BITMAPINFO
*bmi
, UINT usage
,
1466 VOID
**bits
, HANDLE section
, DWORD offset
)
1468 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
1469 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
1472 BOOL bDesktopDC
= FALSE
;
1475 RGBQUAD
*color_table
= NULL
;
1476 void *mapBits
= NULL
;
1478 if (bits
) *bits
= NULL
;
1479 if (!bitmapinfo_from_user_bitmapinfo( info
, bmi
, usage
, FALSE
)) return 0;
1480 if (usage
> DIB_PAL_COLORS
) return 0;
1481 if (info
->bmiHeader
.biPlanes
!= 1)
1483 if (info
->bmiHeader
.biPlanes
* info
->bmiHeader
.biBitCount
> 16) return 0;
1484 WARN( "%u planes not properly supported\n", info
->bmiHeader
.biPlanes
);
1487 if (!(dib
= HeapAlloc( GetProcessHeap(), 0, sizeof(*dib
) ))) return 0;
1489 TRACE("format (%d,%d), planes %d, bpp %d, %s, size %d %s\n",
1490 info
->bmiHeader
.biWidth
, info
->bmiHeader
.biHeight
,
1491 info
->bmiHeader
.biPlanes
, info
->bmiHeader
.biBitCount
,
1492 info
->bmiHeader
.biCompression
== BI_BITFIELDS
? "BI_BITFIELDS" : "BI_RGB",
1493 info
->bmiHeader
.biSizeImage
, usage
== DIB_PAL_COLORS
? "PAL" : "RGB");
1495 dib
->dsBm
.bmType
= 0;
1496 dib
->dsBm
.bmWidth
= info
->bmiHeader
.biWidth
;
1497 dib
->dsBm
.bmHeight
= abs( info
->bmiHeader
.biHeight
);
1498 dib
->dsBm
.bmWidthBytes
= get_dib_stride( info
->bmiHeader
.biWidth
, info
->bmiHeader
.biBitCount
);
1499 dib
->dsBm
.bmPlanes
= info
->bmiHeader
.biPlanes
;
1500 dib
->dsBm
.bmBitsPixel
= info
->bmiHeader
.biBitCount
;
1501 dib
->dsBm
.bmBits
= NULL
;
1502 dib
->dsBmih
= info
->bmiHeader
;
1504 if (info
->bmiHeader
.biBitCount
<= 8) /* build the color table */
1506 if (usage
== DIB_PAL_COLORS
&& !fill_color_table_from_pal_colors( info
, hdc
))
1508 dib
->dsBmih
.biClrUsed
= info
->bmiHeader
.biClrUsed
;
1509 if (!(color_table
= HeapAlloc( GetProcessHeap(), 0, dib
->dsBmih
.biClrUsed
* sizeof(RGBQUAD
) )))
1511 memcpy( color_table
, info
->bmiColors
, dib
->dsBmih
.biClrUsed
* sizeof(RGBQUAD
) );
1514 /* set dsBitfields values */
1515 if (info
->bmiHeader
.biBitCount
== 16 && info
->bmiHeader
.biCompression
== BI_RGB
)
1517 dib
->dsBmih
.biCompression
= BI_BITFIELDS
;
1518 dib
->dsBitfields
[0] = 0x7c00;
1519 dib
->dsBitfields
[1] = 0x03e0;
1520 dib
->dsBitfields
[2] = 0x001f;
1522 else if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
1524 if (usage
== DIB_PAL_COLORS
) goto error
;
1525 dib
->dsBitfields
[0] = *(const DWORD
*)info
->bmiColors
;
1526 dib
->dsBitfields
[1] = *((const DWORD
*)info
->bmiColors
+ 1);
1527 dib
->dsBitfields
[2] = *((const DWORD
*)info
->bmiColors
+ 2);
1528 if (!dib
->dsBitfields
[0] || !dib
->dsBitfields
[1] || !dib
->dsBitfields
[2]) goto error
;
1530 else dib
->dsBitfields
[0] = dib
->dsBitfields
[1] = dib
->dsBitfields
[2] = 0;
1532 /* get storage location for DIB bits */
1536 SYSTEM_INFO SystemInfo
;
1540 GetSystemInfo( &SystemInfo
);
1541 mapOffset
= offset
- (offset
% SystemInfo
.dwAllocationGranularity
);
1542 mapSize
= dib
->dsBmih
.biSizeImage
+ (offset
- mapOffset
);
1543 mapBits
= MapViewOfFile( section
, FILE_MAP_ALL_ACCESS
, 0, mapOffset
, mapSize
);
1544 if (mapBits
) dib
->dsBm
.bmBits
= (char *)mapBits
+ (offset
- mapOffset
);
1549 dib
->dsBm
.bmBits
= VirtualAlloc( NULL
, dib
->dsBmih
.biSizeImage
,
1550 MEM_RESERVE
|MEM_COMMIT
, PAGE_READWRITE
);
1552 dib
->dshSection
= section
;
1553 dib
->dsOffset
= offset
;
1555 if (!dib
->dsBm
.bmBits
) goto error
;
1557 /* If the reference hdc is null, take the desktop dc */
1560 hdc
= CreateCompatibleDC(0);
1564 if (!(dc
= get_dc_ptr( hdc
))) goto error
;
1566 /* create Device Dependent Bitmap and add DIB pointer */
1567 ret
= CreateBitmap( dib
->dsBm
.bmWidth
, dib
->dsBm
.bmHeight
, 1,
1568 (info
->bmiHeader
.biBitCount
== 1) ? 1 : GetDeviceCaps(hdc
, BITSPIXEL
), NULL
);
1570 if (ret
&& ((bmp
= GDI_GetObjPtr(ret
, OBJ_BITMAP
))))
1572 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pCreateDIBSection
);
1574 bmp
->funcs
= physdev
->funcs
;
1575 bmp
->color_table
= color_table
;
1576 GDI_ReleaseObj( ret
);
1578 if (!physdev
->funcs
->pCreateDIBSection( physdev
, ret
, info
, usage
))
1580 DeleteObject( ret
);
1585 release_dc_ptr( dc
);
1586 if (bDesktopDC
) DeleteDC( hdc
);
1587 if (ret
&& bits
) *bits
= dib
->dsBm
.bmBits
;
1591 if (bDesktopDC
) DeleteDC( hdc
);
1592 if (section
) UnmapViewOfFile( mapBits
);
1593 else if (!offset
) VirtualFree( dib
->dsBm
.bmBits
, 0, MEM_RELEASE
);
1594 HeapFree( GetProcessHeap(), 0, color_table
);
1595 HeapFree( GetProcessHeap(), 0, dib
);