makefiles: Explicitly create destination dirs when installing symlinks.
[wine/zf.git] / dlls / windowscodecs / jpegformat.c
blobe04e914cda1ed9db77ec2181f0ec581ee7eef6ae
1 /*
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 "config.h"
20 #include "wine/port.h"
22 #ifdef HAVE_UNISTD_H
23 # include <unistd.h>
24 #endif
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <setjmp.h>
30 #ifdef SONAME_LIBJPEG
31 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
32 #define XMD_H
33 #define UINT8 JPEG_UINT8
34 #define UINT16 JPEG_UINT16
35 #define boolean jpeg_boolean
36 #undef HAVE_STDLIB_H
37 # include <jpeglib.h>
38 #undef HAVE_STDLIB_H
39 #define HAVE_STDLIB_H 1
40 #undef UINT8
41 #undef UINT16
42 #undef boolean
43 #endif
45 #define COBJMACROS
47 #include "windef.h"
48 #include "winbase.h"
49 #include "objbase.h"
51 #include "wincodecs_private.h"
53 #include "wine/heap.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
58 #ifdef SONAME_LIBJPEG
59 WINE_DECLARE_DEBUG_CHANNEL(jpeg);
61 static void *libjpeg_handle;
63 static const WCHAR wszImageQuality[] = {'I','m','a','g','e','Q','u','a','l','i','t','y',0};
64 static const WCHAR wszBitmapTransform[] = {'B','i','t','m','a','p','T','r','a','n','s','f','o','r','m',0};
65 static const WCHAR wszLuminance[] = {'L','u','m','i','n','a','n','c','e',0};
66 static const WCHAR wszChrominance[] = {'C','h','r','o','m','i','n','a','n','c','e',0};
67 static const WCHAR wszJpegYCrCbSubsampling[] = {'J','p','e','g','Y','C','r','C','b','S','u','b','s','a','m','p','l','i','n','g',0};
68 static const WCHAR wszSuppressApp0[] = {'S','u','p','p','r','e','s','s','A','p','p','0',0};
70 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
71 MAKE_FUNCPTR(jpeg_CreateCompress);
72 MAKE_FUNCPTR(jpeg_CreateDecompress);
73 MAKE_FUNCPTR(jpeg_destroy_compress);
74 MAKE_FUNCPTR(jpeg_destroy_decompress);
75 MAKE_FUNCPTR(jpeg_finish_compress);
76 MAKE_FUNCPTR(jpeg_read_header);
77 MAKE_FUNCPTR(jpeg_read_scanlines);
78 MAKE_FUNCPTR(jpeg_resync_to_restart);
79 MAKE_FUNCPTR(jpeg_set_defaults);
80 MAKE_FUNCPTR(jpeg_start_compress);
81 MAKE_FUNCPTR(jpeg_start_decompress);
82 MAKE_FUNCPTR(jpeg_std_error);
83 MAKE_FUNCPTR(jpeg_write_scanlines);
84 #undef MAKE_FUNCPTR
86 static void *load_libjpeg(void)
88 if((libjpeg_handle = dlopen(SONAME_LIBJPEG, RTLD_NOW)) != NULL) {
90 #define LOAD_FUNCPTR(f) \
91 if((p##f = dlsym(libjpeg_handle, #f)) == NULL) { \
92 libjpeg_handle = NULL; \
93 return NULL; \
96 LOAD_FUNCPTR(jpeg_CreateCompress);
97 LOAD_FUNCPTR(jpeg_CreateDecompress);
98 LOAD_FUNCPTR(jpeg_destroy_compress);
99 LOAD_FUNCPTR(jpeg_destroy_decompress);
100 LOAD_FUNCPTR(jpeg_finish_compress);
101 LOAD_FUNCPTR(jpeg_read_header);
102 LOAD_FUNCPTR(jpeg_read_scanlines);
103 LOAD_FUNCPTR(jpeg_resync_to_restart);
104 LOAD_FUNCPTR(jpeg_set_defaults);
105 LOAD_FUNCPTR(jpeg_start_compress);
106 LOAD_FUNCPTR(jpeg_start_decompress);
107 LOAD_FUNCPTR(jpeg_std_error);
108 LOAD_FUNCPTR(jpeg_write_scanlines);
109 #undef LOAD_FUNCPTR
111 return libjpeg_handle;
114 static void error_exit_fn(j_common_ptr cinfo)
116 char message[JMSG_LENGTH_MAX];
117 if (ERR_ON(jpeg))
119 cinfo->err->format_message(cinfo, message);
120 ERR_(jpeg)("%s\n", message);
122 longjmp(*(jmp_buf*)cinfo->client_data, 1);
125 static void emit_message_fn(j_common_ptr cinfo, int msg_level)
127 char message[JMSG_LENGTH_MAX];
129 if (msg_level < 0 && ERR_ON(jpeg))
131 cinfo->err->format_message(cinfo, message);
132 ERR_(jpeg)("%s\n", message);
134 else if (msg_level == 0 && WARN_ON(jpeg))
136 cinfo->err->format_message(cinfo, message);
137 WARN_(jpeg)("%s\n", message);
139 else if (msg_level > 0 && TRACE_ON(jpeg))
141 cinfo->err->format_message(cinfo, message);
142 TRACE_(jpeg)("%s\n", message);
146 typedef struct {
147 IWICBitmapDecoder IWICBitmapDecoder_iface;
148 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
149 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
150 LONG ref;
151 BOOL initialized;
152 BOOL cinfo_initialized;
153 IStream *stream;
154 struct jpeg_decompress_struct cinfo;
155 struct jpeg_error_mgr jerr;
156 struct jpeg_source_mgr source_mgr;
157 BYTE source_buffer[1024];
158 UINT bpp, stride;
159 BYTE *image_data;
160 CRITICAL_SECTION lock;
161 } JpegDecoder;
163 static inline JpegDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
165 return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapDecoder_iface);
168 static inline JpegDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
170 return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapFrameDecode_iface);
173 static inline JpegDecoder *decoder_from_decompress(j_decompress_ptr decompress)
175 return CONTAINING_RECORD(decompress, JpegDecoder, cinfo);
178 static inline JpegDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
180 return CONTAINING_RECORD(iface, JpegDecoder, IWICMetadataBlockReader_iface);
183 static HRESULT WINAPI JpegDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
184 void **ppv)
186 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
187 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
189 if (!ppv) return E_INVALIDARG;
191 if (IsEqualIID(&IID_IUnknown, iid) ||
192 IsEqualIID(&IID_IWICBitmapDecoder, iid))
194 *ppv = &This->IWICBitmapDecoder_iface;
196 else
198 *ppv = NULL;
199 return E_NOINTERFACE;
202 IUnknown_AddRef((IUnknown*)*ppv);
203 return S_OK;
206 static ULONG WINAPI JpegDecoder_AddRef(IWICBitmapDecoder *iface)
208 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
209 ULONG ref = InterlockedIncrement(&This->ref);
211 TRACE("(%p) refcount=%u\n", iface, ref);
213 return ref;
216 static ULONG WINAPI JpegDecoder_Release(IWICBitmapDecoder *iface)
218 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
219 ULONG ref = InterlockedDecrement(&This->ref);
221 TRACE("(%p) refcount=%u\n", iface, ref);
223 if (ref == 0)
225 This->lock.DebugInfo->Spare[0] = 0;
226 DeleteCriticalSection(&This->lock);
227 if (This->cinfo_initialized) pjpeg_destroy_decompress(&This->cinfo);
228 if (This->stream) IStream_Release(This->stream);
229 HeapFree(GetProcessHeap(), 0, This->image_data);
230 HeapFree(GetProcessHeap(), 0, This);
233 return ref;
236 static HRESULT WINAPI JpegDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
237 DWORD *capability)
239 HRESULT hr;
241 TRACE("(%p,%p,%p)\n", iface, stream, capability);
243 if (!stream || !capability) return E_INVALIDARG;
245 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
246 if (hr != S_OK) return hr;
248 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
249 WICBitmapDecoderCapabilityCanDecodeSomeImages;
250 /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
251 return S_OK;
254 static void source_mgr_init_source(j_decompress_ptr cinfo)
258 static jpeg_boolean source_mgr_fill_input_buffer(j_decompress_ptr cinfo)
260 JpegDecoder *This = decoder_from_decompress(cinfo);
261 HRESULT hr;
262 ULONG bytesread;
264 hr = IStream_Read(This->stream, This->source_buffer, 1024, &bytesread);
266 if (FAILED(hr) || bytesread == 0)
268 return FALSE;
270 else
272 This->source_mgr.next_input_byte = This->source_buffer;
273 This->source_mgr.bytes_in_buffer = bytesread;
274 return TRUE;
278 static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
280 JpegDecoder *This = decoder_from_decompress(cinfo);
281 LARGE_INTEGER seek;
283 if (num_bytes > This->source_mgr.bytes_in_buffer)
285 seek.QuadPart = num_bytes - This->source_mgr.bytes_in_buffer;
286 IStream_Seek(This->stream, seek, STREAM_SEEK_CUR, NULL);
287 This->source_mgr.bytes_in_buffer = 0;
289 else if (num_bytes > 0)
291 This->source_mgr.next_input_byte += num_bytes;
292 This->source_mgr.bytes_in_buffer -= num_bytes;
296 static void source_mgr_term_source(j_decompress_ptr cinfo)
300 static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
301 WICDecodeOptions cacheOptions)
303 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
304 int ret;
305 LARGE_INTEGER seek;
306 jmp_buf jmpbuf;
307 UINT data_size, i;
309 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
311 EnterCriticalSection(&This->lock);
313 if (This->cinfo_initialized)
315 LeaveCriticalSection(&This->lock);
316 return WINCODEC_ERR_WRONGSTATE;
319 pjpeg_std_error(&This->jerr);
321 This->jerr.error_exit = error_exit_fn;
322 This->jerr.emit_message = emit_message_fn;
324 This->cinfo.err = &This->jerr;
326 This->cinfo.client_data = jmpbuf;
328 if (setjmp(jmpbuf))
330 LeaveCriticalSection(&This->lock);
331 return E_FAIL;
334 pjpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
336 This->cinfo_initialized = TRUE;
338 This->stream = pIStream;
339 IStream_AddRef(pIStream);
341 seek.QuadPart = 0;
342 IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
344 This->source_mgr.bytes_in_buffer = 0;
345 This->source_mgr.init_source = source_mgr_init_source;
346 This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer;
347 This->source_mgr.skip_input_data = source_mgr_skip_input_data;
348 This->source_mgr.resync_to_restart = pjpeg_resync_to_restart;
349 This->source_mgr.term_source = source_mgr_term_source;
351 This->cinfo.src = &This->source_mgr;
353 ret = pjpeg_read_header(&This->cinfo, TRUE);
355 if (ret != JPEG_HEADER_OK) {
356 WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret);
357 LeaveCriticalSection(&This->lock);
358 return E_FAIL;
361 switch (This->cinfo.jpeg_color_space)
363 case JCS_GRAYSCALE:
364 This->cinfo.out_color_space = JCS_GRAYSCALE;
365 break;
366 case JCS_RGB:
367 case JCS_YCbCr:
368 This->cinfo.out_color_space = JCS_RGB;
369 break;
370 case JCS_CMYK:
371 case JCS_YCCK:
372 This->cinfo.out_color_space = JCS_CMYK;
373 break;
374 default:
375 ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space);
376 LeaveCriticalSection(&This->lock);
377 return E_FAIL;
380 if (!pjpeg_start_decompress(&This->cinfo))
382 ERR("jpeg_start_decompress failed\n");
383 LeaveCriticalSection(&This->lock);
384 return E_FAIL;
387 if (This->cinfo.out_color_space == JCS_GRAYSCALE) This->bpp = 8;
388 else if (This->cinfo.out_color_space == JCS_CMYK) This->bpp = 32;
389 else This->bpp = 24;
391 This->stride = (This->bpp * This->cinfo.output_width + 7) / 8;
392 data_size = This->stride * This->cinfo.output_height;
394 This->image_data = heap_alloc(data_size);
395 if (!This->image_data)
397 LeaveCriticalSection(&This->lock);
398 return E_OUTOFMEMORY;
401 while (This->cinfo.output_scanline < This->cinfo.output_height)
403 UINT first_scanline = This->cinfo.output_scanline;
404 UINT max_rows;
405 JSAMPROW out_rows[4];
406 JDIMENSION ret;
408 max_rows = min(This->cinfo.output_height-first_scanline, 4);
409 for (i=0; i<max_rows; i++)
410 out_rows[i] = This->image_data + This->stride * (first_scanline+i);
412 ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
413 if (ret == 0)
415 ERR("read_scanlines failed\n");
416 LeaveCriticalSection(&This->lock);
417 return E_FAIL;
421 if (This->bpp == 24)
423 /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
424 reverse_bgr8(3, This->image_data,
425 This->cinfo.output_width, This->cinfo.output_height,
426 This->stride);
429 if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
431 /* Adobe JPEG's have inverted CMYK data. */
432 for (i=0; i<data_size; i++)
433 This->image_data[i] ^= 0xff;
436 This->initialized = TRUE;
438 LeaveCriticalSection(&This->lock);
440 return S_OK;
443 static HRESULT WINAPI JpegDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
444 GUID *pguidContainerFormat)
446 memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID));
447 return S_OK;
450 static HRESULT WINAPI JpegDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
451 IWICBitmapDecoderInfo **ppIDecoderInfo)
453 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
455 return get_decoder_info(&CLSID_WICJpegDecoder, ppIDecoderInfo);
458 static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface,
459 IWICPalette *pIPalette)
461 TRACE("(%p,%p)\n", iface, pIPalette);
463 return WINCODEC_ERR_PALETTEUNAVAILABLE;
466 static HRESULT WINAPI JpegDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
467 IWICMetadataQueryReader **reader)
469 TRACE("(%p,%p)\n", iface, reader);
471 if (!reader) return E_INVALIDARG;
473 *reader = NULL;
474 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
477 static HRESULT WINAPI JpegDecoder_GetPreview(IWICBitmapDecoder *iface,
478 IWICBitmapSource **ppIBitmapSource)
480 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
481 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
484 static HRESULT WINAPI JpegDecoder_GetColorContexts(IWICBitmapDecoder *iface,
485 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
487 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
488 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
491 static HRESULT WINAPI JpegDecoder_GetThumbnail(IWICBitmapDecoder *iface,
492 IWICBitmapSource **ppIThumbnail)
494 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
495 return WINCODEC_ERR_CODECNOTHUMBNAIL;
498 static HRESULT WINAPI JpegDecoder_GetFrameCount(IWICBitmapDecoder *iface,
499 UINT *pCount)
501 if (!pCount) return E_INVALIDARG;
503 *pCount = 1;
504 return S_OK;
507 static HRESULT WINAPI JpegDecoder_GetFrame(IWICBitmapDecoder *iface,
508 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
510 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
511 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
513 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
515 if (index != 0) return E_INVALIDARG;
517 IWICBitmapDecoder_AddRef(iface);
518 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
520 return S_OK;
523 static const IWICBitmapDecoderVtbl JpegDecoder_Vtbl = {
524 JpegDecoder_QueryInterface,
525 JpegDecoder_AddRef,
526 JpegDecoder_Release,
527 JpegDecoder_QueryCapability,
528 JpegDecoder_Initialize,
529 JpegDecoder_GetContainerFormat,
530 JpegDecoder_GetDecoderInfo,
531 JpegDecoder_CopyPalette,
532 JpegDecoder_GetMetadataQueryReader,
533 JpegDecoder_GetPreview,
534 JpegDecoder_GetColorContexts,
535 JpegDecoder_GetThumbnail,
536 JpegDecoder_GetFrameCount,
537 JpegDecoder_GetFrame
540 static HRESULT WINAPI JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
541 void **ppv)
543 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
545 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
547 if (!ppv) return E_INVALIDARG;
549 if (IsEqualIID(&IID_IUnknown, iid) ||
550 IsEqualIID(&IID_IWICBitmapSource, iid) ||
551 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
553 *ppv = &This->IWICBitmapFrameDecode_iface;
555 else
557 *ppv = NULL;
558 return E_NOINTERFACE;
561 IUnknown_AddRef((IUnknown*)*ppv);
562 return S_OK;
565 static ULONG WINAPI JpegDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
567 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
568 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
571 static ULONG WINAPI JpegDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
573 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
574 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
577 static HRESULT WINAPI JpegDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
578 UINT *puiWidth, UINT *puiHeight)
580 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
581 *puiWidth = This->cinfo.output_width;
582 *puiHeight = This->cinfo.output_height;
583 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
584 return S_OK;
587 static HRESULT WINAPI JpegDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
588 WICPixelFormatGUID *pPixelFormat)
590 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
591 TRACE("(%p,%p)\n", iface, pPixelFormat);
592 if (This->cinfo.out_color_space == JCS_RGB)
593 memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID));
594 else if (This->cinfo.out_color_space == JCS_CMYK)
595 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppCMYK, sizeof(GUID));
596 else /* This->cinfo.out_color_space == JCS_GRAYSCALE */
597 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID));
598 return S_OK;
601 static HRESULT WINAPI JpegDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
602 double *pDpiX, double *pDpiY)
604 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
606 EnterCriticalSection(&This->lock);
608 switch (This->cinfo.density_unit)
610 case 2: /* pixels per centimeter */
611 *pDpiX = This->cinfo.X_density * 2.54;
612 *pDpiY = This->cinfo.Y_density * 2.54;
613 break;
615 case 1: /* pixels per inch */
616 *pDpiX = This->cinfo.X_density;
617 *pDpiY = This->cinfo.Y_density;
618 break;
620 case 0: /* unknown */
621 default:
622 *pDpiX = 96.0;
623 *pDpiY = 96.0;
624 break;
627 LeaveCriticalSection(&This->lock);
629 TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
631 return S_OK;
634 static HRESULT WINAPI JpegDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
635 IWICPalette *pIPalette)
637 TRACE("(%p,%p)\n", iface, pIPalette);
639 return WINCODEC_ERR_PALETTEUNAVAILABLE;
642 static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
643 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
645 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
647 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
649 return copy_pixels(This->bpp, This->image_data,
650 This->cinfo.output_width, This->cinfo.output_height, This->stride,
651 prc, cbStride, cbBufferSize, pbBuffer);
654 static HRESULT WINAPI JpegDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
655 IWICMetadataQueryReader **ppIMetadataQueryReader)
657 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
659 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
661 if (!ppIMetadataQueryReader)
662 return E_INVALIDARG;
664 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
667 static HRESULT WINAPI JpegDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
668 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
670 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
671 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
674 static HRESULT WINAPI JpegDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
675 IWICBitmapSource **ppIThumbnail)
677 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
678 return WINCODEC_ERR_CODECNOTHUMBNAIL;
681 static const IWICBitmapFrameDecodeVtbl JpegDecoder_Frame_Vtbl = {
682 JpegDecoder_Frame_QueryInterface,
683 JpegDecoder_Frame_AddRef,
684 JpegDecoder_Frame_Release,
685 JpegDecoder_Frame_GetSize,
686 JpegDecoder_Frame_GetPixelFormat,
687 JpegDecoder_Frame_GetResolution,
688 JpegDecoder_Frame_CopyPalette,
689 JpegDecoder_Frame_CopyPixels,
690 JpegDecoder_Frame_GetMetadataQueryReader,
691 JpegDecoder_Frame_GetColorContexts,
692 JpegDecoder_Frame_GetThumbnail
695 static HRESULT WINAPI JpegDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid,
696 void **ppv)
698 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
699 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
702 static ULONG WINAPI JpegDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
704 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
705 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
708 static ULONG WINAPI JpegDecoder_Block_Release(IWICMetadataBlockReader *iface)
710 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
711 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
714 static HRESULT WINAPI JpegDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
715 GUID *pguidContainerFormat)
717 TRACE("%p,%p\n", iface, pguidContainerFormat);
719 if (!pguidContainerFormat) return E_INVALIDARG;
721 memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID));
723 return S_OK;
726 static HRESULT WINAPI JpegDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
727 UINT *pcCount)
729 FIXME("%p,%p\n", iface, pcCount);
731 if (!pcCount) return E_INVALIDARG;
733 *pcCount = 0;
735 return S_OK;
738 static HRESULT WINAPI JpegDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
739 UINT nIndex, IWICMetadataReader **ppIMetadataReader)
741 FIXME("%p,%d,%p\n", iface, nIndex, ppIMetadataReader);
742 return E_INVALIDARG;
745 static HRESULT WINAPI JpegDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
746 IEnumUnknown **ppIEnumMetadata)
748 FIXME("%p,%p\n", iface, ppIEnumMetadata);
749 return E_NOTIMPL;
752 static const IWICMetadataBlockReaderVtbl JpegDecoder_Block_Vtbl = {
753 JpegDecoder_Block_QueryInterface,
754 JpegDecoder_Block_AddRef,
755 JpegDecoder_Block_Release,
756 JpegDecoder_Block_GetContainerFormat,
757 JpegDecoder_Block_GetCount,
758 JpegDecoder_Block_GetReaderByIndex,
759 JpegDecoder_Block_GetEnumerator,
762 HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv)
764 JpegDecoder *This;
765 HRESULT ret;
767 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
769 if (!libjpeg_handle && !load_libjpeg())
771 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
772 return E_FAIL;
775 *ppv = NULL;
777 This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegDecoder));
778 if (!This) return E_OUTOFMEMORY;
780 This->IWICBitmapDecoder_iface.lpVtbl = &JpegDecoder_Vtbl;
781 This->IWICBitmapFrameDecode_iface.lpVtbl = &JpegDecoder_Frame_Vtbl;
782 This->IWICMetadataBlockReader_iface.lpVtbl = &JpegDecoder_Block_Vtbl;
783 This->ref = 1;
784 This->initialized = FALSE;
785 This->cinfo_initialized = FALSE;
786 This->stream = NULL;
787 This->image_data = NULL;
788 InitializeCriticalSection(&This->lock);
789 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegDecoder.lock");
791 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
792 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
794 return ret;
797 typedef struct jpeg_compress_format {
798 const WICPixelFormatGUID *guid;
799 int bpp;
800 int num_components;
801 J_COLOR_SPACE color_space;
802 int swap_rgb;
803 } jpeg_compress_format;
805 static const jpeg_compress_format compress_formats[] = {
806 { &GUID_WICPixelFormat24bppBGR, 24, 3, JCS_RGB, 1 },
807 { &GUID_WICPixelFormat32bppCMYK, 32, 4, JCS_CMYK },
808 { &GUID_WICPixelFormat8bppGray, 8, 1, JCS_GRAYSCALE },
809 { 0 }
812 typedef struct JpegEncoder {
813 IWICBitmapEncoder IWICBitmapEncoder_iface;
814 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
815 LONG ref;
816 struct jpeg_compress_struct cinfo;
817 struct jpeg_error_mgr jerr;
818 struct jpeg_destination_mgr dest_mgr;
819 BOOL initialized;
820 int frame_count;
821 BOOL frame_initialized;
822 BOOL started_compress;
823 int lines_written;
824 BOOL frame_committed;
825 BOOL committed;
826 UINT width, height;
827 double xres, yres;
828 const jpeg_compress_format *format;
829 IStream *stream;
830 WICColor palette[256];
831 UINT colors;
832 CRITICAL_SECTION lock;
833 BYTE dest_buffer[1024];
834 } JpegEncoder;
836 static inline JpegEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
838 return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapEncoder_iface);
841 static inline JpegEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
843 return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapFrameEncode_iface);
846 static inline JpegEncoder *encoder_from_compress(j_compress_ptr compress)
848 return CONTAINING_RECORD(compress, JpegEncoder, cinfo);
851 static void dest_mgr_init_destination(j_compress_ptr cinfo)
853 JpegEncoder *This = encoder_from_compress(cinfo);
855 This->dest_mgr.next_output_byte = This->dest_buffer;
856 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
859 static jpeg_boolean dest_mgr_empty_output_buffer(j_compress_ptr cinfo)
861 JpegEncoder *This = encoder_from_compress(cinfo);
862 HRESULT hr;
863 ULONG byteswritten;
865 hr = IStream_Write(This->stream, This->dest_buffer,
866 sizeof(This->dest_buffer), &byteswritten);
868 if (hr != S_OK || byteswritten == 0)
870 ERR("Failed writing data, hr=%x\n", hr);
871 return FALSE;
874 This->dest_mgr.next_output_byte = This->dest_buffer;
875 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
876 return TRUE;
879 static void dest_mgr_term_destination(j_compress_ptr cinfo)
881 JpegEncoder *This = encoder_from_compress(cinfo);
882 ULONG byteswritten;
883 HRESULT hr;
885 if (This->dest_mgr.free_in_buffer != sizeof(This->dest_buffer))
887 hr = IStream_Write(This->stream, This->dest_buffer,
888 sizeof(This->dest_buffer) - This->dest_mgr.free_in_buffer, &byteswritten);
890 if (hr != S_OK || byteswritten == 0)
891 ERR("Failed writing data, hr=%x\n", hr);
895 static HRESULT WINAPI JpegEncoder_Frame_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
896 void **ppv)
898 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
899 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
901 if (!ppv) return E_INVALIDARG;
903 if (IsEqualIID(&IID_IUnknown, iid) ||
904 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
906 *ppv = &This->IWICBitmapFrameEncode_iface;
908 else
910 *ppv = NULL;
911 return E_NOINTERFACE;
914 IUnknown_AddRef((IUnknown*)*ppv);
915 return S_OK;
918 static ULONG WINAPI JpegEncoder_Frame_AddRef(IWICBitmapFrameEncode *iface)
920 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
921 return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
924 static ULONG WINAPI JpegEncoder_Frame_Release(IWICBitmapFrameEncode *iface)
926 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
927 return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
930 static HRESULT WINAPI JpegEncoder_Frame_Initialize(IWICBitmapFrameEncode *iface,
931 IPropertyBag2 *pIEncoderOptions)
933 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
934 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
936 EnterCriticalSection(&This->lock);
938 if (This->frame_initialized)
940 LeaveCriticalSection(&This->lock);
941 return WINCODEC_ERR_WRONGSTATE;
944 This->frame_initialized = TRUE;
946 LeaveCriticalSection(&This->lock);
948 return S_OK;
951 static HRESULT WINAPI JpegEncoder_Frame_SetSize(IWICBitmapFrameEncode *iface,
952 UINT uiWidth, UINT uiHeight)
954 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
955 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
957 EnterCriticalSection(&This->lock);
959 if (!This->frame_initialized || This->started_compress)
961 LeaveCriticalSection(&This->lock);
962 return WINCODEC_ERR_WRONGSTATE;
965 This->width = uiWidth;
966 This->height = uiHeight;
968 LeaveCriticalSection(&This->lock);
970 return S_OK;
973 static HRESULT WINAPI JpegEncoder_Frame_SetResolution(IWICBitmapFrameEncode *iface,
974 double dpiX, double dpiY)
976 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
977 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
979 EnterCriticalSection(&This->lock);
981 if (!This->frame_initialized || This->started_compress)
983 LeaveCriticalSection(&This->lock);
984 return WINCODEC_ERR_WRONGSTATE;
987 This->xres = dpiX;
988 This->yres = dpiY;
990 LeaveCriticalSection(&This->lock);
992 return S_OK;
995 static HRESULT WINAPI JpegEncoder_Frame_SetPixelFormat(IWICBitmapFrameEncode *iface,
996 WICPixelFormatGUID *pPixelFormat)
998 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
999 int i;
1000 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
1002 EnterCriticalSection(&This->lock);
1004 if (!This->frame_initialized || This->started_compress)
1006 LeaveCriticalSection(&This->lock);
1007 return WINCODEC_ERR_WRONGSTATE;
1010 for (i=0; compress_formats[i].guid; i++)
1012 if (memcmp(compress_formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
1013 break;
1016 if (!compress_formats[i].guid) i = 0;
1018 This->format = &compress_formats[i];
1019 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
1021 LeaveCriticalSection(&This->lock);
1023 return S_OK;
1026 static HRESULT WINAPI JpegEncoder_Frame_SetColorContexts(IWICBitmapFrameEncode *iface,
1027 UINT cCount, IWICColorContext **ppIColorContext)
1029 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1030 return E_NOTIMPL;
1033 static HRESULT WINAPI JpegEncoder_Frame_SetPalette(IWICBitmapFrameEncode *iface,
1034 IWICPalette *palette)
1036 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1037 HRESULT hr;
1039 TRACE("(%p,%p)\n", iface, palette);
1041 if (!palette) return E_INVALIDARG;
1043 EnterCriticalSection(&This->lock);
1045 if (This->frame_initialized)
1046 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1047 else
1048 hr = WINCODEC_ERR_NOTINITIALIZED;
1050 LeaveCriticalSection(&This->lock);
1051 return hr;
1054 static HRESULT WINAPI JpegEncoder_Frame_SetThumbnail(IWICBitmapFrameEncode *iface,
1055 IWICBitmapSource *pIThumbnail)
1057 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
1058 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1061 static HRESULT WINAPI JpegEncoder_Frame_WritePixels(IWICBitmapFrameEncode *iface,
1062 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
1064 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1065 jmp_buf jmpbuf;
1066 BYTE *swapped_data = NULL, *current_row;
1067 UINT line;
1068 int row_size;
1069 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
1071 EnterCriticalSection(&This->lock);
1073 if (!This->frame_initialized || !This->width || !This->height || !This->format)
1075 LeaveCriticalSection(&This->lock);
1076 return WINCODEC_ERR_WRONGSTATE;
1079 if (lineCount == 0 || lineCount + This->lines_written > This->height)
1081 LeaveCriticalSection(&This->lock);
1082 return E_INVALIDARG;
1085 /* set up setjmp/longjmp error handling */
1086 if (setjmp(jmpbuf))
1088 LeaveCriticalSection(&This->lock);
1089 HeapFree(GetProcessHeap(), 0, swapped_data);
1090 return E_FAIL;
1092 This->cinfo.client_data = jmpbuf;
1094 if (!This->started_compress)
1096 This->cinfo.image_width = This->width;
1097 This->cinfo.image_height = This->height;
1098 This->cinfo.input_components = This->format->num_components;
1099 This->cinfo.in_color_space = This->format->color_space;
1101 pjpeg_set_defaults(&This->cinfo);
1103 if (This->xres != 0.0 && This->yres != 0.0)
1105 This->cinfo.density_unit = 1; /* dots per inch */
1106 This->cinfo.X_density = This->xres;
1107 This->cinfo.Y_density = This->yres;
1110 pjpeg_start_compress(&This->cinfo, TRUE);
1112 This->started_compress = TRUE;
1115 row_size = This->format->bpp / 8 * This->width;
1117 if (This->format->swap_rgb)
1119 swapped_data = HeapAlloc(GetProcessHeap(), 0, row_size);
1120 if (!swapped_data)
1122 LeaveCriticalSection(&This->lock);
1123 return E_OUTOFMEMORY;
1127 for (line=0; line < lineCount; line++)
1129 if (This->format->swap_rgb)
1131 UINT x;
1133 memcpy(swapped_data, pbPixels + (cbStride * line), row_size);
1135 for (x=0; x < This->width; x++)
1137 BYTE b;
1139 b = swapped_data[x*3];
1140 swapped_data[x*3] = swapped_data[x*3+2];
1141 swapped_data[x*3+2] = b;
1144 current_row = swapped_data;
1146 else
1147 current_row = pbPixels + (cbStride * line);
1149 if (!pjpeg_write_scanlines(&This->cinfo, &current_row, 1))
1151 ERR("failed writing scanlines\n");
1152 LeaveCriticalSection(&This->lock);
1153 HeapFree(GetProcessHeap(), 0, swapped_data);
1154 return E_FAIL;
1157 This->lines_written++;
1160 LeaveCriticalSection(&This->lock);
1161 HeapFree(GetProcessHeap(), 0, swapped_data);
1163 return S_OK;
1166 static HRESULT WINAPI JpegEncoder_Frame_WriteSource(IWICBitmapFrameEncode *iface,
1167 IWICBitmapSource *pIBitmapSource, WICRect *prc)
1169 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1170 HRESULT hr;
1171 TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc));
1173 if (!This->frame_initialized)
1174 return WINCODEC_ERR_WRONGSTATE;
1176 hr = configure_write_source(iface, pIBitmapSource, prc,
1177 This->format ? This->format->guid : NULL, This->width, This->height,
1178 This->xres, This->yres);
1180 if (SUCCEEDED(hr))
1182 hr = write_source(iface, pIBitmapSource, prc,
1183 This->format->guid, This->format->bpp, FALSE,
1184 This->width, This->height);
1187 return hr;
1190 static HRESULT WINAPI JpegEncoder_Frame_Commit(IWICBitmapFrameEncode *iface)
1192 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1193 jmp_buf jmpbuf;
1194 TRACE("(%p)\n", iface);
1196 EnterCriticalSection(&This->lock);
1198 if (!This->started_compress || This->lines_written != This->height || This->frame_committed)
1200 LeaveCriticalSection(&This->lock);
1201 return WINCODEC_ERR_WRONGSTATE;
1204 /* set up setjmp/longjmp error handling */
1205 if (setjmp(jmpbuf))
1207 LeaveCriticalSection(&This->lock);
1208 return E_FAIL;
1210 This->cinfo.client_data = jmpbuf;
1212 pjpeg_finish_compress(&This->cinfo);
1214 This->frame_committed = TRUE;
1216 LeaveCriticalSection(&This->lock);
1218 return S_OK;
1221 static HRESULT WINAPI JpegEncoder_Frame_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1222 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1224 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1225 return E_NOTIMPL;
1228 static const IWICBitmapFrameEncodeVtbl JpegEncoder_FrameVtbl = {
1229 JpegEncoder_Frame_QueryInterface,
1230 JpegEncoder_Frame_AddRef,
1231 JpegEncoder_Frame_Release,
1232 JpegEncoder_Frame_Initialize,
1233 JpegEncoder_Frame_SetSize,
1234 JpegEncoder_Frame_SetResolution,
1235 JpegEncoder_Frame_SetPixelFormat,
1236 JpegEncoder_Frame_SetColorContexts,
1237 JpegEncoder_Frame_SetPalette,
1238 JpegEncoder_Frame_SetThumbnail,
1239 JpegEncoder_Frame_WritePixels,
1240 JpegEncoder_Frame_WriteSource,
1241 JpegEncoder_Frame_Commit,
1242 JpegEncoder_Frame_GetMetadataQueryWriter
1245 static HRESULT WINAPI JpegEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1246 void **ppv)
1248 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1249 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1251 if (!ppv) return E_INVALIDARG;
1253 if (IsEqualIID(&IID_IUnknown, iid) ||
1254 IsEqualIID(&IID_IWICBitmapEncoder, iid))
1256 *ppv = &This->IWICBitmapEncoder_iface;
1258 else
1260 *ppv = NULL;
1261 return E_NOINTERFACE;
1264 IUnknown_AddRef((IUnknown*)*ppv);
1265 return S_OK;
1268 static ULONG WINAPI JpegEncoder_AddRef(IWICBitmapEncoder *iface)
1270 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1271 ULONG ref = InterlockedIncrement(&This->ref);
1273 TRACE("(%p) refcount=%u\n", iface, ref);
1275 return ref;
1278 static ULONG WINAPI JpegEncoder_Release(IWICBitmapEncoder *iface)
1280 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1281 ULONG ref = InterlockedDecrement(&This->ref);
1283 TRACE("(%p) refcount=%u\n", iface, ref);
1285 if (ref == 0)
1287 This->lock.DebugInfo->Spare[0] = 0;
1288 DeleteCriticalSection(&This->lock);
1289 if (This->initialized) pjpeg_destroy_compress(&This->cinfo);
1290 if (This->stream) IStream_Release(This->stream);
1291 HeapFree(GetProcessHeap(), 0, This);
1294 return ref;
1297 static HRESULT WINAPI JpegEncoder_Initialize(IWICBitmapEncoder *iface,
1298 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1300 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1301 jmp_buf jmpbuf;
1303 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
1305 EnterCriticalSection(&This->lock);
1307 if (This->initialized)
1309 LeaveCriticalSection(&This->lock);
1310 return WINCODEC_ERR_WRONGSTATE;
1313 pjpeg_std_error(&This->jerr);
1315 This->jerr.error_exit = error_exit_fn;
1316 This->jerr.emit_message = emit_message_fn;
1318 This->cinfo.err = &This->jerr;
1320 This->cinfo.client_data = jmpbuf;
1322 if (setjmp(jmpbuf))
1324 LeaveCriticalSection(&This->lock);
1325 return E_FAIL;
1328 pjpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct));
1330 This->stream = pIStream;
1331 IStream_AddRef(pIStream);
1333 This->dest_mgr.next_output_byte = This->dest_buffer;
1334 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
1336 This->dest_mgr.init_destination = dest_mgr_init_destination;
1337 This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer;
1338 This->dest_mgr.term_destination = dest_mgr_term_destination;
1340 This->cinfo.dest = &This->dest_mgr;
1342 This->initialized = TRUE;
1344 LeaveCriticalSection(&This->lock);
1346 return S_OK;
1349 static HRESULT WINAPI JpegEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
1351 TRACE("(%p,%p)\n", iface, format);
1353 if (!format)
1354 return E_INVALIDARG;
1356 memcpy(format, &GUID_ContainerFormatJpeg, sizeof(*format));
1357 return S_OK;
1360 static HRESULT WINAPI JpegEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
1362 IWICComponentInfo *comp_info;
1363 HRESULT hr;
1365 TRACE("%p,%p\n", iface, info);
1367 if (!info) return E_INVALIDARG;
1369 hr = CreateComponentInfo(&CLSID_WICJpegEncoder, &comp_info);
1370 if (hr == S_OK)
1372 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
1373 IWICComponentInfo_Release(comp_info);
1375 return hr;
1378 static HRESULT WINAPI JpegEncoder_SetColorContexts(IWICBitmapEncoder *iface,
1379 UINT cCount, IWICColorContext **ppIColorContext)
1381 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1382 return E_NOTIMPL;
1385 static HRESULT WINAPI JpegEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
1387 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1388 HRESULT hr;
1390 TRACE("(%p,%p)\n", iface, pIPalette);
1392 EnterCriticalSection(&This->lock);
1394 hr = This->initialized ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
1396 LeaveCriticalSection(&This->lock);
1398 return hr;
1401 static HRESULT WINAPI JpegEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1403 TRACE("(%p,%p)\n", iface, pIThumbnail);
1404 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1407 static HRESULT WINAPI JpegEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1409 TRACE("(%p,%p)\n", iface, pIPreview);
1410 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1413 static HRESULT WINAPI JpegEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1414 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
1416 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1417 HRESULT hr;
1418 static const PROPBAG2 opts[6] =
1420 { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszImageQuality },
1421 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszBitmapTransform },
1422 { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszLuminance },
1423 { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszChrominance },
1424 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszJpegYCrCbSubsampling },
1425 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszSuppressApp0 },
1428 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
1430 EnterCriticalSection(&This->lock);
1432 if (This->frame_count != 0)
1434 LeaveCriticalSection(&This->lock);
1435 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1438 if (!This->initialized)
1440 LeaveCriticalSection(&This->lock);
1441 return WINCODEC_ERR_NOTINITIALIZED;
1444 if (ppIEncoderOptions)
1446 hr = CreatePropertyBag2(opts, ARRAY_SIZE(opts), ppIEncoderOptions);
1447 if (FAILED(hr))
1449 LeaveCriticalSection(&This->lock);
1450 return hr;
1454 This->frame_count = 1;
1456 LeaveCriticalSection(&This->lock);
1458 IWICBitmapEncoder_AddRef(iface);
1459 *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface;
1461 return S_OK;
1464 static HRESULT WINAPI JpegEncoder_Commit(IWICBitmapEncoder *iface)
1466 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1467 TRACE("(%p)\n", iface);
1469 EnterCriticalSection(&This->lock);
1471 if (!This->frame_committed || This->committed)
1473 LeaveCriticalSection(&This->lock);
1474 return WINCODEC_ERR_WRONGSTATE;
1477 This->committed = TRUE;
1479 LeaveCriticalSection(&This->lock);
1481 return S_OK;
1484 static HRESULT WINAPI JpegEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1485 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1487 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1488 return E_NOTIMPL;
1491 static const IWICBitmapEncoderVtbl JpegEncoder_Vtbl = {
1492 JpegEncoder_QueryInterface,
1493 JpegEncoder_AddRef,
1494 JpegEncoder_Release,
1495 JpegEncoder_Initialize,
1496 JpegEncoder_GetContainerFormat,
1497 JpegEncoder_GetEncoderInfo,
1498 JpegEncoder_SetColorContexts,
1499 JpegEncoder_SetPalette,
1500 JpegEncoder_SetThumbnail,
1501 JpegEncoder_SetPreview,
1502 JpegEncoder_CreateNewFrame,
1503 JpegEncoder_Commit,
1504 JpegEncoder_GetMetadataQueryWriter
1507 HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv)
1509 JpegEncoder *This;
1510 HRESULT ret;
1512 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1514 *ppv = NULL;
1516 if (!libjpeg_handle && !load_libjpeg())
1518 ERR("Failed writing JPEG because unable to find %s\n",SONAME_LIBJPEG);
1519 return E_FAIL;
1522 This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegEncoder));
1523 if (!This) return E_OUTOFMEMORY;
1525 This->IWICBitmapEncoder_iface.lpVtbl = &JpegEncoder_Vtbl;
1526 This->IWICBitmapFrameEncode_iface.lpVtbl = &JpegEncoder_FrameVtbl;
1527 This->ref = 1;
1528 This->initialized = FALSE;
1529 This->frame_count = 0;
1530 This->frame_initialized = FALSE;
1531 This->started_compress = FALSE;
1532 This->lines_written = 0;
1533 This->frame_committed = FALSE;
1534 This->committed = FALSE;
1535 This->width = This->height = 0;
1536 This->xres = This->yres = 0.0;
1537 This->format = NULL;
1538 This->stream = NULL;
1539 This->colors = 0;
1540 InitializeCriticalSection(&This->lock);
1541 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegEncoder.lock");
1543 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
1544 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1546 return ret;
1549 #else /* !defined(SONAME_LIBJPEG) */
1551 HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv)
1553 ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
1554 return E_FAIL;
1557 HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv)
1559 ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n");
1560 return E_FAIL;
1563 #endif