Icon resizing in CreateIcon
Vincent Béron
vberon at mecano.gme.usherb.ca
Fri Mar 22 16:31:41 CST 2002
This patch implements icon resizing in CreateIcon if the provided
bitmaps are not GetSystemMetrics(SM_CXICON)xGetSystemMetrics(SM_CYICON).
Fixes bug # 175.
(First patch, so any comments on coding style are welcomed)
Changelog:
Vincent Béron <<vberon at mecano.gme.usherb.ca>>
include/bitmap.h, objects/bitmap.c, windows/cursoricon.c:
- Implements icon resizing in CreateIcon.
-------------- next part --------------
diff -urN wine-20020310/include/bitmap.h wine/include/bitmap.h
--- wine-20020310/include/bitmap.h Tue Mar 12 10:37:49 2002
+++ wine/include/bitmap.h Thu Mar 21 20:08:50 2002
@@ -66,6 +66,8 @@
extern INT BITMAP_GetObject( BITMAPOBJ * bmp, INT count, LPVOID buffer );
extern BOOL BITMAP_DeleteObject( HBITMAP16 hbitmap, BITMAPOBJ * bitmap );
extern INT BITMAP_GetWidthBytes( INT width, INT depth );
+extern VOID BITMAP_ResizeMonochrome( INT inWidth, INT inHeight, LPCVOID lpIn,
+ INT outWidth, INT outHeight, LPVOID lpOut );
extern HBITMAP BITMAP_CopyBitmap( HBITMAP hbitmap );
/* objects/dib.c */
diff -urN wine-20020310/objects/bitmap.c wine/objects/bitmap.c
--- wine-20020310/objects/bitmap.c Tue Mar 12 10:37:53 2002
+++ wine/objects/bitmap.c Thu Mar 21 20:08:57 2002
@@ -68,6 +68,88 @@
}
/***********************************************************************
+ * BITMAP_ResizeMonochrome
+ *
+ * Resize a monochrome bitmap from (inWidth,inHeight) to (outWidth, outHeight).
+ */
+VOID BITMAP_ResizeMonochrome( INT inWidth, INT inHeight, LPCVOID lpIn,
+ INT outWidth, INT outHeight, LPVOID lpOut)
+{
+ BOOL hstretch, vstretch;
+ INT nBytesRowSrc, nBytesSrc;
+ INT nBytesRowDst, nBytesDst;
+ INT xinc, xoff, xsrc, xdst;
+ INT yinc, ysrc, ydst;
+ LPBYTE lpRowSrc, lpRowDst;
+
+ hstretch = (inWidth < outWidth);
+ vstretch = (inHeight < outHeight);
+ nBytesRowSrc = BITMAP_GetWidthBytes(inWidth, 1);
+ nBytesSrc = nBytesRowSrc * inHeight;
+ nBytesRowDst = BITMAP_GetWidthBytes(outWidth, 1);
+ nBytesDst = nBytesRowDst * outHeight;
+
+ if(inWidth != outWidth || inHeight != outHeight) {
+ memset(lpOut, 0, nBytesDst);
+
+ if(hstretch) {
+ xinc = ((int)inWidth << 16) / outWidth;
+ xoff = ((inWidth << 16) - (xinc * outWidth)) / 2;
+ } else {
+ xinc = ((int)outWidth << 16) / inWidth;
+ xoff = ((outWidth << 16) - (xinc * inWidth)) / 2;
+ }
+
+ if(vstretch) {
+ yinc = ((int)inHeight << 16) / outHeight;
+ ysrc = ((inHeight << 16) - (yinc * outHeight)) / 2;
+ for(ydst = 0; ydst < outHeight; ysrc += yinc, ydst++) {
+ lpRowSrc = (LPBYTE)lpIn + nBytesRowSrc * (ysrc >> 16);
+ lpRowDst = (LPBYTE)lpOut + nBytesRowDst * ydst;
+ if(hstretch) {
+ xsrc = xoff;
+ for(xdst = 0; xdst < outWidth; xsrc += xinc, xdst++)
+ lpRowDst[xdst >> 3] |=
+ ((lpRowSrc[(xsrc >> 16) >> 3] >> (7 - ((xsrc >> 16) % 8))) & 0x01) <<
+ (7 - (xdst % 8));
+ } else {
+ xdst = xoff;
+ for(xsrc = 0; xsrc < inWidth; xsrc++, xdst += xinc)
+ lpRowDst[(xdst >> 16) >> 3] |=
+ ((lpRowSrc[xsrc >> 3] >> (7 - (xsrc % 8))) & 0x01) <<
+ (7 - ((xdst >> 16) % 8));
+ }
+ }
+ } else {
+ yinc = ((int)outHeight << 16) / inHeight;
+ ydst = ((outHeight << 16) - (yinc * inHeight)) / 2;
+ for(ysrc = 0; ysrc < inHeight; ysrc++, ydst += yinc) {
+ lpRowSrc = (LPBYTE)lpIn + nBytesRowSrc * ysrc;
+ lpRowDst = (LPBYTE)lpOut + nBytesRowDst * (ydst >> 16);
+ if(hstretch) {
+ xsrc = xoff;
+ for(xdst = 0; xdst < outWidth; xsrc += xinc, xdst++)
+ lpRowDst[xdst >> 3] |=
+ ((lpRowSrc[(xsrc >> 16) >> 3] >> (7 - ((xsrc >> 16) % 8))) & 0x01) <<
+ (7 - (xdst % 8));
+ } else {
+ xdst = xoff;
+ for(xsrc = 0; xsrc < inWidth; xsrc++, xdst += xinc)
+ lpRowDst[(xdst >> 16) >> 3] |=
+ ((lpRowSrc[xsrc >> 3] >> (7 - (xsrc % 8))) & 0x01) <<
+ (7 - ((xdst >> 16) % 8));
+ }
+ }
+ }
+ } else {
+ memcpy(lpOut, lpIn, nBytesDst);
+ }
+
+ return;
+}
+
+
+/***********************************************************************
* CreateUserBitmap (GDI.407)
*/
HBITMAP16 WINAPI CreateUserBitmap16( INT16 width, INT16 height, UINT16 planes,
diff -urN wine-20020310/windows/cursoricon.c wine/windows/cursoricon.c
--- wine-20020310/windows/cursoricon.c Tue Mar 12 10:37:57 2002
+++ wine/windows/cursoricon.c Thu Mar 21 21:37:09 2002
@@ -387,7 +387,7 @@
*ptr = NULL;
if (!(bits = map_fileW( filename ))) return FALSE;
- /* FIXME: test for inimated icons
+ /* FIXME: test for animated icons
* hack to load the first icon from the *.ani file
*/
if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
@@ -1158,20 +1158,18 @@
*
* BUGS
*
- * - The provided bitmaps are not resized!
- * - The documentation says the lpXORbits bitmap must be in a device
- * dependent format. But we must still resize it and perform depth
- * conversions if necessary.
+ * - You may wonder why we check if bBitsPixel == 1: StretchDIBits seemed to
+ * replace the white parts of the bitmap by blue. This behavior was there
+ * before the resizing: StretchDIBits (or another function called by it) is
+ * most probably the culprit.
+ * - Before using StretchDIBits, we must realign the scanlines of lpXORbits on
+ * 32bits rather than 16bits. This is probably a bug in StretchDIBits.
* - I'm a bit unsure about the how the 'device dependent format' thing works.
* I did some tests on windows and found that if you provide a 16bpp bitmap
* in lpXORbits, then its format but be 565 RGB if the screen's bit depth
* is 16bpp but it must be 555 RGB if the screen's bit depth is anything
* else. I don't know if this is part of the GDI specs or if this is a
* quirk of the graphics card driver.
- * - You may think that we check whether the bit depths match or not
- * as an optimization. But the truth is that the conversion using
- * CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
- * no idea why.
* - I'm pretty sure that all the things we do in CreateIcon should
* also be done in CreateIconIndirect...
*/
@@ -1185,57 +1183,92 @@
LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
{
HICON hIcon;
- HDC hdc;
+ HDC hdc, hdcMem;
+ ICONINFO iinfo;
+ BITMAPINFO bmi;
+ INT nNeededCX, nNeededCY;
+ LPBYTE lpANDbitsrszd, lpXORbitsrszd;
+ HBITMAP hbmANDrszd = 0, hbmXORrszd = 0;
+ HBITMAP hbmtemp;
+ INT nBytesRowSrc;
+ INT nBytesRowDst, nBytesDst;
+ INT y;
TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
- hdc=GetDC(0);
- if (!hdc)
- return 0;
-
- if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
- CURSORICONINFO info;
+ if(!(hdc=GetDC(0))) return 0;
- info.ptHotSpot.x = ICON_HOTSPOT;
- info.ptHotSpot.y = ICON_HOTSPOT;
- info.nWidth = nWidth;
- info.nHeight = nHeight;
- info.nWidthBytes = 0;
- info.bPlanes = bPlanes;
- info.bBitsPerPixel = bBitsPixel;
-
- hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
+ /* AND bitmask (always monochrpme) */
+ nNeededCX = GetSystemMetrics(SM_CXICON);
+ nNeededCY = GetSystemMetrics(SM_CYICON);
+ nBytesRowDst = BITMAP_GetWidthBytes(nNeededCX, 1);
+ nBytesDst = nBytesRowDst * nNeededCY;
+ if((lpANDbitsrszd = HeapAlloc(GetProcessHeap(), 0, nBytesDst))) {
+ BITMAP_ResizeMonochrome(nWidth, nHeight, lpANDbits,
+ nNeededCX, nNeededCY, lpANDbitsrszd);
+ hbmANDrszd = CreateBitmap(nNeededCX, nNeededCY, 1, 1, lpANDbitsrszd);
+ HeapFree(GetProcessHeap(), 0, lpANDbitsrszd);
+ }
+
+ /* XOR bitmask (bit depth of bitmap must be converted to screen depth) */
+ /* Test for bBitsPixel == 1 to get correct white if monochrome */
+ if(bBitsPixel == 1) {
+ if((lpXORbitsrszd = HeapAlloc(GetProcessHeap(), 0, nBytesDst))) {
+ BITMAP_ResizeMonochrome(nWidth, nHeight, lpXORbits,
+ nNeededCX, nNeededCY, lpXORbitsrszd);
+ hbmXORrszd = CreateBitmap(nNeededCX, nNeededCY, 1, 1, lpXORbitsrszd);
+ HeapFree(GetProcessHeap(), 0, lpXORbitsrszd);
+ }
} else {
- ICONINFO iinfo;
- BITMAPINFO bmi;
-
- iinfo.fIcon=TRUE;
- iinfo.xHotspot=ICON_HOTSPOT;
- iinfo.yHotspot=ICON_HOTSPOT;
- iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
-
- bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
- bmi.bmiHeader.biWidth=nWidth;
- bmi.bmiHeader.biHeight=-nHeight;
- bmi.bmiHeader.biPlanes=bPlanes;
- bmi.bmiHeader.biBitCount=bBitsPixel;
- bmi.bmiHeader.biCompression=BI_RGB;
- bmi.bmiHeader.biSizeImage=0;
- bmi.bmiHeader.biXPelsPerMeter=0;
- bmi.bmiHeader.biYPelsPerMeter=0;
- bmi.bmiHeader.biClrUsed=0;
- bmi.bmiHeader.biClrImportant=0;
-
- iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
- CBM_INIT, lpXORbits,
- &bmi, DIB_RGB_COLORS );
-
- hIcon=CreateIconIndirect(&iinfo);
- DeleteObject(iinfo.hbmMask);
- DeleteObject(iinfo.hbmColor);
+ nBytesRowSrc = BITMAP_GetWidthBytes(nWidth, bBitsPixel);
+ /* Somebody (MS? Wine?) wants the bitmap in 32bit chunks
+ for StretchDIBits rather than 16bits as everywhere else */
+ nBytesRowDst = 4 * ((nWidth * bBitsPixel + 31) >> 5);
+ nBytesDst = nBytesRowDst * nHeight;
+ if((lpXORbitsrszd = HeapAlloc(GetProcessHeap(), 0, nBytesDst))) {
+ for(y = 0; y < nHeight; y++)
+ memcpy((LPBYTE)lpXORbitsrszd + (y * nBytesRowDst),
+ (LPBYTE)lpXORbits + (y * nBytesRowSrc), nBytesRowSrc);
+
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = nWidth;
+ bmi.bmiHeader.biHeight = -nHeight;
+ bmi.bmiHeader.biPlanes = bPlanes;
+ bmi.bmiHeader.biBitCount = bBitsPixel;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter = 0;
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+
+ screen_dc = CreateDCA("DISPLAY", NULL, NULL, NULL);
+ hbmXORrszd = CreateCompatibleBitmap(screen_dc, nNeededCX, nNeededCY);
+ hdcMem = CreateCompatibleDC(screen_dc);
+ SetStretchBltMode(hdcMem, COLORONCOLOR);
+ hbmtemp = SelectObject(hdcMem, hbmXORrszd);
+ StretchDIBits(hdcMem, 0, 0, nNeededCX, nNeededCY,
+ 0, 0, nWidth, nHeight, lpXORbitsrszd,
+ &bmi, DIB_RGB_COLORS, SRCCOPY);
+ SelectObject(hdcMem, hbmtemp);
+ DeleteDC(hdcMem);
+ HeapFree(GetProcessHeap(), 0, lpXORbitsrszd);
+ }
}
+
+ /* Creation of the icon itself */
+ iinfo.fIcon = TRUE;
+ iinfo.xHotspot = ICON_HOTSPOT;
+ iinfo.yHotspot = ICON_HOTSPOT;
+ iinfo.hbmMask = hbmANDrszd;
+ iinfo.hbmColor = hbmXORrszd;
+
+ hIcon = CreateIconIndirect(&iinfo);
+ DeleteObject(iinfo.hbmColor);
+ DeleteObject(iinfo.hbmMask);
ReleaseDC(0,hdc);
+
return hIcon;
}
@@ -1262,7 +1295,7 @@
return 0;
FarSetOwner16( handle, hInstance );
ptr = (char *)GlobalLock16( handle );
- memcpy( ptr, info, sizeof(*info) );
+ memcpy( ptr, info, sizeof(CURSORICONINFO) );
memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
GlobalUnlock16( handle );
More information about the wine-patches
mailing list