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