Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(442)

Side by Side Diff: core/src/fxcodec/codec/fx_codec_jpeg.cpp

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

Powered by Google App Engine
This is Rietveld 408576698