PATCH: gif support for OLE pictures

Marcus Meissner marcus at jet.franken.de
Sun Jan 5 13:21:39 CST 2003


Hi,

This fixes a report from some weeks ago, where an app called OleLoadPicture
on a GIF resource (http://www.myhexin.com/tw2002/rjxz/download.asp?rjxz=exe1).

Please rerun autoconf and autoheader.

The application uses shdocvw.dll right after that, which does not work here,
since I lack the native setup on this machine.

So I was not able to 'see' the GIF images. But it should be correct I hope,
at least the CreateDIBSection and later GetObject does not crash.

Ciao, Marcus

Changelog:
	Implemented loading of GIF pictures for the OLE Automation IPicture
	interface using libungif/libgif.
	Sometimes the persistant stream does not have a header.

Index: configure.ac
===================================================================
RCS file: /home/wine/wine/configure.ac,v
retrieving revision 1.116
diff -u -u -r1.116 configure.ac
--- configure.ac	4 Jan 2003 02:52:05 -0000	1.116
+++ configure.ac	5 Jan 2003 19:09:46 -0000
@@ -146,6 +146,21 @@
     )
 )
 
+GIFLIB=""
+AC_SUBST(GIFLIB)
+AC_CHECK_HEADERS(gif_lib.h,
+    AC_CHECK_LIB(ungif,DGifOpen,
+    	AC_DEFINE(HAVE_LIBGIF,1,[Define if you have libgif/libungif including devel headers])
+	GIFLIB="-lungif",
+	[
+	    AC_CHECK_LIB(gif,DGifOpen,
+		AC_DEFINE(HAVE_LIBGIF,1,[Define if you have libgif/libungif including devel headers])
+		JPEGLIB="-lgif"
+	    )
+	]
+    )
+)
+
 
 AC_SUBST(XLIB)
 AC_SUBST(XFILES)
Index: dlls/oleaut32/olepicture.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/olepicture.c,v
retrieving revision 1.21
diff -u -u -r1.21 olepicture.c
--- dlls/oleaut32/olepicture.c	2 Jan 2003 17:54:57 -0000	1.21
+++ dlls/oleaut32/olepicture.c	5 Jan 2003 19:09:47 -0000
@@ -42,6 +42,14 @@
 #endif
 #include <stdio.h>
 #include <string.h>
+
+/* Must be before wine includes, the header has things conflicting with
+ * WINE headers.
+ */
+#ifdef HAVE_LIBGIF
+# include <gif_lib.h>
+#endif
+
 #include "winerror.h"
 #include "winbase.h"
 #include "wingdi.h"
@@ -810,6 +818,26 @@
 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
 #endif /* HAVE_LIBJPEG */
 
+#ifdef HAVE_LIBGIF
+struct gifdata {
+    unsigned char *data;
+    unsigned int curoff;
+    unsigned int len;
+};
+
+static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
+    struct gifdata *gd = (struct gifdata*)gif->UserData;
+
+    if (len+gd->curoff > gd->len) {
+        FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
+        len = gd->len - gd->curoff;
+    }
+    memcpy(data, gd->data+gd->curoff, len);
+    gd->curoff += len;
+    return len;
+}
+#endif
+
 /************************************************************************
  * OLEPictureImpl_IPersistStream_Load (IUnknown)
  *
@@ -826,30 +854,134 @@
   BYTE 		*xbuf;
   DWORD		header[2];
   WORD		magic;
+  STATSTG       statstg;
   ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
-
+  
   TRACE("(%p,%p)\n",This,pStm);
 
+  /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
+   * out whether we do.
+   */
+  hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
+  if (hr)
+    FIXME("Stat failed with hres %lx\n",hr);
   hr=IStream_Read(pStm,header,8,&xread);
   if (hr || xread!=8) {
       FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
       return hr;
   }
-  xread = 0;
-  xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
-  This->datalen = header[1];
-  while (xread < header[1]) {
-    ULONG nread;
-    hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
-    xread+=nread;
-    if (hr || !nread)
-      break;
+  if (header[1] > statstg.cbSize.QuadPart) {/* Incorrect header, assume none. */
+    xread = 8;
+    xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,statstg.cbSize.QuadPart);
+    memcpy(xbuf,&header,8);
+    This->datalen = statstg.cbSize.QuadPart;
+    while (xread < This->datalen) {
+      ULONG nread;
+      hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
+      xread+=nread;
+      if (hr || !nread)
+	break;
+    }
+    if (xread != This->datalen)
+      FIXME("Could only read %ld of %d bytes in no-header case?\n",xread,This->datalen);
+  } else {
+    xread = 0;
+    xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
+    This->datalen = header[1];
+    while (xread < header[1]) {
+      ULONG nread;
+      hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
+      xread+=nread;
+      if (hr || !nread)
+	break;
+    }
+    if (xread != header[1])
+      FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
   }
