1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "../../../include/fpdfapi/fpdf_module.h" 8 #include "../../../include/fpdfapi/fpdf_page.h" 9 #include "../../../include/fxcodec/fx_codec.h" 10 #include "../../../include/fpdfapi/fpdf_render.h" 11 #include "../fpdf_page/pageint.h" 12 #include "../fpdf_render/render_int.h" 13 CPDF_Dictionary* CPDF_Image::InitJPEG(FX_LPBYTE pData, FX_DWORD size) 14 { 15 FX_INT32 width, height, color_trans, num_comps, bits; 16 if (!CPDF_ModuleMgr::Get()->GetJpegModule()-> 17 LoadInfo(pData, size, width, height, num_comps, bits, color_trans)) { 18 return NULL; 19 } 20 CPDF_Dictionary* pDict = FX_NEW CPDF_Dictionary; 21 pDict->SetAtName("Type", "XObject"); 22 pDict->SetAtName("Subtype", "Image"); 23 pDict->SetAtInteger("Width", width); 24 pDict->SetAtInteger("Height", height); 25 FX_LPCSTR csname = NULL; 26 if (num_comps == 1) { 27 csname = "DeviceGray"; 28 } else if (num_comps == 3) { 29 csname = "DeviceRGB"; 30 } else if (num_comps == 4) { 31 csname = "DeviceCMYK"; 32 CPDF_Array* pDecode = CPDF_Array::Create(); 33 for (int n = 0; n < 4; n ++) { 34 pDecode->AddInteger(1); 35 pDecode->AddInteger(0); 36 } 37 pDict->SetAt(FX_BSTRC("Decode"), pDecode); 38 } 39 pDict->SetAtName("ColorSpace", csname); 40 pDict->SetAtInteger("BitsPerComponent", bits); 41 pDict->SetAtName("Filter", "DCTDecode"); 42 if (!color_trans) { 43 CPDF_Dictionary* pParms = FX_NEW CPDF_Dictionary; 44 pDict->SetAt("DecodeParms", pParms); 45 pParms->SetAtInteger("ColorTransform", 0); 46 } 47 m_bIsMask = FALSE; 48 m_Width = width; 49 m_Height = height; 50 if (m_pStream == NULL) { 51 m_pStream = FX_NEW CPDF_Stream(NULL, 0, NULL); 52 } 53 return pDict; 54 } 55 void CPDF_Image::SetJpegImage(FX_LPBYTE pData, FX_DWORD size) 56 { 57 CPDF_Dictionary *pDict = InitJPEG(pData, size); 58 if (!pDict) { 59 return; 60 } 61 m_pStream->InitStream(pData, size, pDict); 62 } 63 void CPDF_Image::SetJpegImage(IFX_FileRead *pFile) 64 { 65 FX_DWORD size = (FX_DWORD)pFile->GetSize(); 66 if (!size) { 67 return; 68 } 69 FX_DWORD dwEstimateSize = size; 70 if (dwEstimateSize > 8192) { 71 dwEstimateSize = 8192; 72 } 73 FX_LPBYTE pData = FX_Alloc(FX_BYTE, dwEstimateSize); 74 if (!pData) { 75 return; 76 } 77 pFile->ReadBlock(pData, 0, dwEstimateSize); 78 CPDF_Dictionary *pDict = InitJPEG(pData, dwEstimateSize); 79 FX_Free(pData); 80 if (!pDict && size > dwEstimateSize) { 81 pData = FX_Alloc(FX_BYTE, size); 82 if (!pData) { 83 return; 84 } 85 pFile->ReadBlock(pData, 0, size); 86 pDict = InitJPEG(pData, size); 87 FX_Free(pData); 88 } 89 if (!pDict) { 90 return; 91 } 92 m_pStream->InitStream(pFile, pDict); 93 } 94 void _DCTEncodeBitmap(CPDF_Dictionary *pBitmapDict, const CFX_DIBitmap* pBitmap, int quality, FX_LPBYTE &buf, FX_STRSIZE &size) 95 { 96 } 97 void _JBIG2EncodeBitmap(CPDF_Dictionary *pBitmapDict, const CFX_DIBitmap *pBitmap, CPDF_Document *pDoc, FX_LPBYTE &buf, FX_STRSIZE &size, FX_BOOL bLossLess) 98 { 99 } 100 void CPDF_Image::SetImage(const CFX_DIBitmap* pBitmap, FX_INT32 iCompress, IFX_FileWrite *pFileWrite, IFX_FileRead *pFileRead, const CFX_DIBitmap* pMask, const CPDF_ImageSetParam* pParam) 101 { 102 FX_INT32 BitmapWidth = pBitmap->GetWidth(); 103 FX_INT32 BitmapHeight = pBitmap->GetHeight(); 104 if (BitmapWidth < 1 || BitmapHeight < 1) { 105 return; 106 } 107 FX_LPBYTE src_buf = pBitmap->GetBuffer(); 108 FX_INT32 src_pitch = pBitmap->GetPitch(); 109 FX_INT32 bpp = pBitmap->GetBPP(); 110 FX_BOOL bUseMatte = pParam && pParam->pMatteColor && (pBitmap->GetFormat() == FXDIB_Argb); 111 CPDF_Dictionary* pDict = FX_NEW CPDF_Dictionary; 112 pDict->SetAtName(FX_BSTRC("Type"), FX_BSTRC("XObject")); 113 pDict->SetAtName(FX_BSTRC("Subtype"), FX_BSTRC("Image")); 114 pDict->SetAtInteger(FX_BSTRC("Width"), BitmapWidth); 115 pDict->SetAtInteger(FX_BSTRC("Height"), BitmapHeight); 116 FX_LPBYTE dest_buf = NULL; 117 FX_STRSIZE dest_pitch = 0, dest_size = 0, opType = -1; 118 if (bpp == 1) { 119 FX_INT32 reset_a = 0, reset_r = 0, reset_g = 0, reset_b = 0; 120 FX_INT32 set_a = 0, set_r = 0, set_g = 0, set_b = 0; 121 if (!pBitmap->IsAlphaMask()) { 122 ArgbDecode(pBitmap->GetPaletteArgb(0), reset_a, reset_r, reset_g, reset_b); 123 ArgbDecode(pBitmap->GetPaletteArgb(1), set_a, set_r, set_g, set_b); 124 } 125 if (set_a == 0 || reset_a == 0) { 126 pDict->SetAt(FX_BSTRC("ImageMask"), FX_NEW CPDF_Boolean(TRUE)); 127 if (reset_a == 0) { 128 CPDF_Array* pArray = FX_NEW CPDF_Array; 129 pArray->AddInteger(1); 130 pArray->AddInteger(0); 131 pDict->SetAt(FX_BSTRC("Decode"), pArray); 132 } 133 } else { 134 CPDF_Array* pCS = FX_NEW CPDF_Array; 135 pCS->AddName(FX_BSTRC("Indexed")); 136 pCS->AddName(FX_BSTRC("DeviceRGB")); 137 pCS->AddInteger(1); 138 CFX_ByteString ct; 139 FX_LPSTR pBuf = ct.GetBuffer(6); 140 pBuf[0] = (FX_CHAR)reset_r; 141 pBuf[1] = (FX_CHAR)reset_g; 142 pBuf[2] = (FX_CHAR)reset_b; 143 pBuf[3] = (FX_CHAR)set_r; 144 pBuf[4] = (FX_CHAR)set_g; 145 pBuf[5] = (FX_CHAR)set_b; 146 ct.ReleaseBuffer(6); 147 pCS->Add(CPDF_String::Create(ct, TRUE)); 148 pDict->SetAt(FX_BSTRC("ColorSpace"), pCS); 149 } 150 pDict->SetAtInteger(FX_BSTRC("BitsPerComponent"), 1); 151 dest_pitch = (BitmapWidth + 7) / 8; 152 if ((iCompress & 0x03) == PDF_IMAGE_NO_COMPRESS) { 153 opType = 1; 154 } else { 155 opType = 0; 156 } 157 } else if (bpp == 8) { 158 FX_INT32 iPalette = pBitmap->GetPaletteSize(); 159 if (iPalette > 0) { 160 CPDF_Array* pCS = FX_NEW CPDF_Array; 161 m_pDocument->AddIndirectObject(pCS); 162 pCS->AddName(FX_BSTRC("Indexed")); 163 pCS->AddName(FX_BSTRC("DeviceRGB")); 164 pCS->AddInteger(iPalette - 1); 165 FX_LPBYTE pColorTable = FX_Alloc(FX_BYTE, iPalette * 3); 166 FX_LPBYTE ptr = pColorTable; 167 for (FX_INT32 i = 0; i < iPalette; i ++) { 168 FX_DWORD argb = pBitmap->GetPaletteArgb(i); 169 ptr[0] = (FX_BYTE)(argb >> 16); 170 ptr[1] = (FX_BYTE)(argb >> 8); 171 ptr[2] = (FX_BYTE)argb; 172 ptr += 3; 173 } 174 CPDF_Stream *pCTS = CPDF_Stream::Create(pColorTable, iPalette * 3, CPDF_Dictionary::Create()); 175 m_pDocument->AddIndirectObject(pCTS); 176 pCS->AddReference(m_pDocument, pCTS); 177 pDict->SetAtReference(FX_BSTRC("ColorSpace"), m_pDocument, pCS); 178 } else { 179 pDict->SetAtName(FX_BSTRC("ColorSpace"), FX_BSTRC("DeviceGray")); 180 } 181 pDict->SetAtInteger(FX_BSTRC("BitsPerComponent"), 8); 182 if ((iCompress & 0x03) == PDF_IMAGE_NO_COMPRESS) { 183 dest_pitch = BitmapWidth; 184 opType = 1; 185 } else { 186 opType = 0; 187 } 188 } else { 189 pDict->SetAtName(FX_BSTRC("ColorSpace"), FX_BSTRC("DeviceRGB")); 190 pDict->SetAtInteger(FX_BSTRC("BitsPerComponent"), 8); 191 if ((iCompress & 0x03) == PDF_IMAGE_NO_COMPRESS) { 192 dest_pitch = BitmapWidth * 3; 193 opType = 2; 194 } else { 195 opType = 0; 196 } 197 } 198 const CFX_DIBitmap* pMaskBitmap = NULL; 199 if (pBitmap->HasAlpha()) { 200 pMaskBitmap = pBitmap->GetAlphaMask(); 201 } 202 if (!pMaskBitmap && pMask) { 203 FXDIB_Format maskFormat = pMask->GetFormat(); 204 if (maskFormat == FXDIB_1bppMask || maskFormat == FXDIB_8bppMask) { 205 pMaskBitmap = pMask; 206 } 207 } 208 if (pMaskBitmap) { 209 FX_INT32 maskWidth = pMaskBitmap->GetWidth(); 210 FX_INT32 maskHeight = pMaskBitmap->GetHeight(); 211 FX_LPBYTE mask_buf = NULL; 212 FX_STRSIZE mask_size; 213 FX_BOOL bDeleteMask = TRUE; 214 CPDF_Dictionary* pMaskDict = FX_NEW CPDF_Dictionary; 215 pMaskDict->SetAtName(FX_BSTRC("Type"), FX_BSTRC("XObject")); 216 pMaskDict->SetAtName(FX_BSTRC("Subtype"), FX_BSTRC("Image")); 217 pMaskDict->SetAtInteger(FX_BSTRC("Width"), maskWidth); 218 pMaskDict->SetAtInteger(FX_BSTRC("Height"), maskHeight); 219 pMaskDict->SetAtName(FX_BSTRC("ColorSpace"), FX_BSTRC("DeviceGray")); 220 pMaskDict->SetAtInteger(FX_BSTRC("BitsPerComponent"), 8); 221 if (pMaskBitmap->GetBPP() == 8 && (iCompress & PDF_IMAGE_MASK_LOSSY_COMPRESS) != 0) { 222 _DCTEncodeBitmap(pMaskDict, pMaskBitmap, pParam ? pParam->nQuality : 75, mask_buf, mask_size); 223 } else if (pMaskBitmap->GetFormat() == FXDIB_1bppMask) { 224 _JBIG2EncodeBitmap(pMaskDict, pMaskBitmap, m_pDocument, mask_buf, mask_size, TRUE); 225 } else { 226 mask_size = maskHeight * maskWidth; 227 mask_buf = FX_Alloc(FX_BYTE, mask_size); 228 for (FX_INT32 a = 0; a < maskHeight; a ++) { 229 FXSYS_memcpy32(mask_buf + a * maskWidth, pMaskBitmap->GetScanline(a), maskWidth); 230 } 231 } 232 if (pMaskDict) { 233 pMaskDict->SetAtInteger(FX_BSTRC("Length"), mask_size); 234 CPDF_Stream* pMaskStream = NULL; 235 if (bUseMatte) { 236 int a, r, g, b; 237 ArgbDecode(*(pParam->pMatteColor), a, r, g, b); 238 CPDF_Array* pMatte = FX_NEW CPDF_Array; 239 pMatte->AddInteger(r); 240 pMatte->AddInteger(g); 241 pMatte->AddInteger(b); 242 pMaskDict->SetAt(FX_BSTRC("Matte"), pMatte); 243 } 244 pMaskStream = FX_NEW CPDF_Stream(mask_buf, mask_size, pMaskDict); 245 m_pDocument->AddIndirectObject(pMaskStream); 246 bDeleteMask = FALSE; 247 pDict->SetAtReference(FX_BSTRC("SMask"), m_pDocument, pMaskStream); 248 } 249 if (pBitmap->HasAlpha()) { 250 delete pMaskBitmap; 251 } 252 } 253 FX_BOOL bStream = pFileWrite != NULL && pFileRead != NULL; 254 if (opType == 0) { 255 if (iCompress & PDF_IMAGE_LOSSLESS_COMPRESS) { 256 if (pBitmap->GetBPP() == 1) { 257 _JBIG2EncodeBitmap(pDict, pBitmap, m_pDocument, dest_buf, dest_size, TRUE); 258 } 259 } else { 260 if (pBitmap->GetBPP() == 1) { 261 _JBIG2EncodeBitmap(pDict, pBitmap, m_pDocument, dest_buf, dest_size, FALSE); 262 } else if (pBitmap->GetBPP() >= 8 && pBitmap->GetPalette() != NULL) { 263 CFX_DIBitmap *pNewBitmap = FX_NEW CFX_DIBitmap(); 264 pNewBitmap->Copy(pBitmap); 265 pNewBitmap->ConvertFormat(FXDIB_Rgb); 266 SetImage(pNewBitmap, iCompress, pFileWrite, pFileRead); 267 if (pDict) { 268 pDict->Release(); 269 pDict = NULL; 270 } 271 if (dest_buf) { 272 FX_Free(dest_buf); 273 dest_buf = NULL; 274 } 275 dest_size = 0; 276 delete pNewBitmap; 277 return; 278 } else { 279 if (bUseMatte) { 280 CFX_DIBitmap *pNewBitmap = FX_NEW CFX_DIBitmap(); 281 pNewBitmap->Create(BitmapWidth, BitmapHeight, FXDIB_Argb); 282 FX_LPBYTE dst_buf = pNewBitmap->GetBuffer(); 283 FX_INT32 src_offset = 0; 284 for (FX_INT32 row = 0; row < BitmapHeight; row ++) { 285 src_offset = row * src_pitch; 286 for (FX_INT32 column = 0; column < BitmapWidth; column ++) { 287 FX_FLOAT alpha = src_buf[src_offset + 3] / 255.0f; 288 dst_buf[src_offset] = (FX_BYTE)(src_buf[src_offset] * alpha); 289 dst_buf[src_offset + 1] = (FX_BYTE)(src_buf[src_offset + 1] * alpha); 290 dst_buf[src_offset + 2] = (FX_BYTE)(src_buf[src_offset + 2] * alpha); 291 dst_buf[src_offset + 3] = (FX_BYTE)(src_buf[src_offset + 3]); 292 src_offset += 4; 293 } 294 } 295 _DCTEncodeBitmap(pDict, pNewBitmap, pParam ? pParam->nQuality : 75, dest_buf, dest_size); 296 delete pNewBitmap; 297 } else { 298 _DCTEncodeBitmap(pDict, pBitmap, pParam ? pParam->nQuality : 75, dest_buf, dest_size); 299 } 300 } 301 } 302 if (bStream) { 303 pFileWrite->WriteBlock(dest_buf, dest_size); 304 FX_Free(dest_buf); 305 dest_buf = NULL; 306 } 307 } else if (opType == 1) { 308 if (!bStream) { 309 dest_size = dest_pitch * BitmapHeight; 310 dest_buf = FX_Alloc(FX_BYTE, dest_size); 311 } 312 FX_LPBYTE pDest = dest_buf; 313 for (FX_INT32 i = 0; i < BitmapHeight; i ++) { 314 if (!bStream) { 315 FXSYS_memcpy32(pDest, src_buf, dest_pitch); 316 pDest += dest_pitch; 317 } else { 318 pFileWrite->WriteBlock(src_buf, dest_pitch); 319 } 320 src_buf += src_pitch; 321 } 322 } else if (opType == 2) { 323 if (!bStream) { 324 dest_size = dest_pitch * BitmapHeight; 325 dest_buf = FX_Alloc(FX_BYTE, dest_size); 326 } else { 327 dest_buf = FX_Alloc(FX_BYTE, dest_pitch); 328 } 329 FX_LPBYTE pDest = dest_buf; 330 FX_INT32 src_offset = 0; 331 FX_INT32 dest_offset = 0; 332 for (FX_INT32 row = 0; row < BitmapHeight; row ++) { 333 src_offset = row * src_pitch; 334 for (FX_INT32 column = 0; column < BitmapWidth; column ++) { 335 FX_FLOAT alpha = bUseMatte ? src_buf[src_offset + 3] / 255.0f : 1; 336 pDest[dest_offset] = (FX_BYTE)(src_buf[src_offset + 2] * alpha); 337 pDest[dest_offset + 1] = (FX_BYTE)(src_buf[src_offset + 1] * alpha); 338 pDest[dest_offset + 2] = (FX_BYTE)(src_buf[src_offset] * alpha); 339 dest_offset += 3; 340 src_offset += bpp == 24 ? 3 : 4; 341 } 342 if (bStream) { 343 pFileWrite->WriteBlock(pDest, dest_pitch); 344 pDest = dest_buf; 345 } else { 346 pDest += dest_pitch; 347 } 348 dest_offset = 0; 349 } 350 if (bStream) { 351 FX_Free(dest_buf); 352 dest_buf = NULL; 353 } 354 } 355 if (m_pStream == NULL) { 356 m_pStream = FX_NEW CPDF_Stream(NULL, 0, NULL); 357 } 358 if (!bStream) { 359 m_pStream->InitStream(dest_buf, dest_size, pDict); 360 } else { 361 pFileWrite->Flush(); 362 m_pStream->InitStream(pFileRead, pDict); 363 } 364 m_bIsMask = pBitmap->IsAlphaMask(); 365 m_Width = BitmapWidth; 366 m_Height = BitmapHeight; 367 if (dest_buf) { 368 FX_Free(dest_buf); 369 } 370 } 371 void CPDF_Image::ResetCache(CPDF_Page* pPage, const CFX_DIBitmap* pBitmap) 372 { 373 pPage->GetRenderCache()->ResetBitmap(m_pStream, pBitmap); 374 } 375