1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18 
19 #include "config.h"
20 #include "wine/port.h"
21 
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>
29 
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
44 
45 #define COBJMACROS
46 
47 #include "windef.h"
48 #include "winbase.h"
49 #include "objbase.h"
50 
51 #include "wincodecs_private.h"
52 
53 #include "wine/debug.h"
54 #include "wine/library.h"
55 
56 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
57 
58 #ifdef SONAME_LIBJPEG
59 WINE_DECLARE_DEBUG_CHANNEL(jpeg);
60 
61 static void *libjpeg_handle;
62 
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};
69 
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
85 
86 static void *load_libjpeg(void)
87 {
88     if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
89 
90 #define LOAD_FUNCPTR(f) \
91     if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
92         libjpeg_handle = NULL; \
93         return NULL; \
94     }
95 
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
110     }
111     return libjpeg_handle;
112 }
113 
114 static void error_exit_fn(j_common_ptr cinfo)
115 {
116     char message[JMSG_LENGTH_MAX];
117     if (ERR_ON(jpeg))
118     {
119         cinfo->err->format_message(cinfo, message);
120         ERR_(jpeg)("%s\n", message);
121     }
122     longjmp(*(jmp_buf*)cinfo->client_data, 1);
123 }
124 
125 static void emit_message_fn(j_common_ptr cinfo, int msg_level)
126 {
127     char message[JMSG_LENGTH_MAX];
128 
129     if (msg_level < 0 && ERR_ON(jpeg))
130     {
131         cinfo->err->format_message(cinfo, message);
132         ERR_(jpeg)("%s\n", message);
133     }
134     else if (msg_level == 0 && WARN_ON(jpeg))
135     {
136         cinfo->err->format_message(cinfo, message);
137         WARN_(jpeg)("%s\n", message);
138     }
139     else if (msg_level > 0 && TRACE_ON(jpeg))
140     {
141         cinfo->err->format_message(cinfo, message);
142         TRACE_(jpeg)("%s\n", message);
143     }
144 }
145 
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     BYTE *image_data;
159     CRITICAL_SECTION lock;
160 } JpegDecoder;
161 
162 static inline JpegDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
163 {
164     return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapDecoder_iface);
165 }
166 
167 static inline JpegDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
168 {
169     return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapFrameDecode_iface);
170 }
171 
172 static inline JpegDecoder *decoder_from_decompress(j_decompress_ptr decompress)
173 {
174     return CONTAINING_RECORD(decompress, JpegDecoder, cinfo);
175 }
176 
177 static inline JpegDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
178 {
179     return CONTAINING_RECORD(iface, JpegDecoder, IWICMetadataBlockReader_iface);
180 }
181 
182 static HRESULT WINAPI JpegDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
183     void **ppv)
184 {
185     JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
186     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
187 
188     if (!ppv) return E_INVALIDARG;
189 
190     if (IsEqualIID(&IID_IUnknown, iid) ||
191         IsEqualIID(&IID_IWICBitmapDecoder, iid))
192     {
193         *ppv = &This->IWICBitmapDecoder_iface;
194     }
195     else
196     {
197         *ppv = NULL;
198         return E_NOINTERFACE;
199     }
200 
201     IUnknown_AddRef((IUnknown*)*ppv);
202     return S_OK;
203 }
204 
205 static ULONG WINAPI JpegDecoder_AddRef(IWICBitmapDecoder *iface)
206 {
207     JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
208     ULONG ref = InterlockedIncrement(&This->ref);
209 
210     TRACE("(%p) refcount=%u\n", iface, ref);
211 
212     return ref;
213 }
214 
215 static ULONG WINAPI JpegDecoder_Release(IWICBitmapDecoder *iface)
216 {
217     JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
218     ULONG ref = InterlockedDecrement(&This->ref);
219 
220     TRACE("(%p) refcount=%u\n", iface, ref);
221 
222     if (ref == 0)
223     {
224         This->lock.DebugInfo->Spare[0] = 0;
225         DeleteCriticalSection(&This->lock);
226         if (This->cinfo_initialized) pjpeg_destroy_decompress(&This->cinfo);
227         if (This->stream) IStream_Release(This->stream);
228         HeapFree(GetProcessHeap(), 0, This->image_data);
229         HeapFree(GetProcessHeap(), 0, This);
230     }
231 
232     return ref;
233 }
234 
235 static HRESULT WINAPI JpegDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
236     DWORD *capability)
237 {
238     HRESULT hr;
239 
240     TRACE("(%p,%p,%p)\n", iface, stream, capability);
241 
242     if (!stream || !capability) return E_INVALIDARG;
243 
244     hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
245     if (hr != S_OK) return hr;
246 
247     *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
248                   WICBitmapDecoderCapabilityCanDecodeSomeImages;
249     /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
250     return S_OK;
251 }
252 
253 static void source_mgr_init_source(j_decompress_ptr cinfo)
254 {
255 }
256 
257 static jpeg_boolean source_mgr_fill_input_buffer(j_decompress_ptr cinfo)
258 {
259     JpegDecoder *This = decoder_from_decompress(cinfo);
260     HRESULT hr;
261     ULONG bytesread;
262 
263     hr = IStream_Read(This->stream, This->source_buffer, 1024, &bytesread);
264 
265     if (FAILED(hr) || bytesread == 0)
266     {
267         return FALSE;
268     }
269     else
270     {
271         This->source_mgr.next_input_byte = This->source_buffer;
272         This->source_mgr.bytes_in_buffer = bytesread;
273         return TRUE;
274     }
275 }
276 
277 static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
278 {
279     JpegDecoder *This = decoder_from_decompress(cinfo);
280     LARGE_INTEGER seek;
281 
282     if (num_bytes > This->source_mgr.bytes_in_buffer)
283     {
284         seek.QuadPart = num_bytes - This->source_mgr.bytes_in_buffer;
285         IStream_Seek(This->stream, seek, STREAM_SEEK_CUR, NULL);
286         This->source_mgr.bytes_in_buffer = 0;
287     }
288     else if (num_bytes > 0)
289     {
290         This->source_mgr.next_input_byte += num_bytes;
291         This->source_mgr.bytes_in_buffer -= num_bytes;
292     }
293 }
294 
295 static void source_mgr_term_source(j_decompress_ptr cinfo)
296 {
297 }
298 
299 static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
300     WICDecodeOptions cacheOptions)
301 {
302     JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
303     int ret;
304     LARGE_INTEGER seek;
305     jmp_buf jmpbuf;
306     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
307 
308     EnterCriticalSection(&This->lock);
309 
310     if (This->cinfo_initialized)
311     {
312         LeaveCriticalSection(&This->lock);
313         return WINCODEC_ERR_WRONGSTATE;
314     }
315 
316     pjpeg_std_error(&This->jerr);
317 
318     This->jerr.error_exit = error_exit_fn;
319     This->jerr.emit_message = emit_message_fn;
320 
321     This->cinfo.err = &This->jerr;
322 
323     This->cinfo.client_data = jmpbuf;
324 
325     if (setjmp(jmpbuf))
326     {
327         LeaveCriticalSection(&This->lock);
328         return E_FAIL;
329     }
330 
331     pjpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
332 
333     This->cinfo_initialized = TRUE;
334 
335     This->stream = pIStream;
336     IStream_AddRef(pIStream);
337 
338     seek.QuadPart = 0;
339     IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
340 
341     This->source_mgr.bytes_in_buffer = 0;
342     This->source_mgr.init_source = source_mgr_init_source;
343     This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer;
344     This->source_mgr.skip_input_data = source_mgr_skip_input_data;
345     This->source_mgr.resync_to_restart = pjpeg_resync_to_restart;
346     This->source_mgr.term_source = source_mgr_term_source;
347 
348     This->cinfo.src = &This->source_mgr;
349 
350     ret = pjpeg_read_header(&This->cinfo, TRUE);
351 
352     if (ret != JPEG_HEADER_OK) {
353         WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret);
354         LeaveCriticalSection(&This->lock);
355         return E_FAIL;
356     }
357 
358     switch (This->cinfo.jpeg_color_space)
359     {
360     case JCS_GRAYSCALE:
361         This->cinfo.out_color_space = JCS_GRAYSCALE;
362         break;
363     case JCS_RGB:
364     case JCS_YCbCr:
365         This->cinfo.out_color_space = JCS_RGB;
366         break;
367     case JCS_CMYK:
368     case JCS_YCCK:
369         This->cinfo.out_color_space = JCS_CMYK;
370         break;
371     default:
372         ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space);
373         LeaveCriticalSection(&This->lock);
374         return E_FAIL;
375     }
376 
377     if (!pjpeg_start_decompress(&This->cinfo))
378     {
379         ERR("jpeg_start_decompress failed\n");
380         LeaveCriticalSection(&This->lock);
381         return E_FAIL;
382     }
383 
384     This->initialized = TRUE;
385 
386     LeaveCriticalSection(&This->lock);
387 
388     return S_OK;
389 }
390 
391 static HRESULT WINAPI JpegDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
392     GUID *pguidContainerFormat)
393 {
394     memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID));
395     return S_OK;
396 }
397 
398 static HRESULT WINAPI JpegDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
399     IWICBitmapDecoderInfo **ppIDecoderInfo)
400 {
401     HRESULT hr;
402     IWICComponentInfo *compinfo;
403 
404     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
405 
406     hr = CreateComponentInfo(&CLSID_WICJpegDecoder, &compinfo);
407     if (FAILED(hr)) return hr;
408 
409     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
410         (void**)ppIDecoderInfo);
411 
412     IWICComponentInfo_Release(compinfo);
413 
414     return hr;
415 }
416 
417 static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface,
418     IWICPalette *pIPalette)
419 {
420     TRACE("(%p,%p)\n", iface, pIPalette);
421 
422     return WINCODEC_ERR_PALETTEUNAVAILABLE;
423 }
424 
425 static HRESULT WINAPI JpegDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
426     IWICMetadataQueryReader **reader)
427 {
428     FIXME("(%p,%p): stub\n", iface, reader);
429 
430     if (!reader) return E_INVALIDARG;
431 
432     *reader = NULL;
433     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
434 }
435 
436 static HRESULT WINAPI JpegDecoder_GetPreview(IWICBitmapDecoder *iface,
437     IWICBitmapSource **ppIBitmapSource)
438 {
439     FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
440     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
441 }
442 
443 static HRESULT WINAPI JpegDecoder_GetColorContexts(IWICBitmapDecoder *iface,
444     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
445 {
446     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
447     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
448 }
449 
450 static HRESULT WINAPI JpegDecoder_GetThumbnail(IWICBitmapDecoder *iface,
451     IWICBitmapSource **ppIThumbnail)
452 {
453     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
454     return WINCODEC_ERR_CODECNOTHUMBNAIL;
455 }
456 
457 static HRESULT WINAPI JpegDecoder_GetFrameCount(IWICBitmapDecoder *iface,
458     UINT *pCount)
459 {
460     if (!pCount) return E_INVALIDARG;
461 
462     *pCount = 1;
463     return S_OK;
464 }
465 
466 static HRESULT WINAPI JpegDecoder_GetFrame(IWICBitmapDecoder *iface,
467     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
468 {
469     JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
470     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
471 
472     if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
473 
474     if (index != 0) return E_INVALIDARG;
475 
476     IWICBitmapDecoder_AddRef(iface);
477     *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
478 
479     return S_OK;
480 }
481 
482 static const IWICBitmapDecoderVtbl JpegDecoder_Vtbl = {
483     JpegDecoder_QueryInterface,
484     JpegDecoder_AddRef,
485     JpegDecoder_Release,
486     JpegDecoder_QueryCapability,
487     JpegDecoder_Initialize,
488     JpegDecoder_GetContainerFormat,
489     JpegDecoder_GetDecoderInfo,
490     JpegDecoder_CopyPalette,
491     JpegDecoder_GetMetadataQueryReader,
492     JpegDecoder_GetPreview,
493     JpegDecoder_GetColorContexts,
494     JpegDecoder_GetThumbnail,
495     JpegDecoder_GetFrameCount,
496     JpegDecoder_GetFrame
497 };
498 
499 static HRESULT WINAPI JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
500     void **ppv)
501 {
502     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
503 
504     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
505 
506     if (!ppv) return E_INVALIDARG;
507 
508     if (IsEqualIID(&IID_IUnknown, iid) ||
509         IsEqualIID(&IID_IWICBitmapSource, iid) ||
510         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
511     {
512         *ppv = &This->IWICBitmapFrameDecode_iface;
513     }
514     else
515     {
516         *ppv = NULL;
517         return E_NOINTERFACE;
518     }
519 
520     IUnknown_AddRef((IUnknown*)*ppv);
521     return S_OK;
522 }
523 
524 static ULONG WINAPI JpegDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
525 {
526     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
527     return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
528 }
529 
530 static ULONG WINAPI JpegDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
531 {
532     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
533     return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
534 }
535 
536 static HRESULT WINAPI JpegDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
537     UINT *puiWidth, UINT *puiHeight)
538 {
539     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
540     *puiWidth = This->cinfo.output_width;
541     *puiHeight = This->cinfo.output_height;
542     TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
543     return S_OK;
544 }
545 
546 static HRESULT WINAPI JpegDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
547     WICPixelFormatGUID *pPixelFormat)
548 {
549     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
550     TRACE("(%p,%p)\n", iface, pPixelFormat);
551     if (This->cinfo.out_color_space == JCS_RGB)
552         memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID));
553     else if (This->cinfo.out_color_space == JCS_CMYK)
554         memcpy(pPixelFormat, &GUID_WICPixelFormat32bppCMYK, sizeof(GUID));
555     else /* This->cinfo.out_color_space == JCS_GRAYSCALE */
556         memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID));
557     return S_OK;
558 }
559 
560 static HRESULT WINAPI JpegDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
561     double *pDpiX, double *pDpiY)
562 {
563     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
564 
565     EnterCriticalSection(&This->lock);
566 
567     switch (This->cinfo.density_unit)
568     {
569     case 2: /* pixels per centimeter */
570         *pDpiX = This->cinfo.X_density * 2.54;
571         *pDpiY = This->cinfo.Y_density * 2.54;
572         break;
573 
574     case 1: /* pixels per inch */
575         *pDpiX = This->cinfo.X_density;
576         *pDpiY = This->cinfo.Y_density;
577         break;
578 
579     case 0: /* unknown */
580     default:
581         *pDpiX = 96.0;
582         *pDpiY = 96.0;
583         break;
584     }
585 
586     LeaveCriticalSection(&This->lock);
587 
588     TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
589 
590     return S_OK;
591 }
592 
593 static HRESULT WINAPI JpegDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
594     IWICPalette *pIPalette)
595 {
596     FIXME("(%p,%p): stub\n", iface, pIPalette);
597     return E_NOTIMPL;
598 }
599 
600 static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
601     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
602 {
603     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
604     UINT bpp;
605     UINT stride;
606     UINT data_size;
607     UINT max_row_needed;
608     jmp_buf jmpbuf;
609     WICRect rect;
610     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
611 
612     if (!prc)
613     {
614         rect.X = 0;
615         rect.Y = 0;
616         rect.Width = This->cinfo.output_width;
617         rect.Height = This->cinfo.output_height;
618         prc = &rect;
619     }
620     else
621     {
622         if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->cinfo.output_width ||
623             prc->Y+prc->Height > This->cinfo.output_height)
624             return E_INVALIDARG;
625     }
626 
627     if (This->cinfo.out_color_space == JCS_GRAYSCALE) bpp = 8;
628     else if (This->cinfo.out_color_space == JCS_CMYK) bpp = 32;
629     else bpp = 24;
630 
631     stride = bpp * This->cinfo.output_width;
632     data_size = stride * This->cinfo.output_height;
633 
634     max_row_needed = prc->Y + prc->Height;
635     if (max_row_needed > This->cinfo.output_height) return E_INVALIDARG;
636 
637     EnterCriticalSection(&This->lock);
638 
639     if (!This->image_data)
640     {
641         This->image_data = HeapAlloc(GetProcessHeap(), 0, data_size);
642         if (!This->image_data)
643         {
644             LeaveCriticalSection(&This->lock);
645             return E_OUTOFMEMORY;
646         }
647     }
648 
649     This->cinfo.client_data = jmpbuf;
650 
651     if (setjmp(jmpbuf))
652     {
653         LeaveCriticalSection(&This->lock);
654         return E_FAIL;
655     }
656 
657     while (max_row_needed > This->cinfo.output_scanline)
658     {
659         UINT first_scanline = This->cinfo.output_scanline;
660         UINT max_rows;
661         JSAMPROW out_rows[4];
662         UINT i;
663         JDIMENSION ret;
664 
665         max_rows = min(This->cinfo.output_height-first_scanline, 4);
666         for (i=0; i<max_rows; i++)
667             out_rows[i] = This->image_data + stride * (first_scanline+i);
668 
669         ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
670 
671         if (ret == 0)
672         {
673             ERR("read_scanlines failed\n");
674             LeaveCriticalSection(&This->lock);
675             return E_FAIL;
676         }
677 
678         if (bpp == 24)
679         {
680             /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
681             reverse_bgr8(3, This->image_data + stride * first_scanline,
682                 This->cinfo.output_width, This->cinfo.output_scanline - first_scanline,
683                 stride);
684         }
685 
686         if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
687         {
688             DWORD *pDwordData = (DWORD*) (This->image_data + stride * first_scanline);
689             DWORD *pDwordDataEnd = (DWORD*) (This->image_data + This->cinfo.output_scanline * stride);
690 
691             /* Adobe JPEG's have inverted CMYK data. */
692             while(pDwordData < pDwordDataEnd)
693                 *pDwordData++ ^= 0xffffffff;
694         }
695 
696     }
697 
698     LeaveCriticalSection(&This->lock);
699 
700     return copy_pixels(bpp, This->image_data,
701         This->cinfo.output_width, This->cinfo.output_height, stride,
702         prc, cbStride, cbBufferSize, pbBuffer);
703 }
704 
705 static HRESULT WINAPI JpegDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
706     IWICMetadataQueryReader **ppIMetadataQueryReader)
707 {
708     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
709 
710     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
711 
712     if (!ppIMetadataQueryReader)
713         return E_INVALIDARG;
714 
715     return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
716 }
717 
718 static HRESULT WINAPI JpegDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
719     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
720 {
721     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
722     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
723 }
724 
725 static HRESULT WINAPI JpegDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
726     IWICBitmapSource **ppIThumbnail)
727 {
728     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
729     return WINCODEC_ERR_CODECNOTHUMBNAIL;
730 }
731 
732 static const IWICBitmapFrameDecodeVtbl JpegDecoder_Frame_Vtbl = {
733     JpegDecoder_Frame_QueryInterface,
734     JpegDecoder_Frame_AddRef,
735     JpegDecoder_Frame_Release,
736     JpegDecoder_Frame_GetSize,
737     JpegDecoder_Frame_GetPixelFormat,
738     JpegDecoder_Frame_GetResolution,
739     JpegDecoder_Frame_CopyPalette,
740     JpegDecoder_Frame_CopyPixels,
741     JpegDecoder_Frame_GetMetadataQueryReader,
742     JpegDecoder_Frame_GetColorContexts,
743     JpegDecoder_Frame_GetThumbnail
744 };
745 
746 static HRESULT WINAPI JpegDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid,
747     void **ppv)
748 {
749     JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
750     return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
751 }
752 
753 static ULONG WINAPI JpegDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
754 {
755     JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
756     return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
757 }
758 
759 static ULONG WINAPI JpegDecoder_Block_Release(IWICMetadataBlockReader *iface)
760 {
761     JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
762     return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
763 }
764 
765 static HRESULT WINAPI JpegDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
766     GUID *pguidContainerFormat)
767 {
768     TRACE("%p,%p\n", iface, pguidContainerFormat);
769 
770     if (!pguidContainerFormat) return E_INVALIDARG;
771 
772     memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID));
773 
774     return S_OK;
775 }
776 
777 static HRESULT WINAPI JpegDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
778     UINT *pcCount)
779 {
780     FIXME("%p,%p\n", iface, pcCount);
781 
782     if (!pcCount) return E_INVALIDARG;
783 
784     *pcCount = 0;
785 
786     return S_OK;
787 }
788 
789 static HRESULT WINAPI JpegDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
790     UINT nIndex, IWICMetadataReader **ppIMetadataReader)
791 {
792     FIXME("%p,%d,%p\n", iface, nIndex, ppIMetadataReader);
793     return E_INVALIDARG;
794 }
795 
796 static HRESULT WINAPI JpegDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
797     IEnumUnknown **ppIEnumMetadata)
798 {
799     FIXME("%p,%p\n", iface, ppIEnumMetadata);
800     return E_NOTIMPL;
801 }
802 
803 static const IWICMetadataBlockReaderVtbl JpegDecoder_Block_Vtbl = {
804     JpegDecoder_Block_QueryInterface,
805     JpegDecoder_Block_AddRef,
806     JpegDecoder_Block_Release,
807     JpegDecoder_Block_GetContainerFormat,
808     JpegDecoder_Block_GetCount,
809     JpegDecoder_Block_GetReaderByIndex,
810     JpegDecoder_Block_GetEnumerator,
811 };
812 
813 HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv)
814 {
815     JpegDecoder *This;
816     HRESULT ret;
817 
818     TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
819 
820     if (!libjpeg_handle && !load_libjpeg())
821     {
822         ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
823         return E_FAIL;
824     }
825 
826     *ppv = NULL;
827 
828     This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegDecoder));
829     if (!This) return E_OUTOFMEMORY;
830 
831     This->IWICBitmapDecoder_iface.lpVtbl = &JpegDecoder_Vtbl;
832     This->IWICBitmapFrameDecode_iface.lpVtbl = &JpegDecoder_Frame_Vtbl;
833     This->IWICMetadataBlockReader_iface.lpVtbl = &JpegDecoder_Block_Vtbl;
834     This->ref = 1;
835     This->initialized = FALSE;
836     This->cinfo_initialized = FALSE;
837     This->stream = NULL;
838     This->image_data = NULL;
839     InitializeCriticalSection(&This->lock);
840     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegDecoder.lock");
841 
842     ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
843     IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
844 
845     return ret;
846 }
847 
848 typedef struct jpeg_compress_format {
849     const WICPixelFormatGUID *guid;
850     int bpp;
851     int num_components;
852     J_COLOR_SPACE color_space;
853     int swap_rgb;
854 } jpeg_compress_format;
855 
856 static const jpeg_compress_format compress_formats[] = {
857     { &GUID_WICPixelFormat24bppBGR, 24, 3, JCS_RGB, 1 },
858     { &GUID_WICPixelFormat32bppCMYK, 32, 4, JCS_CMYK },
859     { &GUID_WICPixelFormat8bppGray, 8, 1, JCS_GRAYSCALE },
860     { 0 }
861 };
862 
863 typedef struct JpegEncoder {
864     IWICBitmapEncoder IWICBitmapEncoder_iface;
865     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
866     LONG ref;
867     struct jpeg_compress_struct cinfo;
868     struct jpeg_error_mgr jerr;
869     struct jpeg_destination_mgr dest_mgr;
870     BOOL initialized;
871     int frame_count;
872     BOOL frame_initialized;
873     BOOL started_compress;
874     int lines_written;
875     BOOL frame_committed;
876     BOOL committed;
877     UINT width, height;
878     double xres, yres;
879     const jpeg_compress_format *format;
880     IStream *stream;
881     WICColor palette[256];
882     UINT colors;
883     CRITICAL_SECTION lock;
884     BYTE dest_buffer[1024];
885 } JpegEncoder;
886 
887 static inline JpegEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
888 {
889     return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapEncoder_iface);
890 }
891 
892 static inline JpegEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
893 {
894     return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapFrameEncode_iface);
895 }
896 
897 static inline JpegEncoder *encoder_from_compress(j_compress_ptr compress)
898 {
899     return CONTAINING_RECORD(compress, JpegEncoder, cinfo);
900 }
901 
902 static void dest_mgr_init_destination(j_compress_ptr cinfo)
903 {
904     JpegEncoder *This = encoder_from_compress(cinfo);
905 
906     This->dest_mgr.next_output_byte = This->dest_buffer;
907     This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
908 }
909 
910 static jpeg_boolean dest_mgr_empty_output_buffer(j_compress_ptr cinfo)
911 {
912     JpegEncoder *This = encoder_from_compress(cinfo);
913     HRESULT hr;
914     ULONG byteswritten;
915 
916     hr = IStream_Write(This->stream, This->dest_buffer,
917         sizeof(This->dest_buffer), &byteswritten);
918 
919     if (hr != S_OK || byteswritten == 0)
920     {
921         ERR("Failed writing data, hr=%x\n", hr);
922         return FALSE;
923     }
924 
925     This->dest_mgr.next_output_byte = This->dest_buffer;
926     This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
927     return TRUE;
928 }
929 
930 static void dest_mgr_term_destination(j_compress_ptr cinfo)
931 {
932     JpegEncoder *This = encoder_from_compress(cinfo);
933     ULONG byteswritten;
934     HRESULT hr;
935 
936     if (This->dest_mgr.free_in_buffer != sizeof(This->dest_buffer))
937     {
938         hr = IStream_Write(This->stream, This->dest_buffer,
939             sizeof(This->dest_buffer) - This->dest_mgr.free_in_buffer, &byteswritten);
940 
941         if (hr != S_OK || byteswritten == 0)
942             ERR("Failed writing data, hr=%x\n", hr);
943     }
944 }
945 
946 static HRESULT WINAPI JpegEncoder_Frame_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
947     void **ppv)
948 {
949     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
950     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
951 
952     if (!ppv) return E_INVALIDARG;
953 
954     if (IsEqualIID(&IID_IUnknown, iid) ||
955         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
956     {
957         *ppv = &This->IWICBitmapFrameEncode_iface;
958     }
959     else
960     {
961         *ppv = NULL;
962         return E_NOINTERFACE;
963     }
964 
965     IUnknown_AddRef((IUnknown*)*ppv);
966     return S_OK;
967 }
968 
969 static ULONG WINAPI JpegEncoder_Frame_AddRef(IWICBitmapFrameEncode *iface)
970 {
971     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
972     return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
973 }
974 
975 static ULONG WINAPI JpegEncoder_Frame_Release(IWICBitmapFrameEncode *iface)
976 {
977     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
978     return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
979 }
980 
981 static HRESULT WINAPI JpegEncoder_Frame_Initialize(IWICBitmapFrameEncode *iface,
982     IPropertyBag2 *pIEncoderOptions)
983 {
984     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
985     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
986 
987     EnterCriticalSection(&This->lock);
988 
989     if (This->frame_initialized)
990     {
991         LeaveCriticalSection(&This->lock);
992         return WINCODEC_ERR_WRONGSTATE;
993     }
994 
995     This->frame_initialized = TRUE;
996 
997     LeaveCriticalSection(&This->lock);
998 
999     return S_OK;
1000 }
1001 
1002 static HRESULT WINAPI JpegEncoder_Frame_SetSize(IWICBitmapFrameEncode *iface,
1003     UINT uiWidth, UINT uiHeight)
1004 {
1005     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1006     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
1007 
1008     EnterCriticalSection(&This->lock);
1009 
1010     if (!This->frame_initialized || This->started_compress)
1011     {
1012         LeaveCriticalSection(&This->lock);
1013         return WINCODEC_ERR_WRONGSTATE;
1014     }
1015 
1016     This->width = uiWidth;
1017     This->height = uiHeight;
1018 
1019     LeaveCriticalSection(&This->lock);
1020 
1021     return S_OK;
1022 }
1023 
1024 static HRESULT WINAPI JpegEncoder_Frame_SetResolution(IWICBitmapFrameEncode *iface,
1025     double dpiX, double dpiY)
1026 {
1027     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1028     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
1029 
1030     EnterCriticalSection(&This->lock);
1031 
1032     if (!This->frame_initialized || This->started_compress)
1033     {
1034         LeaveCriticalSection(&This->lock);
1035         return WINCODEC_ERR_WRONGSTATE;
1036     }
1037 
1038     This->xres = dpiX;
1039     This->yres = dpiY;
1040 
1041     LeaveCriticalSection(&This->lock);
1042 
1043     return S_OK;
1044 }
1045 
1046 static HRESULT WINAPI JpegEncoder_Frame_SetPixelFormat(IWICBitmapFrameEncode *iface,
1047     WICPixelFormatGUID *pPixelFormat)
1048 {
1049     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1050     int i;
1051     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
1052 
1053     EnterCriticalSection(&This->lock);
1054 
1055     if (!This->frame_initialized || This->started_compress)
1056     {
1057         LeaveCriticalSection(&This->lock);
1058         return WINCODEC_ERR_WRONGSTATE;
1059     }
1060 
1061     for (i=0; compress_formats[i].guid; i++)
1062     {
1063         if (memcmp(compress_formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
1064             break;
1065     }
1066 
1067     if (!compress_formats[i].guid) i = 0;
1068 
1069     This->format = &compress_formats[i];
1070     memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
1071 
1072     LeaveCriticalSection(&This->lock);
1073 
1074     return S_OK;
1075 }
1076 
1077 static HRESULT WINAPI JpegEncoder_Frame_SetColorContexts(IWICBitmapFrameEncode *iface,
1078     UINT cCount, IWICColorContext **ppIColorContext)
1079 {
1080     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1081     return E_NOTIMPL;
1082 }
1083 
1084 static HRESULT WINAPI JpegEncoder_Frame_SetPalette(IWICBitmapFrameEncode *iface,
1085     IWICPalette *palette)
1086 {
1087     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1088     HRESULT hr;
1089 
1090     TRACE("(%p,%p)\n", iface, palette);
1091 
1092     if (!palette) return E_INVALIDARG;
1093 
1094     EnterCriticalSection(&This->lock);
1095 
1096     if (This->frame_initialized)
1097         hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1098     else
1099         hr = WINCODEC_ERR_NOTINITIALIZED;
1100 
1101     LeaveCriticalSection(&This->lock);
1102     return hr;
1103 }
1104 
1105 static HRESULT WINAPI JpegEncoder_Frame_SetThumbnail(IWICBitmapFrameEncode *iface,
1106     IWICBitmapSource *pIThumbnail)
1107 {
1108     FIXME("(%p,%p): stub\n", iface, pIThumbnail);
1109     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1110 }
1111 
1112 static HRESULT WINAPI JpegEncoder_Frame_WritePixels(IWICBitmapFrameEncode *iface,
1113     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
1114 {
1115     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1116     jmp_buf jmpbuf;
1117     BYTE *swapped_data = NULL, *current_row;
1118     UINT line;
1119     int row_size;
1120     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
1121 
1122     EnterCriticalSection(&This->lock);
1123 
1124     if (!This->frame_initialized || !This->width || !This->height || !This->format)
1125     {
1126         LeaveCriticalSection(&This->lock);
1127         return WINCODEC_ERR_WRONGSTATE;
1128     }
1129 
1130     if (lineCount == 0 || lineCount + This->lines_written > This->height)
1131     {
1132         LeaveCriticalSection(&This->lock);
1133         return E_INVALIDARG;
1134     }
1135 
1136     /* set up setjmp/longjmp error handling */
1137     if (setjmp(jmpbuf))
1138     {
1139         LeaveCriticalSection(&This->lock);
1140         HeapFree(GetProcessHeap(), 0, swapped_data);
1141         return E_FAIL;
1142     }
1143     This->cinfo.client_data = jmpbuf;
1144 
1145     if (!This->started_compress)
1146     {
1147         This->cinfo.image_width = This->width;
1148         This->cinfo.image_height = This->height;
1149         This->cinfo.input_components = This->format->num_components;
1150         This->cinfo.in_color_space = This->format->color_space;
1151 
1152         pjpeg_set_defaults(&This->cinfo);
1153 
1154         if (This->xres != 0.0 && This->yres != 0.0)
1155         {
1156             This->cinfo.density_unit = 1; /* dots per inch */
1157             This->cinfo.X_density = This->xres;
1158             This->cinfo.Y_density = This->yres;
1159         }
1160 
1161         pjpeg_start_compress(&This->cinfo, TRUE);
1162 
1163         This->started_compress = TRUE;
1164     }
1165 
1166     row_size = This->format->bpp / 8 * This->width;
1167 
1168     if (This->format->swap_rgb)
1169     {
1170         swapped_data = HeapAlloc(GetProcessHeap(), 0, row_size);
1171         if (!swapped_data)
1172         {
1173             LeaveCriticalSection(&This->lock);
1174             return E_OUTOFMEMORY;
1175         }
1176     }
1177 
1178     for (line=0; line < lineCount; line++)
1179     {
1180         if (This->format->swap_rgb)
1181         {
1182             UINT x;
1183 
1184             memcpy(swapped_data, pbPixels + (cbStride * line), row_size);
1185 
1186             for (x=0; x < This->width; x++)
1187             {
1188                 BYTE b;
1189 
1190                 b = swapped_data[x*3];
1191                 swapped_data[x*3] = swapped_data[x*3+2];
1192                 swapped_data[x*3+2] = b;
1193             }
1194 
1195             current_row = swapped_data;
1196         }
1197         else
1198             current_row = pbPixels + (cbStride * line);
1199 
1200         if (!pjpeg_write_scanlines(&This->cinfo, &current_row, 1))
1201         {
1202             ERR("failed writing scanlines\n");
1203             LeaveCriticalSection(&This->lock);
1204             HeapFree(GetProcessHeap(), 0, swapped_data);
1205             return E_FAIL;
1206         }
1207 
1208         This->lines_written++;
1209     }
1210 
1211     LeaveCriticalSection(&This->lock);
1212     HeapFree(GetProcessHeap(), 0, swapped_data);
1213 
1214     return S_OK;
1215 }
1216 
1217 static HRESULT WINAPI JpegEncoder_Frame_WriteSource(IWICBitmapFrameEncode *iface,
1218     IWICBitmapSource *pIBitmapSource, WICRect *prc)
1219 {
1220     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1221     HRESULT hr;
1222     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
1223 
1224     if (!This->frame_initialized)
1225         return WINCODEC_ERR_WRONGSTATE;
1226 
1227     hr = configure_write_source(iface, pIBitmapSource, prc,
1228         This->format ? This->format->guid : NULL, This->width, This->height,
1229         This->xres, This->yres);
1230 
1231     if (SUCCEEDED(hr))
1232     {
1233         hr = write_source(iface, pIBitmapSource, prc,
1234             This->format->guid, This->format->bpp, This->width, This->height);
1235     }
1236 
1237     return hr;
1238 }
1239 
1240 static HRESULT WINAPI JpegEncoder_Frame_Commit(IWICBitmapFrameEncode *iface)
1241 {
1242     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1243     jmp_buf jmpbuf;
1244     TRACE("(%p)\n", iface);
1245 
1246     EnterCriticalSection(&This->lock);
1247 
1248     if (!This->started_compress || This->lines_written != This->height || This->frame_committed)
1249     {
1250         LeaveCriticalSection(&This->lock);
1251         return WINCODEC_ERR_WRONGSTATE;
1252     }
1253 
1254     /* set up setjmp/longjmp error handling */
1255     if (setjmp(jmpbuf))
1256     {
1257         LeaveCriticalSection(&This->lock);
1258         return E_FAIL;
1259     }
1260     This->cinfo.client_data = jmpbuf;
1261 
1262     pjpeg_finish_compress(&This->cinfo);
1263 
1264     This->frame_committed = TRUE;
1265 
1266     LeaveCriticalSection(&This->lock);
1267 
1268     return S_OK;
1269 }
1270 
1271 static HRESULT WINAPI JpegEncoder_Frame_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1272     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1273 {
1274     FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1275     return E_NOTIMPL;
1276 }
1277 
1278 static const IWICBitmapFrameEncodeVtbl JpegEncoder_FrameVtbl = {
1279     JpegEncoder_Frame_QueryInterface,
1280     JpegEncoder_Frame_AddRef,
1281     JpegEncoder_Frame_Release,
1282     JpegEncoder_Frame_Initialize,
1283     JpegEncoder_Frame_SetSize,
1284     JpegEncoder_Frame_SetResolution,
1285     JpegEncoder_Frame_SetPixelFormat,
1286     JpegEncoder_Frame_SetColorContexts,
1287     JpegEncoder_Frame_SetPalette,
1288     JpegEncoder_Frame_SetThumbnail,
1289     JpegEncoder_Frame_WritePixels,
1290     JpegEncoder_Frame_WriteSource,
1291     JpegEncoder_Frame_Commit,
1292     JpegEncoder_Frame_GetMetadataQueryWriter
1293 };
1294 
1295 static HRESULT WINAPI JpegEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1296     void **ppv)
1297 {
1298     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1299     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1300 
1301     if (!ppv) return E_INVALIDARG;
1302 
1303     if (IsEqualIID(&IID_IUnknown, iid) ||
1304         IsEqualIID(&IID_IWICBitmapEncoder, iid))
1305     {
1306         *ppv = &This->IWICBitmapEncoder_iface;
1307     }
1308     else
1309     {
1310         *ppv = NULL;
1311         return E_NOINTERFACE;
1312     }
1313 
1314     IUnknown_AddRef((IUnknown*)*ppv);
1315     return S_OK;
1316 }
1317 
1318 static ULONG WINAPI JpegEncoder_AddRef(IWICBitmapEncoder *iface)
1319 {
1320     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1321     ULONG ref = InterlockedIncrement(&This->ref);
1322 
1323     TRACE("(%p) refcount=%u\n", iface, ref);
1324 
1325     return ref;
1326 }
1327 
1328 static ULONG WINAPI JpegEncoder_Release(IWICBitmapEncoder *iface)
1329 {
1330     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1331     ULONG ref = InterlockedDecrement(&This->ref);
1332 
1333     TRACE("(%p) refcount=%u\n", iface, ref);
1334 
1335     if (ref == 0)
1336     {
1337         This->lock.DebugInfo->Spare[0] = 0;
1338         DeleteCriticalSection(&This->lock);
1339         if (This->initialized) pjpeg_destroy_compress(&This->cinfo);
1340         if (This->stream) IStream_Release(This->stream);
1341         HeapFree(GetProcessHeap(), 0, This);
1342     }
1343 
1344     return ref;
1345 }
1346 
1347 static HRESULT WINAPI JpegEncoder_Initialize(IWICBitmapEncoder *iface,
1348     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1349 {
1350     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1351     jmp_buf jmpbuf;
1352 
1353     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
1354 
1355     EnterCriticalSection(&This->lock);
1356 
1357     if (This->initialized)
1358     {
1359         LeaveCriticalSection(&This->lock);
1360         return WINCODEC_ERR_WRONGSTATE;
1361     }
1362 
1363     pjpeg_std_error(&This->jerr);
1364 
1365     This->jerr.error_exit = error_exit_fn;
1366     This->jerr.emit_message = emit_message_fn;
1367 
1368     This->cinfo.err = &This->jerr;
1369 
1370     This->cinfo.client_data = jmpbuf;
1371 
1372     if (setjmp(jmpbuf))
1373     {
1374         LeaveCriticalSection(&This->lock);
1375         return E_FAIL;
1376     }
1377 
1378     pjpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct));
1379 
1380     This->stream = pIStream;
1381     IStream_AddRef(pIStream);
1382 
1383     This->dest_mgr.next_output_byte = This->dest_buffer;
1384     This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
1385 
1386     This->dest_mgr.init_destination = dest_mgr_init_destination;
1387     This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer;
1388     This->dest_mgr.term_destination = dest_mgr_term_destination;
1389 
1390     This->cinfo.dest = &This->dest_mgr;
1391 
1392     This->initialized = TRUE;
1393 
1394     LeaveCriticalSection(&This->lock);
1395 
1396     return S_OK;
1397 }
1398 
1399 static HRESULT WINAPI JpegEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
1400     GUID *pguidContainerFormat)
1401 {
1402     FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
1403     return E_NOTIMPL;
1404 }
1405 
1406 static HRESULT WINAPI JpegEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
1407 {
1408     IWICComponentInfo *comp_info;
1409     HRESULT hr;
1410 
1411     TRACE("%p,%p\n", iface, info);
1412 
1413     if (!info) return E_INVALIDARG;
1414 
1415     hr = CreateComponentInfo(&CLSID_WICJpegEncoder, &comp_info);
1416     if (hr == S_OK)
1417     {
1418         hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
1419         IWICComponentInfo_Release(comp_info);
1420     }
1421     return hr;
1422 }
1423 
1424 static HRESULT WINAPI JpegEncoder_SetColorContexts(IWICBitmapEncoder *iface,
1425     UINT cCount, IWICColorContext **ppIColorContext)
1426 {
1427     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1428     return E_NOTIMPL;
1429 }
1430 
1431 static HRESULT WINAPI JpegEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
1432 {
1433     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1434     HRESULT hr;
1435 
1436     TRACE("(%p,%p)\n", iface, pIPalette);
1437 
1438     EnterCriticalSection(&This->lock);
1439 
1440     hr = This->initialized ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
1441 
1442     LeaveCriticalSection(&This->lock);
1443 
1444     return hr;
1445 }
1446 
1447 static HRESULT WINAPI JpegEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1448 {
1449     TRACE("(%p,%p)\n", iface, pIThumbnail);
1450     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1451 }
1452 
1453 static HRESULT WINAPI JpegEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1454 {
1455     TRACE("(%p,%p)\n", iface, pIPreview);
1456     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1457 }
1458 
1459 static HRESULT WINAPI JpegEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1460     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
1461 {
1462     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1463     HRESULT hr;
1464     static const PROPBAG2 opts[6] =
1465     {
1466         { PROPBAG2_TYPE_DATA, VT_R4,            0, 0, (LPOLESTR)wszImageQuality },
1467         { PROPBAG2_TYPE_DATA, VT_UI1,           0, 0, (LPOLESTR)wszBitmapTransform },
1468         { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszLuminance },
1469         { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszChrominance },
1470         { PROPBAG2_TYPE_DATA, VT_UI1,           0, 0, (LPOLESTR)wszJpegYCrCbSubsampling },
1471         { PROPBAG2_TYPE_DATA, VT_BOOL,          0, 0, (LPOLESTR)wszSuppressApp0 },
1472     };
1473 
1474     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
1475 
1476     EnterCriticalSection(&This->lock);
1477 
1478     if (This->frame_count != 0)
1479     {
1480         LeaveCriticalSection(&This->lock);
1481         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1482     }
1483 
1484     if (!This->initialized)
1485     {
1486         LeaveCriticalSection(&This->lock);
1487         return WINCODEC_ERR_NOTINITIALIZED;
1488     }
1489 
1490     if (ppIEncoderOptions)
1491     {
1492         hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions);
1493         if (FAILED(hr))
1494         {
1495             LeaveCriticalSection(&This->lock);
1496             return hr;
1497         }
1498     }
1499 
1500     This->frame_count = 1;
1501 
1502     LeaveCriticalSection(&This->lock);
1503 
1504     IWICBitmapEncoder_AddRef(iface);
1505     *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface;
1506 
1507     return S_OK;
1508 }
1509 
1510 static HRESULT WINAPI JpegEncoder_Commit(IWICBitmapEncoder *iface)
1511 {
1512     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1513     TRACE("(%p)\n", iface);
1514 
1515     EnterCriticalSection(&This->lock);
1516 
1517     if (!This->frame_committed || This->committed)
1518     {
1519         LeaveCriticalSection(&This->lock);
1520         return WINCODEC_ERR_WRONGSTATE;
1521     }
1522 
1523     This->committed = TRUE;
1524 
1525     LeaveCriticalSection(&This->lock);
1526 
1527     return S_OK;
1528 }
1529 
1530 static HRESULT WINAPI JpegEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1531     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1532 {
1533     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1534     return E_NOTIMPL;
1535 }
1536 
1537 static const IWICBitmapEncoderVtbl JpegEncoder_Vtbl = {
1538     JpegEncoder_QueryInterface,
1539     JpegEncoder_AddRef,
1540     JpegEncoder_Release,
1541     JpegEncoder_Initialize,
1542     JpegEncoder_GetContainerFormat,
1543     JpegEncoder_GetEncoderInfo,
1544     JpegEncoder_SetColorContexts,
1545     JpegEncoder_SetPalette,
1546     JpegEncoder_SetThumbnail,
1547     JpegEncoder_SetPreview,
1548     JpegEncoder_CreateNewFrame,
1549     JpegEncoder_Commit,
1550     JpegEncoder_GetMetadataQueryWriter
1551 };
1552 
1553 HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv)
1554 {
1555     JpegEncoder *This;
1556     HRESULT ret;
1557 
1558     TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1559 
1560     *ppv = NULL;
1561 
1562     if (!libjpeg_handle && !load_libjpeg())
1563     {
1564         ERR("Failed writing JPEG because unable to find %s\n",SONAME_LIBJPEG);
1565         return E_FAIL;
1566     }
1567 
1568     This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegEncoder));
1569     if (!This) return E_OUTOFMEMORY;
1570 
1571     This->IWICBitmapEncoder_iface.lpVtbl = &JpegEncoder_Vtbl;
1572     This->IWICBitmapFrameEncode_iface.lpVtbl = &JpegEncoder_FrameVtbl;
1573     This->ref = 1;
1574     This->initialized = FALSE;
1575     This->frame_count = 0;
1576     This->frame_initialized = FALSE;
1577     This->started_compress = FALSE;
1578     This->lines_written = 0;
1579     This->frame_committed = FALSE;
1580     This->committed = FALSE;
1581     This->width = This->height = 0;
1582     This->xres = This->yres = 0.0;
1583     This->format = NULL;
1584     This->stream = NULL;
1585     This->colors = 0;
1586     InitializeCriticalSection(&This->lock);
1587     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegEncoder.lock");
1588 
1589     ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
1590     IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1591 
1592     return ret;
1593 }
1594 
1595 #else /* !defined(SONAME_LIBJPEG) */
1596 
1597 HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv)
1598 {
1599     ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
1600     return E_FAIL;
1601 }
1602 
1603 HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv)
1604 {
1605     ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n");
1606     return E_FAIL;
1607 }
1608 
1609 #endif
1610