-  if (xread != header[1])
-    FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
-
   magic = xbuf[0] + (xbuf[1]<<8);
   switch (magic) {
+  case 0x4947: { /* GIF */
+#ifdef HAVE_LIBGIF
+    struct gifdata 	gd;
+    GifFileType 	*gif;
+    BITMAPINFO		*bmi;
+    HDC			hdcref;
+    LPBYTE              bytes;
+    int                 i,j,ret;
+    GifImageDesc        *gid;
+    SavedImage          *si;
+    ColorMapObject      *cm;
+    
+    gd.data   = xbuf;
+    gd.curoff = 0;
+    gd.len    = xread;
+    gif = DGifOpen((void*)&gd, _gif_inputfunc);
+    ret = DGifSlurp(gif);
+    if (ret == GIF_ERROR) {
+      FIXME("Failed reading GIF using libgif.\n");
+      return E_FAIL;
+    }
+    TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
+    TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
+    TRACE("imgcnt %d\n", gif->ImageCount);
+    if (gif->ImageCount<1) {
+      FIXME("GIF stream does not have images inside?\n");
+      return E_FAIL;
+    }
+    TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
+      gif->Image.Width, gif->Image.Height,
+      gif->Image.Left, gif->Image.Top,
+      gif->Image.Interlace
+    );
+    /* */
+    bmi  = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(1<<gif->SColorResolution)*sizeof(RGBQUAD));
+    bytes= HeapAlloc(GetProcessHeap(),0,gif->SWidth*gif->SHeight);
+    si   = gif->SavedImages+0;
+    gid  = &(si->ImageDesc);
+    cm   = gid->ColorMap;
+    if (!cm) cm = gif->SColorMap;
+    for (i=0;i<(1<<gif->SColorResolution);i++) {
+      bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
+      bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
+      bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
+    }
+    /* Map to in picture coordinates */
+    for (i=0;i<gid->Height;i++)
+      for (j=0;j<gid->Width;j++)
+        bytes[(gid->Top+i)*gif->SWidth+gid->Left+j]=si->RasterBits[i*gid->Width+j];
+    bmi->bmiHeader.biSize		= sizeof(BITMAPINFOHEADER);
+    bmi->bmiHeader.biWidth		= gif->SWidth;
+    bmi->bmiHeader.biHeight		= gif->SHeight;
+    bmi->bmiHeader.biPlanes		= 1;
+    bmi->bmiHeader.biBitCount		= 8;
+    bmi->bmiHeader.biCompression	= BI_RGB;
+    bmi->bmiHeader.biSizeImage		= gif->SWidth*gif->SHeight;
+    bmi->bmiHeader.biXPelsPerMeter	= 0;
+    bmi->bmiHeader.biYPelsPerMeter	= 0;
+    bmi->bmiHeader.biClrUsed		= 1 << gif->SColorResolution;
+    bmi->bmiHeader.biClrImportant	= 0;
+
+    hdcref = GetDC(0);
+    This->desc.u.bmp.hbitmap=CreateDIBitmap(
+	    hdcref,
+	    bmi,
+	    CBM_INIT,
+	    bytes,
+	    bmi,
+	    DIB_PAL_COLORS
+    );
+    DeleteDC(hdcref);
+    This->desc.picType = PICTYPE_BITMAP;
+    OLEPictureImpl_SetBitmap(This);
+    DGifCloseFile(gif);
+    HeapFree(GetProcessHeap(),0,bytes);
+    return S_OK;
+#else
+    FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n");
+    return E_FAIL;
+#endif
+    break;
+  }
   case 0xd8ff: { /* JPEG */
 #ifdef HAVE_LIBJPEG
     struct jpeg_decompress_struct	jd;
@@ -1009,9 +1141,18 @@
     break;
   }
   default:
-    FIXME("Unknown magic %04x\n",magic);
+  {
+    int i;
+    FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread);
     hr=E_FAIL;
+    for (i=0;i<xread+8;i++) {
+	if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
+	else MESSAGE("%02x ",xbuf[i-8]);
+        if (i % 10 == 9) MESSAGE("\n");
+    }
+    MESSAGE("\n");
     break;
+  }
   }
 
   /* FIXME: this notify is not really documented */



More information about the wine-patches mailing list