2 * Copyright 2009 Vincent Povirk for CodeWeavers
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
19 #include "wincodecs_private.h"
29 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
31 #define UINT8 JPEG_UINT8
32 #define UINT16 JPEG_UINT16
33 #define boolean jpeg_boolean
37 #define HAVE_STDLIB_H 1
43 #include <wine/library.h>
46 WINE_DECLARE_DEBUG_CHANNEL(jpeg
);
48 static void *libjpeg_handle
;
50 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
51 MAKE_FUNCPTR(jpeg_CreateCompress
);
52 MAKE_FUNCPTR(jpeg_CreateDecompress
);
53 MAKE_FUNCPTR(jpeg_destroy_compress
);
54 MAKE_FUNCPTR(jpeg_destroy_decompress
);
55 MAKE_FUNCPTR(jpeg_finish_compress
);
56 MAKE_FUNCPTR(jpeg_read_header
);
57 MAKE_FUNCPTR(jpeg_read_scanlines
);
58 MAKE_FUNCPTR(jpeg_resync_to_restart
);
59 MAKE_FUNCPTR(jpeg_set_defaults
);
60 MAKE_FUNCPTR(jpeg_start_compress
);
61 MAKE_FUNCPTR(jpeg_start_decompress
);
62 MAKE_FUNCPTR(jpeg_std_error
);
63 MAKE_FUNCPTR(jpeg_write_scanlines
);
66 static void *load_libjpeg(void)
68 if((libjpeg_handle
= wine_dlopen(SONAME_LIBJPEG
, RTLD_NOW
, NULL
, 0)) != NULL
) {
70 #define LOAD_FUNCPTR(f) \
71 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
72 libjpeg_handle = NULL; \
76 LOAD_FUNCPTR(jpeg_CreateCompress
);
77 LOAD_FUNCPTR(jpeg_CreateDecompress
);
78 LOAD_FUNCPTR(jpeg_destroy_compress
);
79 LOAD_FUNCPTR(jpeg_destroy_decompress
);
80 LOAD_FUNCPTR(jpeg_finish_compress
);
81 LOAD_FUNCPTR(jpeg_read_header
);
82 LOAD_FUNCPTR(jpeg_read_scanlines
);
83 LOAD_FUNCPTR(jpeg_resync_to_restart
);
84 LOAD_FUNCPTR(jpeg_set_defaults
);
85 LOAD_FUNCPTR(jpeg_start_compress
);
86 LOAD_FUNCPTR(jpeg_start_decompress
);
87 LOAD_FUNCPTR(jpeg_std_error
);
88 LOAD_FUNCPTR(jpeg_write_scanlines
);
91 return libjpeg_handle
;
94 static void error_exit_fn(j_common_ptr cinfo
)
96 char message
[JMSG_LENGTH_MAX
];
99 cinfo
->err
->format_message(cinfo
, message
);
100 ERR_(jpeg
)("%s\n", message
);
102 longjmp(*(jmp_buf*)cinfo
->client_data
, 1);
105 static void emit_message_fn(j_common_ptr cinfo
, int msg_level
)
107 char message
[JMSG_LENGTH_MAX
];
109 if (msg_level
< 0 && ERR_ON(jpeg
))
111 cinfo
->err
->format_message(cinfo
, message
);
112 ERR_(jpeg
)("%s\n", message
);
114 else if (msg_level
== 0 && WARN_ON(jpeg
))
116 cinfo
->err
->format_message(cinfo
, message
);
117 WARN_(jpeg
)("%s\n", message
);
119 else if (msg_level
> 0 && TRACE_ON(jpeg
))
121 cinfo
->err
->format_message(cinfo
, message
);
122 TRACE_(jpeg
)("%s\n", message
);
127 IWICBitmapDecoder IWICBitmapDecoder_iface
;
128 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
131 BOOL cinfo_initialized
;
133 struct jpeg_decompress_struct cinfo
;
134 struct jpeg_error_mgr jerr
;
135 struct jpeg_source_mgr source_mgr
;
136 BYTE source_buffer
[1024];
138 CRITICAL_SECTION lock
;
141 static inline JpegDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
143 return CONTAINING_RECORD(iface
, JpegDecoder
, IWICBitmapDecoder_iface
);
146 static inline JpegDecoder
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
148 return CONTAINING_RECORD(iface
, JpegDecoder
, IWICBitmapFrameDecode_iface
);
151 static inline JpegDecoder
*decoder_from_decompress(j_decompress_ptr decompress
)
153 return CONTAINING_RECORD(decompress
, JpegDecoder
, cinfo
);
156 static HRESULT WINAPI
JpegDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
159 JpegDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
160 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
162 if (!ppv
) return E_INVALIDARG
;
164 if (IsEqualIID(&IID_IUnknown
, iid
) ||
165 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
167 *ppv
= &This
->IWICBitmapDecoder_iface
;
172 return E_NOINTERFACE
;
175 IUnknown_AddRef((IUnknown
*)*ppv
);
179 static ULONG WINAPI
JpegDecoder_AddRef(IWICBitmapDecoder
*iface
)
181 JpegDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
182 ULONG ref
= InterlockedIncrement(&This
->ref
);
184 TRACE("(%p) refcount=%u\n", iface
, ref
);
189 static ULONG WINAPI
JpegDecoder_Release(IWICBitmapDecoder
*iface
)
191 JpegDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
192 ULONG ref
= InterlockedDecrement(&This
->ref
);
194 TRACE("(%p) refcount=%u\n", iface
, ref
);
198 This
->lock
.DebugInfo
->Spare
[0] = 0;
199 DeleteCriticalSection(&This
->lock
);
200 if (This
->cinfo_initialized
) pjpeg_destroy_decompress(&This
->cinfo
);
201 if (This
->stream
) IStream_Release(This
->stream
);
202 HeapFree(GetProcessHeap(), 0, This
->image_data
);
203 HeapFree(GetProcessHeap(), 0, This
);
209 static HRESULT WINAPI
JpegDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
214 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
216 if (!stream
|| !capability
) return E_INVALIDARG
;
218 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
219 if (hr
!= S_OK
) return hr
;
221 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
222 WICBitmapDecoderCapabilityCanDecodeSomeImages
;
223 /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
227 static void source_mgr_init_source(j_decompress_ptr cinfo
)
231 static jpeg_boolean
source_mgr_fill_input_buffer(j_decompress_ptr cinfo
)
233 JpegDecoder
*This
= decoder_from_decompress(cinfo
);
237 hr
= IStream_Read(This
->stream
, This
->source_buffer
, 1024, &bytesread
);
239 if (hr
!= S_OK
|| bytesread
== 0)
245 This
->source_mgr
.next_input_byte
= This
->source_buffer
;
246 This
->source_mgr
.bytes_in_buffer
= bytesread
;
251 static void source_mgr_skip_input_data(j_decompress_ptr cinfo
, long num_bytes
)
253 JpegDecoder
*This
= decoder_from_decompress(cinfo
);
256 if (num_bytes
> This
->source_mgr
.bytes_in_buffer
)
258 seek
.QuadPart
= num_bytes
- This
->source_mgr
.bytes_in_buffer
;
259 IStream_Seek(This
->stream
, seek
, STREAM_SEEK_CUR
, NULL
);
260 This
->source_mgr
.bytes_in_buffer
= 0;
262 else if (num_bytes
> 0)
264 This
->source_mgr
.next_input_byte
+= num_bytes
;
265 This
->source_mgr
.bytes_in_buffer
-= num_bytes
;
269 static void source_mgr_term_source(j_decompress_ptr cinfo
)
273 static HRESULT WINAPI
JpegDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
274 WICDecodeOptions cacheOptions
)
276 JpegDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
280 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOptions
);
282 EnterCriticalSection(&This
->lock
);
284 if (This
->cinfo_initialized
)
286 LeaveCriticalSection(&This
->lock
);
287 return WINCODEC_ERR_WRONGSTATE
;
290 pjpeg_std_error(&This
->jerr
);
292 This
->jerr
.error_exit
= error_exit_fn
;
293 This
->jerr
.emit_message
= emit_message_fn
;
295 This
->cinfo
.err
= &This
->jerr
;
297 This
->cinfo
.client_data
= jmpbuf
;
301 LeaveCriticalSection(&This
->lock
);
305 pjpeg_CreateDecompress(&This
->cinfo
, JPEG_LIB_VERSION
, sizeof(struct jpeg_decompress_struct
));
307 This
->cinfo_initialized
= TRUE
;
309 This
->stream
= pIStream
;
310 IStream_AddRef(pIStream
);
313 IStream_Seek(This
->stream
, seek
, STREAM_SEEK_SET
, NULL
);
315 This
->source_mgr
.bytes_in_buffer
= 0;
316 This
->source_mgr
.init_source
= source_mgr_init_source
;
317 This
->source_mgr
.fill_input_buffer
= source_mgr_fill_input_buffer
;
318 This
->source_mgr
.skip_input_data
= source_mgr_skip_input_data
;
319 This
->source_mgr
.resync_to_restart
= pjpeg_resync_to_restart
;
320 This
->source_mgr
.term_source
= source_mgr_term_source
;
322 This
->cinfo
.src
= &This
->source_mgr
;
324 ret
= pjpeg_read_header(&This
->cinfo
, TRUE
);
326 if (ret
!= JPEG_HEADER_OK
) {
327 WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret
);
328 LeaveCriticalSection(&This
->lock
);
332 switch (This
->cinfo
.jpeg_color_space
)
335 This
->cinfo
.out_color_space
= JCS_GRAYSCALE
;
339 This
->cinfo
.out_color_space
= JCS_RGB
;
343 This
->cinfo
.out_color_space
= JCS_CMYK
;
346 ERR("Unknown JPEG color space %i\n", This
->cinfo
.jpeg_color_space
);
347 LeaveCriticalSection(&This
->lock
);
351 if (!pjpeg_start_decompress(&This
->cinfo
))
353 ERR("jpeg_start_decompress failed\n");
354 LeaveCriticalSection(&This
->lock
);
358 This
->initialized
= TRUE
;
360 LeaveCriticalSection(&This
->lock
);
365 static HRESULT WINAPI
JpegDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
366 GUID
*pguidContainerFormat
)
368 memcpy(pguidContainerFormat
, &GUID_ContainerFormatJpeg
, sizeof(GUID
));
372 static HRESULT WINAPI
JpegDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
373 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
376 IWICComponentInfo
*compinfo
;
378 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
380 hr
= CreateComponentInfo(&CLSID_WICJpegDecoder
, &compinfo
);
381 if (FAILED(hr
)) return hr
;
383 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
384 (void**)ppIDecoderInfo
);
386 IWICComponentInfo_Release(compinfo
);
391 static HRESULT WINAPI
JpegDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
392 IWICPalette
*pIPalette
)
394 TRACE("(%p,%p)\n", iface
, pIPalette
);
396 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
399 static HRESULT WINAPI
JpegDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
400 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
402 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
406 static HRESULT WINAPI
JpegDecoder_GetPreview(IWICBitmapDecoder
*iface
,
407 IWICBitmapSource
**ppIBitmapSource
)
409 FIXME("(%p,%p): stub\n", iface
, ppIBitmapSource
);
410 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
413 static HRESULT WINAPI
JpegDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
414 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
416 FIXME("(%p,%u,%p,%p): stub\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
417 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
420 static HRESULT WINAPI
JpegDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
421 IWICBitmapSource
**ppIThumbnail
)
423 FIXME("(%p,%p): stub\n", iface
, ppIThumbnail
);
424 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
427 static HRESULT WINAPI
JpegDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
430 if (!pCount
) return E_INVALIDARG
;
436 static HRESULT WINAPI
JpegDecoder_GetFrame(IWICBitmapDecoder
*iface
,
437 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
439 JpegDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
440 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
442 if (!This
->initialized
) return WINCODEC_ERR_FRAMEMISSING
;
444 if (index
!= 0) return E_INVALIDARG
;
446 IWICBitmapDecoder_AddRef(iface
);
447 *ppIBitmapFrame
= &This
->IWICBitmapFrameDecode_iface
;
452 static const IWICBitmapDecoderVtbl JpegDecoder_Vtbl
= {
453 JpegDecoder_QueryInterface
,
456 JpegDecoder_QueryCapability
,
457 JpegDecoder_Initialize
,
458 JpegDecoder_GetContainerFormat
,
459 JpegDecoder_GetDecoderInfo
,
460 JpegDecoder_CopyPalette
,
461 JpegDecoder_GetMetadataQueryReader
,
462 JpegDecoder_GetPreview
,
463 JpegDecoder_GetColorContexts
,
464 JpegDecoder_GetThumbnail
,
465 JpegDecoder_GetFrameCount
,
469 static HRESULT WINAPI
JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
472 JpegDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
474 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
476 if (!ppv
) return E_INVALIDARG
;
478 if (IsEqualIID(&IID_IUnknown
, iid
) ||
479 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
480 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
482 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
487 return E_NOINTERFACE
;
490 IUnknown_AddRef((IUnknown
*)*ppv
);
494 static ULONG WINAPI
JpegDecoder_Frame_AddRef(IWICBitmapFrameDecode
*iface
)
496 JpegDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
497 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
500 static ULONG WINAPI
JpegDecoder_Frame_Release(IWICBitmapFrameDecode
*iface
)
502 JpegDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
503 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
506 static HRESULT WINAPI
JpegDecoder_Frame_GetSize(IWICBitmapFrameDecode
*iface
,
507 UINT
*puiWidth
, UINT
*puiHeight
)
509 JpegDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
510 *puiWidth
= This
->cinfo
.output_width
;
511 *puiHeight
= This
->cinfo
.output_height
;
512 TRACE("(%p)->(%u,%u)\n", iface
, *puiWidth
, *puiHeight
);
516 static HRESULT WINAPI
JpegDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
517 WICPixelFormatGUID
*pPixelFormat
)
519 JpegDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
520 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
521 if (This
->cinfo
.out_color_space
== JCS_RGB
)
522 memcpy(pPixelFormat
, &GUID_WICPixelFormat24bppBGR
, sizeof(GUID
));
523 else if (This
->cinfo
.out_color_space
== JCS_CMYK
)
524 memcpy(pPixelFormat
, &GUID_WICPixelFormat32bppCMYK
, sizeof(GUID
));
525 else /* This->cinfo.out_color_space == JCS_GRAYSCALE */
526 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppGray
, sizeof(GUID
));
530 static HRESULT WINAPI
JpegDecoder_Frame_GetResolution(IWICBitmapFrameDecode
*iface
,
531 double *pDpiX
, double *pDpiY
)
533 JpegDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
535 EnterCriticalSection(&This
->lock
);
537 switch (This
->cinfo
.density_unit
)
539 case 2: /* pixels per centimeter */
540 *pDpiX
= This
->cinfo
.X_density
* 2.54;
541 *pDpiY
= This
->cinfo
.Y_density
* 2.54;
544 case 1: /* pixels per inch */
545 *pDpiX
= This
->cinfo
.X_density
;
546 *pDpiY
= This
->cinfo
.Y_density
;
549 case 0: /* unknown */
556 LeaveCriticalSection(&This
->lock
);
558 TRACE("(%p)->(%0.2f,%0.2f)\n", iface
, *pDpiX
, *pDpiY
);
563 static HRESULT WINAPI
JpegDecoder_Frame_CopyPalette(IWICBitmapFrameDecode
*iface
,
564 IWICPalette
*pIPalette
)
566 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
570 static HRESULT WINAPI
JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode
*iface
,
571 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
573 JpegDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
580 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
586 rect
.Width
= This
->cinfo
.output_width
;
587 rect
.Height
= This
->cinfo
.output_height
;
592 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->cinfo
.output_width
||
593 prc
->Y
+prc
->Height
> This
->cinfo
.output_height
)
597 if (This
->cinfo
.out_color_space
== JCS_GRAYSCALE
) bpp
= 8;
598 else if (This
->cinfo
.out_color_space
== JCS_CMYK
) bpp
= 32;
601 stride
= bpp
* This
->cinfo
.output_width
;
602 data_size
= stride
* This
->cinfo
.output_height
;
604 max_row_needed
= prc
->Y
+ prc
->Height
;
605 if (max_row_needed
> This
->cinfo
.output_height
) return E_INVALIDARG
;
607 EnterCriticalSection(&This
->lock
);
609 if (!This
->image_data
)
611 This
->image_data
= HeapAlloc(GetProcessHeap(), 0, data_size
);
612 if (!This
->image_data
)
614 LeaveCriticalSection(&This
->lock
);
615 return E_OUTOFMEMORY
;
619 This
->cinfo
.client_data
= jmpbuf
;
623 LeaveCriticalSection(&This
->lock
);
627 while (max_row_needed
> This
->cinfo
.output_scanline
)
629 UINT first_scanline
= This
->cinfo
.output_scanline
;
631 JSAMPROW out_rows
[4];
635 max_rows
= min(This
->cinfo
.output_height
-first_scanline
, 4);
636 for (i
=0; i
<max_rows
; i
++)
637 out_rows
[i
] = This
->image_data
+ stride
* (first_scanline
+i
);
639 ret
= pjpeg_read_scanlines(&This
->cinfo
, out_rows
, max_rows
);
643 ERR("read_scanlines failed\n");
644 LeaveCriticalSection(&This
->lock
);
650 /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
651 reverse_bgr8(3, This
->image_data
+ stride
* first_scanline
,
652 This
->cinfo
.output_width
, This
->cinfo
.output_scanline
- first_scanline
,
656 if (This
->cinfo
.out_color_space
== JCS_CMYK
&& This
->cinfo
.saw_Adobe_marker
)
657 /* Adobe JPEG's have inverted CMYK data. */
658 for (i
=0; i
<data_size
; i
++)
659 This
->image_data
[i
] ^= 0xff;
662 LeaveCriticalSection(&This
->lock
);
664 return copy_pixels(bpp
, This
->image_data
,
665 This
->cinfo
.output_width
, This
->cinfo
.output_height
, stride
,
666 prc
, cbStride
, cbBufferSize
, pbBuffer
);
669 static HRESULT WINAPI
JpegDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
670 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
672 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
673 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
676 static HRESULT WINAPI
JpegDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode
*iface
,
677 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
679 FIXME("(%p,%u,%p,%p): stub\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
680 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
683 static HRESULT WINAPI
JpegDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode
*iface
,
684 IWICBitmapSource
**ppIThumbnail
)
686 FIXME("(%p,%p): stub\n", iface
, ppIThumbnail
);
687 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
690 static const IWICBitmapFrameDecodeVtbl JpegDecoder_Frame_Vtbl
= {
691 JpegDecoder_Frame_QueryInterface
,
692 JpegDecoder_Frame_AddRef
,
693 JpegDecoder_Frame_Release
,
694 JpegDecoder_Frame_GetSize
,
695 JpegDecoder_Frame_GetPixelFormat
,
696 JpegDecoder_Frame_GetResolution
,
697 JpegDecoder_Frame_CopyPalette
,
698 JpegDecoder_Frame_CopyPixels
,
699 JpegDecoder_Frame_GetMetadataQueryReader
,
700 JpegDecoder_Frame_GetColorContexts
,
701 JpegDecoder_Frame_GetThumbnail
704 HRESULT
JpegDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
709 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
711 if (!libjpeg_handle
&& !load_libjpeg())
713 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG
);
719 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
721 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(JpegDecoder
));
722 if (!This
) return E_OUTOFMEMORY
;
724 This
->IWICBitmapDecoder_iface
.lpVtbl
= &JpegDecoder_Vtbl
;
725 This
->IWICBitmapFrameDecode_iface
.lpVtbl
= &JpegDecoder_Frame_Vtbl
;
727 This
->initialized
= FALSE
;
728 This
->cinfo_initialized
= FALSE
;
730 This
->image_data
= NULL
;
731 InitializeCriticalSection(&This
->lock
);
732 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": JpegDecoder.lock");
734 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
735 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
740 typedef struct jpeg_compress_format
{
741 const WICPixelFormatGUID
*guid
;
744 J_COLOR_SPACE color_space
;
746 } jpeg_compress_format
;
748 static const jpeg_compress_format compress_formats
[] = {
749 { &GUID_WICPixelFormat24bppBGR
, 24, 3, JCS_RGB
, 1 },
750 { &GUID_WICPixelFormat32bppCMYK
, 32, 4, JCS_CMYK
},
751 { &GUID_WICPixelFormat8bppGray
, 8, 1, JCS_GRAYSCALE
},
755 typedef struct JpegEncoder
{
756 IWICBitmapEncoder IWICBitmapEncoder_iface
;
757 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
759 struct jpeg_compress_struct cinfo
;
760 struct jpeg_error_mgr jerr
;
761 struct jpeg_destination_mgr dest_mgr
;
764 int frame_initialized
;
765 int started_compress
;
771 const jpeg_compress_format
*format
;
773 CRITICAL_SECTION lock
;
774 BYTE dest_buffer
[1024];
777 static inline JpegEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
779 return CONTAINING_RECORD(iface
, JpegEncoder
, IWICBitmapEncoder_iface
);
782 static inline JpegEncoder
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
784 return CONTAINING_RECORD(iface
, JpegEncoder
, IWICBitmapFrameEncode_iface
);
787 static inline JpegEncoder
*encoder_from_compress(j_compress_ptr compress
)
789 return CONTAINING_RECORD(compress
, JpegEncoder
, cinfo
);
792 static void dest_mgr_init_destination(j_compress_ptr cinfo
)
794 JpegEncoder
*This
= encoder_from_compress(cinfo
);
796 This
->dest_mgr
.next_output_byte
= This
->dest_buffer
;
797 This
->dest_mgr
.free_in_buffer
= sizeof(This
->dest_buffer
);
800 static jpeg_boolean
dest_mgr_empty_output_buffer(j_compress_ptr cinfo
)
802 JpegEncoder
*This
= encoder_from_compress(cinfo
);
806 hr
= IStream_Write(This
->stream
, This
->dest_buffer
,
807 sizeof(This
->dest_buffer
), &byteswritten
);
809 if (hr
!= S_OK
|| byteswritten
== 0)
811 ERR("Failed writing data, hr=%x\n", hr
);
815 This
->dest_mgr
.next_output_byte
= This
->dest_buffer
;
816 This
->dest_mgr
.free_in_buffer
= sizeof(This
->dest_buffer
);
820 static void dest_mgr_term_destination(j_compress_ptr cinfo
)
822 JpegEncoder
*This
= encoder_from_compress(cinfo
);
826 if (This
->dest_mgr
.free_in_buffer
!= sizeof(This
->dest_buffer
))
828 hr
= IStream_Write(This
->stream
, This
->dest_buffer
,
829 sizeof(This
->dest_buffer
) - This
->dest_mgr
.free_in_buffer
, &byteswritten
);
831 if (hr
!= S_OK
|| byteswritten
== 0)
832 ERR("Failed writing data, hr=%x\n", hr
);
836 static HRESULT WINAPI
JpegEncoder_Frame_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
839 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
840 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
842 if (!ppv
) return E_INVALIDARG
;
844 if (IsEqualIID(&IID_IUnknown
, iid
) ||
845 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
847 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
852 return E_NOINTERFACE
;
855 IUnknown_AddRef((IUnknown
*)*ppv
);
859 static ULONG WINAPI
JpegEncoder_Frame_AddRef(IWICBitmapFrameEncode
*iface
)
861 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
862 return IWICBitmapEncoder_AddRef(&This
->IWICBitmapEncoder_iface
);
865 static ULONG WINAPI
JpegEncoder_Frame_Release(IWICBitmapFrameEncode
*iface
)
867 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
868 return IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
871 static HRESULT WINAPI
JpegEncoder_Frame_Initialize(IWICBitmapFrameEncode
*iface
,
872 IPropertyBag2
*pIEncoderOptions
)
874 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
875 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
877 EnterCriticalSection(&This
->lock
);
879 if (This
->frame_initialized
)
881 LeaveCriticalSection(&This
->lock
);
882 return WINCODEC_ERR_WRONGSTATE
;
885 This
->frame_initialized
= TRUE
;
887 LeaveCriticalSection(&This
->lock
);
892 static HRESULT WINAPI
JpegEncoder_Frame_SetSize(IWICBitmapFrameEncode
*iface
,
893 UINT uiWidth
, UINT uiHeight
)
895 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
896 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
898 EnterCriticalSection(&This
->lock
);
900 if (!This
->frame_initialized
|| This
->started_compress
)
902 LeaveCriticalSection(&This
->lock
);
903 return WINCODEC_ERR_WRONGSTATE
;
906 This
->width
= uiWidth
;
907 This
->height
= uiHeight
;
909 LeaveCriticalSection(&This
->lock
);
914 static HRESULT WINAPI
JpegEncoder_Frame_SetResolution(IWICBitmapFrameEncode
*iface
,
915 double dpiX
, double dpiY
)
917 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
918 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
920 EnterCriticalSection(&This
->lock
);
922 if (!This
->frame_initialized
|| This
->started_compress
)
924 LeaveCriticalSection(&This
->lock
);
925 return WINCODEC_ERR_WRONGSTATE
;
931 LeaveCriticalSection(&This
->lock
);
936 static HRESULT WINAPI
JpegEncoder_Frame_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
937 WICPixelFormatGUID
*pPixelFormat
)
939 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
941 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
943 EnterCriticalSection(&This
->lock
);
945 if (!This
->frame_initialized
|| This
->started_compress
)
947 LeaveCriticalSection(&This
->lock
);
948 return WINCODEC_ERR_WRONGSTATE
;
951 for (i
=0; compress_formats
[i
].guid
; i
++)
953 if (memcmp(compress_formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
957 if (!compress_formats
[i
].guid
) i
= 0;
959 This
->format
= &compress_formats
[i
];
960 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
962 LeaveCriticalSection(&This
->lock
);
967 static HRESULT WINAPI
JpegEncoder_Frame_SetColorContexts(IWICBitmapFrameEncode
*iface
,
968 UINT cCount
, IWICColorContext
**ppIColorContext
)
970 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
974 static HRESULT WINAPI
JpegEncoder_Frame_SetPalette(IWICBitmapFrameEncode
*iface
,
975 IWICPalette
*pIPalette
)
977 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
978 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
981 static HRESULT WINAPI
JpegEncoder_Frame_SetThumbnail(IWICBitmapFrameEncode
*iface
,
982 IWICBitmapSource
*pIThumbnail
)
984 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
985 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
988 static HRESULT WINAPI
JpegEncoder_Frame_WritePixels(IWICBitmapFrameEncode
*iface
,
989 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
991 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
993 BYTE
*swapped_data
= NULL
, *current_row
;
996 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
998 EnterCriticalSection(&This
->lock
);
1000 if (!This
->frame_initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1002 LeaveCriticalSection(&This
->lock
);
1003 return WINCODEC_ERR_WRONGSTATE
;
1006 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1008 LeaveCriticalSection(&This
->lock
);
1009 return E_INVALIDARG
;
1012 /* set up setjmp/longjmp error handling */
1015 LeaveCriticalSection(&This
->lock
);
1016 HeapFree(GetProcessHeap(), 0, swapped_data
);
1019 This
->cinfo
.client_data
= jmpbuf
;
1021 if (!This
->started_compress
)
1023 This
->cinfo
.image_width
= This
->width
;
1024 This
->cinfo
.image_height
= This
->height
;
1025 This
->cinfo
.input_components
= This
->format
->num_components
;
1026 This
->cinfo
.in_color_space
= This
->format
->color_space
;
1028 pjpeg_set_defaults(&This
->cinfo
);
1030 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1032 This
->cinfo
.density_unit
= 1; /* dots per inch */
1033 This
->cinfo
.X_density
= This
->xres
;
1034 This
->cinfo
.Y_density
= This
->yres
;
1037 pjpeg_start_compress(&This
->cinfo
, TRUE
);
1039 This
->started_compress
= 1;
1042 row_size
= This
->format
->bpp
/ 8 * This
->width
;
1044 if (This
->format
->swap_rgb
)
1046 swapped_data
= HeapAlloc(GetProcessHeap(), 0, row_size
);
1049 LeaveCriticalSection(&This
->lock
);
1050 return E_OUTOFMEMORY
;
1054 for (line
=0; line
< lineCount
; line
++)
1056 if (This
->format
->swap_rgb
)
1060 memcpy(swapped_data
, pbPixels
+ (cbStride
* line
), row_size
);
1062 for (x
=0; x
< This
->width
; x
++)
1066 b
= swapped_data
[x
*3];
1067 swapped_data
[x
*3] = swapped_data
[x
*3+2];
1068 swapped_data
[x
*3+2] = b
;
1071 current_row
= swapped_data
;
1074 current_row
= pbPixels
+ (cbStride
* line
);
1076 if (!pjpeg_write_scanlines(&This
->cinfo
, ¤t_row
, 1))
1078 ERR("failed writing scanlines\n");
1079 LeaveCriticalSection(&This
->lock
);
1080 HeapFree(GetProcessHeap(), 0, swapped_data
);
1084 This
->lines_written
++;
1087 LeaveCriticalSection(&This
->lock
);
1088 HeapFree(GetProcessHeap(), 0, swapped_data
);
1093 static HRESULT WINAPI
JpegEncoder_Frame_WriteSource(IWICBitmapFrameEncode
*iface
,
1094 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1096 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1099 WICPixelFormatGUID guid
;
1102 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1104 if (!This
->frame_initialized
|| !This
->width
|| !This
->height
)
1105 return WINCODEC_ERR_WRONGSTATE
;
1109 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1110 if (FAILED(hr
)) return hr
;
1111 hr
= IWICBitmapFrameEncode_SetPixelFormat(iface
, &guid
);
1112 if (FAILED(hr
)) return hr
;
1115 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1116 if (FAILED(hr
)) return hr
;
1117 if (memcmp(&guid
, This
->format
->guid
, sizeof(GUID
)) != 0)
1119 /* FIXME: should use WICConvertBitmapSource to convert */
1120 ERR("format %s unsupported\n", debugstr_guid(&guid
));
1124 if (This
->xres
== 0.0 || This
->yres
== 0.0)
1127 hr
= IWICBitmapSource_GetResolution(pIBitmapSource
, &xres
, &yres
);
1128 if (FAILED(hr
)) return hr
;
1129 hr
= IWICBitmapFrameEncode_SetResolution(iface
, xres
, yres
);
1130 if (FAILED(hr
)) return hr
;
1136 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
1137 if (FAILED(hr
)) return hr
;
1145 if (prc
->Width
!= This
->width
) return E_INVALIDARG
;
1147 stride
= (This
->format
->bpp
* This
->width
+ 7)/8;
1149 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
1150 if (!pixeldata
) return E_OUTOFMEMORY
;
1152 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
1153 stride
*prc
->Height
, pixeldata
);
1157 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
1158 stride
*prc
->Height
, pixeldata
);
1161 HeapFree(GetProcessHeap(), 0, pixeldata
);
1166 static HRESULT WINAPI
JpegEncoder_Frame_Commit(IWICBitmapFrameEncode
*iface
)
1168 JpegEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1170 TRACE("(%p)\n", iface
);
1172 EnterCriticalSection(&This
->lock
);
1174 if (!This
->started_compress
|| This
->lines_written
!= This
->height
|| This
->frame_committed
)
1176 LeaveCriticalSection(&This
->lock
);
1177 return WINCODEC_ERR_WRONGSTATE
;
1180 /* set up setjmp/longjmp error handling */
1183 LeaveCriticalSection(&This
->lock
);
1186 This
->cinfo
.client_data
= jmpbuf
;
1188 pjpeg_finish_compress(&This
->cinfo
);
1190 This
->frame_committed
= TRUE
;
1192 LeaveCriticalSection(&This
->lock
);
1197 static HRESULT WINAPI
JpegEncoder_Frame_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1198 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1200 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1204 static const IWICBitmapFrameEncodeVtbl JpegEncoder_FrameVtbl
= {
1205 JpegEncoder_Frame_QueryInterface
,
1206 JpegEncoder_Frame_AddRef
,
1207 JpegEncoder_Frame_Release
,
1208 JpegEncoder_Frame_Initialize
,
1209 JpegEncoder_Frame_SetSize
,
1210 JpegEncoder_Frame_SetResolution
,
1211 JpegEncoder_Frame_SetPixelFormat
,
1212 JpegEncoder_Frame_SetColorContexts
,
1213 JpegEncoder_Frame_SetPalette
,
1214 JpegEncoder_Frame_SetThumbnail
,
1215 JpegEncoder_Frame_WritePixels
,
1216 JpegEncoder_Frame_WriteSource
,
1217 JpegEncoder_Frame_Commit
,
1218 JpegEncoder_Frame_GetMetadataQueryWriter
1221 static HRESULT WINAPI
JpegEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1224 JpegEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1225 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1227 if (!ppv
) return E_INVALIDARG
;
1229 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1230 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1232 *ppv
= &This
->IWICBitmapEncoder_iface
;
1237 return E_NOINTERFACE
;
1240 IUnknown_AddRef((IUnknown
*)*ppv
);
1244 static ULONG WINAPI
JpegEncoder_AddRef(IWICBitmapEncoder
*iface
)
1246 JpegEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1247 ULONG ref
= InterlockedIncrement(&This
->ref
);
1249 TRACE("(%p) refcount=%u\n", iface
, ref
);
1254 static ULONG WINAPI
JpegEncoder_Release(IWICBitmapEncoder
*iface
)
1256 JpegEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1257 ULONG ref
= InterlockedDecrement(&This
->ref
);
1259 TRACE("(%p) refcount=%u\n", iface
, ref
);
1263 This
->lock
.DebugInfo
->Spare
[0] = 0;
1264 DeleteCriticalSection(&This
->lock
);
1265 if (This
->initialized
) pjpeg_destroy_compress(&This
->cinfo
);
1266 if (This
->stream
) IStream_Release(This
->stream
);
1267 HeapFree(GetProcessHeap(), 0, This
);
1273 static HRESULT WINAPI
JpegEncoder_Initialize(IWICBitmapEncoder
*iface
,
1274 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1276 JpegEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1279 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1281 EnterCriticalSection(&This
->lock
);
1283 if (This
->initialized
)
1285 LeaveCriticalSection(&This
->lock
);
1286 return WINCODEC_ERR_WRONGSTATE
;
1289 pjpeg_std_error(&This
->jerr
);
1291 This
->jerr
.error_exit
= error_exit_fn
;
1292 This
->jerr
.emit_message
= emit_message_fn
;
1294 This
->cinfo
.err
= &This
->jerr
;
1296 This
->cinfo
.client_data
= jmpbuf
;
1300 LeaveCriticalSection(&This
->lock
);
1304 pjpeg_CreateCompress(&This
->cinfo
, JPEG_LIB_VERSION
, sizeof(struct jpeg_compress_struct
));
1306 This
->stream
= pIStream
;
1307 IStream_AddRef(pIStream
);
1309 This
->dest_mgr
.next_output_byte
= This
->dest_buffer
;
1310 This
->dest_mgr
.free_in_buffer
= sizeof(This
->dest_buffer
);
1312 This
->dest_mgr
.init_destination
= dest_mgr_init_destination
;
1313 This
->dest_mgr
.empty_output_buffer
= dest_mgr_empty_output_buffer
;
1314 This
->dest_mgr
.term_destination
= dest_mgr_term_destination
;
1316 This
->cinfo
.dest
= &This
->dest_mgr
;
1318 This
->initialized
= TRUE
;
1320 LeaveCriticalSection(&This
->lock
);
1325 static HRESULT WINAPI
JpegEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1326 GUID
*pguidContainerFormat
)
1328 FIXME("(%p,%s): stub\n", iface
, debugstr_guid(pguidContainerFormat
));
1332 static HRESULT WINAPI
JpegEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1333 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1335 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1339 static HRESULT WINAPI
JpegEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1340 UINT cCount
, IWICColorContext
**ppIColorContext
)
1342 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1346 static HRESULT WINAPI
JpegEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
1348 TRACE("(%p,%p)\n", iface
, pIPalette
);
1349 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1352 static HRESULT WINAPI
JpegEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1354 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1355 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1358 static HRESULT WINAPI
JpegEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1360 TRACE("(%p,%p)\n", iface
, pIPreview
);
1361 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1364 static HRESULT WINAPI
JpegEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1365 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1367 JpegEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1370 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1372 EnterCriticalSection(&This
->lock
);
1374 if (This
->frame_count
!= 0)
1376 LeaveCriticalSection(&This
->lock
);
1377 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1380 if (!This
->initialized
)
1382 LeaveCriticalSection(&This
->lock
);
1383 return WINCODEC_ERR_NOTINITIALIZED
;
1386 hr
= CreatePropertyBag2(NULL
, 0, ppIEncoderOptions
);
1389 LeaveCriticalSection(&This
->lock
);
1393 This
->frame_count
= 1;
1395 LeaveCriticalSection(&This
->lock
);
1397 IWICBitmapEncoder_AddRef(iface
);
1398 *ppIFrameEncode
= &This
->IWICBitmapFrameEncode_iface
;
1403 static HRESULT WINAPI
JpegEncoder_Commit(IWICBitmapEncoder
*iface
)
1405 JpegEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1406 TRACE("(%p)\n", iface
);
1408 EnterCriticalSection(&This
->lock
);
1410 if (!This
->frame_committed
|| This
->committed
)
1412 LeaveCriticalSection(&This
->lock
);
1413 return WINCODEC_ERR_WRONGSTATE
;
1416 This
->committed
= TRUE
;
1418 LeaveCriticalSection(&This
->lock
);
1423 static HRESULT WINAPI
JpegEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
1424 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1426 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
1430 static const IWICBitmapEncoderVtbl JpegEncoder_Vtbl
= {
1431 JpegEncoder_QueryInterface
,
1433 JpegEncoder_Release
,
1434 JpegEncoder_Initialize
,
1435 JpegEncoder_GetContainerFormat
,
1436 JpegEncoder_GetEncoderInfo
,
1437 JpegEncoder_SetColorContexts
,
1438 JpegEncoder_SetPalette
,
1439 JpegEncoder_SetThumbnail
,
1440 JpegEncoder_SetPreview
,
1441 JpegEncoder_CreateNewFrame
,
1443 JpegEncoder_GetMetadataQueryWriter
1446 HRESULT
JpegEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1451 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1455 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1457 if (!libjpeg_handle
&& !load_libjpeg())
1459 ERR("Failed writing JPEG because unable to find %s\n",SONAME_LIBJPEG
);
1463 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(JpegEncoder
));
1464 if (!This
) return E_OUTOFMEMORY
;
1466 This
->IWICBitmapEncoder_iface
.lpVtbl
= &JpegEncoder_Vtbl
;
1467 This
->IWICBitmapFrameEncode_iface
.lpVtbl
= &JpegEncoder_FrameVtbl
;
1469 This
->initialized
= 0;
1470 This
->frame_count
= 0;
1471 This
->frame_initialized
= 0;
1472 This
->started_compress
= 0;
1473 This
->lines_written
= 0;
1474 This
->frame_committed
= 0;
1475 This
->committed
= 0;
1476 This
->width
= This
->height
= 0;
1477 This
->xres
= This
->yres
= 0.0;
1478 This
->format
= NULL
;
1479 This
->stream
= NULL
;
1480 InitializeCriticalSection(&This
->lock
);
1481 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": JpegEncoder.lock");
1483 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
1484 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
1489 #else /* !defined(SONAME_LIBJPEG) */
1491 HRESULT
JpegDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1493 ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
1497 HRESULT
JpegEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1499 ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n");