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:
713 POINT prevOrg, prevWndOrg;
714 SIZE prevExt, prevWndExt;
717 /* Render the WMF to the appropriate location by setting the
718 appropriate ratio between "device units" and "logical units" */
719 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
720 /* For the "source rectangle" the y-axis must be inverted */
721 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
722 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
723 /* For the "destination rectangle" no inversion is necessary */
724 SetViewportOrgEx(hdc, x, y, &prevOrg);
725 SetViewportExtEx(hdc, cx, cy, &prevExt);
727 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
728 ERR("PlayMetaFile failed!\n");
730 /* We're done, restore the DC to the previous settings for converting
731 logical units to device units */
732 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
733 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
734 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
735 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
736 SetMapMode(hdc, oldmode);
740 case PICTYPE_ENHMETAFILE:
742 RECT rc = { x, y, x + cx, y + cy };
743 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
748 FIXME("type %d not implemented\n", This->desc.picType);
754 /************************************************************************
755 * OLEPictureImpl_set_hPal
757 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
760 OLEPictureImpl *This = (OLEPictureImpl *)iface;
761 FIXME("(%p)->(%08x): stub\n", This, hpal);
762 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
766 /************************************************************************
767 * OLEPictureImpl_get_CurDC
769 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
772 OLEPictureImpl *This = (OLEPictureImpl *)iface;
773 TRACE("(%p), returning %p\n", This, This->hDCCur);
774 if (phdc) *phdc = This->hDCCur;
778 /************************************************************************
779 * OLEPictureImpl_SelectPicture
781 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
784 OLE_HANDLE *phbmpOut)
786 OLEPictureImpl *This = (OLEPictureImpl *)iface;
787 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
788 if (This->desc.picType == PICTYPE_BITMAP) {
789 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
792 *phdcOut = This->hDCCur;
793 This->hDCCur = hdcIn;
795 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
798 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
803 /************************************************************************
804 * OLEPictureImpl_get_KeepOriginalFormat
806 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
809 OLEPictureImpl *This = (OLEPictureImpl *)iface;
810 TRACE("(%p)->(%p)\n", This, pfKeep);
813 *pfKeep = This->keepOrigFormat;
817 /************************************************************************
818 * OLEPictureImpl_put_KeepOriginalFormat
820 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
823 OLEPictureImpl *This = (OLEPictureImpl *)iface;
824 TRACE("(%p)->(%d)\n", This, keep);
825 This->keepOrigFormat = keep;
826 /* FIXME: what DISPID notification here? */
830 /************************************************************************
831 * OLEPictureImpl_PictureChanged
833 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
835 OLEPictureImpl *This = (OLEPictureImpl *)iface;
836 TRACE("(%p)->()\n", This);
837 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
838 This->bIsDirty = TRUE;
842 /************************************************************************
843 * OLEPictureImpl_SaveAsFile
845 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
850 OLEPictureImpl *This = (OLEPictureImpl *)iface;
851 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
852 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
855 /************************************************************************
856 * OLEPictureImpl_get_Attributes
858 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
861 OLEPictureImpl *This = (OLEPictureImpl *)iface;
862 TRACE("(%p)->(%p).\n", This, pdwAttr);
868 switch (This->desc.picType) {
869 case PICTYPE_UNINITIALIZED:
870 case PICTYPE_NONE: break;
871 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
872 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
873 case PICTYPE_ENHMETAFILE: /* fall through */
874 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
875 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
881 /************************************************************************
882 * IConnectionPointContainer
884 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
885 IConnectionPointContainer* iface,
889 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
891 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
894 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
895 IConnectionPointContainer* iface)
897 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
899 return IPicture_AddRef((IPicture *)This);
902 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
903 IConnectionPointContainer* iface)
905 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
907 return IPicture_Release((IPicture *)This);
910 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
911 IConnectionPointContainer* iface,
912 IEnumConnectionPoints** ppEnum)
914 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
916 FIXME("(%p,%p), stub!\n",This,ppEnum);
920 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
921 IConnectionPointContainer* iface,
923 IConnectionPoint **ppCP)
925 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
926 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
930 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
931 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
932 FIXME("no connection point for %s\n",debugstr_guid(riid));
933 return CONNECT_E_NOCONNECTION;
937 /************************************************************************
941 /************************************************************************
942 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
944 * See Windows documentation for more details on IUnknown methods.
946 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
947 IPersistStream* iface,
951 OLEPictureImpl *This = impl_from_IPersistStream(iface);
953 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
956 /************************************************************************
957 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
959 * See Windows documentation for more details on IUnknown methods.
961 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
962 IPersistStream* iface)
964 OLEPictureImpl *This = impl_from_IPersistStream(iface);
966 return IPicture_AddRef((IPicture *)This);
969 /************************************************************************
970 * OLEPictureImpl_IPersistStream_Release (IUnknown)
972 * See Windows documentation for more details on IUnknown methods.
974 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
975 IPersistStream* iface)
977 OLEPictureImpl *This = impl_from_IPersistStream(iface);
979 return IPicture_Release((IPicture *)This);
982 /************************************************************************
983 * OLEPictureImpl_IPersistStream_GetClassID
985 static HRESULT WINAPI OLEPictureImpl_GetClassID(
986 IPersistStream* iface,CLSID* pClassID)
988 TRACE("(%p)\n", pClassID);
989 *pClassID = CLSID_StdPicture;
993 /************************************************************************
994 * OLEPictureImpl_IPersistStream_IsDirty
996 static HRESULT WINAPI OLEPictureImpl_IsDirty(
997 IPersistStream* iface)
999 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1000 FIXME("(%p),stub!\n",This);
1004 #ifdef SONAME_LIBJPEG
1006 static void *libjpeg_handle;
1007 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1008 MAKE_FUNCPTR(jpeg_std_error);
1009 MAKE_FUNCPTR(jpeg_CreateDecompress);
1010 MAKE_FUNCPTR(jpeg_read_header);
1011 MAKE_FUNCPTR(jpeg_start_decompress);
1012 MAKE_FUNCPTR(jpeg_read_scanlines);
1013 MAKE_FUNCPTR(jpeg_finish_decompress);
1014 MAKE_FUNCPTR(jpeg_destroy_decompress);
1017 static void *load_libjpeg(void)
1019 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1021 #define LOAD_FUNCPTR(f) \
1022 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1023 libjpeg_handle = NULL; \
1027 LOAD_FUNCPTR(jpeg_std_error);
1028 LOAD_FUNCPTR(jpeg_CreateDecompress);
1029 LOAD_FUNCPTR(jpeg_read_header);
1030 LOAD_FUNCPTR(jpeg_start_decompress);
1031 LOAD_FUNCPTR(jpeg_read_scanlines);
1032 LOAD_FUNCPTR(jpeg_finish_decompress);
1033 LOAD_FUNCPTR(jpeg_destroy_decompress);
1036 return libjpeg_handle;
1039 /* for the jpeg decompressor source manager. */
1040 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1042 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1043 ERR("(), should not get here.\n");
1047 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1048 TRACE("Skipping %ld bytes...\n", num_bytes);
1049 cinfo->src->next_input_byte += num_bytes;
1050 cinfo->src->bytes_in_buffer -= num_bytes;
1053 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1054 ERR("(desired=%d), should not get here.\n",desired);
1057 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1058 #endif /* SONAME_LIBJPEG */
1061 unsigned char *data;
1062 unsigned int curoff;
1066 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1067 struct gifdata *gd = (struct gifdata*)gif->UserData;
1069 if (len+gd->curoff > gd->len) {
1070 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1071 len = gd->len - gd->curoff;
1073 memcpy(data, gd->data+gd->curoff, len);
1079 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1090 int transparent = -1;
1097 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1098 ret = DGifSlurp(gif);
1099 if (ret == GIF_ERROR) {
1100 ERR("Failed reading GIF using libgif.\n");
1103 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1104 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1105 TRACE("imgcnt %d\n", gif->ImageCount);
1106 if (gif->ImageCount<1) {
1107 ERR("GIF stream does not have images inside?\n");
1110 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1111 gif->Image.Width, gif->Image.Height,
1112 gif->Image.Left, gif->Image.Top,
1113 gif->Image.Interlace
1116 padding = (gif->SWidth+3) & ~3;
1117 si = gif->SavedImages+0;
1118 gid = &(si->ImageDesc);
1120 if (!cm) cm = gif->SColorMap;
1121 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1122 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1124 /* look for the transparent color extension */
1125 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1126 eb = si->ExtensionBlocks + i;
1127 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1128 if ((eb->Bytes[0] & 1) == 1) {
1129 transparent = (unsigned char)eb->Bytes[3];
1134 for (i = 0; i < cm->ColorCount; i++) {
1135 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1136 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1137 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1138 if (i == transparent) {
1139 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1140 bmi->bmiColors[i].rgbGreen,
1141 bmi->bmiColors[i].rgbBlue);
1145 /* Map to in picture coordinates */
1146 for (i = 0, j = 0; i < gid->Height; i++) {
1147 if (gif->Image.Interlace) {
1149 bytes + (gid->Top + j) * padding + gid->Left,
1150 si->RasterBits + i * gid->Width,
1153 /* Lower bits of interlaced counter encode current interlace */
1154 if (j & 1) j += 2; /* Currently filling odd rows */
1155 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1156 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1158 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1159 /* End of current interlace, go to next interlace */
1160 if (j & 2) j = 1; /* Next iteration fills odd rows */
1161 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1162 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1166 bytes + (gid->Top + i) * padding + gid->Left,
1167 si->RasterBits + i * gid->Width,
1172 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1173 bmi->bmiHeader.biWidth = gif->SWidth;
1174 bmi->bmiHeader.biHeight = -gif->SHeight;
1175 bmi->bmiHeader.biPlanes = 1;
1176 bmi->bmiHeader.biBitCount = 8;
1177 bmi->bmiHeader.biCompression = BI_RGB;
1178 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1179 bmi->bmiHeader.biXPelsPerMeter = 0;
1180 bmi->bmiHeader.biYPelsPerMeter = 0;
1181 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1182 bmi->bmiHeader.biClrImportant = 0;
1185 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1194 if (transparent > -1) {
1195 /* Create the Mask */
1196 HDC hdc = CreateCompatibleDC(0);
1197 HDC hdcMask = CreateCompatibleDC(0);
1199 HBITMAP hOldbitmapmask;
1201 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1204 This->hbmXor = CreateDIBitmap(
1213 bmi->bmiColors[0].rgbRed = 0;
1214 bmi->bmiColors[0].rgbGreen = 0;
1215 bmi->bmiColors[0].rgbBlue = 0;
1216 bmi->bmiColors[1].rgbRed = 255;
1217 bmi->bmiColors[1].rgbGreen = 255;
1218 bmi->bmiColors[1].rgbBlue = 255;
1220 bmi->bmiHeader.biBitCount = 1;
1221 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1222 bmi->bmiHeader.biClrUsed = 2;
1224 for (i = 0; i < gif->SHeight; i++) {
1225 unsigned char * colorPointer = bytes + padding * i;
1226 unsigned char * monoPointer = bytes + monopadding * i;
1227 for (j = 0; j < gif->SWidth; j++) {
1228 unsigned char pixel = colorPointer[j];
1229 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1230 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1234 hTempMask = CreateDIBitmap(
1244 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1245 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1246 hOldbitmap = SelectObject(hdc, hTempMask);
1247 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1249 SetBkColor(hdc, RGB(255, 255, 255));
1250 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1252 /* We no longer need the original bitmap, so we apply the first
1253 transformation with the mask to speed up the rendering */
1254 SelectObject(hdc, This->hbmXor);
1255 SetBkColor(hdc, RGB(0,0,0));
1256 SetTextColor(hdc, RGB(255,255,255));
1257 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1258 hdcMask, 0, 0, SRCAND);
1260 SelectObject(hdc, hOldbitmap);
1261 SelectObject(hdcMask, hOldbitmapmask);
1264 DeleteObject(hTempMask);
1268 This->desc.picType = PICTYPE_BITMAP;
1269 OLEPictureImpl_SetBitmap(This);
1271 HeapFree(GetProcessHeap(),0,bmi);
1272 HeapFree(GetProcessHeap(),0,bytes);
1276 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1278 #ifdef SONAME_LIBJPEG
1279 struct jpeg_decompress_struct jd;
1280 struct jpeg_error_mgr jerr;
1283 JSAMPROW samprow,oldsamprow;
1284 BITMAPINFOHEADER bmi;
1287 struct jpeg_source_mgr xjsm;
1291 if(!libjpeg_handle) {
1292 if(!load_libjpeg()) {
1293 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1298 /* This is basically so we can use in-memory data for jpeg decompression.
1299 * We need to have all the functions.
1301 xjsm.next_input_byte = xbuf;
1302 xjsm.bytes_in_buffer = xread;
1303 xjsm.init_source = _jpeg_init_source;
1304 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1305 xjsm.skip_input_data = _jpeg_skip_input_data;
1306 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1307 xjsm.term_source = _jpeg_term_source;
1309 jd.err = pjpeg_std_error(&jerr);
1310 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1311 * jpeg_create_decompress(&jd); */
1312 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1314 ret=pjpeg_read_header(&jd,TRUE);
1315 jd.out_color_space = JCS_RGB;
1316 pjpeg_start_decompress(&jd);
1317 if (ret != JPEG_HEADER_OK) {
1318 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1319 HeapFree(GetProcessHeap(),0,xbuf);
1323 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1324 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1325 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1328 oldsamprow = samprow;
1329 while ( jd.output_scanline<jd.output_height ) {
1330 x = pjpeg_read_scanlines(&jd,&samprow,1);
1332 ERR("failed to read current scanline?\n");
1335 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1336 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1337 *(bits++) = *(samprow+2);
1338 *(bits++) = *(samprow+1);
1339 *(bits++) = *(samprow);
1341 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1342 samprow = oldsamprow;
1346 bmi.biSize = sizeof(bmi);
1347 bmi.biWidth = jd.output_width;
1348 bmi.biHeight = -jd.output_height;
1350 bmi.biBitCount = jd.output_components<<3;
1351 bmi.biCompression = BI_RGB;
1352 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1353 bmi.biXPelsPerMeter = 0;
1354 bmi.biYPelsPerMeter = 0;
1356 bmi.biClrImportant = 0;
1358 HeapFree(GetProcessHeap(),0,samprow);
1359 pjpeg_finish_decompress(&jd);
1360 pjpeg_destroy_decompress(&jd);
1362 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1371 This->desc.picType = PICTYPE_BITMAP;
1372 OLEPictureImpl_SetBitmap(This);
1373 HeapFree(GetProcessHeap(),0,bits);
1376 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1381 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1383 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1384 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1387 /* Does not matter whether this is a coreheader or not, we only use
1388 * components which are in both
1391 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1395 xbuf+bfh->bfOffBits,
1400 if (This->desc.u.bmp.hbitmap == 0)
1402 This->desc.picType = PICTYPE_BITMAP;
1403 OLEPictureImpl_SetBitmap(This);
1407 /*****************************************************
1408 * start of PNG-specific code
1409 * currently only supports colortype PNG_COLOR_TYPE_RGB
1411 #ifdef SONAME_LIBPNG
1418 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1421 png_io * io_ptr = png_ptr->io_ptr;
1423 if(length + io_ptr->position > io_ptr->size){
1424 length = io_ptr->size - io_ptr->position;
1427 memcpy(data, io_ptr->buff + io_ptr->position, length);
1429 io_ptr->position += length;
1432 static void *libpng_handle;
1433 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1434 MAKE_FUNCPTR(png_create_read_struct);
1435 MAKE_FUNCPTR(png_create_info_struct);
1436 MAKE_FUNCPTR(png_set_read_fn);
1437 MAKE_FUNCPTR(png_read_info);
1438 MAKE_FUNCPTR(png_read_image);
1439 MAKE_FUNCPTR(png_get_rowbytes);
1440 MAKE_FUNCPTR(png_set_bgr);
1441 MAKE_FUNCPTR(png_destroy_read_struct);
1442 MAKE_FUNCPTR(png_set_palette_to_rgb);
1443 MAKE_FUNCPTR(png_read_update_info);
1444 MAKE_FUNCPTR(png_get_tRNS);
1445 MAKE_FUNCPTR(png_get_PLTE);
1446 MAKE_FUNCPTR(png_set_expand);
1449 static void *load_libpng(void)
1451 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1453 #define LOAD_FUNCPTR(f) \
1454 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1455 libpng_handle = NULL; \
1458 LOAD_FUNCPTR(png_create_read_struct);
1459 LOAD_FUNCPTR(png_create_info_struct);
1460 LOAD_FUNCPTR(png_set_read_fn);
1461 LOAD_FUNCPTR(png_read_info);
1462 LOAD_FUNCPTR(png_read_image);
1463 LOAD_FUNCPTR(png_get_rowbytes);
1464 LOAD_FUNCPTR(png_set_bgr);
1465 LOAD_FUNCPTR(png_destroy_read_struct);
1466 LOAD_FUNCPTR(png_set_palette_to_rgb);
1467 LOAD_FUNCPTR(png_read_update_info);
1468 LOAD_FUNCPTR(png_get_tRNS);
1469 LOAD_FUNCPTR(png_get_PLTE);
1470 LOAD_FUNCPTR(png_set_expand);
1474 return libpng_handle;
1476 #endif /* SONAME_LIBPNG */
1478 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1480 #ifdef SONAME_LIBPNG
1482 png_structp png_ptr = NULL;
1483 png_infop info_ptr = NULL;
1484 INT row, rowsize, height, width, num_trans, i, j;
1485 png_bytep* row_pointers = NULL;
1486 png_bytep pngdata = NULL;
1487 BITMAPINFOHEADER bmi;
1488 HDC hdcref = NULL, hdcXor, hdcMask;
1492 png_color_16p trans_values;
1493 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1494 HBITMAP hbmoldXor, hbmoldMask, temp;
1496 if(!libpng_handle) {
1497 if(!load_libpng()) {
1498 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1507 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1510 if(setjmp(png_jmpbuf(png_ptr))){
1511 TRACE("Error in libpng\n");
1516 info_ptr = ppng_create_info_struct(png_ptr);
1517 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1518 ppng_read_info(png_ptr, info_ptr);
1520 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1521 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1522 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1523 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1528 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1531 /* sets format from anything to RGBA */
1532 ppng_set_expand(png_ptr);
1533 /* sets format to BGRA */
1534 ppng_set_bgr(png_ptr);
1536 ppng_read_update_info(png_ptr, info_ptr);
1538 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1539 /* align rowsize to 4-byte boundary */
1540 rowsize = (rowsize + 3) & ~3;
1541 height = info_ptr->height;
1542 width = info_ptr->width;
1544 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1545 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1547 if(!pngdata || !row_pointers){
1552 for (row = 0; row < height; row++){
1553 row_pointers[row] = pngdata + row * rowsize;
1556 ppng_read_image(png_ptr, row_pointers);
1558 bmi.biSize = sizeof(bmi);
1559 bmi.biWidth = width;
1560 bmi.biHeight = -height;
1562 bmi.biBitCount = info_ptr->channels * 8;
1563 bmi.biCompression = BI_RGB;
1564 bmi.biSizeImage = height * rowsize;
1565 bmi.biXPelsPerMeter = 0;
1566 bmi.biYPelsPerMeter = 0;
1568 bmi.biClrImportant = 0;
1571 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1580 /* only fully-transparent alpha is handled */
1581 if((info_ptr->channels != 4) || !transparency){
1582 ReleaseDC(0, hdcref);
1586 This->hbmXor = CreateDIBitmap(
1595 /* set transparent pixels to black, all others to white */
1596 for(i = 0; i < height; i++){
1597 for(j = 3; j < rowsize; j += 4){
1598 if(row_pointers[i][j] == 0)
1599 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1601 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1605 temp = CreateDIBitmap(
1614 ReleaseDC(0, hdcref);
1616 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1617 hdcXor = CreateCompatibleDC(NULL);
1618 hdcMask = CreateCompatibleDC(NULL);
1620 hbmoldXor = SelectObject(hdcXor,temp);
1621 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1622 SetBkColor(hdcXor,black);
1623 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1625 SelectObject(hdcXor,This->hbmXor);
1628 SetTextColor(hdcXor,white);
1629 SetBkColor(hdcXor,black);
1630 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1632 SelectObject(hdcXor,hbmoldXor);
1633 SelectObject(hdcMask,hbmoldMask);
1639 This->desc.picType = PICTYPE_BITMAP;
1640 OLEPictureImpl_SetBitmap(This);
1645 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1646 HeapFree(GetProcessHeap(), 0, row_pointers);
1647 HeapFree(GetProcessHeap(), 0, pngdata);
1649 #else /* SONAME_LIBPNG */
1650 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1655 /*****************************************************
1656 * start of Icon-specific code
1659 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1662 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1667 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1668 FIXME("icon.idType=%d\n",cifd->idType);
1669 FIXME("icon.idCount=%d\n",cifd->idCount);
1671 for (i=0;i<cifd->idCount;i++) {
1672 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1673 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1674 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1675 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1676 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1677 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1678 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1679 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1683 /* If we have more than one icon, try to find the best.
1684 * this currently means '32 pixel wide'.
1686 if (cifd->idCount!=1) {
1687 for (i=0;i<cifd->idCount;i++) {
1688 if (cifd->idEntries[i].bWidth == 32)
1691 if (i==cifd->idCount) i=0;
1694 hicon = CreateIconFromResourceEx(
1695 xbuf+cifd->idEntries[i].dwDIBOffset,
1696 cifd->idEntries[i].dwDIBSize,
1699 cifd->idEntries[i].bWidth,
1700 cifd->idEntries[i].bHeight,
1704 ERR("CreateIcon failed.\n");
1707 This->desc.picType = PICTYPE_ICON;
1708 This->desc.u.icon.hicon = hicon;
1709 This->origWidth = cifd->idEntries[i].bWidth;
1710 This->origHeight = cifd->idEntries[i].bHeight;
1711 hdcRef = CreateCompatibleDC(0);
1712 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1713 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1719 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1720 const BYTE *data, ULONG size)
1725 hemf = SetEnhMetaFileBits(size, data);
1726 if (!hemf) return E_FAIL;
1728 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1730 This->desc.picType = PICTYPE_ENHMETAFILE;
1731 This->desc.u.emf.hemf = hemf;
1733 This->origWidth = 0;
1734 This->origHeight = 0;
1735 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1736 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1741 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1742 const BYTE *data, ULONG size)
1744 APM_HEADER *header = (APM_HEADER *)data;
1747 if (size < sizeof(APM_HEADER))
1749 if (header->key != 0x9ac6cdd7)
1752 /* SetMetaFileBitsEx performs data check on its own */
1753 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1754 if (!hmf) return E_FAIL;
1756 This->desc.picType = PICTYPE_METAFILE;
1757 This->desc.u.wmf.hmeta = hmf;
1758 This->desc.u.wmf.xExt = 0;
1759 This->desc.u.wmf.yExt = 0;
1761 This->origWidth = 0;
1762 This->origHeight = 0;
1763 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1764 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1768 /************************************************************************
1769 * BITMAP FORMAT FLAGS -
1770 * Flags that differentiate between different types of bitmaps.
1773 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1774 #define BITMAP_FORMAT_JPEG 0xd8ff
1775 #define BITMAP_FORMAT_GIF 0x4947
1776 #define BITMAP_FORMAT_PNG 0x5089
1777 #define BITMAP_FORMAT_APM 0xcdd7
1779 /************************************************************************
1780 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1782 * Loads the binary data from the IStream. Starts at current position.
1783 * There appears to be an 2 DWORD header:
1787 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1789 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1790 HRESULT hr = E_FAIL;
1791 BOOL headerisdata = FALSE;
1792 BOOL statfailed = FALSE;
1793 ULONG xread, toread;
1799 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1801 TRACE("(%p,%p)\n",This,pStm);
1803 /****************************************************************************************
1804 * Part 1: Load the data
1806 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1807 * out whether we do.
1809 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1810 * compound file. This may explain most, if not all, of the cases of "no
1811 * header", and the header validation should take this into account.
1812 * At least in Visual Basic 6, resource streams, valid headers are
1813 * header[0] == "lt\0\0",
1814 * header[1] == length_of_stream.
1816 * Also handle streams where we do not have a working "Stat" method by
1817 * reading all data until the end of the stream.
1819 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1821 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1823 /* we will read at least 8 byte ... just right below */
1824 statstg.cbSize.QuadPart = 8;
1829 headerisdata = FALSE;
1831 hr=IStream_Read(pStm,header,8,&xread);
1832 if (hr || xread!=8) {
1833 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1834 return (hr?hr:E_FAIL);
1836 headerread += xread;
1839 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1840 if (toread != 0 && toread != header[1])
1841 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1844 if (toread == 0) break;
1846 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1847 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1848 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1849 (header[0] == EMR_HEADER) || /* EMF header */
1850 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1852 ) {/* Found start of bitmap data */
1853 headerisdata = TRUE;
1855 toread = statstg.cbSize.QuadPart-8;
1859 FIXME("Unknown stream header magic: %08x\n", header[0]);
1863 } while (!headerisdata);
1865 if (statfailed) { /* we don't know the size ... read all we get */
1867 int origsize = sizeinc;
1870 TRACE("Reading all data from stream.\n");
1871 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1873 memcpy (xbuf, header, 8);
1875 while (xread < origsize) {
1876 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1881 if (!nread || hr) /* done, or error */
1883 if (xread == origsize) {
1884 origsize += sizeinc;
1885 sizeinc = 2*sizeinc; /* exponential increase */
1886 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1890 TRACE("hr in no-stat loader case is %08x\n", hr);
1891 TRACE("loaded %d bytes.\n", xread);
1892 This->datalen = xread;
1895 This->datalen = toread+(headerisdata?8:0);
1896 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1898 return E_OUTOFMEMORY;
1901 memcpy (xbuf, header, 8);
1903 while (xread < This->datalen) {
1905 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1910 if (xread != This->datalen)
1911 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1913 if (This->datalen == 0) { /* Marks the "NONE" picture */
1914 This->desc.picType = PICTYPE_NONE;
1919 /****************************************************************************************
1920 * Part 2: Process the loaded data
1923 magic = xbuf[0] + (xbuf[1]<<8);
1924 This->loadtime_format = magic;
1927 case BITMAP_FORMAT_GIF: /* GIF */
1928 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1930 case BITMAP_FORMAT_JPEG: /* JPEG */
1931 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1933 case BITMAP_FORMAT_BMP: /* Bitmap */
1934 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1936 case BITMAP_FORMAT_PNG: /* PNG */
1937 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1939 case BITMAP_FORMAT_APM: /* APM */
1940 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1942 case 0x0000: { /* ICON , first word is dwReserved */
1943 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1950 /* let's see if it's a EMF */
1951 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1952 if (hr == S_OK) break;
1954 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1956 for (i=0;i<xread+8;i++) {
1957 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1958 else MESSAGE("%02x ",xbuf[i-8]);
1959 if (i % 10 == 9) MESSAGE("\n");
1965 This->bIsDirty = FALSE;
1967 /* FIXME: this notify is not really documented */
1969 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1973 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1977 BITMAPINFO * pInfoBitmap;
1978 int iNumPaletteEntries;
1979 unsigned char * pPixelData;
1980 BITMAPFILEHEADER * pFileHeader;
1981 BITMAPINFO * pInfoHeader;
1983 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1984 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1986 /* Find out bitmap size and padded length */
1988 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1989 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1991 /* Fetch bitmap palette & pixel data */
1993 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1994 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1996 /* Calculate the total length required for the BMP data */
1997 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1998 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1999 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
2001 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
2002 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
2004 iNumPaletteEntries = 0;
2007 sizeof(BITMAPFILEHEADER) +
2008 sizeof(BITMAPINFOHEADER) +
2009 iNumPaletteEntries * sizeof(RGBQUAD) +
2010 pInfoBitmap->bmiHeader.biSizeImage;
2011 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2013 /* Fill the BITMAPFILEHEADER */
2014 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
2015 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2016 pFileHeader->bfSize = *pLength;
2017 pFileHeader->bfOffBits =
2018 sizeof(BITMAPFILEHEADER) +
2019 sizeof(BITMAPINFOHEADER) +
2020 iNumPaletteEntries * sizeof(RGBQUAD);
2022 /* Fill the BITMAPINFOHEADER and the palette data */
2023 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2024 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2026 (unsigned char *)(*ppBuffer) +
2027 sizeof(BITMAPFILEHEADER) +
2028 sizeof(BITMAPINFOHEADER) +
2029 iNumPaletteEntries * sizeof(RGBQUAD),
2030 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2033 HeapFree(GetProcessHeap(), 0, pPixelData);
2034 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2038 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2043 *ppBuffer = NULL; *pLength = 0;
2044 if (GetIconInfo(hIcon, &infoIcon)) {
2046 BITMAPINFO * pInfoBitmap;
2047 unsigned char * pIconData = NULL;
2048 unsigned int iDataSize = 0;
2050 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2052 /* Find out icon size */
2054 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2055 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2057 /* Auxiliary pointers */
2058 CURSORICONFILEDIR * pIconDir;
2059 CURSORICONFILEDIRENTRY * pIconEntry;
2060 BITMAPINFOHEADER * pIconBitmapHeader;
2061 unsigned int iOffsetPalette;
2062 unsigned int iOffsetColorData;
2063 unsigned int iOffsetMaskData;
2065 unsigned int iLengthScanLineColor;
2066 unsigned int iLengthScanLineMask;
2067 unsigned int iNumEntriesPalette;
2069 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2070 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2072 FIXME("DEBUG: bitmap size is %d x %d\n",
2073 pInfoBitmap->bmiHeader.biWidth,
2074 pInfoBitmap->bmiHeader.biHeight);
2075 FIXME("DEBUG: bitmap bpp is %d\n",
2076 pInfoBitmap->bmiHeader.biBitCount);
2077 FIXME("DEBUG: bitmap nplanes is %d\n",
2078 pInfoBitmap->bmiHeader.biPlanes);
2079 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2080 pInfoBitmap->bmiHeader.biSizeImage);
2082 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2083 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2084 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2086 /* Fill out the CURSORICONFILEDIR */
2087 pIconDir = (CURSORICONFILEDIR *)pIconData;
2088 pIconDir->idType = 1;
2089 pIconDir->idCount = 1;
2091 /* Fill out the CURSORICONFILEDIRENTRY */
2092 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2093 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2094 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2095 pIconEntry->bColorCount =
2096 (pInfoBitmap->bmiHeader.biBitCount < 8)
2097 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2099 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2100 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2101 pIconEntry->dwDIBSize = 0;
2102 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2104 /* Fill out the BITMAPINFOHEADER */
2105 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2106 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2108 /* Find out whether a palette exists for the bitmap */
2109 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2110 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2111 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2112 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2113 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2114 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2115 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2116 iNumEntriesPalette = 3;
2117 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2118 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2120 iNumEntriesPalette = 0;
2123 /* Add bitmap size and header size to icon data size. */
2124 iOffsetPalette = iDataSize;
2125 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2126 iOffsetColorData = iDataSize;
2127 iDataSize += pIconBitmapHeader->biSizeImage;
2128 iOffsetMaskData = iDataSize;
2129 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2130 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2131 pIconBitmapHeader->biHeight *= 2;
2132 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2133 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2134 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2135 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2137 /* Get the actual bitmap data from the icon bitmap */
2138 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2139 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2140 if (iNumEntriesPalette > 0) {
2141 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2142 iNumEntriesPalette * sizeof(RGBQUAD));
2145 /* Reset all values so that GetDIBits call succeeds */
2146 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2147 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2148 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2150 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2151 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2152 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2154 printf("ERROR: unable to get bitmap mask (error %u)\n",
2159 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2160 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2162 /* Write out everything produced so far to the stream */
2163 *ppBuffer = pIconData; *pLength = iDataSize;
2167 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2172 Remarks (from MSDN entry on GetIconInfo):
2174 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2175 members of ICONINFO. The calling application must manage
2176 these bitmaps and delete them when they are no longer
2179 if (hDC) ReleaseDC(0, hDC);
2180 DeleteObject(infoIcon.hbmMask);
2181 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2182 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2184 printf("ERROR: Unable to get icon information (error %u)\n",
2190 static HRESULT WINAPI OLEPictureImpl_Save(
2191 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2193 HRESULT hResult = E_NOTIMPL;
2195 unsigned int iDataSize;
2197 int iSerializeResult = 0;
2198 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2200 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2202 switch (This->desc.picType) {
2204 if (This->bIsDirty || !This->data) {
2205 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2206 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2210 HeapFree(GetProcessHeap(), 0, This->data);
2211 This->data = pIconData;
2212 This->datalen = iDataSize;
2214 if (This->loadtime_magic != 0xdeadbeef) {
2217 header[0] = This->loadtime_magic;
2218 header[1] = This->datalen;
2219 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2221 IStream_Write(pStm, This->data, This->datalen, &dummy);
2225 case PICTYPE_BITMAP:
2226 if (This->bIsDirty) {
2227 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2228 case BITMAP_FORMAT_BMP:
2229 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2231 case BITMAP_FORMAT_JPEG:
2232 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2234 case BITMAP_FORMAT_GIF:
2235 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2237 case BITMAP_FORMAT_PNG:
2238 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2241 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2244 if (iSerializeResult) {
2246 if (This->loadtime_magic != 0xdeadbeef) {
2251 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2252 header[1] = iDataSize;
2253 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2255 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2257 HeapFree(GetProcessHeap(), 0, This->data);
2258 This->data = pIconData;
2259 This->datalen = iDataSize;
2264 if (This->loadtime_magic != 0xdeadbeef) {
2269 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2270 header[1] = This->datalen;
2271 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2273 IStream_Write(pStm, This->data, This->datalen, &dummy);
2277 case PICTYPE_METAFILE:
2278 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2280 case PICTYPE_ENHMETAFILE:
2281 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2284 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2287 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2291 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2292 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2294 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2295 FIXME("(%p,%p),stub!\n",This,pcbSize);
2300 /************************************************************************
2304 /************************************************************************
2305 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2307 * See Windows documentation for more details on IUnknown methods.
2309 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2314 OLEPictureImpl *This = impl_from_IDispatch(iface);
2316 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2319 /************************************************************************
2320 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2322 * See Windows documentation for more details on IUnknown methods.
2324 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2327 OLEPictureImpl *This = impl_from_IDispatch(iface);
2329 return IPicture_AddRef((IPicture *)This);
2332 /************************************************************************
2333 * OLEPictureImpl_IDispatch_Release (IUnknown)
2335 * See Windows documentation for more details on IUnknown methods.
2337 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2340 OLEPictureImpl *This = impl_from_IDispatch(iface);
2342 return IPicture_Release((IPicture *)This);
2345 /************************************************************************
2346 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2348 * See Windows documentation for more details on IDispatch methods.
2350 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2352 unsigned int* pctinfo)
2354 TRACE("(%p)\n", pctinfo);
2361 /************************************************************************
2362 * OLEPictureImpl_GetTypeInfo (IDispatch)
2364 * See Windows documentation for more details on IDispatch methods.
2366 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2370 ITypeInfo** ppTInfo)
2372 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2376 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2381 hres = LoadTypeLib(stdole2tlb, &tl);
2384 ERR("Could not load stdole2.tlb\n");
2388 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2390 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2395 /************************************************************************
2396 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2398 * See Windows documentation for more details on IDispatch methods.
2400 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2403 LPOLESTR* rgszNames,
2411 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2412 rgszNames, cNames, (int)lcid, rgDispId);
2416 return E_INVALIDARG;
2420 /* retrieve type information */
2421 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2425 ERR("GetTypeInfo failed.\n");
2429 /* convert names to DISPIDs */
2430 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2431 ITypeInfo_Release(pTInfo);
2437 /************************************************************************
2438 * OLEPictureImpl_Invoke (IDispatch)
2440 * See Windows documentation for more details on IDispatch methods.
2442 static HRESULT WINAPI OLEPictureImpl_Invoke(
2444 DISPID dispIdMember,
2448 DISPPARAMS* pDispParams,
2449 VARIANT* pVarResult,
2450 EXCEPINFO* pExepInfo,
2453 OLEPictureImpl *This = impl_from_IDispatch(iface);
2455 /* validate parameters */
2457 if (!IsEqualIID(riid, &IID_NULL))
2459 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2460 return DISP_E_UNKNOWNNAME;
2465 ERR("null pDispParams not allowed\n");
2466 return DISP_E_PARAMNOTOPTIONAL;
2469 if (wFlags & DISPATCH_PROPERTYGET)
2471 if (pDispParams->cArgs != 0)
2473 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2474 return DISP_E_BADPARAMCOUNT;
2478 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2479 return DISP_E_PARAMNOTOPTIONAL;
2482 else if (wFlags & DISPATCH_PROPERTYPUT)
2484 if (pDispParams->cArgs != 1)
2486 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2487 return DISP_E_BADPARAMCOUNT;
2491 switch (dispIdMember)
2493 case DISPID_PICT_HANDLE:
2494 if (wFlags & DISPATCH_PROPERTYGET)
2496 TRACE("DISPID_PICT_HANDLE\n");
2497 V_VT(pVarResult) = VT_I4;
2498 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2501 case DISPID_PICT_HPAL:
2502 if (wFlags & DISPATCH_PROPERTYGET)
2504 TRACE("DISPID_PICT_HPAL\n");
2505 V_VT(pVarResult) = VT_I4;
2506 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2508 else if (wFlags & DISPATCH_PROPERTYPUT)
2512 TRACE("DISPID_PICT_HPAL\n");
2514 VariantInit(&vararg);
2515 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2519 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2521 VariantClear(&vararg);
2525 case DISPID_PICT_TYPE:
2526 if (wFlags & DISPATCH_PROPERTYGET)
2528 TRACE("DISPID_PICT_TYPE\n");
2529 V_VT(pVarResult) = VT_I2;
2530 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2533 case DISPID_PICT_WIDTH:
2534 if (wFlags & DISPATCH_PROPERTYGET)
2536 TRACE("DISPID_PICT_WIDTH\n");
2537 V_VT(pVarResult) = VT_I4;
2538 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2541 case DISPID_PICT_HEIGHT:
2542 if (wFlags & DISPATCH_PROPERTYGET)
2544 TRACE("DISPID_PICT_HEIGHT\n");
2545 V_VT(pVarResult) = VT_I4;
2546 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2551 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2552 return DISP_E_MEMBERNOTFOUND;
2556 static const IPictureVtbl OLEPictureImpl_VTable =
2558 OLEPictureImpl_QueryInterface,
2559 OLEPictureImpl_AddRef,
2560 OLEPictureImpl_Release,
2561 OLEPictureImpl_get_Handle,
2562 OLEPictureImpl_get_hPal,
2563 OLEPictureImpl_get_Type,
2564 OLEPictureImpl_get_Width,
2565 OLEPictureImpl_get_Height,
2566 OLEPictureImpl_Render,
2567 OLEPictureImpl_set_hPal,
2568 OLEPictureImpl_get_CurDC,
2569 OLEPictureImpl_SelectPicture,
2570 OLEPictureImpl_get_KeepOriginalFormat,
2571 OLEPictureImpl_put_KeepOriginalFormat,
2572 OLEPictureImpl_PictureChanged,
2573 OLEPictureImpl_SaveAsFile,
2574 OLEPictureImpl_get_Attributes
2577 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2579 OLEPictureImpl_IDispatch_QueryInterface,
2580 OLEPictureImpl_IDispatch_AddRef,
2581 OLEPictureImpl_IDispatch_Release,
2582 OLEPictureImpl_GetTypeInfoCount,
2583 OLEPictureImpl_GetTypeInfo,
2584 OLEPictureImpl_GetIDsOfNames,
2585 OLEPictureImpl_Invoke
2588 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2590 OLEPictureImpl_IPersistStream_QueryInterface,
2591 OLEPictureImpl_IPersistStream_AddRef,
2592 OLEPictureImpl_IPersistStream_Release,
2593 OLEPictureImpl_GetClassID,
2594 OLEPictureImpl_IsDirty,
2595 OLEPictureImpl_Load,
2596 OLEPictureImpl_Save,
2597 OLEPictureImpl_GetSizeMax
2600 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2602 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2603 OLEPictureImpl_IConnectionPointContainer_AddRef,
2604 OLEPictureImpl_IConnectionPointContainer_Release,
2605 OLEPictureImpl_EnumConnectionPoints,
2606 OLEPictureImpl_FindConnectionPoint
2609 /***********************************************************************
2610 * OleCreatePictureIndirect (OLEAUT32.419)
2612 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2613 BOOL fOwn, LPVOID *ppvObj )
2615 OLEPictureImpl* newPict = NULL;
2618 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2629 * Try to construct a new instance of the class.
2631 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2633 if (newPict == NULL)
2634 return E_OUTOFMEMORY;
2637 * Make sure it supports the interface required by the caller.
2639 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2642 * Release the reference obtained in the constructor. If
2643 * the QueryInterface was unsuccessful, it will free the class.
2645 IPicture_Release((IPicture*)newPict);
2651 /***********************************************************************
2652 * OleLoadPicture (OLEAUT32.418)
2654 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2655 REFIID riid, LPVOID *ppvObj )
2661 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2662 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2664 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2667 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2669 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2670 IPicture_Release(newpic);
2674 hr = IPersistStream_Load(ps,lpstream);
2675 IPersistStream_Release(ps);
2678 ERR("IPersistStream_Load failed\n");
2679 IPicture_Release(newpic);
2683 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2685 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2686 IPicture_Release(newpic);
2690 /***********************************************************************
2691 * OleLoadPictureEx (OLEAUT32.401)
2693 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2694 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2700 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2701 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2703 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2706 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2708 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2709 IPicture_Release(newpic);
2713 hr = IPersistStream_Load(ps,lpstream);
2714 IPersistStream_Release(ps);
2717 ERR("IPersistStream_Load failed\n");
2718 IPicture_Release(newpic);
2722 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2724 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2725 IPicture_Release(newpic);
2729 /***********************************************************************
2730 * OleLoadPicturePath (OLEAUT32.424)
2732 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2733 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2736 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2740 HGLOBAL hGlobal = NULL;
2741 DWORD dwBytesRead = 0;
2744 IPersistStream *pStream;
2747 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2748 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2749 debugstr_guid(riid), ppvRet);
2751 if (!ppvRet) return E_POINTER;
2753 if (strncmpW(szURLorPath, file, 7) == 0) {
2756 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2758 if (hFile == INVALID_HANDLE_VALUE)
2759 return E_UNEXPECTED;
2761 dwFileSize = GetFileSize(hFile, NULL);
2762 if (dwFileSize != INVALID_FILE_SIZE )
2764 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2767 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2770 GlobalFree(hGlobal);
2778 return E_UNEXPECTED;
2780 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2783 GlobalFree(hGlobal);
2790 hRes = CreateBindCtx(0, &pbc);
2791 if (SUCCEEDED(hRes))
2793 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2794 if (SUCCEEDED(hRes))
2796 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2797 IMoniker_Release(pmnk);
2799 IBindCtx_Release(pbc);
2805 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2806 &IID_IPicture, (LPVOID*)&ipicture);
2808 IStream_Release(stream);
2812 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2814 IStream_Release(stream);
2815 IPicture_Release(ipicture);
2819 hRes = IPersistStream_Load(pStream, stream);
2820 IPersistStream_Release(pStream);
2821 IStream_Release(stream);
2824 IPicture_Release(ipicture);
2828 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2830 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2832 IPicture_Release(ipicture);
2836 /*******************************************************************************
2837 * StdPic ClassFactory
2841 /* IUnknown fields */
2842 const IClassFactoryVtbl *lpVtbl;
2844 } IClassFactoryImpl;
2846 static HRESULT WINAPI
2847 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2848 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2850 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2851 return E_NOINTERFACE;
2855 SPCF_AddRef(LPCLASSFACTORY iface) {
2856 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2857 return InterlockedIncrement(&This->ref);
2860 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2861 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2862 /* static class, won't be freed */
2863 return InterlockedDecrement(&This->ref);
2866 static HRESULT WINAPI SPCF_CreateInstance(
2867 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2869 /* Creates an uninitialized picture */
2870 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2874 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2875 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2876 FIXME("(%p)->(%d),stub!\n",This,dolock);
2880 static const IClassFactoryVtbl SPCF_Vtbl = {
2881 SPCF_QueryInterface,
2884 SPCF_CreateInstance,
2887 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2889 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }