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