OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "core/fpdfapi/fpdf_page/cpdf_image.h" | |
8 | |
9 #include <algorithm> | |
10 #include <memory> | |
11 #include <vector> | |
12 | |
13 #include "core/fpdfapi/cpdf_modulemgr.h" | |
14 #include "core/fpdfapi/fpdf_page/cpdf_page.h" | |
15 #include "core/fpdfapi/fpdf_page/pageint.h" | |
16 #include "core/fpdfapi/fpdf_parser/cpdf_array.h" | |
17 #include "core/fpdfapi/fpdf_parser/cpdf_boolean.h" | |
18 #include "core/fpdfapi/fpdf_parser/cpdf_document.h" | |
19 #include "core/fpdfapi/fpdf_parser/cpdf_string.h" | |
20 #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" | |
21 #include "core/fpdfapi/fpdf_render/render_int.h" | |
22 #include "core/fxcodec/fx_codec.h" | |
23 #include "core/fxge/fx_dib.h" | |
24 | |
25 CPDF_Image::CPDF_Image(CPDF_Document* pDoc) | |
26 : CPDF_Image(pDoc, nullptr, false) {} | |
27 | |
28 CPDF_Image::CPDF_Image(CPDF_Document* pDoc, CPDF_Stream* pStream, bool bInline) | |
29 : m_pDIBSource(nullptr), | |
30 m_pMask(nullptr), | |
31 m_MatteColor(0), | |
32 m_pStream(pStream), | |
33 m_bInline(bInline), | |
34 m_pInlineDict(nullptr), | |
35 m_Height(0), | |
36 m_Width(0), | |
37 m_bIsMask(false), | |
38 m_bInterpolate(false), | |
39 m_pDocument(pDoc), | |
40 m_pOC(nullptr) { | |
41 if (!pStream) | |
42 return; | |
43 | |
44 CPDF_Dictionary* pDict = pStream->GetDict(); | |
45 if (m_bInline) | |
46 m_pInlineDict = ToDictionary(pDict->Clone()); | |
47 | |
48 m_pOC = pDict->GetDictFor("OC"); | |
49 m_bIsMask = | |
50 !pDict->KeyExist("ColorSpace") || pDict->GetIntegerFor("ImageMask"); | |
51 m_bInterpolate = !!pDict->GetIntegerFor("Interpolate"); | |
52 m_Height = pDict->GetIntegerFor("Height"); | |
53 m_Width = pDict->GetIntegerFor("Width"); | |
54 } | |
55 | |
56 CPDF_Image::~CPDF_Image() { | |
57 if (m_bInline) { | |
58 if (m_pStream) | |
59 m_pStream->Release(); | |
60 if (m_pInlineDict) | |
61 m_pInlineDict->Release(); | |
62 } | |
63 } | |
64 | |
65 CPDF_Image* CPDF_Image::Clone() { | |
66 if (m_pStream->GetObjNum()) | |
67 return m_pDocument->GetPageData()->GetImage(m_pStream); | |
68 | |
69 CPDF_Image* pImage = | |
70 new CPDF_Image(m_pDocument, ToStream(m_pStream->Clone()), m_bInline); | |
71 if (m_bInline) | |
72 pImage->SetInlineDict(ToDictionary(m_pInlineDict->CloneDirectObject())); | |
73 | |
74 return pImage; | |
75 } | |
76 | |
77 CPDF_Dictionary* CPDF_Image::InitJPEG(uint8_t* pData, uint32_t size) { | |
78 int32_t width; | |
79 int32_t height; | |
80 int32_t num_comps; | |
81 int32_t bits; | |
82 bool color_trans; | |
83 if (!CPDF_ModuleMgr::Get()->GetJpegModule()->LoadInfo( | |
84 pData, size, &width, &height, &num_comps, &bits, &color_trans)) { | |
85 return nullptr; | |
86 } | |
87 | |
88 CPDF_Dictionary* pDict = | |
89 new CPDF_Dictionary(m_pDocument->GetByteStringPool()); | |
90 pDict->SetNameFor("Type", "XObject"); | |
91 pDict->SetNameFor("Subtype", "Image"); | |
92 pDict->SetIntegerFor("Width", width); | |
93 pDict->SetIntegerFor("Height", height); | |
94 const FX_CHAR* csname = nullptr; | |
95 if (num_comps == 1) { | |
96 csname = "DeviceGray"; | |
97 } else if (num_comps == 3) { | |
98 csname = "DeviceRGB"; | |
99 } else if (num_comps == 4) { | |
100 csname = "DeviceCMYK"; | |
101 CPDF_Array* pDecode = new CPDF_Array; | |
102 for (int n = 0; n < 4; n++) { | |
103 pDecode->AddInteger(1); | |
104 pDecode->AddInteger(0); | |
105 } | |
106 pDict->SetFor("Decode", pDecode); | |
107 } | |
108 pDict->SetNameFor("ColorSpace", csname); | |
109 pDict->SetIntegerFor("BitsPerComponent", bits); | |
110 pDict->SetNameFor("Filter", "DCTDecode"); | |
111 if (!color_trans) { | |
112 CPDF_Dictionary* pParms = | |
113 new CPDF_Dictionary(m_pDocument->GetByteStringPool()); | |
114 pDict->SetFor("DecodeParms", pParms); | |
115 pParms->SetIntegerFor("ColorTransform", 0); | |
116 } | |
117 m_bIsMask = FALSE; | |
118 m_Width = width; | |
119 m_Height = height; | |
120 if (!m_pStream) | |
121 m_pStream = new CPDF_Stream; | |
122 return pDict; | |
123 } | |
124 | |
125 void CPDF_Image::SetJpegImage(IFX_FileRead* pFile) { | |
126 uint32_t size = (uint32_t)pFile->GetSize(); | |
127 if (!size) | |
128 return; | |
129 | |
130 uint32_t dwEstimateSize = std::min(size, 8192U); | |
131 std::vector<uint8_t> data(dwEstimateSize); | |
132 pFile->ReadBlock(data.data(), 0, dwEstimateSize); | |
133 CPDF_Dictionary* pDict = InitJPEG(data.data(), dwEstimateSize); | |
134 if (!pDict && size > dwEstimateSize) { | |
135 data.resize(size); | |
136 pFile->ReadBlock(data.data(), 0, size); | |
137 pDict = InitJPEG(data.data(), size); | |
138 } | |
139 if (!pDict) | |
140 return; | |
141 | |
142 m_pStream->InitStreamFromFile(pFile, pDict); | |
143 } | |
144 | |
145 void CPDF_Image::SetImage(const CFX_DIBitmap* pBitmap, int32_t iCompress) { | |
146 int32_t BitmapWidth = pBitmap->GetWidth(); | |
147 int32_t BitmapHeight = pBitmap->GetHeight(); | |
148 if (BitmapWidth < 1 || BitmapHeight < 1) { | |
149 return; | |
150 } | |
151 uint8_t* src_buf = pBitmap->GetBuffer(); | |
152 int32_t src_pitch = pBitmap->GetPitch(); | |
153 int32_t bpp = pBitmap->GetBPP(); | |
154 | |
155 CPDF_Dictionary* pDict = | |
156 new CPDF_Dictionary(m_pDocument->GetByteStringPool()); | |
157 pDict->SetNameFor("Type", "XObject"); | |
158 pDict->SetNameFor("Subtype", "Image"); | |
159 pDict->SetIntegerFor("Width", BitmapWidth); | |
160 pDict->SetIntegerFor("Height", BitmapHeight); | |
161 uint8_t* dest_buf = nullptr; | |
162 FX_STRSIZE dest_pitch = 0, dest_size = 0, opType = -1; | |
163 if (bpp == 1) { | |
164 int32_t reset_a = 0, reset_r = 0, reset_g = 0, reset_b = 0; | |
165 int32_t set_a = 0, set_r = 0, set_g = 0, set_b = 0; | |
166 if (!pBitmap->IsAlphaMask()) { | |
167 ArgbDecode(pBitmap->GetPaletteArgb(0), reset_a, reset_r, reset_g, | |
168 reset_b); | |
169 ArgbDecode(pBitmap->GetPaletteArgb(1), set_a, set_r, set_g, set_b); | |
170 } | |
171 if (set_a == 0 || reset_a == 0) { | |
172 pDict->SetFor("ImageMask", new CPDF_Boolean(TRUE)); | |
173 if (reset_a == 0) { | |
174 CPDF_Array* pArray = new CPDF_Array; | |
175 pArray->AddInteger(1); | |
176 pArray->AddInteger(0); | |
177 pDict->SetFor("Decode", pArray); | |
178 } | |
179 } else { | |
180 CPDF_Array* pCS = new CPDF_Array; | |
181 pCS->AddName("Indexed"); | |
182 pCS->AddName("DeviceRGB"); | |
183 pCS->AddInteger(1); | |
184 CFX_ByteString ct; | |
185 FX_CHAR* pBuf = ct.GetBuffer(6); | |
186 pBuf[0] = (FX_CHAR)reset_r; | |
187 pBuf[1] = (FX_CHAR)reset_g; | |
188 pBuf[2] = (FX_CHAR)reset_b; | |
189 pBuf[3] = (FX_CHAR)set_r; | |
190 pBuf[4] = (FX_CHAR)set_g; | |
191 pBuf[5] = (FX_CHAR)set_b; | |
192 ct.ReleaseBuffer(6); | |
193 pCS->Add(new CPDF_String(ct, TRUE)); | |
194 pDict->SetFor("ColorSpace", pCS); | |
195 } | |
196 pDict->SetIntegerFor("BitsPerComponent", 1); | |
197 dest_pitch = (BitmapWidth + 7) / 8; | |
198 if ((iCompress & 0x03) == PDF_IMAGE_NO_COMPRESS) { | |
199 opType = 1; | |
200 } else { | |
201 opType = 0; | |
202 } | |
203 } else if (bpp == 8) { | |
204 int32_t iPalette = pBitmap->GetPaletteSize(); | |
205 if (iPalette > 0) { | |
206 CPDF_Array* pCS = new CPDF_Array; | |
207 pCS->AddName("Indexed"); | |
208 pCS->AddName("DeviceRGB"); | |
209 pCS->AddInteger(iPalette - 1); | |
210 uint8_t* pColorTable = FX_Alloc2D(uint8_t, iPalette, 3); | |
211 uint8_t* ptr = pColorTable; | |
212 for (int32_t i = 0; i < iPalette; i++) { | |
213 uint32_t argb = pBitmap->GetPaletteArgb(i); | |
214 ptr[0] = (uint8_t)(argb >> 16); | |
215 ptr[1] = (uint8_t)(argb >> 8); | |
216 ptr[2] = (uint8_t)argb; | |
217 ptr += 3; | |
218 } | |
219 CPDF_Stream* pCTS = new CPDF_Stream( | |
220 pColorTable, iPalette * 3, | |
221 new CPDF_Dictionary(m_pDocument->GetByteStringPool())); | |
222 pCS->AddReference(m_pDocument, m_pDocument->AddIndirectObject(pCTS)); | |
223 pDict->SetReferenceFor("ColorSpace", m_pDocument, | |
224 m_pDocument->AddIndirectObject(pCS)); | |
225 } else { | |
226 pDict->SetNameFor("ColorSpace", "DeviceGray"); | |
227 } | |
228 pDict->SetIntegerFor("BitsPerComponent", 8); | |
229 if ((iCompress & 0x03) == PDF_IMAGE_NO_COMPRESS) { | |
230 dest_pitch = BitmapWidth; | |
231 opType = 1; | |
232 } else { | |
233 opType = 0; | |
234 } | |
235 } else { | |
236 pDict->SetNameFor("ColorSpace", "DeviceRGB"); | |
237 pDict->SetIntegerFor("BitsPerComponent", 8); | |
238 if ((iCompress & 0x03) == PDF_IMAGE_NO_COMPRESS) { | |
239 dest_pitch = BitmapWidth * 3; | |
240 opType = 2; | |
241 } else { | |
242 opType = 0; | |
243 } | |
244 } | |
245 const CFX_DIBitmap* pMaskBitmap = nullptr; | |
246 FX_BOOL bDeleteMask = FALSE; | |
247 if (pBitmap->HasAlpha()) { | |
248 pMaskBitmap = pBitmap->GetAlphaMask(); | |
249 bDeleteMask = TRUE; | |
250 } | |
251 if (pMaskBitmap) { | |
252 int32_t maskWidth = pMaskBitmap->GetWidth(); | |
253 int32_t maskHeight = pMaskBitmap->GetHeight(); | |
254 uint8_t* mask_buf = nullptr; | |
255 FX_STRSIZE mask_size = 0; | |
256 CPDF_Dictionary* pMaskDict = | |
257 new CPDF_Dictionary(m_pDocument->GetByteStringPool()); | |
258 pMaskDict->SetNameFor("Type", "XObject"); | |
259 pMaskDict->SetNameFor("Subtype", "Image"); | |
260 pMaskDict->SetIntegerFor("Width", maskWidth); | |
261 pMaskDict->SetIntegerFor("Height", maskHeight); | |
262 pMaskDict->SetNameFor("ColorSpace", "DeviceGray"); | |
263 pMaskDict->SetIntegerFor("BitsPerComponent", 8); | |
264 if (pMaskBitmap->GetBPP() == 8 && | |
265 (iCompress & PDF_IMAGE_MASK_LOSSY_COMPRESS) != 0) { | |
266 } else if (pMaskBitmap->GetFormat() == FXDIB_1bppMask) { | |
267 } else { | |
268 mask_buf = FX_Alloc2D(uint8_t, maskHeight, maskWidth); | |
269 mask_size = maskHeight * maskWidth; // Safe since checked alloc returned. | |
270 for (int32_t a = 0; a < maskHeight; a++) { | |
271 FXSYS_memcpy(mask_buf + a * maskWidth, pMaskBitmap->GetScanline(a), | |
272 maskWidth); | |
273 } | |
274 } | |
275 pMaskDict->SetIntegerFor("Length", mask_size); | |
276 pDict->SetReferenceFor("SMask", m_pDocument, | |
277 m_pDocument->AddIndirectObject(new CPDF_Stream( | |
278 mask_buf, mask_size, pMaskDict))); | |
279 if (bDeleteMask) | |
280 delete pMaskBitmap; | |
281 } | |
282 if (opType == 0) { | |
283 if (iCompress & PDF_IMAGE_LOSSLESS_COMPRESS) { | |
284 } else { | |
285 if (pBitmap->GetBPP() == 1) { | |
286 } else if (pBitmap->GetBPP() >= 8 && pBitmap->GetPalette()) { | |
287 CFX_DIBitmap* pNewBitmap = new CFX_DIBitmap(); | |
288 pNewBitmap->Copy(pBitmap); | |
289 pNewBitmap->ConvertFormat(FXDIB_Rgb); | |
290 SetImage(pNewBitmap, iCompress); | |
291 if (pDict) { | |
292 pDict->Release(); | |
293 pDict = nullptr; | |
294 } | |
295 FX_Free(dest_buf); | |
296 dest_buf = nullptr; | |
297 dest_size = 0; | |
298 delete pNewBitmap; | |
299 return; | |
300 } | |
301 } | |
302 } else if (opType == 1) { | |
303 dest_buf = FX_Alloc2D(uint8_t, dest_pitch, BitmapHeight); | |
304 dest_size = dest_pitch * BitmapHeight; // Safe as checked alloc returned. | |
305 | |
306 uint8_t* pDest = dest_buf; | |
307 for (int32_t i = 0; i < BitmapHeight; i++) { | |
308 FXSYS_memcpy(pDest, src_buf, dest_pitch); | |
309 pDest += dest_pitch; | |
310 src_buf += src_pitch; | |
311 } | |
312 } else if (opType == 2) { | |
313 dest_buf = FX_Alloc2D(uint8_t, dest_pitch, BitmapHeight); | |
314 dest_size = dest_pitch * BitmapHeight; // Safe as checked alloc returned. | |
315 | |
316 uint8_t* pDest = dest_buf; | |
317 int32_t src_offset = 0; | |
318 int32_t dest_offset = 0; | |
319 for (int32_t row = 0; row < BitmapHeight; row++) { | |
320 src_offset = row * src_pitch; | |
321 for (int32_t column = 0; column < BitmapWidth; column++) { | |
322 FX_FLOAT alpha = 1; | |
323 pDest[dest_offset] = (uint8_t)(src_buf[src_offset + 2] * alpha); | |
324 pDest[dest_offset + 1] = (uint8_t)(src_buf[src_offset + 1] * alpha); | |
325 pDest[dest_offset + 2] = (uint8_t)(src_buf[src_offset] * alpha); | |
326 dest_offset += 3; | |
327 src_offset += bpp == 24 ? 3 : 4; | |
328 } | |
329 | |
330 pDest += dest_pitch; | |
331 dest_offset = 0; | |
332 } | |
333 } | |
334 if (!m_pStream) | |
335 m_pStream = new CPDF_Stream; | |
336 | |
337 m_pStream->InitStream(dest_buf, dest_size, pDict); | |
338 m_bIsMask = pBitmap->IsAlphaMask(); | |
339 m_Width = BitmapWidth; | |
340 m_Height = BitmapHeight; | |
341 FX_Free(dest_buf); | |
342 } | |
343 | |
344 void CPDF_Image::ResetCache(CPDF_Page* pPage, const CFX_DIBitmap* pBitmap) { | |
345 pPage->GetRenderCache()->ResetBitmap(m_pStream, pBitmap); | |
346 } | |
347 | |
348 CFX_DIBSource* CPDF_Image::LoadDIBSource(CFX_DIBSource** ppMask, | |
349 uint32_t* pMatteColor, | |
350 FX_BOOL bStdCS, | |
351 uint32_t GroupFamily, | |
352 FX_BOOL bLoadMask) const { | |
353 std::unique_ptr<CPDF_DIBSource> source(new CPDF_DIBSource); | |
354 if (source->Load(m_pDocument, m_pStream, | |
355 reinterpret_cast<CPDF_DIBSource**>(ppMask), pMatteColor, | |
356 nullptr, nullptr, bStdCS, GroupFamily, bLoadMask)) { | |
357 return source.release(); | |
358 } | |
359 return nullptr; | |
360 } | |
361 | |
362 CFX_DIBSource* CPDF_Image::DetachBitmap() { | |
363 CFX_DIBSource* pBitmap = m_pDIBSource; | |
364 m_pDIBSource = nullptr; | |
365 return pBitmap; | |
366 } | |
367 | |
368 CFX_DIBSource* CPDF_Image::DetachMask() { | |
369 CFX_DIBSource* pBitmap = m_pMask; | |
370 m_pMask = nullptr; | |
371 return pBitmap; | |
372 } | |
373 | |
374 FX_BOOL CPDF_Image::StartLoadDIBSource(CPDF_Dictionary* pFormResource, | |
375 CPDF_Dictionary* pPageResource, | |
376 FX_BOOL bStdCS, | |
377 uint32_t GroupFamily, | |
378 FX_BOOL bLoadMask) { | |
379 std::unique_ptr<CPDF_DIBSource> source(new CPDF_DIBSource); | |
380 int ret = | |
381 source->StartLoadDIBSource(m_pDocument, m_pStream, TRUE, pFormResource, | |
382 pPageResource, bStdCS, GroupFamily, bLoadMask); | |
383 if (ret == 2) { | |
384 m_pDIBSource = source.release(); | |
385 return TRUE; | |
386 } | |
387 if (!ret) { | |
388 m_pDIBSource = nullptr; | |
389 return FALSE; | |
390 } | |
391 m_pMask = source->DetachMask(); | |
392 m_MatteColor = source->GetMatteColor(); | |
393 m_pDIBSource = source.release(); | |
394 return FALSE; | |
395 } | |
396 | |
397 FX_BOOL CPDF_Image::Continue(IFX_Pause* pPause) { | |
398 CPDF_DIBSource* pSource = static_cast<CPDF_DIBSource*>(m_pDIBSource); | |
399 int ret = pSource->ContinueLoadDIBSource(pPause); | |
400 if (ret == 2) { | |
401 return TRUE; | |
402 } | |
403 if (!ret) { | |
404 delete m_pDIBSource; | |
405 m_pDIBSource = nullptr; | |
406 return FALSE; | |
407 } | |
408 m_pMask = pSource->DetachMask(); | |
409 m_MatteColor = pSource->GetMatteColor(); | |
410 return FALSE; | |
411 } | |
OLD | NEW |