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
24 #include "wine/port.h"
35 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
37 #define UINT8 JPEG_UINT8
38 #define UINT16 JPEG_UINT16
39 #define boolean jpeg_boolean
43 #define HAVE_STDLIB_H 1
50 #define WIN32_NO_STATUS
56 #include "wincodecs_private.h"
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
63 WINE_DECLARE_DEBUG_CHANNEL(jpeg
);
65 static CRITICAL_SECTION init_jpeg_cs
;
66 static CRITICAL_SECTION_DEBUG init_jpeg_cs_debug
=
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
);
93 static void *load_libjpeg(void)
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); \
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
);
124 result
= libjpeg_handle
;
126 RtlLeaveCriticalSection(&init_jpeg_cs
);
131 static void error_exit_fn(j_common_ptr cinfo
)
133 char message
[JMSG_LENGTH_MAX
];
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
;
168 struct jpeg_decompress_struct cinfo
;
169 struct jpeg_error_mgr jerr
;
170 struct jpeg_source_mgr source_mgr
;
171 BYTE source_buffer
[1024];
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
);
205 hr
= stream_read(This
->stream
, This
->source_buffer
, 1024, &bytesread
);
207 if (FAILED(hr
) || bytesread
== 0)
213 This
->source_mgr
.next_input_byte
= This
->source_buffer
;
214 This
->source_mgr
.bytes_in_buffer
= bytesread
;
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
);
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
;
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
);
285 switch (This
->cinfo
.jpeg_color_space
)
288 This
->cinfo
.out_color_space
= JCS_GRAYSCALE
;
290 This
->frame
.pixel_format
= GUID_WICPixelFormat8bppGray
;
294 This
->cinfo
.out_color_space
= JCS_RGB
;
295 This
->frame
.bpp
= 24;
296 This
->frame
.pixel_format
= GUID_WICPixelFormat24bppBGR
;
300 This
->cinfo
.out_color_space
= JCS_CMYK
;
301 This
->frame
.bpp
= 32;
302 This
->frame
.pixel_format
= GUID_WICPixelFormat32bppCMYK
;
305 ERR("Unknown JPEG color space %i\n", This
->cinfo
.jpeg_color_space
);
309 if (!pjpeg_start_decompress(&This
->cinfo
))
311 ERR("jpeg_start_decompress failed\n");
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;
325 case 1: /* pixels per inch */
326 This
->frame
.dpix
= This
->cinfo
.X_density
;
327 This
->frame
.dpiy
= This
->cinfo
.Y_density
;
330 case 0: /* unknown */
332 This
->frame
.dpix
= This
->frame
.dpiy
= 96.0;
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
;
350 JSAMPROW out_rows
[4];
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
);
360 ERR("read_scanlines failed\n");
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
,
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;
381 st
->flags
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
382 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
383 WICBitmapDecoderCapabilityCanEnumerateMetadata
|
384 DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT
;
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
);
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
)
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. */
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
,
430 HRESULT CDECL
jpeg_decoder_create(struct decoder_info
*info
, struct decoder
**result
)
432 struct jpeg_decoder
*This
;
436 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG
);
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
;
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
;
456 typedef struct jpeg_compress_format
{
457 const WICPixelFormatGUID
*guid
;
460 J_COLOR_SPACE color_space
;
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
},
473 struct encoder encoder
;
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
);
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
);
517 This
->dest_mgr
.next_output_byte
= This
->dest_buffer
;
518 This
->dest_mgr
.free_in_buffer
= sizeof(This
->dest_buffer
);
522 static void dest_mgr_term_destination(j_compress_ptr cinfo
)
524 struct jpeg_encoder
*This
= encoder_from_compress(cinfo
);
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
);
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
;
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
;
573 HRESULT CDECL
jpeg_encoder_get_supported_format(struct encoder
* iface
, GUID
*pixel_format
,
574 DWORD
*bpp
, BOOL
*indexed
)
578 for (i
=0; compress_formats
[i
].guid
; i
++)
580 if (memcmp(compress_formats
[i
].guid
, pixel_format
, sizeof(GUID
)) == 0)
584 if (!compress_formats
[i
].guid
) i
= 0;
586 *pixel_format
= *compress_formats
[i
].guid
;
587 *bpp
= compress_formats
[i
].bpp
;
593 HRESULT CDECL
jpeg_encoder_create_frame(struct encoder
* iface
, const struct encoder_frame
*frame
)
595 struct jpeg_encoder
*This
= impl_from_encoder(iface
);
599 This
->encoder_frame
= *frame
;
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)
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
);
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
);
637 BYTE
*swapped_data
= NULL
, *current_row
;
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
);
655 return E_OUTOFMEMORY
;
658 for (line
=0; line
< line_count
; line
++)
660 if (This
->format
->swap_rgb
)
664 memcpy(swapped_data
, data
+ (stride
* line
), row_size
);
666 for (x
=0; x
< This
->encoder_frame
.width
; x
++)
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
;
678 current_row
= data
+ (stride
* line
);
680 if (!pjpeg_write_scanlines(&This
->cinfo
, ¤t_row
, 1))
682 ERR("failed writing scanlines\n");
693 HRESULT CDECL
jpeg_encoder_commit_frame(struct encoder
* iface
)
695 struct jpeg_encoder
*This
= impl_from_encoder(iface
);
701 This
->cinfo
.client_data
= jmpbuf
;
703 pjpeg_finish_compress(&This
->cinfo
);
708 HRESULT CDECL
jpeg_encoder_commit_file(struct encoder
* iface
)
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
,
731 HRESULT CDECL
jpeg_encoder_create(struct encoder_info
*info
, struct encoder
**result
)
733 struct jpeg_encoder
*This
;
737 ERR("Failed writing JPEG because unable to find %s\n", SONAME_LIBJPEG
);
741 This
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(struct jpeg_encoder
));
742 if (!This
) return E_OUTOFMEMORY
;
744 This
->encoder
.vtable
= &jpeg_encoder_vtable
;
746 This
->cinfo_initialized
= FALSE
;
747 *result
= &This
->encoder
;
749 info
->flags
= ENCODER_FLAGS_SUPPORTS_METADATA
;
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
;
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");
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");