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