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);
526 switch(This->desc.picType) {
528 case PICTYPE_UNINITIALIZED:
532 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
534 case PICTYPE_METAFILE:
535 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
538 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
540 case PICTYPE_ENHMETAFILE:
541 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
544 FIXME("Unimplemented type %d\n", This->desc.picType);
547 TRACE("returning handle %08x\n", *phandle);
551 /************************************************************************
552 * OLEPictureImpl_get_hPal
554 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
557 OLEPictureImpl *This = (OLEPictureImpl *)iface;
559 TRACE("(%p)->(%p)\n", This, phandle);
564 switch (This->desc.picType) {
565 case (UINT)PICTYPE_UNINITIALIZED:
571 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
574 case PICTYPE_METAFILE:
578 case PICTYPE_ENHMETAFILE:
580 FIXME("unimplemented for type %d. Returning 0 palette.\n",
586 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
590 /************************************************************************
591 * OLEPictureImpl_get_Type
593 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
596 OLEPictureImpl *This = (OLEPictureImpl *)iface;
597 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
598 *ptype = This->desc.picType;
602 /************************************************************************
603 * OLEPictureImpl_get_Width
605 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
606 OLE_XSIZE_HIMETRIC *pwidth)
608 OLEPictureImpl *This = (OLEPictureImpl *)iface;
609 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
610 *pwidth = This->himetricWidth;
614 /************************************************************************
615 * OLEPictureImpl_get_Height
617 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
618 OLE_YSIZE_HIMETRIC *pheight)
620 OLEPictureImpl *This = (OLEPictureImpl *)iface;
621 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
622 *pheight = This->himetricHeight;
626 /************************************************************************
627 * OLEPictureImpl_Render
629 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
630 LONG x, LONG y, LONG cx, LONG cy,
631 OLE_XPOS_HIMETRIC xSrc,
632 OLE_YPOS_HIMETRIC ySrc,
633 OLE_XSIZE_HIMETRIC cxSrc,
634 OLE_YSIZE_HIMETRIC cySrc,
637 OLEPictureImpl *This = (OLEPictureImpl *)iface;
638 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
639 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
641 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
642 prcWBounds->right, prcWBounds->bottom);
644 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
645 return CTL_E_INVALIDPROPERTYVALUE;
649 * While the documentation suggests this to be here (or after rendering?)
650 * it does cause an endless recursion in my sample app. -MM 20010804
651 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
654 switch(This->desc.picType) {
655 case PICTYPE_UNINITIALIZED:
664 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
665 NB y-axis gets flipped */
667 hdcBmp = CreateCompatibleDC(0);
668 SetMapMode(hdcBmp, MM_ANISOTROPIC);
669 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
670 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
671 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
672 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
675 HDC hdcMask = CreateCompatibleDC(0);
676 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
678 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
680 SetMapMode(hdcMask, MM_ANISOTROPIC);
681 SetWindowOrgEx(hdcMask, 0, 0, NULL);
682 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
683 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
684 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
686 SetBkColor(hdc, RGB(255, 255, 255));
687 SetTextColor(hdc, RGB(0, 0, 0));
688 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
689 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
691 SelectObject(hdcMask, hOldbm);
694 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
695 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
698 SelectObject(hdcBmp, hbmpOld);
703 FIXME("Not quite correct implementation of rendering icons...\n");
704 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
707 case PICTYPE_METAFILE:
713 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
714 SetViewportOrgEx(hdc, x, y, &prevOrg);
715 SetViewportExtEx(hdc, cx, cy, &prevExt);
717 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
718 ERR("PlayMetaFile failed!\n");
720 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
721 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
722 SetMapMode(hdc, oldmode);
726 case PICTYPE_ENHMETAFILE:
728 RECT rc = { x, y, x + cx, y + cy };
729 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
734 FIXME("type %d not implemented\n", This->desc.picType);
740 /************************************************************************
741 * OLEPictureImpl_set_hPal
743 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
746 OLEPictureImpl *This = (OLEPictureImpl *)iface;
747 FIXME("(%p)->(%08x): stub\n", This, hpal);
748 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
752 /************************************************************************
753 * OLEPictureImpl_get_CurDC
755 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
758 OLEPictureImpl *This = (OLEPictureImpl *)iface;
759 TRACE("(%p), returning %p\n", This, This->hDCCur);
760 if (phdc) *phdc = This->hDCCur;
764 /************************************************************************
765 * OLEPictureImpl_SelectPicture
767 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
770 OLE_HANDLE *phbmpOut)
772 OLEPictureImpl *This = (OLEPictureImpl *)iface;
773 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
774 if (This->desc.picType == PICTYPE_BITMAP) {
775 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
778 *phdcOut = This->hDCCur;
779 This->hDCCur = hdcIn;
781 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
784 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
789 /************************************************************************
790 * OLEPictureImpl_get_KeepOriginalFormat
792 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
795 OLEPictureImpl *This = (OLEPictureImpl *)iface;
796 TRACE("(%p)->(%p)\n", This, pfKeep);
799 *pfKeep = This->keepOrigFormat;
803 /************************************************************************
804 * OLEPictureImpl_put_KeepOriginalFormat
806 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
809 OLEPictureImpl *This = (OLEPictureImpl *)iface;
810 TRACE("(%p)->(%d)\n", This, keep);
811 This->keepOrigFormat = keep;
812 /* FIXME: what DISPID notification here? */
816 /************************************************************************
817 * OLEPictureImpl_PictureChanged
819 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
821 OLEPictureImpl *This = (OLEPictureImpl *)iface;
822 TRACE("(%p)->()\n", This);
823 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
824 This->bIsDirty = TRUE;
828 /************************************************************************
829 * OLEPictureImpl_SaveAsFile
831 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
836 OLEPictureImpl *This = (OLEPictureImpl *)iface;
837 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
838 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
841 /************************************************************************
842 * OLEPictureImpl_get_Attributes
844 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
847 OLEPictureImpl *This = (OLEPictureImpl *)iface;
848 TRACE("(%p)->(%p).\n", This, pdwAttr);
854 switch (This->desc.picType) {
855 case PICTYPE_UNINITIALIZED:
856 case PICTYPE_NONE: break;
857 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
858 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
859 case PICTYPE_ENHMETAFILE: /* fall through */
860 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
861 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
867 /************************************************************************
868 * IConnectionPointContainer
870 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
871 IConnectionPointContainer* iface,
875 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
877 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
880 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
881 IConnectionPointContainer* iface)
883 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
885 return IPicture_AddRef((IPicture *)This);
888 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
889 IConnectionPointContainer* iface)
891 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
893 return IPicture_Release((IPicture *)This);
896 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
897 IConnectionPointContainer* iface,
898 IEnumConnectionPoints** ppEnum)
900 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
902 FIXME("(%p,%p), stub!\n",This,ppEnum);
906 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
907 IConnectionPointContainer* iface,
909 IConnectionPoint **ppCP)
911 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
912 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
916 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
917 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
918 FIXME("no connection point for %s\n",debugstr_guid(riid));
919 return CONNECT_E_NOCONNECTION;
923 /************************************************************************
927 /************************************************************************
928 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
930 * See Windows documentation for more details on IUnknown methods.
932 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
933 IPersistStream* iface,
937 OLEPictureImpl *This = impl_from_IPersistStream(iface);
939 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
942 /************************************************************************
943 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
945 * See Windows documentation for more details on IUnknown methods.
947 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
948 IPersistStream* iface)
950 OLEPictureImpl *This = impl_from_IPersistStream(iface);
952 return IPicture_AddRef((IPicture *)This);
955 /************************************************************************
956 * OLEPictureImpl_IPersistStream_Release (IUnknown)
958 * See Windows documentation for more details on IUnknown methods.
960 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
961 IPersistStream* iface)
963 OLEPictureImpl *This = impl_from_IPersistStream(iface);
965 return IPicture_Release((IPicture *)This);
968 /************************************************************************
969 * OLEPictureImpl_IPersistStream_GetClassID
971 static HRESULT WINAPI OLEPictureImpl_GetClassID(
972 IPersistStream* iface,CLSID* pClassID)
974 TRACE("(%p)\n", pClassID);
975 *pClassID = CLSID_StdPicture;
979 /************************************************************************
980 * OLEPictureImpl_IPersistStream_IsDirty
982 static HRESULT WINAPI OLEPictureImpl_IsDirty(
983 IPersistStream* iface)
985 OLEPictureImpl *This = impl_from_IPersistStream(iface);
986 FIXME("(%p),stub!\n",This);
990 #ifdef SONAME_LIBJPEG
992 static void *libjpeg_handle;
993 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
994 MAKE_FUNCPTR(jpeg_std_error);
995 MAKE_FUNCPTR(jpeg_CreateDecompress);
996 MAKE_FUNCPTR(jpeg_read_header);
997 MAKE_FUNCPTR(jpeg_start_decompress);
998 MAKE_FUNCPTR(jpeg_read_scanlines);
999 MAKE_FUNCPTR(jpeg_finish_decompress);
1000 MAKE_FUNCPTR(jpeg_destroy_decompress);
1003 static void *load_libjpeg(void)
1005 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1007 #define LOAD_FUNCPTR(f) \
1008 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1009 libjpeg_handle = NULL; \
1013 LOAD_FUNCPTR(jpeg_std_error);
1014 LOAD_FUNCPTR(jpeg_CreateDecompress);
1015 LOAD_FUNCPTR(jpeg_read_header);
1016 LOAD_FUNCPTR(jpeg_start_decompress);
1017 LOAD_FUNCPTR(jpeg_read_scanlines);
1018 LOAD_FUNCPTR(jpeg_finish_decompress);
1019 LOAD_FUNCPTR(jpeg_destroy_decompress);
1022 return libjpeg_handle;
1025 /* for the jpeg decompressor source manager. */
1026 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1028 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1029 ERR("(), should not get here.\n");
1033 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1034 TRACE("Skipping %ld bytes...\n", num_bytes);
1035 cinfo->src->next_input_byte += num_bytes;
1036 cinfo->src->bytes_in_buffer -= num_bytes;
1039 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1040 ERR("(desired=%d), should not get here.\n",desired);
1043 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1044 #endif /* SONAME_LIBJPEG */
1047 unsigned char *data;
1048 unsigned int curoff;
1052 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1053 struct gifdata *gd = (struct gifdata*)gif->UserData;
1055 if (len+gd->curoff > gd->len) {
1056 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1057 len = gd->len - gd->curoff;
1059 memcpy(data, gd->data+gd->curoff, len);
1065 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1076 int transparent = -1;
1083 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1084 ret = DGifSlurp(gif);
1085 if (ret == GIF_ERROR) {
1086 ERR("Failed reading GIF using libgif.\n");
1089 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1090 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1091 TRACE("imgcnt %d\n", gif->ImageCount);
1092 if (gif->ImageCount<1) {
1093 ERR("GIF stream does not have images inside?\n");
1096 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1097 gif->Image.Width, gif->Image.Height,
1098 gif->Image.Left, gif->Image.Top,
1099 gif->Image.Interlace
1102 padding = (gif->SWidth+3) & ~3;
1103 si = gif->SavedImages+0;
1104 gid = &(si->ImageDesc);
1106 if (!cm) cm = gif->SColorMap;
1107 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1108 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1110 /* look for the transparent color extension */
1111 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1112 eb = si->ExtensionBlocks + i;
1113 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1114 if ((eb->Bytes[0] & 1) == 1) {
1115 transparent = (unsigned char)eb->Bytes[3];
1120 for (i = 0; i < cm->ColorCount; i++) {
1121 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1122 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1123 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1124 if (i == transparent) {
1125 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1126 bmi->bmiColors[i].rgbGreen,
1127 bmi->bmiColors[i].rgbBlue);
1131 /* Map to in picture coordinates */
1132 for (i = 0, j = 0; i < gid->Height; i++) {
1133 if (gif->Image.Interlace) {
1135 bytes + (gid->Top + j) * padding + gid->Left,
1136 si->RasterBits + i * gid->Width,
1139 /* Lower bits of interlaced counter encode current interlace */
1140 if (j & 1) j += 2; /* Currently filling odd rows */
1141 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1142 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1144 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1145 /* End of current interlace, go to next interlace */
1146 if (j & 2) j = 1; /* Next iteration fills odd rows */
1147 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1148 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1152 bytes + (gid->Top + i) * padding + gid->Left,
1153 si->RasterBits + i * gid->Width,
1158 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1159 bmi->bmiHeader.biWidth = gif->SWidth;
1160 bmi->bmiHeader.biHeight = -gif->SHeight;
1161 bmi->bmiHeader.biPlanes = 1;
1162 bmi->bmiHeader.biBitCount = 8;
1163 bmi->bmiHeader.biCompression = BI_RGB;
1164 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1165 bmi->bmiHeader.biXPelsPerMeter = 0;
1166 bmi->bmiHeader.biYPelsPerMeter = 0;
1167 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1168 bmi->bmiHeader.biClrImportant = 0;
1171 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1180 if (transparent > -1) {
1181 /* Create the Mask */
1182 HDC hdc = CreateCompatibleDC(0);
1183 HDC hdcMask = CreateCompatibleDC(0);
1185 HBITMAP hOldbitmapmask;
1187 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1190 This->hbmXor = CreateDIBitmap(
1199 bmi->bmiColors[0].rgbRed = 0;
1200 bmi->bmiColors[0].rgbGreen = 0;
1201 bmi->bmiColors[0].rgbBlue = 0;
1202 bmi->bmiColors[1].rgbRed = 255;
1203 bmi->bmiColors[1].rgbGreen = 255;
1204 bmi->bmiColors[1].rgbBlue = 255;
1206 bmi->bmiHeader.biBitCount = 1;
1207 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1208 bmi->bmiHeader.biClrUsed = 2;
1210 for (i = 0; i < gif->SHeight; i++) {
1211 unsigned char * colorPointer = bytes + padding * i;
1212 unsigned char * monoPointer = bytes + monopadding * i;
1213 for (j = 0; j < gif->SWidth; j++) {
1214 unsigned char pixel = colorPointer[j];
1215 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1216 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1220 hTempMask = CreateDIBitmap(
1230 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1231 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1232 hOldbitmap = SelectObject(hdc, hTempMask);
1233 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1235 SetBkColor(hdc, RGB(255, 255, 255));
1236 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1238 /* We no longer need the original bitmap, so we apply the first
1239 transformation with the mask to speed up the rendering */
1240 SelectObject(hdc, This->hbmXor);
1241 SetBkColor(hdc, RGB(0,0,0));
1242 SetTextColor(hdc, RGB(255,255,255));
1243 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1244 hdcMask, 0, 0, SRCAND);
1246 SelectObject(hdc, hOldbitmap);
1247 SelectObject(hdcMask, hOldbitmapmask);
1250 DeleteObject(hTempMask);
1254 This->desc.picType = PICTYPE_BITMAP;
1255 OLEPictureImpl_SetBitmap(This);
1257 HeapFree(GetProcessHeap(),0,bmi);
1258 HeapFree(GetProcessHeap(),0,bytes);
1262 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1264 #ifdef SONAME_LIBJPEG
1265 struct jpeg_decompress_struct jd;
1266 struct jpeg_error_mgr jerr;
1269 JSAMPROW samprow,oldsamprow;
1270 BITMAPINFOHEADER bmi;
1273 struct jpeg_source_mgr xjsm;
1277 if(!libjpeg_handle) {
1278 if(!load_libjpeg()) {
1279 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1284 /* This is basically so we can use in-memory data for jpeg decompression.
1285 * We need to have all the functions.
1287 xjsm.next_input_byte = xbuf;
1288 xjsm.bytes_in_buffer = xread;
1289 xjsm.init_source = _jpeg_init_source;
1290 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1291 xjsm.skip_input_data = _jpeg_skip_input_data;
1292 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1293 xjsm.term_source = _jpeg_term_source;
1295 jd.err = pjpeg_std_error(&jerr);
1296 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1297 * jpeg_create_decompress(&jd); */
1298 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1300 ret=pjpeg_read_header(&jd,TRUE);
1301 jd.out_color_space = JCS_RGB;
1302 pjpeg_start_decompress(&jd);
1303 if (ret != JPEG_HEADER_OK) {
1304 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1305 HeapFree(GetProcessHeap(),0,xbuf);
1309 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1310 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1311 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1314 oldsamprow = samprow;
1315 while ( jd.output_scanline<jd.output_height ) {
1316 x = pjpeg_read_scanlines(&jd,&samprow,1);
1318 ERR("failed to read current scanline?\n");
1321 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1322 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1323 *(bits++) = *(samprow+2);
1324 *(bits++) = *(samprow+1);
1325 *(bits++) = *(samprow);
1327 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1328 samprow = oldsamprow;
1332 bmi.biSize = sizeof(bmi);
1333 bmi.biWidth = jd.output_width;
1334 bmi.biHeight = -jd.output_height;
1336 bmi.biBitCount = jd.output_components<<3;
1337 bmi.biCompression = BI_RGB;
1338 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1339 bmi.biXPelsPerMeter = 0;
1340 bmi.biYPelsPerMeter = 0;
1342 bmi.biClrImportant = 0;
1344 HeapFree(GetProcessHeap(),0,samprow);
1345 pjpeg_finish_decompress(&jd);
1346 pjpeg_destroy_decompress(&jd);
1348 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1357 This->desc.picType = PICTYPE_BITMAP;
1358 OLEPictureImpl_SetBitmap(This);
1359 HeapFree(GetProcessHeap(),0,bits);
1362 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1367 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1369 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1370 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1373 /* Does not matter whether this is a coreheader or not, we only use
1374 * components which are in both
1377 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1381 xbuf+bfh->bfOffBits,
1386 if (This->desc.u.bmp.hbitmap == 0)
1388 This->desc.picType = PICTYPE_BITMAP;
1389 OLEPictureImpl_SetBitmap(This);
1393 /*****************************************************
1394 * start of PNG-specific code
1395 * currently only supports colortype PNG_COLOR_TYPE_RGB
1397 #ifdef SONAME_LIBPNG
1404 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1407 png_io * io_ptr = png_ptr->io_ptr;
1409 if(length + io_ptr->position > io_ptr->size){
1410 length = io_ptr->size - io_ptr->position;
1413 memcpy(data, io_ptr->buff + io_ptr->position, length);
1415 io_ptr->position += length;
1418 static void *libpng_handle;
1419 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1420 MAKE_FUNCPTR(png_create_read_struct);
1421 MAKE_FUNCPTR(png_create_info_struct);
1422 MAKE_FUNCPTR(png_set_read_fn);
1423 MAKE_FUNCPTR(png_read_info);
1424 MAKE_FUNCPTR(png_read_image);
1425 MAKE_FUNCPTR(png_get_rowbytes);
1426 MAKE_FUNCPTR(png_set_bgr);
1427 MAKE_FUNCPTR(png_destroy_read_struct);
1428 MAKE_FUNCPTR(png_set_palette_to_rgb);
1429 MAKE_FUNCPTR(png_read_update_info);
1430 MAKE_FUNCPTR(png_get_tRNS);
1431 MAKE_FUNCPTR(png_get_PLTE);
1432 MAKE_FUNCPTR(png_set_expand);
1435 static void *load_libpng(void)
1437 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1439 #define LOAD_FUNCPTR(f) \
1440 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1441 libpng_handle = NULL; \
1444 LOAD_FUNCPTR(png_create_read_struct);
1445 LOAD_FUNCPTR(png_create_info_struct);
1446 LOAD_FUNCPTR(png_set_read_fn);
1447 LOAD_FUNCPTR(png_read_info);
1448 LOAD_FUNCPTR(png_read_image);
1449 LOAD_FUNCPTR(png_get_rowbytes);
1450 LOAD_FUNCPTR(png_set_bgr);
1451 LOAD_FUNCPTR(png_destroy_read_struct);
1452 LOAD_FUNCPTR(png_set_palette_to_rgb);
1453 LOAD_FUNCPTR(png_read_update_info);
1454 LOAD_FUNCPTR(png_get_tRNS);
1455 LOAD_FUNCPTR(png_get_PLTE);
1456 LOAD_FUNCPTR(png_set_expand);
1460 return libpng_handle;
1462 #endif /* SONAME_LIBPNG */
1464 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1466 #ifdef SONAME_LIBPNG
1468 png_structp png_ptr = NULL;
1469 png_infop info_ptr = NULL;
1470 INT row, rowsize, height, width, num_trans, i, j;
1471 png_bytep* row_pointers = NULL;
1472 png_bytep pngdata = NULL;
1473 BITMAPINFOHEADER bmi;
1474 HDC hdcref = NULL, hdcXor, hdcMask;
1478 png_color_16p trans_values;
1479 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1480 HBITMAP hbmoldXor, hbmoldMask, temp;
1482 if(!libpng_handle) {
1483 if(!load_libpng()) {
1484 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1493 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1496 if(setjmp(png_jmpbuf(png_ptr))){
1497 TRACE("Error in libpng\n");
1502 info_ptr = ppng_create_info_struct(png_ptr);
1503 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1504 ppng_read_info(png_ptr, info_ptr);
1506 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1507 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1508 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1509 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1514 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1517 /* sets format from anything to RGBA */
1518 ppng_set_expand(png_ptr);
1519 /* sets format to BGRA */
1520 ppng_set_bgr(png_ptr);
1522 ppng_read_update_info(png_ptr, info_ptr);
1524 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1525 /* align rowsize to 4-byte boundary */
1526 rowsize = (rowsize + 3) & ~3;
1527 height = info_ptr->height;
1528 width = info_ptr->width;
1530 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1531 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1533 if(!pngdata || !row_pointers){
1538 for (row = 0; row < height; row++){
1539 row_pointers[row] = pngdata + row * rowsize;
1542 ppng_read_image(png_ptr, row_pointers);
1544 bmi.biSize = sizeof(bmi);
1545 bmi.biWidth = width;
1546 bmi.biHeight = -height;
1548 bmi.biBitCount = info_ptr->channels * 8;
1549 bmi.biCompression = BI_RGB;
1550 bmi.biSizeImage = height * rowsize;
1551 bmi.biXPelsPerMeter = 0;
1552 bmi.biYPelsPerMeter = 0;
1554 bmi.biClrImportant = 0;
1557 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1566 /* only fully-transparent alpha is handled */
1567 if((info_ptr->channels != 4) || !transparency){
1568 ReleaseDC(0, hdcref);
1572 This->hbmXor = CreateDIBitmap(
1581 /* set transparent pixels to black, all others to white */
1582 for(i = 0; i < height; i++){
1583 for(j = 3; j < rowsize; j += 4){
1584 if(row_pointers[i][j] == 0)
1585 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1587 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1591 temp = CreateDIBitmap(
1600 ReleaseDC(0, hdcref);
1602 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1603 hdcXor = CreateCompatibleDC(NULL);
1604 hdcMask = CreateCompatibleDC(NULL);
1606 hbmoldXor = SelectObject(hdcXor,temp);
1607 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1608 SetBkColor(hdcXor,black);
1609 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1611 SelectObject(hdcXor,This->hbmXor);
1614 SetTextColor(hdcXor,white);
1615 SetBkColor(hdcXor,black);
1616 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1618 SelectObject(hdcXor,hbmoldXor);
1619 SelectObject(hdcMask,hbmoldMask);
1625 This->desc.picType = PICTYPE_BITMAP;
1626 OLEPictureImpl_SetBitmap(This);
1631 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1632 HeapFree(GetProcessHeap(), 0, row_pointers);
1633 HeapFree(GetProcessHeap(), 0, pngdata);
1635 #else /* SONAME_LIBPNG */
1636 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1641 /*****************************************************
1642 * start of Icon-specific code
1645 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1648 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1653 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1654 FIXME("icon.idType=%d\n",cifd->idType);
1655 FIXME("icon.idCount=%d\n",cifd->idCount);
1657 for (i=0;i<cifd->idCount;i++) {
1658 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1659 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1660 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1661 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1662 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1663 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1664 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1665 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1669 /* If we have more than one icon, try to find the best.
1670 * this currently means '32 pixel wide'.
1672 if (cifd->idCount!=1) {
1673 for (i=0;i<cifd->idCount;i++) {
1674 if (cifd->idEntries[i].bWidth == 32)
1677 if (i==cifd->idCount) i=0;
1680 hicon = CreateIconFromResourceEx(
1681 xbuf+cifd->idEntries[i].dwDIBOffset,
1682 cifd->idEntries[i].dwDIBSize,
1685 cifd->idEntries[i].bWidth,
1686 cifd->idEntries[i].bHeight,
1690 ERR("CreateIcon failed.\n");
1693 This->desc.picType = PICTYPE_ICON;
1694 This->desc.u.icon.hicon = hicon;
1695 This->origWidth = cifd->idEntries[i].bWidth;
1696 This->origHeight = cifd->idEntries[i].bHeight;
1697 hdcRef = CreateCompatibleDC(0);
1698 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1699 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1705 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1706 const BYTE *data, ULONG size)
1711 hemf = SetEnhMetaFileBits(size, data);
1712 if (!hemf) return E_FAIL;
1714 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1716 This->desc.picType = PICTYPE_ENHMETAFILE;
1717 This->desc.u.emf.hemf = hemf;
1719 This->origWidth = 0;
1720 This->origHeight = 0;
1721 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1722 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1727 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1728 const BYTE *data, ULONG size)
1730 APM_HEADER *header = (APM_HEADER *)data;
1733 if (size < sizeof(APM_HEADER))
1735 if (header->key != 0x9ac6cdd7)
1738 /* SetMetaFileBitsEx performs data check on its own */
1739 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1740 if (!hmf) return E_FAIL;
1742 This->desc.picType = PICTYPE_METAFILE;
1743 This->desc.u.wmf.hmeta = hmf;
1744 This->desc.u.wmf.xExt = 0;
1745 This->desc.u.wmf.yExt = 0;
1747 This->origWidth = 0;
1748 This->origHeight = 0;
1749 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1750 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1754 /************************************************************************
1755 * BITMAP FORMAT FLAGS -
1756 * Flags that differentiate between different types of bitmaps.
1759 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1760 #define BITMAP_FORMAT_JPEG 0xd8ff
1761 #define BITMAP_FORMAT_GIF 0x4947
1762 #define BITMAP_FORMAT_PNG 0x5089
1763 #define BITMAP_FORMAT_APM 0xcdd7
1765 /************************************************************************
1766 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1768 * Loads the binary data from the IStream. Starts at current position.
1769 * There appears to be an 2 DWORD header:
1773 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1775 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1776 HRESULT hr = E_FAIL;
1777 BOOL headerisdata = FALSE;
1778 BOOL statfailed = FALSE;
1779 ULONG xread, toread;
1785 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1787 TRACE("(%p,%p)\n",This,pStm);
1789 /****************************************************************************************
1790 * Part 1: Load the data
1792 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1793 * out whether we do.
1795 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1796 * compound file. This may explain most, if not all, of the cases of "no
1797 * header", and the header validation should take this into account.
1798 * At least in Visual Basic 6, resource streams, valid headers are
1799 * header[0] == "lt\0\0",
1800 * header[1] == length_of_stream.
1802 * Also handle streams where we do not have a working "Stat" method by
1803 * reading all data until the end of the stream.
1805 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1807 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1809 /* we will read at least 8 byte ... just right below */
1810 statstg.cbSize.QuadPart = 8;
1815 headerisdata = FALSE;
1817 hr=IStream_Read(pStm,header,8,&xread);
1818 if (hr || xread!=8) {
1819 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1820 return (hr?hr:E_FAIL);
1822 headerread += xread;
1825 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1826 if (toread != 0 && toread != header[1])
1827 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1830 if (toread == 0) break;
1832 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1833 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1834 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1835 (header[0] == EMR_HEADER) || /* EMF header */
1836 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1838 ) {/* Found start of bitmap data */
1839 headerisdata = TRUE;
1841 toread = statstg.cbSize.QuadPart-8;
1845 FIXME("Unknown stream header magic: %08x\n", header[0]);
1849 } while (!headerisdata);
1851 if (statfailed) { /* we don't know the size ... read all we get */
1853 int origsize = sizeinc;
1856 TRACE("Reading all data from stream.\n");
1857 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1859 memcpy (xbuf, header, 8);
1861 while (xread < origsize) {
1862 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1867 if (!nread || hr) /* done, or error */
1869 if (xread == origsize) {
1870 origsize += sizeinc;
1871 sizeinc = 2*sizeinc; /* exponential increase */
1872 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1876 TRACE("hr in no-stat loader case is %08x\n", hr);
1877 TRACE("loaded %d bytes.\n", xread);
1878 This->datalen = xread;
1881 This->datalen = toread+(headerisdata?8:0);
1882 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1884 return E_OUTOFMEMORY;
1887 memcpy (xbuf, header, 8);
1889 while (xread < This->datalen) {
1891 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1896 if (xread != This->datalen)
1897 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1899 if (This->datalen == 0) { /* Marks the "NONE" picture */
1900 This->desc.picType = PICTYPE_NONE;
1905 /****************************************************************************************
1906 * Part 2: Process the loaded data
1909 magic = xbuf[0] + (xbuf[1]<<8);
1910 This->loadtime_format = magic;
1913 case BITMAP_FORMAT_GIF: /* GIF */
1914 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1916 case BITMAP_FORMAT_JPEG: /* JPEG */
1917 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1919 case BITMAP_FORMAT_BMP: /* Bitmap */
1920 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1922 case BITMAP_FORMAT_PNG: /* PNG */
1923 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1925 case BITMAP_FORMAT_APM: /* APM */
1926 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1928 case 0x0000: { /* ICON , first word is dwReserved */
1929 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1936 /* let's see if it's a EMF */
1937 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1938 if (hr == S_OK) break;
1940 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1942 for (i=0;i<xread+8;i++) {
1943 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1944 else MESSAGE("%02x ",xbuf[i-8]);
1945 if (i % 10 == 9) MESSAGE("\n");
1951 This->bIsDirty = FALSE;
1953 /* FIXME: this notify is not really documented */
1955 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1959 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1963 BITMAPINFO * pInfoBitmap;
1964 int iNumPaletteEntries;
1965 unsigned char * pPixelData;
1966 BITMAPFILEHEADER * pFileHeader;
1967 BITMAPINFO * pInfoHeader;
1969 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1970 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1972 /* Find out bitmap size and padded length */
1974 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1975 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1977 /* Fetch bitmap palette & pixel data */
1979 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1980 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1982 /* Calculate the total length required for the BMP data */
1983 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1984 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1985 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1987 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1988 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1990 iNumPaletteEntries = 0;
1993 sizeof(BITMAPFILEHEADER) +
1994 sizeof(BITMAPINFOHEADER) +
1995 iNumPaletteEntries * sizeof(RGBQUAD) +
1996 pInfoBitmap->bmiHeader.biSizeImage;
1997 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1999 /* Fill the BITMAPFILEHEADER */
2000 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
2001 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2002 pFileHeader->bfSize = *pLength;
2003 pFileHeader->bfOffBits =
2004 sizeof(BITMAPFILEHEADER) +
2005 sizeof(BITMAPINFOHEADER) +
2006 iNumPaletteEntries * sizeof(RGBQUAD);
2008 /* Fill the BITMAPINFOHEADER and the palette data */
2009 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2010 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2012 (unsigned char *)(*ppBuffer) +
2013 sizeof(BITMAPFILEHEADER) +
2014 sizeof(BITMAPINFOHEADER) +
2015 iNumPaletteEntries * sizeof(RGBQUAD),
2016 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2019 HeapFree(GetProcessHeap(), 0, pPixelData);
2020 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2024 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2029 *ppBuffer = NULL; *pLength = 0;
2030 if (GetIconInfo(hIcon, &infoIcon)) {
2032 BITMAPINFO * pInfoBitmap;
2033 unsigned char * pIconData = NULL;
2034 unsigned int iDataSize = 0;
2036 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2038 /* Find out icon size */
2040 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2041 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2043 /* Auxiliary pointers */
2044 CURSORICONFILEDIR * pIconDir;
2045 CURSORICONFILEDIRENTRY * pIconEntry;
2046 BITMAPINFOHEADER * pIconBitmapHeader;
2047 unsigned int iOffsetPalette;
2048 unsigned int iOffsetColorData;
2049 unsigned int iOffsetMaskData;
2051 unsigned int iLengthScanLineColor;
2052 unsigned int iLengthScanLineMask;
2053 unsigned int iNumEntriesPalette;
2055 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2056 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2058 FIXME("DEBUG: bitmap size is %d x %d\n",
2059 pInfoBitmap->bmiHeader.biWidth,
2060 pInfoBitmap->bmiHeader.biHeight);
2061 FIXME("DEBUG: bitmap bpp is %d\n",
2062 pInfoBitmap->bmiHeader.biBitCount);
2063 FIXME("DEBUG: bitmap nplanes is %d\n",
2064 pInfoBitmap->bmiHeader.biPlanes);
2065 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2066 pInfoBitmap->bmiHeader.biSizeImage);
2068 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2069 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2070 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2072 /* Fill out the CURSORICONFILEDIR */
2073 pIconDir = (CURSORICONFILEDIR *)pIconData;
2074 pIconDir->idType = 1;
2075 pIconDir->idCount = 1;
2077 /* Fill out the CURSORICONFILEDIRENTRY */
2078 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2079 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2080 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2081 pIconEntry->bColorCount =
2082 (pInfoBitmap->bmiHeader.biBitCount < 8)
2083 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2085 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2086 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2087 pIconEntry->dwDIBSize = 0;
2088 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2090 /* Fill out the BITMAPINFOHEADER */
2091 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2092 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2094 /* Find out whether a palette exists for the bitmap */
2095 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2096 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2097 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2098 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2099 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2100 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2101 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2102 iNumEntriesPalette = 3;
2103 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2104 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2106 iNumEntriesPalette = 0;
2109 /* Add bitmap size and header size to icon data size. */
2110 iOffsetPalette = iDataSize;
2111 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2112 iOffsetColorData = iDataSize;
2113 iDataSize += pIconBitmapHeader->biSizeImage;
2114 iOffsetMaskData = iDataSize;
2115 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2116 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2117 pIconBitmapHeader->biHeight *= 2;
2118 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2119 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2120 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2121 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2123 /* Get the actual bitmap data from the icon bitmap */
2124 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2125 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2126 if (iNumEntriesPalette > 0) {
2127 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2128 iNumEntriesPalette * sizeof(RGBQUAD));
2131 /* Reset all values so that GetDIBits call succeeds */
2132 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2133 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2134 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2136 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2137 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2138 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2140 printf("ERROR: unable to get bitmap mask (error %u)\n",
2145 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2146 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2148 /* Write out everything produced so far to the stream */
2149 *ppBuffer = pIconData; *pLength = iDataSize;
2153 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2158 Remarks (from MSDN entry on GetIconInfo):
2160 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2161 members of ICONINFO. The calling application must manage
2162 these bitmaps and delete them when they are no longer
2165 if (hDC) ReleaseDC(0, hDC);
2166 DeleteObject(infoIcon.hbmMask);
2167 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2168 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2170 printf("ERROR: Unable to get icon information (error %u)\n",
2176 static HRESULT WINAPI OLEPictureImpl_Save(
2177 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2179 HRESULT hResult = E_NOTIMPL;
2181 unsigned int iDataSize;
2183 int iSerializeResult = 0;
2184 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2186 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2188 switch (This->desc.picType) {
2190 if (This->bIsDirty || !This->data) {
2191 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2192 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2196 HeapFree(GetProcessHeap(), 0, This->data);
2197 This->data = pIconData;
2198 This->datalen = iDataSize;
2200 if (This->loadtime_magic != 0xdeadbeef) {
2203 header[0] = This->loadtime_magic;
2204 header[1] = This->datalen;
2205 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2207 IStream_Write(pStm, This->data, This->datalen, &dummy);
2211 case PICTYPE_BITMAP:
2212 if (This->bIsDirty) {
2213 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2214 case BITMAP_FORMAT_BMP:
2215 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2217 case BITMAP_FORMAT_JPEG:
2218 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2220 case BITMAP_FORMAT_GIF:
2221 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2223 case BITMAP_FORMAT_PNG:
2224 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2227 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2230 if (iSerializeResult) {
2232 if (This->loadtime_magic != 0xdeadbeef) {
2237 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2238 header[1] = iDataSize;
2239 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2241 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2243 HeapFree(GetProcessHeap(), 0, This->data);
2244 This->data = pIconData;
2245 This->datalen = iDataSize;
2250 if (This->loadtime_magic != 0xdeadbeef) {
2255 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2256 header[1] = This->datalen;
2257 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2259 IStream_Write(pStm, This->data, This->datalen, &dummy);
2263 case PICTYPE_METAFILE:
2264 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2266 case PICTYPE_ENHMETAFILE:
2267 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2270 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2273 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2277 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2278 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2280 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2281 FIXME("(%p,%p),stub!\n",This,pcbSize);
2286 /************************************************************************
2290 /************************************************************************
2291 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2293 * See Windows documentation for more details on IUnknown methods.
2295 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2300 OLEPictureImpl *This = impl_from_IDispatch(iface);
2302 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2305 /************************************************************************
2306 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2308 * See Windows documentation for more details on IUnknown methods.
2310 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2313 OLEPictureImpl *This = impl_from_IDispatch(iface);
2315 return IPicture_AddRef((IPicture *)This);
2318 /************************************************************************
2319 * OLEPictureImpl_IDispatch_Release (IUnknown)
2321 * See Windows documentation for more details on IUnknown methods.
2323 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2326 OLEPictureImpl *This = impl_from_IDispatch(iface);
2328 return IPicture_Release((IPicture *)This);
2331 /************************************************************************
2332 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2334 * See Windows documentation for more details on IDispatch methods.
2336 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2338 unsigned int* pctinfo)
2340 TRACE("(%p)\n", pctinfo);
2347 /************************************************************************
2348 * OLEPictureImpl_GetTypeInfo (IDispatch)
2350 * See Windows documentation for more details on IDispatch methods.
2352 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2356 ITypeInfo** ppTInfo)
2358 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2362 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2367 hres = LoadTypeLib(stdole2tlb, &tl);
2370 ERR("Could not load stdole2.tlb\n");
2374 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2376 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2381 /************************************************************************
2382 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2384 * See Windows documentation for more details on IDispatch methods.
2386 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2389 LPOLESTR* rgszNames,
2397 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2398 rgszNames, cNames, (int)lcid, rgDispId);
2402 return E_INVALIDARG;
2406 /* retrieve type information */
2407 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2411 ERR("GetTypeInfo failed.\n");
2415 /* convert names to DISPIDs */
2416 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2417 ITypeInfo_Release(pTInfo);
2423 /************************************************************************
2424 * OLEPictureImpl_Invoke (IDispatch)
2426 * See Windows documentation for more details on IDispatch methods.
2428 static HRESULT WINAPI OLEPictureImpl_Invoke(
2430 DISPID dispIdMember,
2434 DISPPARAMS* pDispParams,
2435 VARIANT* pVarResult,
2436 EXCEPINFO* pExepInfo,
2439 OLEPictureImpl *This = impl_from_IDispatch(iface);
2441 /* validate parameters */
2443 if (!IsEqualIID(riid, &IID_NULL))
2445 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2446 return DISP_E_UNKNOWNNAME;
2451 ERR("null pDispParams not allowed\n");
2452 return DISP_E_PARAMNOTOPTIONAL;
2455 if (wFlags & DISPATCH_PROPERTYGET)
2457 if (pDispParams->cArgs != 0)
2459 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2460 return DISP_E_BADPARAMCOUNT;
2464 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2465 return DISP_E_PARAMNOTOPTIONAL;
2468 else if (wFlags & DISPATCH_PROPERTYPUT)
2470 if (pDispParams->cArgs != 1)
2472 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2473 return DISP_E_BADPARAMCOUNT;
2477 switch (dispIdMember)
2479 case DISPID_PICT_HANDLE:
2480 if (wFlags & DISPATCH_PROPERTYGET)
2482 TRACE("DISPID_PICT_HANDLE\n");
2483 V_VT(pVarResult) = VT_I4;
2484 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2487 case DISPID_PICT_HPAL:
2488 if (wFlags & DISPATCH_PROPERTYGET)
2490 TRACE("DISPID_PICT_HPAL\n");
2491 V_VT(pVarResult) = VT_I4;
2492 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2494 else if (wFlags & DISPATCH_PROPERTYPUT)
2498 TRACE("DISPID_PICT_HPAL\n");
2500 VariantInit(&vararg);
2501 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2505 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2507 VariantClear(&vararg);
2511 case DISPID_PICT_TYPE:
2512 if (wFlags & DISPATCH_PROPERTYGET)
2514 TRACE("DISPID_PICT_TYPE\n");
2515 V_VT(pVarResult) = VT_I2;
2516 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2519 case DISPID_PICT_WIDTH:
2520 if (wFlags & DISPATCH_PROPERTYGET)
2522 TRACE("DISPID_PICT_WIDTH\n");
2523 V_VT(pVarResult) = VT_I4;
2524 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2527 case DISPID_PICT_HEIGHT:
2528 if (wFlags & DISPATCH_PROPERTYGET)
2530 TRACE("DISPID_PICT_HEIGHT\n");
2531 V_VT(pVarResult) = VT_I4;
2532 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2537 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2538 return DISP_E_MEMBERNOTFOUND;
2542 static const IPictureVtbl OLEPictureImpl_VTable =
2544 OLEPictureImpl_QueryInterface,
2545 OLEPictureImpl_AddRef,
2546 OLEPictureImpl_Release,
2547 OLEPictureImpl_get_Handle,
2548 OLEPictureImpl_get_hPal,
2549 OLEPictureImpl_get_Type,
2550 OLEPictureImpl_get_Width,
2551 OLEPictureImpl_get_Height,
2552 OLEPictureImpl_Render,
2553 OLEPictureImpl_set_hPal,
2554 OLEPictureImpl_get_CurDC,
2555 OLEPictureImpl_SelectPicture,
2556 OLEPictureImpl_get_KeepOriginalFormat,
2557 OLEPictureImpl_put_KeepOriginalFormat,
2558 OLEPictureImpl_PictureChanged,
2559 OLEPictureImpl_SaveAsFile,
2560 OLEPictureImpl_get_Attributes
2563 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2565 OLEPictureImpl_IDispatch_QueryInterface,
2566 OLEPictureImpl_IDispatch_AddRef,
2567 OLEPictureImpl_IDispatch_Release,
2568 OLEPictureImpl_GetTypeInfoCount,
2569 OLEPictureImpl_GetTypeInfo,
2570 OLEPictureImpl_GetIDsOfNames,
2571 OLEPictureImpl_Invoke
2574 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2576 OLEPictureImpl_IPersistStream_QueryInterface,
2577 OLEPictureImpl_IPersistStream_AddRef,
2578 OLEPictureImpl_IPersistStream_Release,
2579 OLEPictureImpl_GetClassID,
2580 OLEPictureImpl_IsDirty,
2581 OLEPictureImpl_Load,
2582 OLEPictureImpl_Save,
2583 OLEPictureImpl_GetSizeMax
2586 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2588 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2589 OLEPictureImpl_IConnectionPointContainer_AddRef,
2590 OLEPictureImpl_IConnectionPointContainer_Release,
2591 OLEPictureImpl_EnumConnectionPoints,
2592 OLEPictureImpl_FindConnectionPoint
2595 /***********************************************************************
2596 * OleCreatePictureIndirect (OLEAUT32.419)
2598 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2599 BOOL fOwn, LPVOID *ppvObj )
2601 OLEPictureImpl* newPict = NULL;
2604 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2615 * Try to construct a new instance of the class.
2617 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2619 if (newPict == NULL)
2620 return E_OUTOFMEMORY;
2623 * Make sure it supports the interface required by the caller.
2625 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2628 * Release the reference obtained in the constructor. If
2629 * the QueryInterface was unsuccessful, it will free the class.
2631 IPicture_Release((IPicture*)newPict);
2637 /***********************************************************************
2638 * OleLoadPicture (OLEAUT32.418)
2640 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2641 REFIID riid, LPVOID *ppvObj )
2647 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2648 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2650 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2653 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2655 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2656 IPicture_Release(newpic);
2660 hr = IPersistStream_Load(ps,lpstream);
2661 IPersistStream_Release(ps);
2664 ERR("IPersistStream_Load failed\n");
2665 IPicture_Release(newpic);
2669 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2671 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2672 IPicture_Release(newpic);
2676 /***********************************************************************
2677 * OleLoadPictureEx (OLEAUT32.401)
2679 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2680 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2686 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2687 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2689 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2692 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2694 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2695 IPicture_Release(newpic);
2699 hr = IPersistStream_Load(ps,lpstream);
2700 IPersistStream_Release(ps);
2703 ERR("IPersistStream_Load failed\n");
2704 IPicture_Release(newpic);
2708 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2710 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2711 IPicture_Release(newpic);
2715 /***********************************************************************
2716 * OleLoadPicturePath (OLEAUT32.424)
2718 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2719 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2722 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2726 HGLOBAL hGlobal = NULL;
2727 DWORD dwBytesRead = 0;
2730 IPersistStream *pStream;
2733 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2734 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2735 debugstr_guid(riid), ppvRet);
2737 if (!ppvRet) return E_POINTER;
2739 if (strncmpW(szURLorPath, file, 7) == 0) {
2742 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2744 if (hFile == INVALID_HANDLE_VALUE)
2745 return E_UNEXPECTED;
2747 dwFileSize = GetFileSize(hFile, NULL);
2748 if (dwFileSize != INVALID_FILE_SIZE )
2750 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2753 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2756 GlobalFree(hGlobal);
2764 return E_UNEXPECTED;
2766 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2769 GlobalFree(hGlobal);
2776 hRes = CreateBindCtx(0, &pbc);
2777 if (SUCCEEDED(hRes))
2779 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2780 if (SUCCEEDED(hRes))
2782 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2783 IMoniker_Release(pmnk);
2785 IBindCtx_Release(pbc);
2791 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2792 &IID_IPicture, (LPVOID*)&ipicture);
2794 IStream_Release(stream);
2798 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2800 IStream_Release(stream);
2801 IPicture_Release(ipicture);
2805 hRes = IPersistStream_Load(pStream, stream);
2806 IPersistStream_Release(pStream);
2807 IStream_Release(stream);
2810 IPicture_Release(ipicture);
2814 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2816 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2818 IPicture_Release(ipicture);
2822 /*******************************************************************************
2823 * StdPic ClassFactory
2827 /* IUnknown fields */
2828 const IClassFactoryVtbl *lpVtbl;
2830 } IClassFactoryImpl;
2832 static HRESULT WINAPI
2833 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2834 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2836 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2837 return E_NOINTERFACE;
2841 SPCF_AddRef(LPCLASSFACTORY iface) {
2842 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2843 return InterlockedIncrement(&This->ref);
2846 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2847 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2848 /* static class, won't be freed */
2849 return InterlockedDecrement(&This->ref);
2852 static HRESULT WINAPI SPCF_CreateInstance(
2853 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2855 /* Creates an uninitialized picture */
2856 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2860 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2861 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2862 FIXME("(%p)->(%d),stub!\n",This,dolock);
2866 static const IClassFactoryVtbl SPCF_Vtbl = {
2867 SPCF_QueryInterface,
2870 SPCF_CreateInstance,
2873 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2875 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }