mshtml: Use lazy allocation for connection points.
[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     UINT line;
1002     int row_size;
1003     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
1004
1005     EnterCriticalSection(&This->lock);
1006
1007     if (!This->frame_initialized || !This->width || !This->height || !This->format)
1008     {
1009         LeaveCriticalSection(&This->lock);
1010         return WINCODEC_ERR_WRONGSTATE;
1011     }
1012
1013     if (lineCount == 0 || lineCount + This->lines_written > This->height)
1014     {
1015         LeaveCriticalSection(&This->lock);
1016         return E_INVALIDARG;
1017     }
1018
1019     /* set up setjmp/longjmp error handling */
1020     if (setjmp(jmpbuf))
1021     {
1022         LeaveCriticalSection(&This->lock);
1023         HeapFree(GetProcessHeap(), 0, swapped_data);
1024         return E_FAIL;
1025     }
1026     This->cinfo.client_data = jmpbuf;
1027
1028     if (!This->started_compress)
1029     {
1030         This->cinfo.image_width = This->width;
1031         This->cinfo.image_height = This->height;
1032         This->cinfo.input_components = This->format->num_components;
1033         This->cinfo.in_color_space = This->format->color_space;
1034
1035         pjpeg_set_defaults(&This->cinfo);
1036
1037         if (This->xres != 0.0 && This->yres != 0.0)
1038         {
1039             This->cinfo.density_unit = 1; /* dots per inch */
1040             This->cinfo.X_density = This->xres;
1041             This->cinfo.Y_density = This->yres;
1042         }
1043
1044         pjpeg_start_compress(&This->cinfo, TRUE);
1045
1046         This->started_compress = 1;
1047     }
1048
1049     row_size = This->format->bpp / 8 * This->width;
1050
1051     if (This->format->swap_rgb)
1052     {
1053         swapped_data = HeapAlloc(GetProcessHeap(), 0, row_size);
1054         if (!swapped_data)
1055         {
1056             LeaveCriticalSection(&This->lock);
1057             return E_OUTOFMEMORY;
1058         }
1059     }
1060
1061     for (line=0; line < lineCount; line++)
1062     {
1063         if (This->format->swap_rgb)
1064         {
1065             UINT x;
1066
1067             memcpy(swapped_data, pbPixels + (cbStride * line), row_size);
1068
1069             for (x=0; x < This->width; x++)
1070             {
1071                 BYTE b;
1072
1073                 b = swapped_data[x*3];
1074                 swapped_data[x*3] = swapped_data[x*3+2];
1075                 swapped_data[x*3+2] = b;
1076             }
1077
1078             current_row = swapped_data;
1079         }
1080         else
1081             current_row = pbPixels + (cbStride * line);
1082
1083         if (!pjpeg_write_scanlines(&This->cinfo, &current_row, 1))
1084         {
1085             ERR("failed writing scanlines\n");
1086             LeaveCriticalSection(&This->lock);
1087             HeapFree(GetProcessHeap(), 0, swapped_data);
1088             return E_FAIL;
1089         }
1090
1091         This->lines_written++;
1092     }
1093
1094     LeaveCriticalSection(&This->lock);
1095     HeapFree(GetProcessHeap(), 0, swapped_data);
1096
1097     return S_OK;
1098 }
1099
1100 static HRESULT WINAPI JpegEncoder_Frame_WriteSource(IWICBitmapFrameEncode *iface,
1101     IWICBitmapSource *pIBitmapSource, WICRect *prc)
1102 {
1103     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1104     HRESULT hr;
1105     WICRect rc;
1106     WICPixelFormatGUID guid;
1107     UINT stride;
1108     BYTE *pixeldata;
1109     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
1110
1111     if (!This->frame_initialized || !This->width || !This->height)
1112         return WINCODEC_ERR_WRONGSTATE;
1113
1114     if (!This->format)
1115     {
1116         hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
1117         if (FAILED(hr)) return hr;
1118         hr = IWICBitmapFrameEncode_SetPixelFormat(iface, &guid);
1119         if (FAILED(hr)) return hr;
1120     }
1121
1122     hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
1123     if (FAILED(hr)) return hr;
1124     if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
1125     {
1126         /* FIXME: should use WICConvertBitmapSource to convert */
1127         ERR("format %s unsupported\n", debugstr_guid(&guid));
1128         return E_FAIL;
1129     }
1130
1131     if (This->xres == 0.0 || This->yres == 0.0)
1132     {
1133         double xres, yres;
1134         hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
1135         if (FAILED(hr)) return hr;
1136         hr = IWICBitmapFrameEncode_SetResolution(iface, xres, yres);
1137         if (FAILED(hr)) return hr;
1138     }
1139
1140     if (!prc)
1141     {
1142         UINT width, height;
1143         hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
1144         if (FAILED(hr)) return hr;
1145         rc.X = 0;
1146         rc.Y = 0;
1147         rc.Width = width;
1148         rc.Height = height;
1149         prc = &rc;
1150     }
1151
1152     if (prc->Width != This->width) return E_INVALIDARG;
1153
1154     stride = (This->format->bpp * This->width + 7)/8;
1155
1156     pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
1157     if (!pixeldata) return E_OUTOFMEMORY;
1158
1159     hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
1160         stride*prc->Height, pixeldata);
1161
1162     if (SUCCEEDED(hr))
1163     {
1164         hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
1165             stride*prc->Height, pixeldata);
1166     }
1167
1168     HeapFree(GetProcessHeap(), 0, pixeldata);
1169
1170     return hr;
1171 }
1172
1173 static HRESULT WINAPI JpegEncoder_Frame_Commit(IWICBitmapFrameEncode *iface)
1174 {
1175     JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1176     jmp_buf jmpbuf;
1177     TRACE("(%p)\n", iface);
1178
1179     EnterCriticalSection(&This->lock);
1180
1181     if (!This->started_compress || This->lines_written != This->height || This->frame_committed)
1182     {
1183         LeaveCriticalSection(&This->lock);
1184         return WINCODEC_ERR_WRONGSTATE;
1185     }
1186
1187     /* set up setjmp/longjmp error handling */
1188     if (setjmp(jmpbuf))
1189     {
1190         LeaveCriticalSection(&This->lock);
1191         return E_FAIL;
1192     }
1193     This->cinfo.client_data = jmpbuf;
1194
1195     pjpeg_finish_compress(&This->cinfo);
1196
1197     This->frame_committed = TRUE;
1198
1199     LeaveCriticalSection(&This->lock);
1200
1201     return S_OK;
1202 }
1203
1204 static HRESULT WINAPI JpegEncoder_Frame_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1205     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1206 {
1207     FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1208     return E_NOTIMPL;
1209 }
1210
1211 static const IWICBitmapFrameEncodeVtbl JpegEncoder_FrameVtbl = {
1212     JpegEncoder_Frame_QueryInterface,
1213     JpegEncoder_Frame_AddRef,
1214     JpegEncoder_Frame_Release,
1215     JpegEncoder_Frame_Initialize,
1216     JpegEncoder_Frame_SetSize,
1217     JpegEncoder_Frame_SetResolution,
1218     JpegEncoder_Frame_SetPixelFormat,
1219     JpegEncoder_Frame_SetColorContexts,
1220     JpegEncoder_Frame_SetPalette,
1221     JpegEncoder_Frame_SetThumbnail,
1222     JpegEncoder_Frame_WritePixels,
1223     JpegEncoder_Frame_WriteSource,
1224     JpegEncoder_Frame_Commit,
1225     JpegEncoder_Frame_GetMetadataQueryWriter
1226 };
1227
1228 static HRESULT WINAPI JpegEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1229     void **ppv)
1230 {
1231     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1232     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1233
1234     if (!ppv) return E_INVALIDARG;
1235
1236     if (IsEqualIID(&IID_IUnknown, iid) ||
1237         IsEqualIID(&IID_IWICBitmapEncoder, iid))
1238     {
1239         *ppv = &This->IWICBitmapEncoder_iface;
1240     }
1241     else
1242     {
1243         *ppv = NULL;
1244         return E_NOINTERFACE;
1245     }
1246
1247     IUnknown_AddRef((IUnknown*)*ppv);
1248     return S_OK;
1249 }
1250
1251 static ULONG WINAPI JpegEncoder_AddRef(IWICBitmapEncoder *iface)
1252 {
1253     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1254     ULONG ref = InterlockedIncrement(&This->ref);
1255
1256     TRACE("(%p) refcount=%u\n", iface, ref);
1257
1258     return ref;
1259 }
1260
1261 static ULONG WINAPI JpegEncoder_Release(IWICBitmapEncoder *iface)
1262 {
1263     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1264     ULONG ref = InterlockedDecrement(&This->ref);
1265
1266     TRACE("(%p) refcount=%u\n", iface, ref);
1267
1268     if (ref == 0)
1269     {
1270         This->lock.DebugInfo->Spare[0] = 0;
1271         DeleteCriticalSection(&This->lock);
1272         if (This->initialized) pjpeg_destroy_compress(&This->cinfo);
1273         if (This->stream) IStream_Release(This->stream);
1274         HeapFree(GetProcessHeap(), 0, This);
1275     }
1276
1277     return ref;
1278 }
1279
1280 static HRESULT WINAPI JpegEncoder_Initialize(IWICBitmapEncoder *iface,
1281     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1282 {
1283     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1284     jmp_buf jmpbuf;
1285
1286     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
1287
1288     EnterCriticalSection(&This->lock);
1289
1290     if (This->initialized)
1291     {
1292         LeaveCriticalSection(&This->lock);
1293         return WINCODEC_ERR_WRONGSTATE;
1294     }
1295
1296     pjpeg_std_error(&This->jerr);
1297
1298     This->jerr.error_exit = error_exit_fn;
1299     This->jerr.emit_message = emit_message_fn;
1300
1301     This->cinfo.err = &This->jerr;
1302
1303     This->cinfo.client_data = jmpbuf;
1304
1305     if (setjmp(jmpbuf))
1306     {
1307         LeaveCriticalSection(&This->lock);
1308         return E_FAIL;
1309     }
1310
1311     pjpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct));
1312
1313     This->stream = pIStream;
1314     IStream_AddRef(pIStream);
1315
1316     This->dest_mgr.next_output_byte = This->dest_buffer;
1317     This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
1318
1319     This->dest_mgr.init_destination = dest_mgr_init_destination;
1320     This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer;
1321     This->dest_mgr.term_destination = dest_mgr_term_destination;
1322
1323     This->cinfo.dest = &This->dest_mgr;
1324
1325     This->initialized = TRUE;
1326
1327     LeaveCriticalSection(&This->lock);
1328
1329     return S_OK;
1330 }
1331
1332 static HRESULT WINAPI JpegEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
1333     GUID *pguidContainerFormat)
1334 {
1335     FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
1336     return E_NOTIMPL;
1337 }
1338
1339 static HRESULT WINAPI JpegEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
1340     IWICBitmapEncoderInfo **ppIEncoderInfo)
1341 {
1342     FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
1343     return E_NOTIMPL;
1344 }
1345
1346 static HRESULT WINAPI JpegEncoder_SetColorContexts(IWICBitmapEncoder *iface,
1347     UINT cCount, IWICColorContext **ppIColorContext)
1348 {
1349     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1350     return E_NOTIMPL;
1351 }
1352
1353 static HRESULT WINAPI JpegEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
1354 {
1355     TRACE("(%p,%p)\n", iface, pIPalette);
1356     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1357 }
1358
1359 static HRESULT WINAPI JpegEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1360 {
1361     TRACE("(%p,%p)\n", iface, pIThumbnail);
1362     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1363 }
1364
1365 static HRESULT WINAPI JpegEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1366 {
1367     TRACE("(%p,%p)\n", iface, pIPreview);
1368     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1369 }
1370
1371 static HRESULT WINAPI JpegEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1372     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
1373 {
1374     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1375     HRESULT hr;
1376
1377     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
1378
1379     EnterCriticalSection(&This->lock);
1380
1381     if (This->frame_count != 0)
1382     {
1383         LeaveCriticalSection(&This->lock);
1384         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1385     }
1386
1387     if (!This->initialized)
1388     {
1389         LeaveCriticalSection(&This->lock);
1390         return WINCODEC_ERR_NOTINITIALIZED;
1391     }
1392
1393     hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions);
1394     if (FAILED(hr))
1395     {
1396         LeaveCriticalSection(&This->lock);
1397         return hr;
1398     }
1399
1400     This->frame_count = 1;
1401
1402     LeaveCriticalSection(&This->lock);
1403
1404     IWICBitmapEncoder_AddRef(iface);
1405     *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface;
1406
1407     return S_OK;
1408 }
1409
1410 static HRESULT WINAPI JpegEncoder_Commit(IWICBitmapEncoder *iface)
1411 {
1412     JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1413     TRACE("(%p)\n", iface);
1414
1415     EnterCriticalSection(&This->lock);
1416
1417     if (!This->frame_committed || This->committed)
1418     {
1419         LeaveCriticalSection(&This->lock);
1420         return WINCODEC_ERR_WRONGSTATE;
1421     }
1422
1423     This->committed = TRUE;
1424
1425     LeaveCriticalSection(&This->lock);
1426
1427     return S_OK;
1428 }
1429
1430 static HRESULT WINAPI JpegEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1431     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1432 {
1433     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1434     return E_NOTIMPL;
1435 }
1436
1437 static const IWICBitmapEncoderVtbl JpegEncoder_Vtbl = {
1438     JpegEncoder_QueryInterface,
1439     JpegEncoder_AddRef,
1440     JpegEncoder_Release,
1441     JpegEncoder_Initialize,
1442     JpegEncoder_GetContainerFormat,
1443     JpegEncoder_GetEncoderInfo,
1444     JpegEncoder_SetColorContexts,
1445     JpegEncoder_SetPalette,
1446     JpegEncoder_SetThumbnail,
1447     JpegEncoder_SetPreview,
1448     JpegEncoder_CreateNewFrame,
1449     JpegEncoder_Commit,
1450     JpegEncoder_GetMetadataQueryWriter
1451 };
1452
1453 HRESULT JpegEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1454 {
1455     JpegEncoder *This;
1456     HRESULT ret;
1457
1458     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1459
1460     *ppv = NULL;
1461
1462     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1463
1464     if (!libjpeg_handle && !load_libjpeg())
1465     {
1466         ERR("Failed writing JPEG because unable to find %s\n",SONAME_LIBJPEG);
1467         return E_FAIL;
1468     }
1469
1470     This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegEncoder));
1471     if (!This) return E_OUTOFMEMORY;
1472
1473     This->IWICBitmapEncoder_iface.lpVtbl = &JpegEncoder_Vtbl;
1474     This->IWICBitmapFrameEncode_iface.lpVtbl = &JpegEncoder_FrameVtbl;
1475     This->ref = 1;
1476     This->initialized = 0;
1477     This->frame_count = 0;
1478     This->frame_initialized = 0;
1479     This->started_compress = 0;
1480     This->lines_written = 0;
1481     This->frame_committed = 0;
1482     This->committed = 0;
1483     This->width = This->height = 0;
1484     This->xres = This->yres = 0.0;
1485     This->format = NULL;
1486     This->stream = NULL;
1487     InitializeCriticalSection(&This->lock);
1488     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegEncoder.lock");
1489
1490     ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
1491     IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1492
1493     return ret;
1494 }
1495
1496 #else /* !defined(SONAME_LIBJPEG) */
1497
1498 HRESULT JpegDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1499 {
1500     ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
1501     return E_FAIL;
1502 }
1503
1504 HRESULT JpegEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1505 {
1506     ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n");
1507     return E_FAIL;
1508 }
1509
1510 #endif