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 = HandleToUlong(This->desc.u.bmp.hbitmap);
534 case PICTYPE_METAFILE:
535 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
538 *phandle = HandleToUlong(This->desc.u.icon.hicon);
540 case PICTYPE_ENHMETAFILE:
541 *phandle = HandleToUlong(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 = HandleToUlong(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);
602 *ptype = This->desc.picType;
606 /************************************************************************
607 * OLEPictureImpl_get_Width
609 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
610 OLE_XSIZE_HIMETRIC *pwidth)
612 OLEPictureImpl *This = (OLEPictureImpl *)iface;
613 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
614 *pwidth = This->himetricWidth;
618 /************************************************************************
619 * OLEPictureImpl_get_Height
621 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
622 OLE_YSIZE_HIMETRIC *pheight)
624 OLEPictureImpl *This = (OLEPictureImpl *)iface;
625 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
626 *pheight = This->himetricHeight;
630 /************************************************************************
631 * OLEPictureImpl_Render
633 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
634 LONG x, LONG y, LONG cx, LONG cy,
635 OLE_XPOS_HIMETRIC xSrc,
636 OLE_YPOS_HIMETRIC ySrc,
637 OLE_XSIZE_HIMETRIC cxSrc,
638 OLE_YSIZE_HIMETRIC cySrc,
641 OLEPictureImpl *This = (OLEPictureImpl *)iface;
642 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
643 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
645 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
646 prcWBounds->right, prcWBounds->bottom);
648 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
649 return CTL_E_INVALIDPROPERTYVALUE;
653 * While the documentation suggests this to be here (or after rendering?)
654 * it does cause an endless recursion in my sample app. -MM 20010804
655 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
658 switch(This->desc.picType) {
659 case PICTYPE_UNINITIALIZED:
668 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
669 NB y-axis gets flipped */
671 hdcBmp = CreateCompatibleDC(0);
672 SetMapMode(hdcBmp, MM_ANISOTROPIC);
673 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
674 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
675 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
676 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
679 HDC hdcMask = CreateCompatibleDC(0);
680 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
682 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
684 SetMapMode(hdcMask, MM_ANISOTROPIC);
685 SetWindowOrgEx(hdcMask, 0, 0, NULL);
686 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
687 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
688 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
690 SetBkColor(hdc, RGB(255, 255, 255));
691 SetTextColor(hdc, RGB(0, 0, 0));
692 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
693 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
695 SelectObject(hdcMask, hOldbm);
698 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
699 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
702 SelectObject(hdcBmp, hbmpOld);
707 FIXME("Not quite correct implementation of rendering icons...\n");
708 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
711 case PICTYPE_METAFILE:
717 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
718 SetViewportOrgEx(hdc, x, y, &prevOrg);
719 SetViewportExtEx(hdc, cx, cy, &prevExt);
721 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
722 ERR("PlayMetaFile failed!\n");
724 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
725 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
726 SetMapMode(hdc, oldmode);
730 case PICTYPE_ENHMETAFILE:
732 RECT rc = { x, y, x + cx, y + cy };
733 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
738 FIXME("type %d not implemented\n", This->desc.picType);
744 /************************************************************************
745 * OLEPictureImpl_set_hPal
747 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
750 OLEPictureImpl *This = (OLEPictureImpl *)iface;
751 FIXME("(%p)->(%08x): stub\n", This, hpal);
752 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
756 /************************************************************************
757 * OLEPictureImpl_get_CurDC
759 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
762 OLEPictureImpl *This = (OLEPictureImpl *)iface;
763 TRACE("(%p), returning %p\n", This, This->hDCCur);
764 if (phdc) *phdc = This->hDCCur;
768 /************************************************************************
769 * OLEPictureImpl_SelectPicture
771 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
774 OLE_HANDLE *phbmpOut)
776 OLEPictureImpl *This = (OLEPictureImpl *)iface;
777 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
778 if (This->desc.picType == PICTYPE_BITMAP) {
779 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
782 *phdcOut = This->hDCCur;
783 This->hDCCur = hdcIn;
785 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
788 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
793 /************************************************************************
794 * OLEPictureImpl_get_KeepOriginalFormat
796 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
799 OLEPictureImpl *This = (OLEPictureImpl *)iface;
800 TRACE("(%p)->(%p)\n", This, pfKeep);
803 *pfKeep = This->keepOrigFormat;
807 /************************************************************************
808 * OLEPictureImpl_put_KeepOriginalFormat
810 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
813 OLEPictureImpl *This = (OLEPictureImpl *)iface;
814 TRACE("(%p)->(%d)\n", This, keep);
815 This->keepOrigFormat = keep;
816 /* FIXME: what DISPID notification here? */
820 /************************************************************************
821 * OLEPictureImpl_PictureChanged
823 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
825 OLEPictureImpl *This = (OLEPictureImpl *)iface;
826 TRACE("(%p)->()\n", This);
827 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
828 This->bIsDirty = TRUE;
832 /************************************************************************
833 * OLEPictureImpl_SaveAsFile
835 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
840 OLEPictureImpl *This = (OLEPictureImpl *)iface;
841 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
842 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
845 /************************************************************************
846 * OLEPictureImpl_get_Attributes
848 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
851 OLEPictureImpl *This = (OLEPictureImpl *)iface;
852 TRACE("(%p)->(%p).\n", This, pdwAttr);
858 switch (This->desc.picType) {
859 case PICTYPE_UNINITIALIZED:
860 case PICTYPE_NONE: break;
861 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
862 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
863 case PICTYPE_ENHMETAFILE: /* fall through */
864 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
865 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
871 /************************************************************************
872 * IConnectionPointContainer
874 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
875 IConnectionPointContainer* iface,
879 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
881 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
884 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
885 IConnectionPointContainer* iface)
887 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
889 return IPicture_AddRef((IPicture *)This);
892 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
893 IConnectionPointContainer* iface)
895 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
897 return IPicture_Release((IPicture *)This);
900 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
901 IConnectionPointContainer* iface,
902 IEnumConnectionPoints** ppEnum)
904 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
906 FIXME("(%p,%p), stub!\n",This,ppEnum);
910 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
911 IConnectionPointContainer* iface,
913 IConnectionPoint **ppCP)
915 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
916 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
920 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
921 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
922 FIXME("no connection point for %s\n",debugstr_guid(riid));
923 return CONNECT_E_NOCONNECTION;
927 /************************************************************************
931 /************************************************************************
932 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
934 * See Windows documentation for more details on IUnknown methods.
936 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
937 IPersistStream* iface,
941 OLEPictureImpl *This = impl_from_IPersistStream(iface);
943 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
946 /************************************************************************
947 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
949 * See Windows documentation for more details on IUnknown methods.
951 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
952 IPersistStream* iface)
954 OLEPictureImpl *This = impl_from_IPersistStream(iface);
956 return IPicture_AddRef((IPicture *)This);
959 /************************************************************************
960 * OLEPictureImpl_IPersistStream_Release (IUnknown)
962 * See Windows documentation for more details on IUnknown methods.
964 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
965 IPersistStream* iface)
967 OLEPictureImpl *This = impl_from_IPersistStream(iface);
969 return IPicture_Release((IPicture *)This);
972 /************************************************************************
973 * OLEPictureImpl_IPersistStream_GetClassID
975 static HRESULT WINAPI OLEPictureImpl_GetClassID(
976 IPersistStream* iface,CLSID* pClassID)
978 TRACE("(%p)\n", pClassID);
979 *pClassID = CLSID_StdPicture;
983 /************************************************************************
984 * OLEPictureImpl_IPersistStream_IsDirty
986 static HRESULT WINAPI OLEPictureImpl_IsDirty(
987 IPersistStream* iface)
989 OLEPictureImpl *This = impl_from_IPersistStream(iface);
990 FIXME("(%p),stub!\n",This);
994 #ifdef SONAME_LIBJPEG
996 static void *libjpeg_handle;
997 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
998 MAKE_FUNCPTR(jpeg_std_error);
999 MAKE_FUNCPTR(jpeg_CreateDecompress);
1000 MAKE_FUNCPTR(jpeg_read_header);
1001 MAKE_FUNCPTR(jpeg_start_decompress);
1002 MAKE_FUNCPTR(jpeg_read_scanlines);
1003 MAKE_FUNCPTR(jpeg_finish_decompress);
1004 MAKE_FUNCPTR(jpeg_destroy_decompress);
1007 static void *load_libjpeg(void)
1009 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1011 #define LOAD_FUNCPTR(f) \
1012 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1013 libjpeg_handle = NULL; \
1017 LOAD_FUNCPTR(jpeg_std_error);
1018 LOAD_FUNCPTR(jpeg_CreateDecompress);
1019 LOAD_FUNCPTR(jpeg_read_header);
1020 LOAD_FUNCPTR(jpeg_start_decompress);
1021 LOAD_FUNCPTR(jpeg_read_scanlines);
1022 LOAD_FUNCPTR(jpeg_finish_decompress);
1023 LOAD_FUNCPTR(jpeg_destroy_decompress);
1026 return libjpeg_handle;
1029 /* for the jpeg decompressor source manager. */
1030 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1032 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1033 ERR("(), should not get here.\n");
1037 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1038 TRACE("Skipping %ld bytes...\n", num_bytes);
1039 cinfo->src->next_input_byte += num_bytes;
1040 cinfo->src->bytes_in_buffer -= num_bytes;
1043 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1044 ERR("(desired=%d), should not get here.\n",desired);
1047 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1048 #endif /* SONAME_LIBJPEG */
1051 unsigned char *data;
1052 unsigned int curoff;
1056 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1057 struct gifdata *gd = (struct gifdata*)gif->UserData;
1059 if (len+gd->curoff > gd->len) {
1060 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1061 len = gd->len - gd->curoff;
1063 memcpy(data, gd->data+gd->curoff, len);
1069 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1080 int transparent = -1;
1087 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1088 ret = DGifSlurp(gif);
1089 if (ret == GIF_ERROR) {
1090 ERR("Failed reading GIF using libgif.\n");
1093 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1094 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1095 TRACE("imgcnt %d\n", gif->ImageCount);
1096 if (gif->ImageCount<1) {
1097 ERR("GIF stream does not have images inside?\n");
1100 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1101 gif->Image.Width, gif->Image.Height,
1102 gif->Image.Left, gif->Image.Top,
1103 gif->Image.Interlace
1106 padding = (gif->SWidth+3) & ~3;
1107 si = gif->SavedImages+0;
1108 gid = &(si->ImageDesc);
1110 if (!cm) cm = gif->SColorMap;
1111 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1112 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1114 /* look for the transparent color extension */
1115 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1116 eb = si->ExtensionBlocks + i;
1117 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1118 if ((eb->Bytes[0] & 1) == 1) {
1119 transparent = (unsigned char)eb->Bytes[3];
1124 for (i = 0; i < cm->ColorCount; i++) {
1125 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1126 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1127 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1128 if (i == transparent) {
1129 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1130 bmi->bmiColors[i].rgbGreen,
1131 bmi->bmiColors[i].rgbBlue);
1135 /* Map to in picture coordinates */
1136 for (i = 0, j = 0; i < gid->Height; i++) {
1137 if (gif->Image.Interlace) {
1139 bytes + (gid->Top + j) * padding + gid->Left,
1140 si->RasterBits + i * gid->Width,
1143 /* Lower bits of interlaced counter encode current interlace */
1144 if (j & 1) j += 2; /* Currently filling odd rows */
1145 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1146 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1148 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1149 /* End of current interlace, go to next interlace */
1150 if (j & 2) j = 1; /* Next iteration fills odd rows */
1151 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1152 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1156 bytes + (gid->Top + i) * padding + gid->Left,
1157 si->RasterBits + i * gid->Width,
1162 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1163 bmi->bmiHeader.biWidth = gif->SWidth;
1164 bmi->bmiHeader.biHeight = -gif->SHeight;
1165 bmi->bmiHeader.biPlanes = 1;
1166 bmi->bmiHeader.biBitCount = 8;
1167 bmi->bmiHeader.biCompression = BI_RGB;
1168 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1169 bmi->bmiHeader.biXPelsPerMeter = 0;
1170 bmi->bmiHeader.biYPelsPerMeter = 0;
1171 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1172 bmi->bmiHeader.biClrImportant = 0;
1175 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1184 if (transparent > -1) {
1185 /* Create the Mask */
1186 HDC hdc = CreateCompatibleDC(0);
1187 HDC hdcMask = CreateCompatibleDC(0);
1189 HBITMAP hOldbitmapmask;
1191 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1194 This->hbmXor = CreateDIBitmap(
1203 bmi->bmiColors[0].rgbRed = 0;
1204 bmi->bmiColors[0].rgbGreen = 0;
1205 bmi->bmiColors[0].rgbBlue = 0;
1206 bmi->bmiColors[1].rgbRed = 255;
1207 bmi->bmiColors[1].rgbGreen = 255;
1208 bmi->bmiColors[1].rgbBlue = 255;
1210 bmi->bmiHeader.biBitCount = 1;
1211 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1212 bmi->bmiHeader.biClrUsed = 2;
1214 for (i = 0; i < gif->SHeight; i++) {
1215 unsigned char * colorPointer = bytes + padding * i;
1216 unsigned char * monoPointer = bytes + monopadding * i;
1217 for (j = 0; j < gif->SWidth; j++) {
1218 unsigned char pixel = colorPointer[j];
1219 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1220 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1224 hTempMask = CreateDIBitmap(
1234 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1235 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1236 hOldbitmap = SelectObject(hdc, hTempMask);
1237 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1239 SetBkColor(hdc, RGB(255, 255, 255));
1240 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1242 /* We no longer need the original bitmap, so we apply the first
1243 transformation with the mask to speed up the rendering */
1244 SelectObject(hdc, This->hbmXor);
1245 SetBkColor(hdc, RGB(0,0,0));
1246 SetTextColor(hdc, RGB(255,255,255));
1247 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1248 hdcMask, 0, 0, SRCAND);
1250 SelectObject(hdc, hOldbitmap);
1251 SelectObject(hdcMask, hOldbitmapmask);
1254 DeleteObject(hTempMask);
1258 This->desc.picType = PICTYPE_BITMAP;
1259 OLEPictureImpl_SetBitmap(This);
1261 HeapFree(GetProcessHeap(),0,bmi);
1262 HeapFree(GetProcessHeap(),0,bytes);
1266 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1268 #ifdef SONAME_LIBJPEG
1269 struct jpeg_decompress_struct jd;
1270 struct jpeg_error_mgr jerr;
1273 JSAMPROW samprow,oldsamprow;
1274 BITMAPINFOHEADER bmi;
1277 struct jpeg_source_mgr xjsm;
1281 if(!libjpeg_handle) {
1282 if(!load_libjpeg()) {
1283 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1288 /* This is basically so we can use in-memory data for jpeg decompression.
1289 * We need to have all the functions.
1291 xjsm.next_input_byte = xbuf;
1292 xjsm.bytes_in_buffer = xread;
1293 xjsm.init_source = _jpeg_init_source;
1294 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1295 xjsm.skip_input_data = _jpeg_skip_input_data;
1296 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1297 xjsm.term_source = _jpeg_term_source;
1299 jd.err = pjpeg_std_error(&jerr);
1300 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1301 * jpeg_create_decompress(&jd); */
1302 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1304 ret=pjpeg_read_header(&jd,TRUE);
1305 jd.out_color_space = JCS_RGB;
1306 pjpeg_start_decompress(&jd);
1307 if (ret != JPEG_HEADER_OK) {
1308 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1309 HeapFree(GetProcessHeap(),0,xbuf);
1313 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1314 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1315 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1318 oldsamprow = samprow;
1319 while ( jd.output_scanline<jd.output_height ) {
1320 x = pjpeg_read_scanlines(&jd,&samprow,1);
1322 ERR("failed to read current scanline?\n");
1325 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1326 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1327 *(bits++) = *(samprow+2);
1328 *(bits++) = *(samprow+1);
1329 *(bits++) = *(samprow);
1331 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1332 samprow = oldsamprow;
1336 bmi.biSize = sizeof(bmi);
1337 bmi.biWidth = jd.output_width;
1338 bmi.biHeight = -jd.output_height;
1340 bmi.biBitCount = jd.output_components<<3;
1341 bmi.biCompression = BI_RGB;
1342 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1343 bmi.biXPelsPerMeter = 0;
1344 bmi.biYPelsPerMeter = 0;
1346 bmi.biClrImportant = 0;
1348 HeapFree(GetProcessHeap(),0,samprow);
1349 pjpeg_finish_decompress(&jd);
1350 pjpeg_destroy_decompress(&jd);
1352 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1361 This->desc.picType = PICTYPE_BITMAP;
1362 OLEPictureImpl_SetBitmap(This);
1363 HeapFree(GetProcessHeap(),0,bits);
1366 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1371 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1373 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1374 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1377 /* Does not matter whether this is a coreheader or not, we only use
1378 * components which are in both
1381 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1385 xbuf+bfh->bfOffBits,
1390 if (This->desc.u.bmp.hbitmap == 0)
1392 This->desc.picType = PICTYPE_BITMAP;
1393 OLEPictureImpl_SetBitmap(This);
1397 /*****************************************************
1398 * start of PNG-specific code
1399 * currently only supports colortype PNG_COLOR_TYPE_RGB
1401 #ifdef SONAME_LIBPNG
1408 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1411 png_io * io_ptr = png_ptr->io_ptr;
1413 if(length + io_ptr->position > io_ptr->size){
1414 length = io_ptr->size - io_ptr->position;
1417 memcpy(data, io_ptr->buff + io_ptr->position, length);
1419 io_ptr->position += length;
1422 static void *libpng_handle;
1423 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1424 MAKE_FUNCPTR(png_create_read_struct);
1425 MAKE_FUNCPTR(png_create_info_struct);
1426 MAKE_FUNCPTR(png_set_read_fn);
1427 MAKE_FUNCPTR(png_read_info);
1428 MAKE_FUNCPTR(png_read_image);
1429 MAKE_FUNCPTR(png_get_rowbytes);
1430 MAKE_FUNCPTR(png_set_bgr);
1431 MAKE_FUNCPTR(png_destroy_read_struct);
1432 MAKE_FUNCPTR(png_set_palette_to_rgb);
1433 MAKE_FUNCPTR(png_read_update_info);
1434 MAKE_FUNCPTR(png_get_tRNS);
1435 MAKE_FUNCPTR(png_get_PLTE);
1436 MAKE_FUNCPTR(png_set_expand);
1439 static void *load_libpng(void)
1441 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1443 #define LOAD_FUNCPTR(f) \
1444 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1445 libpng_handle = NULL; \
1448 LOAD_FUNCPTR(png_create_read_struct);
1449 LOAD_FUNCPTR(png_create_info_struct);
1450 LOAD_FUNCPTR(png_set_read_fn);
1451 LOAD_FUNCPTR(png_read_info);
1452 LOAD_FUNCPTR(png_read_image);
1453 LOAD_FUNCPTR(png_get_rowbytes);
1454 LOAD_FUNCPTR(png_set_bgr);
1455 LOAD_FUNCPTR(png_destroy_read_struct);
1456 LOAD_FUNCPTR(png_set_palette_to_rgb);
1457 LOAD_FUNCPTR(png_read_update_info);
1458 LOAD_FUNCPTR(png_get_tRNS);
1459 LOAD_FUNCPTR(png_get_PLTE);
1460 LOAD_FUNCPTR(png_set_expand);
1464 return libpng_handle;
1466 #endif /* SONAME_LIBPNG */
1468 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1470 #ifdef SONAME_LIBPNG
1472 png_structp png_ptr = NULL;
1473 png_infop info_ptr = NULL;
1474 INT row, rowsize, height, width, num_trans, i, j;
1475 png_bytep* row_pointers = NULL;
1476 png_bytep pngdata = NULL;
1477 BITMAPINFOHEADER bmi;
1478 HDC hdcref = NULL, hdcXor, hdcMask;
1482 png_color_16p trans_values;
1483 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1484 HBITMAP hbmoldXor, hbmoldMask, temp;
1486 if(!libpng_handle) {
1487 if(!load_libpng()) {
1488 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1497 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1500 if(setjmp(png_jmpbuf(png_ptr))){
1501 TRACE("Error in libpng\n");
1506 info_ptr = ppng_create_info_struct(png_ptr);
1507 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1508 ppng_read_info(png_ptr, info_ptr);
1510 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1511 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1512 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1513 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1518 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1521 /* sets format from anything to RGBA */
1522 ppng_set_expand(png_ptr);
1523 /* sets format to BGRA */
1524 ppng_set_bgr(png_ptr);
1526 ppng_read_update_info(png_ptr, info_ptr);
1528 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1529 /* align rowsize to 4-byte boundary */
1530 rowsize = (rowsize + 3) & ~3;
1531 height = info_ptr->height;
1532 width = info_ptr->width;
1534 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1535 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1537 if(!pngdata || !row_pointers){
1542 for (row = 0; row < height; row++){
1543 row_pointers[row] = pngdata + row * rowsize;
1546 ppng_read_image(png_ptr, row_pointers);
1548 bmi.biSize = sizeof(bmi);
1549 bmi.biWidth = width;
1550 bmi.biHeight = -height;
1552 bmi.biBitCount = info_ptr->channels * 8;
1553 bmi.biCompression = BI_RGB;
1554 bmi.biSizeImage = height * rowsize;
1555 bmi.biXPelsPerMeter = 0;
1556 bmi.biYPelsPerMeter = 0;
1558 bmi.biClrImportant = 0;
1561 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1570 /* only fully-transparent alpha is handled */
1571 if((info_ptr->channels != 4) || !transparency){
1572 ReleaseDC(0, hdcref);
1576 This->hbmXor = CreateDIBitmap(
1585 /* set transparent pixels to black, all others to white */
1586 for(i = 0; i < height; i++){
1587 for(j = 3; j < rowsize; j += 4){
1588 if(row_pointers[i][j] == 0)
1589 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1591 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1595 temp = CreateDIBitmap(
1604 ReleaseDC(0, hdcref);
1606 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1607 hdcXor = CreateCompatibleDC(NULL);
1608 hdcMask = CreateCompatibleDC(NULL);
1610 hbmoldXor = SelectObject(hdcXor,temp);
1611 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1612 SetBkColor(hdcXor,black);
1613 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1615 SelectObject(hdcXor,This->hbmXor);
1618 SetTextColor(hdcXor,white);
1619 SetBkColor(hdcXor,black);
1620 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1622 SelectObject(hdcXor,hbmoldXor);
1623 SelectObject(hdcMask,hbmoldMask);
1629 This->desc.picType = PICTYPE_BITMAP;
1630 OLEPictureImpl_SetBitmap(This);
1635 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1636 HeapFree(GetProcessHeap(), 0, row_pointers);
1637 HeapFree(GetProcessHeap(), 0, pngdata);
1639 #else /* SONAME_LIBPNG */
1640 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1645 /*****************************************************
1646 * start of Icon-specific code
1649 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1652 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1657 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1658 FIXME("icon.idType=%d\n",cifd->idType);
1659 FIXME("icon.idCount=%d\n",cifd->idCount);
1661 for (i=0;i<cifd->idCount;i++) {
1662 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1663 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1664 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1665 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1666 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1667 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1668 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1669 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1673 /* If we have more than one icon, try to find the best.
1674 * this currently means '32 pixel wide'.
1676 if (cifd->idCount!=1) {
1677 for (i=0;i<cifd->idCount;i++) {
1678 if (cifd->idEntries[i].bWidth == 32)
1681 if (i==cifd->idCount) i=0;
1684 hicon = CreateIconFromResourceEx(
1685 xbuf+cifd->idEntries[i].dwDIBOffset,
1686 cifd->idEntries[i].dwDIBSize,
1689 cifd->idEntries[i].bWidth,
1690 cifd->idEntries[i].bHeight,
1694 ERR("CreateIcon failed.\n");
1697 This->desc.picType = PICTYPE_ICON;
1698 This->desc.u.icon.hicon = hicon;
1699 This->origWidth = cifd->idEntries[i].bWidth;
1700 This->origHeight = cifd->idEntries[i].bHeight;
1701 hdcRef = CreateCompatibleDC(0);
1702 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1703 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1709 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1710 const BYTE *data, ULONG size)
1715 hemf = SetEnhMetaFileBits(size, data);
1716 if (!hemf) return E_FAIL;
1718 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1720 This->desc.picType = PICTYPE_ENHMETAFILE;
1721 This->desc.u.emf.hemf = hemf;
1723 This->origWidth = 0;
1724 This->origHeight = 0;
1725 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1726 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1731 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1732 const BYTE *data, ULONG size)
1734 APM_HEADER *header = (APM_HEADER *)data;
1737 if (size < sizeof(APM_HEADER))
1739 if (header->key != 0x9ac6cdd7)
1742 /* SetMetaFileBitsEx performs data check on its own */
1743 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1744 if (!hmf) return E_FAIL;
1746 This->desc.picType = PICTYPE_METAFILE;
1747 This->desc.u.wmf.hmeta = hmf;
1748 This->desc.u.wmf.xExt = 0;
1749 This->desc.u.wmf.yExt = 0;
1751 This->origWidth = 0;
1752 This->origHeight = 0;
1753 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1754 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1758 /************************************************************************
1759 * BITMAP FORMAT FLAGS -
1760 * Flags that differentiate between different types of bitmaps.
1763 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1764 #define BITMAP_FORMAT_JPEG 0xd8ff
1765 #define BITMAP_FORMAT_GIF 0x4947
1766 #define BITMAP_FORMAT_PNG 0x5089
1767 #define BITMAP_FORMAT_APM 0xcdd7
1769 /************************************************************************
1770 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1772 * Loads the binary data from the IStream. Starts at current position.
1773 * There appears to be an 2 DWORD header:
1777 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1779 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1780 HRESULT hr = E_FAIL;
1781 BOOL headerisdata = FALSE;
1782 BOOL statfailed = FALSE;
1783 ULONG xread, toread;
1789 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1791 TRACE("(%p,%p)\n",This,pStm);
1793 /****************************************************************************************
1794 * Part 1: Load the data
1796 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1797 * out whether we do.
1799 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1800 * compound file. This may explain most, if not all, of the cases of "no
1801 * header", and the header validation should take this into account.
1802 * At least in Visual Basic 6, resource streams, valid headers are
1803 * header[0] == "lt\0\0",
1804 * header[1] == length_of_stream.
1806 * Also handle streams where we do not have a working "Stat" method by
1807 * reading all data until the end of the stream.
1809 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1811 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1813 /* we will read at least 8 byte ... just right below */
1814 statstg.cbSize.QuadPart = 8;
1819 headerisdata = FALSE;
1821 hr=IStream_Read(pStm,header,8,&xread);
1822 if (hr || xread!=8) {
1823 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1824 return (hr?hr:E_FAIL);
1826 headerread += xread;
1829 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1830 if (toread != 0 && toread != header[1])
1831 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1834 if (toread == 0) break;
1836 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1837 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1838 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1839 (header[0] == EMR_HEADER) || /* EMF header */
1840 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1842 ) {/* Found start of bitmap data */
1843 headerisdata = TRUE;
1845 toread = statstg.cbSize.QuadPart-8;
1849 FIXME("Unknown stream header magic: %08x\n", header[0]);
1853 } while (!headerisdata);
1855 if (statfailed) { /* we don't know the size ... read all we get */
1857 int origsize = sizeinc;
1860 TRACE("Reading all data from stream.\n");
1861 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1863 memcpy (xbuf, header, 8);
1865 while (xread < origsize) {
1866 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1871 if (!nread || hr) /* done, or error */
1873 if (xread == origsize) {
1874 origsize += sizeinc;
1875 sizeinc = 2*sizeinc; /* exponential increase */
1876 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1880 TRACE("hr in no-stat loader case is %08x\n", hr);
1881 TRACE("loaded %d bytes.\n", xread);
1882 This->datalen = xread;
1885 This->datalen = toread+(headerisdata?8:0);
1886 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1888 return E_OUTOFMEMORY;
1891 memcpy (xbuf, header, 8);
1893 while (xread < This->datalen) {
1895 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1900 if (xread != This->datalen)
1901 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1903 if (This->datalen == 0) { /* Marks the "NONE" picture */
1904 This->desc.picType = PICTYPE_NONE;
1909 /****************************************************************************************
1910 * Part 2: Process the loaded data
1913 magic = xbuf[0] + (xbuf[1]<<8);
1914 This->loadtime_format = magic;
1917 case BITMAP_FORMAT_GIF: /* GIF */
1918 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1920 case BITMAP_FORMAT_JPEG: /* JPEG */
1921 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1923 case BITMAP_FORMAT_BMP: /* Bitmap */
1924 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1926 case BITMAP_FORMAT_PNG: /* PNG */
1927 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1929 case BITMAP_FORMAT_APM: /* APM */
1930 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1932 case 0x0000: { /* ICON , first word is dwReserved */
1933 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1940 /* let's see if it's a EMF */
1941 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1942 if (hr == S_OK) break;
1944 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1946 for (i=0;i<xread+8;i++) {
1947 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1948 else MESSAGE("%02x ",xbuf[i-8]);
1949 if (i % 10 == 9) MESSAGE("\n");
1955 This->bIsDirty = FALSE;
1957 /* FIXME: this notify is not really documented */
1959 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1963 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1967 BITMAPINFO * pInfoBitmap;
1968 int iNumPaletteEntries;
1969 unsigned char * pPixelData;
1970 BITMAPFILEHEADER * pFileHeader;
1971 BITMAPINFO * pInfoHeader;
1973 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1974 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1976 /* Find out bitmap size and padded length */
1978 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1979 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1981 /* Fetch bitmap palette & pixel data */
1983 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1984 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1986 /* Calculate the total length required for the BMP data */
1987 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1988 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1989 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1991 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1992 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1994 iNumPaletteEntries = 0;
1997 sizeof(BITMAPFILEHEADER) +
1998 sizeof(BITMAPINFOHEADER) +
1999 iNumPaletteEntries * sizeof(RGBQUAD) +
2000 pInfoBitmap->bmiHeader.biSizeImage;
2001 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2003 /* Fill the BITMAPFILEHEADER */
2004 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
2005 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2006 pFileHeader->bfSize = *pLength;
2007 pFileHeader->bfOffBits =
2008 sizeof(BITMAPFILEHEADER) +
2009 sizeof(BITMAPINFOHEADER) +
2010 iNumPaletteEntries * sizeof(RGBQUAD);
2012 /* Fill the BITMAPINFOHEADER and the palette data */
2013 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2014 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2016 (unsigned char *)(*ppBuffer) +
2017 sizeof(BITMAPFILEHEADER) +
2018 sizeof(BITMAPINFOHEADER) +
2019 iNumPaletteEntries * sizeof(RGBQUAD),
2020 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2023 HeapFree(GetProcessHeap(), 0, pPixelData);
2024 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2028 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2033 *ppBuffer = NULL; *pLength = 0;
2034 if (GetIconInfo(hIcon, &infoIcon)) {
2036 BITMAPINFO * pInfoBitmap;
2037 unsigned char * pIconData = NULL;
2038 unsigned int iDataSize = 0;
2040 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2042 /* Find out icon size */
2044 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2045 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2047 /* Auxiliary pointers */
2048 CURSORICONFILEDIR * pIconDir;
2049 CURSORICONFILEDIRENTRY * pIconEntry;
2050 BITMAPINFOHEADER * pIconBitmapHeader;
2051 unsigned int iOffsetPalette;
2052 unsigned int iOffsetColorData;
2053 unsigned int iOffsetMaskData;
2055 unsigned int iLengthScanLineColor;
2056 unsigned int iLengthScanLineMask;
2057 unsigned int iNumEntriesPalette;
2059 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2060 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2062 FIXME("DEBUG: bitmap size is %d x %d\n",
2063 pInfoBitmap->bmiHeader.biWidth,
2064 pInfoBitmap->bmiHeader.biHeight);
2065 FIXME("DEBUG: bitmap bpp is %d\n",
2066 pInfoBitmap->bmiHeader.biBitCount);
2067 FIXME("DEBUG: bitmap nplanes is %d\n",
2068 pInfoBitmap->bmiHeader.biPlanes);
2069 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2070 pInfoBitmap->bmiHeader.biSizeImage);
2072 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2073 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2074 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2076 /* Fill out the CURSORICONFILEDIR */
2077 pIconDir = (CURSORICONFILEDIR *)pIconData;
2078 pIconDir->idType = 1;
2079 pIconDir->idCount = 1;
2081 /* Fill out the CURSORICONFILEDIRENTRY */
2082 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2083 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2084 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2085 pIconEntry->bColorCount =
2086 (pInfoBitmap->bmiHeader.biBitCount < 8)
2087 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2089 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2090 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2091 pIconEntry->dwDIBSize = 0;
2092 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2094 /* Fill out the BITMAPINFOHEADER */
2095 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2096 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2098 /* Find out whether a palette exists for the bitmap */
2099 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2100 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2101 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2102 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2103 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2104 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2105 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2106 iNumEntriesPalette = 3;
2107 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2108 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2110 iNumEntriesPalette = 0;
2113 /* Add bitmap size and header size to icon data size. */
2114 iOffsetPalette = iDataSize;
2115 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2116 iOffsetColorData = iDataSize;
2117 iDataSize += pIconBitmapHeader->biSizeImage;
2118 iOffsetMaskData = iDataSize;
2119 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2120 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2121 pIconBitmapHeader->biHeight *= 2;
2122 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2123 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2124 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2125 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2127 /* Get the actual bitmap data from the icon bitmap */
2128 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2129 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2130 if (iNumEntriesPalette > 0) {
2131 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2132 iNumEntriesPalette * sizeof(RGBQUAD));
2135 /* Reset all values so that GetDIBits call succeeds */
2136 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2137 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2138 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2140 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2141 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2142 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2144 printf("ERROR: unable to get bitmap mask (error %u)\n",
2149 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2150 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2152 /* Write out everything produced so far to the stream */
2153 *ppBuffer = pIconData; *pLength = iDataSize;
2157 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2162 Remarks (from MSDN entry on GetIconInfo):
2164 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2165 members of ICONINFO. The calling application must manage
2166 these bitmaps and delete them when they are no longer
2169 if (hDC) ReleaseDC(0, hDC);
2170 DeleteObject(infoIcon.hbmMask);
2171 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2172 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2174 printf("ERROR: Unable to get icon information (error %u)\n",
2180 static HRESULT WINAPI OLEPictureImpl_Save(
2181 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2183 HRESULT hResult = E_NOTIMPL;
2185 unsigned int iDataSize;
2187 int iSerializeResult = 0;
2188 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2190 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2192 switch (This->desc.picType) {
2194 if (This->bIsDirty || !This->data) {
2195 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2196 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2200 HeapFree(GetProcessHeap(), 0, This->data);
2201 This->data = pIconData;
2202 This->datalen = iDataSize;
2204 if (This->loadtime_magic != 0xdeadbeef) {
2207 header[0] = This->loadtime_magic;
2208 header[1] = This->datalen;
2209 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2211 IStream_Write(pStm, This->data, This->datalen, &dummy);
2215 case PICTYPE_BITMAP:
2216 if (This->bIsDirty) {
2217 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2218 case BITMAP_FORMAT_BMP:
2219 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2221 case BITMAP_FORMAT_JPEG:
2222 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2224 case BITMAP_FORMAT_GIF:
2225 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2227 case BITMAP_FORMAT_PNG:
2228 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2231 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2234 if (iSerializeResult) {
2236 if (This->loadtime_magic != 0xdeadbeef) {
2241 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2242 header[1] = iDataSize;
2243 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2245 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2247 HeapFree(GetProcessHeap(), 0, This->data);
2248 This->data = pIconData;
2249 This->datalen = iDataSize;
2254 if (This->loadtime_magic != 0xdeadbeef) {
2259 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2260 header[1] = This->datalen;
2261 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2263 IStream_Write(pStm, This->data, This->datalen, &dummy);
2267 case PICTYPE_METAFILE:
2268 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2270 case PICTYPE_ENHMETAFILE:
2271 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2274 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2277 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2281 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2282 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2284 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2285 FIXME("(%p,%p),stub!\n",This,pcbSize);
2290 /************************************************************************
2294 /************************************************************************
2295 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2297 * See Windows documentation for more details on IUnknown methods.
2299 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2304 OLEPictureImpl *This = impl_from_IDispatch(iface);
2306 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2309 /************************************************************************
2310 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2312 * See Windows documentation for more details on IUnknown methods.
2314 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2317 OLEPictureImpl *This = impl_from_IDispatch(iface);
2319 return IPicture_AddRef((IPicture *)This);
2322 /************************************************************************
2323 * OLEPictureImpl_IDispatch_Release (IUnknown)
2325 * See Windows documentation for more details on IUnknown methods.
2327 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2330 OLEPictureImpl *This = impl_from_IDispatch(iface);
2332 return IPicture_Release((IPicture *)This);
2335 /************************************************************************
2336 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2338 * See Windows documentation for more details on IDispatch methods.
2340 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2342 unsigned int* pctinfo)
2344 TRACE("(%p)\n", pctinfo);
2351 /************************************************************************
2352 * OLEPictureImpl_GetTypeInfo (IDispatch)
2354 * See Windows documentation for more details on IDispatch methods.
2356 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2360 ITypeInfo** ppTInfo)
2362 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2366 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2371 hres = LoadTypeLib(stdole2tlb, &tl);
2374 ERR("Could not load stdole2.tlb\n");
2378 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2380 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2385 /************************************************************************
2386 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2388 * See Windows documentation for more details on IDispatch methods.
2390 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2393 LPOLESTR* rgszNames,
2401 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2402 rgszNames, cNames, (int)lcid, rgDispId);
2406 return E_INVALIDARG;
2410 /* retrieve type information */
2411 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2415 ERR("GetTypeInfo failed.\n");
2419 /* convert names to DISPIDs */
2420 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2421 ITypeInfo_Release(pTInfo);
2427 /************************************************************************
2428 * OLEPictureImpl_Invoke (IDispatch)
2430 * See Windows documentation for more details on IDispatch methods.
2432 static HRESULT WINAPI OLEPictureImpl_Invoke(
2434 DISPID dispIdMember,
2438 DISPPARAMS* pDispParams,
2439 VARIANT* pVarResult,
2440 EXCEPINFO* pExepInfo,
2443 OLEPictureImpl *This = impl_from_IDispatch(iface);
2445 /* validate parameters */
2447 if (!IsEqualIID(riid, &IID_NULL))
2449 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2450 return DISP_E_UNKNOWNNAME;
2455 ERR("null pDispParams not allowed\n");
2456 return DISP_E_PARAMNOTOPTIONAL;
2459 if (wFlags & DISPATCH_PROPERTYGET)
2461 if (pDispParams->cArgs != 0)
2463 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2464 return DISP_E_BADPARAMCOUNT;
2468 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2469 return DISP_E_PARAMNOTOPTIONAL;
2472 else if (wFlags & DISPATCH_PROPERTYPUT)
2474 if (pDispParams->cArgs != 1)
2476 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2477 return DISP_E_BADPARAMCOUNT;
2481 switch (dispIdMember)
2483 case DISPID_PICT_HANDLE:
2484 if (wFlags & DISPATCH_PROPERTYGET)
2486 TRACE("DISPID_PICT_HANDLE\n");
2487 V_VT(pVarResult) = VT_I4;
2488 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2491 case DISPID_PICT_HPAL:
2492 if (wFlags & DISPATCH_PROPERTYGET)
2494 TRACE("DISPID_PICT_HPAL\n");
2495 V_VT(pVarResult) = VT_I4;
2496 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2498 else if (wFlags & DISPATCH_PROPERTYPUT)
2502 TRACE("DISPID_PICT_HPAL\n");
2504 VariantInit(&vararg);
2505 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2509 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2511 VariantClear(&vararg);
2515 case DISPID_PICT_TYPE:
2516 if (wFlags & DISPATCH_PROPERTYGET)
2518 TRACE("DISPID_PICT_TYPE\n");
2519 V_VT(pVarResult) = VT_I2;
2520 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2523 case DISPID_PICT_WIDTH:
2524 if (wFlags & DISPATCH_PROPERTYGET)
2526 TRACE("DISPID_PICT_WIDTH\n");
2527 V_VT(pVarResult) = VT_I4;
2528 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2531 case DISPID_PICT_HEIGHT:
2532 if (wFlags & DISPATCH_PROPERTYGET)
2534 TRACE("DISPID_PICT_HEIGHT\n");
2535 V_VT(pVarResult) = VT_I4;
2536 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2541 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2542 return DISP_E_MEMBERNOTFOUND;
2546 static const IPictureVtbl OLEPictureImpl_VTable =
2548 OLEPictureImpl_QueryInterface,
2549 OLEPictureImpl_AddRef,
2550 OLEPictureImpl_Release,
2551 OLEPictureImpl_get_Handle,
2552 OLEPictureImpl_get_hPal,
2553 OLEPictureImpl_get_Type,
2554 OLEPictureImpl_get_Width,
2555 OLEPictureImpl_get_Height,
2556 OLEPictureImpl_Render,
2557 OLEPictureImpl_set_hPal,
2558 OLEPictureImpl_get_CurDC,
2559 OLEPictureImpl_SelectPicture,
2560 OLEPictureImpl_get_KeepOriginalFormat,
2561 OLEPictureImpl_put_KeepOriginalFormat,
2562 OLEPictureImpl_PictureChanged,
2563 OLEPictureImpl_SaveAsFile,
2564 OLEPictureImpl_get_Attributes
2567 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2569 OLEPictureImpl_IDispatch_QueryInterface,
2570 OLEPictureImpl_IDispatch_AddRef,
2571 OLEPictureImpl_IDispatch_Release,
2572 OLEPictureImpl_GetTypeInfoCount,
2573 OLEPictureImpl_GetTypeInfo,
2574 OLEPictureImpl_GetIDsOfNames,
2575 OLEPictureImpl_Invoke
2578 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2580 OLEPictureImpl_IPersistStream_QueryInterface,
2581 OLEPictureImpl_IPersistStream_AddRef,
2582 OLEPictureImpl_IPersistStream_Release,
2583 OLEPictureImpl_GetClassID,
2584 OLEPictureImpl_IsDirty,
2585 OLEPictureImpl_Load,
2586 OLEPictureImpl_Save,
2587 OLEPictureImpl_GetSizeMax
2590 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2592 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2593 OLEPictureImpl_IConnectionPointContainer_AddRef,
2594 OLEPictureImpl_IConnectionPointContainer_Release,
2595 OLEPictureImpl_EnumConnectionPoints,
2596 OLEPictureImpl_FindConnectionPoint
2599 /***********************************************************************
2600 * OleCreatePictureIndirect (OLEAUT32.419)
2602 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2603 BOOL fOwn, LPVOID *ppvObj )
2605 OLEPictureImpl* newPict = NULL;
2608 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2619 * Try to construct a new instance of the class.
2621 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2623 if (newPict == NULL)
2624 return E_OUTOFMEMORY;
2627 * Make sure it supports the interface required by the caller.
2629 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2632 * Release the reference obtained in the constructor. If
2633 * the QueryInterface was unsuccessful, it will free the class.
2635 IPicture_Release((IPicture*)newPict);
2641 /***********************************************************************
2642 * OleLoadPicture (OLEAUT32.418)
2644 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2645 REFIID riid, LPVOID *ppvObj )
2651 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2652 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2654 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2657 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2659 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2660 IPicture_Release(newpic);
2664 hr = IPersistStream_Load(ps,lpstream);
2665 IPersistStream_Release(ps);
2668 ERR("IPersistStream_Load failed\n");
2669 IPicture_Release(newpic);
2673 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2675 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2676 IPicture_Release(newpic);
2680 /***********************************************************************
2681 * OleLoadPictureEx (OLEAUT32.401)
2683 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2684 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2690 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2691 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2693 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2696 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2698 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2699 IPicture_Release(newpic);
2703 hr = IPersistStream_Load(ps,lpstream);
2704 IPersistStream_Release(ps);
2707 ERR("IPersistStream_Load failed\n");
2708 IPicture_Release(newpic);
2712 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2714 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2715 IPicture_Release(newpic);
2719 /***********************************************************************
2720 * OleLoadPicturePath (OLEAUT32.424)
2722 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2723 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2726 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2730 HGLOBAL hGlobal = NULL;
2731 DWORD dwBytesRead = 0;
2734 IPersistStream *pStream;
2737 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2738 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2739 debugstr_guid(riid), ppvRet);
2741 if (!ppvRet) return E_POINTER;
2743 if (strncmpW(szURLorPath, file, 7) == 0) {
2746 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2748 if (hFile == INVALID_HANDLE_VALUE)
2749 return E_UNEXPECTED;
2751 dwFileSize = GetFileSize(hFile, NULL);
2752 if (dwFileSize != INVALID_FILE_SIZE )
2754 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2757 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2760 GlobalFree(hGlobal);
2768 return E_UNEXPECTED;
2770 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2773 GlobalFree(hGlobal);
2780 hRes = CreateBindCtx(0, &pbc);
2781 if (SUCCEEDED(hRes))
2783 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2784 if (SUCCEEDED(hRes))
2786 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2787 IMoniker_Release(pmnk);
2789 IBindCtx_Release(pbc);
2795 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2796 &IID_IPicture, (LPVOID*)&ipicture);
2798 IStream_Release(stream);
2802 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2804 IStream_Release(stream);
2805 IPicture_Release(ipicture);
2809 hRes = IPersistStream_Load(pStream, stream);
2810 IPersistStream_Release(pStream);
2811 IStream_Release(stream);
2814 IPicture_Release(ipicture);
2818 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2820 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2822 IPicture_Release(ipicture);
2826 /*******************************************************************************
2827 * StdPic ClassFactory
2831 /* IUnknown fields */
2832 const IClassFactoryVtbl *lpVtbl;
2834 } IClassFactoryImpl;
2836 static HRESULT WINAPI
2837 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2838 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2840 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2841 return E_NOINTERFACE;
2845 SPCF_AddRef(LPCLASSFACTORY iface) {
2846 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2847 return InterlockedIncrement(&This->ref);
2850 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2851 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2852 /* static class, won't be freed */
2853 return InterlockedDecrement(&This->ref);
2856 static HRESULT WINAPI SPCF_CreateInstance(
2857 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2859 /* Creates an uninitialized picture */
2860 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2864 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2865 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2866 FIXME("(%p)->(%d),stub!\n",This,dolock);
2870 static const IClassFactoryVtbl SPCF_Vtbl = {
2871 SPCF_QueryInterface,
2874 SPCF_CreateInstance,
2877 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2879 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }