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 * null driver fallback implementations
53 LONG CDECL nulldrv_GetBitmapBits( HBITMAP bitmap, void *bits, LONG size )
55 BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
57 if (bmp->bitmap.bmBits) memcpy( bits, bmp->bitmap.bmBits, size );
58 else memset( bits, 0, size );
59 GDI_ReleaseObj( bitmap );
63 LONG CDECL nulldrv_SetBitmapBits( HBITMAP bitmap, const void *bits, LONG size )
65 BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
67 if (!bmp->bitmap.bmBits)
69 LONG total = bmp->bitmap.bmHeight * bmp->bitmap.bmWidthBytes; /* alloc enough for entire bitmap */
70 if (!(bmp->bitmap.bmBits = HeapAlloc( GetProcessHeap(), 0, total )))
72 GDI_ReleaseObj( bitmap );
75 if (size < total) memset( (char *)bmp->bitmap.bmBits + size, 0, total - size );
77 memcpy( bmp->bitmap.bmBits, bits, size );
78 GDI_ReleaseObj( bitmap );
82 INT CDECL nulldrv_GetDIBits( PHYSDEV dev, HBITMAP bitmap, UINT start, UINT lines, LPVOID bits,
83 BITMAPINFO *info, UINT coloruse )
85 /* FIXME: transfer bits from bmp->bitmap.bmBits */
89 INT CDECL nulldrv_SetDIBits( PHYSDEV dev, HBITMAP bitmap, UINT start, UINT lines,
90 const void *bits, const BITMAPINFO *info, UINT coloruse )
92 /* FIXME: transfer bits to bmp->bitmap.bmBits */
96 /***********************************************************************
97 * BITMAP_GetWidthBytes
99 * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
102 INT BITMAP_GetWidthBytes( INT bmWidth, INT bpp )
107 return 2 * ((bmWidth+15) >> 4);
110 bmWidth *= 3; /* fall through */
112 return bmWidth + (bmWidth & 1);
122 return 2 * ((bmWidth+3) >> 2);
125 WARN("Unknown depth %d, please report.\n", bpp );
131 /******************************************************************************
132 * CreateBitmap [GDI32.@]
134 * Creates a bitmap with the specified info.
137 * width [I] bitmap width
138 * height [I] bitmap height
139 * planes [I] Number of color planes
140 * bpp [I] Number of bits to identify a color
141 * bits [I] Pointer to array containing color data
144 * Success: Handle to bitmap
147 HBITMAP WINAPI CreateBitmap( INT width, INT height, UINT planes,
148 UINT bpp, LPCVOID bits )
154 bm.bmHeight = height;
155 bm.bmWidthBytes = BITMAP_GetWidthBytes( width, bpp );
156 bm.bmPlanes = planes;
157 bm.bmBitsPixel = bpp;
158 bm.bmBits = (LPVOID)bits;
160 return CreateBitmapIndirect( &bm );
163 /******************************************************************************
164 * CreateCompatibleBitmap [GDI32.@]
166 * Creates a bitmap compatible with the DC.
169 * hdc [I] Handle to device context
170 * width [I] Width of bitmap
171 * height [I] Height of bitmap
174 * Success: Handle to bitmap
177 HBITMAP WINAPI CreateCompatibleBitmap( HDC hdc, INT width, INT height)
181 TRACE("(%p,%d,%d) =\n", hdc, width, height);
183 if (GetObjectType( hdc ) != OBJ_MEMDC)
185 hbmpRet = CreateBitmap(width, height,
186 GetDeviceCaps(hdc, PLANES),
187 GetDeviceCaps(hdc, BITSPIXEL),
193 HBITMAP bitmap = GetCurrentObject( hdc, OBJ_BITMAP );
194 INT size = GetObjectW( bitmap, sizeof(dib), &dib );
198 if (size == sizeof(BITMAP))
200 /* A device-dependent bitmap is selected in the DC */
201 hbmpRet = CreateBitmap(width, height,
203 dib.dsBm.bmBitsPixel,
208 /* A DIB section is selected in the DC */
212 /* Allocate memory for a BITMAPINFOHEADER structure and a
213 color table. The maximum number of colors in a color table
214 is 256 which corresponds to a bitmap with depth 8.
215 Bitmaps with higher depths don't have color tables. */
216 bi = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
220 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
221 bi->bmiHeader.biWidth = width;
222 bi->bmiHeader.biHeight = height;
223 bi->bmiHeader.biPlanes = dib.dsBmih.biPlanes;
224 bi->bmiHeader.biBitCount = dib.dsBmih.biBitCount;
225 bi->bmiHeader.biCompression = dib.dsBmih.biCompression;
226 bi->bmiHeader.biSizeImage = 0;
227 bi->bmiHeader.biXPelsPerMeter = dib.dsBmih.biXPelsPerMeter;
228 bi->bmiHeader.biYPelsPerMeter = dib.dsBmih.biYPelsPerMeter;
229 bi->bmiHeader.biClrUsed = dib.dsBmih.biClrUsed;
230 bi->bmiHeader.biClrImportant = dib.dsBmih.biClrImportant;
232 if (bi->bmiHeader.biCompression == BI_BITFIELDS)
234 /* Copy the color masks */
235 CopyMemory(bi->bmiColors, dib.dsBitfields, 3 * sizeof(DWORD));
237 else if (bi->bmiHeader.biBitCount <= 8)
239 /* Copy the color table */
240 GetDIBColorTable(hdc, 0, 256, bi->bmiColors);
243 hbmpRet = CreateDIBSection(hdc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
244 HeapFree(GetProcessHeap(), 0, bi);
249 TRACE("\t\t%p\n", hbmpRet);
254 /******************************************************************************
255 * CreateBitmapIndirect [GDI32.@]
257 * Creates a bitmap with the specified info.
260 * bmp [I] Pointer to the bitmap info describing the bitmap
263 * Success: Handle to bitmap
264 * Failure: NULL. Use GetLastError() to determine the cause.
267 * If a width or height of 0 are given, a 1x1 monochrome bitmap is returned.
269 HBITMAP WINAPI CreateBitmapIndirect( const BITMAP *bmp )
275 if (!bmp || bmp->bmType)
277 SetLastError( ERROR_INVALID_PARAMETER );
281 if (bmp->bmWidth > 0x7ffffff || bmp->bmHeight > 0x7ffffff)
283 SetLastError( ERROR_INVALID_PARAMETER );
289 if (!bm.bmWidth || !bm.bmHeight)
291 return GetStockObject( DEFAULT_BITMAP );
296 bm.bmHeight = -bm.bmHeight;
298 bm.bmWidth = -bm.bmWidth;
301 if (bm.bmPlanes != 1)
303 FIXME("planes = %d\n", bm.bmPlanes);
304 SetLastError( ERROR_INVALID_PARAMETER );
308 /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */
309 if(bm.bmBitsPixel == 1) bm.bmBitsPixel = 1;
310 else if(bm.bmBitsPixel <= 4) bm.bmBitsPixel = 4;
311 else if(bm.bmBitsPixel <= 8) bm.bmBitsPixel = 8;
312 else if(bm.bmBitsPixel <= 16) bm.bmBitsPixel = 16;
313 else if(bm.bmBitsPixel <= 24) bm.bmBitsPixel = 24;
314 else if(bm.bmBitsPixel <= 32) bm.bmBitsPixel = 32;
316 WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bm.bmBitsPixel);
317 SetLastError(ERROR_INVALID_PARAMETER);
321 /* Windows ignores the provided bm.bmWidthBytes */
322 bm.bmWidthBytes = BITMAP_GetWidthBytes( bm.bmWidth, bm.bmBitsPixel );
323 /* XP doesn't allow to create bitmaps larger than 128 Mb */
324 if (bm.bmHeight > 128 * 1024 * 1024 / bm.bmWidthBytes)
326 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
330 /* Create the BITMAPOBJ */
331 if (!(bmpobj = HeapAlloc( GetProcessHeap(), 0, sizeof(*bmpobj) )))
333 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
340 bmpobj->bitmap.bmBits = NULL;
341 bmpobj->funcs = &null_driver;
343 bmpobj->color_table = NULL;
344 bmpobj->nb_colors = 0;
346 if (!(hbitmap = alloc_gdi_handle( &bmpobj->header, OBJ_BITMAP, &bitmap_funcs )))
348 HeapFree( GetProcessHeap(), 0, bmpobj );
353 SetBitmapBits( hbitmap, bm.bmHeight * bm.bmWidthBytes, bm.bmBits );
355 TRACE("%dx%d, %d colors returning %p\n", bm.bmWidth, bm.bmHeight,
356 1 << (bm.bmPlanes * bm.bmBitsPixel), hbitmap);
362 /***********************************************************************
363 * GetBitmapBits [GDI32.@]
365 * Copies bitmap bits of bitmap to buffer.
368 * Success: Number of bytes copied
371 LONG WINAPI GetBitmapBits(
372 HBITMAP hbitmap, /* [in] Handle to bitmap */
373 LONG count, /* [in] Number of bytes to copy */
374 LPVOID bits) /* [out] Pointer to buffer to receive bits */
376 BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
381 if (bmp->dib) /* simply copy the bits from the DIB */
383 DIBSECTION *dib = bmp->dib;
384 const char *src = dib->dsBm.bmBits;
385 INT width_bytes = BITMAP_GetWidthBytes(dib->dsBm.bmWidth, dib->dsBm.bmBitsPixel);
386 LONG max = width_bytes * bmp->bitmap.bmHeight;
394 if (count > max) count = max;
397 /* GetBitmapBits returns not 32-bit aligned data */
399 if (bmp->dib->dsBmih.biHeight >= 0) /* not top-down, need to flip contents vertically */
401 src += dib->dsBm.bmWidthBytes * dib->dsBm.bmHeight;
404 src -= dib->dsBm.bmWidthBytes;
405 memcpy( bits, src, min( count, width_bytes ) );
406 bits = (char *)bits + width_bytes;
407 count -= width_bytes;
414 memcpy( bits, src, min( count, width_bytes ) );
415 src += dib->dsBm.bmWidthBytes;
416 bits = (char *)bits + width_bytes;
417 count -= width_bytes;
423 /* If the bits vector is null, the function should return the read size */
426 ret = bmp->bitmap.bmWidthBytes * bmp->bitmap.bmHeight;
431 WARN("(%d): Negative number of bytes passed???\n", count );
435 /* Only get entire lines */
436 height = count / bmp->bitmap.bmWidthBytes;
437 if (height > bmp->bitmap.bmHeight) height = bmp->bitmap.bmHeight;
438 count = height * bmp->bitmap.bmWidthBytes;
441 WARN("Less than one entire line requested\n");
447 TRACE("(%p, %d, %p) %dx%d %d colors fetched height: %d\n",
448 hbitmap, count, bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
449 1 << bmp->bitmap.bmBitsPixel, height );
451 ret = bmp->funcs->pGetBitmapBits( hbitmap, bits, count );
453 GDI_ReleaseObj( hbitmap );
458 /******************************************************************************
459 * SetBitmapBits [GDI32.@]
461 * Sets bits of color data for a bitmap.
464 * Success: Number of bytes used in setting the bitmap bits
467 LONG WINAPI SetBitmapBits(
468 HBITMAP hbitmap, /* [in] Handle to bitmap */
469 LONG count, /* [in] Number of bytes in bitmap array */
470 LPCVOID bits) /* [in] Address of array with bitmap bits */
477 bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
481 WARN("(%d): Negative number of bytes passed???\n", count );
485 if (bmp->dib) /* simply copy the bits into the DIB */
487 DIBSECTION *dib = bmp->dib;
488 char *dest = dib->dsBm.bmBits;
489 LONG max = dib->dsBm.bmWidthBytes * dib->dsBm.bmHeight;
490 if (count > max) count = max;
493 if (bmp->dib->dsBmih.biHeight >= 0) /* not top-down, need to flip contents vertically */
495 dest += dib->dsBm.bmWidthBytes * dib->dsBm.bmHeight;
498 dest -= dib->dsBm.bmWidthBytes;
499 memcpy( dest, bits, min( count, dib->dsBm.bmWidthBytes ) );
500 bits = (const char *)bits + dib->dsBm.bmWidthBytes;
501 count -= dib->dsBm.bmWidthBytes;
504 else memcpy( dest, bits, count );
506 GDI_ReleaseObj( hbitmap );
510 /* Only get entire lines */
511 height = count / bmp->bitmap.bmWidthBytes;
512 if (height > bmp->bitmap.bmHeight) height = bmp->bitmap.bmHeight;
513 count = height * bmp->bitmap.bmWidthBytes;
515 TRACE("(%p, %d, %p) %dx%d %d colors fetched height: %d\n",
516 hbitmap, count, bits, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
517 1 << bmp->bitmap.bmBitsPixel, height );
519 ret = bmp->funcs->pSetBitmapBits( hbitmap, bits, count );
520 GDI_ReleaseObj( hbitmap );
524 /**********************************************************************
528 HBITMAP BITMAP_CopyBitmap(HBITMAP hbitmap)
532 BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
542 GDI_ReleaseObj( hbitmap );
543 dc = CreateCompatibleDC( NULL );
546 if (!(bi = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ))))
551 bi->bmiHeader = dib.dsBmih;
553 /* Get the color table or the color masks */
554 GetDIBits( dc, hbitmap, 0, 0, NULL, bi, DIB_RGB_COLORS );
555 bi->bmiHeader.biHeight = dib.dsBmih.biHeight;
557 res = CreateDIBSection( dc, bi, DIB_RGB_COLORS, &bits, NULL, 0 );
558 if (res) SetDIBits( dc, res, 0, dib.dsBm.bmHeight, dib.dsBm.bmBits, bi, DIB_RGB_COLORS );
559 HeapFree( GetProcessHeap(), 0, bi );
563 dib.dsBm = bmp->bitmap;
564 dib.dsBm.bmBits = NULL;
565 GDI_ReleaseObj( hbitmap );
567 res = CreateBitmapIndirect( &dib.dsBm );
569 char *buf = HeapAlloc( GetProcessHeap(), 0, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight );
570 GetBitmapBits (hbitmap, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight, buf);
571 SetBitmapBits (res, dib.dsBm.bmWidthBytes * dib.dsBm.bmHeight, buf);
572 HeapFree( GetProcessHeap(), 0, buf );
578 /***********************************************************************
581 * Set the type of DC that owns the bitmap. This is used when the
582 * bitmap is selected into a device to initialize the bitmap function
585 BOOL BITMAP_SetOwnerDC( HBITMAP hbitmap, PHYSDEV physdev )
590 /* never set the owner of the stock bitmap since it can be selected in multiple DCs */
591 if (hbitmap == GetStockObject(DEFAULT_BITMAP)) return TRUE;
593 if (!(bitmap = GDI_GetObjPtr( hbitmap, OBJ_BITMAP ))) return FALSE;
595 if (!bitmap->dib && bitmap->funcs != physdev->funcs)
597 /* we can only change from the null driver to some other driver */
598 if (bitmap->funcs == &null_driver)
600 if (physdev->funcs->pCreateBitmap)
602 ret = physdev->funcs->pCreateBitmap( physdev, hbitmap, bitmap->bitmap.bmBits );
603 if (ret) bitmap->funcs = physdev->funcs;
607 WARN( "Trying to select bitmap %p in DC that doesn't support it\n", hbitmap );
613 FIXME( "Trying to select bitmap %p in different DC type\n", hbitmap );
617 GDI_ReleaseObj( hbitmap );
622 /***********************************************************************
623 * BITMAP_SelectObject
625 static HGDIOBJ BITMAP_SelectObject( HGDIOBJ handle, HDC hdc )
630 PHYSDEV physdev = NULL, old_physdev = NULL;
632 if (!(dc = get_dc_ptr( hdc ))) return 0;
634 if (GetObjectType( hdc ) != OBJ_MEMDC)
640 if (handle == dc->hBitmap) goto done; /* nothing to do */
642 if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
648 if (bitmap->header.selcount && (handle != GetStockObject(DEFAULT_BITMAP)))
650 WARN( "Bitmap already selected in another DC\n" );
651 GDI_ReleaseObj( handle );
656 old_physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
657 if(old_physdev == &dc->dibdrv.dev)
658 pop_dc_driver( dc, old_physdev );
662 physdev = &dc->dibdrv.dev;
663 push_dc_driver( dc, physdev, physdev->funcs );
666 physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
668 if (!BITMAP_SetOwnerDC( handle, physdev ))
670 GDI_ReleaseObj( handle );
674 if (!physdev->funcs->pSelectBitmap( physdev, handle ))
676 GDI_ReleaseObj( handle );
681 dc->hBitmap = handle;
682 GDI_inc_ref_count( handle );
684 dc->vis_rect.left = 0;
685 dc->vis_rect.top = 0;
686 dc->vis_rect.right = bitmap->bitmap.bmWidth;
687 dc->vis_rect.bottom = bitmap->bitmap.bmHeight;
688 SetRectRgn( dc->hVisRgn, 0, 0, bitmap->bitmap.bmWidth, bitmap->bitmap.bmHeight);
689 GDI_ReleaseObj( handle );
691 GDI_dec_ref_count( ret );
697 if(physdev == &dc->dibdrv.dev) pop_dc_driver( dc, physdev );
698 if(old_physdev == &dc->dibdrv.dev) push_dc_driver( dc, old_physdev, old_physdev->funcs );
700 release_dc_ptr( dc );
705 /***********************************************************************
706 * BITMAP_DeleteObject
708 static BOOL BITMAP_DeleteObject( HGDIOBJ handle )
710 const DC_FUNCTIONS *funcs;
711 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
713 if (!bmp) return FALSE;
715 GDI_ReleaseObj( handle );
717 funcs->pDeleteBitmap( handle );
719 if (!(bmp = free_gdi_handle( handle ))) return FALSE;
721 HeapFree( GetProcessHeap(), 0, bmp->bitmap.bmBits );
725 DIBSECTION *dib = bmp->dib;
727 if (dib->dsBm.bmBits)
731 SYSTEM_INFO SystemInfo;
732 GetSystemInfo( &SystemInfo );
733 UnmapViewOfFile( (char *)dib->dsBm.bmBits -
734 (dib->dsOffset % SystemInfo.dwAllocationGranularity) );
736 else if (!dib->dsOffset)
737 VirtualFree(dib->dsBm.bmBits, 0L, MEM_RELEASE );
739 HeapFree(GetProcessHeap(), 0, dib);
740 HeapFree(GetProcessHeap(), 0, bmp->color_table);
742 return HeapFree( GetProcessHeap(), 0, bmp );
746 /***********************************************************************
749 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
752 BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
756 if (!buffer) ret = sizeof(BITMAP);
757 else if (count < sizeof(BITMAP)) ret = 0;
760 if (count >= sizeof(DIBSECTION))
762 DIBSECTION *dib = buffer;
764 dib->dsBmih.biHeight = abs( dib->dsBmih.biHeight );
765 ret = sizeof(DIBSECTION);
767 else /* if (count >= sizeof(BITMAP)) */
769 DIBSECTION *dib = bmp->dib;
770 memcpy( buffer, &dib->dsBm, sizeof(BITMAP) );
771 ret = sizeof(BITMAP);
776 memcpy( buffer, &bmp->bitmap, sizeof(BITMAP) );
777 ((BITMAP *) buffer)->bmBits = NULL;
778 ret = sizeof(BITMAP);
780 GDI_ReleaseObj( handle );
785 /******************************************************************************
786 * CreateDiscardableBitmap [GDI32.@]
788 * Creates a discardable bitmap.
791 * Success: Handle to bitmap
794 HBITMAP WINAPI CreateDiscardableBitmap(
795 HDC hdc, /* [in] Handle to device context */
796 INT width, /* [in] Bitmap width */
797 INT height) /* [in] Bitmap height */
799 return CreateCompatibleBitmap( hdc, width, height );
803 /******************************************************************************
804 * GetBitmapDimensionEx [GDI32.@]
806 * Retrieves dimensions of a bitmap.
812 BOOL WINAPI GetBitmapDimensionEx(
813 HBITMAP hbitmap, /* [in] Handle to bitmap */
814 LPSIZE size) /* [out] Address of struct receiving dimensions */
816 BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
817 if (!bmp) return FALSE;
819 GDI_ReleaseObj( hbitmap );
824 /******************************************************************************
825 * SetBitmapDimensionEx [GDI32.@]
827 * Assigns dimensions to a bitmap.
828 * MSDN says that this function will fail if hbitmap is a handle created by
829 * CreateDIBSection, but that's not true on Windows 2000.
835 BOOL WINAPI SetBitmapDimensionEx(
836 HBITMAP hbitmap, /* [in] Handle to bitmap */
837 INT x, /* [in] Bitmap width */
838 INT y, /* [in] Bitmap height */
839 LPSIZE prevSize) /* [out] Address of structure for orig dims */
841 BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
842 if (!bmp) return FALSE;
843 if (prevSize) *prevSize = bmp->size;
846 GDI_ReleaseObj( hbitmap );