ReactOS 0.4.15-dev-8039-g69ebfd6
jpegformat.c
Go to the documentation of this file.
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
58
59#ifdef SONAME_LIBJPEG
61
62static void *libjpeg_handle;
63
64static const WCHAR wszImageQuality[] = {'I','m','a','g','e','Q','u','a','l','i','t','y',0};
65static const WCHAR wszBitmapTransform[] = {'B','i','t','m','a','p','T','r','a','n','s','f','o','r','m',0};
66static const WCHAR wszLuminance[] = {'L','u','m','i','n','a','n','c','e',0};
67static const WCHAR wszChrominance[] = {'C','h','r','o','m','i','n','a','n','c','e',0};
68static const WCHAR wszJpegYCrCbSubsampling[] = {'J','p','e','g','Y','C','r','C','b','S','u','b','s','a','m','p','l','i','n','g',0};
69static 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
82MAKE_FUNCPTR(jpeg_start_decompress);
85#undef MAKE_FUNCPTR
86
87static 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
107 LOAD_FUNCPTR(jpeg_start_decompress);
110#undef LOAD_FUNCPTR
111 }
112 return libjpeg_handle;
113}
114
115static void error_exit_fn(j_common_ptr cinfo)
116{
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
126static void emit_message_fn(j_common_ptr cinfo, int msg_level)
127{
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
147typedef struct {
148 IWICBitmapDecoder IWICBitmapDecoder_iface;
149 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
150 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
151 LONG ref;
153 BOOL cinfo_initialized;
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;
162} JpegDecoder;
163
164static inline JpegDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
165{
166 return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapDecoder_iface);
167}
168
169static inline JpegDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
170{
171 return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapFrameDecode_iface);
172}
173
174static inline JpegDecoder *decoder_from_decompress(j_decompress_ptr decompress)
175{
176 return CONTAINING_RECORD(decompress, JpegDecoder, cinfo);
177}
178
179static inline JpegDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
180{
181 return CONTAINING_RECORD(iface, JpegDecoder, IWICMetadataBlockReader_iface);
182}
183
184static 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
207static ULONG WINAPI JpegDecoder_AddRef(IWICBitmapDecoder *iface)
208{
209 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
211
212 TRACE("(%p) refcount=%u\n", iface, ref);
213
214 return ref;
215}
216
217static ULONG WINAPI JpegDecoder_Release(IWICBitmapDecoder *iface)
218{
219 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
221
222 TRACE("(%p) refcount=%u\n", iface, ref);
223
224 if (ref == 0)
225 {
226 This->lock.DebugInfo->Spare[0] = 0;
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);
232 }
233
234 return ref;
235}
236
237static 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
251 /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
252 return S_OK;
253}
254
255static void source_mgr_init_source(j_decompress_ptr cinfo)
256{
257}
258
259static 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
279static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
280{
281 JpegDecoder *This = decoder_from_decompress(cinfo);
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
297static void source_mgr_term_source(j_decompress_ptr cinfo)
298{
299}
300
301static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
302 WICDecodeOptions cacheOptions)
303{
304 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
305 int ret;
308 UINT data_size, i;
309
310 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
311
313
314 if (This->cinfo_initialized)
315 {
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 {
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);
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);
378 return E_FAIL;
379 }
380
381 if (!pjpeg_start_decompress(&This->cinfo))
382 {
383 ERR("jpeg_start_decompress failed\n");
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 {
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];
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");
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
440
441 return S_OK;
442}
443
444static HRESULT WINAPI JpegDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
445 GUID *pguidContainerFormat)
446{
447 memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID));
448 return S_OK;
449}
450
451static 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
459static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface,
460 IWICPalette *pIPalette)
461{
462 TRACE("(%p,%p)\n", iface, pIPalette);
463
465}
466
467static HRESULT WINAPI JpegDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
469{
470 TRACE("(%p,%p)\n", iface, reader);
471
472 if (!reader) return E_INVALIDARG;
473
474 *reader = NULL;
476}
477
478static HRESULT WINAPI JpegDecoder_GetPreview(IWICBitmapDecoder *iface,
479 IWICBitmapSource **ppIBitmapSource)
480{
481 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
483}
484
485static 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);
490}
491
492static HRESULT WINAPI JpegDecoder_GetThumbnail(IWICBitmapDecoder *iface,
493 IWICBitmapSource **ppIThumbnail)
494{
495 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
497}
498
499static 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
508static 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
524static 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
541static 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
566static ULONG WINAPI JpegDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
567{
568 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
569 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
570}
571
572static ULONG WINAPI JpegDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
573{
574 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
575 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
576}
577
578static 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
588static 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
602static HRESULT WINAPI JpegDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
603 double *pDpiX, double *pDpiY)
604{
605 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
606
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
629
630 TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
631
632 return S_OK;
633}
634
635static 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
642static 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
654static 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
667static 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);
672}
673
674static HRESULT WINAPI JpegDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
675 IWICBitmapSource **ppIThumbnail)
676{
677 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
679}
680
681static 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
695static 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
702static ULONG WINAPI JpegDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
703{
704 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
705 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
706}
707
708static ULONG WINAPI JpegDecoder_Block_Release(IWICMetadataBlockReader *iface)
709{
710 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface);
711 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
712}
713
714static 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
726static 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
738static 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
745static HRESULT WINAPI JpegDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
746 IEnumUnknown **ppIEnumMetadata)
747{
748 FIXME("%p,%p\n", iface, ppIEnumMetadata);
749 return E_NOTIMPL;
750}
751
752static 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
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;
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
797typedef struct jpeg_compress_format {
799 int bpp;
800 int num_components;
801 J_COLOR_SPACE color_space;
802 int swap_rgb;
803} jpeg_compress_format;
804
805static 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
812typedef 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;
820 int frame_count;
821 BOOL frame_initialized;
822 BOOL started_compress;
823 int lines_written;
824 BOOL frame_committed;
825 BOOL committed;
827 double xres, yres;
828 const jpeg_compress_format *format;
830 WICColor palette[256];
831 UINT colors;
833 BYTE dest_buffer[1024];
834} JpegEncoder;
835
836static inline JpegEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
837{
838 return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapEncoder_iface);
839}
840
841static inline JpegEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
842{
843 return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapFrameEncode_iface);
844}
845
846static inline JpegEncoder *encoder_from_compress(j_compress_ptr compress)
847{
848 return CONTAINING_RECORD(compress, JpegEncoder, cinfo);
849}
850
851static 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
859static 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
879static 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
895static 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
918static ULONG WINAPI JpegEncoder_Frame_AddRef(IWICBitmapFrameEncode *iface)
919{
920 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
921 return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
922}
923
924static ULONG WINAPI JpegEncoder_Frame_Release(IWICBitmapFrameEncode *iface)
925{
926 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
927 return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
928}
929
930static 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
937
938 if (This->frame_initialized)
939 {
942 }
943
944 This->frame_initialized = TRUE;
945
947
948 return S_OK;
949}
950
951static 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
958
959 if (!This->frame_initialized || This->started_compress)
960 {
963 }
964
965 This->width = uiWidth;
966 This->height = uiHeight;
967
969
970 return S_OK;
971}
972
973static 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
980
981 if (!This->frame_initialized || This->started_compress)
982 {
985 }
986
987 This->xres = dpiX;
988 This->yres = dpiY;
989
991
992 return S_OK;
993}
994
995static 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);
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
1026static 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
1033static HRESULT WINAPI JpegEncoder_Frame_SetPalette(IWICBitmapFrameEncode *iface,
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
1049
1050 LeaveCriticalSection(&This->lock);
1051 return hr;
1052}
1053
1054static HRESULT WINAPI JpegEncoder_Frame_SetThumbnail(IWICBitmapFrameEncode *iface,
1055 IWICBitmapSource *pIThumbnail)
1056{
1057 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
1059}
1060
1061static HRESULT WINAPI JpegEncoder_Frame_WritePixels(IWICBitmapFrameEncode *iface,
1062 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
1063{
1064 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
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);
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
1166static 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)
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
1189static HRESULT WINAPI JpegEncoder_Frame_Commit(IWICBitmapFrameEncode *iface)
1190{
1191 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
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);
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
1220static 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
1227static 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
1244static 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
1267static ULONG WINAPI JpegEncoder_AddRef(IWICBitmapEncoder *iface)
1268{
1269 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1271
1272 TRACE("(%p) refcount=%u\n", iface, ref);
1273
1274 return ref;
1275}
1276
1277static ULONG WINAPI JpegEncoder_Release(IWICBitmapEncoder *iface)
1278{
1279 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
1281
1282 TRACE("(%p) refcount=%u\n", iface, ref);
1283
1284 if (ref == 0)
1285 {
1286 This->lock.DebugInfo->Spare[0] = 0;
1288 if (This->initialized) pjpeg_destroy_compress(&This->cinfo);
1289 if (This->stream) IStream_Release(This->stream);
1291 }
1292
1293 return ref;
1294}
1295
1296static HRESULT WINAPI JpegEncoder_Initialize(IWICBitmapEncoder *iface,
1297 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1298{
1299 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
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);
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
1348static 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
1359static 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
1377static 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
1384static 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
1394
1395 LeaveCriticalSection(&This->lock);
1396
1397 return hr;
1398}
1399
1400static HRESULT WINAPI JpegEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1401{
1402 TRACE("(%p,%p)\n", iface, pIThumbnail);
1404}
1405
1406static HRESULT WINAPI JpegEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1407{
1408 TRACE("(%p,%p)\n", iface, pIPreview);
1410}
1411
1412static 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);
1435 }
1436
1437 if (!This->initialized)
1438 {
1439 LeaveCriticalSection(&This->lock);
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
1463static 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);
1474 }
1475
1476 This->committed = TRUE;
1477
1478 LeaveCriticalSection(&This->lock);
1479
1480 return S_OK;
1481}
1482
1483static HRESULT WINAPI JpegEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1484 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1485{
1486 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1487 return E_NOTIMPL;
1488}
1489
1490static 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
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;
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
1551{
1552 ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
1553 return E_FAIL;
1554}
1555
1557{
1558 ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n");
1559 return E_FAIL;
1560}
1561
1562#endif
static jmp_buf jmpbuf
Definition: NtContinue.c:24
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
static void * heap_alloc(size_t len)
Definition: appwiz.h:66
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:33
const GUID IID_IUnknown
static BmpDecoder * impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
Definition: bmpdecode.c:88
static BmpDecoder * impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
Definition: bmpdecode.c:83
static BmpFrameEncode * impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
Definition: bmpencode.c:84
static BmpEncoder * impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
Definition: bmpencode.c:433
#define FIXME(fmt,...)
Definition: debug.h:114
#define WARN(fmt,...)
Definition: debug.h:115
#define ERR(fmt,...)
Definition: debug.h:113
#define setjmp
Definition: setjmp.h:209
_JBTYPE jmp_buf[_JBLEN]
Definition: setjmp.h:186
void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, const struct pixel_format_desc *format) DECLSPEC_HIDDEN
Definition: surface.c:1700
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
DWORD bpp
Definition: surface.c:185
#define GetProcessHeap()
Definition: compat.h:736
#define TRACE_(x)
Definition: compat.h:76
#define HeapAlloc
Definition: compat.h:733
#define TRACE_ON(x)
Definition: compat.h:75
#define HeapFree(x, y, z)
Definition: compat.h:735
#define WINE_DECLARE_DEBUG_CHANNEL(x)
Definition: compat.h:45
@ VT_R4
Definition: compat.h:2299
@ VT_ARRAY
Definition: compat.h:2341
@ VT_I4
Definition: compat.h:2298
@ VT_BOOL
Definition: compat.h:2306
@ VT_UI1
Definition: compat.h:2311
static GpStatus get_decoder_info(IStream *stream, const struct image_codec **result)
Definition: image.c:4285
static GifDecoder * impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
Definition: gifformat.c:607
HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
Definition: info.c:2075
HRESULT JpegEncoder_CreateInstance(REFIID iid, void **ppv)
Definition: jpegformat.c:1556
HRESULT JpegDecoder_CreateInstance(REFIID iid, void **ppv)
Definition: jpegformat.c:1550
HRESULT write_source(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, const WICRect *prc, const WICPixelFormatGUID *format, UINT bpp, INT width, INT height)
Definition: main.c:155
void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT height, INT stride)
Definition: main.c:212
HRESULT configure_write_source(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, const WICRect *prc, const WICPixelFormatGUID *format, INT width, INT height, double xres, double yres)
Definition: main.c:123
HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count, IPropertyBag2 **ppPropertyBag2)
Definition: propertybag.c:281
#define LOAD_FUNCPTR(f)
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLint GLint GLsizei width
Definition: gl.h:1546
GLsizei stride
Definition: glext.h:5848
GLuint index
Definition: glext.h:6031
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
jpeg_destroy_compress(j_compress_ptr cinfo)
Definition: jcapimin.c:96
jpeg_finish_compress(j_compress_ptr cinfo)
Definition: jcapimin.c:155
jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize)
Definition: jcapimin.c:31
jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines)
Definition: jcapistd.c:78
jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
Definition: jcapistd.c:39
jpeg_set_defaults(j_compress_ptr cinfo)
Definition: jcparam.c:196
jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize)
Definition: jdapimin.c:31
jpeg_destroy_decompress(j_decompress_ptr cinfo)
Definition: jdapimin.c:92
jpeg_read_header(j_decompress_ptr cinfo, boolean require_image)
Definition: jdapimin.c:245
jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)
Definition: jdapistd.c:153
jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired)
Definition: jdmarker.c:1338
jpeg_std_error(struct jpeg_error_mgr *err)
Definition: jerror.c:232
unsigned int JDIMENSION
Definition: jmorecfg.h:229
J_COLOR_SPACE
Definition: jpeglib.h:220
@ JCS_YCCK
Definition: jpeglib.h:226
@ JCS_YCbCr
Definition: jpeglib.h:224
@ JCS_CMYK
Definition: jpeglib.h:225
@ JCS_GRAYSCALE
Definition: jpeglib.h:222
@ JCS_RGB
Definition: jpeglib.h:223
#define JPEG_LIB_VERSION
Definition: jpeglib.h:40
JSAMPLE FAR * JSAMPROW
Definition: jpeglib.h:75
#define JPEG_HEADER_OK
Definition: jpeglib.h:1046
#define JMSG_LENGTH_MAX
Definition: jpeglib.h:711
#define b
Definition: ke_i.h:79
#define debugstr_guid
Definition: kernel32.h:35
void * wine_dlopen(const char *filename, int flag, char *error, size_t errorsize)
Definition: loader.c:53
HRESULT MetadataQueryReader_CreateInstance(IWICMetadataBlockReader *mbr, const WCHAR *root, IWICMetadataQueryReader **out)
const GUID * guid
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define WARN_ON(c)
Definition: module.h:257
static LPOLESTR
Definition: stg_prop.c:27
static HPALETTE palette
Definition: clipboard.c:1345
static const WCHAR wszImageQuality[]
Definition: converter.c:644
static const WCHAR wszChrominance[]
Definition: converter.c:647
static const WCHAR wszBitmapTransform[]
Definition: converter.c:645
static const WCHAR wszSuppressApp0[]
Definition: converter.c:649
static const WCHAR wszLuminance[]
Definition: converter.c:646
static const WCHAR wszJpegYCrCbSubsampling[]
Definition: converter.c:648
#define RTLD_NOW
Definition: port.h:100
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
_Out_ LPRECT prc
Definition: ntgdi.h:1658
long LONG
Definition: pedump.c:60
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define REFIID
Definition: guiddef.h:118
#define MAKE_FUNCPTR(f)
#define ERR_(ch,...)
Definition: debug.h:156
#define WARN_(ch,...)
Definition: debug.h:157
#define SONAME_LIBJPEG
Definition: config.h:1242
#define ERR_ON(ch)
Definition: debug.h:412
int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
Definition: compress.c:68
int seek(void *fd, ulong off, int mode)
Definition: pe.c:51
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
Definition: parser.c:49
Definition: tftpd.h:60
Definition: reader.h:84
Definition: send.c:48
Definition: parse.h:23
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
static BOOL initialized
Definition: syslog.c:39
rwlock_t lock
Definition: tcpcore.h:0
#define DWORD_PTR
Definition: treelist.c:76
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
int ret
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
WICBitmapEncoderCacheOption
Definition: wincodec.idl:69
WICDecodeOptions
Definition: wincodec.idl:27
@ WICDecodeMetadataCacheOnDemand
Definition: wincodec.idl:28
UINT32 WICColor
Definition: wincodec.idl:312
@ WICBitmapDecoderCapabilityCanDecodeSomeImages
Definition: wincodec.idl:50
@ WICBitmapDecoderCapabilityCanDecodeAllImages
Definition: wincodec.idl:49
static const char * debug_wic_rect(const WICRect *rect)
#define WINAPI
Definition: msvc.h:6
#define WINCODEC_ERR_WRONGSTATE
Definition: winerror.h:3281
#define WINCODEC_ERR_UNSUPPORTEDOPERATION
Definition: winerror.h:3308
#define WINCODEC_ERR_NOTINITIALIZED
Definition: winerror.h:3285
#define E_NOINTERFACE
Definition: winerror.h:2364
#define WINCODEC_ERR_PALETTEUNAVAILABLE
Definition: winerror.h:3292
#define WINCODEC_ERR_CODECNOTHUMBNAIL
Definition: winerror.h:3291
#define WINCODEC_ERR_FRAMEMISSING
Definition: winerror.h:3301
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193