diff options
Diffstat (limited to 'core/fxcodec/codec/fx_codec_jpeg.cpp')
-rw-r--r-- | core/fxcodec/codec/fx_codec_jpeg.cpp | 136 |
1 files changed, 120 insertions, 16 deletions
diff --git a/core/fxcodec/codec/fx_codec_jpeg.cpp b/core/fxcodec/codec/fx_codec_jpeg.cpp index fdfdd4faeb..c797605575 100644 --- a/core/fxcodec/codec/fx_codec_jpeg.cpp +++ b/core/fxcodec/codec/fx_codec_jpeg.cpp @@ -27,6 +27,7 @@ extern "C" { } extern "C" { + static void JpegScanSOI(const uint8_t** src_buf, uint32_t* src_size) { if (*src_size == 0) return; @@ -41,16 +42,13 @@ static void JpegScanSOI(const uint8_t** src_buf, uint32_t* src_size) { offset++; } } -}; -extern "C" { + static void _src_do_nothing(struct jpeg_decompress_struct* cinfo) {} -}; -extern "C" { + static void _error_fatal(j_common_ptr cinfo) { longjmp(*(jmp_buf*)cinfo->client_data, -1); } -}; -extern "C" { + static void _src_skip_data(struct jpeg_decompress_struct* cinfo, long num) { if (num > (long)cinfo->src->bytes_in_buffer) { _error_fatal((j_common_ptr)cinfo); @@ -58,25 +56,28 @@ static void _src_skip_data(struct jpeg_decompress_struct* cinfo, long num) { cinfo->src->next_input_byte += num; cinfo->src->bytes_in_buffer -= num; } -}; -extern "C" { + static boolean _src_fill_buffer(j_decompress_ptr cinfo) { return 0; } -}; -extern "C" { + static boolean _src_resync(j_decompress_ptr cinfo, int desired) { return 0; } -}; -extern "C" { + static void _error_do_nothing(j_common_ptr cinfo) {} -}; -extern "C" { + static void _error_do_nothing1(j_common_ptr cinfo, int) {} -}; -extern "C" { + static void _error_do_nothing2(j_common_ptr cinfo, char*) {} + +#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ +static void _dest_do_nothing(j_compress_ptr cinfo) {} + +static boolean _dest_empty(j_compress_ptr cinfo) { + return false; +} +#endif }; #define JPEG_MARKER_ICC (JPEG_APP0 + 2) @@ -480,3 +481,106 @@ uint32_t CCodec_JpegModule::GetAvailInput(FXJPEG_Context* ctx, } return (uint32_t)ctx->m_SrcMgr.bytes_in_buffer; } + +#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_ +#define JPEG_BLOCK_SIZE 1048576 +bool CCodec_JpegModule::JpegEncode(const CFX_DIBSource* pSource, + uint8_t** dest_buf, + FX_STRSIZE* dest_size) { + struct jpeg_error_mgr jerr; + jerr.error_exit = _error_do_nothing; + jerr.emit_message = _error_do_nothing1; + jerr.output_message = _error_do_nothing; + jerr.format_message = _error_do_nothing2; + jerr.reset_error_mgr = _error_do_nothing; + + struct jpeg_compress_struct cinfo; + memset(&cinfo, 0, sizeof(cinfo)); + cinfo.err = &jerr; + jpeg_create_compress(&cinfo); + int Bpp = pSource->GetBPP() / 8; + uint32_t nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1; + uint32_t pitch = pSource->GetPitch(); + uint32_t width = pdfium::base::checked_cast<uint32_t>(pSource->GetWidth()); + uint32_t height = pdfium::base::checked_cast<uint32_t>(pSource->GetHeight()); + FX_SAFE_UINT32 safe_buf_len = width; + safe_buf_len *= height; + safe_buf_len *= nComponents; + safe_buf_len += 1024; + if (!safe_buf_len.IsValid()) + return false; + + uint32_t dest_buf_length = safe_buf_len.ValueOrDie(); + *dest_buf = FX_TryAlloc(uint8_t, dest_buf_length); + const int MIN_TRY_BUF_LEN = 1024; + while (!(*dest_buf) && dest_buf_length > MIN_TRY_BUF_LEN) { + dest_buf_length >>= 1; + *dest_buf = FX_TryAlloc(uint8_t, dest_buf_length); + } + if (!(*dest_buf)) + return false; + + struct jpeg_destination_mgr dest; + dest.init_destination = _dest_do_nothing; + dest.term_destination = _dest_do_nothing; + dest.empty_output_buffer = _dest_empty; + dest.next_output_byte = *dest_buf; + dest.free_in_buffer = dest_buf_length; + cinfo.dest = &dest; + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = nComponents; + if (nComponents == 1) { + cinfo.in_color_space = JCS_GRAYSCALE; + } else if (nComponents == 3) { + cinfo.in_color_space = JCS_RGB; + } else { + cinfo.in_color_space = JCS_CMYK; + } + uint8_t* line_buf = nullptr; + if (nComponents > 1) + line_buf = FX_Alloc2D(uint8_t, width, nComponents); + + jpeg_set_defaults(&cinfo); + jpeg_start_compress(&cinfo, TRUE); + JSAMPROW row_pointer[1]; + JDIMENSION row; + while (cinfo.next_scanline < cinfo.image_height) { + const uint8_t* src_scan = pSource->GetScanline(cinfo.next_scanline); + if (nComponents > 1) { + uint8_t* dest_scan = line_buf; + if (nComponents == 3) { + for (uint32_t i = 0; i < width; i++) { + dest_scan[0] = src_scan[2]; + dest_scan[1] = src_scan[1]; + dest_scan[2] = src_scan[0]; + dest_scan += 3; + src_scan += Bpp; + } + } else { + for (uint32_t i = 0; i < pitch; i++) { + *dest_scan++ = ~*src_scan++; + } + } + row_pointer[0] = line_buf; + } else { + row_pointer[0] = (uint8_t*)src_scan; + } + row = cinfo.next_scanline; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + if (cinfo.next_scanline == row) { + *dest_buf = + FX_Realloc(uint8_t, *dest_buf, dest_buf_length + JPEG_BLOCK_SIZE); + dest.next_output_byte = *dest_buf + dest_buf_length - dest.free_in_buffer; + dest_buf_length += JPEG_BLOCK_SIZE; + dest.free_in_buffer += JPEG_BLOCK_SIZE; + } + } + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + FX_Free(line_buf); + *dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer; + + return true; +} +#endif |