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