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