msvcrt: Move btowc implementation to mbcs.c file.
[wine.git] / dlls / windowscodecs / libjpeg.c
blob84e4df5e007a04e9300182479fc420d9f4fcf7cd
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
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.
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.
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
19 #if 0
20 #pragma makedep unix
21 #endif
23 #include "config.h"
24 #include "wine/port.h"
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <setjmp.h>
34 #ifdef SONAME_LIBJPEG
35 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
36 #define XMD_H
37 #define UINT8 JPEG_UINT8
38 #define UINT16 JPEG_UINT16
39 #define boolean jpeg_boolean
40 #undef HAVE_STDLIB_H
41 # include <jpeglib.h>
42 #undef HAVE_STDLIB_H
43 #define HAVE_STDLIB_H 1
44 #undef UINT8
45 #undef UINT16
46 #undef boolean
47 #endif
49 #include "ntstatus.h"
50 #define WIN32_NO_STATUS
51 #include "windef.h"
52 #include "winternl.h"
53 #include "winbase.h"
54 #include "objbase.h"
56 #include "wincodecs_private.h"
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
62 #ifdef SONAME_LIBJPEG
63 WINE_DECLARE_DEBUG_CHANNEL(jpeg);
65 static CRITICAL_SECTION init_jpeg_cs;
66 static CRITICAL_SECTION_DEBUG init_jpeg_cs_debug =
68 0, 0, &init_jpeg_cs,
69 { &init_jpeg_cs_debug.ProcessLocksList,
70 &init_jpeg_cs_debug.ProcessLocksList },
71 0, 0, { (DWORD_PTR)(__FILE__ ": init_jpeg_cs") }
73 static CRITICAL_SECTION init_jpeg_cs = { &init_jpeg_cs_debug, -1, 0, 0, 0, 0 };
75 static void *libjpeg_handle;
77 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
78 MAKE_FUNCPTR(jpeg_CreateCompress);
79 MAKE_FUNCPTR(jpeg_CreateDecompress);
80 MAKE_FUNCPTR(jpeg_destroy_compress);
81 MAKE_FUNCPTR(jpeg_destroy_decompress);
82 MAKE_FUNCPTR(jpeg_finish_compress);
83 MAKE_FUNCPTR(jpeg_read_header);
84 MAKE_FUNCPTR(jpeg_read_scanlines);
85 MAKE_FUNCPTR(jpeg_resync_to_restart);
86 MAKE_FUNCPTR(jpeg_set_defaults);
87 MAKE_FUNCPTR(jpeg_start_compress);
88 MAKE_FUNCPTR(jpeg_start_decompress);
89 MAKE_FUNCPTR(jpeg_std_error);
90 MAKE_FUNCPTR(jpeg_write_scanlines);
91 #undef MAKE_FUNCPTR
93 static void *load_libjpeg(void)
95 void *result;
97 RtlEnterCriticalSection(&init_jpeg_cs);
99 if((libjpeg_handle = dlopen(SONAME_LIBJPEG, RTLD_NOW)) != NULL) {
101 #define LOAD_FUNCPTR(f) \
102 if((p##f = dlsym(libjpeg_handle, #f)) == NULL) { \
103 ERR("failed to load symbol %s\n", #f); \
104 libjpeg_handle = NULL; \
105 RtlLeaveCriticalSection(&init_jpeg_cs); \
106 return NULL; \
109 LOAD_FUNCPTR(jpeg_CreateCompress);
110 LOAD_FUNCPTR(jpeg_CreateDecompress);
111 LOAD_FUNCPTR(jpeg_destroy_compress);
112 LOAD_FUNCPTR(jpeg_destroy_decompress);
113 LOAD_FUNCPTR(jpeg_finish_compress);
114 LOAD_FUNCPTR(jpeg_read_header);
115 LOAD_FUNCPTR(jpeg_read_scanlines);
116 LOAD_FUNCPTR(jpeg_resync_to_restart);
117 LOAD_FUNCPTR(jpeg_set_defaults);
118 LOAD_FUNCPTR(jpeg_start_compress);
119 LOAD_FUNCPTR(jpeg_start_decompress);
120 LOAD_FUNCPTR(jpeg_std_error);
121 LOAD_FUNCPTR(jpeg_write_scanlines);
122 #undef LOAD_FUNCPTR
124 result = libjpeg_handle;
126 RtlLeaveCriticalSection(&init_jpeg_cs);
128 return result;
131 static void error_exit_fn(j_common_ptr cinfo)
133 char message[JMSG_LENGTH_MAX];
134 if (ERR_ON(jpeg))
136 cinfo->err->format_message(cinfo, message);
137 ERR_(jpeg)("%s\n", message);
139 longjmp(*(jmp_buf*)cinfo->client_data, 1);
142 static void emit_message_fn(j_common_ptr cinfo, int msg_level)
144 char message[JMSG_LENGTH_MAX];
146 if (msg_level < 0 && ERR_ON(jpeg))
148 cinfo->err->format_message(cinfo, message);
149 ERR_(jpeg)("%s\n", message);
151 else if (msg_level == 0 && WARN_ON(jpeg))
153 cinfo->err->format_message(cinfo, message);
154 WARN_(jpeg)("%s\n", message);
156 else if (msg_level > 0 && TRACE_ON(jpeg))
158 cinfo->err->format_message(cinfo, message);
159 TRACE_(jpeg)("%s\n", message);
163 struct jpeg_decoder {
164 struct decoder decoder;
165 struct decoder_frame frame;
166 BOOL cinfo_initialized;
167 IStream *stream;
168 struct jpeg_decompress_struct cinfo;
169 struct jpeg_error_mgr jerr;
170 struct jpeg_source_mgr source_mgr;
171 BYTE source_buffer[1024];
172 UINT stride;
173 BYTE *image_data;
176 static inline struct jpeg_decoder *impl_from_decoder(struct decoder* iface)
178 return CONTAINING_RECORD(iface, struct jpeg_decoder, decoder);
181 static inline struct jpeg_decoder *decoder_from_decompress(j_decompress_ptr decompress)
183 return CONTAINING_RECORD(decompress, struct jpeg_decoder, cinfo);
186 static void CDECL jpeg_decoder_destroy(struct decoder* iface)
188 struct jpeg_decoder *This = impl_from_decoder(iface);
190 if (This->cinfo_initialized) pjpeg_destroy_decompress(&This->cinfo);
191 free(This->image_data);
192 RtlFreeHeap(GetProcessHeap(), 0, This);
195 static void source_mgr_init_source(j_decompress_ptr cinfo)
199 static jpeg_boolean source_mgr_fill_input_buffer(j_decompress_ptr cinfo)
201 struct jpeg_decoder *This = decoder_from_decompress(cinfo);
202 HRESULT hr;
203 ULONG bytesread;
205 hr = stream_read(This->stream, This->source_buffer, 1024, &bytesread);
207 if (FAILED(hr) || bytesread == 0)
209 return FALSE;
211 else
213 This->source_mgr.next_input_byte = This->source_buffer;
214 This->source_mgr.bytes_in_buffer = bytesread;
215 return TRUE;
219 static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
221 struct jpeg_decoder *This = decoder_from_decompress(cinfo);
223 if (num_bytes > This->source_mgr.bytes_in_buffer)
225 stream_seek(This->stream, num_bytes - This->source_mgr.bytes_in_buffer, STREAM_SEEK_CUR, NULL);
226 This->source_mgr.bytes_in_buffer = 0;
228 else if (num_bytes > 0)
230 This->source_mgr.next_input_byte += num_bytes;
231 This->source_mgr.bytes_in_buffer -= num_bytes;
235 static void source_mgr_term_source(j_decompress_ptr cinfo)
239 static HRESULT CDECL jpeg_decoder_initialize(struct decoder* iface, IStream *stream, struct decoder_stat *st)
241 struct jpeg_decoder *This = impl_from_decoder(iface);
242 int ret;
243 jmp_buf jmpbuf;
244 UINT data_size, i;
246 if (This->cinfo_initialized)
247 return WINCODEC_ERR_WRONGSTATE;
249 pjpeg_std_error(&This->jerr);
251 This->jerr.error_exit = error_exit_fn;
252 This->jerr.emit_message = emit_message_fn;
254 This->cinfo.err = &This->jerr;
256 This->cinfo.client_data = jmpbuf;
258 if (setjmp(jmpbuf))
259 return E_FAIL;
261 pjpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
263 This->cinfo_initialized = TRUE;
265 This->stream = stream;
267 stream_seek(This->stream, 0, STREAM_SEEK_SET, NULL);
269 This->source_mgr.bytes_in_buffer = 0;
270 This->source_mgr.init_source = source_mgr_init_source;
271 This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer;
272 This->source_mgr.skip_input_data = source_mgr_skip_input_data;
273 This->source_mgr.resync_to_restart = pjpeg_resync_to_restart;
274 This->source_mgr.term_source = source_mgr_term_source;
276 This->cinfo.src = &This->source_mgr;
278 ret = pjpeg_read_header(&This->cinfo, TRUE);
280 if (ret != JPEG_HEADER_OK) {
281 WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret);
282 return E_FAIL;
285 switch (This->cinfo.jpeg_color_space)
287 case JCS_GRAYSCALE:
288 This->cinfo.out_color_space = JCS_GRAYSCALE;
289 This->frame.bpp = 8;
290 This->frame.pixel_format = GUID_WICPixelFormat8bppGray;
291 break;
292 case JCS_RGB:
293 case JCS_YCbCr:
294 This->cinfo.out_color_space = JCS_RGB;
295 This->frame.bpp = 24;
296 This->frame.pixel_format = GUID_WICPixelFormat24bppBGR;
297 break;
298 case JCS_CMYK:
299 case JCS_YCCK:
300 This->cinfo.out_color_space = JCS_CMYK;
301 This->frame.bpp = 32;
302 This->frame.pixel_format = GUID_WICPixelFormat32bppCMYK;
303 break;
304 default:
305 ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space);
306 return E_FAIL;
309 if (!pjpeg_start_decompress(&This->cinfo))
311 ERR("jpeg_start_decompress failed\n");
312 return E_FAIL;
315 This->frame.width = This->cinfo.output_width;
316 This->frame.height = This->cinfo.output_height;
318 switch (This->cinfo.density_unit)
320 case 2: /* pixels per centimeter */
321 This->frame.dpix = This->cinfo.X_density * 2.54;
322 This->frame.dpiy = This->cinfo.Y_density * 2.54;
323 break;
325 case 1: /* pixels per inch */
326 This->frame.dpix = This->cinfo.X_density;
327 This->frame.dpiy = This->cinfo.Y_density;
328 break;
330 case 0: /* unknown */
331 default:
332 This->frame.dpix = This->frame.dpiy = 96.0;
333 break;
336 This->frame.num_color_contexts = 0;
337 This->frame.num_colors = 0;
339 This->stride = (This->frame.bpp * This->cinfo.output_width + 7) / 8;
340 data_size = This->stride * This->cinfo.output_height;
342 This->image_data = malloc(data_size);
343 if (!This->image_data)
344 return E_OUTOFMEMORY;
346 while (This->cinfo.output_scanline < This->cinfo.output_height)
348 UINT first_scanline = This->cinfo.output_scanline;
349 UINT max_rows;
350 JSAMPROW out_rows[4];
351 JDIMENSION ret;
353 max_rows = min(This->cinfo.output_height-first_scanline, 4);
354 for (i=0; i<max_rows; i++)
355 out_rows[i] = This->image_data + This->stride * (first_scanline+i);
357 ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
358 if (ret == 0)
360 ERR("read_scanlines failed\n");
361 return E_FAIL;
365 if (This->frame.bpp == 24)
367 /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
368 reverse_bgr8(3, This->image_data,
369 This->cinfo.output_width, This->cinfo.output_height,
370 This->stride);
373 if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
375 /* Adobe JPEG's have inverted CMYK data. */
376 for (i=0; i<data_size; i++)
377 This->image_data[i] ^= 0xff;
380 st->frame_count = 1;
381 st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
382 WICBitmapDecoderCapabilityCanDecodeSomeImages |
383 WICBitmapDecoderCapabilityCanEnumerateMetadata |
384 DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT;
385 return S_OK;
388 static HRESULT CDECL jpeg_decoder_get_frame_info(struct decoder* iface, UINT frame, struct decoder_frame *info)
390 struct jpeg_decoder *This = impl_from_decoder(iface);
391 *info = This->frame;
392 return S_OK;
395 static HRESULT CDECL jpeg_decoder_copy_pixels(struct decoder* iface, UINT frame,
396 const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
398 struct jpeg_decoder *This = impl_from_decoder(iface);
399 return copy_pixels(This->frame.bpp, This->image_data,
400 This->frame.width, This->frame.height, This->stride,
401 prc, stride, buffersize, buffer);
404 static HRESULT CDECL jpeg_decoder_get_metadata_blocks(struct decoder* iface, UINT frame,
405 UINT *count, struct decoder_block **blocks)
407 FIXME("stub\n");
408 *count = 0;
409 *blocks = NULL;
410 return S_OK;
413 static HRESULT CDECL jpeg_decoder_get_color_context(struct decoder* This, UINT frame, UINT num,
414 BYTE **data, DWORD *datasize)
416 /* This should never be called because we report 0 color contexts and the unsupported flag. */
417 FIXME("stub\n");
418 return E_NOTIMPL;
421 static const struct decoder_funcs jpeg_decoder_vtable = {
422 jpeg_decoder_initialize,
423 jpeg_decoder_get_frame_info,
424 jpeg_decoder_copy_pixels,
425 jpeg_decoder_get_metadata_blocks,
426 jpeg_decoder_get_color_context,
427 jpeg_decoder_destroy
430 HRESULT CDECL jpeg_decoder_create(struct decoder_info *info, struct decoder **result)
432 struct jpeg_decoder *This;
434 if (!load_libjpeg())
436 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
437 return E_FAIL;
440 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(struct jpeg_decoder));
441 if (!This) return E_OUTOFMEMORY;
443 This->decoder.vtable = &jpeg_decoder_vtable;
444 This->cinfo_initialized = FALSE;
445 This->stream = NULL;
446 This->image_data = NULL;
447 *result = &This->decoder;
449 info->container_format = GUID_ContainerFormatJpeg;
450 info->block_format = GUID_ContainerFormatJpeg;
451 info->clsid = CLSID_WICJpegDecoder;
453 return S_OK;
456 typedef struct jpeg_compress_format {
457 const WICPixelFormatGUID *guid;
458 int bpp;
459 int num_components;
460 J_COLOR_SPACE color_space;
461 int swap_rgb;
462 } jpeg_compress_format;
464 static const jpeg_compress_format compress_formats[] = {
465 { &GUID_WICPixelFormat24bppBGR, 24, 3, JCS_RGB, 1 },
466 { &GUID_WICPixelFormat32bppCMYK, 32, 4, JCS_CMYK },
467 { &GUID_WICPixelFormat8bppGray, 8, 1, JCS_GRAYSCALE },
468 { 0 }
471 struct jpeg_encoder
473 struct encoder encoder;
474 IStream *stream;
475 BOOL cinfo_initialized;
476 struct jpeg_compress_struct cinfo;
477 struct jpeg_error_mgr jerr;
478 struct jpeg_destination_mgr dest_mgr;
479 struct encoder_frame encoder_frame;
480 const jpeg_compress_format *format;
481 BYTE dest_buffer[1024];
484 static inline struct jpeg_encoder *impl_from_encoder(struct encoder* iface)
486 return CONTAINING_RECORD(iface, struct jpeg_encoder, encoder);
489 static inline struct jpeg_encoder *encoder_from_compress(j_compress_ptr compress)
491 return CONTAINING_RECORD(compress, struct jpeg_encoder, cinfo);
494 static void dest_mgr_init_destination(j_compress_ptr cinfo)
496 struct jpeg_encoder *This = encoder_from_compress(cinfo);
498 This->dest_mgr.next_output_byte = This->dest_buffer;
499 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
502 static jpeg_boolean dest_mgr_empty_output_buffer(j_compress_ptr cinfo)
504 struct jpeg_encoder *This = encoder_from_compress(cinfo);
505 HRESULT hr;
506 ULONG byteswritten;
508 hr = stream_write(This->stream, This->dest_buffer,
509 sizeof(This->dest_buffer), &byteswritten);
511 if (hr != S_OK || byteswritten == 0)
513 ERR("Failed writing data, hr=%x\n", hr);
514 return FALSE;
517 This->dest_mgr.next_output_byte = This->dest_buffer;
518 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
519 return TRUE;
522 static void dest_mgr_term_destination(j_compress_ptr cinfo)
524 struct jpeg_encoder *This = encoder_from_compress(cinfo);
525 ULONG byteswritten;
526 HRESULT hr;
528 if (This->dest_mgr.free_in_buffer != sizeof(This->dest_buffer))
530 hr = stream_write(This->stream, This->dest_buffer,
531 sizeof(This->dest_buffer) - This->dest_mgr.free_in_buffer, &byteswritten);
533 if (hr != S_OK || byteswritten == 0)
534 ERR("Failed writing data, hr=%x\n", hr);
538 HRESULT CDECL jpeg_encoder_initialize(struct encoder* iface, IStream *stream)
540 struct jpeg_encoder *This = impl_from_encoder(iface);
541 jmp_buf jmpbuf;
543 pjpeg_std_error(&This->jerr);
545 This->jerr.error_exit = error_exit_fn;
546 This->jerr.emit_message = emit_message_fn;
548 This->cinfo.err = &This->jerr;
550 This->cinfo.client_data = jmpbuf;
552 if (setjmp(jmpbuf))
553 return E_FAIL;
555 pjpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct));
557 This->stream = stream;
559 This->dest_mgr.next_output_byte = This->dest_buffer;
560 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
562 This->dest_mgr.init_destination = dest_mgr_init_destination;
563 This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer;
564 This->dest_mgr.term_destination = dest_mgr_term_destination;
566 This->cinfo.dest = &This->dest_mgr;
568 This->cinfo_initialized = TRUE;
570 return S_OK;
573 HRESULT CDECL jpeg_encoder_get_supported_format(struct encoder* iface, GUID *pixel_format,
574 DWORD *bpp, BOOL *indexed)
576 int i;
578 for (i=0; compress_formats[i].guid; i++)
580 if (memcmp(compress_formats[i].guid, pixel_format, sizeof(GUID)) == 0)
581 break;
584 if (!compress_formats[i].guid) i = 0;
586 *pixel_format = *compress_formats[i].guid;
587 *bpp = compress_formats[i].bpp;
588 *indexed = FALSE;
590 return S_OK;
593 HRESULT CDECL jpeg_encoder_create_frame(struct encoder* iface, const struct encoder_frame *frame)
595 struct jpeg_encoder *This = impl_from_encoder(iface);
596 jmp_buf jmpbuf;
597 int i;
599 This->encoder_frame = *frame;
601 if (setjmp(jmpbuf))
602 return E_FAIL;
604 This->cinfo.client_data = jmpbuf;
606 for (i=0; compress_formats[i].guid; i++)
608 if (memcmp(compress_formats[i].guid, &frame->pixel_format, sizeof(GUID)) == 0)
609 break;
611 This->format = &compress_formats[i];
613 This->cinfo.image_width = frame->width;
614 This->cinfo.image_height = frame->height;
615 This->cinfo.input_components = This->format->num_components;
616 This->cinfo.in_color_space = This->format->color_space;
618 pjpeg_set_defaults(&This->cinfo);
620 if (frame->dpix != 0.0 && frame->dpiy != 0.0)
622 This->cinfo.density_unit = 1; /* dots per inch */
623 This->cinfo.X_density = frame->dpix;
624 This->cinfo.Y_density = frame->dpiy;
627 pjpeg_start_compress(&This->cinfo, TRUE);
629 return S_OK;
632 HRESULT CDECL jpeg_encoder_write_lines(struct encoder* iface, BYTE *data,
633 DWORD line_count, DWORD stride)
635 struct jpeg_encoder *This = impl_from_encoder(iface);
636 jmp_buf jmpbuf;
637 BYTE *swapped_data = NULL, *current_row;
638 UINT line;
639 int row_size;
641 if (setjmp(jmpbuf))
643 free(swapped_data);
644 return E_FAIL;
647 This->cinfo.client_data = jmpbuf;
649 row_size = This->format->bpp / 8 * This->encoder_frame.width;
651 if (This->format->swap_rgb)
653 swapped_data = malloc(row_size);
654 if (!swapped_data)
655 return E_OUTOFMEMORY;
658 for (line=0; line < line_count; line++)
660 if (This->format->swap_rgb)
662 UINT x;
664 memcpy(swapped_data, data + (stride * line), row_size);
666 for (x=0; x < This->encoder_frame.width; x++)
668 BYTE b;
670 b = swapped_data[x*3];
671 swapped_data[x*3] = swapped_data[x*3+2];
672 swapped_data[x*3+2] = b;
675 current_row = swapped_data;
677 else
678 current_row = data + (stride * line);
680 if (!pjpeg_write_scanlines(&This->cinfo, &current_row, 1))
682 ERR("failed writing scanlines\n");
683 free(swapped_data);
684 return E_FAIL;
688 free(swapped_data);
690 return S_OK;
693 HRESULT CDECL jpeg_encoder_commit_frame(struct encoder* iface)
695 struct jpeg_encoder *This = impl_from_encoder(iface);
696 jmp_buf jmpbuf;
698 if (setjmp(jmpbuf))
699 return E_FAIL;
701 This->cinfo.client_data = jmpbuf;
703 pjpeg_finish_compress(&This->cinfo);
705 return S_OK;
708 HRESULT CDECL jpeg_encoder_commit_file(struct encoder* iface)
710 return S_OK;
713 void CDECL jpeg_encoder_destroy(struct encoder* iface)
715 struct jpeg_encoder *This = impl_from_encoder(iface);
716 if (This->cinfo_initialized)
717 pjpeg_destroy_compress(&This->cinfo);
718 RtlFreeHeap(GetProcessHeap(), 0, This);
721 static const struct encoder_funcs jpeg_encoder_vtable = {
722 jpeg_encoder_initialize,
723 jpeg_encoder_get_supported_format,
724 jpeg_encoder_create_frame,
725 jpeg_encoder_write_lines,
726 jpeg_encoder_commit_frame,
727 jpeg_encoder_commit_file,
728 jpeg_encoder_destroy
731 HRESULT CDECL jpeg_encoder_create(struct encoder_info *info, struct encoder **result)
733 struct jpeg_encoder *This;
735 if (!load_libjpeg())
737 ERR("Failed writing JPEG because unable to find %s\n", SONAME_LIBJPEG);
738 return E_FAIL;
741 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(struct jpeg_encoder));
742 if (!This) return E_OUTOFMEMORY;
744 This->encoder.vtable = &jpeg_encoder_vtable;
745 This->stream = NULL;
746 This->cinfo_initialized = FALSE;
747 *result = &This->encoder;
749 info->flags = 0;
750 info->container_format = GUID_ContainerFormatJpeg;
751 info->clsid = CLSID_WICJpegEncoder;
752 info->encoder_options[0] = ENCODER_OPTION_IMAGE_QUALITY;
753 info->encoder_options[1] = ENCODER_OPTION_BITMAP_TRANSFORM;
754 info->encoder_options[2] = ENCODER_OPTION_LUMINANCE;
755 info->encoder_options[3] = ENCODER_OPTION_CHROMINANCE;
756 info->encoder_options[4] = ENCODER_OPTION_YCRCB_SUBSAMPLING;
757 info->encoder_options[5] = ENCODER_OPTION_SUPPRESS_APP0;
758 info->encoder_options[6] = ENCODER_OPTION_END;
760 return S_OK;
763 #else /* !defined(SONAME_LIBJPEG) */
765 HRESULT CDECL jpeg_decoder_create(struct decoder_info *info, struct decoder **result)
767 ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
768 return E_FAIL;
771 HRESULT CDECL jpeg_encoder_create(struct encoder_info *info, struct encoder **result)
773 ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n");
774 return E_FAIL;
777 #endif