[prev in list] [next in list] [prev in thread] [next in thread] 

List:       wine-devel
Subject:    Re: PATCH: imagelist _Read
From:       "Jeremy White" <jwhite () codeweavers ! com>
Date:       2000-01-31 17:19:00
[Download RAW message or body]

Hi Marcus,

Sorry - we had an implementation of ImageList_Read in Twine
that we meant to submit to Wine, just never got the time for it.

I'm attaching a hacked patch that I had working in Corel's Wine
tree for it.  I think you've gone far enough that our code may not
help, but what the heck.

This imagelist stuff is largely undocumented, and our code may
shed some light on something you've missed.


Jer


["imagelist.c.patch" (text/plain)]

Index: imagelist.c
===================================================================
RCS file: /home/cvs/r/corelwine/dlls/comctl32/imagelist.c,v
retrieving revision 1.3
diff -u -r1.3 imagelist.c
--- imagelist.c	1999/12/15 15:21:06	1.3
+++ imagelist.c	2000/01/31 17:13:28
@@ -1881,8 +1881,294 @@
     return himlDst;
 }
 
+/*****************************************************************************
+ * Function : W_IDIBToBitmap()                                               *
+ * Purpose  : Creates a bitmap from a DIB.                                   *
+ * Parameters : HANDLE hDIB - specifies the DIB to convert.                  *
+ * Returns :  A handle to a device dependent bitmap. The handle will be NULL *
+ *            if the handle cannot be created for any reason.                *
+ * Comments : To keep code simple, palettes have not been used/created. If   *
+ *            want to know how to preserve the colors of a 256 bitmap (by    *
+ *            using a Palatte) please see the samples DIBView and WINCAP.    *
+ *****************************************************************************/ 
 
+WORD W_IPaletteSize (LPSTR pv);
+WORD W_IDIBNumColors (LPSTR pv);
+HBITMAP W_IDIBToBitmap (HANDLE hDIB);
+
+HBITMAP W_IDIBToBitmap (HANDLE hDIB)
+{
+   LPSTR lpDIBHdr, lpDIBBits;     /* pointer to DIB header, pointer to DIB bits*/
+   HBITMAP hBitmap;
+   HDC hDC;
+
+   lpDIBHdr = GlobalLock(hDIB);
+
+   /* Get a pointer to the DIB bits*/
+   lpDIBBits = lpDIBHdr + *(LPDWORD)lpDIBHdr + W_IPaletteSize((LPSTR)lpDIBHdr);
+
+   hDC = GetDC( ( HWND )NULL);
+   if (!hDC)
+   {
+      GlobalUnlock(hDIB);
+      return ( HBITMAP )NULL;
+   }
+
+   /* create bitmap from DIB info. and bits */
+   hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
+                            lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
+
+    ReleaseDC( ( HWND )NULL, hDC);
+   GlobalUnlock(hDIB);
+
+   return hBitmap;
+}
+
+/*****************************************************************************
+ * Function : W_IPaletteSize()                                               *
+ * Purpose  : Calculates the palette size in bytes. If the info. block is of *
+ *            the BITMAPCOREHEADER type, the number of colors is multiplied  *
+ *            by sizeof(RGBTRIPLE) to give the palette size, otherwise the   *
+ *            number of colors is multiplied by sizeof(RGBQUAD).             *
+ * Parameters : LPSTR pv - pointer to the BITMAPINFOHEADER                   *
+ * Returns :  The size of the palette.                                       *
+ * Comments :                                                                *
+ ***************************************************************************** */
+
+WORD W_IPaletteSize (LPSTR pv)
+{
+   LPBITMAPINFOHEADER lpbi;
+   WORD NumColors;
+
+   lpbi = (LPBITMAPINFOHEADER)pv;
+   NumColors = W_IDIBNumColors((LPSTR)lpbi);
+
+   if (lpbi->biSize == sizeof(BITMAPCOREHEADER))  /* OS/2 style DIBs*/
+      return NumColors * sizeof(RGBTRIPLE);
+   else
+      return NumColors * sizeof(RGBQUAD);
+}
+
+/*****************************************************************************
+ * Function : W_IDIBNumColors()                                              *
+ * Purpose  : This function calculates the number of colors in the DIB's     *
+ *            color table by finding the bits per pixel for the DIB (whether *
+ *            Win3.0 or OS/2-style DIB). If bits per pixel is 1: colors=2,   *
+ *            if 4: colors=16, if 8: colors=256, if 24, no colors in color   *
+ *            table.                                                         *
+ * Parameters : LPSTR lpbi - pointer to packed-DIB memory block.             *
+ * Returns :  The number of colors in the color table.                       *
+ * Comments :                                                                *
+ *****************************************************************************/
+
+WORD W_IDIBNumColors (LPSTR pv)
+{
+   int bits;
+   LPBITMAPINFOHEADER lpbi;
+   LPBITMAPCOREHEADER lpbc;
+
+   lpbi = ((LPBITMAPINFOHEADER)pv);     /* assume win 3.0 style DIBs*/
+   lpbc = ((LPBITMAPCOREHEADER)pv);     /* assume OS/2 style DIBs*/
+
+   /* With the BITMAPINFO format headers, the size of the palette
+      is in biClrUsed, whereas in the BITMAPCORE - style headers, it
+      is dependent on the bits per pixel ( = 2 raised to the power of
+      bits/pixel).*/
+
+   if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
+   {
+      if (lpbi->biClrUsed != 0)
+         return (WORD)lpbi->biClrUsed;
+      bits = lpbi->biBitCount;
+   }
+   else
+      bits = lpbc->bcBitCount;
+
+   switch (bits)
+   {
+      case 1:
+         return 2;
+
+      case 4:
+         return 16;
+
+      case 8:
+         return 256;
+
+      default:
+         /* A 24 bitcount DIB has no color table*/
+         return 0;
+   }
+}
+
+
+#define BIStream_Read(p,a,b,c) IStream_Read(p,a,b,c)
+
+typedef struct {
+	USHORT	type;
+	USHORT	sizelo;
+	USHORT	sizehi;
+	USHORT	res1;
+	USHORT	res2;
+	USHORT	offbitslo;
+	USHORT	offbitshi;
+} BINBITMAPFILEHEADER;
+
+/*----------------------------------------------------------------------------*
+**  Convenience function for ImageList_Read()
+**----------------------------------------------------------------------------*/
+static HANDLE DIBitmapFromStream(LPSTREAM pstm)
+{
+    HANDLE hDIB;
+
+    BITMAPFILEHEADER bf;
+    BITMAPINFOHEADER bi;
+    BINBITMAPFILEHEADER bbh;
+
+    DWORD dwHeaderSize;
+    DWORD dwColorTableSize;
+    DWORD dwImageSize;
+    DWORD dwTotalSize;
+
+    /* Offsets into the GlobalAlloc() memory */
+    BYTE *pInfoHeader;
+    BYTE *pColorTable;
+    BYTE *pImageData;
+
+    HRESULT                 rc;
+    ULONG                   bytes_read;
+
+    /*-----------------------------------------------------------------------
+    **  Read the bitmap headers:
+    **   1) BITMAPFILEHEADER
+    **   2) BITMAPINFOHEADER
+    **---------------------------------------------------------------------*/
+
+    rc = BIStream_Read(pstm, &bbh, sizeof(bbh), &bytes_read);
+    if (rc != S_OK || bytes_read != sizeof(bbh))
+    {
+	ERR("DIBitmapFromStream() returning NULL...\n"
+		"  (Failed to read BITMAPFILEHEADER)\n");
+        return (HANDLE)NULL;
+    }
+
+    bf.bfType = bbh.type;
+    bf.bfSize = MAKELONG(bbh.sizehi,bbh.sizelo);
+    bf.bfOffBits = MAKELONG(bbh.offbitshi,bbh.offbitslo); 
+ 
+    rc = BIStream_Read(pstm, &bi, sizeof(bi), &bytes_read);
+    if (rc != S_OK || bytes_read != sizeof(bi))
+    {
+	ERR("DIBitmapFromStream() returning NULL...\n"
+		"  (Failed to read BITMAPINFOHEADER)\n");
+        return (HANDLE)NULL;
+    }
+
+    /*-----------------------------------------------------------------------
+    **  Copy all bitmap info into a global memory chunk.  This includes a
+    **  BITMAPINFOHEADER, a (variable size) color table, and raw pixel data.
+    **  This global memory chunk will be binary equivalent to a loaded DIB.
+    **---------------------------------------------------------------------*/
+
+    /* Make code easier to read */
+    dwHeaderSize = bi.biSize;
+    dwColorTableSize = (DWORD)W_IPaletteSize((LPSTR)&bi);
+    dwImageSize = bi.biSizeImage;
+    dwTotalSize = dwHeaderSize + dwColorTableSize + dwImageSize;
+
+    /* Allocate space for everything */
+    hDIB = GlobalAlloc(GHND, dwTotalSize);
+    if (hDIB == (HANDLE)NULL)
+    {
+	ERR("DIBitmapFromStream() returning NULL...\n"
+		"  (Failed to allocate %ld bytes for DIB)\n", dwTotalSize);
+        return (HANDLE)NULL;
+    }
+
+    /* Start with BITMAPINFOHEADER */
+    pInfoHeader = (BYTE*)GlobalLock(hDIB);
+    *(LPBITMAPINFOHEADER)pInfoHeader = bi;
+
+    /* Copy color table into our block of memory */
+    pColorTable = pInfoHeader + dwHeaderSize;
+
+    if(dwColorTableSize) {
+    	rc = BIStream_Read(pstm, pColorTable, dwColorTableSize, &bytes_read);
+	
+    	if (rc != S_OK || bytes_read != dwColorTableSize) {
+		ERR( "DIBitmapFromStream() returning NULL...\n"
+			"  (Failed to read color table)\n");
+        	return (HANDLE)NULL;
+    	}
+    }
+
+    /* Copy bitmap data from the stream to a temporary block of memory */
+    /*  and then into our global memory */
+    pImageData = pInfoHeader + dwHeaderSize + dwColorTableSize;
+
+    rc = BIStream_Read(pstm, pImageData, dwImageSize, &bytes_read);
+    if (rc != S_OK || bytes_read != dwImageSize)
+    {
+	ERR( "DIBitmapFromStream() returning NULL...\n"
+		"  (Failed to read image data into DIB)\n");
+        return (HANDLE)NULL;
+    }
+
+    /* Release pInfoHeader and other related pointers */
+    GlobalUnlock(hDIB);
+
+    return (hDIB);
+}
+
+typedef struct {
+	USHORT	sig;
+	USHORT	ver;
+	USHORT  images_possible_now;
+	USHORT  images_initial_count;
+	USHORT  images_extra_allocate;
+	USHORT	subwidth; 
+	USHORT	subheight;
+	USHORT	dummy1;
+	USHORT	dummy2;
+	char	fill;
+	char    flags;
+	USHORT	dummy3[4];
+} IMAGELISTFILEHEADER;
+
+#if SEVERE
+static void
+DumpBitmap(char *p,HBITMAP hBitmap,int x,int y)
+{
+	HDC hDC,hDCMem;
+	BITMAP bm;
+	POINT  ptSize,ptOrg;
+
+	hDC = GetDC(0);
+	hDCMem = CreateCompatibleDC(hDC);
+
+	SelectObject(hDCMem,hBitmap);
+	SetMapMode(hDCMem,hDC);
+	GetObject(hBitmap,sizeof(BITMAP),(LPVOID) &bm);
+	
+	LOGSTR((LF_CONSOLE,"dump bitmap %s: %d,%d\n",
+		p,bm.bmWidth,bm.bmHeight));
+
+	ptSize.x = bm.bmWidth;
+	ptSize.y = bm.bmHeight;
+	DPtoLP(hDC,&ptSize,1);
+	ptOrg.x = 0;
+	ptOrg.y = 0;
+	DPtoLP(hDCMem,&ptOrg,1);
+	BitBlt(hDC,x,y,ptSize.x,ptSize.y,hDCMem,ptOrg.x,ptOrg.y,SRCCOPY);
+
+	DeleteDC(hDCMem);
+	ReleaseDC(0,hDC);
+}
+#endif
+
 /*************************************************************************
+ * STUB From Wine cvs 7/16/99.  Wine License applies.
+ *
  * ImageList_Read [COMCTL32.66]
  *
  * Reads an image list from a stream.
@@ -1895,33 +2181,160 @@
  *     Failure: NULL
  *
  * NOTES
- *     This function can not be implemented yet, because
- *     IStream32::Read is not implemented yet.
+ *     Makes use of reverse-engineered IMAGELISTFILEHEADER struct, so 
+ *     it's possible we've missed some image formatting possibilities.
  *
  * BUGS
- *     empty stub.
+ *     
  */
-
 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
 {
-    HRESULT errCode;
-    ULONG ulRead;
-    ILHEAD ilHead;
-    HIMAGELIST himl;
+    /*-----------------------------------------------------------------------
+    **  Local variables
+    **---------------------------------------------------------------------*/
+    HRESULT  rc;
+    ULONG bytes_read;
+    int i;
+
+    HIMAGELIST list_handle;
+    IMAGELISTFILEHEADER il;
+    HDC hDC;
+    HDC hDCSrc,hDCSrcMask;
+    HDC hDCDst,hDCDstMask;
+
+    HANDLE hDIB;
+    HBITMAP hBitmap = (HBITMAP)NULL;
+    HBITMAP hMaskBitmap = (HBITMAP)NULL;
+
+    HBITMAP hBMDst     = (HBITMAP)NULL;
+    HBITMAP hBMDstMask = (HBITMAP)NULL;
+
+    TRACE("ImageList_Read(LPSTREAM = %x)\n", pstm);
+
+    /*-----------------------------------------------------------------------
+    **  Read the IMAGELISTFILEHEADER header
+    **---------------------------------------------------------------------*/
+    rc = BIStream_Read(pstm, &il, sizeof(il), &bytes_read);
+    if (rc != S_OK || bytes_read != sizeof(il))
+    {
+	TRACE("ImageList_Read() returning NULL...\n"
+		"  (Failed to read IMAGELISTFILEHEADER)\n");
+        return(NULL);
+    }
+
+    /*-----------------------------------------------------------------------
+    **  Load in Image bitmap (as a DIB) from IStream, then convert to BMP
+    **---------------------------------------------------------------------*/
 
+    hDIB = DIBitmapFromStream(pstm);
+    hBitmap = W_IDIBToBitmap(hDIB);
 
-    FIXME("empty stub!\n");
+    GlobalFree(hDIB);
 
-    errCode = IStream_Read (pstm, &ilHead, sizeof(ILHEAD), &ulRead);
-    if (errCode != S_OK)
-    return NULL;
+    /*-----------------------------------------------------------------------
+    **  Load in Mask bitmap, if ILC_MASK is set
+    **---------------------------------------------------------------------*/
 
-    FIXME("Magic: 0x%x\n", ilHead.usMagic);
+    hDIB = DIBitmapFromStream(pstm);
+    hMaskBitmap = W_IDIBToBitmap(hDIB);
 
-    himl = ImageList_Create (32, 32, ILD_NORMAL, 2, 2);
+    /*-----------------------------------------------------------------------
+    **  Create an empty ImageList
+    **---------------------------------------------------------------------*/
 
-    return himl;
+    {
+	int flag = ILC_MASK;
+    	list_handle = ImageList_Create(il.subwidth, il.subheight, 
+		il.flags|flag,
+		il.images_initial_count, 
+		il.images_extra_allocate);
+    }
+
+    if (list_handle == NULL)
+    {
+	TRACE("ImageList_Read() returning NULL\n");
+        return (NULL);
+    }
+
+    /*-----------------------------------------------------------------------
+    **  BitBlt image-sized chunks of the initial bitmap into a temporary
+    **  bitmap, then add one at a time to the ImageList.
+    **
+    **  hBitmap - color bitmap with all images in one big chunk
+    **  hMaskBitmap - B&W mask bitmap with all masks in one big chunk
+    **
+    **---------------------------------------------------------------------*/
+
+    hDC = GetDC(GetDesktopWindow());
+    hDCSrc= CreateCompatibleDC(hDC);
+    hDCSrcMask= CreateCompatibleDC(hDC);
+
+    hDCDst= CreateCompatibleDC(hDC);
+    hDCDstMask= CreateCompatibleDC(hDC);
+
+    hBMDst     = CreateCompatibleBitmap(hDC, il.subwidth, il.subheight);
+    hBMDstMask = CreateCompatibleBitmap(hDC, il.subwidth, il.subheight);
+
+    /* these hold the source bitmaps */
+    SelectObject(hDCSrc, hBitmap);
+    SelectObject(hDCSrcMask,hMaskBitmap);
+#if 0
+DEBUG_DumpDC(hDCSrc,0,0);
+DEBUG_DumpDC(hDCSrcMask,16,0);
+
+APISTR((LF_CONSOLE, "ImageList_Read() dumped bitmaps\n"));
+debuggerbreak();
+#endif
+
+    /* these hold the destination sub-bitmaps */
+    SelectObject(hDCDst, hBMDst);
+    SelectObject(hDCDstMask,hBMDstMask);
+
+    for (i = 0; i < il.images_possible_now; i++)
+    {
+        int x, y;
+	int cx,cy;
+
+	x = (i % 4) * il.subwidth;
+	y = (i / 4) * il.subheight;
+	cx = il.subwidth; 
+	cy = il.subheight;
+
+	/* copy the subsection of the bitmap */
+        BitBlt(hDCDst, 0, 0, il.subwidth, il.subheight,
+	       hDCSrc, x, y, SRCCOPY);
+
+	/* copy the mask portion of the bitmap */
+	BitBlt(hDCDstMask, 0, 0, il.subwidth, il.subheight,
+	       hDCSrcMask, x, y, SRCCOPY);
+
+	ImageList_Add(list_handle, hBMDst, hBMDstMask);
+
+    }
+
+    /* Clean up our trash */
+    ReleaseDC((HWND)NULL, hDC);
+
+    /* these are the src/dst copy DC's */
+    DeleteDC(hDCSrc);
+    DeleteDC(hDCSrcMask);
+    DeleteDC(hDCDst);
+    DeleteDC(hDCDstMask);
+
+    /* these are what we read in */
+    DeleteObject(hBitmap);
+    DeleteObject(hMaskBitmap);
+
+    /* these are the transient copies */
+    DeleteObject(hBMDst);
+    DeleteObject(hBMDstMask);
+
+    TRACE("ImageList_Read() returning %x\n", list_handle);
+    return(list_handle);
 }
+
+
+
 
 
 /*************************************************************************


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic