diff options
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/fpdfapi/fpdf_edit/fpdf_edit_create.cpp | 95 | ||||
-rw-r--r-- | core/src/fpdfapi/fpdf_edit/fpdf_edit_image.cpp | 7 | ||||
-rw-r--r-- | core/src/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp | 35 | ||||
-rw-r--r-- | core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp | 12 | ||||
-rw-r--r-- | core/src/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp | 6 | ||||
-rw-r--r-- | core/src/fxcodec/codec/codec_int.h | 54 | ||||
-rw-r--r-- | core/src/fxcodec/codec/fx_codec.cpp | 115 | ||||
-rw-r--r-- | core/src/fxcodec/codec/fx_codec_fax.cpp | 187 | ||||
-rw-r--r-- | core/src/fxcodec/codec/fx_codec_flate.cpp | 201 | ||||
-rw-r--r-- | core/src/fxcodec/codec/fx_codec_jpeg.cpp | 229 | ||||
-rw-r--r-- | core/src/fxge/ge/fx_ge_ps.cpp | 699 |
11 files changed, 1486 insertions, 154 deletions
diff --git a/core/src/fpdfapi/fpdf_edit/fpdf_edit_create.cpp b/core/src/fpdfapi/fpdf_edit/fpdf_edit_create.cpp index 1151c6390e..49ec0bae92 100644 --- a/core/src/fpdfapi/fpdf_edit/fpdf_edit_create.cpp +++ b/core/src/fpdfapi/fpdf_edit/fpdf_edit_create.cpp @@ -307,11 +307,11 @@ class CPDF_FlateEncoder { public: CPDF_FlateEncoder(); ~CPDF_FlateEncoder(); - bool Initialize(CPDF_Stream* pStream, FX_BOOL bFlateEncode); - bool Initialize(const uint8_t* pBuffer, - FX_DWORD size, - bool bFlateEncode, - bool bXRefStream); + FX_BOOL Initialize(CPDF_Stream* pStream, FX_BOOL bFlateEncode); + FX_BOOL Initialize(const uint8_t* pBuffer, + FX_DWORD size, + FX_BOOL bFlateEncode, + FX_BOOL bXRefStream = FALSE); void CloneDict(); uint8_t* m_pData; FX_DWORD m_dwSize; @@ -334,7 +334,8 @@ void CPDF_FlateEncoder::CloneDict() { m_bCloned = TRUE; } } -bool CPDF_FlateEncoder::Initialize(CPDF_Stream* pStream, FX_BOOL bFlateEncode) { +FX_BOOL CPDF_FlateEncoder::Initialize(CPDF_Stream* pStream, + FX_BOOL bFlateEncode) { m_Acc.LoadAllData(pStream, TRUE); if ((pStream && pStream->GetDict() && pStream->GetDict()->KeyExist("Filter")) || @@ -353,41 +354,36 @@ bool CPDF_FlateEncoder::Initialize(CPDF_Stream* pStream, FX_BOOL bFlateEncode) { m_dwSize = m_Acc.GetSize(); m_pDict = pStream->GetDict(); } - return true; + return TRUE; } - m_pData = nullptr; + m_pData = NULL; m_dwSize = 0; m_bNewData = TRUE; m_bCloned = TRUE; - if (!::FlateEncode(m_Acc.GetData(), m_Acc.GetSize(), &m_pData, &m_dwSize)) - return false; - + ::FlateEncode(m_Acc.GetData(), m_Acc.GetSize(), m_pData, m_dwSize); m_pDict = ToDictionary(pStream->GetDict()->Clone()); m_pDict->SetAtInteger("Length", m_dwSize); m_pDict->SetAtName("Filter", "FlateDecode"); m_pDict->RemoveAt("DecodeParms"); - return true; + return TRUE; } - -bool CPDF_FlateEncoder::Initialize(const uint8_t* pBuffer, - FX_DWORD size, - bool bFlateEncode, - bool bXRefStream) { +FX_BOOL CPDF_FlateEncoder::Initialize(const uint8_t* pBuffer, + FX_DWORD size, + FX_BOOL bFlateEncode, + FX_BOOL bXRefStream) { if (!bFlateEncode) { m_pData = (uint8_t*)pBuffer; m_dwSize = size; - return true; + return TRUE; } m_bNewData = TRUE; - bool ret; if (bXRefStream) { - ret = ::PngEncode(pBuffer, size, &m_pData, &m_dwSize); + ::FlateEncode(pBuffer, size, 12, 1, 8, 7, m_pData, m_dwSize); } else { - ret = ::FlateEncode(pBuffer, size, &m_pData, &m_dwSize); + ::FlateEncode(pBuffer, size, m_pData, m_dwSize); } - return ret; + return TRUE; } - CPDF_FlateEncoder::~CPDF_FlateEncoder() { if (m_bCloned && m_pDict) { m_pDict->Release(); @@ -522,15 +518,11 @@ FX_FILESIZE CPDF_ObjectStream::End(CPDF_Creator* pCreator) { } else { tempBuffer << m_Buffer; CPDF_FlateEncoder encoder; - if (!encoder.Initialize(tempBuffer.GetBuffer(), tempBuffer.GetLength(), - pCreator->m_bCompress, false)) { - return -1; - } + encoder.Initialize(tempBuffer.GetBuffer(), tempBuffer.GetLength(), + pCreator->m_bCompress); CPDF_Encryptor encryptor; - if (!encryptor.Initialize(pHandler, m_dwObjNum, encoder.m_pData, - encoder.m_dwSize)) { - return -1; - } + encryptor.Initialize(pHandler, m_dwObjNum, encoder.m_pData, + encoder.m_dwSize); if ((len = pFile->AppendDWord(encryptor.m_dwSize)) < 0) { return -1; } @@ -776,21 +768,22 @@ FX_BOOL CPDF_XRefStream::GenerateXRefStream(CPDF_Creator* pCreator, } offset += len + 6; } + FX_BOOL bPredictor = TRUE; CPDF_FlateEncoder encoder; - if (!encoder.Initialize(m_Buffer.GetBuffer(), m_Buffer.GetLength(), - pCreator->m_bCompress, true)) { - return FALSE; - } + encoder.Initialize(m_Buffer.GetBuffer(), m_Buffer.GetLength(), + pCreator->m_bCompress, bPredictor); if (pCreator->m_bCompress) { if (pFile->AppendString("/Filter /FlateDecode") < 0) { return FALSE; } offset += 20; - if ((len = pFile->AppendString("/DecodeParms<</Columns 7/Predictor 12>>")) < - 0) { - return FALSE; + if (bPredictor) { + if ((len = pFile->AppendString( + "/DecodeParms<</Columns 7/Predictor 12>>")) < 0) { + return FALSE; + } + offset += len; } - offset += len; } if (pFile->AppendString("/Length ") < 0) { return FALSE; @@ -1009,10 +1002,8 @@ int32_t CPDF_Creator::WriteStream(const CPDF_Object* pStream, FX_DWORD objnum, CPDF_CryptoHandler* pCrypto) { CPDF_FlateEncoder encoder; - if (!encoder.Initialize(const_cast<CPDF_Stream*>(pStream->AsStream()), - pStream == m_pMetadata ? FALSE : m_bCompress)) { - return -1; - } + encoder.Initialize(const_cast<CPDF_Stream*>(pStream->AsStream()), + pStream == m_pMetadata ? FALSE : m_bCompress); CPDF_Encryptor encryptor; if (!encryptor.Initialize(pCrypto, objnum, encoder.m_pData, encoder.m_dwSize)) { @@ -1116,10 +1107,8 @@ int32_t CPDF_Creator::WriteDirectObj(FX_DWORD objnum, break; } CPDF_Encryptor encryptor; - if (!encryptor.Initialize(m_pCryptoHandler, objnum, (uint8_t*)str.c_str(), - str.GetLength())) { - return -1; - } + encryptor.Initialize(m_pCryptoHandler, objnum, (uint8_t*)str.c_str(), + str.GetLength()); CFX_ByteString content = PDF_EncodeString( CFX_ByteString((const FX_CHAR*)encryptor.m_pData, encryptor.m_dwSize), bHex); @@ -1131,17 +1120,11 @@ int32_t CPDF_Creator::WriteDirectObj(FX_DWORD objnum, } case PDFOBJ_STREAM: { CPDF_FlateEncoder encoder; - if (!encoder.Initialize(const_cast<CPDF_Stream*>(pObj->AsStream()), - m_bCompress)) { - return -1; - } - + encoder.Initialize(const_cast<CPDF_Stream*>(pObj->AsStream()), + m_bCompress); CPDF_Encryptor encryptor; CPDF_CryptoHandler* pHandler = m_pCryptoHandler; - if (!encryptor.Initialize(pHandler, objnum, encoder.m_pData, - encoder.m_dwSize)) { - return -1; - } + encryptor.Initialize(pHandler, objnum, encoder.m_pData, encoder.m_dwSize); if ((FX_DWORD)encoder.m_pDict->GetInteger("Length") != encryptor.m_dwSize) { encoder.CloneDict(); diff --git a/core/src/fpdfapi/fpdf_edit/fpdf_edit_image.cpp b/core/src/fpdfapi/fpdf_edit/fpdf_edit_image.cpp index 386c49d005..2b68a0403f 100644 --- a/core/src/fpdfapi/fpdf_edit/fpdf_edit_image.cpp +++ b/core/src/fpdfapi/fpdf_edit/fpdf_edit_image.cpp @@ -16,12 +16,11 @@ CPDF_Dictionary* CPDF_Image::InitJPEG(uint8_t* pData, FX_DWORD size) { int32_t height; int32_t num_comps; int32_t bits; - bool color_trans; + FX_BOOL color_trans; if (!CPDF_ModuleMgr::Get()->GetJpegModule()->LoadInfo( - pData, size, &width, &height, &num_comps, &bits, &color_trans)) { - return nullptr; + pData, size, width, height, num_comps, bits, color_trans)) { + return NULL; } - CPDF_Dictionary* pDict = new CPDF_Dictionary; pDict->SetAtName("Type", "XObject"); pDict->SetAtName("Subtype", "Image"); diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp index 8832940f80..c855a7c5c2 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode.cpp @@ -540,27 +540,30 @@ CFX_ByteString PDF_EncodeString(const CFX_ByteString& src, FX_BOOL bHex) { result.AppendChar(')'); return result.GetByteString(); } - -bool FlateEncode(const uint8_t* src_buf, +void FlateEncode(const uint8_t* src_buf, FX_DWORD src_size, - uint8_t** dest_buf, - FX_DWORD* dest_size) { + uint8_t*& dest_buf, + FX_DWORD& dest_size) { CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); - return pEncoders && - pEncoders->GetFlateModule()->Encode(src_buf, src_size, dest_buf, - dest_size); + if (pEncoders) { + pEncoders->GetFlateModule()->Encode(src_buf, src_size, dest_buf, dest_size); + } } - -bool PngEncode(const uint8_t* src_buf, - FX_DWORD src_size, - uint8_t** dest_buf, - FX_DWORD* dest_size) { +void FlateEncode(const uint8_t* src_buf, + FX_DWORD src_size, + int predictor, + int Colors, + int BitsPerComponent, + int Columns, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { CCodec_ModuleMgr* pEncoders = CPDF_ModuleMgr::Get()->GetCodecModule(); - return pEncoders && - pEncoders->GetFlateModule()->Encode(src_buf, src_size, dest_buf, - dest_size); + if (pEncoders) { + pEncoders->GetFlateModule()->Encode(src_buf, src_size, predictor, Colors, + BitsPerComponent, Columns, dest_buf, + dest_size); + } } - FX_DWORD FlateDecode(const uint8_t* src_buf, FX_DWORD src_size, uint8_t*& dest_buf, diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp index 810a633c83..c80770366b 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp @@ -47,14 +47,14 @@ TEST_F(FPDFParserDecodeEmbeddertest, FlateEncode) { for (size_t i = 0; i < FX_ArraySize(flate_encode_cases); ++i) { FlateEncodeCase* ptr = &flate_encode_cases[i]; - unsigned char* buf; - unsigned int buf_size; - EXPECT_TRUE(FlateEncode(ptr->input, ptr->input_size, &buf, &buf_size)); - ASSERT_TRUE(buf); + unsigned char* result; + unsigned int result_size; + FlateEncode(ptr->input, ptr->input_size, result, result_size); + ASSERT_TRUE(result); EXPECT_EQ(std::string((const char*)ptr->expected, ptr->expected_size), - std::string((const char*)buf, buf_size)) + std::string((const char*)result, result_size)) << " for case " << i; - FX_Free(buf); + FX_Free(result); } } diff --git a/core/src/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp b/core/src/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp index c107c002c2..0306ff0227 100644 --- a/core/src/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp +++ b/core/src/fpdfapi/fpdf_render/fpdf_render_loadimage.cpp @@ -615,11 +615,11 @@ int CPDF_DIBSource::CreateDecoder() { src_data, src_size, m_Width, m_Height, m_nComponents, pParams ? pParams->GetInteger("ColorTransform", 1) : 1); if (!m_pDecoder) { - bool bTransform = false; + FX_BOOL bTransform = FALSE; int comps, bpc; ICodec_JpegModule* pJpegModule = CPDF_ModuleMgr::Get()->GetJpegModule(); - if (pJpegModule->LoadInfo(src_data, src_size, &m_Width, &m_Height, &comps, - &bpc, &bTransform)) { + if (pJpegModule->LoadInfo(src_data, src_size, m_Width, m_Height, comps, + bpc, bTransform)) { if (m_nComponents != comps) { FX_Free(m_pCompData); m_nComponents = comps; diff --git a/core/src/fxcodec/codec/codec_int.h b/core/src/fxcodec/codec/codec_int.h index c3daf3bdf2..1495f9e680 100644 --- a/core/src/fxcodec/codec/codec_int.h +++ b/core/src/fxcodec/codec/codec_int.h @@ -22,6 +22,14 @@ class CFX_IccTransformCache; class CCodec_BasicModule : public ICodec_BasicModule { public: // ICodec_BasicModule: + FX_BOOL RunLengthEncode(const uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& dest_buf, + FX_DWORD& dest_size) override; + FX_BOOL A85Encode(const uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& dest_buf, + FX_DWORD& dest_size) override; ICodec_ScanlineDecoder* CreateRunLengthDecoder(const uint8_t* src_buf, FX_DWORD src_size, int width, @@ -105,6 +113,12 @@ class CCodec_FaxModule : public ICodec_FaxModule { FX_BOOL BlackIs1, int Columns, int Rows) override; + FX_BOOL Encode(const uint8_t* src_buf, + int width, + int height, + int pitch, + uint8_t*& dest_buf, + FX_DWORD& dest_size) override; }; class CCodec_FlateModule : public ICodec_FlateModule { @@ -130,14 +144,18 @@ class CCodec_FlateModule : public ICodec_FlateModule { FX_DWORD estimated_size, uint8_t*& dest_buf, FX_DWORD& dest_size); - virtual bool Encode(const uint8_t* src_buf, - FX_DWORD src_size, - uint8_t** dest_buf, - FX_DWORD* dest_size); - virtual bool PngEncode(const uint8_t* src_buf, + virtual FX_BOOL Encode(const uint8_t* src_buf, FX_DWORD src_size, - uint8_t** dest_buf, - FX_DWORD* dest_size); + int predictor, + int Colors, + int BitsPerComponent, + int Columns, + uint8_t*& dest_buf, + FX_DWORD& dest_size); + virtual FX_BOOL Encode(const uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& dest_buf, + FX_DWORD& dest_size); }; class CCodec_JpegModule : public ICodec_JpegModule { @@ -149,13 +167,21 @@ class CCodec_JpegModule : public ICodec_JpegModule { int height, int nComps, FX_BOOL ColorTransform) override; - bool LoadInfo(const uint8_t* src_buf, - FX_DWORD src_size, - int* width, - int* height, - int* num_components, - int* bits_per_components, - bool* color_transform) override; + FX_BOOL LoadInfo(const uint8_t* src_buf, + FX_DWORD src_size, + int& width, + int& height, + int& num_components, + int& bits_per_components, + FX_BOOL& color_transform, + uint8_t** icc_buf_ptr, + FX_DWORD* icc_length) override; + FX_BOOL Encode(const CFX_DIBSource* pSource, + uint8_t*& dest_buf, + FX_STRSIZE& dest_size, + int quality, + const uint8_t* icc_buf, + FX_DWORD icc_length) override; void* Start() override; void Finish(void* pContext) override; void Input(void* pContext, diff --git a/core/src/fxcodec/codec/fx_codec.cpp b/core/src/fxcodec/codec/fx_codec.cpp index d7c7c4eeb4..6998114f83 100644 --- a/core/src/fxcodec/codec/fx_codec.cpp +++ b/core/src/fxcodec/codec/fx_codec.cpp @@ -142,6 +142,121 @@ void CCodec_ScanlineDecoder::DownScale(int dest_width, int dest_height) { m_pDataCache = nonstd::move(cache); } +FX_BOOL CCodec_BasicModule::RunLengthEncode(const uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { + return FALSE; +} + +#define EXPONENT_DETECT(ptr) \ + for (;; ptr++) { \ + if (!std::isdigit(*ptr)) { \ + if (endptr) \ + *endptr = (char*)ptr; \ + break; \ + } else { \ + exp_ret *= 10; \ + exp_ret += FXSYS_toDecimalDigit(*ptr); \ + continue; \ + } \ + } + +extern "C" double FXstrtod(const char* nptr, char** endptr) { + double ret = 0.0; + const char* ptr = nptr; + const char* exp_ptr = NULL; + int e_number = 0, e_signal = 0, e_point = 0, is_negative = 0; + int exp_ret = 0, exp_sig = 1, fra_ret = 0, fra_count = 0, fra_base = 1; + if (!nptr) { + return 0.0; + } + for (;; ptr++) { + if (!e_number && !e_point && (*ptr == '\t' || *ptr == ' ')) + continue; + + if (std::isdigit(*ptr)) { + if (!e_number) + e_number = 1; + + if (!e_point) { + ret *= 10; + ret += FXSYS_toDecimalDigit(*ptr); + } else { + fra_count++; + fra_ret *= 10; + fra_ret += FXSYS_toDecimalDigit(*ptr); + } + continue; + } + if (!e_point && *ptr == '.') { + e_point = 1; + continue; + } + if (!e_number && !e_point && !e_signal) { + switch (*ptr) { + case '-': + is_negative = 1; + case '+': + e_signal = 1; + continue; + } + } + if (e_number && (*ptr == 'e' || *ptr == 'E')) { + exp_ptr = ptr++; + if (*ptr == '+' || *ptr == '-') { + exp_sig = (*ptr++ == '+') ? 1 : -1; + if (!std::isdigit(*ptr)) { + if (endptr) { + *endptr = (char*)exp_ptr; + } + break; + } + EXPONENT_DETECT(ptr); + } else if (std::isdigit(*ptr)) { + EXPONENT_DETECT(ptr); + } else { + if (endptr) { + *endptr = (char*)exp_ptr; + } + break; + } + break; + } + if (ptr != nptr && !e_number) { + if (endptr) { + *endptr = (char*)nptr; + } + break; + } + if (endptr) { + *endptr = (char*)ptr; + } + break; + } + while (fra_count--) { + fra_base *= 10; + } + ret += (double)fra_ret / (double)fra_base; + if (exp_sig == 1) { + while (exp_ret--) { + ret *= 10.0; + } + } else { + while (exp_ret--) { + ret /= 10.0; + } + } + return is_negative ? -ret : ret; +} +#undef EXPONENT_DETECT + +FX_BOOL CCodec_BasicModule::A85Encode(const uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { + return FALSE; +} class CCodec_RLScanlineDecoder : public CCodec_ScanlineDecoder { public: CCodec_RLScanlineDecoder(); diff --git a/core/src/fxcodec/codec/fx_codec_fax.cpp b/core/src/fxcodec/codec/fx_codec_fax.cpp index 686fc08b61..b198e74784 100644 --- a/core/src/fxcodec/codec/fx_codec_fax.cpp +++ b/core/src/fxcodec/codec/fx_codec_fax.cpp @@ -466,6 +466,134 @@ FX_BOOL FaxGet1DLine(const uint8_t* src_buf, return TRUE; } +const uint8_t BlackRunTerminator[128] = { + 0x37, 10, 0x02, 3, 0x03, 2, 0x02, 2, 0x03, 3, 0x03, 4, 0x02, 4, + 0x03, 5, 0x05, 6, 0x04, 6, 0x04, 7, 0x05, 7, 0x07, 7, 0x04, 8, + 0x07, 8, 0x18, 9, 0x17, 10, 0x18, 10, 0x08, 10, 0x67, 11, 0x68, 11, + 0x6c, 11, 0x37, 11, 0x28, 11, 0x17, 11, 0x18, 11, 0xca, 12, 0xcb, 12, + 0xcc, 12, 0xcd, 12, 0x68, 12, 0x69, 12, 0x6a, 12, 0x6b, 12, 0xd2, 12, + 0xd3, 12, 0xd4, 12, 0xd5, 12, 0xd6, 12, 0xd7, 12, 0x6c, 12, 0x6d, 12, + 0xda, 12, 0xdb, 12, 0x54, 12, 0x55, 12, 0x56, 12, 0x57, 12, 0x64, 12, + 0x65, 12, 0x52, 12, 0x53, 12, 0x24, 12, 0x37, 12, 0x38, 12, 0x27, 12, + 0x28, 12, 0x58, 12, 0x59, 12, 0x2b, 12, 0x2c, 12, 0x5a, 12, 0x66, 12, + 0x67, 12, +}; + +const uint8_t BlackRunMarkup[80] = { + 0x0f, 10, 0xc8, 12, 0xc9, 12, 0x5b, 12, 0x33, 12, 0x34, 12, 0x35, 12, + 0x6c, 13, 0x6d, 13, 0x4a, 13, 0x4b, 13, 0x4c, 13, 0x4d, 13, 0x72, 13, + 0x73, 13, 0x74, 13, 0x75, 13, 0x76, 13, 0x77, 13, 0x52, 13, 0x53, 13, + 0x54, 13, 0x55, 13, 0x5a, 13, 0x5b, 13, 0x64, 13, 0x65, 13, 0x08, 11, + 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12, + 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12, +}; + +const uint8_t WhiteRunTerminator[128] = { + 0x35, 8, 0x07, 6, 0x07, 4, 0x08, 4, 0x0B, 4, 0x0C, 4, 0x0E, 4, 0x0F, 4, + 0x13, 5, 0x14, 5, 0x07, 5, 0x08, 5, 0x08, 6, 0x03, 6, 0x34, 6, 0x35, 6, + 0x2a, 6, 0x2B, 6, 0x27, 7, 0x0c, 7, 0x08, 7, 0x17, 7, 0x03, 7, 0x04, 7, + 0x28, 7, 0x2B, 7, 0x13, 7, 0x24, 7, 0x18, 7, 0x02, 8, 0x03, 8, 0x1a, 8, + 0x1b, 8, 0x12, 8, 0x13, 8, 0x14, 8, 0x15, 8, 0x16, 8, 0x17, 8, 0x28, 8, + 0x29, 8, 0x2a, 8, 0x2b, 8, 0x2c, 8, 0x2d, 8, 0x04, 8, 0x05, 8, 0x0a, 8, + 0x0b, 8, 0x52, 8, 0x53, 8, 0x54, 8, 0x55, 8, 0x24, 8, 0x25, 8, 0x58, 8, + 0x59, 8, 0x5a, 8, 0x5b, 8, 0x4a, 8, 0x4b, 8, 0x32, 8, 0x33, 8, 0x34, 8, +}; + +const uint8_t WhiteRunMarkup[80] = { + 0x1b, 5, 0x12, 5, 0x17, 6, 0x37, 7, 0x36, 8, 0x37, 8, 0x64, 8, + 0x65, 8, 0x68, 8, 0x67, 8, 0xcc, 9, 0xcd, 9, 0xd2, 9, 0xd3, 9, + 0xd4, 9, 0xd5, 9, 0xd6, 9, 0xd7, 9, 0xd8, 9, 0xd9, 9, 0xda, 9, + 0xdb, 9, 0x98, 9, 0x99, 9, 0x9a, 9, 0x18, 6, 0x9b, 9, 0x08, 11, + 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12, + 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12, +}; + +void AddBitStream(uint8_t* dest_buf, int& dest_bitpos, int data, int bitlen) { + for (int i = bitlen - 1; i >= 0; i--) { + if (data & (1 << i)) { + dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8); + } + dest_bitpos++; + } +} + +void FaxEncodeRun(uint8_t* dest_buf, int& dest_bitpos, int run, bool bWhite) { + while (run >= 2560) { + AddBitStream(dest_buf, dest_bitpos, 0x1f, 12); + run -= 2560; + } + if (run >= 64) { + int markup = run - run % 64; + const uint8_t* p = bWhite ? WhiteRunMarkup : BlackRunMarkup; + p += (markup / 64 - 1) * 2; + AddBitStream(dest_buf, dest_bitpos, *p, p[1]); + } + run %= 64; + const uint8_t* p = bWhite ? WhiteRunTerminator : BlackRunTerminator; + p += run * 2; + AddBitStream(dest_buf, dest_bitpos, *p, p[1]); +} + +void FaxEncode2DLine(uint8_t* dest_buf, + int& dest_bitpos, + const uint8_t* src_buf, + const uint8_t* ref_buf, + int cols) { + int a0 = -1; + bool a0color = true; + while (1) { + int a1 = FindBit(src_buf, cols, a0 + 1, !a0color); + int b1, b2; + FaxG4FindB1B2(ref_buf, cols, a0, a0color, b1, b2); + if (b2 < a1) { + dest_bitpos += 3; + dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8); + dest_bitpos++; + a0 = b2; + } else if (a1 - b1 <= 3 && b1 - a1 <= 3) { + int delta = a1 - b1; + switch (delta) { + case 0: + dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8); + break; + case 1: + case 2: + case 3: + dest_bitpos += delta == 1 ? 1 : delta + 2; + dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8); + dest_bitpos++; + dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8); + break; + case -1: + case -2: + case -3: + dest_bitpos += delta == -1 ? 1 : -delta + 2; + dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8); + dest_bitpos++; + break; + } + dest_bitpos++; + a0 = a1; + a0color = !a0color; + } else { + int a2 = FindBit(src_buf, cols, a1 + 1, a0color); + dest_bitpos++; + dest_bitpos++; + dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8); + dest_bitpos++; + if (a0 < 0) { + a0 = 0; + } + FaxEncodeRun(dest_buf, dest_bitpos, a1 - a0, a0color); + FaxEncodeRun(dest_buf, dest_bitpos, a2 - a1, !a0color); + a0 = a2; + } + if (a0 >= cols) { + return; + } + } +} + } // namespace class CCodec_FaxDecoder : public CCodec_ScanlineDecoder { @@ -626,6 +754,65 @@ void FaxG4Decode(const uint8_t* src_buf, *pbitpos = bitpos; } +class CCodec_FaxEncoder { + public: + CCodec_FaxEncoder(const uint8_t* src_buf, int width, int height, int pitch); + ~CCodec_FaxEncoder(); + void Encode(uint8_t*& dest_buf, FX_DWORD& dest_size); + void Encode2DLine(const uint8_t* scan_line); + CFX_BinaryBuf m_DestBuf; + uint8_t* m_pRefLine; + uint8_t* m_pLineBuf; + int m_Cols, m_Rows, m_Pitch; + const uint8_t* m_pSrcBuf; +}; +CCodec_FaxEncoder::CCodec_FaxEncoder(const uint8_t* src_buf, + int width, + int height, + int pitch) { + m_pSrcBuf = src_buf; + m_Cols = width; + m_Rows = height; + m_Pitch = pitch; + m_pRefLine = FX_Alloc(uint8_t, m_Pitch); + FXSYS_memset(m_pRefLine, 0xff, m_Pitch); + m_pLineBuf = FX_Alloc2D(uint8_t, m_Pitch, 8); + m_DestBuf.EstimateSize(0, 10240); +} +CCodec_FaxEncoder::~CCodec_FaxEncoder() { + FX_Free(m_pRefLine); + FX_Free(m_pLineBuf); +} +void CCodec_FaxEncoder::Encode(uint8_t*& dest_buf, FX_DWORD& dest_size) { + int dest_bitpos = 0; + uint8_t last_byte = 0; + for (int i = 0; i < m_Rows; i++) { + const uint8_t* scan_line = m_pSrcBuf + i * m_Pitch; + FXSYS_memset(m_pLineBuf, 0, m_Pitch * 8); + m_pLineBuf[0] = last_byte; + FaxEncode2DLine(m_pLineBuf, dest_bitpos, scan_line, m_pRefLine, m_Cols); + m_DestBuf.AppendBlock(m_pLineBuf, dest_bitpos / 8); + last_byte = m_pLineBuf[dest_bitpos / 8]; + dest_bitpos %= 8; + FXSYS_memcpy(m_pRefLine, scan_line, m_Pitch); + } + if (dest_bitpos) { + m_DestBuf.AppendByte(last_byte); + } + dest_buf = m_DestBuf.GetBuffer(); + dest_size = m_DestBuf.GetSize(); + m_DestBuf.DetachBuffer(); +} +FX_BOOL CCodec_FaxModule::Encode(const uint8_t* src_buf, + int width, + int height, + int pitch, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { + CCodec_FaxEncoder encoder(src_buf, width, height, pitch); + encoder.Encode(dest_buf, dest_size); + return TRUE; +} ICodec_ScanlineDecoder* CCodec_FaxModule::CreateDecoder( const uint8_t* src_buf, FX_DWORD src_size, diff --git a/core/src/fxcodec/codec/fx_codec_flate.cpp b/core/src/fxcodec/codec/fx_codec_flate.cpp index 844a17e282..b293781318 100644 --- a/core/src/fxcodec/codec/fx_codec_flate.cpp +++ b/core/src/fxcodec/codec/fx_codec_flate.cpp @@ -25,11 +25,11 @@ static int FPDFAPI_FlateGetTotalOut(void* context) { static int FPDFAPI_FlateGetTotalIn(void* context) { return ((z_stream*)context)->total_in; } -static bool FPDFAPI_FlateCompress(unsigned char* dest_buf, +static void FPDFAPI_FlateCompress(unsigned char* dest_buf, unsigned long* dest_size, const unsigned char* src_buf, unsigned long src_size) { - return compress(dest_buf, dest_size, src_buf, src_size) == Z_OK; + compress(dest_buf, dest_size, src_buf, src_size); } void* FPDFAPI_FlateInit(void* (*alloc_func)(void*, unsigned int, unsigned int), void (*free_func)(void*, void*)) { @@ -225,7 +225,7 @@ int CLZWDecoder::Decode(uint8_t* dest_buf, return 0; } -uint8_t PathPredictor(int a, int b, int c) { +uint8_t PaethPredictor(int a, int b, int c) { int p = a + b - c; int pa = FXSYS_abs(p - a); int pb = FXSYS_abs(p - b); @@ -239,8 +239,16 @@ uint8_t PathPredictor(int a, int b, int c) { return (uint8_t)c; } -void PNG_PredictorEncode(uint8_t*& data_buf, FX_DWORD& data_size) { - const int row_size = 7; +FX_BOOL PNG_PredictorEncode(uint8_t*& data_buf, + FX_DWORD& data_size, + int predictor, + int Colors, + int BitsPerComponent, + int Columns) { + const int BytesPerPixel = (Colors * BitsPerComponent + 7) / 8; + const int row_size = (Colors * BitsPerComponent * Columns + 7) / 8; + if (row_size <= 0) + return FALSE; const int row_count = (data_size + row_size - 1) / row_size; const int last_row_size = data_size % row_size; uint8_t* dest_buf = FX_Alloc2D(uint8_t, row_size + 1, row_count); @@ -248,12 +256,67 @@ void PNG_PredictorEncode(uint8_t*& data_buf, FX_DWORD& data_size) { uint8_t* pSrcData = data_buf; uint8_t* pDestData = dest_buf; for (int row = 0; row < row_count; row++) { + if (predictor == 10) { + pDestData[0] = 0; + int move_size = row_size; + if (move_size * (row + 1) > (int)data_size) { + move_size = data_size - (move_size * row); + } + FXSYS_memmove(pDestData + 1, pSrcData, move_size); + pDestData += (move_size + 1); + pSrcData += move_size; + byte_cnt += move_size; + continue; + } for (int byte = 0; byte < row_size && byte_cnt < (int)data_size; byte++) { + switch (predictor) { + case 11: { + pDestData[0] = 1; + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pSrcData[byte - BytesPerPixel]; + } + pDestData[byte + 1] = pSrcData[byte] - left; + } break; + case 12: { pDestData[0] = 2; uint8_t up = 0; - if (row) + if (row) { up = pSrcData[byte - row_size]; + } pDestData[byte + 1] = pSrcData[byte] - up; + } break; + case 13: { + pDestData[0] = 3; + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pSrcData[byte - BytesPerPixel]; + } + uint8_t up = 0; + if (row) { + up = pSrcData[byte - row_size]; + } + pDestData[byte + 1] = pSrcData[byte] - (left + up) / 2; + } break; + case 14: { + pDestData[0] = 4; + uint8_t left = 0; + if (byte >= BytesPerPixel) { + left = pSrcData[byte - BytesPerPixel]; + } + uint8_t up = 0; + if (row) { + up = pSrcData[byte - row_size]; + } + uint8_t upper_left = 0; + if (byte >= BytesPerPixel && row) { + upper_left = pSrcData[byte - row_size - BytesPerPixel]; + } + pDestData[byte + 1] = + pSrcData[byte] - PaethPredictor(left, up, upper_left); + } break; + default: { pDestData[byte + 1] = pSrcData[byte]; } break; + } byte_cnt++; } pDestData += (row_size + 1); @@ -263,6 +326,7 @@ void PNG_PredictorEncode(uint8_t*& data_buf, FX_DWORD& data_size) { data_buf = dest_buf; data_size = (row_size + 1) * row_count - (last_row_size > 0 ? (row_size - last_row_size) : 0); + return TRUE; } void PNG_PredictLine(uint8_t* pDestData, @@ -322,7 +386,7 @@ void PNG_PredictLine(uint8_t* pDestData, if (byte >= BytesPerPixel && pLastLine) { upper_left = pLastLine[byte - BytesPerPixel]; } - pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left); + pDestData[byte] = raw_byte + PaethPredictor(left, up, upper_left); break; } default: @@ -407,7 +471,7 @@ FX_BOOL PNG_Predictor(uint8_t*& data_buf, if (byte >= BytesPerPixel && row) { upper_left = pDestData[byte - row_size - BytesPerPixel]; } - pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left); + pDestData[byte] = raw_byte + PaethPredictor(left, up, upper_left); break; } default: @@ -426,6 +490,73 @@ FX_BOOL PNG_Predictor(uint8_t*& data_buf, return TRUE; } +void TIFF_PredictorEncodeLine(uint8_t* dest_buf, + int row_size, + int BitsPerComponent, + int Colors, + int Columns) { + int BytesPerPixel = BitsPerComponent * Colors / 8; + if (BitsPerComponent < 8) { + uint8_t mask = 0x01; + if (BitsPerComponent == 2) { + mask = 0x03; + } else if (BitsPerComponent == 4) { + mask = 0x0F; + } + int row_bits = Colors * BitsPerComponent * Columns; + for (int i = row_bits - BitsPerComponent; i >= BitsPerComponent; + i -= BitsPerComponent) { + int col = i % 8; + int index = i / 8; + int col_pre = + (col == 0) ? (8 - BitsPerComponent) : (col - BitsPerComponent); + int index_pre = (col == 0) ? (index - 1) : index; + uint8_t cur = (dest_buf[index] >> (8 - col - BitsPerComponent)) & mask; + uint8_t left = + (dest_buf[index_pre] >> (8 - col_pre - BitsPerComponent)) & mask; + cur -= left; + cur &= mask; + cur <<= (8 - col - BitsPerComponent); + dest_buf[index] &= ~(mask << ((8 - col - BitsPerComponent))); + dest_buf[index] |= cur; + } + } else if (BitsPerComponent == 8) { + for (int i = row_size - 1; i >= BytesPerPixel; i--) { + dest_buf[i] -= dest_buf[i - BytesPerPixel]; + } + } else { + for (int i = row_size - BytesPerPixel; i >= BytesPerPixel; + i -= BytesPerPixel) { + FX_WORD pixel = (dest_buf[i] << 8) | dest_buf[i + 1]; + pixel -= + (dest_buf[i - BytesPerPixel] << 8) | dest_buf[i - BytesPerPixel + 1]; + dest_buf[i] = pixel >> 8; + dest_buf[i + 1] = (uint8_t)pixel; + } + } +} + +FX_BOOL TIFF_PredictorEncode(uint8_t*& data_buf, + FX_DWORD& data_size, + int Colors, + int BitsPerComponent, + int Columns) { + int row_size = (Colors * BitsPerComponent * Columns + 7) / 8; + if (row_size == 0) + return FALSE; + const int row_count = (data_size + row_size - 1) / row_size; + const int last_row_size = data_size % row_size; + for (int row = 0; row < row_count; row++) { + uint8_t* scan_line = data_buf + row * row_size; + if ((row + 1) * row_size > (int)data_size) { + row_size = last_row_size; + } + TIFF_PredictorEncodeLine(scan_line, row_size, BitsPerComponent, Colors, + Columns); + } + return TRUE; +} + void TIFF_PredictLine(uint8_t* dest_buf, FX_DWORD row_size, int BitsPerComponent, @@ -832,29 +963,41 @@ FX_DWORD CCodec_FlateModule::FlateOrLZWDecode(FX_BOOL bLZW, } return ret ? offset : -1; } - -bool CCodec_FlateModule::Encode(const uint8_t* src_buf, - FX_DWORD src_size, - uint8_t** dest_buf, - FX_DWORD* dest_size) { - *dest_size = src_size + src_size / 1000 + 12; - *dest_buf = FX_Alloc(uint8_t, *dest_size); - unsigned long temp_size = *dest_size; - if (!FPDFAPI_FlateCompress(*dest_buf, &temp_size, src_buf, src_size)) - return false; - - *dest_size = (FX_DWORD)temp_size; - return true; -} - -bool CCodec_FlateModule::PngEncode(const uint8_t* src_buf, +FX_BOOL CCodec_FlateModule::Encode(const uint8_t* src_buf, FX_DWORD src_size, - uint8_t** dest_buf, - FX_DWORD* dest_size) { - uint8_t* pSrcBuf = FX_Alloc(uint8_t, src_size); + int predictor, + int Colors, + int BitsPerComponent, + int Columns, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { + if (predictor != 2 && predictor < 10) { + return Encode(src_buf, src_size, dest_buf, dest_size); + } + uint8_t* pSrcBuf = NULL; + pSrcBuf = FX_Alloc(uint8_t, src_size); FXSYS_memcpy(pSrcBuf, src_buf, src_size); - PNG_PredictorEncode(pSrcBuf, src_size); - FX_BOOL ret = Encode(pSrcBuf, src_size, dest_buf, dest_size); + FX_BOOL ret = TRUE; + if (predictor == 2) { + ret = TIFF_PredictorEncode(pSrcBuf, src_size, Colors, BitsPerComponent, + Columns); + } else if (predictor >= 10) { + ret = PNG_PredictorEncode(pSrcBuf, src_size, predictor, Colors, + BitsPerComponent, Columns); + } + if (ret) + ret = Encode(pSrcBuf, src_size, dest_buf, dest_size); FX_Free(pSrcBuf); return ret; } +FX_BOOL CCodec_FlateModule::Encode(const uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { + dest_size = src_size + src_size / 1000 + 12; + dest_buf = FX_Alloc(uint8_t, dest_size); + unsigned long temp_size = dest_size; + FPDFAPI_FlateCompress(dest_buf, &temp_size, src_buf, src_size); + dest_size = (FX_DWORD)temp_size; + return TRUE; +} diff --git a/core/src/fxcodec/codec/fx_codec_jpeg.cpp b/core/src/fxcodec/codec/fx_codec_jpeg.cpp index 820a5c7004..043964f254 100644 --- a/core/src/fxcodec/codec/fx_codec_jpeg.cpp +++ b/core/src/fxcodec/codec/fx_codec_jpeg.cpp @@ -74,17 +74,171 @@ static void _error_do_nothing1(j_common_ptr cinfo, int) {} extern "C" { static void _error_do_nothing2(j_common_ptr cinfo, char*) {} }; - +#define JPEG_MARKER_EXIF (JPEG_APP0 + 1) #define JPEG_MARKER_ICC (JPEG_APP0 + 2) +#define JPEG_MARKER_AUTHORTIME (JPEG_APP0 + 3) #define JPEG_MARKER_MAXSIZE 0xFFFF +#define JPEG_OVERHEAD_LEN 14 +static FX_BOOL _JpegEmbedIccProfile(j_compress_ptr cinfo, + const uint8_t* icc_buf_ptr, + FX_DWORD icc_length) { + if (!icc_buf_ptr || icc_length == 0) { + return FALSE; + } + FX_DWORD icc_segment_size = (JPEG_MARKER_MAXSIZE - 2 - JPEG_OVERHEAD_LEN); + FX_DWORD icc_segment_num = (icc_length / icc_segment_size) + 1; + if (icc_segment_num > 255) { + return FALSE; + } + FX_DWORD icc_data_length = + JPEG_OVERHEAD_LEN + (icc_segment_num > 1 ? icc_segment_size : icc_length); + uint8_t* icc_data = FX_Alloc(uint8_t, icc_data_length); + FXSYS_memcpy(icc_data, "\x49\x43\x43\x5f\x50\x52\x4f\x46\x49\x4c\x45\x00", + 12); + icc_data[13] = (uint8_t)icc_segment_num; + for (uint8_t i = 0; i < (icc_segment_num - 1); i++) { + icc_data[12] = i + 1; + FXSYS_memcpy(icc_data + JPEG_OVERHEAD_LEN, + icc_buf_ptr + i * icc_segment_size, icc_segment_size); + jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, icc_data_length); + } + icc_data[12] = (uint8_t)icc_segment_num; + FX_DWORD icc_size = (icc_segment_num - 1) * icc_segment_size; + FXSYS_memcpy(icc_data + JPEG_OVERHEAD_LEN, icc_buf_ptr + icc_size, + icc_length - icc_size); + jpeg_write_marker(cinfo, JPEG_MARKER_ICC, icc_data, + JPEG_OVERHEAD_LEN + icc_length - icc_size); + FX_Free(icc_data); + return TRUE; +} +extern "C" { +static void _dest_do_nothing(j_compress_ptr cinfo) {} +}; +extern "C" { +static boolean _dest_empty(j_compress_ptr cinfo) { + return FALSE; +} +}; +#define JPEG_BLOCK_SIZE 1048576 +static void _JpegEncode(const CFX_DIBSource* pSource, + uint8_t*& dest_buf, + FX_STRSIZE& dest_size, + int quality, + const uint8_t* icc_buf, + FX_DWORD icc_length) { + 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; -static bool JpegLoadInfo(const uint8_t* src_buf, - FX_DWORD src_size, - int* width, - int* height, - int* num_components, - int* bits_per_components, - bool* color_transform) { + struct jpeg_compress_struct cinfo; + memset(&cinfo, 0, sizeof(cinfo)); + cinfo.err = &jerr; + jpeg_create_compress(&cinfo); + int Bpp = pSource->GetBPP() / 8; + FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1; + FX_DWORD pitch = pSource->GetPitch(); + FX_DWORD width = pdfium::base::checked_cast<FX_DWORD>(pSource->GetWidth()); + FX_DWORD height = pdfium::base::checked_cast<FX_DWORD>(pSource->GetHeight()); + FX_SAFE_DWORD safe_buf_len = width; + safe_buf_len *= height; + safe_buf_len *= nComponents; + safe_buf_len += 1024; + if (icc_length) { + safe_buf_len += 255 * 18; + safe_buf_len += icc_length; + } + FX_DWORD dest_buf_length = 0; + if (!safe_buf_len.IsValid()) { + dest_buf = nullptr; + } else { + 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) { + FX_OutOfMemoryTerminate(); + } + 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 = NULL; + if (nComponents > 1) { + line_buf = FX_Alloc2D(uint8_t, width, nComponents); + } + jpeg_set_defaults(&cinfo); + if (quality != 75) { + jpeg_set_quality(&cinfo, quality, TRUE); + } + jpeg_start_compress(&cinfo, TRUE); + _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length); + 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 (FX_DWORD 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 (FX_DWORD 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; +} +static FX_BOOL _JpegLoadInfo(const uint8_t* src_buf, + FX_DWORD src_size, + int& width, + int& height, + int& num_components, + int& bits_per_components, + FX_BOOL& color_transform, + uint8_t** icc_buf_ptr, + FX_DWORD* icc_length) { _JpegScanSOI(src_buf, src_size); struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; @@ -98,7 +252,7 @@ static bool JpegLoadInfo(const uint8_t* src_buf, jmp_buf mark; cinfo.client_data = &mark; if (setjmp(mark) == -1) { - return false; + return FALSE; } jpeg_create_decompress(&cinfo); struct jpeg_source_mgr src; @@ -112,21 +266,30 @@ static bool JpegLoadInfo(const uint8_t* src_buf, cinfo.src = &src; if (setjmp(mark) == -1) { jpeg_destroy_decompress(&cinfo); - return false; + return FALSE; + } + if (icc_buf_ptr && icc_length) { + jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE); } int ret = jpeg_read_header(&cinfo, TRUE); if (ret != JPEG_HEADER_OK) { jpeg_destroy_decompress(&cinfo); - return false; + return FALSE; } - *width = cinfo.image_width; - *height = cinfo.image_height; - *num_components = cinfo.num_components; - *color_transform = + width = cinfo.image_width; + height = cinfo.image_height; + num_components = cinfo.num_components; + color_transform = cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK; - *bits_per_components = cinfo.data_precision; + bits_per_components = cinfo.data_precision; + if (icc_buf_ptr) { + *icc_buf_ptr = NULL; + } + if (icc_length) { + *icc_length = 0; + } jpeg_destroy_decompress(&cinfo); - return true; + return TRUE; } class CCodec_JpegDecoder : public CCodec_ScanlineDecoder { @@ -349,17 +512,31 @@ ICodec_ScanlineDecoder* CCodec_JpegModule::CreateDecoder( } return pDecoder; } -bool CCodec_JpegModule::LoadInfo(const uint8_t* src_buf, - FX_DWORD src_size, - int* width, - int* height, - int* num_components, - int* bits_per_components, - bool* color_transform) { - return JpegLoadInfo(src_buf, src_size, width, height, num_components, - bits_per_components, color_transform); +FX_BOOL CCodec_JpegModule::LoadInfo(const uint8_t* src_buf, + FX_DWORD src_size, + int& width, + int& height, + int& num_components, + int& bits_per_components, + FX_BOOL& color_transform, + uint8_t** icc_buf_ptr, + FX_DWORD* icc_length) { + return _JpegLoadInfo(src_buf, src_size, width, height, num_components, + bits_per_components, color_transform, icc_buf_ptr, + icc_length); } +FX_BOOL CCodec_JpegModule::Encode(const CFX_DIBSource* pSource, + uint8_t*& dest_buf, + FX_STRSIZE& dest_size, + int quality, + const uint8_t* icc_buf, + FX_DWORD icc_length) { + if (pSource->GetBPP() < 8 || pSource->GetPalette()) + return FALSE; + _JpegEncode(pSource, dest_buf, dest_size, quality, icc_buf, icc_length); + return TRUE; +} struct FXJPEG_Context { jmp_buf m_JumpMark; jpeg_decompress_struct m_Info; diff --git a/core/src/fxge/ge/fx_ge_ps.cpp b/core/src/fxge/ge/fx_ge_ps.cpp new file mode 100644 index 0000000000..f9fd8dea30 --- /dev/null +++ b/core/src/fxge/ge/fx_ge_ps.cpp @@ -0,0 +1,699 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_ge.h" +#include "core/include/fxcodec/fx_codec.h" +#include "text_int.h" + +struct PSGlyph { + CFX_Font* m_pFont; + FX_DWORD m_GlyphIndex; + FX_BOOL m_bGlyphAdjust; + FX_FLOAT m_AdjustMatrix[4]; +}; +class CPSFont { + public: + PSGlyph m_Glyphs[256]; + int m_nGlyphs; +}; +CFX_PSRenderer::CFX_PSRenderer() { + m_pOutput = NULL; + m_bColorSet = m_bGraphStateSet = FALSE; + m_bInited = FALSE; +} +CFX_PSRenderer::~CFX_PSRenderer() { + for (int i = 0; i < (int)m_PSFontList.GetSize(); i++) { + CPSFont* pFont = m_PSFontList[i]; + delete pFont; + } +} +#define OUTPUT_PS(str) m_pOutput->OutputPS(str, sizeof str - 1) +void CFX_PSRenderer::Init(IFX_PSOutput* pOutput, + int pslevel, + int width, + int height, + FX_BOOL bCmykOutput) { + m_PSLevel = pslevel; + m_pOutput = pOutput; + m_ClipBox.left = m_ClipBox.top = 0; + m_ClipBox.right = width; + m_ClipBox.bottom = height; + m_bCmykOutput = bCmykOutput; +} +FX_BOOL CFX_PSRenderer::StartRendering() { + if (m_bInited) { + return TRUE; + } + static const char init_str[] = + "\nsave\n/im/initmatrix load def\n" + "/n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load " + "def/h/closepath load def\n" + "/f/fill load def/F/eofill load def/s/stroke load def/W/clip load " + "def/W*/eoclip load def\n" + "/rg/setrgbcolor load def/k/setcmykcolor load def\n" + "/J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load " + "def/M/setmiterlimit load def/d/setdash load def\n" + "/q/gsave load def/Q/grestore load def/iM/imagemask load def\n" + "/Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont " + "load def\n" + "/cm/concat load def/Cm/currentmatrix load def/mx/matrix load " + "def/sm/setmatrix load def\n"; + OUTPUT_PS(init_str); + m_bInited = TRUE; + return TRUE; +} +void CFX_PSRenderer::EndRendering() { + if (m_bInited) { + OUTPUT_PS("\nrestore\n"); + } + m_bInited = FALSE; +} +void CFX_PSRenderer::SaveState() { + StartRendering(); + OUTPUT_PS("q\n"); + m_ClipBoxStack.Add(m_ClipBox); +} +void CFX_PSRenderer::RestoreState(FX_BOOL bKeepSaved) { + StartRendering(); + if (bKeepSaved) { + OUTPUT_PS("Q\nq\n"); + } else { + OUTPUT_PS("Q\n"); + } + m_bColorSet = m_bGraphStateSet = FALSE; + m_ClipBox = m_ClipBoxStack.GetAt(m_ClipBoxStack.GetSize() - 1); + if (!bKeepSaved) { + m_ClipBoxStack.RemoveAt(m_ClipBoxStack.GetSize() - 1); + } +} +void CFX_PSRenderer::OutputPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device) { + int nPoints = pPathData->GetPointCount(); + CFX_ByteTextBuf buf; + buf.EstimateSize(nPoints * 10); + for (int i = 0; i < nPoints; i++) { + uint8_t flag = pPathData->GetFlag(i); + FX_FLOAT x = pPathData->GetPointX(i); + FX_FLOAT y = pPathData->GetPointY(i); + if (pObject2Device) { + pObject2Device->Transform(x, y); + } + buf << x << " " << y; + switch (flag & FXPT_TYPE) { + case FXPT_MOVETO: + buf << " m "; + break; + case FXPT_LINETO: + if (flag & FXPT_CLOSEFIGURE) { + buf << " l h "; + } else { + buf << " l "; + } + break; + case FXPT_BEZIERTO: { + FX_FLOAT x1 = pPathData->GetPointX(i + 1); + FX_FLOAT x2 = pPathData->GetPointX(i + 2); + FX_FLOAT y1 = pPathData->GetPointY(i + 1); + FX_FLOAT y2 = pPathData->GetPointY(i + 2); + if (pObject2Device) { + pObject2Device->Transform(x1, y1); + pObject2Device->Transform(x2, y2); + } + buf << " " << x1 << " " << y1 << " " << x2 << " " << y2; + if (flag & FXPT_CLOSEFIGURE) { + buf << " c h\n"; + } else { + buf << " c\n"; + } + i += 2; + break; + } + } + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); +} +void CFX_PSRenderer::SetClip_PathFill(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + int fill_mode) { + StartRendering(); + OutputPath(pPathData, pObject2Device); + CFX_FloatRect rect = pPathData->GetBoundingBox(); + if (pObject2Device) { + rect.Transform(pObject2Device); + } + m_ClipBox.Intersect(rect.GetOutterRect()); + if ((fill_mode & 3) == FXFILL_WINDING) { + OUTPUT_PS("W n\n"); + } else { + OUTPUT_PS("W* n\n"); + } +} +void CFX_PSRenderer::SetClip_PathStroke(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState) { + StartRendering(); + SetGraphState(pGraphState); + if (pObject2Device) { + CFX_ByteTextBuf buf; + buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm "; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } + OutputPath(pPathData, NULL); + CFX_FloatRect rect = pPathData->GetBoundingBox(pGraphState->m_LineWidth, + pGraphState->m_MiterLimit); + rect.Transform(pObject2Device); + m_ClipBox.Intersect(rect.GetOutterRect()); + if (pObject2Device) { + OUTPUT_PS("strokepath W n sm\n"); + } else { + OUTPUT_PS("strokepath W n\n"); + } +} +FX_BOOL CFX_PSRenderer::DrawPath(const CFX_PathData* pPathData, + const CFX_Matrix* pObject2Device, + const CFX_GraphStateData* pGraphState, + FX_DWORD fill_color, + FX_DWORD stroke_color, + int fill_mode, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + int fill_alpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXARGB_A(fill_color); + int stroke_alpha = FXGETFLAG_COLORTYPE(alpha_flag) + ? FXGETFLAG_ALPHA_STROKE(alpha_flag) + : FXARGB_A(stroke_color); + if (fill_alpha && fill_alpha < 255) { + return FALSE; + } + if (stroke_alpha && stroke_alpha < 255) { + return FALSE; + } + if (fill_alpha == 0 && stroke_alpha == 0) { + return FALSE; + } + if (stroke_alpha) { + SetGraphState(pGraphState); + if (pObject2Device) { + CFX_ByteTextBuf buf; + buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm "; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } + } + OutputPath(pPathData, stroke_alpha ? NULL : pObject2Device); + if (fill_mode && fill_alpha) { + SetColor(fill_color, alpha_flag, pIccTransform); + if ((fill_mode & 3) == FXFILL_WINDING) { + if (stroke_alpha) { + OUTPUT_PS("q f Q "); + } else { + OUTPUT_PS("f"); + } + } else if ((fill_mode & 3) == FXFILL_ALTERNATE) { + if (stroke_alpha) { + OUTPUT_PS("q F Q "); + } else { + OUTPUT_PS("F"); + } + } + } + if (stroke_alpha) { + SetColor(stroke_color, alpha_flag, pIccTransform); + if (pObject2Device) { + OUTPUT_PS("s sm"); + } else { + OUTPUT_PS("s"); + } + } + OUTPUT_PS("\n"); + return TRUE; +} +void CFX_PSRenderer::SetGraphState(const CFX_GraphStateData* pGraphState) { + CFX_ByteTextBuf buf; + if (!m_bGraphStateSet || + m_CurGraphState.m_LineCap != pGraphState->m_LineCap) { + buf << pGraphState->m_LineCap << " J\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_DashCount != pGraphState->m_DashCount || + FXSYS_memcmp(m_CurGraphState.m_DashArray, pGraphState->m_DashArray, + sizeof(FX_FLOAT) * m_CurGraphState.m_DashCount)) { + buf << "["; + for (int i = 0; i < pGraphState->m_DashCount; i++) { + buf << pGraphState->m_DashArray[i] << " "; + } + buf << "]" << pGraphState->m_DashPhase << " d\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_LineJoin != pGraphState->m_LineJoin) { + buf << pGraphState->m_LineJoin << " j\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_LineWidth != pGraphState->m_LineWidth) { + buf << pGraphState->m_LineWidth << " w\n"; + } + if (!m_bGraphStateSet || + m_CurGraphState.m_MiterLimit != pGraphState->m_MiterLimit) { + buf << pGraphState->m_MiterLimit << " M\n"; + } + m_CurGraphState.Copy(*pGraphState); + m_bGraphStateSet = TRUE; + if (buf.GetSize()) { + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } +} +static void FaxCompressData(uint8_t* src_buf, + int width, + int height, + uint8_t*& dest_buf, + FX_DWORD& dest_size) { + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (width * height > 128 && pEncoders && + pEncoders->GetFaxModule()->Encode(src_buf, width, height, (width + 7) / 8, + dest_buf, dest_size)) { + FX_Free(src_buf); + } else { + dest_buf = src_buf; + dest_size = (width + 7) / 8 * height; + } +} +static void PSCompressData(int PSLevel, + uint8_t* src_buf, + FX_DWORD src_size, + uint8_t*& output_buf, + FX_DWORD& output_size, + const FX_CHAR*& filter) { + output_buf = src_buf; + output_size = src_size; + filter = ""; + if (src_size < 1024) { + return; + } + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + uint8_t* dest_buf = NULL; + FX_DWORD dest_size = src_size; + if (PSLevel >= 3) { + if (pEncoders && + pEncoders->GetFlateModule()->Encode(src_buf, src_size, dest_buf, + dest_size)) { + filter = "/FlateDecode filter "; + } + } else { + if (pEncoders && + pEncoders->GetBasicModule()->RunLengthEncode(src_buf, src_size, + dest_buf, dest_size)) { + filter = "/RunLengthDecode filter "; + } + } + if (dest_size < src_size) { + output_buf = dest_buf; + output_size = dest_size; + } else { + filter = NULL; + FX_Free(dest_buf); + } +} +FX_BOOL CFX_PSRenderer::SetDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + int left, + int top, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + CFX_Matrix matrix((FX_FLOAT)(pSource->GetWidth()), 0.0f, 0.0f, + -(FX_FLOAT)(pSource->GetHeight()), (FX_FLOAT)(left), + (FX_FLOAT)(top + pSource->GetHeight())); + return DrawDIBits(pSource, color, &matrix, 0, alpha_flag, pIccTransform); +} +FX_BOOL CFX_PSRenderer::StretchDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + int dest_left, + int dest_top, + int dest_width, + int dest_height, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + CFX_Matrix matrix((FX_FLOAT)(dest_width), 0.0f, 0.0f, + (FX_FLOAT)(-dest_height), (FX_FLOAT)(dest_left), + (FX_FLOAT)(dest_top + dest_height)); + return DrawDIBits(pSource, color, &matrix, flags, alpha_flag, pIccTransform); +} +FX_BOOL CFX_PSRenderer::DrawDIBits(const CFX_DIBSource* pSource, + FX_DWORD color, + const CFX_Matrix* pMatrix, + FX_DWORD flags, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + if ((pMatrix->a == 0 && pMatrix->b == 0) || + (pMatrix->c == 0 && pMatrix->d == 0)) { + return TRUE; + } + if (pSource->HasAlpha()) { + return FALSE; + } + int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(color) + : FXARGB_A(color); + if (pSource->IsAlphaMask() && (alpha < 255 || pSource->GetBPP() != 1)) { + return FALSE; + } + OUTPUT_PS("q\n"); + CFX_ByteTextBuf buf; + buf << "[" << pMatrix->a << " " << pMatrix->b << " " << pMatrix->c << " " + << pMatrix->d << " " << pMatrix->e << " " << pMatrix->f << "]cm "; + int width = pSource->GetWidth(); + int height = pSource->GetHeight(); + buf << width << " " << height; + if (pSource->GetBPP() == 1 && !pSource->GetPalette()) { + int pitch = (width + 7) / 8; + FX_DWORD src_size = height * pitch; + uint8_t* src_buf = FX_Alloc(uint8_t, src_size); + for (int row = 0; row < height; row++) { + const uint8_t* src_scan = pSource->GetScanline(row); + FXSYS_memcpy(src_buf + row * pitch, src_scan, pitch); + } + uint8_t* output_buf; + FX_DWORD output_size; + FaxCompressData(src_buf, width, height, output_buf, output_size); + if (pSource->IsAlphaMask()) { + SetColor(color, alpha_flag, pIccTransform); + m_bColorSet = FALSE; + buf << " true["; + } else { + buf << " 1["; + } + buf << width << " 0 0 -" << height << " 0 " << height + << "]currentfile/ASCII85Decode filter "; + if (output_buf != src_buf) + buf << "<</K -1/EndOfBlock false/Columns " << width << "/Rows " << height + << ">>/CCITTFaxDecode filter "; + if (pSource->IsAlphaMask()) { + buf << "iM\n"; + } else { + buf << "false 1 colorimage\n"; + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + WritePSBinary(output_buf, output_size); + FX_Free(output_buf); + } else { + CFX_DIBSource* pConverted = (CFX_DIBSource*)pSource; + if (pIccTransform) { + FXDIB_Format format = m_bCmykOutput ? FXDIB_Cmyk : FXDIB_Rgb; + pConverted = pSource->CloneConvert(format, NULL, pIccTransform); + } else { + switch (pSource->GetFormat()) { + case FXDIB_1bppRgb: + case FXDIB_Rgb32: + pConverted = pSource->CloneConvert(FXDIB_Rgb); + break; + case FXDIB_8bppRgb: + if (pSource->GetPalette()) { + pConverted = pSource->CloneConvert(FXDIB_Rgb); + } + break; + case FXDIB_1bppCmyk: + pConverted = pSource->CloneConvert(FXDIB_Cmyk); + break; + case FXDIB_8bppCmyk: + if (pSource->GetPalette()) { + pConverted = pSource->CloneConvert(FXDIB_Cmyk); + } + break; + default: + break; + } + } + if (!pConverted) { + OUTPUT_PS("\nQ\n"); + return FALSE; + } + int Bpp = pConverted->GetBPP() / 8; + uint8_t* output_buf = NULL; + FX_STRSIZE output_size = 0; + const FX_CHAR* filter = NULL; + if (flags & FXRENDER_IMAGE_LOSSY) { + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (pEncoders && + pEncoders->GetJpegModule()->Encode(pConverted, output_buf, + output_size)) { + filter = "/DCTDecode filter "; + } + } + if (!filter) { + int src_pitch = width * Bpp; + output_size = height * src_pitch; + output_buf = FX_Alloc(uint8_t, output_size); + for (int row = 0; row < height; row++) { + const uint8_t* src_scan = pConverted->GetScanline(row); + uint8_t* dest_scan = output_buf + row * src_pitch; + if (Bpp == 3) { + for (int col = 0; col < width; col++) { + *dest_scan++ = src_scan[2]; + *dest_scan++ = src_scan[1]; + *dest_scan++ = *src_scan; + src_scan += 3; + } + } else { + FXSYS_memcpy(dest_scan, src_scan, src_pitch); + } + } + uint8_t* compressed_buf; + FX_DWORD compressed_size; + PSCompressData(m_PSLevel, output_buf, output_size, compressed_buf, + compressed_size, filter); + if (output_buf != compressed_buf) { + FX_Free(output_buf); + } + output_buf = compressed_buf; + output_size = compressed_size; + } + if (pConverted != pSource) { + delete pConverted; + pConverted = NULL; + } + buf << " 8["; + buf << width << " 0 0 -" << height << " 0 " << height << "]"; + buf << "currentfile/ASCII85Decode filter "; + if (filter) { + buf << filter; + } + buf << "false " << Bpp; + buf << " colorimage\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + WritePSBinary(output_buf, output_size); + FX_Free(output_buf); + } + OUTPUT_PS("\nQ\n"); + return TRUE; +} +void CFX_PSRenderer::SetColor(FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + if (!CFX_GEModule::Get()->GetCodecModule() || + !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = NULL; + } + FX_BOOL bCMYK = FALSE; + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + color = FXGETFLAG_COLORTYPE(alpha_flag) ? FXCMYK_TODIB(color) + : FXARGB_TODIB(color); + uint8_t* pColor = (uint8_t*)&color; + pIccModule->TranslateScanline(pIccTransform, pColor, pColor, 1); + color = m_bCmykOutput ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + bCMYK = m_bCmykOutput; + } else { + bCMYK = FXGETFLAG_COLORTYPE(alpha_flag); + } + if (bCMYK != m_bCmykOutput || !m_bColorSet || m_LastColor != color) { + CFX_ByteTextBuf buf; + if (bCMYK) { + buf << FXSYS_GetCValue(color) / 255.0 << " " + << FXSYS_GetMValue(color) / 255.0 << " " + << FXSYS_GetYValue(color) / 255.0 << " " + << FXSYS_GetKValue(color) / 255.0 << " k\n"; + } else { + buf << FXARGB_R(color) / 255.0 << " " << FXARGB_G(color) / 255.0 << " " + << FXARGB_B(color) / 255.0 << " rg\n"; + } + if (bCMYK == m_bCmykOutput) { + m_bColorSet = TRUE; + m_LastColor = color; + } + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + } +} +void CFX_PSRenderer::FindPSFontGlyph(CFX_FaceCache* pFaceCache, + CFX_Font* pFont, + const FXTEXT_CHARPOS& charpos, + int& ps_fontnum, + int& ps_glyphindex) { + for (int i = 0; i < (int)m_PSFontList.GetSize(); i++) { + CPSFont* pPSFont = m_PSFontList[i]; + for (int j = 0; j < pPSFont->m_nGlyphs; j++) + if (pPSFont->m_Glyphs[j].m_pFont == pFont && + pPSFont->m_Glyphs[j].m_GlyphIndex == charpos.m_GlyphIndex) { + if ((!pPSFont->m_Glyphs[j].m_bGlyphAdjust && !charpos.m_bGlyphAdjust) || + (pPSFont->m_Glyphs[j].m_bGlyphAdjust && charpos.m_bGlyphAdjust && + (FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[0] - + charpos.m_AdjustMatrix[0]) < 0.01 && + FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[1] - + charpos.m_AdjustMatrix[1]) < 0.01 && + FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[2] - + charpos.m_AdjustMatrix[2]) < 0.01 && + FXSYS_fabs(pPSFont->m_Glyphs[j].m_AdjustMatrix[3] - + charpos.m_AdjustMatrix[3]) < 0.01))) { + ps_fontnum = i; + ps_glyphindex = j; + return; + } + } + } + if (m_PSFontList.GetSize() == 0 || + m_PSFontList[m_PSFontList.GetSize() - 1]->m_nGlyphs == 256) { + CPSFont* pPSFont = new CPSFont; + pPSFont->m_nGlyphs = 0; + m_PSFontList.Add(pPSFont); + CFX_ByteTextBuf buf; + buf << "8 dict begin/FontType 3 def/FontMatrix[1 0 0 1 0 0]def\n" + "/FontBBox[0 0 0 0]def/Encoding 256 array def 0 1 255{Encoding " + "exch/.notdef put}for\n" + "/CharProcs 1 dict def CharProcs begin/.notdef {} def end\n" + "/BuildGlyph{1 0 -10 -10 10 10 setcachedevice exch/CharProcs get " + "exch 2 copy known not{pop/.notdef}if get exec}bind def\n" + "/BuildChar{1 index/Encoding get exch get 1 index/BuildGlyph get " + "exec}bind def\n" + "currentdict end\n"; + buf << "/X" << m_PSFontList.GetSize() - 1 << " exch definefont pop\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + buf.Clear(); + } + ps_fontnum = m_PSFontList.GetSize() - 1; + CPSFont* pPSFont = m_PSFontList[ps_fontnum]; + ps_glyphindex = pPSFont->m_nGlyphs; + pPSFont->m_Glyphs[ps_glyphindex].m_GlyphIndex = charpos.m_GlyphIndex; + pPSFont->m_Glyphs[ps_glyphindex].m_pFont = pFont; + pPSFont->m_Glyphs[ps_glyphindex].m_bGlyphAdjust = charpos.m_bGlyphAdjust; + if (charpos.m_bGlyphAdjust) { + pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[0] = + charpos.m_AdjustMatrix[0]; + pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[1] = + charpos.m_AdjustMatrix[1]; + pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[2] = + charpos.m_AdjustMatrix[2]; + pPSFont->m_Glyphs[ps_glyphindex].m_AdjustMatrix[3] = + charpos.m_AdjustMatrix[3]; + } + pPSFont->m_nGlyphs++; + CFX_Matrix matrix; + if (charpos.m_bGlyphAdjust) + matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], + charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0); + matrix.Concat(1.0f, 0, 0, 1.0f, 0, 0); + const CFX_PathData* pPathData = pFaceCache->LoadGlyphPath( + pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth); + if (!pPathData) { + return; + } + CFX_PathData TransformedPath(*pPathData); + if (charpos.m_bGlyphAdjust) { + TransformedPath.Transform(&matrix); + } + CFX_ByteTextBuf buf; + buf << "/X" << ps_fontnum << " Ff/CharProcs get begin/" << ps_glyphindex + << "{n "; + for (int p = 0; p < TransformedPath.GetPointCount(); p++) { + FX_FLOAT x = TransformedPath.GetPointX(p), y = TransformedPath.GetPointY(p); + switch (TransformedPath.GetFlag(p) & FXPT_TYPE) { + case FXPT_MOVETO: { + buf << x << " " << y << " m\n"; + break; + } + case FXPT_LINETO: { + buf << x << " " << y << " l\n"; + break; + } + case FXPT_BEZIERTO: { + buf << x << " " << y << " " << TransformedPath.GetPointX(p + 1) << " " + << TransformedPath.GetPointY(p + 1) << " " + << TransformedPath.GetPointX(p + 2) << " " + << TransformedPath.GetPointY(p + 2) << " c\n"; + p += 2; + break; + } + } + } + buf << "f}bind def end\n"; + buf << "/X" << ps_fontnum << " Ff/Encoding get " << ps_glyphindex << "/" + << ps_glyphindex << " put\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); +} +FX_BOOL CFX_PSRenderer::DrawText(int nChars, + const FXTEXT_CHARPOS* pCharPos, + CFX_Font* pFont, + CFX_FontCache* pCache, + const CFX_Matrix* pObject2Device, + FX_FLOAT font_size, + FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + StartRendering(); + int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) + : FXARGB_A(color); + if (alpha < 255) { + return FALSE; + } + if ((pObject2Device->a == 0 && pObject2Device->b == 0) || + (pObject2Device->c == 0 && pObject2Device->d == 0)) { + return TRUE; + } + SetColor(color, alpha_flag, pIccTransform); + CFX_ByteTextBuf buf; + buf << "q[" << pObject2Device->a << " " << pObject2Device->b << " " + << pObject2Device->c << " " << pObject2Device->d << " " + << pObject2Device->e << " " << pObject2Device->f << "]cm\n"; + if (!pCache) { + pCache = CFX_GEModule::Get()->GetFontCache(); + } + CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont); + FX_FONTCACHE_DEFINE(pCache, pFont); + int last_fontnum = -1; + for (int i = 0; i < nChars; i++) { + int ps_fontnum, ps_glyphindex; + FindPSFontGlyph(pFaceCache, pFont, pCharPos[i], ps_fontnum, ps_glyphindex); + if (last_fontnum != ps_fontnum) { + buf << "/X" << ps_fontnum << " Ff " << font_size << " Fs Sf "; + last_fontnum = ps_fontnum; + } + buf << pCharPos[i].m_OriginX << " " << pCharPos[i].m_OriginY << " m"; + CFX_ByteString hex; + hex.Format("<%02X>", ps_glyphindex); + buf << hex << "Tj\n"; + } + buf << "Q\n"; + m_pOutput->OutputPS((const FX_CHAR*)buf.GetBuffer(), buf.GetSize()); + return TRUE; +} +void CFX_PSRenderer::WritePSBinary(const uint8_t* data, int len) { + uint8_t* dest_buf; + FX_DWORD dest_size; + CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule(); + if (pEncoders && + pEncoders->GetBasicModule()->A85Encode(data, len, dest_buf, dest_size)) { + m_pOutput->OutputPS((const FX_CHAR*)dest_buf, dest_size); + FX_Free(dest_buf); + } else { + m_pOutput->OutputPS((const FX_CHAR*)data, len); + } +} |