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
87 #include "wincodecs_private.h"
89 #include "wine/debug.h"
90 #include "wine/library.h"
92 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
94 #if defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) && \
95 MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
97 typedef struct IcnsEncoder
{
98 IWICBitmapEncoder IWICBitmapEncoder_iface
;
101 IconFamilyHandle icns_family
;
102 BOOL any_frame_committed
;
103 int outstanding_commits
;
105 CRITICAL_SECTION lock
;
108 static inline IcnsEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
110 return CONTAINING_RECORD(iface
, IcnsEncoder
, IWICBitmapEncoder_iface
);
113 typedef struct IcnsFrameEncode
{
114 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
115 IcnsEncoder
*encoder
;
125 static inline IcnsFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
127 return CONTAINING_RECORD(iface
, IcnsFrameEncode
, IWICBitmapFrameEncode_iface
);
130 static HRESULT WINAPI
IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
133 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
134 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
136 if (!ppv
) return E_INVALIDARG
;
138 if (IsEqualIID(&IID_IUnknown
, iid
) ||
139 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
141 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
146 return E_NOINTERFACE
;
149 IUnknown_AddRef((IUnknown
*)*ppv
);
153 static ULONG WINAPI
IcnsFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
155 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
156 ULONG ref
= InterlockedIncrement(&This
->ref
);
158 TRACE("(%p) refcount=%u\n", iface
, ref
);
163 static ULONG WINAPI
IcnsFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
165 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
166 ULONG ref
= InterlockedDecrement(&This
->ref
);
168 TRACE("(%p) refcount=%u\n", iface
, ref
);
172 if (!This
->committed
)
174 EnterCriticalSection(&This
->encoder
->lock
);
175 This
->encoder
->outstanding_commits
--;
176 LeaveCriticalSection(&This
->encoder
->lock
);
178 HeapFree(GetProcessHeap(), 0, This
->icns_image
);
180 IWICBitmapEncoder_Release(&This
->encoder
->IWICBitmapEncoder_iface
);
181 HeapFree(GetProcessHeap(), 0, This
);
187 static HRESULT WINAPI
IcnsFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
188 IPropertyBag2
*pIEncoderOptions
)
190 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
193 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
195 EnterCriticalSection(&This
->encoder
->lock
);
197 if (This
->initialized
)
199 hr
= WINCODEC_ERR_WRONGSTATE
;
202 This
->initialized
= TRUE
;
205 LeaveCriticalSection(&This
->encoder
->lock
);
209 static HRESULT WINAPI
IcnsFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
210 UINT uiWidth
, UINT uiHeight
)
212 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
215 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
217 EnterCriticalSection(&This
->encoder
->lock
);
219 if (!This
->initialized
|| This
->icns_image
)
221 hr
= WINCODEC_ERR_WRONGSTATE
;
225 if (uiWidth
!= uiHeight
)
227 WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth
, uiHeight
);
242 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
247 This
->size
= uiWidth
;
250 LeaveCriticalSection(&This
->encoder
->lock
);
254 static HRESULT WINAPI
IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
255 double dpiX
, double dpiY
)
257 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
260 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
262 EnterCriticalSection(&This
->encoder
->lock
);
264 if (!This
->initialized
|| This
->icns_image
)
266 hr
= WINCODEC_ERR_WRONGSTATE
;
271 LeaveCriticalSection(&This
->encoder
->lock
);
275 static HRESULT WINAPI
IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
276 WICPixelFormatGUID
*pPixelFormat
)
278 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
281 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
283 EnterCriticalSection(&This
->encoder
->lock
);
285 if (!This
->initialized
|| This
->icns_image
)
287 hr
= WINCODEC_ERR_WRONGSTATE
;
291 memcpy(pPixelFormat
, &GUID_WICPixelFormat32bppBGRA
, sizeof(GUID
));
294 LeaveCriticalSection(&This
->encoder
->lock
);
298 static HRESULT WINAPI
IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
299 UINT cCount
, IWICColorContext
**ppIColorContext
)
301 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
305 static HRESULT WINAPI
IcnsFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
306 IWICPalette
*pIPalette
)
308 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
309 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
312 static HRESULT WINAPI
IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
313 IWICBitmapSource
*pIThumbnail
)
315 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
316 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
319 static HRESULT WINAPI
IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
320 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
322 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
326 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
328 EnterCriticalSection(&This
->encoder
->lock
);
330 if (!This
->initialized
|| !This
->size
)
332 hr
= WINCODEC_ERR_WRONGSTATE
;
335 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->size
)
341 if (!This
->icns_image
)
345 case 16: This
->icns_type
= kIconServices16PixelDataARGB
; break;
346 case 32: This
->icns_type
= kIconServices32PixelDataARGB
; break;
347 case 48: This
->icns_type
= kIconServices48PixelDataARGB
; break;
348 case 128: This
->icns_type
= kIconServices128PixelDataARGB
; break;
349 case 256: This
->icns_type
= kIconServices256PixelDataARGB
; break;
350 case 512: This
->icns_type
= kIconServices512PixelDataARGB
; break;
352 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
356 This
->icns_image
= HeapAlloc(GetProcessHeap(), 0, This
->size
* This
->size
* 4);
357 if (!This
->icns_image
)
359 WARN("failed to allocate image buffer\n");
365 for (i
= 0; i
< lineCount
; i
++)
367 BYTE
*src_row
, *dst_row
;
369 src_row
= pbPixels
+ cbStride
* i
;
370 dst_row
= This
->icns_image
+ (This
->lines_written
+ i
)*(This
->size
*4);
371 /* swap bgr -> rgb */
372 for (j
= 0; j
< This
->size
*4; j
+= 4)
374 dst_row
[j
] = src_row
[j
+3];
375 dst_row
[j
+1] = src_row
[j
+2];
376 dst_row
[j
+2] = src_row
[j
+1];
377 dst_row
[j
+3] = src_row
[j
];
380 This
->lines_written
+= lineCount
;
383 LeaveCriticalSection(&This
->encoder
->lock
);
387 static HRESULT WINAPI
IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
388 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
390 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
393 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
395 if (!This
->initialized
)
396 return WINCODEC_ERR_WRONGSTATE
;
398 hr
= configure_write_source(iface
, pIBitmapSource
, prc
,
399 &GUID_WICPixelFormat32bppBGRA
, This
->size
, This
->size
,
404 hr
= write_source(iface
, pIBitmapSource
, prc
,
405 &GUID_WICPixelFormat32bppBGRA
, 32, This
->size
, This
->size
);
411 static HRESULT WINAPI
IcnsFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
413 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
418 TRACE("(%p)\n", iface
);
420 EnterCriticalSection(&This
->encoder
->lock
);
422 if (!This
->icns_image
|| This
->lines_written
!= This
->size
|| This
->committed
)
424 hr
= WINCODEC_ERR_WRONGSTATE
;
428 ret
= PtrToHand(This
->icns_image
, &handle
, This
->size
* This
->size
* 4);
429 if (ret
!= noErr
|| !handle
)
431 WARN("PtrToHand failed with error %d\n", ret
);
436 ret
= SetIconFamilyData(This
->encoder
->icns_family
, This
->icns_type
, handle
);
437 DisposeHandle(handle
);
441 WARN("SetIconFamilyData failed for image with error %d\n", ret
);
446 This
->committed
= TRUE
;
447 This
->encoder
->any_frame_committed
= TRUE
;
448 This
->encoder
->outstanding_commits
--;
451 LeaveCriticalSection(&This
->encoder
->lock
);
455 static HRESULT WINAPI
IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
456 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
458 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
462 static const IWICBitmapFrameEncodeVtbl IcnsEncoder_FrameVtbl
= {
463 IcnsFrameEncode_QueryInterface
,
464 IcnsFrameEncode_AddRef
,
465 IcnsFrameEncode_Release
,
466 IcnsFrameEncode_Initialize
,
467 IcnsFrameEncode_SetSize
,
468 IcnsFrameEncode_SetResolution
,
469 IcnsFrameEncode_SetPixelFormat
,
470 IcnsFrameEncode_SetColorContexts
,
471 IcnsFrameEncode_SetPalette
,
472 IcnsFrameEncode_SetThumbnail
,
473 IcnsFrameEncode_WritePixels
,
474 IcnsFrameEncode_WriteSource
,
475 IcnsFrameEncode_Commit
,
476 IcnsFrameEncode_GetMetadataQueryWriter
479 static HRESULT WINAPI
IcnsEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
482 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
483 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
485 if (!ppv
) return E_INVALIDARG
;
487 if (IsEqualIID(&IID_IUnknown
, iid
) ||
488 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
490 *ppv
= &This
->IWICBitmapEncoder_iface
;
495 return E_NOINTERFACE
;
498 IUnknown_AddRef((IUnknown
*)*ppv
);
502 static ULONG WINAPI
IcnsEncoder_AddRef(IWICBitmapEncoder
*iface
)
504 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
505 ULONG ref
= InterlockedIncrement(&This
->ref
);
507 TRACE("(%p) refcount=%u\n", iface
, ref
);
512 static ULONG WINAPI
IcnsEncoder_Release(IWICBitmapEncoder
*iface
)
514 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
515 ULONG ref
= InterlockedDecrement(&This
->ref
);
517 TRACE("(%p) refcount=%u\n", iface
, ref
);
521 This
->lock
.DebugInfo
->Spare
[0] = 0;
522 DeleteCriticalSection(&This
->lock
);
523 if (This
->icns_family
)
524 DisposeHandle((Handle
)This
->icns_family
);
526 IStream_Release(This
->stream
);
527 HeapFree(GetProcessHeap(), 0, This
);
533 static HRESULT WINAPI
IcnsEncoder_Initialize(IWICBitmapEncoder
*iface
,
534 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
536 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
539 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
541 EnterCriticalSection(&This
->lock
);
543 if (This
->icns_family
)
545 hr
= WINCODEC_ERR_WRONGSTATE
;
548 This
->icns_family
= (IconFamilyHandle
)NewHandle(0);
549 if (!This
->icns_family
)
551 WARN("error creating icns family\n");
555 IStream_AddRef(pIStream
);
556 This
->stream
= pIStream
;
559 LeaveCriticalSection(&This
->lock
);
564 static HRESULT WINAPI
IcnsEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
565 GUID
*pguidContainerFormat
)
567 FIXME("(%p,%s): stub\n", iface
, debugstr_guid(pguidContainerFormat
));
571 static HRESULT WINAPI
IcnsEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
572 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
574 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
578 static HRESULT WINAPI
IcnsEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
579 UINT cCount
, IWICColorContext
**ppIColorContext
)
581 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
585 static HRESULT WINAPI
IcnsEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
587 TRACE("(%p,%p)\n", iface
, pIPalette
);
588 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
591 static HRESULT WINAPI
IcnsEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
593 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
594 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
597 static HRESULT WINAPI
IcnsEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
599 TRACE("(%p,%p)\n", iface
, pIPreview
);
600 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
603 static HRESULT WINAPI
IcnsEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
604 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
606 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
608 IcnsFrameEncode
*frameEncode
= NULL
;
610 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
612 EnterCriticalSection(&This
->lock
);
614 if (!This
->icns_family
)
616 hr
= WINCODEC_ERR_NOTINITIALIZED
;
620 if (ppIEncoderOptions
)
622 hr
= CreatePropertyBag2(NULL
, 0, ppIEncoderOptions
);
627 frameEncode
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode
));
628 if (frameEncode
== NULL
)
633 frameEncode
->IWICBitmapFrameEncode_iface
.lpVtbl
= &IcnsEncoder_FrameVtbl
;
634 frameEncode
->encoder
= This
;
635 frameEncode
->ref
= 1;
636 frameEncode
->initialized
= FALSE
;
637 frameEncode
->size
= 0;
638 frameEncode
->icns_image
= NULL
;
639 frameEncode
->lines_written
= 0;
640 frameEncode
->committed
= FALSE
;
641 *ppIFrameEncode
= &frameEncode
->IWICBitmapFrameEncode_iface
;
642 This
->outstanding_commits
++;
643 IWICBitmapEncoder_AddRef(&This
->IWICBitmapEncoder_iface
);
646 LeaveCriticalSection(&This
->lock
);
651 static HRESULT WINAPI
IcnsEncoder_Commit(IWICBitmapEncoder
*iface
)
653 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
658 TRACE("(%p)\n", iface
);
660 EnterCriticalSection(&This
->lock
);
662 if (!This
->any_frame_committed
|| This
->outstanding_commits
> 0 || This
->committed
)
664 hr
= WINCODEC_ERR_WRONGSTATE
;
668 buffer_size
= GetHandleSize((Handle
)This
->icns_family
);
669 hr
= IStream_Write(This
->stream
, *This
->icns_family
, buffer_size
, &byteswritten
);
670 if (FAILED(hr
) || byteswritten
!= buffer_size
)
672 WARN("writing file failed, hr = 0x%08X\n", hr
);
677 This
->committed
= TRUE
;
680 LeaveCriticalSection(&This
->lock
);
684 static HRESULT WINAPI
IcnsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
685 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
687 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
691 static const IWICBitmapEncoderVtbl IcnsEncoder_Vtbl
= {
692 IcnsEncoder_QueryInterface
,
695 IcnsEncoder_Initialize
,
696 IcnsEncoder_GetContainerFormat
,
697 IcnsEncoder_GetEncoderInfo
,
698 IcnsEncoder_SetColorContexts
,
699 IcnsEncoder_SetPalette
,
700 IcnsEncoder_SetThumbnail
,
701 IcnsEncoder_SetPreview
,
702 IcnsEncoder_CreateNewFrame
,
704 IcnsEncoder_GetMetadataQueryWriter
707 HRESULT
IcnsEncoder_CreateInstance(REFIID iid
, void** ppv
)
712 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
716 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsEncoder
));
717 if (!This
) return E_OUTOFMEMORY
;
719 This
->IWICBitmapEncoder_iface
.lpVtbl
= &IcnsEncoder_Vtbl
;
722 This
->icns_family
= NULL
;
723 This
->any_frame_committed
= FALSE
;
724 This
->outstanding_commits
= 0;
725 This
->committed
= FALSE
;
726 InitializeCriticalSection(&This
->lock
);
727 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IcnsEncoder.lock");
729 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
730 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
735 #else /* !defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) ||
736 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 */
738 HRESULT
IcnsEncoder_CreateInstance(REFIID iid
, void** ppv
)
740 ERR("Trying to save ICNS picture, but ICNS support is not compiled in.\n");