d3dcompiler/tests: Add D3D_BLOB_OUTPUT_SIGNATURE_BLOB test.
[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 WINE_DECLARE_DEBUG_CHANNEL(jpeg);
59
60 #ifdef SONAME_LIBJPEG
61
62 static void *libjpeg_handle;
63
64 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
65 MAKE_FUNCPTR(jpeg_CreateDecompress);
66 MAKE_FUNCPTR(jpeg_destroy_decompress);
67 MAKE_FUNCPTR(jpeg_read_header);
68 MAKE_FUNCPTR(jpeg_read_scanlines);
69 MAKE_FUNCPTR(jpeg_resync_to_restart);
70 MAKE_FUNCPTR(jpeg_start_decompress);
71 MAKE_FUNCPTR(jpeg_std_error);
72 #undef MAKE_FUNCPTR
73
74 static void *load_libjpeg(void)
75 {
76     if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
77
78 #define LOAD_FUNCPTR(f) \
79     if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
80         libjpeg_handle = NULL; \
81         return NULL; \
82     }
83
84         LOAD_FUNCPTR(jpeg_CreateDecompress);
85         LOAD_FUNCPTR(jpeg_destroy_decompress);
86         LOAD_FUNCPTR(jpeg_read_header);
87         LOAD_FUNCPTR(jpeg_read_scanlines);
88         LOAD_FUNCPTR(jpeg_resync_to_restart);
89         LOAD_FUNCPTR(jpeg_start_decompress);
90         LOAD_FUNCPTR(jpeg_std_error);
91 #undef LOAD_FUNCPTR
92     }
93     return libjpeg_handle;
94 }
95
96 static void error_exit_fn(j_common_ptr cinfo)
97 {
98     char message[JMSG_LENGTH_MAX];
99     if (ERR_ON(jpeg))
100     {
101         cinfo->err->format_message(cinfo, message);
102         ERR_(jpeg)("%s\n", message);
103     }
104     longjmp(*(jmp_buf*)cinfo->client_data, 1);
105 }
106
107 static void emit_message_fn(j_common_ptr cinfo, int msg_level)
108 {
109     char message[JMSG_LENGTH_MAX];
110
111     if (msg_level < 0 && ERR_ON(jpeg))
112     {
113         cinfo->err->format_message(cinfo, message);
114         ERR_(jpeg)("%s\n", message);
115     }
116     else if (msg_level == 0 && WARN_ON(jpeg))
117     {
118         cinfo->err->format_message(cinfo, message);
119         WARN_(jpeg)("%s\n", message);
120     }
121     else if (msg_level > 0 && TRACE_ON(jpeg))
122     {
123         cinfo->err->format_message(cinfo, message);
124         TRACE_(jpeg)("%s\n", message);
125     }
126 }
127
128 typedef struct {
129     const IWICBitmapDecoderVtbl *lpVtbl;
130     const IWICBitmapFrameDecodeVtbl *lpFrameVtbl;
131     LONG ref;
132     BOOL initialized;
133     BOOL cinfo_initialized;
134     IStream *stream;
135     struct jpeg_decompress_struct cinfo;
136     struct jpeg_error_mgr jerr;
137     struct jpeg_source_mgr source_mgr;
138     BYTE source_buffer[1024];
139     BYTE *image_data;
140     CRITICAL_SECTION lock;
141 } JpegDecoder;
142
143 static inline JpegDecoder *decoder_from_decompress(j_decompress_ptr decompress)
144 {
145     return CONTAINING_RECORD(decompress, JpegDecoder, cinfo);
146 }
147
148 static inline JpegDecoder *decoder_from_frame(IWICBitmapFrameDecode *iface)
149 {
150     return CONTAINING_RECORD(iface, JpegDecoder, lpFrameVtbl);
151 }
152
153 static HRESULT WINAPI JpegDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
154     void **ppv)
155 {
156     JpegDecoder *This = (JpegDecoder*)iface;
157     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
158
159     if (!ppv) return E_INVALIDARG;
160
161     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
162     {
163         *ppv = This;
164     }
165     else
166     {
167         *ppv = NULL;
168         return E_NOINTERFACE;
169     }
170
171     IUnknown_AddRef((IUnknown*)*ppv);
172     return S_OK;
173 }
174
175 static ULONG WINAPI JpegDecoder_AddRef(IWICBitmapDecoder *iface)
176 {
177     JpegDecoder *This = (JpegDecoder*)iface;
178     ULONG ref = InterlockedIncrement(&This->ref);
179
180     TRACE("(%p) refcount=%u\n", iface, ref);
181
182     return ref;
183 }
184
185 static ULONG WINAPI JpegDecoder_Release(IWICBitmapDecoder *iface)
186 {
187     JpegDecoder *This = (JpegDecoder*)iface;
188     ULONG ref = InterlockedDecrement(&This->ref);
189
190     TRACE("(%p) refcount=%u\n", iface, ref);
191
192     if (ref == 0)
193     {
194         This->lock.DebugInfo->Spare[0] = 0;
195         DeleteCriticalSection(&This->lock);
196         if (This->cinfo_initialized) pjpeg_destroy_decompress(&This->cinfo);
197         if (This->stream) IStream_Release(This->stream);
198         HeapFree(GetProcessHeap(), 0, This->image_data);
199         HeapFree(GetProcessHeap(), 0, This);
200     }
201
202     return ref;
203 }
204
205 static HRESULT WINAPI JpegDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
206     DWORD *pdwCapability)
207 {
208     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
209     return E_NOTIMPL;
210 }
211
212 static void source_mgr_init_source(j_decompress_ptr cinfo)
213 {
214 }
215
216 static jpeg_boolean source_mgr_fill_input_buffer(j_decompress_ptr cinfo)
217 {
218     JpegDecoder *This = decoder_from_decompress(cinfo);
219     HRESULT hr;
220     ULONG bytesread;
221
222     hr = IStream_Read(This->stream, This->source_buffer, 1024, &bytesread);
223
224     if (hr != S_OK || bytesread == 0)
225     {
226         return FALSE;
227     }
228     else
229     {
230         This->source_mgr.next_input_byte = This->source_buffer;
231         This->source_mgr.bytes_in_buffer = bytesread;
232         return TRUE;
233     }
234 }
235
236 static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
237 {
238     JpegDecoder *This = decoder_from_decompress(cinfo);
239     LARGE_INTEGER seek;
240
241     if (num_bytes > This->source_mgr.bytes_in_buffer)
242     {
243         seek.QuadPart = num_bytes - This->source_mgr.bytes_in_buffer;
244         IStream_Seek(This->stream, seek, STREAM_SEEK_CUR, NULL);
245         This->source_mgr.bytes_in_buffer = 0;
246     }
247     else if (num_bytes > 0)
248     {
249         This->source_mgr.next_input_byte += num_bytes;
250         This->source_mgr.bytes_in_buffer -= num_bytes;
251     }
252 }
253
254 static void source_mgr_term_source(j_decompress_ptr cinfo)
255 {
256 }
257
258 static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
259     WICDecodeOptions cacheOptions)
260 {
261     JpegDecoder *This = (JpegDecoder*)iface;
262     int ret;
263     LARGE_INTEGER seek;
264     jmp_buf jmpbuf;
265     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
266
267     EnterCriticalSection(&This->lock);
268
269     if (This->cinfo_initialized)
270     {
271         LeaveCriticalSection(&This->lock);
272         return WINCODEC_ERR_WRONGSTATE;
273     }
274
275     pjpeg_std_error(&This->jerr);
276
277     This->jerr.error_exit = error_exit_fn;
278     This->jerr.emit_message = emit_message_fn;
279
280     This->cinfo.err = &This->jerr;
281
282     This->cinfo.client_data = &jmpbuf;
283
284     if (setjmp(jmpbuf))
285     {
286         LeaveCriticalSection(&This->lock);
287         return E_FAIL;
288     }
289
290     pjpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
291
292     This->cinfo_initialized = TRUE;
293
294     This->stream = pIStream;
295     IStream_AddRef(pIStream);
296
297     seek.QuadPart = 0;
298     IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
299
300     This->source_mgr.bytes_in_buffer = 0;
301     This->source_mgr.init_source = source_mgr_init_source;
302     This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer;
303     This->source_mgr.skip_input_data = source_mgr_skip_input_data;
304     This->source_mgr.resync_to_restart = pjpeg_resync_to_restart;
305     This->source_mgr.term_source = source_mgr_term_source;
306
307     This->cinfo.src = &This->source_mgr;
308
309     ret = pjpeg_read_header(&This->cinfo, TRUE);
310
311     if (ret != JPEG_HEADER_OK) {
312         WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret);
313         LeaveCriticalSection(&This->lock);
314         return E_FAIL;
315     }
316
317     switch (This->cinfo.jpeg_color_space)
318     {
319     case JCS_GRAYSCALE:
320         This->cinfo.out_color_space = JCS_GRAYSCALE;
321         break;
322     case JCS_RGB:
323     case JCS_YCbCr:
324         This->cinfo.out_color_space = JCS_RGB;
325         break;
326     case JCS_CMYK:
327     case JCS_YCCK:
328         This->cinfo.out_color_space = JCS_CMYK;
329         break;
330     default:
331         ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space);
332         LeaveCriticalSection(&This->lock);
333         return E_FAIL;
334     }
335
336     if (!pjpeg_start_decompress(&This->cinfo))
337     {
338         ERR("jpeg_start_decompress failed\n");
339         LeaveCriticalSection(&This->lock);
340         return E_FAIL;
341     }
342
343     This->initialized = TRUE;
344
345     LeaveCriticalSection(&This->lock);
346
347     return S_OK;
348 }
349
350 static HRESULT WINAPI JpegDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
351     GUID *pguidContainerFormat)
352 {
353     memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID));
354     return S_OK;
355 }
356
357 static HRESULT WINAPI JpegDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
358     IWICBitmapDecoderInfo **ppIDecoderInfo)
359 {
360     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
361     return E_NOTIMPL;
362 }
363
364 static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface,
365     IWICPalette *pIPalette)
366 {
367     TRACE("(%p,%p)\n", iface, pIPalette);
368
369     return WINCODEC_ERR_PALETTEUNAVAILABLE;
370 }
371
372 static HRESULT WINAPI JpegDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
373     IWICMetadataQueryReader **ppIMetadataQueryReader)
374 {
375     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
376     return E_NOTIMPL;
377 }
378
379 static HRESULT WINAPI JpegDecoder_GetPreview(IWICBitmapDecoder *iface,
380     IWICBitmapSource **ppIBitmapSource)
381 {
382     FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
383     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
384 }
385
386 static HRESULT WINAPI JpegDecoder_GetColorContexts(IWICBitmapDecoder *iface,
387     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
388 {
389     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
390     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
391 }
392
393 static HRESULT WINAPI JpegDecoder_GetThumbnail(IWICBitmapDecoder *iface,
394     IWICBitmapSource **ppIThumbnail)
395 {
396     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
397     return WINCODEC_ERR_CODECNOTHUMBNAIL;
398 }
399
400 static HRESULT WINAPI JpegDecoder_GetFrameCount(IWICBitmapDecoder *iface,
401     UINT *pCount)
402 {
403     *pCount = 1;
404     return S_OK;
405 }
406
407 static HRESULT WINAPI JpegDecoder_GetFrame(IWICBitmapDecoder *iface,
408     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
409 {
410     JpegDecoder *This = (JpegDecoder*)iface;
411     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
412
413     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
414
415     if (index != 0) return E_INVALIDARG;
416
417     IWICBitmapDecoder_AddRef(iface);
418     *ppIBitmapFrame = (IWICBitmapFrameDecode*)&This->lpFrameVtbl;
419
420     return S_OK;
421 }
422
423 static const IWICBitmapDecoderVtbl JpegDecoder_Vtbl = {
424     JpegDecoder_QueryInterface,
425     JpegDecoder_AddRef,
426     JpegDecoder_Release,
427     JpegDecoder_QueryCapability,
428     JpegDecoder_Initialize,
429     JpegDecoder_GetContainerFormat,
430     JpegDecoder_GetDecoderInfo,
431     JpegDecoder_CopyPalette,
432     JpegDecoder_GetMetadataQueryReader,
433     JpegDecoder_GetPreview,
434     JpegDecoder_GetColorContexts,
435     JpegDecoder_GetThumbnail,
436     JpegDecoder_GetFrameCount,
437     JpegDecoder_GetFrame
438 };
439
440 static HRESULT WINAPI JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
441     void **ppv)
442 {
443     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
444
445     if (!ppv) return E_INVALIDARG;
446
447     if (IsEqualIID(&IID_IUnknown, iid) ||
448         IsEqualIID(&IID_IWICBitmapSource, iid) ||
449         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
450     {
451         *ppv = iface;
452     }
453     else
454     {
455         *ppv = NULL;
456         return E_NOINTERFACE;
457     }
458
459     IUnknown_AddRef((IUnknown*)*ppv);
460     return S_OK;
461 }
462
463 static ULONG WINAPI JpegDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
464 {
465     JpegDecoder *This = decoder_from_frame(iface);
466     return IUnknown_AddRef((IUnknown*)This);
467 }
468
469 static ULONG WINAPI JpegDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
470 {
471     JpegDecoder *This = decoder_from_frame(iface);
472     return IUnknown_Release((IUnknown*)This);
473 }
474
475 static HRESULT WINAPI JpegDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
476     UINT *puiWidth, UINT *puiHeight)
477 {
478     JpegDecoder *This = decoder_from_frame(iface);
479     *puiWidth = This->cinfo.output_width;
480     *puiHeight = This->cinfo.output_height;
481     TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
482     return S_OK;
483 }
484
485 static HRESULT WINAPI JpegDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
486     WICPixelFormatGUID *pPixelFormat)
487 {
488     JpegDecoder *This = decoder_from_frame(iface);
489     TRACE("(%p,%p)\n", iface, pPixelFormat);
490     if (This->cinfo.out_color_space == JCS_RGB)
491         memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID));
492     else if (This->cinfo.out_color_space == JCS_CMYK)
493         memcpy(pPixelFormat, &GUID_WICPixelFormat32bppCMYK, sizeof(GUID));
494     else /* This->cinfo.out_color_space == JCS_GRAYSCALE */
495         memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID));
496     return S_OK;
497 }
498
499 static HRESULT WINAPI JpegDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
500     double *pDpiX, double *pDpiY)
501 {
502     FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
503     return E_NOTIMPL;
504 }
505
506 static HRESULT WINAPI JpegDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
507     IWICPalette *pIPalette)
508 {
509     FIXME("(%p,%p): stub\n", iface, pIPalette);
510     return E_NOTIMPL;
511 }
512
513 static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
514     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
515 {
516     JpegDecoder *This = decoder_from_frame(iface);
517     UINT bpp;
518     UINT stride;
519     UINT data_size;
520     UINT max_row_needed;
521     jmp_buf jmpbuf;
522     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
523
524     if (This->cinfo.out_color_space == JCS_GRAYSCALE) bpp = 8;
525     else if (This->cinfo.out_color_space == JCS_CMYK) bpp = 32;
526     else bpp = 24;
527
528     stride = bpp * This->cinfo.output_width;
529     data_size = stride * This->cinfo.output_height;
530
531     max_row_needed = prc->Y + prc->Height;
532     if (max_row_needed > This->cinfo.output_height) return E_INVALIDARG;
533
534     EnterCriticalSection(&This->lock);
535
536     if (!This->image_data)
537     {
538         This->image_data = HeapAlloc(GetProcessHeap(), 0, data_size);
539         if (!This->image_data)
540         {
541             LeaveCriticalSection(&This->lock);
542             return E_OUTOFMEMORY;
543         }
544     }
545
546     This->cinfo.client_data = &jmpbuf;
547
548     if (setjmp(jmpbuf))
549     {
550         LeaveCriticalSection(&This->lock);
551         return E_FAIL;
552     }
553
554     while (max_row_needed > This->cinfo.output_scanline)
555     {
556         UINT first_scanline = This->cinfo.output_scanline;
557         UINT max_rows;
558         JSAMPROW out_rows[4];
559         UINT i, j;
560         JDIMENSION ret;
561
562         max_rows = min(This->cinfo.output_height-first_scanline, 4);
563         for (i=0; i<max_rows; i++)
564             out_rows[i] = This->image_data + stride * (first_scanline+i);
565
566         ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
567
568         if (ret == 0)
569         {
570             ERR("read_scanlines failed\n");
571             LeaveCriticalSection(&This->lock);
572             return E_FAIL;
573         }
574
575         if (bpp == 24)
576         {
577             /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
578             for (i=first_scanline; i<This->cinfo.output_scanline; i++)
579             {
580                 BYTE *pixel = This->image_data + stride * i;
581                 for (j=0; j<This->cinfo.output_width; j++)
582                 {
583                     BYTE red=pixel[0];
584                     BYTE blue=pixel[2];
585                     pixel[0]=blue;
586                     pixel[2]=red;
587                     pixel+=3;
588                 }
589             }
590         }
591
592         if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
593             /* Adobe JPEG's have inverted CMYK data. */
594             for (i=0; i<data_size; i++)
595                 This->image_data[i] ^= 0xff;
596     }
597
598     LeaveCriticalSection(&This->lock);
599
600     return copy_pixels(bpp, This->image_data,
601         This->cinfo.output_width, This->cinfo.output_height, stride,
602         prc, cbStride, cbBufferSize, pbBuffer);
603 }
604
605 static HRESULT WINAPI JpegDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
606     IWICMetadataQueryReader **ppIMetadataQueryReader)
607 {
608     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
609     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
610 }
611
612 static HRESULT WINAPI JpegDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
613     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
614 {
615     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
616     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
617 }
618
619 static HRESULT WINAPI JpegDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
620     IWICBitmapSource **ppIThumbnail)
621 {
622     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
623     return WINCODEC_ERR_CODECNOTHUMBNAIL;
624 }
625
626 static const IWICBitmapFrameDecodeVtbl JpegDecoder_Frame_Vtbl = {
627     JpegDecoder_Frame_QueryInterface,
628     JpegDecoder_Frame_AddRef,
629     JpegDecoder_Frame_Release,
630     JpegDecoder_Frame_GetSize,
631     JpegDecoder_Frame_GetPixelFormat,
632     JpegDecoder_Frame_GetResolution,
633     JpegDecoder_Frame_CopyPalette,
634     JpegDecoder_Frame_CopyPixels,
635     JpegDecoder_Frame_GetMetadataQueryReader,
636     JpegDecoder_Frame_GetColorContexts,
637     JpegDecoder_Frame_GetThumbnail
638 };
639
640 HRESULT JpegDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
641 {
642     JpegDecoder *This;
643     HRESULT ret;
644
645     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
646
647     if (!libjpeg_handle && !load_libjpeg())
648     {
649         ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
650         return E_FAIL;
651     }
652
653     *ppv = NULL;
654
655     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
656
657     This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegDecoder));
658     if (!This) return E_OUTOFMEMORY;
659
660     This->lpVtbl = &JpegDecoder_Vtbl;
661     This->lpFrameVtbl = &JpegDecoder_Frame_Vtbl;
662     This->ref = 1;
663     This->initialized = FALSE;
664     This->cinfo_initialized = FALSE;
665     This->stream = NULL;
666     This->image_data = NULL;
667     InitializeCriticalSection(&This->lock);
668     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegDecoder.lock");
669
670     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
671     IUnknown_Release((IUnknown*)This);
672
673     return ret;
674 }
675
676 #else /* !defined(SONAME_LIBJPEG) */
677
678 HRESULT JpegDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
679 {
680     ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
681     return E_FAIL;
682 }
683
684 #endif