2 * Copyright 2010 Damjan Jovanovic
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
24 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
25 #define GetCurrentProcess GetCurrentProcess_Mac
26 #define GetCurrentThread GetCurrentThread_Mac
27 #define LoadResource LoadResource_Mac
28 #define AnimatePalette AnimatePalette_Mac
29 #define EqualRgn EqualRgn_Mac
30 #define FillRgn FillRgn_Mac
31 #define FrameRgn FrameRgn_Mac
32 #define GetPixel GetPixel_Mac
33 #define InvertRgn InvertRgn_Mac
34 #define LineTo LineTo_Mac
35 #define OffsetRgn OffsetRgn_Mac
36 #define PaintRgn PaintRgn_Mac
37 #define Polygon Polygon_Mac
38 #define ResizePalette ResizePalette_Mac
39 #define SetRectRgn SetRectRgn_Mac
40 #define EqualRect EqualRect_Mac
41 #define FillRect FillRect_Mac
42 #define FrameRect FrameRect_Mac
43 #define GetCursor GetCursor_Mac
44 #define InvertRect InvertRect_Mac
45 #define OffsetRect OffsetRect_Mac
46 #define PtInRect PtInRect_Mac
47 #define SetCursor SetCursor_Mac
48 #define SetRect SetRect_Mac
49 #define ShowCursor ShowCursor_Mac
50 #define UnionRect UnionRect_Mac
51 #include <ApplicationServices/ApplicationServices.h>
52 #undef GetCurrentProcess
53 #undef GetCurrentThread
86 #include "wincodecs_private.h"
88 #include "wine/debug.h"
90 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
92 #if defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) && \
93 MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
95 typedef struct IcnsEncoder
{
96 IWICBitmapEncoder IWICBitmapEncoder_iface
;
99 IconFamilyHandle icns_family
;
100 BOOL any_frame_committed
;
101 int outstanding_commits
;
103 CRITICAL_SECTION lock
;
106 static inline IcnsEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
108 return CONTAINING_RECORD(iface
, IcnsEncoder
, IWICBitmapEncoder_iface
);
111 typedef struct IcnsFrameEncode
{
112 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
113 IcnsEncoder
*encoder
;
123 static inline IcnsFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
125 return CONTAINING_RECORD(iface
, IcnsFrameEncode
, IWICBitmapFrameEncode_iface
);
128 static HRESULT WINAPI
IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
131 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
132 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
134 if (!ppv
) return E_INVALIDARG
;
136 if (IsEqualIID(&IID_IUnknown
, iid
) ||
137 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
139 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
144 return E_NOINTERFACE
;
147 IUnknown_AddRef((IUnknown
*)*ppv
);
151 static ULONG WINAPI
IcnsFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
153 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
154 ULONG ref
= InterlockedIncrement(&This
->ref
);
156 TRACE("(%p) refcount=%u\n", iface
, ref
);
161 static ULONG WINAPI
IcnsFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
163 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
164 ULONG ref
= InterlockedDecrement(&This
->ref
);
166 TRACE("(%p) refcount=%u\n", iface
, ref
);
170 if (!This
->committed
)
172 EnterCriticalSection(&This
->encoder
->lock
);
173 This
->encoder
->outstanding_commits
--;
174 LeaveCriticalSection(&This
->encoder
->lock
);
176 HeapFree(GetProcessHeap(), 0, This
->icns_image
);
178 IWICBitmapEncoder_Release(&This
->encoder
->IWICBitmapEncoder_iface
);
179 HeapFree(GetProcessHeap(), 0, This
);
185 static HRESULT WINAPI
IcnsFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
186 IPropertyBag2
*pIEncoderOptions
)
188 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
191 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
193 EnterCriticalSection(&This
->encoder
->lock
);
195 if (This
->initialized
)
197 hr
= WINCODEC_ERR_WRONGSTATE
;
200 This
->initialized
= TRUE
;
203 LeaveCriticalSection(&This
->encoder
->lock
);
207 static HRESULT WINAPI
IcnsFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
208 UINT uiWidth
, UINT uiHeight
)
210 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
213 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
215 EnterCriticalSection(&This
->encoder
->lock
);
217 if (!This
->initialized
|| This
->icns_image
)
219 hr
= WINCODEC_ERR_WRONGSTATE
;
223 if (uiWidth
!= uiHeight
)
225 WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth
, uiHeight
);
240 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
245 This
->size
= uiWidth
;
248 LeaveCriticalSection(&This
->encoder
->lock
);
252 static HRESULT WINAPI
IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
253 double dpiX
, double dpiY
)
255 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
258 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
260 EnterCriticalSection(&This
->encoder
->lock
);
262 if (!This
->initialized
|| This
->icns_image
)
264 hr
= WINCODEC_ERR_WRONGSTATE
;
269 LeaveCriticalSection(&This
->encoder
->lock
);
273 static HRESULT WINAPI
IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
274 WICPixelFormatGUID
*pPixelFormat
)
276 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
279 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
281 EnterCriticalSection(&This
->encoder
->lock
);
283 if (!This
->initialized
|| This
->icns_image
)
285 hr
= WINCODEC_ERR_WRONGSTATE
;
289 memcpy(pPixelFormat
, &GUID_WICPixelFormat32bppBGRA
, sizeof(GUID
));
292 LeaveCriticalSection(&This
->encoder
->lock
);
296 static HRESULT WINAPI
IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
297 UINT cCount
, IWICColorContext
**ppIColorContext
)
299 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
303 static HRESULT WINAPI
IcnsFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
304 IWICPalette
*pIPalette
)
306 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
307 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
310 static HRESULT WINAPI
IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
311 IWICBitmapSource
*pIThumbnail
)
313 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
314 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
317 static HRESULT WINAPI
IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
318 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
320 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
324 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
326 EnterCriticalSection(&This
->encoder
->lock
);
328 if (!This
->initialized
|| !This
->size
)
330 hr
= WINCODEC_ERR_WRONGSTATE
;
333 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->size
)
339 if (!This
->icns_image
)
343 case 16: This
->icns_type
= kIconServices16PixelDataARGB
; break;
344 case 32: This
->icns_type
= kIconServices32PixelDataARGB
; break;
345 case 48: This
->icns_type
= kIconServices48PixelDataARGB
; break;
346 case 128: This
->icns_type
= kIconServices128PixelDataARGB
; break;
347 case 256: This
->icns_type
= kIconServices256PixelDataARGB
; break;
348 case 512: This
->icns_type
= kIconServices512PixelDataARGB
; break;
350 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
354 This
->icns_image
= HeapAlloc(GetProcessHeap(), 0, This
->size
* This
->size
* 4);
355 if (!This
->icns_image
)
357 WARN("failed to allocate image buffer\n");
363 for (i
= 0; i
< lineCount
; i
++)
365 BYTE
*src_row
, *dst_row
;
367 src_row
= pbPixels
+ cbStride
* i
;
368 dst_row
= This
->icns_image
+ (This
->lines_written
+ i
)*(This
->size
*4);
369 /* swap bgr -> rgb */
370 for (j
= 0; j
< This
->size
*4; j
+= 4)
372 dst_row
[j
] = src_row
[j
+3];
373 dst_row
[j
+1] = src_row
[j
+2];
374 dst_row
[j
+2] = src_row
[j
+1];
375 dst_row
[j
+3] = src_row
[j
];
378 This
->lines_written
+= lineCount
;
381 LeaveCriticalSection(&This
->encoder
->lock
);
385 static HRESULT WINAPI
IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
386 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
388 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
391 TRACE("(%p,%p,%s)\n", iface
, pIBitmapSource
, debug_wic_rect(prc
));
393 if (!This
->initialized
)
394 return WINCODEC_ERR_WRONGSTATE
;
396 hr
= configure_write_source(iface
, pIBitmapSource
, prc
,
397 &GUID_WICPixelFormat32bppBGRA
, This
->size
, This
->size
,
402 hr
= write_source(iface
, pIBitmapSource
, prc
,
403 &GUID_WICPixelFormat32bppBGRA
, 32, FALSE
, This
->size
, This
->size
);
409 static HRESULT WINAPI
IcnsFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
411 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
416 TRACE("(%p)\n", iface
);
418 EnterCriticalSection(&This
->encoder
->lock
);
420 if (!This
->icns_image
|| This
->lines_written
!= This
->size
|| This
->committed
)
422 hr
= WINCODEC_ERR_WRONGSTATE
;
426 ret
= PtrToHand(This
->icns_image
, &handle
, This
->size
* This
->size
* 4);
427 if (ret
!= noErr
|| !handle
)
429 WARN("PtrToHand failed with error %d\n", ret
);
434 ret
= SetIconFamilyData(This
->encoder
->icns_family
, This
->icns_type
, handle
);
435 DisposeHandle(handle
);
439 WARN("SetIconFamilyData failed for image with error %d\n", ret
);
444 This
->committed
= TRUE
;
445 This
->encoder
->any_frame_committed
= TRUE
;
446 This
->encoder
->outstanding_commits
--;
449 LeaveCriticalSection(&This
->encoder
->lock
);
453 static HRESULT WINAPI
IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
454 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
456 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
460 static const IWICBitmapFrameEncodeVtbl IcnsEncoder_FrameVtbl
= {
461 IcnsFrameEncode_QueryInterface
,
462 IcnsFrameEncode_AddRef
,
463 IcnsFrameEncode_Release
,
464 IcnsFrameEncode_Initialize
,
465 IcnsFrameEncode_SetSize
,
466 IcnsFrameEncode_SetResolution
,
467 IcnsFrameEncode_SetPixelFormat
,
468 IcnsFrameEncode_SetColorContexts
,
469 IcnsFrameEncode_SetPalette
,
470 IcnsFrameEncode_SetThumbnail
,
471 IcnsFrameEncode_WritePixels
,
472 IcnsFrameEncode_WriteSource
,
473 IcnsFrameEncode_Commit
,
474 IcnsFrameEncode_GetMetadataQueryWriter
477 static HRESULT WINAPI
IcnsEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
480 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
481 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
483 if (!ppv
) return E_INVALIDARG
;
485 if (IsEqualIID(&IID_IUnknown
, iid
) ||
486 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
488 *ppv
= &This
->IWICBitmapEncoder_iface
;
493 return E_NOINTERFACE
;
496 IUnknown_AddRef((IUnknown
*)*ppv
);
500 static ULONG WINAPI
IcnsEncoder_AddRef(IWICBitmapEncoder
*iface
)
502 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
503 ULONG ref
= InterlockedIncrement(&This
->ref
);
505 TRACE("(%p) refcount=%u\n", iface
, ref
);
510 static ULONG WINAPI
IcnsEncoder_Release(IWICBitmapEncoder
*iface
)
512 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
513 ULONG ref
= InterlockedDecrement(&This
->ref
);
515 TRACE("(%p) refcount=%u\n", iface
, ref
);
519 This
->lock
.DebugInfo
->Spare
[0] = 0;
520 DeleteCriticalSection(&This
->lock
);
521 if (This
->icns_family
)
522 DisposeHandle((Handle
)This
->icns_family
);
524 IStream_Release(This
->stream
);
525 HeapFree(GetProcessHeap(), 0, This
);
531 static HRESULT WINAPI
IcnsEncoder_Initialize(IWICBitmapEncoder
*iface
,
532 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
534 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
537 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
539 EnterCriticalSection(&This
->lock
);
541 if (This
->icns_family
)
543 hr
= WINCODEC_ERR_WRONGSTATE
;
546 This
->icns_family
= (IconFamilyHandle
)NewHandle(0);
547 if (!This
->icns_family
)
549 WARN("error creating icns family\n");
553 IStream_AddRef(pIStream
);
554 This
->stream
= pIStream
;
557 LeaveCriticalSection(&This
->lock
);
562 static HRESULT WINAPI
IcnsEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
563 GUID
*pguidContainerFormat
)
565 FIXME("(%p,%s): stub\n", iface
, debugstr_guid(pguidContainerFormat
));
569 static HRESULT WINAPI
IcnsEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
570 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
572 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
576 static HRESULT WINAPI
IcnsEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
577 UINT cCount
, IWICColorContext
**ppIColorContext
)
579 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
583 static HRESULT WINAPI
IcnsEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
585 TRACE("(%p,%p)\n", iface
, pIPalette
);
586 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
589 static HRESULT WINAPI
IcnsEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
591 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
592 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
595 static HRESULT WINAPI
IcnsEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
597 TRACE("(%p,%p)\n", iface
, pIPreview
);
598 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
601 static HRESULT WINAPI
IcnsEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
602 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
604 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
606 IcnsFrameEncode
*frameEncode
= NULL
;
608 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
610 EnterCriticalSection(&This
->lock
);
612 if (!This
->icns_family
)
614 hr
= WINCODEC_ERR_NOTINITIALIZED
;
618 if (ppIEncoderOptions
)
620 hr
= CreatePropertyBag2(NULL
, 0, ppIEncoderOptions
);
625 frameEncode
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode
));
626 if (frameEncode
== NULL
)
631 frameEncode
->IWICBitmapFrameEncode_iface
.lpVtbl
= &IcnsEncoder_FrameVtbl
;
632 frameEncode
->encoder
= This
;
633 frameEncode
->ref
= 1;
634 frameEncode
->initialized
= FALSE
;
635 frameEncode
->size
= 0;
636 frameEncode
->icns_image
= NULL
;
637 frameEncode
->lines_written
= 0;
638 frameEncode
->committed
= FALSE
;
639 *ppIFrameEncode
= &frameEncode
->IWICBitmapFrameEncode_iface
;
640 This
->outstanding_commits
++;
641 IWICBitmapEncoder_AddRef(&This
->IWICBitmapEncoder_iface
);
644 LeaveCriticalSection(&This
->lock
);
649 static HRESULT WINAPI
IcnsEncoder_Commit(IWICBitmapEncoder
*iface
)
651 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
656 TRACE("(%p)\n", iface
);
658 EnterCriticalSection(&This
->lock
);
660 if (!This
->any_frame_committed
|| This
->outstanding_commits
> 0 || This
->committed
)
662 hr
= WINCODEC_ERR_WRONGSTATE
;
666 buffer_size
= GetHandleSize((Handle
)This
->icns_family
);
667 hr
= IStream_Write(This
->stream
, *This
->icns_family
, buffer_size
, &byteswritten
);
668 if (FAILED(hr
) || byteswritten
!= buffer_size
)
670 WARN("writing file failed, hr = 0x%08X\n", hr
);
675 This
->committed
= TRUE
;
678 LeaveCriticalSection(&This
->lock
);
682 static HRESULT WINAPI
IcnsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
683 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
685 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
689 static const IWICBitmapEncoderVtbl IcnsEncoder_Vtbl
= {
690 IcnsEncoder_QueryInterface
,
693 IcnsEncoder_Initialize
,
694 IcnsEncoder_GetContainerFormat
,
695 IcnsEncoder_GetEncoderInfo
,
696 IcnsEncoder_SetColorContexts
,
697 IcnsEncoder_SetPalette
,
698 IcnsEncoder_SetThumbnail
,
699 IcnsEncoder_SetPreview
,
700 IcnsEncoder_CreateNewFrame
,
702 IcnsEncoder_GetMetadataQueryWriter
705 HRESULT
IcnsEncoder_CreateInstance(REFIID iid
, void** ppv
)
710 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
714 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsEncoder
));
715 if (!This
) return E_OUTOFMEMORY
;
717 This
->IWICBitmapEncoder_iface
.lpVtbl
= &IcnsEncoder_Vtbl
;
720 This
->icns_family
= NULL
;
721 This
->any_frame_committed
= FALSE
;
722 This
->outstanding_commits
= 0;
723 This
->committed
= FALSE
;
724 InitializeCriticalSection(&This
->lock
);
725 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IcnsEncoder.lock");
727 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
728 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
733 #else /* !defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) ||
734 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 */
736 HRESULT
IcnsEncoder_CreateInstance(REFIID iid
, void** ppv
)
738 ERR("Trying to save ICNS picture, but ICNS support is not compiled in.\n");