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"
84 #include "wine/library.h"
88 WINE_DEFAULT_DEBUG_CHANNEL(ole);
92 /* Header for Aldus Placable Metafiles - a standard metafile follows */
93 typedef struct _APM_HEADER
115 } CURSORICONFILEDIRENTRY;
122 CURSORICONFILEDIRENTRY idEntries[1];
127 /*************************************************************************
128 * Declaration of implementation class
131 typedef struct OLEPictureImpl {
134 * IPicture handles IUnknown
137 const IPictureVtbl *lpVtbl;
138 const IDispatchVtbl *lpvtblIDispatch;
139 const IPersistStreamVtbl *lpvtblIPersistStream;
140 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
142 /* Object reference count */
145 /* We own the object and must destroy it ourselves */
148 /* Picture description */
151 /* These are the pixel size of a bitmap */
155 /* And these are the size of the picture converted into HIMETRIC units */
156 OLE_XSIZE_HIMETRIC himetricWidth;
157 OLE_YSIZE_HIMETRIC himetricHeight;
159 IConnectionPoint *pCP;
164 /* Bitmap transparency mask */
172 BOOL bIsDirty; /* Set to TRUE if picture has changed */
173 unsigned int loadtime_magic; /* If a length header was found, saves value */
174 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
178 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
181 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
183 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
186 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
188 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
191 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
193 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
197 * Predeclare VTables. They get initialized at the end.
199 static const IPictureVtbl OLEPictureImpl_VTable;
200 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
201 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
202 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
204 /***********************************************************************
205 * Implementation of the OLEPictureImpl class.
208 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
212 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
213 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
214 ERR("GetObject fails\n");
217 This->origWidth = bm.bmWidth;
218 This->origHeight = bm.bmHeight;
219 /* The width and height are stored in HIMETRIC units (0.01 mm),
220 so we take our pixel width divide by pixels per inch and
221 multiply by 25.4 * 100 */
222 /* Should we use GetBitmapDimension if available? */
223 hdcRef = CreateCompatibleDC(0);
224 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
225 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
229 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
233 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
234 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
238 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
239 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
240 ERR("GetObject fails on icon bitmap\n");
244 This->origWidth = bm.bmWidth;
245 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
246 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
248 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
249 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
250 ReleaseDC(0, hdcRef);
252 DeleteObject(infoIcon.hbmMask);
253 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
255 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
259 /************************************************************************
260 * OLEPictureImpl_Construct
262 * This method will construct a new instance of the OLEPictureImpl
265 * The caller of this method must release the object when it's
268 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
270 OLEPictureImpl* newObject = 0;
273 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
276 * Allocate space for the object.
278 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
284 * Initialize the virtual function table.
286 newObject->lpVtbl = &OLEPictureImpl_VTable;
287 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
288 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
289 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
291 newObject->pCP = NULL;
292 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
295 HeapFree(GetProcessHeap(), 0, newObject);
300 * Start with one reference count. The caller of this function
301 * must release the interface pointer when it is done.
304 newObject->hDCCur = 0;
306 newObject->fOwn = fOwn;
308 /* dunno about original value */
309 newObject->keepOrigFormat = TRUE;
311 newObject->hbmMask = NULL;
312 newObject->hbmXor = NULL;
313 newObject->loadtime_magic = 0xdeadbeef;
314 newObject->loadtime_format = 0;
315 newObject->bIsDirty = FALSE;
318 newObject->desc = *pictDesc;
320 switch(pictDesc->picType) {
322 OLEPictureImpl_SetBitmap(newObject);
325 case PICTYPE_METAFILE:
326 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
327 newObject->himetricWidth = pictDesc->u.wmf.xExt;
328 newObject->himetricHeight = pictDesc->u.wmf.yExt;
332 /* not sure what to do here */
333 newObject->himetricWidth = newObject->himetricHeight = 0;
337 OLEPictureImpl_SetIcon(newObject);
339 case PICTYPE_ENHMETAFILE:
341 FIXME("Unsupported type %d\n", pictDesc->picType);
342 newObject->himetricWidth = newObject->himetricHeight = 0;
346 newObject->desc.picType = PICTYPE_UNINITIALIZED;
349 TRACE("returning %p\n", newObject);
353 /************************************************************************
354 * OLEPictureImpl_Destroy
356 * This method is called by the Release method when the reference
357 * count goes down to 0. It will free all resources used by
359 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
361 TRACE("(%p)\n", Obj);
364 IConnectionPoint_Release(Obj->pCP);
366 if(Obj->fOwn) { /* We need to destroy the picture */
367 switch(Obj->desc.picType) {
369 DeleteObject(Obj->desc.u.bmp.hbitmap);
370 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
371 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
373 case PICTYPE_METAFILE:
374 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
377 DestroyIcon(Obj->desc.u.icon.hicon);
379 case PICTYPE_ENHMETAFILE:
380 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
383 case PICTYPE_UNINITIALIZED:
387 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
391 HeapFree(GetProcessHeap(), 0, Obj->data);
392 HeapFree(GetProcessHeap(), 0, Obj);
396 /************************************************************************
397 * OLEPictureImpl_AddRef (IUnknown)
399 * See Windows documentation for more details on IUnknown methods.
401 static ULONG WINAPI OLEPictureImpl_AddRef(
404 OLEPictureImpl *This = (OLEPictureImpl *)iface;
405 ULONG refCount = InterlockedIncrement(&This->ref);
407 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
412 /************************************************************************
413 * OLEPictureImpl_Release (IUnknown)
415 * See Windows documentation for more details on IUnknown methods.
417 static ULONG WINAPI OLEPictureImpl_Release(
420 OLEPictureImpl *This = (OLEPictureImpl *)iface;
421 ULONG refCount = InterlockedDecrement(&This->ref);
423 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
426 * If the reference count goes down to 0, perform suicide.
428 if (!refCount) OLEPictureImpl_Destroy(This);
433 /************************************************************************
434 * OLEPictureImpl_QueryInterface (IUnknown)
436 * See Windows documentation for more details on IUnknown methods.
438 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
443 OLEPictureImpl *This = (OLEPictureImpl *)iface;
444 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
447 * Perform a sanity check on the parameters.
449 if ( (This==0) || (ppvObject==0) )
453 * Initialize the return parameter.
458 * Compare the riid with the interface IDs implemented by this object.
460 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462 else if (IsEqualIID(&IID_IDispatch, riid))
463 *ppvObject = &This->lpvtblIDispatch;
464 else if (IsEqualIID(&IID_IPictureDisp, riid))
465 *ppvObject = &This->lpvtblIDispatch;
466 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
467 *ppvObject = &This->lpvtblIPersistStream;
468 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
469 *ppvObject = &This->lpvtblIConnectionPointContainer;
472 * Check that we obtained an interface.
476 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
477 return E_NOINTERFACE;
481 * Query Interface always increases the reference count by one when it is
484 OLEPictureImpl_AddRef((IPicture*)This);
489 /***********************************************************************
490 * OLEPicture_SendNotify (internal)
492 * Sends notification messages of changed properties to any interested
495 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
497 IEnumConnections *pEnum;
500 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
502 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
503 IPropertyNotifySink *sink;
505 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
506 IPropertyNotifySink_OnChanged(sink, dispID);
507 IPropertyNotifySink_Release(sink);
508 IUnknown_Release(CD.pUnk);
510 IEnumConnections_Release(pEnum);
513 /************************************************************************
514 * OLEPictureImpl_get_Handle
516 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
519 OLEPictureImpl *This = (OLEPictureImpl *)iface;
520 TRACE("(%p)->(%p)\n", This, phandle);
525 switch(This->desc.picType) {
527 case PICTYPE_UNINITIALIZED:
531 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
533 case PICTYPE_METAFILE:
534 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
537 *phandle = HandleToUlong(This->desc.u.icon.hicon);
539 case PICTYPE_ENHMETAFILE:
540 *phandle = HandleToUlong(This->desc.u.emf.hemf);
543 FIXME("Unimplemented type %d\n", This->desc.picType);
546 TRACE("returning handle %08x\n", *phandle);
550 /************************************************************************
551 * OLEPictureImpl_get_hPal
553 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
556 OLEPictureImpl *This = (OLEPictureImpl *)iface;
558 TRACE("(%p)->(%p)\n", This, phandle);
563 switch (This->desc.picType) {
564 case (UINT)PICTYPE_UNINITIALIZED:
570 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
573 case PICTYPE_METAFILE:
577 case PICTYPE_ENHMETAFILE:
579 FIXME("unimplemented for type %d. Returning 0 palette.\n",
585 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
589 /************************************************************************
590 * OLEPictureImpl_get_Type
592 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
595 OLEPictureImpl *This = (OLEPictureImpl *)iface;
596 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
601 *ptype = This->desc.picType;
605 /************************************************************************
606 * OLEPictureImpl_get_Width
608 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
609 OLE_XSIZE_HIMETRIC *pwidth)
611 OLEPictureImpl *This = (OLEPictureImpl *)iface;
612 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
613 *pwidth = This->himetricWidth;
617 /************************************************************************
618 * OLEPictureImpl_get_Height
620 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
621 OLE_YSIZE_HIMETRIC *pheight)
623 OLEPictureImpl *This = (OLEPictureImpl *)iface;
624 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
625 *pheight = This->himetricHeight;
629 /************************************************************************
630 * OLEPictureImpl_Render
632 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
633 LONG x, LONG y, LONG cx, LONG cy,
634 OLE_XPOS_HIMETRIC xSrc,
635 OLE_YPOS_HIMETRIC ySrc,
636 OLE_XSIZE_HIMETRIC cxSrc,
637 OLE_YSIZE_HIMETRIC cySrc,
640 OLEPictureImpl *This = (OLEPictureImpl *)iface;
641 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
642 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
644 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
645 prcWBounds->right, prcWBounds->bottom);
647 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
648 return CTL_E_INVALIDPROPERTYVALUE;
652 * While the documentation suggests this to be here (or after rendering?)
653 * it does cause an endless recursion in my sample app. -MM 20010804
654 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
657 switch(This->desc.picType) {
658 case PICTYPE_UNINITIALIZED:
667 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
668 NB y-axis gets flipped */
670 hdcBmp = CreateCompatibleDC(0);
671 SetMapMode(hdcBmp, MM_ANISOTROPIC);
672 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
673 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
674 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
675 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
678 HDC hdcMask = CreateCompatibleDC(0);
679 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
681 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
683 SetMapMode(hdcMask, MM_ANISOTROPIC);
684 SetWindowOrgEx(hdcMask, 0, 0, NULL);
685 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
686 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
687 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
689 SetBkColor(hdc, RGB(255, 255, 255));
690 SetTextColor(hdc, RGB(0, 0, 0));
691 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
692 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
694 SelectObject(hdcMask, hOldbm);
697 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
698 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
701 SelectObject(hdcBmp, hbmpOld);
706 FIXME("Not quite correct implementation of rendering icons...\n");
707 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
710 case PICTYPE_METAFILE:
712 POINT prevOrg, prevWndOrg;
713 SIZE prevExt, prevWndExt;
716 /* Render the WMF to the appropriate location by setting the
717 appropriate ratio between "device units" and "logical units" */
718 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
719 /* For the "source rectangle" the y-axis must be inverted */
720 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
721 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
722 /* For the "destination rectangle" no inversion is necessary */
723 SetViewportOrgEx(hdc, x, y, &prevOrg);
724 SetViewportExtEx(hdc, cx, cy, &prevExt);
726 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
727 ERR("PlayMetaFile failed!\n");
729 /* We're done, restore the DC to the previous settings for converting
730 logical units to device units */
731 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
732 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
733 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
734 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
735 SetMapMode(hdc, oldmode);
739 case PICTYPE_ENHMETAFILE:
741 RECT rc = { x, y, x + cx, y + cy };
742 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
747 FIXME("type %d not implemented\n", This->desc.picType);
753 /************************************************************************
754 * OLEPictureImpl_set_hPal
756 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
759 OLEPictureImpl *This = (OLEPictureImpl *)iface;
760 FIXME("(%p)->(%08x): stub\n", This, hpal);
761 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
765 /************************************************************************
766 * OLEPictureImpl_get_CurDC
768 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
771 OLEPictureImpl *This = (OLEPictureImpl *)iface;
772 TRACE("(%p), returning %p\n", This, This->hDCCur);
773 if (phdc) *phdc = This->hDCCur;
777 /************************************************************************
778 * OLEPictureImpl_SelectPicture
780 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
783 OLE_HANDLE *phbmpOut)
785 OLEPictureImpl *This = (OLEPictureImpl *)iface;
786 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
787 if (This->desc.picType == PICTYPE_BITMAP) {
788 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
791 *phdcOut = This->hDCCur;
792 This->hDCCur = hdcIn;
794 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
797 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
802 /************************************************************************
803 * OLEPictureImpl_get_KeepOriginalFormat
805 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
808 OLEPictureImpl *This = (OLEPictureImpl *)iface;
809 TRACE("(%p)->(%p)\n", This, pfKeep);
812 *pfKeep = This->keepOrigFormat;
816 /************************************************************************
817 * OLEPictureImpl_put_KeepOriginalFormat
819 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
822 OLEPictureImpl *This = (OLEPictureImpl *)iface;
823 TRACE("(%p)->(%d)\n", This, keep);
824 This->keepOrigFormat = keep;
825 /* FIXME: what DISPID notification here? */
829 /************************************************************************
830 * OLEPictureImpl_PictureChanged
832 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
834 OLEPictureImpl *This = (OLEPictureImpl *)iface;
835 TRACE("(%p)->()\n", This);
836 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
837 This->bIsDirty = TRUE;
841 /************************************************************************
842 * OLEPictureImpl_SaveAsFile
844 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
849 OLEPictureImpl *This = (OLEPictureImpl *)iface;
850 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
851 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
854 /************************************************************************
855 * OLEPictureImpl_get_Attributes
857 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
860 OLEPictureImpl *This = (OLEPictureImpl *)iface;
861 TRACE("(%p)->(%p).\n", This, pdwAttr);
867 switch (This->desc.picType) {
868 case PICTYPE_UNINITIALIZED:
869 case PICTYPE_NONE: break;
870 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
871 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
872 case PICTYPE_ENHMETAFILE: /* fall through */
873 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
874 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
880 /************************************************************************
881 * IConnectionPointContainer
883 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
884 IConnectionPointContainer* iface,
888 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
890 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
893 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
894 IConnectionPointContainer* iface)
896 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
898 return IPicture_AddRef((IPicture *)This);
901 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
902 IConnectionPointContainer* iface)
904 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
906 return IPicture_Release((IPicture *)This);
909 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
910 IConnectionPointContainer* iface,
911 IEnumConnectionPoints** ppEnum)
913 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
915 FIXME("(%p,%p), stub!\n",This,ppEnum);
919 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
920 IConnectionPointContainer* iface,
922 IConnectionPoint **ppCP)
924 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
925 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
929 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
930 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
931 FIXME("no connection point for %s\n",debugstr_guid(riid));
932 return CONNECT_E_NOCONNECTION;
936 /************************************************************************
940 /************************************************************************
941 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
943 * See Windows documentation for more details on IUnknown methods.
945 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
946 IPersistStream* iface,
950 OLEPictureImpl *This = impl_from_IPersistStream(iface);
952 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
955 /************************************************************************
956 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
958 * See Windows documentation for more details on IUnknown methods.
960 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
961 IPersistStream* iface)
963 OLEPictureImpl *This = impl_from_IPersistStream(iface);
965 return IPicture_AddRef((IPicture *)This);
968 /************************************************************************
969 * OLEPictureImpl_IPersistStream_Release (IUnknown)
971 * See Windows documentation for more details on IUnknown methods.
973 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
974 IPersistStream* iface)
976 OLEPictureImpl *This = impl_from_IPersistStream(iface);
978 return IPicture_Release((IPicture *)This);
981 /************************************************************************
982 * OLEPictureImpl_IPersistStream_GetClassID
984 static HRESULT WINAPI OLEPictureImpl_GetClassID(
985 IPersistStream* iface,CLSID* pClassID)
987 TRACE("(%p)\n", pClassID);
988 *pClassID = CLSID_StdPicture;
992 /************************************************************************
993 * OLEPictureImpl_IPersistStream_IsDirty
995 static HRESULT WINAPI OLEPictureImpl_IsDirty(
996 IPersistStream* iface)
998 OLEPictureImpl *This = impl_from_IPersistStream(iface);
999 FIXME("(%p),stub!\n",This);
1003 #ifdef SONAME_LIBJPEG
1005 static void *libjpeg_handle;
1006 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1007 MAKE_FUNCPTR(jpeg_std_error);
1008 MAKE_FUNCPTR(jpeg_CreateDecompress);
1009 MAKE_FUNCPTR(jpeg_read_header);
1010 MAKE_FUNCPTR(jpeg_start_decompress);
1011 MAKE_FUNCPTR(jpeg_read_scanlines);
1012 MAKE_FUNCPTR(jpeg_finish_decompress);
1013 MAKE_FUNCPTR(jpeg_destroy_decompress);
1016 static void *load_libjpeg(void)
1018 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1020 #define LOAD_FUNCPTR(f) \
1021 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1022 libjpeg_handle = NULL; \
1026 LOAD_FUNCPTR(jpeg_std_error);
1027 LOAD_FUNCPTR(jpeg_CreateDecompress);
1028 LOAD_FUNCPTR(jpeg_read_header);
1029 LOAD_FUNCPTR(jpeg_start_decompress);
1030 LOAD_FUNCPTR(jpeg_read_scanlines);
1031 LOAD_FUNCPTR(jpeg_finish_decompress);
1032 LOAD_FUNCPTR(jpeg_destroy_decompress);
1035 return libjpeg_handle;
1038 /* for the jpeg decompressor source manager. */
1039 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1041 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1042 ERR("(), should not get here.\n");
1046 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1047 TRACE("Skipping %ld bytes...\n", num_bytes);
1048 cinfo->src->next_input_byte += num_bytes;
1049 cinfo->src->bytes_in_buffer -= num_bytes;
1052 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1053 ERR("(desired=%d), should not get here.\n",desired);
1056 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1057 #endif /* SONAME_LIBJPEG */
1060 unsigned char *data;
1061 unsigned int curoff;
1065 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1066 struct gifdata *gd = gif->UserData;
1068 if (len+gd->curoff > gd->len) {
1069 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1070 len = gd->len - gd->curoff;
1072 memcpy(data, gd->data+gd->curoff, len);
1078 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1089 int transparent = -1;
1096 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1097 ret = DGifSlurp(gif);
1098 if (ret == GIF_ERROR) {
1099 ERR("Failed reading GIF using libgif.\n");
1102 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1103 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1104 TRACE("imgcnt %d\n", gif->ImageCount);
1105 if (gif->ImageCount<1) {
1106 ERR("GIF stream does not have images inside?\n");
1109 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1110 gif->Image.Width, gif->Image.Height,
1111 gif->Image.Left, gif->Image.Top,
1112 gif->Image.Interlace
1115 padding = (gif->SWidth+3) & ~3;
1116 si = gif->SavedImages+0;
1117 gid = &(si->ImageDesc);
1119 if (!cm) cm = gif->SColorMap;
1120 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1121 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1123 /* look for the transparent color extension */
1124 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1125 eb = si->ExtensionBlocks + i;
1126 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1127 if ((eb->Bytes[0] & 1) == 1) {
1128 transparent = (unsigned char)eb->Bytes[3];
1133 for (i = 0; i < cm->ColorCount; i++) {
1134 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1135 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1136 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1137 if (i == transparent) {
1138 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1139 bmi->bmiColors[i].rgbGreen,
1140 bmi->bmiColors[i].rgbBlue);
1144 /* Map to in picture coordinates */
1145 for (i = 0, j = 0; i < gid->Height; i++) {
1146 if (gif->Image.Interlace) {
1148 bytes + (gid->Top + j) * padding + gid->Left,
1149 si->RasterBits + i * gid->Width,
1152 /* Lower bits of interlaced counter encode current interlace */
1153 if (j & 1) j += 2; /* Currently filling odd rows */
1154 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1155 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1157 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1158 /* End of current interlace, go to next interlace */
1159 if (j & 2) j = 1; /* Next iteration fills odd rows */
1160 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1161 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1165 bytes + (gid->Top + i) * padding + gid->Left,
1166 si->RasterBits + i * gid->Width,
1171 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1172 bmi->bmiHeader.biWidth = gif->SWidth;
1173 bmi->bmiHeader.biHeight = -gif->SHeight;
1174 bmi->bmiHeader.biPlanes = 1;
1175 bmi->bmiHeader.biBitCount = 8;
1176 bmi->bmiHeader.biCompression = BI_RGB;
1177 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1178 bmi->bmiHeader.biXPelsPerMeter = 0;
1179 bmi->bmiHeader.biYPelsPerMeter = 0;
1180 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1181 bmi->bmiHeader.biClrImportant = 0;
1184 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1193 if (transparent > -1) {
1194 /* Create the Mask */
1195 HDC hdc = CreateCompatibleDC(0);
1196 HDC hdcMask = CreateCompatibleDC(0);
1198 HBITMAP hOldbitmapmask;
1200 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1203 This->hbmXor = CreateDIBitmap(
1212 bmi->bmiColors[0].rgbRed = 0;
1213 bmi->bmiColors[0].rgbGreen = 0;
1214 bmi->bmiColors[0].rgbBlue = 0;
1215 bmi->bmiColors[1].rgbRed = 255;
1216 bmi->bmiColors[1].rgbGreen = 255;
1217 bmi->bmiColors[1].rgbBlue = 255;
1219 bmi->bmiHeader.biBitCount = 1;
1220 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1221 bmi->bmiHeader.biClrUsed = 2;
1223 for (i = 0; i < gif->SHeight; i++) {
1224 unsigned char * colorPointer = bytes + padding * i;
1225 unsigned char * monoPointer = bytes + monopadding * i;
1226 for (j = 0; j < gif->SWidth; j++) {
1227 unsigned char pixel = colorPointer[j];
1228 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1229 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1233 hTempMask = CreateDIBitmap(
1243 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1244 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1245 hOldbitmap = SelectObject(hdc, hTempMask);
1246 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1248 SetBkColor(hdc, RGB(255, 255, 255));
1249 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1251 /* We no longer need the original bitmap, so we apply the first
1252 transformation with the mask to speed up the rendering */
1253 SelectObject(hdc, This->hbmXor);
1254 SetBkColor(hdc, RGB(0,0,0));
1255 SetTextColor(hdc, RGB(255,255,255));
1256 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1257 hdcMask, 0, 0, SRCAND);
1259 SelectObject(hdc, hOldbitmap);
1260 SelectObject(hdcMask, hOldbitmapmask);
1263 DeleteObject(hTempMask);
1267 This->desc.picType = PICTYPE_BITMAP;
1268 OLEPictureImpl_SetBitmap(This);
1270 HeapFree(GetProcessHeap(),0,bmi);
1271 HeapFree(GetProcessHeap(),0,bytes);
1275 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1277 #ifdef SONAME_LIBJPEG
1278 struct jpeg_decompress_struct jd;
1279 struct jpeg_error_mgr jerr;
1282 JSAMPROW samprow,oldsamprow;
1283 BITMAPINFOHEADER bmi;
1286 struct jpeg_source_mgr xjsm;
1290 if(!libjpeg_handle) {
1291 if(!load_libjpeg()) {
1292 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1297 /* This is basically so we can use in-memory data for jpeg decompression.
1298 * We need to have all the functions.
1300 xjsm.next_input_byte = xbuf;
1301 xjsm.bytes_in_buffer = xread;
1302 xjsm.init_source = _jpeg_init_source;
1303 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1304 xjsm.skip_input_data = _jpeg_skip_input_data;
1305 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1306 xjsm.term_source = _jpeg_term_source;
1308 jd.err = pjpeg_std_error(&jerr);
1309 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1310 * jpeg_create_decompress(&jd); */
1311 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1313 ret=pjpeg_read_header(&jd,TRUE);
1314 jd.out_color_space = JCS_RGB;
1315 pjpeg_start_decompress(&jd);
1316 if (ret != JPEG_HEADER_OK) {
1317 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1318 HeapFree(GetProcessHeap(),0,xbuf);
1322 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1323 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1324 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1327 oldsamprow = samprow;
1328 while ( jd.output_scanline<jd.output_height ) {
1329 x = pjpeg_read_scanlines(&jd,&samprow,1);
1331 ERR("failed to read current scanline?\n");
1334 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1335 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1336 *(bits++) = *(samprow+2);
1337 *(bits++) = *(samprow+1);
1338 *(bits++) = *(samprow);
1340 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1341 samprow = oldsamprow;
1345 bmi.biSize = sizeof(bmi);
1346 bmi.biWidth = jd.output_width;
1347 bmi.biHeight = -jd.output_height;
1349 bmi.biBitCount = jd.output_components<<3;
1350 bmi.biCompression = BI_RGB;
1351 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1352 bmi.biXPelsPerMeter = 0;
1353 bmi.biYPelsPerMeter = 0;
1355 bmi.biClrImportant = 0;
1357 HeapFree(GetProcessHeap(),0,samprow);
1358 pjpeg_finish_decompress(&jd);
1359 pjpeg_destroy_decompress(&jd);
1361 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1370 This->desc.picType = PICTYPE_BITMAP;
1371 OLEPictureImpl_SetBitmap(This);
1372 HeapFree(GetProcessHeap(),0,bits);
1375 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1380 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1382 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1383 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1386 /* Does not matter whether this is a coreheader or not, we only use
1387 * components which are in both
1390 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1394 xbuf+bfh->bfOffBits,
1399 if (This->desc.u.bmp.hbitmap == 0)
1401 This->desc.picType = PICTYPE_BITMAP;
1402 OLEPictureImpl_SetBitmap(This);
1406 /*****************************************************
1407 * start of PNG-specific code
1408 * currently only supports colortype PNG_COLOR_TYPE_RGB
1410 #ifdef SONAME_LIBPNG
1417 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1420 png_io * io_ptr = png_ptr->io_ptr;
1422 if(length + io_ptr->position > io_ptr->size){
1423 length = io_ptr->size - io_ptr->position;
1426 memcpy(data, io_ptr->buff + io_ptr->position, length);
1428 io_ptr->position += length;
1431 static void *libpng_handle;
1432 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1433 MAKE_FUNCPTR(png_create_read_struct);
1434 MAKE_FUNCPTR(png_create_info_struct);
1435 MAKE_FUNCPTR(png_set_read_fn);
1436 MAKE_FUNCPTR(png_read_info);
1437 MAKE_FUNCPTR(png_read_image);
1438 MAKE_FUNCPTR(png_get_rowbytes);
1439 MAKE_FUNCPTR(png_set_bgr);
1440 MAKE_FUNCPTR(png_destroy_read_struct);
1441 MAKE_FUNCPTR(png_set_palette_to_rgb);
1442 MAKE_FUNCPTR(png_read_update_info);
1443 MAKE_FUNCPTR(png_get_tRNS);
1444 MAKE_FUNCPTR(png_get_PLTE);
1445 MAKE_FUNCPTR(png_set_expand);
1448 static void *load_libpng(void)
1450 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1452 #define LOAD_FUNCPTR(f) \
1453 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1454 libpng_handle = NULL; \
1457 LOAD_FUNCPTR(png_create_read_struct);
1458 LOAD_FUNCPTR(png_create_info_struct);
1459 LOAD_FUNCPTR(png_set_read_fn);
1460 LOAD_FUNCPTR(png_read_info);
1461 LOAD_FUNCPTR(png_read_image);
1462 LOAD_FUNCPTR(png_get_rowbytes);
1463 LOAD_FUNCPTR(png_set_bgr);
1464 LOAD_FUNCPTR(png_destroy_read_struct);
1465 LOAD_FUNCPTR(png_set_palette_to_rgb);
1466 LOAD_FUNCPTR(png_read_update_info);
1467 LOAD_FUNCPTR(png_get_tRNS);
1468 LOAD_FUNCPTR(png_get_PLTE);
1469 LOAD_FUNCPTR(png_set_expand);
1473 return libpng_handle;
1475 #endif /* SONAME_LIBPNG */
1477 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1479 #ifdef SONAME_LIBPNG
1481 png_structp png_ptr = NULL;
1482 png_infop info_ptr = NULL;
1483 INT row, rowsize, height, width, num_trans, i, j;
1484 png_bytep* row_pointers = NULL;
1485 png_bytep pngdata = NULL;
1486 BITMAPINFOHEADER bmi;
1487 HDC hdcref = NULL, hdcXor, hdcMask;
1491 png_color_16p trans_values;
1492 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1493 HBITMAP hbmoldXor, hbmoldMask, temp;
1495 if(!libpng_handle) {
1496 if(!load_libpng()) {
1497 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1506 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1509 if(setjmp(png_jmpbuf(png_ptr))){
1510 TRACE("Error in libpng\n");
1515 info_ptr = ppng_create_info_struct(png_ptr);
1516 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1517 ppng_read_info(png_ptr, info_ptr);
1519 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1520 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1521 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1522 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1527 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1530 /* sets format from anything to RGBA */
1531 ppng_set_expand(png_ptr);
1532 /* sets format to BGRA */
1533 ppng_set_bgr(png_ptr);
1535 ppng_read_update_info(png_ptr, info_ptr);
1537 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1538 /* align rowsize to 4-byte boundary */
1539 rowsize = (rowsize + 3) & ~3;
1540 height = info_ptr->height;
1541 width = info_ptr->width;
1543 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1544 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1546 if(!pngdata || !row_pointers){
1551 for (row = 0; row < height; row++){
1552 row_pointers[row] = pngdata + row * rowsize;
1555 ppng_read_image(png_ptr, row_pointers);
1557 bmi.biSize = sizeof(bmi);
1558 bmi.biWidth = width;
1559 bmi.biHeight = -height;
1561 bmi.biBitCount = info_ptr->channels * 8;
1562 bmi.biCompression = BI_RGB;
1563 bmi.biSizeImage = height * rowsize;
1564 bmi.biXPelsPerMeter = 0;
1565 bmi.biYPelsPerMeter = 0;
1567 bmi.biClrImportant = 0;
1570 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1579 /* only fully-transparent alpha is handled */
1580 if((info_ptr->channels != 4) || !transparency){
1581 ReleaseDC(0, hdcref);
1585 This->hbmXor = CreateDIBitmap(
1594 /* set transparent pixels to black, all others to white */
1595 for(i = 0; i < height; i++){
1596 for(j = 3; j < rowsize; j += 4){
1597 if(row_pointers[i][j] == 0)
1598 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1600 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1604 temp = CreateDIBitmap(
1613 ReleaseDC(0, hdcref);
1615 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1616 hdcXor = CreateCompatibleDC(NULL);
1617 hdcMask = CreateCompatibleDC(NULL);
1619 hbmoldXor = SelectObject(hdcXor,temp);
1620 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1621 SetBkColor(hdcXor,black);
1622 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1624 SelectObject(hdcXor,This->hbmXor);
1627 SetTextColor(hdcXor,white);
1628 SetBkColor(hdcXor,black);
1629 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1631 SelectObject(hdcXor,hbmoldXor);
1632 SelectObject(hdcMask,hbmoldMask);
1638 This->desc.picType = PICTYPE_BITMAP;
1639 OLEPictureImpl_SetBitmap(This);
1644 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1645 HeapFree(GetProcessHeap(), 0, row_pointers);
1646 HeapFree(GetProcessHeap(), 0, pngdata);
1648 #else /* SONAME_LIBPNG */
1649 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1654 /*****************************************************
1655 * start of Icon-specific code
1658 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1661 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1666 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1667 FIXME("icon.idType=%d\n",cifd->idType);
1668 FIXME("icon.idCount=%d\n",cifd->idCount);
1670 for (i=0;i<cifd->idCount;i++) {
1671 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1672 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1673 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1674 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1675 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1676 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1677 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1678 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1682 /* If we have more than one icon, try to find the best.
1683 * this currently means '32 pixel wide'.
1685 if (cifd->idCount!=1) {
1686 for (i=0;i<cifd->idCount;i++) {
1687 if (cifd->idEntries[i].bWidth == 32)
1690 if (i==cifd->idCount) i=0;
1693 hicon = CreateIconFromResourceEx(
1694 xbuf+cifd->idEntries[i].dwDIBOffset,
1695 cifd->idEntries[i].dwDIBSize,
1698 cifd->idEntries[i].bWidth,
1699 cifd->idEntries[i].bHeight,
1703 ERR("CreateIcon failed.\n");
1706 This->desc.picType = PICTYPE_ICON;
1707 This->desc.u.icon.hicon = hicon;
1708 This->origWidth = cifd->idEntries[i].bWidth;
1709 This->origHeight = cifd->idEntries[i].bHeight;
1710 hdcRef = CreateCompatibleDC(0);
1711 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1712 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1718 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1719 const BYTE *data, ULONG size)
1724 hemf = SetEnhMetaFileBits(size, data);
1725 if (!hemf) return E_FAIL;
1727 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1729 This->desc.picType = PICTYPE_ENHMETAFILE;
1730 This->desc.u.emf.hemf = hemf;
1732 This->origWidth = 0;
1733 This->origHeight = 0;
1734 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1735 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1740 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1741 const BYTE *data, ULONG size)
1743 APM_HEADER *header = (APM_HEADER *)data;
1746 if (size < sizeof(APM_HEADER))
1748 if (header->key != 0x9ac6cdd7)
1751 /* SetMetaFileBitsEx performs data check on its own */
1752 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1753 if (!hmf) return E_FAIL;
1755 This->desc.picType = PICTYPE_METAFILE;
1756 This->desc.u.wmf.hmeta = hmf;
1757 This->desc.u.wmf.xExt = 0;
1758 This->desc.u.wmf.yExt = 0;
1760 This->origWidth = 0;
1761 This->origHeight = 0;
1762 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1763 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1767 /************************************************************************
1768 * BITMAP FORMAT FLAGS -
1769 * Flags that differentiate between different types of bitmaps.
1772 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1773 #define BITMAP_FORMAT_JPEG 0xd8ff
1774 #define BITMAP_FORMAT_GIF 0x4947
1775 #define BITMAP_FORMAT_PNG 0x5089
1776 #define BITMAP_FORMAT_APM 0xcdd7
1778 /************************************************************************
1779 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1781 * Loads the binary data from the IStream. Starts at current position.
1782 * There appears to be an 2 DWORD header:
1786 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1788 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1789 HRESULT hr = E_FAIL;
1790 BOOL headerisdata = FALSE;
1791 BOOL statfailed = FALSE;
1792 ULONG xread, toread;
1798 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1800 TRACE("(%p,%p)\n",This,pStm);
1802 /****************************************************************************************
1803 * Part 1: Load the data
1805 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1806 * out whether we do.
1808 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1809 * compound file. This may explain most, if not all, of the cases of "no
1810 * header", and the header validation should take this into account.
1811 * At least in Visual Basic 6, resource streams, valid headers are
1812 * header[0] == "lt\0\0",
1813 * header[1] == length_of_stream.
1815 * Also handle streams where we do not have a working "Stat" method by
1816 * reading all data until the end of the stream.
1818 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1820 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1822 /* we will read at least 8 byte ... just right below */
1823 statstg.cbSize.QuadPart = 8;
1828 headerisdata = FALSE;
1830 hr=IStream_Read(pStm,header,8,&xread);
1831 if (hr || xread!=8) {
1832 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1833 return (hr?hr:E_FAIL);
1835 headerread += xread;
1838 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1839 if (toread != 0 && toread != header[1])
1840 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1843 if (toread == 0) break;
1845 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1846 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1847 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1848 (header[0] == EMR_HEADER) || /* EMF header */
1849 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1851 ) {/* Found start of bitmap data */
1852 headerisdata = TRUE;
1854 toread = statstg.cbSize.QuadPart-8;
1858 FIXME("Unknown stream header magic: %08x\n", header[0]);
1862 } while (!headerisdata);
1864 if (statfailed) { /* we don't know the size ... read all we get */
1866 int origsize = sizeinc;
1869 TRACE("Reading all data from stream.\n");
1870 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1872 memcpy (xbuf, header, 8);
1874 while (xread < origsize) {
1875 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1880 if (!nread || hr) /* done, or error */
1882 if (xread == origsize) {
1883 origsize += sizeinc;
1884 sizeinc = 2*sizeinc; /* exponential increase */
1885 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1889 TRACE("hr in no-stat loader case is %08x\n", hr);
1890 TRACE("loaded %d bytes.\n", xread);
1891 This->datalen = xread;
1894 This->datalen = toread+(headerisdata?8:0);
1895 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1897 return E_OUTOFMEMORY;
1900 memcpy (xbuf, header, 8);
1902 while (xread < This->datalen) {
1904 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1909 if (xread != This->datalen)
1910 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1912 if (This->datalen == 0) { /* Marks the "NONE" picture */
1913 This->desc.picType = PICTYPE_NONE;
1918 /****************************************************************************************
1919 * Part 2: Process the loaded data
1922 magic = xbuf[0] + (xbuf[1]<<8);
1923 This->loadtime_format = magic;
1926 case BITMAP_FORMAT_GIF: /* GIF */
1927 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1929 case BITMAP_FORMAT_JPEG: /* JPEG */
1930 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1932 case BITMAP_FORMAT_BMP: /* Bitmap */
1933 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1935 case BITMAP_FORMAT_PNG: /* PNG */
1936 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1938 case BITMAP_FORMAT_APM: /* APM */
1939 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1941 case 0x0000: { /* ICON , first word is dwReserved */
1942 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1949 /* let's see if it's a EMF */
1950 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1951 if (hr == S_OK) break;
1953 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1955 for (i=0;i<xread+8;i++) {
1956 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1957 else MESSAGE("%02x ",xbuf[i-8]);
1958 if (i % 10 == 9) MESSAGE("\n");
1964 This->bIsDirty = FALSE;
1966 /* FIXME: this notify is not really documented */
1968 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1972 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1976 BITMAPINFO * pInfoBitmap;
1977 int iNumPaletteEntries;
1978 unsigned char * pPixelData;
1979 BITMAPFILEHEADER * pFileHeader;
1980 BITMAPINFO * pInfoHeader;
1982 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1983 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1985 /* Find out bitmap size and padded length */
1987 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1988 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1990 /* Fetch bitmap palette & pixel data */
1992 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1993 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1995 /* Calculate the total length required for the BMP data */
1996 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1997 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1998 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
2000 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
2001 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
2003 iNumPaletteEntries = 0;
2006 sizeof(BITMAPFILEHEADER) +
2007 sizeof(BITMAPINFOHEADER) +
2008 iNumPaletteEntries * sizeof(RGBQUAD) +
2009 pInfoBitmap->bmiHeader.biSizeImage;
2010 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2012 /* Fill the BITMAPFILEHEADER */
2013 pFileHeader = *ppBuffer;
2014 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2015 pFileHeader->bfSize = *pLength;
2016 pFileHeader->bfOffBits =
2017 sizeof(BITMAPFILEHEADER) +
2018 sizeof(BITMAPINFOHEADER) +
2019 iNumPaletteEntries * sizeof(RGBQUAD);
2021 /* Fill the BITMAPINFOHEADER and the palette data */
2022 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2023 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2025 (unsigned char *)(*ppBuffer) +
2026 sizeof(BITMAPFILEHEADER) +
2027 sizeof(BITMAPINFOHEADER) +
2028 iNumPaletteEntries * sizeof(RGBQUAD),
2029 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2032 HeapFree(GetProcessHeap(), 0, pPixelData);
2033 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2037 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2042 *ppBuffer = NULL; *pLength = 0;
2043 if (GetIconInfo(hIcon, &infoIcon)) {
2045 BITMAPINFO * pInfoBitmap;
2046 unsigned char * pIconData = NULL;
2047 unsigned int iDataSize = 0;
2049 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2051 /* Find out icon size */
2053 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2054 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2056 /* Auxiliary pointers */
2057 CURSORICONFILEDIR * pIconDir;
2058 CURSORICONFILEDIRENTRY * pIconEntry;
2059 BITMAPINFOHEADER * pIconBitmapHeader;
2060 unsigned int iOffsetPalette;
2061 unsigned int iOffsetColorData;
2062 unsigned int iOffsetMaskData;
2064 unsigned int iLengthScanLineColor;
2065 unsigned int iLengthScanLineMask;
2066 unsigned int iNumEntriesPalette;
2068 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2069 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2071 FIXME("DEBUG: bitmap size is %d x %d\n",
2072 pInfoBitmap->bmiHeader.biWidth,
2073 pInfoBitmap->bmiHeader.biHeight);
2074 FIXME("DEBUG: bitmap bpp is %d\n",
2075 pInfoBitmap->bmiHeader.biBitCount);
2076 FIXME("DEBUG: bitmap nplanes is %d\n",
2077 pInfoBitmap->bmiHeader.biPlanes);
2078 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2079 pInfoBitmap->bmiHeader.biSizeImage);
2081 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2082 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2083 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2085 /* Fill out the CURSORICONFILEDIR */
2086 pIconDir = (CURSORICONFILEDIR *)pIconData;
2087 pIconDir->idType = 1;
2088 pIconDir->idCount = 1;
2090 /* Fill out the CURSORICONFILEDIRENTRY */
2091 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2092 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2093 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2094 pIconEntry->bColorCount =
2095 (pInfoBitmap->bmiHeader.biBitCount < 8)
2096 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2098 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2099 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2100 pIconEntry->dwDIBSize = 0;
2101 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2103 /* Fill out the BITMAPINFOHEADER */
2104 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2105 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2107 /* Find out whether a palette exists for the bitmap */
2108 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2109 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2110 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2111 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2112 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2113 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2114 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2115 iNumEntriesPalette = 3;
2116 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2117 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2119 iNumEntriesPalette = 0;
2122 /* Add bitmap size and header size to icon data size. */
2123 iOffsetPalette = iDataSize;
2124 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2125 iOffsetColorData = iDataSize;
2126 iDataSize += pIconBitmapHeader->biSizeImage;
2127 iOffsetMaskData = iDataSize;
2128 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2129 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2130 pIconBitmapHeader->biHeight *= 2;
2131 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2132 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2133 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2134 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2136 /* Get the actual bitmap data from the icon bitmap */
2137 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2138 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2139 if (iNumEntriesPalette > 0) {
2140 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2141 iNumEntriesPalette * sizeof(RGBQUAD));
2144 /* Reset all values so that GetDIBits call succeeds */
2145 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2146 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2147 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2149 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2150 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2151 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2153 printf("ERROR: unable to get bitmap mask (error %u)\n",
2158 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2159 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2161 /* Write out everything produced so far to the stream */
2162 *ppBuffer = pIconData; *pLength = iDataSize;
2166 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2171 Remarks (from MSDN entry on GetIconInfo):
2173 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2174 members of ICONINFO. The calling application must manage
2175 these bitmaps and delete them when they are no longer
2178 if (hDC) ReleaseDC(0, hDC);
2179 DeleteObject(infoIcon.hbmMask);
2180 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2181 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2183 printf("ERROR: Unable to get icon information (error %u)\n",
2189 static HRESULT WINAPI OLEPictureImpl_Save(
2190 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2192 HRESULT hResult = E_NOTIMPL;
2194 unsigned int iDataSize;
2196 int iSerializeResult = 0;
2197 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2199 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2201 switch (This->desc.picType) {
2203 if (This->bIsDirty || !This->data) {
2204 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2205 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2209 HeapFree(GetProcessHeap(), 0, This->data);
2210 This->data = pIconData;
2211 This->datalen = iDataSize;
2213 if (This->loadtime_magic != 0xdeadbeef) {
2216 header[0] = This->loadtime_magic;
2217 header[1] = This->datalen;
2218 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2220 IStream_Write(pStm, This->data, This->datalen, &dummy);
2224 case PICTYPE_BITMAP:
2225 if (This->bIsDirty) {
2226 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2227 case BITMAP_FORMAT_BMP:
2228 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2230 case BITMAP_FORMAT_JPEG:
2231 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2233 case BITMAP_FORMAT_GIF:
2234 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2236 case BITMAP_FORMAT_PNG:
2237 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2240 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2243 if (iSerializeResult) {
2245 if (This->loadtime_magic != 0xdeadbeef) {
2250 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2251 header[1] = iDataSize;
2252 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2254 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2256 HeapFree(GetProcessHeap(), 0, This->data);
2257 This->data = pIconData;
2258 This->datalen = iDataSize;
2263 if (This->loadtime_magic != 0xdeadbeef) {
2268 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2269 header[1] = This->datalen;
2270 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2272 IStream_Write(pStm, This->data, This->datalen, &dummy);
2276 case PICTYPE_METAFILE:
2277 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2279 case PICTYPE_ENHMETAFILE:
2280 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2283 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2286 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2290 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2291 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2293 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2294 FIXME("(%p,%p),stub!\n",This,pcbSize);
2299 /************************************************************************
2303 /************************************************************************
2304 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2306 * See Windows documentation for more details on IUnknown methods.
2308 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2313 OLEPictureImpl *This = impl_from_IDispatch(iface);
2315 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2318 /************************************************************************
2319 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2321 * See Windows documentation for more details on IUnknown methods.
2323 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2326 OLEPictureImpl *This = impl_from_IDispatch(iface);
2328 return IPicture_AddRef((IPicture *)This);
2331 /************************************************************************
2332 * OLEPictureImpl_IDispatch_Release (IUnknown)
2334 * See Windows documentation for more details on IUnknown methods.
2336 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2339 OLEPictureImpl *This = impl_from_IDispatch(iface);
2341 return IPicture_Release((IPicture *)This);
2344 /************************************************************************
2345 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2347 * See Windows documentation for more details on IDispatch methods.
2349 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2351 unsigned int* pctinfo)
2353 TRACE("(%p)\n", pctinfo);
2360 /************************************************************************
2361 * OLEPictureImpl_GetTypeInfo (IDispatch)
2363 * See Windows documentation for more details on IDispatch methods.
2365 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2369 ITypeInfo** ppTInfo)
2371 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2375 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2380 hres = LoadTypeLib(stdole2tlb, &tl);
2383 ERR("Could not load stdole2.tlb\n");
2387 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2389 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2394 /************************************************************************
2395 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2397 * See Windows documentation for more details on IDispatch methods.
2399 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2402 LPOLESTR* rgszNames,
2410 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2411 rgszNames, cNames, (int)lcid, rgDispId);
2415 return E_INVALIDARG;
2419 /* retrieve type information */
2420 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2424 ERR("GetTypeInfo failed.\n");
2428 /* convert names to DISPIDs */
2429 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2430 ITypeInfo_Release(pTInfo);
2436 /************************************************************************
2437 * OLEPictureImpl_Invoke (IDispatch)
2439 * See Windows documentation for more details on IDispatch methods.
2441 static HRESULT WINAPI OLEPictureImpl_Invoke(
2443 DISPID dispIdMember,
2447 DISPPARAMS* pDispParams,
2448 VARIANT* pVarResult,
2449 EXCEPINFO* pExepInfo,
2452 OLEPictureImpl *This = impl_from_IDispatch(iface);
2454 /* validate parameters */
2456 if (!IsEqualIID(riid, &IID_NULL))
2458 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2459 return DISP_E_UNKNOWNNAME;
2464 ERR("null pDispParams not allowed\n");
2465 return DISP_E_PARAMNOTOPTIONAL;
2468 if (wFlags & DISPATCH_PROPERTYGET)
2470 if (pDispParams->cArgs != 0)
2472 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2473 return DISP_E_BADPARAMCOUNT;
2477 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2478 return DISP_E_PARAMNOTOPTIONAL;
2481 else if (wFlags & DISPATCH_PROPERTYPUT)
2483 if (pDispParams->cArgs != 1)
2485 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2486 return DISP_E_BADPARAMCOUNT;
2490 switch (dispIdMember)
2492 case DISPID_PICT_HANDLE:
2493 if (wFlags & DISPATCH_PROPERTYGET)
2495 TRACE("DISPID_PICT_HANDLE\n");
2496 V_VT(pVarResult) = VT_I4;
2497 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2500 case DISPID_PICT_HPAL:
2501 if (wFlags & DISPATCH_PROPERTYGET)
2503 TRACE("DISPID_PICT_HPAL\n");
2504 V_VT(pVarResult) = VT_I4;
2505 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2507 else if (wFlags & DISPATCH_PROPERTYPUT)
2511 TRACE("DISPID_PICT_HPAL\n");
2513 VariantInit(&vararg);
2514 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2518 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2520 VariantClear(&vararg);
2524 case DISPID_PICT_TYPE:
2525 if (wFlags & DISPATCH_PROPERTYGET)
2527 TRACE("DISPID_PICT_TYPE\n");
2528 V_VT(pVarResult) = VT_I2;
2529 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2532 case DISPID_PICT_WIDTH:
2533 if (wFlags & DISPATCH_PROPERTYGET)
2535 TRACE("DISPID_PICT_WIDTH\n");
2536 V_VT(pVarResult) = VT_I4;
2537 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2540 case DISPID_PICT_HEIGHT:
2541 if (wFlags & DISPATCH_PROPERTYGET)
2543 TRACE("DISPID_PICT_HEIGHT\n");
2544 V_VT(pVarResult) = VT_I4;
2545 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2550 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2551 return DISP_E_MEMBERNOTFOUND;
2555 static const IPictureVtbl OLEPictureImpl_VTable =
2557 OLEPictureImpl_QueryInterface,
2558 OLEPictureImpl_AddRef,
2559 OLEPictureImpl_Release,
2560 OLEPictureImpl_get_Handle,
2561 OLEPictureImpl_get_hPal,
2562 OLEPictureImpl_get_Type,
2563 OLEPictureImpl_get_Width,
2564 OLEPictureImpl_get_Height,
2565 OLEPictureImpl_Render,
2566 OLEPictureImpl_set_hPal,
2567 OLEPictureImpl_get_CurDC,
2568 OLEPictureImpl_SelectPicture,
2569 OLEPictureImpl_get_KeepOriginalFormat,
2570 OLEPictureImpl_put_KeepOriginalFormat,
2571 OLEPictureImpl_PictureChanged,
2572 OLEPictureImpl_SaveAsFile,
2573 OLEPictureImpl_get_Attributes
2576 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2578 OLEPictureImpl_IDispatch_QueryInterface,
2579 OLEPictureImpl_IDispatch_AddRef,
2580 OLEPictureImpl_IDispatch_Release,
2581 OLEPictureImpl_GetTypeInfoCount,
2582 OLEPictureImpl_GetTypeInfo,
2583 OLEPictureImpl_GetIDsOfNames,
2584 OLEPictureImpl_Invoke
2587 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2589 OLEPictureImpl_IPersistStream_QueryInterface,
2590 OLEPictureImpl_IPersistStream_AddRef,
2591 OLEPictureImpl_IPersistStream_Release,
2592 OLEPictureImpl_GetClassID,
2593 OLEPictureImpl_IsDirty,
2594 OLEPictureImpl_Load,
2595 OLEPictureImpl_Save,
2596 OLEPictureImpl_GetSizeMax
2599 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2601 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2602 OLEPictureImpl_IConnectionPointContainer_AddRef,
2603 OLEPictureImpl_IConnectionPointContainer_Release,
2604 OLEPictureImpl_EnumConnectionPoints,
2605 OLEPictureImpl_FindConnectionPoint
2608 /***********************************************************************
2609 * OleCreatePictureIndirect (OLEAUT32.419)
2611 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2612 BOOL fOwn, LPVOID *ppvObj )
2614 OLEPictureImpl* newPict = NULL;
2617 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2628 * Try to construct a new instance of the class.
2630 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2632 if (newPict == NULL)
2633 return E_OUTOFMEMORY;
2636 * Make sure it supports the interface required by the caller.
2638 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2641 * Release the reference obtained in the constructor. If
2642 * the QueryInterface was unsuccessful, it will free the class.
2644 IPicture_Release((IPicture*)newPict);
2650 /***********************************************************************
2651 * OleLoadPicture (OLEAUT32.418)
2653 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2654 REFIID riid, LPVOID *ppvObj )
2660 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2661 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2663 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2666 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2668 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2669 IPicture_Release(newpic);
2673 hr = IPersistStream_Load(ps,lpstream);
2674 IPersistStream_Release(ps);
2677 ERR("IPersistStream_Load failed\n");
2678 IPicture_Release(newpic);
2682 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2684 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2685 IPicture_Release(newpic);
2689 /***********************************************************************
2690 * OleLoadPictureEx (OLEAUT32.401)
2692 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2693 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2699 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2700 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2702 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2705 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2707 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2708 IPicture_Release(newpic);
2712 hr = IPersistStream_Load(ps,lpstream);
2713 IPersistStream_Release(ps);
2716 ERR("IPersistStream_Load failed\n");
2717 IPicture_Release(newpic);
2721 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2723 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2724 IPicture_Release(newpic);
2728 /***********************************************************************
2729 * OleLoadPicturePath (OLEAUT32.424)
2731 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2732 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2735 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2739 HGLOBAL hGlobal = NULL;
2740 DWORD dwBytesRead = 0;
2743 IPersistStream *pStream;
2746 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2747 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2748 debugstr_guid(riid), ppvRet);
2750 if (!ppvRet) return E_POINTER;
2752 if (strncmpW(szURLorPath, file, 7) == 0) {
2755 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2757 if (hFile == INVALID_HANDLE_VALUE)
2758 return E_UNEXPECTED;
2760 dwFileSize = GetFileSize(hFile, NULL);
2761 if (dwFileSize != INVALID_FILE_SIZE )
2763 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2766 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2769 GlobalFree(hGlobal);
2777 return E_UNEXPECTED;
2779 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2782 GlobalFree(hGlobal);
2789 hRes = CreateBindCtx(0, &pbc);
2790 if (SUCCEEDED(hRes))
2792 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2793 if (SUCCEEDED(hRes))
2795 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2796 IMoniker_Release(pmnk);
2798 IBindCtx_Release(pbc);
2804 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2805 &IID_IPicture, (LPVOID*)&ipicture);
2807 IStream_Release(stream);
2811 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2813 IStream_Release(stream);
2814 IPicture_Release(ipicture);
2818 hRes = IPersistStream_Load(pStream, stream);
2819 IPersistStream_Release(pStream);
2820 IStream_Release(stream);
2823 IPicture_Release(ipicture);
2827 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2829 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2831 IPicture_Release(ipicture);
2835 /*******************************************************************************
2836 * StdPic ClassFactory
2840 /* IUnknown fields */
2841 const IClassFactoryVtbl *lpVtbl;
2843 } IClassFactoryImpl;
2845 static HRESULT WINAPI
2846 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2847 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2849 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2850 return E_NOINTERFACE;
2854 SPCF_AddRef(LPCLASSFACTORY iface) {
2855 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2856 return InterlockedIncrement(&This->ref);
2859 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2860 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2861 /* static class, won't be freed */
2862 return InterlockedDecrement(&This->ref);
2865 static HRESULT WINAPI SPCF_CreateInstance(
2866 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2868 /* Creates an uninitialized picture */
2869 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2873 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2874 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2875 FIXME("(%p)->(%d),stub!\n",This,dolock);
2879 static const IClassFactoryVtbl SPCF_Vtbl = {
2880 SPCF_QueryInterface,
2883 SPCF_CreateInstance,
2886 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2888 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }