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