1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../../include/fxcodec/fx_codec.h"
8 #include "../../../include/fxge/fx_dib.h"
9 #include "codec_int.h"
10 extern "C" {
_JpegScanSOI(const FX_BYTE * & src_buf,FX_DWORD & src_size)11 static void _JpegScanSOI(const FX_BYTE*& src_buf, FX_DWORD& src_size)
12 {
13 if (src_size == 0) {
14 return;
15 }
16 FX_DWORD offset = 0;
17 while (offset < src_size - 1) {
18 if (src_buf[offset] == 0xff && src_buf[offset + 1] == 0xd8) {
19 src_buf += offset;
20 src_size -= offset;
21 return;
22 }
23 offset ++;
24 }
25 }
26 };
27 extern "C" {
28 #undef FAR
29 #include "../../fx_jpeglib.h"
30 }
31 extern "C" {
_src_do_nothing(struct jpeg_decompress_struct * cinfo)32 static void _src_do_nothing(struct jpeg_decompress_struct* cinfo) {}
33 };
34 extern "C" {
_error_fatal(j_common_ptr cinfo)35 static void _error_fatal(j_common_ptr cinfo)
36 {
37 longjmp(*(jmp_buf*)cinfo->client_data, -1);
38 }
39 };
40 extern "C" {
_src_skip_data(struct jpeg_decompress_struct * cinfo,long num)41 static void _src_skip_data(struct jpeg_decompress_struct* cinfo, long num)
42 {
43 if (num > (long)cinfo->src->bytes_in_buffer) {
44 _error_fatal((j_common_ptr)cinfo);
45 }
46 cinfo->src->next_input_byte += num;
47 cinfo->src->bytes_in_buffer -= num;
48 }
49 };
50 extern "C" {
_src_fill_buffer(j_decompress_ptr cinfo)51 static boolean _src_fill_buffer(j_decompress_ptr cinfo)
52 {
53 return 0;
54 }
55 };
56 extern "C" {
_src_resync(j_decompress_ptr cinfo,int desired)57 static boolean _src_resync(j_decompress_ptr cinfo, int desired)
58 {
59 return 0;
60 }
61 };
62 extern "C" {
_error_do_nothing(j_common_ptr cinfo)63 static void _error_do_nothing(j_common_ptr cinfo) {}
64 };
65 extern "C" {
_error_do_nothing1(j_common_ptr cinfo,int)66 static void _error_do_nothing1(j_common_ptr cinfo, int) {}
67 };
68 extern "C" {
_error_do_nothing2(j_common_ptr cinfo,char *)69 static void _error_do_nothing2(j_common_ptr cinfo, char*) {}
70 };
71 #define JPEG_MARKER_EXIF (JPEG_APP0 + 1)
72 #define JPEG_MARKER_ICC (JPEG_APP0 + 2)
73 #define JPEG_MARKER_AUTHORTIME (JPEG_APP0 + 3)
74 #define JPEG_MARKER_MAXSIZE 0xFFFF
75 #define JPEG_OVERHEAD_LEN 14
_JpegIsIccMarker(jpeg_saved_marker_ptr marker)76 static FX_BOOL _JpegIsIccMarker(jpeg_saved_marker_ptr marker)
77 {
78 if (marker->marker == JPEG_MARKER_ICC &&
79 marker->data_length >= JPEG_OVERHEAD_LEN &&
80 (FXSYS_memcmp32(marker->data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", 12) == 0)) {
81 return TRUE;
82 }
83 return FALSE;
84 }
_JpegLoadIccProfile(j_decompress_ptr cinfo,FX_LPBYTE * icc_buf_ptr,FX_DWORD * icc_length)85 static FX_BOOL _JpegLoadIccProfile(j_decompress_ptr cinfo, FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
86 {
87 if(icc_buf_ptr == NULL || icc_length == NULL) {
88 return FALSE;
89 }
90 *icc_buf_ptr = NULL;
91 *icc_length = 0;
92 FX_LPBYTE icc_data_ptr = NULL;
93 FX_DWORD icc_data_len = 0;
94 FX_BYTE count_icc_marker = 0;
95 FX_BYTE num_icc_marker = 0;
96 jpeg_saved_marker_ptr marker_list[256] = {NULL};
97 for (jpeg_saved_marker_ptr cur_marker = cinfo->marker_list;
98 cur_marker != NULL;
99 cur_marker = cur_marker->next) {
100 if(_JpegIsIccMarker(cur_marker)) {
101 if(count_icc_marker == 0) {
102 num_icc_marker = cur_marker->data[13];
103 } else if(num_icc_marker != cur_marker->data[13]) {
104 return FALSE;
105 }
106 int sn = cur_marker->data[12] - 1;
107 if(sn < 0 || sn >= num_icc_marker) {
108 return FALSE;
109 }
110 if(marker_list[sn] == NULL) {
111 marker_list[sn] = cur_marker;
112 } else {
113 return FALSE;
114 }
115 count_icc_marker ++;
116 icc_data_len += (cur_marker->data_length - JPEG_OVERHEAD_LEN);
117 }
118 }
119 if(count_icc_marker != num_icc_marker) {
120 return FALSE;
121 }
122 if(num_icc_marker == 0) {
123 return TRUE;
124 }
125 icc_data_ptr = FX_Alloc(FX_BYTE, icc_data_len);
126 if(icc_buf_ptr == NULL) {
127 return FALSE;
128 }
129 *icc_buf_ptr = icc_data_ptr;
130 *icc_length = icc_data_len;
131 for (int idx = 0; idx < num_icc_marker; idx++) {
132 icc_data_len = marker_list[idx]->data_length - JPEG_OVERHEAD_LEN;
133 FXSYS_memcpy32(icc_data_ptr, marker_list[idx]->data + JPEG_OVERHEAD_LEN, icc_data_len);
134 icc_data_ptr += icc_data_len;
135 }
136 return TRUE;
137 }
_JpegEmbedIccProfile(j_compress_ptr cinfo,FX_LPCBYTE icc_buf_ptr,FX_DWORD icc_length)138 static FX_BOOL _JpegEmbedIccProfile(j_compress_ptr cinfo, FX_LPCBYTE icc_buf_ptr, FX_DWORD icc_length)
139 {
140 if(icc_buf_ptr == NULL || icc_length == 0) {
141 return FALSE;
142 }
143 FX_DWORD icc_segment_size = (JPEG_MARKER_MAXSIZE - 2 - JPEG_OVERHEAD_LEN);
144 FX_DWORD icc_segment_num = (icc_length / icc_segment_size) + 1;
145 if (icc_segment_num > 255) {
146 return FALSE;
147 }
148 FX_DWORD icc_data_length = JPEG_OVERHEAD_LEN + (icc_segment_num > 1 ? icc_segment_size : icc_length);
149 FX_LPBYTE icc_data = FX_Alloc(FX_BYTE, icc_data_length);
150 if (icc_data == NULL) {
151 return FALSE;
152 }
153 FXSYS_memcpy32(icc_data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", 12);
154 icc_data[13] = (FX_BYTE)icc_segment_num;
155 for (FX_BYTE i = 0; i < (icc_segment_num - 1); i++) {
156 icc_data[12] = i + 1;
157 FXSYS_memcpy32(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + i * icc_segment_size, icc_segment_size);
158 jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, icc_data_length);
159 }
160 icc_data[12] = (FX_BYTE)icc_segment_num;
161 FX_DWORD icc_size = (icc_segment_num - 1) * icc_segment_size;
162 FXSYS_memcpy32(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + icc_size, icc_length - icc_size);
163 jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, JPEG_OVERHEAD_LEN + icc_length - icc_size);
164 FX_Free(icc_data);
165 return TRUE;
166 }
167 extern "C" {
_dest_do_nothing(j_compress_ptr cinfo)168 static void _dest_do_nothing(j_compress_ptr cinfo) {}
169 };
170 extern "C" {
_dest_empty(j_compress_ptr cinfo)171 static boolean _dest_empty(j_compress_ptr cinfo)
172 {
173 return FALSE;
174 }
175 };
176 #define JPEG_BLOCK_SIZE 1048576
_JpegEncode(const CFX_DIBSource * pSource,FX_LPBYTE & dest_buf,FX_STRSIZE & dest_size,int quality,FX_LPCBYTE icc_buf,FX_DWORD icc_length)177 static void _JpegEncode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length)
178 {
179 struct jpeg_compress_struct cinfo;
180 struct jpeg_error_mgr jerr;
181 jerr.error_exit = _error_do_nothing;
182 jerr.emit_message = _error_do_nothing1;
183 jerr.output_message = _error_do_nothing;
184 jerr.format_message = _error_do_nothing2;
185 jerr.reset_error_mgr = _error_do_nothing;
186 cinfo.err = &jerr;
187 jpeg_create_compress(&cinfo);
188 int Bpp = pSource->GetBPP() / 8;
189 int nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1;
190 int pitch = pSource->GetPitch();
191 int width = pSource->GetWidth();
192 int height = pSource->GetHeight();
193 FX_DWORD dest_buf_length = width * height * nComponents + 1024 + (icc_length ? (icc_length + 255 * 18) : 0);
194 dest_buf = FX_Alloc(FX_BYTE, dest_buf_length);
195 while (dest_buf == NULL) {
196 dest_buf_length >>= 1;
197 dest_buf = FX_Alloc(FX_BYTE, dest_buf_length);
198 }
199 FXSYS_memset32(dest_buf, 0, dest_buf_length);
200 struct jpeg_destination_mgr dest;
201 dest.init_destination = _dest_do_nothing;
202 dest.term_destination = _dest_do_nothing;
203 dest.empty_output_buffer = _dest_empty;
204 dest.next_output_byte = dest_buf;
205 dest.free_in_buffer = dest_buf_length;
206 cinfo.dest = &dest;
207 cinfo.image_width = width;
208 cinfo.image_height = height;
209 cinfo.input_components = nComponents;
210 if (nComponents == 1) {
211 cinfo.in_color_space = JCS_GRAYSCALE;
212 } else if (nComponents == 3) {
213 cinfo.in_color_space = JCS_RGB;
214 } else {
215 cinfo.in_color_space = JCS_CMYK;
216 }
217 FX_LPBYTE line_buf = NULL;
218 if (nComponents > 1) {
219 line_buf = FX_Alloc(FX_BYTE, width * nComponents);
220 if (line_buf == NULL) {
221 return;
222 }
223 }
224 jpeg_set_defaults(&cinfo);
225 if(quality != 75) {
226 jpeg_set_quality(&cinfo, quality, TRUE);
227 }
228 jpeg_start_compress(&cinfo, TRUE);
229 _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length);
230 JSAMPROW row_pointer[1];
231 JDIMENSION row;
232 while (cinfo.next_scanline < cinfo.image_height) {
233 FX_LPCBYTE src_scan = pSource->GetScanline(cinfo.next_scanline);
234 if (nComponents > 1) {
235 FX_LPBYTE dest_scan = line_buf;
236 if (nComponents == 3) {
237 for (int i = 0; i < width; i ++) {
238 dest_scan[0] = src_scan[2];
239 dest_scan[1] = src_scan[1];
240 dest_scan[2] = src_scan[0];
241 dest_scan += 3;
242 src_scan += Bpp;
243 }
244 } else {
245 for (int i = 0; i < pitch; i ++) {
246 *dest_scan++ = ~*src_scan++;
247 }
248 }
249 row_pointer[0] = line_buf;
250 } else {
251 row_pointer[0] = (FX_LPBYTE)src_scan;
252 }
253 row = cinfo.next_scanline;
254 jpeg_write_scanlines(&cinfo, row_pointer, 1);
255 if (cinfo.next_scanline == row) {
256 dest_buf = FX_Realloc(FX_BYTE, dest_buf, dest_buf_length + JPEG_BLOCK_SIZE);
257 if (dest_buf == NULL) {
258 FX_Free(line_buf);
259 return;
260 }
261 dest.next_output_byte = dest_buf + dest_buf_length - dest.free_in_buffer;
262 dest_buf_length += JPEG_BLOCK_SIZE;
263 dest.free_in_buffer += JPEG_BLOCK_SIZE;
264 }
265 }
266 jpeg_finish_compress(&cinfo);
267 jpeg_destroy_compress(&cinfo);
268 if (line_buf) {
269 FX_Free(line_buf);
270 }
271 dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer;
272 }
_JpegLoadInfo(FX_LPCBYTE src_buf,FX_DWORD src_size,int & width,int & height,int & num_components,int & bits_per_components,FX_BOOL & color_transform,FX_LPBYTE * icc_buf_ptr,FX_DWORD * icc_length)273 static FX_BOOL _JpegLoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height,
274 int& num_components, int& bits_per_components, FX_BOOL& color_transform,
275 FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
276 {
277 _JpegScanSOI(src_buf, src_size);
278 struct jpeg_decompress_struct cinfo;
279 struct jpeg_error_mgr jerr;
280 jerr.error_exit = _error_fatal;
281 jerr.emit_message = _error_do_nothing1;
282 jerr.output_message = _error_do_nothing;
283 jerr.format_message = _error_do_nothing2;
284 jerr.reset_error_mgr = _error_do_nothing;
285 cinfo.err = &jerr;
286 jmp_buf mark;
287 cinfo.client_data = &mark;
288 if (setjmp(mark) == -1) {
289 return FALSE;
290 }
291 jpeg_create_decompress(&cinfo);
292 struct jpeg_source_mgr src;
293 src.init_source = _src_do_nothing;
294 src.term_source = _src_do_nothing;
295 src.skip_input_data = _src_skip_data;
296 src.fill_input_buffer = _src_fill_buffer;
297 src.resync_to_restart = _src_resync;
298 src.bytes_in_buffer = src_size;
299 src.next_input_byte = src_buf;
300 cinfo.src = &src;
301 if (setjmp(mark) == -1) {
302 jpeg_destroy_decompress(&cinfo);
303 return FALSE;
304 }
305 if(icc_buf_ptr && icc_length) {
306 jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE);
307 }
308 int ret = jpeg_read_header(&cinfo, TRUE);
309 if (ret != JPEG_HEADER_OK) {
310 jpeg_destroy_decompress(&cinfo);
311 return FALSE;
312 }
313 width = cinfo.image_width;
314 height = cinfo.image_height;
315 num_components = cinfo.num_components;
316 color_transform = cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK;
317 bits_per_components = cinfo.data_precision;
318 if(icc_buf_ptr != NULL) {
319 *icc_buf_ptr = NULL;
320 }
321 if(icc_length != NULL) {
322 *icc_length = 0;
323 }
324 jpeg_destroy_decompress(&cinfo);
325 return TRUE;
326 }
327 class CCodec_JpegDecoder : public CCodec_ScanlineDecoder
328 {
329 public:
330 CCodec_JpegDecoder();
331 ~CCodec_JpegDecoder();
332 FX_BOOL Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps,
333 FX_BOOL ColorTransform, IFX_JpegProvider* pJP);
Destroy()334 virtual void Destroy()
335 {
336 delete this;
337 }
338 virtual void v_DownScale(int dest_width, int dest_height);
339 virtual FX_BOOL v_Rewind();
340 virtual FX_LPBYTE v_GetNextLine();
341 virtual FX_DWORD GetSrcOffset();
342 jmp_buf m_JmpBuf;
343 struct jpeg_decompress_struct cinfo;
344 struct jpeg_error_mgr jerr;
345 struct jpeg_source_mgr src;
346 FX_LPCBYTE m_SrcBuf;
347 FX_DWORD m_SrcSize;
348 FX_LPBYTE m_pScanlineBuf;
349 FX_BOOL InitDecode();
350 FX_BOOL m_bInited, m_bStarted, m_bJpegTransform;
351 protected:
352 IFX_JpegProvider* m_pExtProvider;
353 void* m_pExtContext;
354 FX_DWORD m_nDefaultScaleDenom;
355 };
CCodec_JpegDecoder()356 CCodec_JpegDecoder::CCodec_JpegDecoder()
357 {
358 m_pScanlineBuf = NULL;
359 m_DownScale = 1;
360 m_bStarted = FALSE;
361 m_bInited = FALSE;
362 m_pExtProvider = NULL;
363 m_pExtContext = NULL;
364 FXSYS_memset32(&cinfo, 0, sizeof(cinfo));
365 FXSYS_memset32(&jerr, 0, sizeof(jerr));
366 FXSYS_memset32(&src, 0, sizeof(src));
367 m_nDefaultScaleDenom = 1;
368 }
~CCodec_JpegDecoder()369 CCodec_JpegDecoder::~CCodec_JpegDecoder()
370 {
371 if (m_pExtProvider) {
372 m_pExtProvider->DestroyDecoder(m_pExtContext);
373 return;
374 }
375 if (m_pScanlineBuf) {
376 FX_Free(m_pScanlineBuf);
377 }
378 if (m_bInited) {
379 jpeg_destroy_decompress(&cinfo);
380 }
381 }
InitDecode()382 FX_BOOL CCodec_JpegDecoder::InitDecode()
383 {
384 cinfo.err = &jerr;
385 cinfo.client_data = &m_JmpBuf;
386 if (setjmp(m_JmpBuf) == -1) {
387 return FALSE;
388 }
389 jpeg_create_decompress(&cinfo);
390 m_bInited = TRUE;
391 cinfo.src = &src;
392 src.bytes_in_buffer = m_SrcSize;
393 src.next_input_byte = m_SrcBuf;
394 if (setjmp(m_JmpBuf) == -1) {
395 jpeg_destroy_decompress(&cinfo);
396 m_bInited = FALSE;
397 return FALSE;
398 }
399 cinfo.image_width = m_OrigWidth;
400 cinfo.image_height = m_OrigHeight;
401 int ret = jpeg_read_header(&cinfo, TRUE);
402 if (ret != JPEG_HEADER_OK) {
403 return FALSE;
404 }
405 if (cinfo.saw_Adobe_marker) {
406 m_bJpegTransform = TRUE;
407 }
408 if (cinfo.num_components == 3 && !m_bJpegTransform) {
409 cinfo.out_color_space = cinfo.jpeg_color_space;
410 }
411 m_OrigWidth = cinfo.image_width;
412 m_OrigHeight = cinfo.image_height;
413 m_OutputWidth = m_OrigWidth;
414 m_OutputHeight = m_OutputHeight;
415 m_nDefaultScaleDenom = cinfo.scale_denom;
416 return TRUE;
417 }
Create(FX_LPCBYTE src_buf,FX_DWORD src_size,int width,int height,int nComps,FX_BOOL ColorTransform,IFX_JpegProvider * pJP)418 FX_BOOL CCodec_JpegDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
419 int nComps, FX_BOOL ColorTransform, IFX_JpegProvider* pJP)
420 {
421 if (pJP) {
422 m_pExtProvider = pJP;
423 m_pExtContext = m_pExtProvider->CreateDecoder(src_buf, src_size, width, height, nComps, ColorTransform);
424 return m_pExtContext != NULL;
425 }
426 _JpegScanSOI(src_buf, src_size);
427 m_SrcBuf = src_buf;
428 m_SrcSize = src_size;
429 jerr.error_exit = _error_fatal;
430 jerr.emit_message = _error_do_nothing1;
431 jerr.output_message = _error_do_nothing;
432 jerr.format_message = _error_do_nothing2;
433 jerr.reset_error_mgr = _error_do_nothing;
434 src.init_source = _src_do_nothing;
435 src.term_source = _src_do_nothing;
436 src.skip_input_data = _src_skip_data;
437 src.fill_input_buffer = _src_fill_buffer;
438 src.resync_to_restart = _src_resync;
439 m_bJpegTransform = ColorTransform;
440 if(src_size > 1 && FXSYS_memcmp32(src_buf + src_size - 2, "\xFF\xD9", 2) != 0) {
441 ((FX_LPBYTE)src_buf)[src_size - 2] = 0xFF;
442 ((FX_LPBYTE)src_buf)[src_size - 1] = 0xD9;
443 }
444 m_OutputWidth = m_OrigWidth = width;
445 m_OutputHeight = m_OrigHeight = height;
446 if (!InitDecode()) {
447 return FALSE;
448 }
449 if (cinfo.num_components < nComps) {
450 return FALSE;
451 }
452 if ((int)cinfo.image_width < width) {
453 return FALSE;
454 }
455 m_Pitch = (cinfo.image_width * cinfo.num_components + 3) / 4 * 4;
456 m_pScanlineBuf = FX_Alloc(FX_BYTE, m_Pitch);
457 if (m_pScanlineBuf == NULL) {
458 return FALSE;
459 }
460 m_nComps = cinfo.num_components;
461 m_bpc = 8;
462 m_bColorTransformed = FALSE;
463 m_bStarted = FALSE;
464 return TRUE;
465 }
466 extern "C" {
FX_GetDownsampleRatio(FX_INT32 originWidth,FX_INT32 originHeight,FX_INT32 downsampleWidth,FX_INT32 downsampleHeight)467 FX_INT32 FX_GetDownsampleRatio(FX_INT32 originWidth, FX_INT32 originHeight, FX_INT32 downsampleWidth, FX_INT32 downsampleHeight)
468 {
469 int iratio_w = originWidth / downsampleWidth;
470 int iratio_h = originHeight / downsampleHeight;
471 int ratio = (iratio_w > iratio_h) ? iratio_h : iratio_w;
472 if (ratio >= 8) {
473 return 8;
474 } else if (ratio >= 4) {
475 return 4;
476 } else if (ratio >= 2) {
477 return 2;
478 }
479 return 1;
480 }
481 }
v_DownScale(int dest_width,int dest_height)482 void CCodec_JpegDecoder::v_DownScale(int dest_width, int dest_height)
483 {
484 if (m_pExtProvider) {
485 m_pExtProvider->DownScale(m_pExtContext, dest_width, dest_height);
486 return;
487 }
488 int old_scale = m_DownScale;
489 m_DownScale = FX_GetDownsampleRatio(m_OrigWidth, m_OrigHeight, dest_width, dest_height);
490 m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale;
491 m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale;
492 m_Pitch = (m_OutputWidth * m_nComps + 3) / 4 * 4;
493 if (old_scale != m_DownScale) {
494 m_NextLine = -1;
495 }
496 }
v_Rewind()497 FX_BOOL CCodec_JpegDecoder::v_Rewind()
498 {
499 if (m_pExtProvider) {
500 return m_pExtProvider->Rewind(m_pExtContext);
501 }
502 if (m_bStarted) {
503 jpeg_destroy_decompress(&cinfo);
504 if (!InitDecode()) {
505 return FALSE;
506 }
507 }
508 if (setjmp(m_JmpBuf) == -1) {
509 return FALSE;
510 }
511 cinfo.scale_denom = m_nDefaultScaleDenom * m_DownScale;
512 m_OutputWidth = (m_OrigWidth + m_DownScale - 1) / m_DownScale;
513 m_OutputHeight = (m_OrigHeight + m_DownScale - 1) / m_DownScale;
514 if (!jpeg_start_decompress(&cinfo)) {
515 jpeg_destroy_decompress(&cinfo);
516 return FALSE;
517 }
518 if ((int)cinfo.output_width > m_OrigWidth) {
519 FXSYS_assert(FALSE);
520 return FALSE;
521 }
522 m_bStarted = TRUE;
523 return TRUE;
524 }
v_GetNextLine()525 FX_LPBYTE CCodec_JpegDecoder::v_GetNextLine()
526 {
527 if (m_pExtProvider) {
528 return m_pExtProvider->GetNextLine(m_pExtContext);
529 }
530 int nlines = jpeg_read_scanlines(&cinfo, &m_pScanlineBuf, 1);
531 if (nlines < 1) {
532 return NULL;
533 }
534 return m_pScanlineBuf;
535 }
GetSrcOffset()536 FX_DWORD CCodec_JpegDecoder::GetSrcOffset()
537 {
538 if (m_pExtProvider) {
539 return m_pExtProvider->GetSrcOffset(m_pExtContext);
540 }
541 return (FX_DWORD)(m_SrcSize - src.bytes_in_buffer);
542 }
CreateDecoder(FX_LPCBYTE src_buf,FX_DWORD src_size,int width,int height,int nComps,FX_BOOL ColorTransform)543 ICodec_ScanlineDecoder* CCodec_JpegModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size,
544 int width, int height, int nComps, FX_BOOL ColorTransform)
545 {
546 if (src_buf == NULL || src_size == 0) {
547 return NULL;
548 }
549 CCodec_JpegDecoder* pDecoder = FX_NEW CCodec_JpegDecoder;
550 if (pDecoder == NULL) {
551 return NULL;
552 }
553 if (!pDecoder->Create(src_buf, src_size, width, height, nComps, ColorTransform, m_pExtProvider)) {
554 delete pDecoder;
555 return NULL;
556 }
557 return pDecoder;
558 }
LoadInfo(FX_LPCBYTE src_buf,FX_DWORD src_size,int & width,int & height,int & num_components,int & bits_per_components,FX_BOOL & color_transform,FX_LPBYTE * icc_buf_ptr,FX_DWORD * icc_length)559 FX_BOOL CCodec_JpegModule::LoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height,
560 int& num_components, int& bits_per_components, FX_BOOL& color_transform,
561 FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
562 {
563 if (m_pExtProvider) {
564 return m_pExtProvider->LoadInfo(src_buf, src_size, width, height,
565 num_components, bits_per_components, color_transform,
566 icc_buf_ptr, icc_length);
567 }
568 return _JpegLoadInfo(src_buf, src_size, width, height, num_components, bits_per_components, color_transform, icc_buf_ptr, icc_length);
569 }
Encode(const CFX_DIBSource * pSource,FX_LPBYTE & dest_buf,FX_STRSIZE & dest_size,int quality,FX_LPCBYTE icc_buf,FX_DWORD icc_length)570 FX_BOOL CCodec_JpegModule::Encode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length)
571 {
572 if (m_pExtProvider) {
573 return m_pExtProvider->Encode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length);
574 }
575 if(pSource->GetBPP() < 8 || pSource->GetPalette() != NULL) {
576 ASSERT(pSource->GetBPP() >= 8 && pSource->GetPalette() == NULL);
577 return FALSE;
578 }
579 _JpegEncode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length);
580 return TRUE;
581 }
582 struct FXJPEG_Context {
583 jmp_buf m_JumpMark;
584 jpeg_decompress_struct m_Info;
585 jpeg_error_mgr m_ErrMgr;
586 jpeg_source_mgr m_SrcMgr;
587 unsigned int m_SkipSize;
588 void* (*m_AllocFunc)(unsigned int);
589 void (*m_FreeFunc)(void*);
590 };
591 extern "C" {
_error_fatal1(j_common_ptr cinfo)592 static void _error_fatal1(j_common_ptr cinfo)
593 {
594 longjmp(((FXJPEG_Context*)cinfo->client_data)->m_JumpMark, -1);
595 }
596 };
597 extern "C" {
_src_skip_data1(struct jpeg_decompress_struct * cinfo,long num)598 static void _src_skip_data1(struct jpeg_decompress_struct* cinfo, long num)
599 {
600 if (cinfo->src->bytes_in_buffer < (size_t)num) {
601 ((FXJPEG_Context*)cinfo->client_data)->m_SkipSize = (unsigned int)(num - cinfo->src->bytes_in_buffer);
602 cinfo->src->bytes_in_buffer = 0;
603 } else {
604 cinfo->src->next_input_byte += num;
605 cinfo->src->bytes_in_buffer -= num;
606 }
607 }
608 };
jpeg_alloc_func(unsigned int size)609 static void* jpeg_alloc_func(unsigned int size)
610 {
611 return FX_Alloc(char, size);
612 }
jpeg_free_func(void * p)613 static void jpeg_free_func(void* p)
614 {
615 FX_Free(p);
616 }
Start()617 void* CCodec_JpegModule::Start()
618 {
619 if (m_pExtProvider) {
620 return m_pExtProvider->Start();
621 }
622 FXJPEG_Context* p = (FXJPEG_Context*)FX_Alloc(FX_BYTE, sizeof(FXJPEG_Context));
623 if (p == NULL) {
624 return NULL;
625 }
626 p->m_AllocFunc = jpeg_alloc_func;
627 p->m_FreeFunc = jpeg_free_func;
628 p->m_ErrMgr.error_exit = _error_fatal1;
629 p->m_ErrMgr.emit_message = _error_do_nothing1;
630 p->m_ErrMgr.output_message = _error_do_nothing;
631 p->m_ErrMgr.format_message = _error_do_nothing2;
632 p->m_ErrMgr.reset_error_mgr = _error_do_nothing;
633 p->m_SrcMgr.init_source = _src_do_nothing;
634 p->m_SrcMgr.term_source = _src_do_nothing;
635 p->m_SrcMgr.skip_input_data = _src_skip_data1;
636 p->m_SrcMgr.fill_input_buffer = _src_fill_buffer;
637 p->m_SrcMgr.resync_to_restart = _src_resync;
638 p->m_Info.client_data = p;
639 p->m_Info.err = &p->m_ErrMgr;
640 if (setjmp(p->m_JumpMark) == -1) {
641 return 0;
642 }
643 jpeg_create_decompress(&p->m_Info);
644 p->m_Info.src = &p->m_SrcMgr;
645 p->m_SkipSize = 0;
646 return p;
647 }
Finish(void * pContext)648 void CCodec_JpegModule::Finish(void* pContext)
649 {
650 if (m_pExtProvider) {
651 m_pExtProvider->Finish(pContext);
652 return;
653 }
654 FXJPEG_Context* p = (FXJPEG_Context*)pContext;
655 jpeg_destroy_decompress(&p->m_Info);
656 p->m_FreeFunc(p);
657 }
Input(void * pContext,const unsigned char * src_buf,FX_DWORD src_size)658 void CCodec_JpegModule::Input(void* pContext, const unsigned char* src_buf, FX_DWORD src_size)
659 {
660 if (m_pExtProvider) {
661 m_pExtProvider->Input(pContext, src_buf, src_size);
662 return;
663 }
664 FXJPEG_Context* p = (FXJPEG_Context*)pContext;
665 if (p->m_SkipSize) {
666 if (p->m_SkipSize > src_size) {
667 p->m_SrcMgr.bytes_in_buffer = 0;
668 p->m_SkipSize -= src_size;
669 return;
670 }
671 src_size -= p->m_SkipSize;
672 src_buf += p->m_SkipSize;
673 p->m_SkipSize = 0;
674 }
675 p->m_SrcMgr.next_input_byte = src_buf;
676 p->m_SrcMgr.bytes_in_buffer = src_size;
677 }
ReadHeader(void * pContext,int * width,int * height,int * nComps)678 int CCodec_JpegModule::ReadHeader(void* pContext, int* width, int* height, int* nComps)
679 {
680 if (m_pExtProvider) {
681 return m_pExtProvider->ReadHeader(pContext, width, height, nComps);
682 }
683 FXJPEG_Context* p = (FXJPEG_Context*)pContext;
684 if (setjmp(p->m_JumpMark) == -1) {
685 return 1;
686 }
687 int ret = jpeg_read_header(&p->m_Info, true);
688 if (ret == JPEG_SUSPENDED) {
689 return 2;
690 }
691 if (ret != JPEG_HEADER_OK) {
692 return 1;
693 }
694 *width = p->m_Info.image_width;
695 *height = p->m_Info.image_height;
696 *nComps = p->m_Info.num_components;
697 return 0;
698 }
StartScanline(void * pContext,int down_scale)699 FX_BOOL CCodec_JpegModule::StartScanline(void* pContext, int down_scale)
700 {
701 if (m_pExtProvider) {
702 return m_pExtProvider->StartScanline(pContext, down_scale);
703 }
704 FXJPEG_Context* p = (FXJPEG_Context*)pContext;
705 if (setjmp(p->m_JumpMark) == -1) {
706 return FALSE;
707 }
708 p->m_Info.scale_denom = down_scale;
709 return jpeg_start_decompress(&p->m_Info);
710 }
ReadScanline(void * pContext,unsigned char * dest_buf)711 FX_BOOL CCodec_JpegModule::ReadScanline(void* pContext, unsigned char* dest_buf)
712 {
713 if (m_pExtProvider) {
714 return m_pExtProvider->ReadScanline(pContext, dest_buf);
715 }
716 FXJPEG_Context* p = (FXJPEG_Context*)pContext;
717 if (setjmp(p->m_JumpMark) == -1) {
718 return FALSE;
719 }
720 int nlines = jpeg_read_scanlines(&p->m_Info, &dest_buf, 1);
721 return nlines == 1;
722 }
GetAvailInput(void * pContext,FX_LPBYTE * avail_buf_ptr)723 FX_DWORD CCodec_JpegModule::GetAvailInput(void* pContext, FX_LPBYTE* avail_buf_ptr)
724 {
725 if (m_pExtProvider) {
726 return m_pExtProvider->GetAvailInput(pContext, avail_buf_ptr);
727 }
728 if(avail_buf_ptr != NULL) {
729 *avail_buf_ptr = NULL;
730 if(((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer > 0) {
731 *avail_buf_ptr = (FX_LPBYTE)((FXJPEG_Context*)pContext)->m_SrcMgr.next_input_byte;
732 }
733 }
734 return (FX_DWORD)((FXJPEG_Context*)pContext)->m_SrcMgr.bytes_in_buffer;
735 }
736