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
29 #include "gdi_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(bitmap
);
35 static HGDIOBJ
BITMAP_SelectObject( HGDIOBJ handle
, HDC hdc
);
36 static INT
BITMAP_GetObject( HGDIOBJ handle
, INT count
, LPVOID buffer
);
37 static BOOL
BITMAP_DeleteObject( HGDIOBJ handle
);
39 static const struct gdi_obj_funcs bitmap_funcs
=
41 BITMAP_SelectObject
, /* pSelectObject */
42 BITMAP_GetObject
, /* pGetObjectA */
43 BITMAP_GetObject
, /* pGetObjectW */
44 NULL
, /* pUnrealizeObject */
45 BITMAP_DeleteObject
/* pDeleteObject */
49 /******************************************************************************
50 * CreateBitmap [GDI32.@]
52 * Creates a bitmap with the specified info.
55 * width [I] bitmap width
56 * height [I] bitmap height
57 * planes [I] Number of color planes
58 * bpp [I] Number of bits to identify a color
59 * bits [I] Pointer to array containing color data
62 * Success: Handle to bitmap
65 HBITMAP WINAPI
CreateBitmap( INT width
, INT height
, UINT planes
,
66 UINT bpp
, LPCVOID bits
)
73 bm
.bmWidthBytes
= get_bitmap_stride( width
, bpp
);
76 bm
.bmBits
= (LPVOID
)bits
;
78 return CreateBitmapIndirect( &bm
);
81 /******************************************************************************
82 * CreateCompatibleBitmap [GDI32.@]
84 * Creates a bitmap compatible with the DC.
87 * hdc [I] Handle to device context
88 * width [I] Width of bitmap
89 * height [I] Height of bitmap
92 * Success: Handle to bitmap
95 HBITMAP WINAPI
CreateCompatibleBitmap( HDC hdc
, INT width
, INT height
)
97 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
98 BITMAPINFO
*bi
= (BITMAPINFO
*)buffer
;
101 TRACE("(%p,%d,%d)\n", hdc
, width
, height
);
103 if (GetObjectType( hdc
) != OBJ_MEMDC
)
104 return CreateBitmap( width
, height
,
105 GetDeviceCaps(hdc
, PLANES
), GetDeviceCaps(hdc
, BITSPIXEL
), NULL
);
107 switch (GetObjectW( GetCurrentObject( hdc
, OBJ_BITMAP
), sizeof(dib
), &dib
))
109 case sizeof(BITMAP
): /* A device-dependent bitmap is selected in the DC */
110 return CreateBitmap( width
, height
, dib
.dsBm
.bmPlanes
, dib
.dsBm
.bmBitsPixel
, NULL
);
112 case sizeof(DIBSECTION
): /* A DIB section is selected in the DC */
113 bi
->bmiHeader
= dib
.dsBmih
;
114 bi
->bmiHeader
.biWidth
= width
;
115 bi
->bmiHeader
.biHeight
= height
;
116 if (dib
.dsBmih
.biCompression
== BI_BITFIELDS
) /* copy the color masks */
117 memcpy(bi
->bmiColors
, dib
.dsBitfields
, sizeof(dib
.dsBitfields
));
118 else if (dib
.dsBmih
.biBitCount
<= 8) /* copy the color table */
119 GetDIBColorTable(hdc
, 0, 256, bi
->bmiColors
);
120 return CreateDIBSection( hdc
, bi
, DIB_RGB_COLORS
, NULL
, NULL
, 0 );
128 /******************************************************************************
129 * CreateBitmapIndirect [GDI32.@]
131 * Creates a bitmap with the specified info.
134 * bmp [I] Pointer to the bitmap info describing the bitmap
137 * Success: Handle to bitmap
138 * Failure: NULL. Use GetLastError() to determine the cause.
141 * If a width or height of 0 is given, a 1x1 monochrome bitmap is returned.
143 HBITMAP WINAPI
CreateBitmapIndirect( const BITMAP
*bmp
)
151 if (!bmp
|| bmp
->bmType
)
153 SetLastError( ERROR_INVALID_PARAMETER
);
157 if (bmp
->bmWidth
> 0x7ffffff || bmp
->bmHeight
> 0x7ffffff)
159 SetLastError( ERROR_INVALID_PARAMETER
);
165 if (!bm
.bmWidth
|| !bm
.bmHeight
)
167 return GetStockObject( DEFAULT_BITMAP
);
172 bm
.bmHeight
= -bm
.bmHeight
;
174 bm
.bmWidth
= -bm
.bmWidth
;
177 if (bm
.bmPlanes
!= 1)
179 FIXME("planes = %d\n", bm
.bmPlanes
);
180 SetLastError( ERROR_INVALID_PARAMETER
);
184 /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */
185 if(bm
.bmBitsPixel
== 1) bm
.bmBitsPixel
= 1;
186 else if(bm
.bmBitsPixel
<= 4) bm
.bmBitsPixel
= 4;
187 else if(bm
.bmBitsPixel
<= 8) bm
.bmBitsPixel
= 8;
188 else if(bm
.bmBitsPixel
<= 16) bm
.bmBitsPixel
= 16;
189 else if(bm
.bmBitsPixel
<= 24) bm
.bmBitsPixel
= 24;
190 else if(bm
.bmBitsPixel
<= 32) bm
.bmBitsPixel
= 32;
192 WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bm
.bmBitsPixel
);
193 SetLastError(ERROR_INVALID_PARAMETER
);
197 /* Windows ignores the provided bm.bmWidthBytes */
198 bm
.bmWidthBytes
= get_bitmap_stride( bm
.bmWidth
, bm
.bmBitsPixel
);
200 dib_stride
= get_dib_stride( bm
.bmWidth
, bm
.bmBitsPixel
);
201 size
= dib_stride
* bm
.bmHeight
;
202 /* Check for overflow (dib_stride itself must be ok because of the constraint on bm.bmWidth above). */
203 if (dib_stride
!= size
/ bm
.bmHeight
)
205 SetLastError( ERROR_INVALID_PARAMETER
);
209 /* Create the BITMAPOBJ */
210 if (!(bmpobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*bmpobj
) )))
212 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
216 bmpobj
->dib
.dsBm
= bm
;
217 bmpobj
->dib
.dsBm
.bmBits
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
218 if (!bmpobj
->dib
.dsBm
.bmBits
)
220 HeapFree( GetProcessHeap(), 0, bmpobj
);
221 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
225 if (!(hbitmap
= alloc_gdi_handle( bmpobj
, OBJ_BITMAP
, &bitmap_funcs
)))
227 HeapFree( GetProcessHeap(), 0, bmpobj
->dib
.dsBm
.bmBits
);
228 HeapFree( GetProcessHeap(), 0, bmpobj
);
233 SetBitmapBits( hbitmap
, bm
.bmHeight
* bm
.bmWidthBytes
, bm
.bmBits
);
235 TRACE("%dx%d, bpp %d planes %d: returning %p\n", bm
.bmWidth
, bm
.bmHeight
,
236 bm
.bmBitsPixel
, bm
.bmPlanes
, hbitmap
);
242 /***********************************************************************
243 * GetBitmapBits [GDI32.@]
245 * Copies bitmap bits of bitmap to buffer.
248 * Success: Number of bytes copied
251 LONG WINAPI
GetBitmapBits(
252 HBITMAP hbitmap
, /* [in] Handle to bitmap */
253 LONG count
, /* [in] Number of bytes to copy */
254 LPVOID bits
) /* [out] Pointer to buffer to receive bits */
256 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
257 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
258 struct gdi_image_bits src_bits
;
259 struct bitblt_coords src
;
260 int dst_stride
, max
, ret
;
261 BITMAPOBJ
*bmp
= GDI_GetObjPtr( hbitmap
, OBJ_BITMAP
);
265 dst_stride
= get_bitmap_stride( bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmBitsPixel
);
266 ret
= max
= dst_stride
* bmp
->dib
.dsBm
.bmHeight
;
267 if (!bits
) goto done
;
268 if (count
< 0 || count
> max
) count
= max
;
271 src
.visrect
.left
= 0;
272 src
.visrect
.right
= bmp
->dib
.dsBm
.bmWidth
;
274 src
.visrect
.bottom
= (count
+ dst_stride
- 1) / dst_stride
;
276 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
277 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
279 if (!get_image_from_bitmap( bmp
, info
, &src_bits
, &src
))
281 const char *src_ptr
= src_bits
.ptr
;
282 int src_stride
= info
->bmiHeader
.biSizeImage
/ abs( info
->bmiHeader
.biHeight
);
284 /* GetBitmapBits returns 16-bit aligned data */
286 if (info
->bmiHeader
.biHeight
> 0)
288 src_ptr
+= (info
->bmiHeader
.biHeight
- 1) * src_stride
;
289 src_stride
= -src_stride
;
291 src_ptr
+= src
.visrect
.top
* src_stride
;
293 if (src_stride
== dst_stride
) memcpy( bits
, src_ptr
, count
);
294 else while (count
> 0)
296 memcpy( bits
, src_ptr
, min( count
, dst_stride
) );
297 src_ptr
+= src_stride
;
298 bits
= (char *)bits
+ dst_stride
;
301 if (src_bits
.free
) src_bits
.free( &src_bits
);
306 GDI_ReleaseObj( hbitmap
);
311 /******************************************************************************
312 * SetBitmapBits [GDI32.@]
314 * Sets bits of color data for a bitmap.
317 * Success: Number of bytes used in setting the bitmap bits
320 LONG WINAPI
SetBitmapBits(
321 HBITMAP hbitmap
, /* [in] Handle to bitmap */
322 LONG count
, /* [in] Number of bytes in bitmap array */
323 LPCVOID bits
) /* [in] Address of array with bitmap bits */
325 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
326 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
329 int i
, src_stride
, dst_stride
;
330 struct bitblt_coords src
, dst
;
331 struct gdi_image_bits src_bits
;
336 bmp
= GDI_GetObjPtr( hbitmap
, OBJ_BITMAP
);
340 WARN("(%d): Negative number of bytes passed???\n", count
);
344 src_stride
= get_bitmap_stride( bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmBitsPixel
);
345 count
= min( count
, src_stride
* bmp
->dib
.dsBm
.bmHeight
);
347 dst_stride
= get_dib_stride( bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmBitsPixel
);
349 src
.visrect
.left
= src
.x
= 0;
350 src
.visrect
.top
= src
.y
= 0;
351 src
.visrect
.right
= src
.width
= bmp
->dib
.dsBm
.bmWidth
;
352 src
.visrect
.bottom
= src
.height
= (count
+ src_stride
- 1 ) / src_stride
;
355 if (count
% src_stride
)
358 int extra_pixels
= ((count
% src_stride
) << 3) / bmp
->dib
.dsBm
.bmBitsPixel
;
360 if ((count
% src_stride
<< 3) % bmp
->dib
.dsBm
.bmBitsPixel
)
361 FIXME( "Unhandled partial pixel\n" );
362 clip
= CreateRectRgn( src
.visrect
.left
, src
.visrect
.top
,
363 src
.visrect
.right
, src
.visrect
.bottom
- 1 );
364 last_row
= CreateRectRgn( src
.visrect
.left
, src
.visrect
.bottom
- 1,
365 src
.visrect
.left
+ extra_pixels
, src
.visrect
.bottom
);
366 CombineRgn( clip
, clip
, last_row
, RGN_OR
);
367 DeleteObject( last_row
);
370 TRACE("(%p, %d, %p) %dx%d %d bpp fetched height: %d\n",
371 hbitmap
, count
, bits
, bmp
->dib
.dsBm
.bmWidth
, bmp
->dib
.dsBm
.bmHeight
,
372 bmp
->dib
.dsBm
.bmBitsPixel
, src
.height
);
374 if (src_stride
== dst_stride
)
376 src_bits
.ptr
= (void *)bits
;
377 src_bits
.is_copy
= FALSE
;
378 src_bits
.free
= NULL
;
382 if (!(src_bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, dst
.height
* dst_stride
)))
384 GDI_ReleaseObj( hbitmap
);
387 src_bits
.is_copy
= TRUE
;
388 src_bits
.free
= free_heap_bits
;
389 for (i
= 0; i
< count
/ src_stride
; i
++)
390 memcpy( (char *)src_bits
.ptr
+ i
* dst_stride
, (char *)bits
+ i
* src_stride
, src_stride
);
391 if (count
% src_stride
)
392 memcpy( (char *)src_bits
.ptr
+ i
* dst_stride
, (char *)bits
+ i
* src_stride
, count
% src_stride
);
395 /* query the color info */
396 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
397 info
->bmiHeader
.biPlanes
= 1;
398 info
->bmiHeader
.biBitCount
= bmp
->dib
.dsBm
.bmBitsPixel
;
399 info
->bmiHeader
.biCompression
= BI_RGB
;
400 info
->bmiHeader
.biXPelsPerMeter
= 0;
401 info
->bmiHeader
.biYPelsPerMeter
= 0;
402 info
->bmiHeader
.biClrUsed
= 0;
403 info
->bmiHeader
.biClrImportant
= 0;
404 info
->bmiHeader
.biWidth
= 0;
405 info
->bmiHeader
.biHeight
= 0;
406 info
->bmiHeader
.biSizeImage
= 0;
407 err
= put_image_into_bitmap( bmp
, 0, info
, NULL
, NULL
, NULL
);
409 if (!err
|| err
== ERROR_BAD_FORMAT
)
411 info
->bmiHeader
.biWidth
= bmp
->dib
.dsBm
.bmWidth
;
412 info
->bmiHeader
.biHeight
= -dst
.height
;
413 info
->bmiHeader
.biSizeImage
= dst
.height
* dst_stride
;
414 err
= put_image_into_bitmap( bmp
, clip
, info
, &src_bits
, &src
, &dst
);
418 if (clip
) DeleteObject( clip
);
419 if (src_bits
.free
) src_bits
.free( &src_bits
);
420 GDI_ReleaseObj( hbitmap
);
425 /***********************************************************************
426 * BITMAP_SelectObject
428 static HGDIOBJ
BITMAP_SelectObject( HGDIOBJ handle
, HDC hdc
)
435 if (!(dc
= get_dc_ptr( hdc
))) return 0;
437 if (GetObjectType( hdc
) != OBJ_MEMDC
)
443 if (handle
== dc
->hBitmap
) goto done
; /* nothing to do */
445 if (!(bitmap
= GDI_GetObjPtr( handle
, OBJ_BITMAP
)))
451 if (handle
!= GetStockObject(DEFAULT_BITMAP
) && GDI_get_ref_count( handle
))
453 WARN( "Bitmap already selected in another DC\n" );
454 GDI_ReleaseObj( handle
);
459 if (bitmap
->dib
.dsBm
.bmBitsPixel
!= 1 &&
460 bitmap
->dib
.dsBm
.bmBitsPixel
!= GetDeviceCaps( hdc
, BITSPIXEL
))
462 WARN( "Wrong format bitmap %u bpp\n", bitmap
->dib
.dsBm
.bmBitsPixel
);
463 GDI_ReleaseObj( handle
);
468 physdev
= GET_DC_PHYSDEV( dc
, pSelectBitmap
);
469 if (!physdev
->funcs
->pSelectBitmap( physdev
, handle
))
471 GDI_ReleaseObj( handle
);
476 dc
->hBitmap
= handle
;
477 GDI_inc_ref_count( handle
);
479 dc
->vis_rect
.left
= 0;
480 dc
->vis_rect
.top
= 0;
481 dc
->vis_rect
.right
= bitmap
->dib
.dsBm
.bmWidth
;
482 dc
->vis_rect
.bottom
= bitmap
->dib
.dsBm
.bmHeight
;
483 dc
->device_rect
= dc
->vis_rect
;
484 GDI_ReleaseObj( handle
);
486 GDI_dec_ref_count( ret
);
490 release_dc_ptr( dc
);
495 /***********************************************************************
496 * BITMAP_DeleteObject
498 static BOOL
BITMAP_DeleteObject( HGDIOBJ handle
)
500 BITMAPOBJ
*bmp
= free_gdi_handle( handle
);
502 if (!bmp
) return FALSE
;
503 HeapFree( GetProcessHeap(), 0, bmp
->dib
.dsBm
.bmBits
);
504 HeapFree( GetProcessHeap(), 0, bmp
);
509 /***********************************************************************
512 static INT
BITMAP_GetObject( HGDIOBJ handle
, INT count
, LPVOID buffer
)
515 BITMAPOBJ
*bmp
= GDI_GetObjPtr( handle
, OBJ_BITMAP
);
519 if (!buffer
) ret
= sizeof(BITMAP
);
520 else if (count
>= sizeof(BITMAP
))
522 BITMAP
*bitmap
= buffer
;
523 *bitmap
= bmp
->dib
.dsBm
;
524 bitmap
->bmBits
= NULL
;
525 ret
= sizeof(BITMAP
);
527 GDI_ReleaseObj( handle
);
532 /******************************************************************************
533 * CreateDiscardableBitmap [GDI32.@]
535 * Creates a discardable bitmap.
538 * Success: Handle to bitmap
541 HBITMAP WINAPI
CreateDiscardableBitmap(
542 HDC hdc
, /* [in] Handle to device context */
543 INT width
, /* [in] Bitmap width */
544 INT height
) /* [in] Bitmap height */
546 return CreateCompatibleBitmap( hdc
, width
, height
);
550 /******************************************************************************
551 * GetBitmapDimensionEx [GDI32.@]
553 * Retrieves dimensions of a bitmap.
559 BOOL WINAPI
GetBitmapDimensionEx(
560 HBITMAP hbitmap
, /* [in] Handle to bitmap */
561 LPSIZE size
) /* [out] Address of struct receiving dimensions */
563 BITMAPOBJ
* bmp
= GDI_GetObjPtr( hbitmap
, OBJ_BITMAP
);
564 if (!bmp
) return FALSE
;
566 GDI_ReleaseObj( hbitmap
);
571 /******************************************************************************
572 * SetBitmapDimensionEx [GDI32.@]
574 * Assigns dimensions to a bitmap.
575 * MSDN says that this function will fail if hbitmap is a handle created by
576 * CreateDIBSection, but that's not true on Windows 2000.
582 BOOL WINAPI
SetBitmapDimensionEx(
583 HBITMAP hbitmap
, /* [in] Handle to bitmap */
584 INT x
, /* [in] Bitmap width */
585 INT y
, /* [in] Bitmap height */
586 LPSIZE prevSize
) /* [out] Address of structure for orig dims */
588 BITMAPOBJ
* bmp
= GDI_GetObjPtr( hbitmap
, OBJ_BITMAP
);
589 if (!bmp
) return FALSE
;
590 if (prevSize
) *prevSize
= bmp
->size
;
593 GDI_ReleaseObj( hbitmap
);