xref: /reactos/dll/win32/windowscodecs/libjpeg.c (revision 197ed01e)
1*197ed01eSMikhail Tyukin /*
2*197ed01eSMikhail Tyukin  * Copyright 2009 Vincent Povirk for CodeWeavers
3*197ed01eSMikhail Tyukin  *
4*197ed01eSMikhail Tyukin  * This library is free software; you can redistribute it and/or
5*197ed01eSMikhail Tyukin  * modify it under the terms of the GNU Lesser General Public
6*197ed01eSMikhail Tyukin  * License as published by the Free Software Foundation; either
7*197ed01eSMikhail Tyukin  * version 2.1 of the License, or (at your option) any later version.
8*197ed01eSMikhail Tyukin  *
9*197ed01eSMikhail Tyukin  * This library is distributed in the hope that it will be useful,
10*197ed01eSMikhail Tyukin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*197ed01eSMikhail Tyukin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12*197ed01eSMikhail Tyukin  * Lesser General Public License for more details.
13*197ed01eSMikhail Tyukin  *
14*197ed01eSMikhail Tyukin  * You should have received a copy of the GNU Lesser General Public
15*197ed01eSMikhail Tyukin  * License along with this library; if not, write to the Free Software
16*197ed01eSMikhail Tyukin  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17*197ed01eSMikhail Tyukin  */
18*197ed01eSMikhail Tyukin 
19*197ed01eSMikhail Tyukin #include <stdarg.h>
20*197ed01eSMikhail Tyukin #include <stdio.h>
21*197ed01eSMikhail Tyukin #include <string.h>
22*197ed01eSMikhail Tyukin #include <setjmp.h>
23*197ed01eSMikhail Tyukin #include <basetsd.h>
24*197ed01eSMikhail Tyukin #include <jpeglib.h>
25*197ed01eSMikhail Tyukin 
26*197ed01eSMikhail Tyukin #include "ntstatus.h"
27*197ed01eSMikhail Tyukin #define WIN32_NO_STATUS
28*197ed01eSMikhail Tyukin #include "windef.h"
29*197ed01eSMikhail Tyukin #include "winternl.h"
30*197ed01eSMikhail Tyukin #include "winbase.h"
31*197ed01eSMikhail Tyukin #include "objbase.h"
32*197ed01eSMikhail Tyukin 
33*197ed01eSMikhail Tyukin #include "wincodecs_private.h"
34*197ed01eSMikhail Tyukin 
35*197ed01eSMikhail Tyukin #include "wine/debug.h"
36*197ed01eSMikhail Tyukin 
37*197ed01eSMikhail Tyukin WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38*197ed01eSMikhail Tyukin WINE_DECLARE_DEBUG_CHANNEL(jpeg);
39*197ed01eSMikhail Tyukin 
error_exit_fn(j_common_ptr cinfo)40*197ed01eSMikhail Tyukin static void error_exit_fn(j_common_ptr cinfo)
41*197ed01eSMikhail Tyukin {
42*197ed01eSMikhail Tyukin     char message[JMSG_LENGTH_MAX];
43*197ed01eSMikhail Tyukin     if (ERR_ON(jpeg))
44*197ed01eSMikhail Tyukin     {
45*197ed01eSMikhail Tyukin         cinfo->err->format_message(cinfo, message);
46*197ed01eSMikhail Tyukin         ERR_(jpeg)("%s\n", message);
47*197ed01eSMikhail Tyukin     }
48*197ed01eSMikhail Tyukin     longjmp(*(jmp_buf*)cinfo->client_data, 1);
49*197ed01eSMikhail Tyukin }
50*197ed01eSMikhail Tyukin 
emit_message_fn(j_common_ptr cinfo,int msg_level)51*197ed01eSMikhail Tyukin static void emit_message_fn(j_common_ptr cinfo, int msg_level)
52*197ed01eSMikhail Tyukin {
53*197ed01eSMikhail Tyukin     char message[JMSG_LENGTH_MAX];
54*197ed01eSMikhail Tyukin 
55*197ed01eSMikhail Tyukin     if (msg_level < 0 && ERR_ON(jpeg))
56*197ed01eSMikhail Tyukin     {
57*197ed01eSMikhail Tyukin         cinfo->err->format_message(cinfo, message);
58*197ed01eSMikhail Tyukin         ERR_(jpeg)("%s\n", message);
59*197ed01eSMikhail Tyukin     }
60*197ed01eSMikhail Tyukin     else if (msg_level == 0 && WARN_ON(jpeg))
61*197ed01eSMikhail Tyukin     {
62*197ed01eSMikhail Tyukin         cinfo->err->format_message(cinfo, message);
63*197ed01eSMikhail Tyukin         WARN_(jpeg)("%s\n", message);
64*197ed01eSMikhail Tyukin     }
65*197ed01eSMikhail Tyukin     else if (msg_level > 0 && TRACE_ON(jpeg))
66*197ed01eSMikhail Tyukin     {
67*197ed01eSMikhail Tyukin         cinfo->err->format_message(cinfo, message);
68*197ed01eSMikhail Tyukin         TRACE_(jpeg)("%s\n", message);
69*197ed01eSMikhail Tyukin     }
70*197ed01eSMikhail Tyukin }
71*197ed01eSMikhail Tyukin 
72*197ed01eSMikhail Tyukin struct jpeg_decoder {
73*197ed01eSMikhail Tyukin     struct decoder decoder;
74*197ed01eSMikhail Tyukin     struct decoder_frame frame;
75*197ed01eSMikhail Tyukin     BOOL cinfo_initialized;
76*197ed01eSMikhail Tyukin     IStream *stream;
77*197ed01eSMikhail Tyukin     struct jpeg_decompress_struct cinfo;
78*197ed01eSMikhail Tyukin     struct jpeg_error_mgr jerr;
79*197ed01eSMikhail Tyukin     struct jpeg_source_mgr source_mgr;
80*197ed01eSMikhail Tyukin     BYTE source_buffer[1024];
81*197ed01eSMikhail Tyukin     UINT stride;
82*197ed01eSMikhail Tyukin     BYTE *image_data;
83*197ed01eSMikhail Tyukin };
84*197ed01eSMikhail Tyukin 
impl_from_decoder(struct decoder * iface)85*197ed01eSMikhail Tyukin static inline struct jpeg_decoder *impl_from_decoder(struct decoder* iface)
86*197ed01eSMikhail Tyukin {
87*197ed01eSMikhail Tyukin     return CONTAINING_RECORD(iface, struct jpeg_decoder, decoder);
88*197ed01eSMikhail Tyukin }
89*197ed01eSMikhail Tyukin 
decoder_from_decompress(j_decompress_ptr decompress)90*197ed01eSMikhail Tyukin static inline struct jpeg_decoder *decoder_from_decompress(j_decompress_ptr decompress)
91*197ed01eSMikhail Tyukin {
92*197ed01eSMikhail Tyukin     return CONTAINING_RECORD(decompress, struct jpeg_decoder, cinfo);
93*197ed01eSMikhail Tyukin }
94*197ed01eSMikhail Tyukin 
jpeg_decoder_destroy(struct decoder * iface)95*197ed01eSMikhail Tyukin static void CDECL jpeg_decoder_destroy(struct decoder* iface)
96*197ed01eSMikhail Tyukin {
97*197ed01eSMikhail Tyukin     struct jpeg_decoder *This = impl_from_decoder(iface);
98*197ed01eSMikhail Tyukin 
99*197ed01eSMikhail Tyukin     if (This->cinfo_initialized) jpeg_destroy_decompress(&This->cinfo);
100*197ed01eSMikhail Tyukin     free(This->image_data);
101*197ed01eSMikhail Tyukin     free(This);
102*197ed01eSMikhail Tyukin }
103*197ed01eSMikhail Tyukin 
source_mgr_init_source(j_decompress_ptr cinfo)104*197ed01eSMikhail Tyukin static void source_mgr_init_source(j_decompress_ptr cinfo)
105*197ed01eSMikhail Tyukin {
106*197ed01eSMikhail Tyukin }
107*197ed01eSMikhail Tyukin 
source_mgr_fill_input_buffer(j_decompress_ptr cinfo)108*197ed01eSMikhail Tyukin static boolean source_mgr_fill_input_buffer(j_decompress_ptr cinfo)
109*197ed01eSMikhail Tyukin {
110*197ed01eSMikhail Tyukin     struct jpeg_decoder *This = decoder_from_decompress(cinfo);
111*197ed01eSMikhail Tyukin     HRESULT hr;
112*197ed01eSMikhail Tyukin     ULONG bytesread;
113*197ed01eSMikhail Tyukin 
114*197ed01eSMikhail Tyukin     hr = stream_read(This->stream, This->source_buffer, 1024, &bytesread);
115*197ed01eSMikhail Tyukin 
116*197ed01eSMikhail Tyukin     if (FAILED(hr) || bytesread == 0)
117*197ed01eSMikhail Tyukin     {
118*197ed01eSMikhail Tyukin         return FALSE;
119*197ed01eSMikhail Tyukin     }
120*197ed01eSMikhail Tyukin     else
121*197ed01eSMikhail Tyukin     {
122*197ed01eSMikhail Tyukin         This->source_mgr.next_input_byte = This->source_buffer;
123*197ed01eSMikhail Tyukin         This->source_mgr.bytes_in_buffer = bytesread;
124*197ed01eSMikhail Tyukin         return TRUE;
125*197ed01eSMikhail Tyukin     }
126*197ed01eSMikhail Tyukin }
127*197ed01eSMikhail Tyukin 
source_mgr_skip_input_data(j_decompress_ptr cinfo,long num_bytes)128*197ed01eSMikhail Tyukin static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
129*197ed01eSMikhail Tyukin {
130*197ed01eSMikhail Tyukin     struct jpeg_decoder *This = decoder_from_decompress(cinfo);
131*197ed01eSMikhail Tyukin 
132*197ed01eSMikhail Tyukin     if (num_bytes > This->source_mgr.bytes_in_buffer)
133*197ed01eSMikhail Tyukin     {
134*197ed01eSMikhail Tyukin         stream_seek(This->stream, num_bytes - This->source_mgr.bytes_in_buffer, STREAM_SEEK_CUR, NULL);
135*197ed01eSMikhail Tyukin         This->source_mgr.bytes_in_buffer = 0;
136*197ed01eSMikhail Tyukin     }
137*197ed01eSMikhail Tyukin     else if (num_bytes > 0)
138*197ed01eSMikhail Tyukin     {
139*197ed01eSMikhail Tyukin         This->source_mgr.next_input_byte += num_bytes;
140*197ed01eSMikhail Tyukin         This->source_mgr.bytes_in_buffer -= num_bytes;
141*197ed01eSMikhail Tyukin     }
142*197ed01eSMikhail Tyukin }
143*197ed01eSMikhail Tyukin 
source_mgr_term_source(j_decompress_ptr cinfo)144*197ed01eSMikhail Tyukin static void source_mgr_term_source(j_decompress_ptr cinfo)
145*197ed01eSMikhail Tyukin {
146*197ed01eSMikhail Tyukin }
147*197ed01eSMikhail Tyukin 
jpeg_decoder_initialize(struct decoder * iface,IStream * stream,struct decoder_stat * st)148*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_initialize(struct decoder* iface, IStream *stream, struct decoder_stat *st)
149*197ed01eSMikhail Tyukin {
150*197ed01eSMikhail Tyukin     struct jpeg_decoder *This = impl_from_decoder(iface);
151*197ed01eSMikhail Tyukin     int ret;
152*197ed01eSMikhail Tyukin     jmp_buf jmpbuf;
153*197ed01eSMikhail Tyukin     UINT data_size, i;
154*197ed01eSMikhail Tyukin 
155*197ed01eSMikhail Tyukin     if (This->cinfo_initialized)
156*197ed01eSMikhail Tyukin         return WINCODEC_ERR_WRONGSTATE;
157*197ed01eSMikhail Tyukin 
158*197ed01eSMikhail Tyukin     jpeg_std_error(&This->jerr);
159*197ed01eSMikhail Tyukin 
160*197ed01eSMikhail Tyukin     This->jerr.error_exit = error_exit_fn;
161*197ed01eSMikhail Tyukin     This->jerr.emit_message = emit_message_fn;
162*197ed01eSMikhail Tyukin 
163*197ed01eSMikhail Tyukin     This->cinfo.err = &This->jerr;
164*197ed01eSMikhail Tyukin 
165*197ed01eSMikhail Tyukin     This->cinfo.client_data = jmpbuf;
166*197ed01eSMikhail Tyukin 
167*197ed01eSMikhail Tyukin     if (setjmp(jmpbuf))
168*197ed01eSMikhail Tyukin         return E_FAIL;
169*197ed01eSMikhail Tyukin 
170*197ed01eSMikhail Tyukin     jpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
171*197ed01eSMikhail Tyukin 
172*197ed01eSMikhail Tyukin     This->cinfo_initialized = TRUE;
173*197ed01eSMikhail Tyukin 
174*197ed01eSMikhail Tyukin     This->stream = stream;
175*197ed01eSMikhail Tyukin 
176*197ed01eSMikhail Tyukin     stream_seek(This->stream, 0, STREAM_SEEK_SET, NULL);
177*197ed01eSMikhail Tyukin 
178*197ed01eSMikhail Tyukin     This->source_mgr.bytes_in_buffer = 0;
179*197ed01eSMikhail Tyukin     This->source_mgr.init_source = source_mgr_init_source;
180*197ed01eSMikhail Tyukin     This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer;
181*197ed01eSMikhail Tyukin     This->source_mgr.skip_input_data = source_mgr_skip_input_data;
182*197ed01eSMikhail Tyukin     This->source_mgr.resync_to_restart = jpeg_resync_to_restart;
183*197ed01eSMikhail Tyukin     This->source_mgr.term_source = source_mgr_term_source;
184*197ed01eSMikhail Tyukin 
185*197ed01eSMikhail Tyukin     This->cinfo.src = &This->source_mgr;
186*197ed01eSMikhail Tyukin 
187*197ed01eSMikhail Tyukin     ret = jpeg_read_header(&This->cinfo, TRUE);
188*197ed01eSMikhail Tyukin 
189*197ed01eSMikhail Tyukin     if (ret != JPEG_HEADER_OK) {
190*197ed01eSMikhail Tyukin         WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret);
191*197ed01eSMikhail Tyukin         return E_FAIL;
192*197ed01eSMikhail Tyukin     }
193*197ed01eSMikhail Tyukin 
194*197ed01eSMikhail Tyukin     switch (This->cinfo.jpeg_color_space)
195*197ed01eSMikhail Tyukin     {
196*197ed01eSMikhail Tyukin     case JCS_GRAYSCALE:
197*197ed01eSMikhail Tyukin         This->cinfo.out_color_space = JCS_GRAYSCALE;
198*197ed01eSMikhail Tyukin         This->frame.bpp = 8;
199*197ed01eSMikhail Tyukin         This->frame.pixel_format = GUID_WICPixelFormat8bppGray;
200*197ed01eSMikhail Tyukin         break;
201*197ed01eSMikhail Tyukin     case JCS_RGB:
202*197ed01eSMikhail Tyukin     case JCS_YCbCr:
203*197ed01eSMikhail Tyukin         This->cinfo.out_color_space = JCS_RGB;
204*197ed01eSMikhail Tyukin         This->frame.bpp = 24;
205*197ed01eSMikhail Tyukin         This->frame.pixel_format = GUID_WICPixelFormat24bppBGR;
206*197ed01eSMikhail Tyukin         break;
207*197ed01eSMikhail Tyukin     case JCS_CMYK:
208*197ed01eSMikhail Tyukin     case JCS_YCCK:
209*197ed01eSMikhail Tyukin         This->cinfo.out_color_space = JCS_CMYK;
210*197ed01eSMikhail Tyukin         This->frame.bpp = 32;
211*197ed01eSMikhail Tyukin         This->frame.pixel_format = GUID_WICPixelFormat32bppCMYK;
212*197ed01eSMikhail Tyukin         break;
213*197ed01eSMikhail Tyukin     default:
214*197ed01eSMikhail Tyukin         ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space);
215*197ed01eSMikhail Tyukin         return E_FAIL;
216*197ed01eSMikhail Tyukin     }
217*197ed01eSMikhail Tyukin 
218*197ed01eSMikhail Tyukin     if (!jpeg_start_decompress(&This->cinfo))
219*197ed01eSMikhail Tyukin     {
220*197ed01eSMikhail Tyukin         ERR("jpeg_start_decompress failed\n");
221*197ed01eSMikhail Tyukin         return E_FAIL;
222*197ed01eSMikhail Tyukin     }
223*197ed01eSMikhail Tyukin 
224*197ed01eSMikhail Tyukin     This->frame.width = This->cinfo.output_width;
225*197ed01eSMikhail Tyukin     This->frame.height = This->cinfo.output_height;
226*197ed01eSMikhail Tyukin 
227*197ed01eSMikhail Tyukin     switch (This->cinfo.density_unit)
228*197ed01eSMikhail Tyukin     {
229*197ed01eSMikhail Tyukin     case 2: /* pixels per centimeter */
230*197ed01eSMikhail Tyukin         This->frame.dpix = This->cinfo.X_density * 2.54;
231*197ed01eSMikhail Tyukin         This->frame.dpiy = This->cinfo.Y_density * 2.54;
232*197ed01eSMikhail Tyukin         break;
233*197ed01eSMikhail Tyukin 
234*197ed01eSMikhail Tyukin     case 1: /* pixels per inch */
235*197ed01eSMikhail Tyukin         This->frame.dpix = This->cinfo.X_density;
236*197ed01eSMikhail Tyukin         This->frame.dpiy = This->cinfo.Y_density;
237*197ed01eSMikhail Tyukin         break;
238*197ed01eSMikhail Tyukin 
239*197ed01eSMikhail Tyukin     case 0: /* unknown */
240*197ed01eSMikhail Tyukin     default:
241*197ed01eSMikhail Tyukin         This->frame.dpix = This->frame.dpiy = 96.0;
242*197ed01eSMikhail Tyukin         break;
243*197ed01eSMikhail Tyukin     }
244*197ed01eSMikhail Tyukin 
245*197ed01eSMikhail Tyukin     This->frame.num_color_contexts = 0;
246*197ed01eSMikhail Tyukin     This->frame.num_colors = 0;
247*197ed01eSMikhail Tyukin 
248*197ed01eSMikhail Tyukin     This->stride = (This->frame.bpp * This->cinfo.output_width + 7) / 8;
249*197ed01eSMikhail Tyukin     data_size = This->stride * This->cinfo.output_height;
250*197ed01eSMikhail Tyukin 
251*197ed01eSMikhail Tyukin     if (data_size / This->stride < This->cinfo.output_height)
252*197ed01eSMikhail Tyukin         /* overflow in multiplication */
253*197ed01eSMikhail Tyukin         return E_OUTOFMEMORY;
254*197ed01eSMikhail Tyukin 
255*197ed01eSMikhail Tyukin     This->image_data = malloc(data_size);
256*197ed01eSMikhail Tyukin     if (!This->image_data)
257*197ed01eSMikhail Tyukin         return E_OUTOFMEMORY;
258*197ed01eSMikhail Tyukin 
259*197ed01eSMikhail Tyukin     while (This->cinfo.output_scanline < This->cinfo.output_height)
260*197ed01eSMikhail Tyukin     {
261*197ed01eSMikhail Tyukin         UINT first_scanline = This->cinfo.output_scanline;
262*197ed01eSMikhail Tyukin         UINT max_rows;
263*197ed01eSMikhail Tyukin         JSAMPROW out_rows[4];
264*197ed01eSMikhail Tyukin         JDIMENSION ret;
265*197ed01eSMikhail Tyukin 
266*197ed01eSMikhail Tyukin         max_rows = min(This->cinfo.output_height-first_scanline, 4);
267*197ed01eSMikhail Tyukin         for (i=0; i<max_rows; i++)
268*197ed01eSMikhail Tyukin             out_rows[i] = This->image_data + This->stride * (first_scanline+i);
269*197ed01eSMikhail Tyukin 
270*197ed01eSMikhail Tyukin         ret = jpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
271*197ed01eSMikhail Tyukin         if (ret == 0)
272*197ed01eSMikhail Tyukin         {
273*197ed01eSMikhail Tyukin             ERR("read_scanlines failed\n");
274*197ed01eSMikhail Tyukin             return E_FAIL;
275*197ed01eSMikhail Tyukin         }
276*197ed01eSMikhail Tyukin     }
277*197ed01eSMikhail Tyukin 
278*197ed01eSMikhail Tyukin     if (This->frame.bpp == 24)
279*197ed01eSMikhail Tyukin     {
280*197ed01eSMikhail Tyukin         /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
281*197ed01eSMikhail Tyukin         reverse_bgr8(3, This->image_data,
282*197ed01eSMikhail Tyukin             This->cinfo.output_width, This->cinfo.output_height,
283*197ed01eSMikhail Tyukin             This->stride);
284*197ed01eSMikhail Tyukin     }
285*197ed01eSMikhail Tyukin 
286*197ed01eSMikhail Tyukin     if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
287*197ed01eSMikhail Tyukin     {
288*197ed01eSMikhail Tyukin         /* Adobe JPEG's have inverted CMYK data. */
289*197ed01eSMikhail Tyukin         for (i=0; i<data_size; i++)
290*197ed01eSMikhail Tyukin             This->image_data[i] ^= 0xff;
291*197ed01eSMikhail Tyukin     }
292*197ed01eSMikhail Tyukin 
293*197ed01eSMikhail Tyukin     st->frame_count = 1;
294*197ed01eSMikhail Tyukin     st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
295*197ed01eSMikhail Tyukin                 WICBitmapDecoderCapabilityCanDecodeSomeImages |
296*197ed01eSMikhail Tyukin                 WICBitmapDecoderCapabilityCanEnumerateMetadata |
297*197ed01eSMikhail Tyukin                 DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT;
298*197ed01eSMikhail Tyukin     return S_OK;
299*197ed01eSMikhail Tyukin }
300*197ed01eSMikhail Tyukin 
jpeg_decoder_get_frame_info(struct decoder * iface,UINT frame,struct decoder_frame * info)301*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_get_frame_info(struct decoder* iface, UINT frame, struct decoder_frame *info)
302*197ed01eSMikhail Tyukin {
303*197ed01eSMikhail Tyukin     struct jpeg_decoder *This = impl_from_decoder(iface);
304*197ed01eSMikhail Tyukin     *info = This->frame;
305*197ed01eSMikhail Tyukin     return S_OK;
306*197ed01eSMikhail Tyukin }
307*197ed01eSMikhail Tyukin 
jpeg_decoder_copy_pixels(struct decoder * iface,UINT frame,const WICRect * prc,UINT stride,UINT buffersize,BYTE * buffer)308*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_copy_pixels(struct decoder* iface, UINT frame,
309*197ed01eSMikhail Tyukin     const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
310*197ed01eSMikhail Tyukin {
311*197ed01eSMikhail Tyukin     struct jpeg_decoder *This = impl_from_decoder(iface);
312*197ed01eSMikhail Tyukin     return copy_pixels(This->frame.bpp, This->image_data,
313*197ed01eSMikhail Tyukin         This->frame.width, This->frame.height, This->stride,
314*197ed01eSMikhail Tyukin         prc, stride, buffersize, buffer);
315*197ed01eSMikhail Tyukin }
316*197ed01eSMikhail Tyukin 
jpeg_decoder_get_metadata_blocks(struct decoder * iface,UINT frame,UINT * count,struct decoder_block ** blocks)317*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_get_metadata_blocks(struct decoder* iface, UINT frame,
318*197ed01eSMikhail Tyukin     UINT *count, struct decoder_block **blocks)
319*197ed01eSMikhail Tyukin {
320*197ed01eSMikhail Tyukin     FIXME("stub\n");
321*197ed01eSMikhail Tyukin     *count = 0;
322*197ed01eSMikhail Tyukin     *blocks = NULL;
323*197ed01eSMikhail Tyukin     return S_OK;
324*197ed01eSMikhail Tyukin }
325*197ed01eSMikhail Tyukin 
jpeg_decoder_get_color_context(struct decoder * This,UINT frame,UINT num,BYTE ** data,DWORD * datasize)326*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_get_color_context(struct decoder* This, UINT frame, UINT num,
327*197ed01eSMikhail Tyukin     BYTE **data, DWORD *datasize)
328*197ed01eSMikhail Tyukin {
329*197ed01eSMikhail Tyukin     /* This should never be called because we report 0 color contexts and the unsupported flag. */
330*197ed01eSMikhail Tyukin     FIXME("stub\n");
331*197ed01eSMikhail Tyukin     return E_NOTIMPL;
332*197ed01eSMikhail Tyukin }
333*197ed01eSMikhail Tyukin 
334*197ed01eSMikhail Tyukin static const struct decoder_funcs jpeg_decoder_vtable = {
335*197ed01eSMikhail Tyukin     jpeg_decoder_initialize,
336*197ed01eSMikhail Tyukin     jpeg_decoder_get_frame_info,
337*197ed01eSMikhail Tyukin     jpeg_decoder_copy_pixels,
338*197ed01eSMikhail Tyukin     jpeg_decoder_get_metadata_blocks,
339*197ed01eSMikhail Tyukin     jpeg_decoder_get_color_context,
340*197ed01eSMikhail Tyukin     jpeg_decoder_destroy
341*197ed01eSMikhail Tyukin };
342*197ed01eSMikhail Tyukin 
jpeg_decoder_create(struct decoder_info * info,struct decoder ** result)343*197ed01eSMikhail Tyukin HRESULT CDECL jpeg_decoder_create(struct decoder_info *info, struct decoder **result)
344*197ed01eSMikhail Tyukin {
345*197ed01eSMikhail Tyukin     struct jpeg_decoder *This;
346*197ed01eSMikhail Tyukin 
347*197ed01eSMikhail Tyukin     This = malloc(sizeof(struct jpeg_decoder));
348*197ed01eSMikhail Tyukin     if (!This) return E_OUTOFMEMORY;
349*197ed01eSMikhail Tyukin 
350*197ed01eSMikhail Tyukin     This->decoder.vtable = &jpeg_decoder_vtable;
351*197ed01eSMikhail Tyukin     This->cinfo_initialized = FALSE;
352*197ed01eSMikhail Tyukin     This->stream = NULL;
353*197ed01eSMikhail Tyukin     This->image_data = NULL;
354*197ed01eSMikhail Tyukin     *result = &This->decoder;
355*197ed01eSMikhail Tyukin 
356*197ed01eSMikhail Tyukin     info->container_format = GUID_ContainerFormatJpeg;
357*197ed01eSMikhail Tyukin     info->block_format = GUID_ContainerFormatJpeg;
358*197ed01eSMikhail Tyukin     info->clsid = CLSID_WICJpegDecoder;
359*197ed01eSMikhail Tyukin 
360*197ed01eSMikhail Tyukin     return S_OK;
361*197ed01eSMikhail Tyukin }
362*197ed01eSMikhail Tyukin 
363*197ed01eSMikhail Tyukin typedef struct jpeg_compress_format {
364*197ed01eSMikhail Tyukin     const WICPixelFormatGUID *guid;
365*197ed01eSMikhail Tyukin     int bpp;
366*197ed01eSMikhail Tyukin     int num_components;
367*197ed01eSMikhail Tyukin     J_COLOR_SPACE color_space;
368*197ed01eSMikhail Tyukin     int swap_rgb;
369*197ed01eSMikhail Tyukin } jpeg_compress_format;
370*197ed01eSMikhail Tyukin 
371*197ed01eSMikhail Tyukin static const jpeg_compress_format compress_formats[] = {
372*197ed01eSMikhail Tyukin     { &GUID_WICPixelFormat24bppBGR, 24, 3, JCS_RGB, 1 },
373*197ed01eSMikhail Tyukin     { &GUID_WICPixelFormat32bppCMYK, 32, 4, JCS_CMYK },
374*197ed01eSMikhail Tyukin     { &GUID_WICPixelFormat8bppGray, 8, 1, JCS_GRAYSCALE },
375*197ed01eSMikhail Tyukin     { 0 }
376*197ed01eSMikhail Tyukin };
377*197ed01eSMikhail Tyukin 
378*197ed01eSMikhail Tyukin struct jpeg_encoder
379*197ed01eSMikhail Tyukin {
380*197ed01eSMikhail Tyukin     struct encoder encoder;
381*197ed01eSMikhail Tyukin     IStream *stream;
382*197ed01eSMikhail Tyukin     BOOL cinfo_initialized;
383*197ed01eSMikhail Tyukin     struct jpeg_compress_struct cinfo;
384*197ed01eSMikhail Tyukin     struct jpeg_error_mgr jerr;
385*197ed01eSMikhail Tyukin     struct jpeg_destination_mgr dest_mgr;
386*197ed01eSMikhail Tyukin     struct encoder_frame encoder_frame;
387*197ed01eSMikhail Tyukin     const jpeg_compress_format *format;
388*197ed01eSMikhail Tyukin     BYTE dest_buffer[1024];
389*197ed01eSMikhail Tyukin };
390*197ed01eSMikhail Tyukin 
impl_from_encoder(struct encoder * iface)391*197ed01eSMikhail Tyukin static inline struct jpeg_encoder *impl_from_encoder(struct encoder* iface)
392*197ed01eSMikhail Tyukin {
393*197ed01eSMikhail Tyukin     return CONTAINING_RECORD(iface, struct jpeg_encoder, encoder);
394*197ed01eSMikhail Tyukin }
395*197ed01eSMikhail Tyukin 
encoder_from_compress(j_compress_ptr compress)396*197ed01eSMikhail Tyukin static inline struct jpeg_encoder *encoder_from_compress(j_compress_ptr compress)
397*197ed01eSMikhail Tyukin {
398*197ed01eSMikhail Tyukin     return CONTAINING_RECORD(compress, struct jpeg_encoder, cinfo);
399*197ed01eSMikhail Tyukin }
400*197ed01eSMikhail Tyukin 
dest_mgr_init_destination(j_compress_ptr cinfo)401*197ed01eSMikhail Tyukin static void dest_mgr_init_destination(j_compress_ptr cinfo)
402*197ed01eSMikhail Tyukin {
403*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = encoder_from_compress(cinfo);
404*197ed01eSMikhail Tyukin 
405*197ed01eSMikhail Tyukin     This->dest_mgr.next_output_byte = This->dest_buffer;
406*197ed01eSMikhail Tyukin     This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
407*197ed01eSMikhail Tyukin }
408*197ed01eSMikhail Tyukin 
dest_mgr_empty_output_buffer(j_compress_ptr cinfo)409*197ed01eSMikhail Tyukin static boolean dest_mgr_empty_output_buffer(j_compress_ptr cinfo)
410*197ed01eSMikhail Tyukin {
411*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = encoder_from_compress(cinfo);
412*197ed01eSMikhail Tyukin     HRESULT hr;
413*197ed01eSMikhail Tyukin     ULONG byteswritten;
414*197ed01eSMikhail Tyukin 
415*197ed01eSMikhail Tyukin     hr = stream_write(This->stream, This->dest_buffer,
416*197ed01eSMikhail Tyukin         sizeof(This->dest_buffer), &byteswritten);
417*197ed01eSMikhail Tyukin 
418*197ed01eSMikhail Tyukin     if (hr != S_OK || byteswritten == 0)
419*197ed01eSMikhail Tyukin     {
420*197ed01eSMikhail Tyukin         ERR("Failed writing data, hr=%lx\n", hr);
421*197ed01eSMikhail Tyukin         return FALSE;
422*197ed01eSMikhail Tyukin     }
423*197ed01eSMikhail Tyukin 
424*197ed01eSMikhail Tyukin     This->dest_mgr.next_output_byte = This->dest_buffer;
425*197ed01eSMikhail Tyukin     This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
426*197ed01eSMikhail Tyukin     return TRUE;
427*197ed01eSMikhail Tyukin }
428*197ed01eSMikhail Tyukin 
dest_mgr_term_destination(j_compress_ptr cinfo)429*197ed01eSMikhail Tyukin static void dest_mgr_term_destination(j_compress_ptr cinfo)
430*197ed01eSMikhail Tyukin {
431*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = encoder_from_compress(cinfo);
432*197ed01eSMikhail Tyukin     ULONG byteswritten;
433*197ed01eSMikhail Tyukin     HRESULT hr;
434*197ed01eSMikhail Tyukin 
435*197ed01eSMikhail Tyukin     if (This->dest_mgr.free_in_buffer != sizeof(This->dest_buffer))
436*197ed01eSMikhail Tyukin     {
437*197ed01eSMikhail Tyukin         hr = stream_write(This->stream, This->dest_buffer,
438*197ed01eSMikhail Tyukin             sizeof(This->dest_buffer) - This->dest_mgr.free_in_buffer, &byteswritten);
439*197ed01eSMikhail Tyukin 
440*197ed01eSMikhail Tyukin         if (hr != S_OK || byteswritten == 0)
441*197ed01eSMikhail Tyukin             ERR("Failed writing data, hr=%lx\n", hr);
442*197ed01eSMikhail Tyukin     }
443*197ed01eSMikhail Tyukin }
444*197ed01eSMikhail Tyukin 
jpeg_encoder_initialize(struct encoder * iface,IStream * stream)445*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_initialize(struct encoder* iface, IStream *stream)
446*197ed01eSMikhail Tyukin {
447*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = impl_from_encoder(iface);
448*197ed01eSMikhail Tyukin     jmp_buf jmpbuf;
449*197ed01eSMikhail Tyukin 
450*197ed01eSMikhail Tyukin     jpeg_std_error(&This->jerr);
451*197ed01eSMikhail Tyukin 
452*197ed01eSMikhail Tyukin     This->jerr.error_exit = error_exit_fn;
453*197ed01eSMikhail Tyukin     This->jerr.emit_message = emit_message_fn;
454*197ed01eSMikhail Tyukin 
455*197ed01eSMikhail Tyukin     This->cinfo.err = &This->jerr;
456*197ed01eSMikhail Tyukin 
457*197ed01eSMikhail Tyukin     This->cinfo.client_data = jmpbuf;
458*197ed01eSMikhail Tyukin 
459*197ed01eSMikhail Tyukin     if (setjmp(jmpbuf))
460*197ed01eSMikhail Tyukin         return E_FAIL;
461*197ed01eSMikhail Tyukin 
462*197ed01eSMikhail Tyukin     jpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct));
463*197ed01eSMikhail Tyukin 
464*197ed01eSMikhail Tyukin     This->stream = stream;
465*197ed01eSMikhail Tyukin 
466*197ed01eSMikhail Tyukin     This->dest_mgr.next_output_byte = This->dest_buffer;
467*197ed01eSMikhail Tyukin     This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
468*197ed01eSMikhail Tyukin 
469*197ed01eSMikhail Tyukin     This->dest_mgr.init_destination = dest_mgr_init_destination;
470*197ed01eSMikhail Tyukin     This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer;
471*197ed01eSMikhail Tyukin     This->dest_mgr.term_destination = dest_mgr_term_destination;
472*197ed01eSMikhail Tyukin 
473*197ed01eSMikhail Tyukin     This->cinfo.dest = &This->dest_mgr;
474*197ed01eSMikhail Tyukin 
475*197ed01eSMikhail Tyukin     This->cinfo_initialized = TRUE;
476*197ed01eSMikhail Tyukin 
477*197ed01eSMikhail Tyukin     return S_OK;
478*197ed01eSMikhail Tyukin }
479*197ed01eSMikhail Tyukin 
jpeg_encoder_get_supported_format(struct encoder * iface,GUID * pixel_format,DWORD * bpp,BOOL * indexed)480*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_get_supported_format(struct encoder* iface, GUID *pixel_format,
481*197ed01eSMikhail Tyukin     DWORD *bpp, BOOL *indexed)
482*197ed01eSMikhail Tyukin {
483*197ed01eSMikhail Tyukin     int i;
484*197ed01eSMikhail Tyukin 
485*197ed01eSMikhail Tyukin     for (i=0; compress_formats[i].guid; i++)
486*197ed01eSMikhail Tyukin     {
487*197ed01eSMikhail Tyukin         if (memcmp(compress_formats[i].guid, pixel_format, sizeof(GUID)) == 0)
488*197ed01eSMikhail Tyukin             break;
489*197ed01eSMikhail Tyukin     }
490*197ed01eSMikhail Tyukin 
491*197ed01eSMikhail Tyukin     if (!compress_formats[i].guid) i = 0;
492*197ed01eSMikhail Tyukin 
493*197ed01eSMikhail Tyukin     *pixel_format = *compress_formats[i].guid;
494*197ed01eSMikhail Tyukin     *bpp = compress_formats[i].bpp;
495*197ed01eSMikhail Tyukin     *indexed = FALSE;
496*197ed01eSMikhail Tyukin 
497*197ed01eSMikhail Tyukin     return S_OK;
498*197ed01eSMikhail Tyukin }
499*197ed01eSMikhail Tyukin 
jpeg_encoder_create_frame(struct encoder * iface,const struct encoder_frame * frame)500*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_create_frame(struct encoder* iface, const struct encoder_frame *frame)
501*197ed01eSMikhail Tyukin {
502*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = impl_from_encoder(iface);
503*197ed01eSMikhail Tyukin     jmp_buf jmpbuf;
504*197ed01eSMikhail Tyukin     int i;
505*197ed01eSMikhail Tyukin 
506*197ed01eSMikhail Tyukin     This->encoder_frame = *frame;
507*197ed01eSMikhail Tyukin 
508*197ed01eSMikhail Tyukin     if (setjmp(jmpbuf))
509*197ed01eSMikhail Tyukin         return E_FAIL;
510*197ed01eSMikhail Tyukin 
511*197ed01eSMikhail Tyukin     This->cinfo.client_data = jmpbuf;
512*197ed01eSMikhail Tyukin 
513*197ed01eSMikhail Tyukin     for (i=0; compress_formats[i].guid; i++)
514*197ed01eSMikhail Tyukin     {
515*197ed01eSMikhail Tyukin         if (memcmp(compress_formats[i].guid, &frame->pixel_format, sizeof(GUID)) == 0)
516*197ed01eSMikhail Tyukin             break;
517*197ed01eSMikhail Tyukin     }
518*197ed01eSMikhail Tyukin     This->format = &compress_formats[i];
519*197ed01eSMikhail Tyukin 
520*197ed01eSMikhail Tyukin     This->cinfo.image_width = frame->width;
521*197ed01eSMikhail Tyukin     This->cinfo.image_height = frame->height;
522*197ed01eSMikhail Tyukin     This->cinfo.input_components = This->format->num_components;
523*197ed01eSMikhail Tyukin     This->cinfo.in_color_space = This->format->color_space;
524*197ed01eSMikhail Tyukin 
525*197ed01eSMikhail Tyukin     jpeg_set_defaults(&This->cinfo);
526*197ed01eSMikhail Tyukin 
527*197ed01eSMikhail Tyukin     if (frame->dpix != 0.0 && frame->dpiy != 0.0)
528*197ed01eSMikhail Tyukin     {
529*197ed01eSMikhail Tyukin         This->cinfo.density_unit = 1; /* dots per inch */
530*197ed01eSMikhail Tyukin         This->cinfo.X_density = frame->dpix;
531*197ed01eSMikhail Tyukin         This->cinfo.Y_density = frame->dpiy;
532*197ed01eSMikhail Tyukin     }
533*197ed01eSMikhail Tyukin 
534*197ed01eSMikhail Tyukin     jpeg_start_compress(&This->cinfo, TRUE);
535*197ed01eSMikhail Tyukin 
536*197ed01eSMikhail Tyukin     return S_OK;
537*197ed01eSMikhail Tyukin }
538*197ed01eSMikhail Tyukin 
jpeg_encoder_write_lines(struct encoder * iface,BYTE * data,DWORD line_count,DWORD stride)539*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_write_lines(struct encoder* iface, BYTE *data,
540*197ed01eSMikhail Tyukin     DWORD line_count, DWORD stride)
541*197ed01eSMikhail Tyukin {
542*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = impl_from_encoder(iface);
543*197ed01eSMikhail Tyukin     jmp_buf jmpbuf;
544*197ed01eSMikhail Tyukin     BYTE *swapped_data = NULL, *current_row;
545*197ed01eSMikhail Tyukin     UINT line;
546*197ed01eSMikhail Tyukin     int row_size;
547*197ed01eSMikhail Tyukin 
548*197ed01eSMikhail Tyukin     if (setjmp(jmpbuf))
549*197ed01eSMikhail Tyukin     {
550*197ed01eSMikhail Tyukin         free(swapped_data);
551*197ed01eSMikhail Tyukin         return E_FAIL;
552*197ed01eSMikhail Tyukin     }
553*197ed01eSMikhail Tyukin 
554*197ed01eSMikhail Tyukin     This->cinfo.client_data = jmpbuf;
555*197ed01eSMikhail Tyukin 
556*197ed01eSMikhail Tyukin     row_size = This->format->bpp / 8 * This->encoder_frame.width;
557*197ed01eSMikhail Tyukin 
558*197ed01eSMikhail Tyukin     if (This->format->swap_rgb)
559*197ed01eSMikhail Tyukin     {
560*197ed01eSMikhail Tyukin         swapped_data = malloc(row_size);
561*197ed01eSMikhail Tyukin         if (!swapped_data)
562*197ed01eSMikhail Tyukin             return E_OUTOFMEMORY;
563*197ed01eSMikhail Tyukin     }
564*197ed01eSMikhail Tyukin 
565*197ed01eSMikhail Tyukin     for (line=0; line < line_count; line++)
566*197ed01eSMikhail Tyukin     {
567*197ed01eSMikhail Tyukin         if (This->format->swap_rgb)
568*197ed01eSMikhail Tyukin         {
569*197ed01eSMikhail Tyukin             UINT x;
570*197ed01eSMikhail Tyukin 
571*197ed01eSMikhail Tyukin             memcpy(swapped_data, data + (stride * line), row_size);
572*197ed01eSMikhail Tyukin 
573*197ed01eSMikhail Tyukin             for (x=0; x < This->encoder_frame.width; x++)
574*197ed01eSMikhail Tyukin             {
575*197ed01eSMikhail Tyukin                 BYTE b;
576*197ed01eSMikhail Tyukin 
577*197ed01eSMikhail Tyukin                 b = swapped_data[x*3];
578*197ed01eSMikhail Tyukin                 swapped_data[x*3] = swapped_data[x*3+2];
579*197ed01eSMikhail Tyukin                 swapped_data[x*3+2] = b;
580*197ed01eSMikhail Tyukin             }
581*197ed01eSMikhail Tyukin 
582*197ed01eSMikhail Tyukin             current_row = swapped_data;
583*197ed01eSMikhail Tyukin         }
584*197ed01eSMikhail Tyukin         else
585*197ed01eSMikhail Tyukin             current_row = data + (stride * line);
586*197ed01eSMikhail Tyukin 
587*197ed01eSMikhail Tyukin         if (!jpeg_write_scanlines(&This->cinfo, &current_row, 1))
588*197ed01eSMikhail Tyukin         {
589*197ed01eSMikhail Tyukin             ERR("failed writing scanlines\n");
590*197ed01eSMikhail Tyukin             free(swapped_data);
591*197ed01eSMikhail Tyukin             return E_FAIL;
592*197ed01eSMikhail Tyukin         }
593*197ed01eSMikhail Tyukin     }
594*197ed01eSMikhail Tyukin 
595*197ed01eSMikhail Tyukin     free(swapped_data);
596*197ed01eSMikhail Tyukin 
597*197ed01eSMikhail Tyukin     return S_OK;
598*197ed01eSMikhail Tyukin }
599*197ed01eSMikhail Tyukin 
jpeg_encoder_commit_frame(struct encoder * iface)600*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_commit_frame(struct encoder* iface)
601*197ed01eSMikhail Tyukin {
602*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = impl_from_encoder(iface);
603*197ed01eSMikhail Tyukin     jmp_buf jmpbuf;
604*197ed01eSMikhail Tyukin 
605*197ed01eSMikhail Tyukin     if (setjmp(jmpbuf))
606*197ed01eSMikhail Tyukin         return E_FAIL;
607*197ed01eSMikhail Tyukin 
608*197ed01eSMikhail Tyukin     This->cinfo.client_data = jmpbuf;
609*197ed01eSMikhail Tyukin 
610*197ed01eSMikhail Tyukin     jpeg_finish_compress(&This->cinfo);
611*197ed01eSMikhail Tyukin 
612*197ed01eSMikhail Tyukin     return S_OK;
613*197ed01eSMikhail Tyukin }
614*197ed01eSMikhail Tyukin 
jpeg_encoder_commit_file(struct encoder * iface)615*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_commit_file(struct encoder* iface)
616*197ed01eSMikhail Tyukin {
617*197ed01eSMikhail Tyukin     return S_OK;
618*197ed01eSMikhail Tyukin }
619*197ed01eSMikhail Tyukin 
jpeg_encoder_destroy(struct encoder * iface)620*197ed01eSMikhail Tyukin static void CDECL jpeg_encoder_destroy(struct encoder* iface)
621*197ed01eSMikhail Tyukin {
622*197ed01eSMikhail Tyukin     struct jpeg_encoder *This = impl_from_encoder(iface);
623*197ed01eSMikhail Tyukin     if (This->cinfo_initialized)
624*197ed01eSMikhail Tyukin         jpeg_destroy_compress(&This->cinfo);
625*197ed01eSMikhail Tyukin     free(This);
626*197ed01eSMikhail Tyukin };
627*197ed01eSMikhail Tyukin 
628*197ed01eSMikhail Tyukin static const struct encoder_funcs jpeg_encoder_vtable = {
629*197ed01eSMikhail Tyukin     jpeg_encoder_initialize,
630*197ed01eSMikhail Tyukin     jpeg_encoder_get_supported_format,
631*197ed01eSMikhail Tyukin     jpeg_encoder_create_frame,
632*197ed01eSMikhail Tyukin     jpeg_encoder_write_lines,
633*197ed01eSMikhail Tyukin     jpeg_encoder_commit_frame,
634*197ed01eSMikhail Tyukin     jpeg_encoder_commit_file,
635*197ed01eSMikhail Tyukin     jpeg_encoder_destroy
636*197ed01eSMikhail Tyukin };
637*197ed01eSMikhail Tyukin 
jpeg_encoder_create(struct encoder_info * info,struct encoder ** result)638*197ed01eSMikhail Tyukin HRESULT CDECL jpeg_encoder_create(struct encoder_info *info, struct encoder **result)
639*197ed01eSMikhail Tyukin {
640*197ed01eSMikhail Tyukin     struct jpeg_encoder *This;
641*197ed01eSMikhail Tyukin 
642*197ed01eSMikhail Tyukin     This = malloc(sizeof(struct jpeg_encoder));
643*197ed01eSMikhail Tyukin     if (!This) return E_OUTOFMEMORY;
644*197ed01eSMikhail Tyukin 
645*197ed01eSMikhail Tyukin     This->encoder.vtable = &jpeg_encoder_vtable;
646*197ed01eSMikhail Tyukin     This->stream = NULL;
647*197ed01eSMikhail Tyukin     This->cinfo_initialized = FALSE;
648*197ed01eSMikhail Tyukin     *result = &This->encoder;
649*197ed01eSMikhail Tyukin 
650*197ed01eSMikhail Tyukin     info->flags = ENCODER_FLAGS_SUPPORTS_METADATA;
651*197ed01eSMikhail Tyukin     info->container_format = GUID_ContainerFormatJpeg;
652*197ed01eSMikhail Tyukin     info->clsid = CLSID_WICJpegEncoder;
653*197ed01eSMikhail Tyukin     info->encoder_options[0] = ENCODER_OPTION_IMAGE_QUALITY;
654*197ed01eSMikhail Tyukin     info->encoder_options[1] = ENCODER_OPTION_BITMAP_TRANSFORM;
655*197ed01eSMikhail Tyukin     info->encoder_options[2] = ENCODER_OPTION_LUMINANCE;
656*197ed01eSMikhail Tyukin     info->encoder_options[3] = ENCODER_OPTION_CHROMINANCE;
657*197ed01eSMikhail Tyukin     info->encoder_options[4] = ENCODER_OPTION_YCRCB_SUBSAMPLING;
658*197ed01eSMikhail Tyukin     info->encoder_options[5] = ENCODER_OPTION_SUPPRESS_APP0;
659*197ed01eSMikhail Tyukin     info->encoder_options[6] = ENCODER_OPTION_END;
660*197ed01eSMikhail Tyukin 
661*197ed01eSMikhail Tyukin     return S_OK;
662*197ed01eSMikhail Tyukin }
663