4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
30 * NOTES (or things that msdn doesn't tell you)
32 * The width and height properties are returned in HIMETRIC units (0.01mm)
33 * IPicture::Render also uses these to select a region of the src picture.
34 * A bitmap's size is converted into these units by using the screen resolution
35 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
40 #include "wine/port.h"
50 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
52 #define UINT8 JPEG_UINT8
53 #define UINT16 JPEG_UINT16
54 #define boolean jpeg_boolean
65 /* Must be before wine includes, the header has things conflicting with
69 #define NONAMELESSUNION
70 #define NONAMELESSSTRUCT
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
85 #include "wine/wingdi16.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(ole);
93 /* Header for Aldus Placable Metafiles - a standard metafile follows */
94 typedef struct _APM_HEADER
116 } CURSORICONFILEDIRENTRY;
123 CURSORICONFILEDIRENTRY idEntries[1];
128 /*************************************************************************
129 * Declaration of implementation class
132 typedef struct OLEPictureImpl {
135 * IPicture handles IUnknown
138 const IPictureVtbl *lpVtbl;
139 const IDispatchVtbl *lpvtblIDispatch;
140 const IPersistStreamVtbl *lpvtblIPersistStream;
141 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
143 /* Object reference count */
146 /* We own the object and must destroy it ourselves */
149 /* Picture description */
152 /* These are the pixel size of a bitmap */
156 /* And these are the size of the picture converted into HIMETRIC units */
157 OLE_XSIZE_HIMETRIC himetricWidth;
158 OLE_YSIZE_HIMETRIC himetricHeight;
160 IConnectionPoint *pCP;
165 /* Bitmap transparency mask */
173 BOOL bIsDirty; /* Set to TRUE if picture has changed */
174 unsigned int loadtime_magic; /* If a length header was found, saves value */
175 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
179 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
182 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
184 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
187 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
189 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
192 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
194 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
198 * Predeclare VTables. They get initialized at the end.
200 static const IPictureVtbl OLEPictureImpl_VTable;
201 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
202 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
203 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
205 /***********************************************************************
206 * Implementation of the OLEPictureImpl class.
209 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
213 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
214 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
215 ERR("GetObject fails\n");
218 This->origWidth = bm.bmWidth;
219 This->origHeight = bm.bmHeight;
220 /* The width and height are stored in HIMETRIC units (0.01 mm),
221 so we take our pixel width divide by pixels per inch and
222 multiply by 25.4 * 100 */
223 /* Should we use GetBitmapDimension if available? */
224 hdcRef = CreateCompatibleDC(0);
225 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
226 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
230 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
234 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
235 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
239 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
240 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
241 ERR("GetObject fails on icon bitmap\n");
245 This->origWidth = bm.bmWidth;
246 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
247 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
249 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
250 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
251 ReleaseDC(0, hdcRef);
253 DeleteObject(infoIcon.hbmMask);
254 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
256 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
260 /************************************************************************
261 * OLEPictureImpl_Construct
263 * This method will construct a new instance of the OLEPictureImpl
266 * The caller of this method must release the object when it's
269 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
271 OLEPictureImpl* newObject = 0;
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
285 * Initialize the virtual function table.
287 newObject->lpVtbl = &OLEPictureImpl_VTable;
288 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
289 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
290 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
292 newObject->pCP = NULL;
293 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
296 HeapFree(GetProcessHeap(), 0, newObject);
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
323 OLEPictureImpl_SetBitmap(newObject);
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
328 newObject->himetricWidth = pictDesc->u.wmf.xExt;
329 newObject->himetricHeight = pictDesc->u.wmf.yExt;
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
338 OLEPictureImpl_SetIcon(newObject);
340 case PICTYPE_ENHMETAFILE:
342 FIXME("Unsupported type %d\n", pictDesc->picType);
343 newObject->himetricWidth = newObject->himetricHeight = 0;
347 newObject->desc.picType = PICTYPE_UNINITIALIZED;
350 TRACE("returning %p\n", newObject);
354 /************************************************************************
355 * OLEPictureImpl_Destroy
357 * This method is called by the Release method when the reference
358 * count goes down to 0. It will free all resources used by
360 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
362 TRACE("(%p)\n", Obj);
365 IConnectionPoint_Release(Obj->pCP);
367 if(Obj->fOwn) { /* We need to destroy the picture */
368 switch(Obj->desc.picType) {
370 DeleteObject(Obj->desc.u.bmp.hbitmap);
371 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
372 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
374 case PICTYPE_METAFILE:
375 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
378 DestroyIcon(Obj->desc.u.icon.hicon);
380 case PICTYPE_ENHMETAFILE:
381 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
384 case PICTYPE_UNINITIALIZED:
388 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
392 HeapFree(GetProcessHeap(), 0, Obj->data);
393 HeapFree(GetProcessHeap(), 0, Obj);
397 /************************************************************************
398 * OLEPictureImpl_AddRef (IUnknown)
400 * See Windows documentation for more details on IUnknown methods.
402 static ULONG WINAPI OLEPictureImpl_AddRef(
405 OLEPictureImpl *This = (OLEPictureImpl *)iface;
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
413 /************************************************************************
414 * OLEPictureImpl_Release (IUnknown)
416 * See Windows documentation for more details on IUnknown methods.
418 static ULONG WINAPI OLEPictureImpl_Release(
421 OLEPictureImpl *This = (OLEPictureImpl *)iface;
422 ULONG refCount = InterlockedDecrement(&This->ref);
424 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
427 * If the reference count goes down to 0, perform suicide.
429 if (!refCount) OLEPictureImpl_Destroy(This);
434 /************************************************************************
435 * OLEPictureImpl_QueryInterface (IUnknown)
437 * See Windows documentation for more details on IUnknown methods.
439 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
444 OLEPictureImpl *This = (OLEPictureImpl *)iface;
445 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
448 * Perform a sanity check on the parameters.
450 if ( (This==0) || (ppvObject==0) )
454 * Initialize the return parameter.
459 * Compare the riid with the interface IDs implemented by this object.
461 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462 *ppvObject = (IPicture*)This;
463 else if (IsEqualIID(&IID_IDispatch, riid))
464 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
465 else if (IsEqualIID(&IID_IPictureDisp, riid))
466 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
467 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
468 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
469 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
470 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
473 * Check that we obtained an interface.
477 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
478 return E_NOINTERFACE;
482 * Query Interface always increases the reference count by one when it is
485 OLEPictureImpl_AddRef((IPicture*)This);
490 /***********************************************************************
491 * OLEPicture_SendNotify (internal)
493 * Sends notification messages of changed properties to any interested
496 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
498 IEnumConnections *pEnum;
501 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
503 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
504 IPropertyNotifySink *sink;
506 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
507 IPropertyNotifySink_OnChanged(sink, dispID);
508 IPropertyNotifySink_Release(sink);
509 IUnknown_Release(CD.pUnk);
511 IEnumConnections_Release(pEnum);
514 /************************************************************************
515 * OLEPictureImpl_get_Handle
517 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
520 OLEPictureImpl *This = (OLEPictureImpl *)iface;
521 TRACE("(%p)->(%p)\n", This, phandle);
522 switch(This->desc.picType) {
524 case PICTYPE_UNINITIALIZED:
528 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
530 case PICTYPE_METAFILE:
531 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
534 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
536 case PICTYPE_ENHMETAFILE:
537 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
540 FIXME("Unimplemented type %d\n", This->desc.picType);
543 TRACE("returning handle %08x\n", *phandle);
547 /************************************************************************
548 * OLEPictureImpl_get_hPal
550 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
553 OLEPictureImpl *This = (OLEPictureImpl *)iface;
555 TRACE("(%p)->(%p)\n", This, phandle);
560 switch (This->desc.picType) {
561 case (UINT)PICTYPE_UNINITIALIZED:
567 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
570 case PICTYPE_METAFILE:
574 case PICTYPE_ENHMETAFILE:
576 FIXME("unimplemented for type %d. Returning 0 palette.\n",
582 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
586 /************************************************************************
587 * OLEPictureImpl_get_Type
589 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
592 OLEPictureImpl *This = (OLEPictureImpl *)iface;
593 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
594 *ptype = This->desc.picType;
598 /************************************************************************
599 * OLEPictureImpl_get_Width
601 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
602 OLE_XSIZE_HIMETRIC *pwidth)
604 OLEPictureImpl *This = (OLEPictureImpl *)iface;
605 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
606 *pwidth = This->himetricWidth;
610 /************************************************************************
611 * OLEPictureImpl_get_Height
613 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
614 OLE_YSIZE_HIMETRIC *pheight)
616 OLEPictureImpl *This = (OLEPictureImpl *)iface;
617 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
618 *pheight = This->himetricHeight;
622 /************************************************************************
623 * OLEPictureImpl_Render
625 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
626 LONG x, LONG y, LONG cx, LONG cy,
627 OLE_XPOS_HIMETRIC xSrc,
628 OLE_YPOS_HIMETRIC ySrc,
629 OLE_XSIZE_HIMETRIC cxSrc,
630 OLE_YSIZE_HIMETRIC cySrc,
633 OLEPictureImpl *This = (OLEPictureImpl *)iface;
634 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
635 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
637 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
638 prcWBounds->right, prcWBounds->bottom);
641 * While the documentation suggests this to be here (or after rendering?)
642 * it does cause an endless recursion in my sample app. -MM 20010804
643 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
646 switch(This->desc.picType) {
652 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
653 NB y-axis gets flipped */
655 hdcBmp = CreateCompatibleDC(0);
656 SetMapMode(hdcBmp, MM_ANISOTROPIC);
657 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
658 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
659 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
660 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
663 HDC hdcMask = CreateCompatibleDC(0);
664 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
666 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
668 SetMapMode(hdcMask, MM_ANISOTROPIC);
669 SetWindowOrgEx(hdcMask, 0, 0, NULL);
670 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
671 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
672 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
674 SetBkColor(hdc, RGB(255, 255, 255));
675 SetTextColor(hdc, RGB(0, 0, 0));
676 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
677 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
679 SelectObject(hdcMask, hOldbm);
682 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
683 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
686 SelectObject(hdcBmp, hbmpOld);
691 FIXME("Not quite correct implementation of rendering icons...\n");
692 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
695 case PICTYPE_METAFILE:
701 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
702 SetViewportOrgEx(hdc, x, y, &prevOrg);
703 SetViewportExtEx(hdc, cx, cy, &prevExt);
705 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
706 ERR("PlayMetaFile failed!\n");
708 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
709 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
710 SetMapMode(hdc, oldmode);
714 case PICTYPE_ENHMETAFILE:
716 RECT rc = { x, y, x + cx, y + cy };
717 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
722 FIXME("type %d not implemented\n", This->desc.picType);
728 /************************************************************************
729 * OLEPictureImpl_set_hPal
731 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
734 OLEPictureImpl *This = (OLEPictureImpl *)iface;
735 FIXME("(%p)->(%08x): stub\n", This, hpal);
736 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
740 /************************************************************************
741 * OLEPictureImpl_get_CurDC
743 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
746 OLEPictureImpl *This = (OLEPictureImpl *)iface;
747 TRACE("(%p), returning %p\n", This, This->hDCCur);
748 if (phdc) *phdc = This->hDCCur;
752 /************************************************************************
753 * OLEPictureImpl_SelectPicture
755 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
758 OLE_HANDLE *phbmpOut)
760 OLEPictureImpl *This = (OLEPictureImpl *)iface;
761 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
762 if (This->desc.picType == PICTYPE_BITMAP) {
763 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
766 *phdcOut = This->hDCCur;
767 This->hDCCur = hdcIn;
769 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
772 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
777 /************************************************************************
778 * OLEPictureImpl_get_KeepOriginalFormat
780 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
783 OLEPictureImpl *This = (OLEPictureImpl *)iface;
784 TRACE("(%p)->(%p)\n", This, pfKeep);
787 *pfKeep = This->keepOrigFormat;
791 /************************************************************************
792 * OLEPictureImpl_put_KeepOriginalFormat
794 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
797 OLEPictureImpl *This = (OLEPictureImpl *)iface;
798 TRACE("(%p)->(%d)\n", This, keep);
799 This->keepOrigFormat = keep;
800 /* FIXME: what DISPID notification here? */
804 /************************************************************************
805 * OLEPictureImpl_PictureChanged
807 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
809 OLEPictureImpl *This = (OLEPictureImpl *)iface;
810 TRACE("(%p)->()\n", This);
811 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
812 This->bIsDirty = TRUE;
816 /************************************************************************
817 * OLEPictureImpl_SaveAsFile
819 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
824 OLEPictureImpl *This = (OLEPictureImpl *)iface;
825 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
826 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
829 /************************************************************************
830 * OLEPictureImpl_get_Attributes
832 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
835 OLEPictureImpl *This = (OLEPictureImpl *)iface;
836 TRACE("(%p)->(%p).\n", This, pdwAttr);
838 switch (This->desc.picType) {
839 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
840 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
841 case PICTYPE_ENHMETAFILE: /* fall through */
842 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
843 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
849 /************************************************************************
850 * IConnectionPointContainer
852 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
853 IConnectionPointContainer* iface,
857 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
859 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
862 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
863 IConnectionPointContainer* iface)
865 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
867 return IPicture_AddRef((IPicture *)This);
870 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
871 IConnectionPointContainer* iface)
873 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
875 return IPicture_Release((IPicture *)This);
878 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
879 IConnectionPointContainer* iface,
880 IEnumConnectionPoints** ppEnum)
882 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
884 FIXME("(%p,%p), stub!\n",This,ppEnum);
888 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
889 IConnectionPointContainer* iface,
891 IConnectionPoint **ppCP)
893 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
894 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
898 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
899 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
900 FIXME("no connection point for %s\n",debugstr_guid(riid));
901 return CONNECT_E_NOCONNECTION;
905 /************************************************************************
909 /************************************************************************
910 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
912 * See Windows documentation for more details on IUnknown methods.
914 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
915 IPersistStream* iface,
919 OLEPictureImpl *This = impl_from_IPersistStream(iface);
921 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
924 /************************************************************************
925 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
927 * See Windows documentation for more details on IUnknown methods.
929 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
930 IPersistStream* iface)
932 OLEPictureImpl *This = impl_from_IPersistStream(iface);
934 return IPicture_AddRef((IPicture *)This);
937 /************************************************************************
938 * OLEPictureImpl_IPersistStream_Release (IUnknown)
940 * See Windows documentation for more details on IUnknown methods.
942 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
943 IPersistStream* iface)
945 OLEPictureImpl *This = impl_from_IPersistStream(iface);
947 return IPicture_Release((IPicture *)This);
950 /************************************************************************
951 * OLEPictureImpl_IPersistStream_GetClassID
953 static HRESULT WINAPI OLEPictureImpl_GetClassID(
954 IPersistStream* iface,CLSID* pClassID)
956 TRACE("(%p)\n", pClassID);
957 *pClassID = CLSID_StdPicture;
961 /************************************************************************
962 * OLEPictureImpl_IPersistStream_IsDirty
964 static HRESULT WINAPI OLEPictureImpl_IsDirty(
965 IPersistStream* iface)
967 OLEPictureImpl *This = impl_from_IPersistStream(iface);
968 FIXME("(%p),stub!\n",This);
972 #ifdef SONAME_LIBJPEG
974 static void *libjpeg_handle;
975 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
976 MAKE_FUNCPTR(jpeg_std_error);
977 MAKE_FUNCPTR(jpeg_CreateDecompress);
978 MAKE_FUNCPTR(jpeg_read_header);
979 MAKE_FUNCPTR(jpeg_start_decompress);
980 MAKE_FUNCPTR(jpeg_read_scanlines);
981 MAKE_FUNCPTR(jpeg_finish_decompress);
982 MAKE_FUNCPTR(jpeg_destroy_decompress);
985 static void *load_libjpeg(void)
987 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
989 #define LOAD_FUNCPTR(f) \
990 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
991 libjpeg_handle = NULL; \
995 LOAD_FUNCPTR(jpeg_std_error);
996 LOAD_FUNCPTR(jpeg_CreateDecompress);
997 LOAD_FUNCPTR(jpeg_read_header);
998 LOAD_FUNCPTR(jpeg_start_decompress);
999 LOAD_FUNCPTR(jpeg_read_scanlines);
1000 LOAD_FUNCPTR(jpeg_finish_decompress);
1001 LOAD_FUNCPTR(jpeg_destroy_decompress);
1004 return libjpeg_handle;
1007 /* for the jpeg decompressor source manager. */
1008 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1010 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1011 ERR("(), should not get here.\n");
1015 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1016 TRACE("Skipping %ld bytes...\n", num_bytes);
1017 cinfo->src->next_input_byte += num_bytes;
1018 cinfo->src->bytes_in_buffer -= num_bytes;
1021 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1022 ERR("(desired=%d), should not get here.\n",desired);
1025 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1026 #endif /* SONAME_LIBJPEG */
1029 unsigned char *data;
1030 unsigned int curoff;
1034 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1035 struct gifdata *gd = (struct gifdata*)gif->UserData;
1037 if (len+gd->curoff > gd->len) {
1038 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1039 len = gd->len - gd->curoff;
1041 memcpy(data, gd->data+gd->curoff, len);
1047 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1058 int transparent = -1;
1065 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1066 ret = DGifSlurp(gif);
1067 if (ret == GIF_ERROR) {
1068 ERR("Failed reading GIF using libgif.\n");
1071 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1072 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1073 TRACE("imgcnt %d\n", gif->ImageCount);
1074 if (gif->ImageCount<1) {
1075 ERR("GIF stream does not have images inside?\n");
1078 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1079 gif->Image.Width, gif->Image.Height,
1080 gif->Image.Left, gif->Image.Top,
1081 gif->Image.Interlace
1084 padding = (gif->SWidth+3) & ~3;
1085 si = gif->SavedImages+0;
1086 gid = &(si->ImageDesc);
1088 if (!cm) cm = gif->SColorMap;
1089 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1090 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1092 /* look for the transparent color extension */
1093 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1094 eb = si->ExtensionBlocks + i;
1095 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1096 if ((eb->Bytes[0] & 1) == 1) {
1097 transparent = (unsigned char)eb->Bytes[3];
1102 for (i = 0; i < cm->ColorCount; i++) {
1103 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1104 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1105 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1106 if (i == transparent) {
1107 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1108 bmi->bmiColors[i].rgbGreen,
1109 bmi->bmiColors[i].rgbBlue);
1113 /* Map to in picture coordinates */
1114 for (i = 0, j = 0; i < gid->Height; i++) {
1115 if (gif->Image.Interlace) {
1117 bytes + (gid->Top + j) * padding + gid->Left,
1118 si->RasterBits + i * gid->Width,
1121 /* Lower bits of interlaced counter encode current interlace */
1122 if (j & 1) j += 2; /* Currently filling odd rows */
1123 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1124 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1126 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1127 /* End of current interlace, go to next interlace */
1128 if (j & 2) j = 1; /* Next iteration fills odd rows */
1129 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1130 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1134 bytes + (gid->Top + i) * padding + gid->Left,
1135 si->RasterBits + i * gid->Width,
1140 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1141 bmi->bmiHeader.biWidth = gif->SWidth;
1142 bmi->bmiHeader.biHeight = -gif->SHeight;
1143 bmi->bmiHeader.biPlanes = 1;
1144 bmi->bmiHeader.biBitCount = 8;
1145 bmi->bmiHeader.biCompression = BI_RGB;
1146 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1147 bmi->bmiHeader.biXPelsPerMeter = 0;
1148 bmi->bmiHeader.biYPelsPerMeter = 0;
1149 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1150 bmi->bmiHeader.biClrImportant = 0;
1153 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1162 if (transparent > -1) {
1163 /* Create the Mask */
1164 HDC hdc = CreateCompatibleDC(0);
1165 HDC hdcMask = CreateCompatibleDC(0);
1167 HBITMAP hOldbitmapmask;
1169 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1172 This->hbmXor = CreateDIBitmap(
1181 bmi->bmiColors[0].rgbRed = 0;
1182 bmi->bmiColors[0].rgbGreen = 0;
1183 bmi->bmiColors[0].rgbBlue = 0;
1184 bmi->bmiColors[1].rgbRed = 255;
1185 bmi->bmiColors[1].rgbGreen = 255;
1186 bmi->bmiColors[1].rgbBlue = 255;
1188 bmi->bmiHeader.biBitCount = 1;
1189 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1190 bmi->bmiHeader.biClrUsed = 2;
1192 for (i = 0; i < gif->SHeight; i++) {
1193 unsigned char * colorPointer = bytes + padding * i;
1194 unsigned char * monoPointer = bytes + monopadding * i;
1195 for (j = 0; j < gif->SWidth; j++) {
1196 unsigned char pixel = colorPointer[j];
1197 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1198 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1202 hTempMask = CreateDIBitmap(
1212 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1213 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1214 hOldbitmap = SelectObject(hdc, hTempMask);
1215 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1217 SetBkColor(hdc, RGB(255, 255, 255));
1218 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1220 /* We no longer need the original bitmap, so we apply the first
1221 transformation with the mask to speed up the rendering */
1222 SelectObject(hdc, This->hbmXor);
1223 SetBkColor(hdc, RGB(0,0,0));
1224 SetTextColor(hdc, RGB(255,255,255));
1225 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1226 hdcMask, 0, 0, SRCAND);
1228 SelectObject(hdc, hOldbitmap);
1229 SelectObject(hdcMask, hOldbitmapmask);
1232 DeleteObject(hTempMask);
1236 This->desc.picType = PICTYPE_BITMAP;
1237 OLEPictureImpl_SetBitmap(This);
1239 HeapFree(GetProcessHeap(),0,bmi);
1240 HeapFree(GetProcessHeap(),0,bytes);
1244 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1246 #ifdef SONAME_LIBJPEG
1247 struct jpeg_decompress_struct jd;
1248 struct jpeg_error_mgr jerr;
1251 JSAMPROW samprow,oldsamprow;
1252 BITMAPINFOHEADER bmi;
1255 struct jpeg_source_mgr xjsm;
1259 if(!libjpeg_handle) {
1260 if(!load_libjpeg()) {
1261 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1266 /* This is basically so we can use in-memory data for jpeg decompression.
1267 * We need to have all the functions.
1269 xjsm.next_input_byte = xbuf;
1270 xjsm.bytes_in_buffer = xread;
1271 xjsm.init_source = _jpeg_init_source;
1272 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1273 xjsm.skip_input_data = _jpeg_skip_input_data;
1274 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1275 xjsm.term_source = _jpeg_term_source;
1277 jd.err = pjpeg_std_error(&jerr);
1278 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1279 * jpeg_create_decompress(&jd); */
1280 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1282 ret=pjpeg_read_header(&jd,TRUE);
1283 jd.out_color_space = JCS_RGB;
1284 pjpeg_start_decompress(&jd);
1285 if (ret != JPEG_HEADER_OK) {
1286 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1287 HeapFree(GetProcessHeap(),0,xbuf);
1291 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1292 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1293 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1296 oldsamprow = samprow;
1297 while ( jd.output_scanline<jd.output_height ) {
1298 x = pjpeg_read_scanlines(&jd,&samprow,1);
1300 ERR("failed to read current scanline?\n");
1303 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1304 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1305 *(bits++) = *(samprow+2);
1306 *(bits++) = *(samprow+1);
1307 *(bits++) = *(samprow);
1309 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1310 samprow = oldsamprow;
1314 bmi.biSize = sizeof(bmi);
1315 bmi.biWidth = jd.output_width;
1316 bmi.biHeight = -jd.output_height;
1318 bmi.biBitCount = jd.output_components<<3;
1319 bmi.biCompression = BI_RGB;
1320 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1321 bmi.biXPelsPerMeter = 0;
1322 bmi.biYPelsPerMeter = 0;
1324 bmi.biClrImportant = 0;
1326 HeapFree(GetProcessHeap(),0,samprow);
1327 pjpeg_finish_decompress(&jd);
1328 pjpeg_destroy_decompress(&jd);
1330 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1339 This->desc.picType = PICTYPE_BITMAP;
1340 OLEPictureImpl_SetBitmap(This);
1341 HeapFree(GetProcessHeap(),0,bits);
1344 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1349 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1351 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1352 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1355 /* Does not matter whether this is a coreheader or not, we only use
1356 * components which are in both
1359 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1363 xbuf+bfh->bfOffBits,
1368 if (This->desc.u.bmp.hbitmap == 0)
1370 This->desc.picType = PICTYPE_BITMAP;
1371 OLEPictureImpl_SetBitmap(This);
1375 /*****************************************************
1376 * start of PNG-specific code
1377 * currently only supports colortype PNG_COLOR_TYPE_RGB
1379 #ifdef SONAME_LIBPNG
1386 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1389 png_io * io_ptr = png_ptr->io_ptr;
1391 if(length + io_ptr->position > io_ptr->size){
1392 length = io_ptr->size - io_ptr->position;
1395 memcpy(data, io_ptr->buff + io_ptr->position, length);
1397 io_ptr->position += length;
1400 static void *libpng_handle;
1401 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1402 MAKE_FUNCPTR(png_create_read_struct);
1403 MAKE_FUNCPTR(png_create_info_struct);
1404 MAKE_FUNCPTR(png_set_read_fn);
1405 MAKE_FUNCPTR(png_read_info);
1406 MAKE_FUNCPTR(png_read_image);
1407 MAKE_FUNCPTR(png_get_rowbytes);
1408 MAKE_FUNCPTR(png_set_bgr);
1409 MAKE_FUNCPTR(png_destroy_read_struct);
1410 MAKE_FUNCPTR(png_set_palette_to_rgb);
1411 MAKE_FUNCPTR(png_read_update_info);
1412 MAKE_FUNCPTR(png_get_tRNS);
1413 MAKE_FUNCPTR(png_get_PLTE);
1414 MAKE_FUNCPTR(png_set_expand);
1417 static void *load_libpng(void)
1419 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1421 #define LOAD_FUNCPTR(f) \
1422 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1423 libpng_handle = NULL; \
1426 LOAD_FUNCPTR(png_create_read_struct);
1427 LOAD_FUNCPTR(png_create_info_struct);
1428 LOAD_FUNCPTR(png_set_read_fn);
1429 LOAD_FUNCPTR(png_read_info);
1430 LOAD_FUNCPTR(png_read_image);
1431 LOAD_FUNCPTR(png_get_rowbytes);
1432 LOAD_FUNCPTR(png_set_bgr);
1433 LOAD_FUNCPTR(png_destroy_read_struct);
1434 LOAD_FUNCPTR(png_set_palette_to_rgb);
1435 LOAD_FUNCPTR(png_read_update_info);
1436 LOAD_FUNCPTR(png_get_tRNS);
1437 LOAD_FUNCPTR(png_get_PLTE);
1438 LOAD_FUNCPTR(png_set_expand);
1442 return libpng_handle;
1444 #endif /* SONAME_LIBPNG */
1446 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1448 #ifdef SONAME_LIBPNG
1450 png_structp png_ptr = NULL;
1451 png_infop info_ptr = NULL;
1452 INT row, rowsize, height, width, num_trans, i, j;
1453 png_bytep* row_pointers = NULL;
1454 png_bytep pngdata = NULL;
1455 BITMAPINFOHEADER bmi;
1456 HDC hdcref = NULL, hdcXor, hdcMask;
1460 png_color_16p trans_values;
1461 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1462 HBITMAP hbmoldXor, hbmoldMask, temp;
1464 if(!libpng_handle) {
1465 if(!load_libpng()) {
1466 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1475 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1478 if(setjmp(png_jmpbuf(png_ptr))){
1479 TRACE("Error in libpng\n");
1484 info_ptr = ppng_create_info_struct(png_ptr);
1485 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1486 ppng_read_info(png_ptr, info_ptr);
1488 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1489 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1490 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1491 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1496 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1499 /* sets format from anything to RGBA */
1500 ppng_set_expand(png_ptr);
1501 /* sets format to BGRA */
1502 ppng_set_bgr(png_ptr);
1504 ppng_read_update_info(png_ptr, info_ptr);
1506 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1507 /* align rowsize to 4-byte boundary */
1508 rowsize = (rowsize + 3) & ~3;
1509 height = info_ptr->height;
1510 width = info_ptr->width;
1512 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1513 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1515 if(!pngdata || !row_pointers){
1520 for (row = 0; row < height; row++){
1521 row_pointers[row] = pngdata + row * rowsize;
1524 ppng_read_image(png_ptr, row_pointers);
1526 bmi.biSize = sizeof(bmi);
1527 bmi.biWidth = width;
1528 bmi.biHeight = -height;
1530 bmi.biBitCount = info_ptr->channels * 8;
1531 bmi.biCompression = BI_RGB;
1532 bmi.biSizeImage = height * rowsize;
1533 bmi.biXPelsPerMeter = 0;
1534 bmi.biYPelsPerMeter = 0;
1536 bmi.biClrImportant = 0;
1539 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1548 /* only fully-transparent alpha is handled */
1549 if((info_ptr->channels != 4) || !transparency){
1550 ReleaseDC(0, hdcref);
1554 This->hbmXor = CreateDIBitmap(
1563 /* set transparent pixels to black, all others to white */
1564 for(i = 0; i < height; i++){
1565 for(j = 3; j < rowsize; j += 4){
1566 if(row_pointers[i][j] == 0)
1567 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1569 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1573 temp = CreateDIBitmap(
1582 ReleaseDC(0, hdcref);
1584 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1585 hdcXor = CreateCompatibleDC(NULL);
1586 hdcMask = CreateCompatibleDC(NULL);
1588 hbmoldXor = SelectObject(hdcXor,temp);
1589 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1590 SetBkColor(hdcXor,black);
1591 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1593 SelectObject(hdcXor,This->hbmXor);
1596 SetTextColor(hdcXor,white);
1597 SetBkColor(hdcXor,black);
1598 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1600 SelectObject(hdcXor,hbmoldXor);
1601 SelectObject(hdcMask,hbmoldMask);
1607 This->desc.picType = PICTYPE_BITMAP;
1608 OLEPictureImpl_SetBitmap(This);
1613 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1614 HeapFree(GetProcessHeap(), 0, row_pointers);
1615 HeapFree(GetProcessHeap(), 0, pngdata);
1617 #else /* SONAME_LIBPNG */
1618 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1623 /*****************************************************
1624 * start of Icon-specific code
1627 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1630 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1635 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1636 FIXME("icon.idType=%d\n",cifd->idType);
1637 FIXME("icon.idCount=%d\n",cifd->idCount);
1639 for (i=0;i<cifd->idCount;i++) {
1640 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1641 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1642 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1643 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1644 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1645 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1646 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1647 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1651 /* If we have more than one icon, try to find the best.
1652 * this currently means '32 pixel wide'.
1654 if (cifd->idCount!=1) {
1655 for (i=0;i<cifd->idCount;i++) {
1656 if (cifd->idEntries[i].bWidth == 32)
1659 if (i==cifd->idCount) i=0;
1662 hicon = CreateIconFromResourceEx(
1663 xbuf+cifd->idEntries[i].dwDIBOffset,
1664 cifd->idEntries[i].dwDIBSize,
1667 cifd->idEntries[i].bWidth,
1668 cifd->idEntries[i].bHeight,
1672 ERR("CreateIcon failed.\n");
1675 This->desc.picType = PICTYPE_ICON;
1676 This->desc.u.icon.hicon = hicon;
1677 This->origWidth = cifd->idEntries[i].bWidth;
1678 This->origHeight = cifd->idEntries[i].bHeight;
1679 hdcRef = CreateCompatibleDC(0);
1680 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1681 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1687 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1688 const BYTE *data, ULONG size)
1693 hemf = SetEnhMetaFileBits(size, data);
1694 if (!hemf) return E_FAIL;
1696 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1698 This->desc.picType = PICTYPE_ENHMETAFILE;
1699 This->desc.u.emf.hemf = hemf;
1701 This->origWidth = 0;
1702 This->origHeight = 0;
1703 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1704 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1709 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1710 const BYTE *data, ULONG size)
1712 APM_HEADER *header = (APM_HEADER *)data;
1715 if (size < sizeof(APM_HEADER))
1717 if (header->key != 0x9ac6cdd7)
1720 /* SetMetaFileBitsEx performs data check on its own */
1721 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1722 if (!hmf) return E_FAIL;
1724 This->desc.picType = PICTYPE_METAFILE;
1725 This->desc.u.wmf.hmeta = hmf;
1726 This->desc.u.wmf.xExt = 0;
1727 This->desc.u.wmf.yExt = 0;
1729 This->origWidth = 0;
1730 This->origHeight = 0;
1731 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1732 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1736 /************************************************************************
1737 * BITMAP FORMAT FLAGS -
1738 * Flags that differentiate between different types of bitmaps.
1741 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1742 #define BITMAP_FORMAT_JPEG 0xd8ff
1743 #define BITMAP_FORMAT_GIF 0x4947
1744 #define BITMAP_FORMAT_PNG 0x5089
1745 #define BITMAP_FORMAT_APM 0xcdd7
1747 /************************************************************************
1748 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1750 * Loads the binary data from the IStream. Starts at current position.
1751 * There appears to be an 2 DWORD header:
1755 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1757 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1758 HRESULT hr = E_FAIL;
1759 BOOL headerisdata = FALSE;
1760 BOOL statfailed = FALSE;
1761 ULONG xread, toread;
1767 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1769 TRACE("(%p,%p)\n",This,pStm);
1771 /****************************************************************************************
1772 * Part 1: Load the data
1774 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1775 * out whether we do.
1777 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1778 * compound file. This may explain most, if not all, of the cases of "no
1779 * header", and the header validation should take this into account.
1780 * At least in Visual Basic 6, resource streams, valid headers are
1781 * header[0] == "lt\0\0",
1782 * header[1] == length_of_stream.
1784 * Also handle streams where we do not have a working "Stat" method by
1785 * reading all data until the end of the stream.
1787 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1789 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1791 /* we will read at least 8 byte ... just right below */
1792 statstg.cbSize.QuadPart = 8;
1797 headerisdata = FALSE;
1799 hr=IStream_Read(pStm,header,8,&xread);
1800 if (hr || xread!=8) {
1801 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1802 return (hr?hr:E_FAIL);
1804 headerread += xread;
1807 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1808 if (toread != 0 && toread != header[1])
1809 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1812 if (toread == 0) break;
1814 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1815 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1816 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1817 (header[0] == EMR_HEADER) || /* EMF header */
1818 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1820 ) {/* Found start of bitmap data */
1821 headerisdata = TRUE;
1823 toread = statstg.cbSize.QuadPart-8;
1827 FIXME("Unknown stream header magic: %08x\n", header[0]);
1831 } while (!headerisdata);
1833 if (statfailed) { /* we don't know the size ... read all we get */
1835 int origsize = sizeinc;
1838 TRACE("Reading all data from stream.\n");
1839 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1841 memcpy (xbuf, header, 8);
1843 while (xread < origsize) {
1844 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1849 if (!nread || hr) /* done, or error */
1851 if (xread == origsize) {
1852 origsize += sizeinc;
1853 sizeinc = 2*sizeinc; /* exponential increase */
1854 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1858 TRACE("hr in no-stat loader case is %08x\n", hr);
1859 TRACE("loaded %d bytes.\n", xread);
1860 This->datalen = xread;
1863 This->datalen = toread+(headerisdata?8:0);
1864 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1866 return E_OUTOFMEMORY;
1869 memcpy (xbuf, header, 8);
1871 while (xread < This->datalen) {
1873 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1878 if (xread != This->datalen)
1879 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1881 if (This->datalen == 0) { /* Marks the "NONE" picture */
1882 This->desc.picType = PICTYPE_NONE;
1887 /****************************************************************************************
1888 * Part 2: Process the loaded data
1891 magic = xbuf[0] + (xbuf[1]<<8);
1892 This->loadtime_format = magic;
1895 case BITMAP_FORMAT_GIF: /* GIF */
1896 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1898 case BITMAP_FORMAT_JPEG: /* JPEG */
1899 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1901 case BITMAP_FORMAT_BMP: /* Bitmap */
1902 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1904 case BITMAP_FORMAT_PNG: /* PNG */
1905 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1907 case BITMAP_FORMAT_APM: /* APM */
1908 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1910 case 0x0000: { /* ICON , first word is dwReserved */
1911 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1918 /* let's see if it's a EMF */
1919 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1920 if (hr == S_OK) break;
1922 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1924 for (i=0;i<xread+8;i++) {
1925 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1926 else MESSAGE("%02x ",xbuf[i-8]);
1927 if (i % 10 == 9) MESSAGE("\n");
1933 This->bIsDirty = FALSE;
1935 /* FIXME: this notify is not really documented */
1937 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1941 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1945 BITMAPINFO * pInfoBitmap;
1946 int iNumPaletteEntries;
1947 unsigned char * pPixelData;
1948 BITMAPFILEHEADER * pFileHeader;
1949 BITMAPINFO * pInfoHeader;
1951 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1952 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1954 /* Find out bitmap size and padded length */
1956 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1957 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1959 /* Fetch bitmap palette & pixel data */
1961 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1962 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1964 /* Calculate the total length required for the BMP data */
1965 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1966 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1967 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1969 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1970 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1972 iNumPaletteEntries = 0;
1975 sizeof(BITMAPFILEHEADER) +
1976 sizeof(BITMAPINFOHEADER) +
1977 iNumPaletteEntries * sizeof(RGBQUAD) +
1978 pInfoBitmap->bmiHeader.biSizeImage;
1979 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1981 /* Fill the BITMAPFILEHEADER */
1982 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1983 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1984 pFileHeader->bfSize = *pLength;
1985 pFileHeader->bfOffBits =
1986 sizeof(BITMAPFILEHEADER) +
1987 sizeof(BITMAPINFOHEADER) +
1988 iNumPaletteEntries * sizeof(RGBQUAD);
1990 /* Fill the BITMAPINFOHEADER and the palette data */
1991 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1992 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1994 (unsigned char *)(*ppBuffer) +
1995 sizeof(BITMAPFILEHEADER) +
1996 sizeof(BITMAPINFOHEADER) +
1997 iNumPaletteEntries * sizeof(RGBQUAD),
1998 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2001 HeapFree(GetProcessHeap(), 0, pPixelData);
2002 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2006 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2011 *ppBuffer = NULL; *pLength = 0;
2012 if (GetIconInfo(hIcon, &infoIcon)) {
2014 BITMAPINFO * pInfoBitmap;
2015 unsigned char * pIconData = NULL;
2016 unsigned int iDataSize = 0;
2018 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2020 /* Find out icon size */
2022 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2023 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2025 /* Auxiliary pointers */
2026 CURSORICONFILEDIR * pIconDir;
2027 CURSORICONFILEDIRENTRY * pIconEntry;
2028 BITMAPINFOHEADER * pIconBitmapHeader;
2029 unsigned int iOffsetPalette;
2030 unsigned int iOffsetColorData;
2031 unsigned int iOffsetMaskData;
2033 unsigned int iLengthScanLineColor;
2034 unsigned int iLengthScanLineMask;
2035 unsigned int iNumEntriesPalette;
2037 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2038 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2040 FIXME("DEBUG: bitmap size is %d x %d\n",
2041 pInfoBitmap->bmiHeader.biWidth,
2042 pInfoBitmap->bmiHeader.biHeight);
2043 FIXME("DEBUG: bitmap bpp is %d\n",
2044 pInfoBitmap->bmiHeader.biBitCount);
2045 FIXME("DEBUG: bitmap nplanes is %d\n",
2046 pInfoBitmap->bmiHeader.biPlanes);
2047 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2048 pInfoBitmap->bmiHeader.biSizeImage);
2050 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2051 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2052 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2054 /* Fill out the CURSORICONFILEDIR */
2055 pIconDir = (CURSORICONFILEDIR *)pIconData;
2056 pIconDir->idType = 1;
2057 pIconDir->idCount = 1;
2059 /* Fill out the CURSORICONFILEDIRENTRY */
2060 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2061 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2062 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2063 pIconEntry->bColorCount =
2064 (pInfoBitmap->bmiHeader.biBitCount < 8)
2065 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2067 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2068 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2069 pIconEntry->dwDIBSize = 0;
2070 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2072 /* Fill out the BITMAPINFOHEADER */
2073 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2074 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2076 /* Find out whether a palette exists for the bitmap */
2077 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2078 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2079 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2080 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2081 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2082 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2083 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2084 iNumEntriesPalette = 3;
2085 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2086 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2088 iNumEntriesPalette = 0;
2091 /* Add bitmap size and header size to icon data size. */
2092 iOffsetPalette = iDataSize;
2093 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2094 iOffsetColorData = iDataSize;
2095 iDataSize += pIconBitmapHeader->biSizeImage;
2096 iOffsetMaskData = iDataSize;
2097 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2098 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2099 pIconBitmapHeader->biHeight *= 2;
2100 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2101 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2102 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2103 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2105 /* Get the actual bitmap data from the icon bitmap */
2106 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2107 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2108 if (iNumEntriesPalette > 0) {
2109 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2110 iNumEntriesPalette * sizeof(RGBQUAD));
2113 /* Reset all values so that GetDIBits call succeeds */
2114 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2115 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2116 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2118 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2119 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2120 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2122 printf("ERROR: unable to get bitmap mask (error %u)\n",
2127 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2128 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2130 /* Write out everything produced so far to the stream */
2131 *ppBuffer = pIconData; *pLength = iDataSize;
2135 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2140 Remarks (from MSDN entry on GetIconInfo):
2142 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2143 members of ICONINFO. The calling application must manage
2144 these bitmaps and delete them when they are no longer
2147 if (hDC) ReleaseDC(0, hDC);
2148 DeleteObject(infoIcon.hbmMask);
2149 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2150 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2152 printf("ERROR: Unable to get icon information (error %u)\n",
2158 static HRESULT WINAPI OLEPictureImpl_Save(
2159 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2161 HRESULT hResult = E_NOTIMPL;
2163 unsigned int iDataSize;
2165 int iSerializeResult = 0;
2166 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2168 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2170 switch (This->desc.picType) {
2172 if (This->bIsDirty || !This->data) {
2173 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2174 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2178 HeapFree(GetProcessHeap(), 0, This->data);
2179 This->data = pIconData;
2180 This->datalen = iDataSize;
2182 if (This->loadtime_magic != 0xdeadbeef) {
2185 header[0] = This->loadtime_magic;
2186 header[1] = This->datalen;
2187 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2189 IStream_Write(pStm, This->data, This->datalen, &dummy);
2193 case PICTYPE_BITMAP:
2194 if (This->bIsDirty) {
2195 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2196 case BITMAP_FORMAT_BMP:
2197 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2199 case BITMAP_FORMAT_JPEG:
2200 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2202 case BITMAP_FORMAT_GIF:
2203 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2205 case BITMAP_FORMAT_PNG:
2206 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2209 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2212 if (iSerializeResult) {
2214 if (This->loadtime_magic != 0xdeadbeef) {
2219 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2220 header[1] = iDataSize;
2221 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2223 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2225 HeapFree(GetProcessHeap(), 0, This->data);
2226 This->data = pIconData;
2227 This->datalen = iDataSize;
2232 if (This->loadtime_magic != 0xdeadbeef) {
2237 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2238 header[1] = This->datalen;
2239 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2241 IStream_Write(pStm, This->data, This->datalen, &dummy);
2245 case PICTYPE_METAFILE:
2246 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2248 case PICTYPE_ENHMETAFILE:
2249 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2252 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2255 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2259 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2260 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2262 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2263 FIXME("(%p,%p),stub!\n",This,pcbSize);
2268 /************************************************************************
2272 /************************************************************************
2273 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2275 * See Windows documentation for more details on IUnknown methods.
2277 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2282 OLEPictureImpl *This = impl_from_IDispatch(iface);
2284 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2287 /************************************************************************
2288 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2290 * See Windows documentation for more details on IUnknown methods.
2292 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2295 OLEPictureImpl *This = impl_from_IDispatch(iface);
2297 return IPicture_AddRef((IPicture *)This);
2300 /************************************************************************
2301 * OLEPictureImpl_IDispatch_Release (IUnknown)
2303 * See Windows documentation for more details on IUnknown methods.
2305 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2308 OLEPictureImpl *This = impl_from_IDispatch(iface);
2310 return IPicture_Release((IPicture *)This);
2313 /************************************************************************
2314 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2316 * See Windows documentation for more details on IDispatch methods.
2318 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2320 unsigned int* pctinfo)
2322 TRACE("(%p)\n", pctinfo);
2329 /************************************************************************
2330 * OLEPictureImpl_GetTypeInfo (IDispatch)
2332 * See Windows documentation for more details on IDispatch methods.
2334 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2338 ITypeInfo** ppTInfo)
2340 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2344 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2349 hres = LoadTypeLib(stdole2tlb, &tl);
2352 ERR("Could not load stdole2.tlb\n");
2356 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2358 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2363 /************************************************************************
2364 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2366 * See Windows documentation for more details on IDispatch methods.
2368 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2371 LPOLESTR* rgszNames,
2379 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2380 rgszNames, cNames, (int)lcid, rgDispId);
2384 return E_INVALIDARG;
2388 /* retrieve type information */
2389 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2393 ERR("GetTypeInfo failed.\n");
2397 /* convert names to DISPIDs */
2398 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2399 ITypeInfo_Release(pTInfo);
2405 /************************************************************************
2406 * OLEPictureImpl_Invoke (IDispatch)
2408 * See Windows documentation for more details on IDispatch methods.
2410 static HRESULT WINAPI OLEPictureImpl_Invoke(
2412 DISPID dispIdMember,
2416 DISPPARAMS* pDispParams,
2417 VARIANT* pVarResult,
2418 EXCEPINFO* pExepInfo,
2421 OLEPictureImpl *This = impl_from_IDispatch(iface);
2423 /* validate parameters */
2425 if (!IsEqualIID(riid, &IID_NULL))
2427 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2428 return DISP_E_UNKNOWNNAME;
2433 ERR("null pDispParams not allowed\n");
2434 return DISP_E_PARAMNOTOPTIONAL;
2437 if (wFlags & DISPATCH_PROPERTYGET)
2439 if (pDispParams->cArgs != 0)
2441 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2442 return DISP_E_BADPARAMCOUNT;
2446 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2447 return DISP_E_PARAMNOTOPTIONAL;
2450 else if (wFlags & DISPATCH_PROPERTYPUT)
2452 if (pDispParams->cArgs != 1)
2454 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2455 return DISP_E_BADPARAMCOUNT;
2459 switch (dispIdMember)
2461 case DISPID_PICT_HANDLE:
2462 if (wFlags & DISPATCH_PROPERTYGET)
2464 TRACE("DISPID_PICT_HANDLE\n");
2465 V_VT(pVarResult) = VT_I4;
2466 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2469 case DISPID_PICT_HPAL:
2470 if (wFlags & DISPATCH_PROPERTYGET)
2472 TRACE("DISPID_PICT_HPAL\n");
2473 V_VT(pVarResult) = VT_I4;
2474 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2476 else if (wFlags & DISPATCH_PROPERTYPUT)
2480 TRACE("DISPID_PICT_HPAL\n");
2482 VariantInit(&vararg);
2483 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2487 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2489 VariantClear(&vararg);
2493 case DISPID_PICT_TYPE:
2494 if (wFlags & DISPATCH_PROPERTYGET)
2496 TRACE("DISPID_PICT_TYPE\n");
2497 V_VT(pVarResult) = VT_I2;
2498 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2501 case DISPID_PICT_WIDTH:
2502 if (wFlags & DISPATCH_PROPERTYGET)
2504 TRACE("DISPID_PICT_WIDTH\n");
2505 V_VT(pVarResult) = VT_I4;
2506 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2509 case DISPID_PICT_HEIGHT:
2510 if (wFlags & DISPATCH_PROPERTYGET)
2512 TRACE("DISPID_PICT_HEIGHT\n");
2513 V_VT(pVarResult) = VT_I4;
2514 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2519 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2520 return DISP_E_MEMBERNOTFOUND;
2524 static const IPictureVtbl OLEPictureImpl_VTable =
2526 OLEPictureImpl_QueryInterface,
2527 OLEPictureImpl_AddRef,
2528 OLEPictureImpl_Release,
2529 OLEPictureImpl_get_Handle,
2530 OLEPictureImpl_get_hPal,
2531 OLEPictureImpl_get_Type,
2532 OLEPictureImpl_get_Width,
2533 OLEPictureImpl_get_Height,
2534 OLEPictureImpl_Render,
2535 OLEPictureImpl_set_hPal,
2536 OLEPictureImpl_get_CurDC,
2537 OLEPictureImpl_SelectPicture,
2538 OLEPictureImpl_get_KeepOriginalFormat,
2539 OLEPictureImpl_put_KeepOriginalFormat,
2540 OLEPictureImpl_PictureChanged,
2541 OLEPictureImpl_SaveAsFile,
2542 OLEPictureImpl_get_Attributes
2545 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2547 OLEPictureImpl_IDispatch_QueryInterface,
2548 OLEPictureImpl_IDispatch_AddRef,
2549 OLEPictureImpl_IDispatch_Release,
2550 OLEPictureImpl_GetTypeInfoCount,
2551 OLEPictureImpl_GetTypeInfo,
2552 OLEPictureImpl_GetIDsOfNames,
2553 OLEPictureImpl_Invoke
2556 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2558 OLEPictureImpl_IPersistStream_QueryInterface,
2559 OLEPictureImpl_IPersistStream_AddRef,
2560 OLEPictureImpl_IPersistStream_Release,
2561 OLEPictureImpl_GetClassID,
2562 OLEPictureImpl_IsDirty,
2563 OLEPictureImpl_Load,
2564 OLEPictureImpl_Save,
2565 OLEPictureImpl_GetSizeMax
2568 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2570 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2571 OLEPictureImpl_IConnectionPointContainer_AddRef,
2572 OLEPictureImpl_IConnectionPointContainer_Release,
2573 OLEPictureImpl_EnumConnectionPoints,
2574 OLEPictureImpl_FindConnectionPoint
2577 /***********************************************************************
2578 * OleCreatePictureIndirect (OLEAUT32.419)
2580 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2581 BOOL fOwn, LPVOID *ppvObj )
2583 OLEPictureImpl* newPict = NULL;
2586 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2597 * Try to construct a new instance of the class.
2599 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2601 if (newPict == NULL)
2602 return E_OUTOFMEMORY;
2605 * Make sure it supports the interface required by the caller.
2607 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2610 * Release the reference obtained in the constructor. If
2611 * the QueryInterface was unsuccessful, it will free the class.
2613 IPicture_Release((IPicture*)newPict);
2619 /***********************************************************************
2620 * OleLoadPicture (OLEAUT32.418)
2622 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2623 REFIID riid, LPVOID *ppvObj )
2629 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2630 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2632 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2635 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2637 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2638 IPicture_Release(newpic);
2642 hr = IPersistStream_Load(ps,lpstream);
2643 IPersistStream_Release(ps);
2646 ERR("IPersistStream_Load failed\n");
2647 IPicture_Release(newpic);
2651 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2653 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2654 IPicture_Release(newpic);
2658 /***********************************************************************
2659 * OleLoadPictureEx (OLEAUT32.401)
2661 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2662 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2668 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2669 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2671 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2674 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2676 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2677 IPicture_Release(newpic);
2681 hr = IPersistStream_Load(ps,lpstream);
2682 IPersistStream_Release(ps);
2685 ERR("IPersistStream_Load failed\n");
2686 IPicture_Release(newpic);
2690 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2692 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2693 IPicture_Release(newpic);
2697 /***********************************************************************
2698 * OleLoadPicturePath (OLEAUT32.424)
2700 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2701 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2704 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2708 HGLOBAL hGlobal = NULL;
2709 DWORD dwBytesRead = 0;
2712 IPersistStream *pStream;
2715 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2716 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2717 debugstr_guid(riid), ppvRet);
2719 if (!ppvRet) return E_POINTER;
2721 if (strncmpW(szURLorPath, file, 7) == 0) {
2724 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2726 if (hFile == INVALID_HANDLE_VALUE)
2727 return E_UNEXPECTED;
2729 dwFileSize = GetFileSize(hFile, NULL);
2730 if (dwFileSize != INVALID_FILE_SIZE )
2732 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2735 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2738 GlobalFree(hGlobal);
2746 return E_UNEXPECTED;
2748 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2751 GlobalFree(hGlobal);
2758 hRes = CreateBindCtx(0, &pbc);
2759 if (SUCCEEDED(hRes))
2761 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2762 if (SUCCEEDED(hRes))
2764 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2765 IMoniker_Release(pmnk);
2767 IBindCtx_Release(pbc);
2773 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2774 &IID_IPicture, (LPVOID*)&ipicture);
2776 IStream_Release(stream);
2780 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2782 IStream_Release(stream);
2783 IPicture_Release(ipicture);
2787 hRes = IPersistStream_Load(pStream, stream);
2788 IPersistStream_Release(pStream);
2789 IStream_Release(stream);
2792 IPicture_Release(ipicture);
2796 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2798 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2800 IPicture_Release(ipicture);
2804 /*******************************************************************************
2805 * StdPic ClassFactory
2809 /* IUnknown fields */
2810 const IClassFactoryVtbl *lpVtbl;
2812 } IClassFactoryImpl;
2814 static HRESULT WINAPI
2815 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2816 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2818 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2819 return E_NOINTERFACE;
2823 SPCF_AddRef(LPCLASSFACTORY iface) {
2824 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2825 return InterlockedIncrement(&This->ref);
2828 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2829 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2830 /* static class, won't be freed */
2831 return InterlockedDecrement(&This->ref);
2834 static HRESULT WINAPI SPCF_CreateInstance(
2835 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2837 /* Creates an uninitialized picture */
2838 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2842 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2843 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2844 FIXME("(%p)->(%d),stub!\n",This,dolock);
2848 static const IClassFactoryVtbl SPCF_Vtbl = {
2849 SPCF_QueryInterface,
2852 SPCF_CreateInstance,
2855 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2857 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }