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