ReactOS  0.4.15-dev-1177-g6cb3b62
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 
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
82 MAKE_FUNCPTR(jpeg_start_decompress);
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 
107  LOAD_FUNCPTR(jpeg_start_decompress);
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;
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;
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);
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);
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);
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 
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);
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;
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);
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 
465 }
466 
467 static 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 
478 static HRESULT WINAPI JpegDecoder_GetPreview(IWICBitmapDecoder *iface,
479  IWICBitmapSource **ppIBitmapSource)
480 {
481  FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
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);
490 }
491 
492 static HRESULT WINAPI JpegDecoder_GetThumbnail(IWICBitmapDecoder *iface,
493  IWICBitmapSource **ppIThumbnail)
494 {
495  FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
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);
672 }
673 
674 static HRESULT WINAPI JpegDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
675  IWICBitmapSource **ppIThumbnail)
676 {
677  FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
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 
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 
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;
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;
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);
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);
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);
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,
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 
1054 static HRESULT WINAPI JpegEncoder_Frame_SetThumbnail(IWICBitmapFrameEncode *iface,
1055  IWICBitmapSource *pIThumbnail)
1056 {
1057  FIXME("(%p,%p): stub\n", iface, pIThumbnail);
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);
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);
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 
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);
1404 }
1405 
1406 static HRESULT WINAPI JpegEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1407 {
1408  TRACE("(%p,%p)\n", iface, pIPreview);
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);
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 
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 
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
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs)
HRESULT JpegEncoder_CreateInstance(REFIID iid, void **ppv)
Definition: jpegformat.c:1556
jpeg_read_header(j_decompress_ptr cinfo, boolean require_image)
Definition: jdapimin.c:245
GLint GLint GLsizei width
Definition: gl.h:1546
Definition: tftpd.h:59
#define REFIID
Definition: guiddef.h:118
#define E_NOINTERFACE
Definition: winerror.h:2364
Definition: compat.h:2046
jpeg_finish_compress(j_compress_ptr cinfo)
Definition: jcapimin.c:155
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
JSAMPLE FAR * JSAMPROW
Definition: jpeglib.h:75
rwlock_t lock
Definition: tcpcore.h:1163
#define DWORD_PTR
Definition: treelist.c:76
HRESULT hr
Definition: shlfolder.c:183
#define TRUE
Definition: types.h:120
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR_(ch,...)
Definition: debug.h:156
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: glext.h:5579
REFIID LPVOID * ppv
Definition: atlbase.h:39
jpeg_destroy_compress(j_compress_ptr cinfo)
Definition: jcapimin.c:96
static const WCHAR wszBitmapTransform[]
Definition: converter.c:645
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
#define WINCODEC_ERR_NOTINITIALIZED
Definition: winerror.h:3277
jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize)
Definition: jcapimin.c:31
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
WICBitmapEncoderCacheOption
Definition: wincodec.idl:69
static LPOLESTR
Definition: stg_prop.c:27
#define E_FAIL
Definition: ddrawi.h:102
Definition: send.c:48
static const WCHAR wszLuminance[]
Definition: converter.c:646
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
Definition: jcapistd.c:39
#define WARN_ON(c)
Definition: module.h:255
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
const GUID * guid
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
HRESULT write_source(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, const WICRect *prc, const WICPixelFormatGUID *format, UINT bpp, INT width, INT height)
Definition: main.c:155
long LONG
Definition: pedump.c:60
static BmpFrameEncode * impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
Definition: bmpencode.c:84
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:111
#define E_INVALIDARG
Definition: ddrawi.h:101
#define WINCODEC_ERR_PALETTEUNAVAILABLE
Definition: winerror.h:3284
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
smooth NULL
Definition: ftsmooth.c:416
void * wine_dlopen(const char *filename, int flag, char *error, size_t errorsize)
Definition: loader.c:53
static const WCHAR wszSuppressApp0[]
Definition: converter.c:649
Definition: parser.c:48
#define JMSG_LENGTH_MAX
Definition: jpeglib.h:711
HRESULT JpegDecoder_CreateInstance(REFIID iid, void **ppv)
Definition: jpegformat.c:1550
GLuint index
Definition: glext.h:6031
#define JPEG_LIB_VERSION
Definition: jpeglib.h:40
#define debugstr_guid
Definition: kernel32.h:35
int longjmp(jmp_buf buf, int retval)
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define b
Definition: ke_i.h:79
HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
Definition: info.c:2075
#define TRACE_(x)
Definition: compat.h:76
#define LOAD_FUNCPTR(f)
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
#define TRACE(s)
Definition: solgame.cpp:4
GLsizei stride
Definition: glext.h:5848
#define GetProcessHeap()
Definition: compat.h:484
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
__wchar_t WCHAR
Definition: xmlstorage.h:180
static BmpEncoder * impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
Definition: bmpencode.c:433
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
LONG HRESULT
Definition: typedefs.h:79
int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
Definition: compress.c:68
jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines)
Definition: jcapistd.c:78
const GUID IID_IUnknown
static BOOL initialized
Definition: syslog.c:39
#define WINAPI
Definition: msvc.h:6
static BmpDecoder * impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
Definition: bmpdecode.c:83
ed2 num_bytes
Definition: write.c:2832
unsigned long DWORD
Definition: ntddk_ex.h:95
#define RTLD_NOW
Definition: port.h:100
#define WINCODEC_ERR_CODECNOTHUMBNAIL
Definition: winerror.h:3283
#define ERR_ON(ch)
Definition: debug.h:411
int seek(void *fd, ulong off, int mode)
Definition: pe.c:51
#define SONAME_LIBJPEG
Definition: config.h:1242
int ret
char line[200]
Definition: main.c:97
#define WINCODEC_ERR_FRAMEMISSING
Definition: winerror.h:3293
Definition: compat.h:2047
#define InterlockedDecrement
Definition: armddk.h:52
Definition: parse.h:22
GLuint GLuint stream
Definition: glext.h:7522
static const char * debug_wic_rect(const WICRect *rect)
jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired)
Definition: jdmarker.c:1338
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define WINE_DECLARE_DEBUG_CHANNEL(x)
Definition: compat.h:45
static const WCHAR wszImageQuality[]
Definition: converter.c:644
#define WINCODEC_ERR_UNSUPPORTEDOPERATION
Definition: winerror.h:3300
jpeg_destroy_decompress(j_decompress_ptr cinfo)
Definition: jdapimin.c:92
unsigned char BYTE
Definition: xxhash.c:193
static HPALETTE palette
Definition: clipboard.c:1345
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
static const WCHAR wszChrominance[]
Definition: converter.c:647
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:1660
jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)
Definition: jdapistd.c:153
#define ERR(fmt,...)
Definition: debug.h:110
WICDecodeOptions
Definition: wincodec.idl:27
#define WINCODEC_ERR_WRONGSTATE
Definition: winerror.h:3273
#define S_OK
Definition: intsafe.h:51
static GpStatus get_decoder_info(IStream *stream, const struct image_codec **result)
Definition: image.c:4237
#define InterlockedIncrement
Definition: armddk.h:53
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
static BmpDecoder * impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
Definition: bmpdecode.c:88
HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count, IPropertyBag2 **ppPropertyBag2)
Definition: propertybag.c:281
#define ARRAY_SIZE(a)
Definition: main.h:24
#define E_NOTIMPL
Definition: ddrawi.h:99
static GifDecoder * impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
Definition: gifformat.c:607
#define MAKE_FUNCPTR(f)
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define setjmp
Definition: setjmp.h:183
Definition: reader.h:83
static const WCHAR wszJpegYCrCbSubsampling[]
Definition: converter.c:648
jpeg_set_defaults(j_compress_ptr cinfo)
Definition: jcparam.c:196
jpeg_std_error(struct jpeg_error_mgr *err)
Definition: jerror.c:232
unsigned int JDIMENSION
Definition: jmorecfg.h:229
unsigned int ULONG
Definition: retypes.h:1
void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT height, INT stride)
Definition: main.c:212
DWORD bpp
Definition: surface.c:182
long jmp_buf[100]
Definition: of.h:11
jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize)
Definition: jdapimin.c:31
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
HRESULT MetadataQueryReader_CreateInstance(IWICMetadataBlockReader *mbr, const WCHAR *root, IWICMetadataQueryReader **out)
_Out_ LPRECT prc
Definition: ntgdi.h:1658
J_COLOR_SPACE
Definition: jpeglib.h:220
static jmp_buf jmpbuf
Definition: NtContinue.c:20
#define TRACE_ON(x)
Definition: compat.h:75
UINT32 WICColor
Definition: wincodec.idl:250
#define WARN_(ch,...)
Definition: debug.h:157
#define HeapFree(x, y, z)
Definition: compat.h:483
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define JPEG_HEADER_OK
Definition: jpeglib.h:1046
#define SUCCEEDED(hr)
Definition: intsafe.h:49