4 * Copyright 1993 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "ntgdi_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitmap
);
39 static INT
BITMAP_GetObject( HGDIOBJ handle
, INT count
, LPVOID buffer
);
40 static BOOL
BITMAP_DeleteObject( HGDIOBJ handle
);
42 static const struct gdi_obj_funcs bitmap_funcs
=
44 BITMAP_GetObject
, /* pGetObjectW */
45 NULL
, /* pUnrealizeObject */
46 BITMAP_DeleteObject
/* pDeleteObject */
50 /******************************************************************************
51 * NtGdiCreateCompatibleBitmap (win32u.@)
53 * Creates a bitmap compatible with the DC.
55 HBITMAP WINAPI
NtGdiCreateCompatibleBitmap( HDC hdc
, INT width
, INT height
)
57 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
58 BITMAPINFO
*bi
= (BITMAPINFO
*)buffer
;
61 TRACE( "(%p,%d,%d)\n", hdc
, width
, height
);
63 if (!width
|| !height
) return 0;
65 if (get_gdi_object_type( hdc
) != NTGDI_OBJ_MEMDC
)
66 return NtGdiCreateBitmap( width
, height
,
67 NtGdiGetDeviceCaps( hdc
, PLANES
),
68 NtGdiGetDeviceCaps( hdc
, BITSPIXEL
), NULL
);
70 switch (NtGdiExtGetObjectW( NtGdiGetDCObject( hdc
, NTGDI_OBJ_SURF
),
73 case sizeof(BITMAP
): /* A device-dependent bitmap is selected in the DC */
74 return NtGdiCreateBitmap( width
, height
, dib
.dsBm
.bmPlanes
, dib
.dsBm
.bmBitsPixel
, NULL
);
76 case sizeof(DIBSECTION
): /* A DIB section is selected in the DC */
77 bi
->bmiHeader
= dib
.dsBmih
;
78 bi
->bmiHeader
.biWidth
= width
;
79 bi
->bmiHeader
.biHeight
= height
;
80 if (dib
.dsBmih
.biCompression
== BI_BITFIELDS
) /* copy the color masks */
81 memcpy( bi
->bmiColors
, dib
.dsBitfields
, sizeof(dib
.dsBitfields
) );
82 else if (dib
.dsBmih
.biBitCount
<= 8) /* copy the color table */
83 NtGdiDoPalette( hdc
, 0, 256, bi
->bmiColors
, NtGdiGetDIBColorTable
, FALSE
);
84 return NtGdiCreateDIBSection( hdc
, NULL
, 0, bi
, DIB_RGB_COLORS
, 0, 0, 0, NULL
);
92 /******************************************************************************
93 * NtGdiCreateBitmap (win32u.@)
95 * Creates a bitmap with the specified info.
97 HBITMAP WINAPI
NtGdiCreateBitmap( INT width
, INT height
, UINT planes
,
98 UINT bpp
, const void *bits
)
105 if (width
> 0x7ffffff || height
> 0x7ffffff)
107 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
111 if (!width
|| !height
)
121 FIXME("planes = %d\n", planes
);
122 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
126 /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */
127 if(bpp
== 1) bpp
= 1;
128 else if(bpp
<= 4) bpp
= 4;
129 else if(bpp
<= 8) bpp
= 8;
130 else if(bpp
<= 16) bpp
= 16;
131 else if(bpp
<= 24) bpp
= 24;
132 else if(bpp
<= 32) bpp
= 32;
135 WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bpp
);
136 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER
);
140 dib_stride
= get_dib_stride( width
, bpp
);
141 size
= dib_stride
* height
;
142 /* Check for overflow (dib_stride itself must be ok because of the constraint on bm.bmWidth above). */
143 if (dib_stride
!= size
/ height
)
145 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
149 /* Create the BITMAPOBJ */
150 if (!(bmpobj
= calloc( 1, sizeof(*bmpobj
) )))
152 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY
);
156 bmpobj
->dib
.dsBm
.bmType
= 0;
157 bmpobj
->dib
.dsBm
.bmWidth
= width
;
158 bmpobj
->dib
.dsBm
.bmHeight
= height
;
159 bmpobj
->dib
.dsBm
.bmWidthBytes
= get_bitmap_stride( width
, bpp
);
160 bmpobj
->dib
.dsBm
.bmPlanes
= planes
;
161 bmpobj
->dib
.dsBm
.bmBitsPixel
= bpp
;
162 bmpobj
->dib
.dsBm
.bmBits
= calloc( 1, size
);
163 if (!bmpobj
->dib
.dsBm
.bmBits
)
166 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY
);
170 if (!(hbitmap
= alloc_gdi_handle( &bmpobj
->obj
, NTGDI_OBJ_BITMAP
, &bitmap_funcs
)))
172 free( bmpobj
->dib
.dsBm
.bmBits
);
178 NtGdiSetBitmapBits( hbitmap
, height
* bmpobj
->dib
.dsBm
.bmWidthBytes
, bits
);
180 TRACE("%dx%d, bpp %d planes %d: returning %p\n", width
, height
, bpp
, planes
, hbitmap
);
185 /***********************************************************************
186 * NtGdiGetBitmapBits (win32u.@)
188 * Copies bitmap bits of bitmap to buffer.
191 * Success: Number of bytes copied
194 LONG WINAPI
NtGdiGetBitmapBits(
195 HBITMAP hbitmap
, /* [in] Handle to bitmap */
196 LONG count
, /* [in] Number of bytes to copy */
197 LPVOID bits
) /* [out] Pointer to buffer to receive bits */
199 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
200 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
201 struct gdi_image_bits src_bits
;
202 struct bitblt_coords src
;
203 int dst_stride
, max
, ret
;
204 BITMAPOBJ
*bmp
= GDI_GetObjPtr( hbitmap
, NTGDI_OBJ_BITMAP
);
208 dst_stride
= get_bitmap_stride( bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmBitsPixel
);
209 ret
= max
= dst_stride
* bmp
->dib
.dsBm
.bmHeight
;
210 if (!bits
) goto done
;
211 if (count
< 0 || count
> max
) count
= max
;
214 src
.visrect
.left
= 0;
215 src
.visrect
.right
= bmp
->dib
.dsBm
.bmWidth
;
217 src
.visrect
.bottom
= (count
+ dst_stride
- 1) / dst_stride
;
219 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
220 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
222 if (!get_image_from_bitmap( bmp
, info
, &src_bits
, &src
))
224 const char *src_ptr
= src_bits
.ptr
;
225 int src_stride
= info
->bmiHeader
.biSizeImage
/ abs( info
->bmiHeader
.biHeight
);
227 /* GetBitmapBits returns 16-bit aligned data */
229 if (info
->bmiHeader
.biHeight
> 0)
231 src_ptr
+= (info
->bmiHeader
.biHeight
- 1) * src_stride
;
232 src_stride
= -src_stride
;
234 src_ptr
+= src
.visrect
.top
* src_stride
;
236 if (src_stride
== dst_stride
) memcpy( bits
, src_ptr
, count
);
237 else while (count
> 0)
239 memcpy( bits
, src_ptr
, min( count
, dst_stride
) );
240 src_ptr
+= src_stride
;
241 bits
= (char *)bits
+ dst_stride
;
244 if (src_bits
.free
) src_bits
.free( &src_bits
);
249 GDI_ReleaseObj( hbitmap
);
254 /******************************************************************************
255 * NtGdiSetBitmapBits (win32u.@)
257 * Sets bits of color data for a bitmap.
260 * Success: Number of bytes used in setting the bitmap bits
263 LONG WINAPI
NtGdiSetBitmapBits(
264 HBITMAP hbitmap
, /* [in] Handle to bitmap */
265 LONG count
, /* [in] Number of bytes in bitmap array */
266 LPCVOID bits
) /* [in] Address of array with bitmap bits */
268 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
269 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
272 int i
, src_stride
, dst_stride
;
273 struct bitblt_coords src
, dst
;
274 struct gdi_image_bits src_bits
;
279 bmp
= GDI_GetObjPtr( hbitmap
, NTGDI_OBJ_BITMAP
);
283 WARN("(%d): Negative number of bytes passed???\n", (int)count
);
287 src_stride
= get_bitmap_stride( bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmBitsPixel
);
288 count
= min( count
, src_stride
* bmp
->dib
.dsBm
.bmHeight
);
290 dst_stride
= get_dib_stride( bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmBitsPixel
);
292 src
.visrect
.left
= src
.x
= 0;
293 src
.visrect
.top
= src
.y
= 0;
294 src
.visrect
.right
= src
.width
= bmp
->dib
.dsBm
.bmWidth
;
295 src
.visrect
.bottom
= src
.height
= (count
+ src_stride
- 1 ) / src_stride
;
298 if (count
% src_stride
)
301 int extra_pixels
= ((count
% src_stride
) << 3) / bmp
->dib
.dsBm
.bmBitsPixel
;
303 if ((count
% src_stride
<< 3) % bmp
->dib
.dsBm
.bmBitsPixel
)
304 FIXME( "Unhandled partial pixel\n" );
305 clip
= NtGdiCreateRectRgn( src
.visrect
.left
, src
.visrect
.top
,
306 src
.visrect
.right
, src
.visrect
.bottom
- 1 );
307 last_row
= NtGdiCreateRectRgn( src
.visrect
.left
, src
.visrect
.bottom
- 1,
308 src
.visrect
.left
+ extra_pixels
, src
.visrect
.bottom
);
309 NtGdiCombineRgn( clip
, clip
, last_row
, RGN_OR
);
310 NtGdiDeleteObjectApp( last_row
);
313 TRACE("(%p, %d, %p) %dx%d %d bpp fetched height: %d\n",
314 hbitmap
, (int)count
, bits
, bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmHeight
,
315 bmp
->dib
.dsBm
.bmBitsPixel
, src
.height
);
317 if (src_stride
== dst_stride
)
319 src_bits
.ptr
= (void *)bits
;
320 src_bits
.is_copy
= FALSE
;
321 src_bits
.free
= NULL
;
325 if (!(src_bits
.ptr
= malloc( dst
.height
* dst_stride
)))
327 GDI_ReleaseObj( hbitmap
);
330 src_bits
.is_copy
= TRUE
;
331 src_bits
.free
= free_heap_bits
;
332 for (i
= 0; i
< count
/ src_stride
; i
++)
333 memcpy( (char *)src_bits
.ptr
+ i
* dst_stride
, (char *)bits
+ i
* src_stride
, src_stride
);
334 if (count
% src_stride
)
335 memcpy( (char *)src_bits
.ptr
+ i
* dst_stride
, (char *)bits
+ i
* src_stride
, count
% src_stride
);
338 /* query the color info */
339 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
340 info
->bmiHeader
.biPlanes
= 1;
341 info
->bmiHeader
.biBitCount
= bmp
->dib
.dsBm
.bmBitsPixel
;
342 info
->bmiHeader
.biCompression
= BI_RGB
;
343 info
->bmiHeader
.biXPelsPerMeter
= 0;
344 info
->bmiHeader
.biYPelsPerMeter
= 0;
345 info
->bmiHeader
.biClrUsed
= 0;
346 info
->bmiHeader
.biClrImportant
= 0;
347 info
->bmiHeader
.biWidth
= 0;
348 info
->bmiHeader
.biHeight
= 0;
349 info
->bmiHeader
.biSizeImage
= 0;
350 err
= put_image_into_bitmap( bmp
, 0, info
, NULL
, NULL
, NULL
);
352 if (!err
|| err
== ERROR_BAD_FORMAT
)
354 info
->bmiHeader
.biWidth
= bmp
->dib
.dsBm
.bmWidth
;
355 info
->bmiHeader
.biHeight
= -dst
.height
;
356 info
->bmiHeader
.biSizeImage
= dst
.height
* dst_stride
;
357 err
= put_image_into_bitmap( bmp
, clip
, info
, &src_bits
, &src
, &dst
);
361 if (clip
) NtGdiDeleteObjectApp( clip
);
362 if (src_bits
.free
) src_bits
.free( &src_bits
);
363 GDI_ReleaseObj( hbitmap
);
368 /***********************************************************************
369 * NtGdiSelectBitmap (win32u.@)
371 HGDIOBJ WINAPI
NtGdiSelectBitmap( HDC hdc
, HGDIOBJ handle
)
378 if (!(dc
= get_dc_ptr( hdc
))) return 0;
380 if (get_gdi_object_type( hdc
) != NTGDI_OBJ_MEMDC
)
386 if (handle
== dc
->hBitmap
) goto done
; /* nothing to do */
388 if (!(bitmap
= GDI_GetObjPtr( handle
, NTGDI_OBJ_BITMAP
)))
394 if (handle
!= GetStockObject( DEFAULT_BITMAP
) && GDI_get_ref_count( handle
))
396 WARN( "Bitmap already selected in another DC\n" );
397 GDI_ReleaseObj( handle
);
402 if (!is_bitmapobj_dib( bitmap
) &&
403 bitmap
->dib
.dsBm
.bmBitsPixel
!= 1 &&
404 bitmap
->dib
.dsBm
.bmBitsPixel
!= NtGdiGetDeviceCaps( hdc
, BITSPIXEL
) &&
405 /* Display compatible DCs should accept 32-bit DDBs because other color depths are emulated */
406 !(NtGdiGetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASDISPLAY
&& bitmap
->dib
.dsBm
.bmBitsPixel
== 32))
408 WARN( "Wrong format bitmap %u bpp\n", bitmap
->dib
.dsBm
.bmBitsPixel
);
409 GDI_ReleaseObj( handle
);
414 physdev
= GET_DC_PHYSDEV( dc
, pSelectBitmap
);
415 if (!physdev
->funcs
->pSelectBitmap( physdev
, handle
))
417 GDI_ReleaseObj( handle
);
422 dc
->hBitmap
= handle
;
423 GDI_inc_ref_count( handle
);
425 dc
->attr
->vis_rect
.left
= 0;
426 dc
->attr
->vis_rect
.top
= 0;
427 dc
->attr
->vis_rect
.right
= bitmap
->dib
.dsBm
.bmWidth
;
428 dc
->attr
->vis_rect
.bottom
= bitmap
->dib
.dsBm
.bmHeight
;
429 dc
->device_rect
= dc
->attr
->vis_rect
;
430 GDI_ReleaseObj( handle
);
432 GDI_dec_ref_count( ret
);
436 release_dc_ptr( dc
);
441 /***********************************************************************
442 * BITMAP_DeleteObject
444 static BOOL
BITMAP_DeleteObject( HGDIOBJ handle
)
446 BITMAPOBJ
*bmp
= free_gdi_handle( handle
);
448 if (!bmp
) return FALSE
;
449 free( bmp
->dib
.dsBm
.bmBits
);
455 /***********************************************************************
458 static INT
BITMAP_GetObject( HGDIOBJ handle
, INT count
, LPVOID buffer
)
461 BITMAPOBJ
*bmp
= GDI_GetObjPtr( handle
, NTGDI_OBJ_BITMAP
);
465 if (!buffer
) ret
= sizeof(BITMAP
);
466 else if (count
>= sizeof(BITMAP
))
468 BITMAP
*bitmap
= buffer
;
469 *bitmap
= bmp
->dib
.dsBm
;
470 bitmap
->bmBits
= NULL
;
471 ret
= sizeof(BITMAP
);
473 GDI_ReleaseObj( handle
);
478 /******************************************************************************
479 * NtGdiGetBitmapDimension (win32u.@)
481 * Retrieves dimensions of a bitmap.
487 BOOL WINAPI
NtGdiGetBitmapDimension(
488 HBITMAP hbitmap
, /* [in] Handle to bitmap */
489 LPSIZE size
) /* [out] Address of struct receiving dimensions */
491 BITMAPOBJ
* bmp
= GDI_GetObjPtr( hbitmap
, NTGDI_OBJ_BITMAP
);
492 if (!bmp
) return FALSE
;
494 GDI_ReleaseObj( hbitmap
);
499 /******************************************************************************
500 * NtGdiSetBitmapDimension (win32u.@)
502 * Assigns dimensions to a bitmap.
503 * MSDN says that this function will fail if hbitmap is a handle created by
504 * CreateDIBSection, but that's not true on Windows 2000.
510 BOOL WINAPI
NtGdiSetBitmapDimension(
511 HBITMAP hbitmap
, /* [in] Handle to bitmap */
512 INT x
, /* [in] Bitmap width */
513 INT y
, /* [in] Bitmap height */
514 LPSIZE prevSize
) /* [out] Address of structure for orig dims */
516 BITMAPOBJ
* bmp
= GDI_GetObjPtr( hbitmap
, NTGDI_OBJ_BITMAP
);
517 if (!bmp
) return FALSE
;
518 if (prevSize
) *prevSize
= bmp
->size
;
521 GDI_ReleaseObj( hbitmap
);