Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_image.cpp
Go to the documentation of this file.
1// Copyright 2016 The PDFium Authors
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/page/cpdf_image.h"
8
9#include <stdint.h>
10
11#include <algorithm>
12#include <array>
13#include <memory>
14#include <utility>
15
16#include "constants/stream_dict_common.h"
17#include "core/fpdfapi/page/cpdf_dib.h"
18#include "core/fpdfapi/page/cpdf_page.h"
19#include "core/fpdfapi/page/cpdf_pageimagecache.h"
20#include "core/fpdfapi/parser/cpdf_array.h"
21#include "core/fpdfapi/parser/cpdf_boolean.h"
22#include "core/fpdfapi/parser/cpdf_dictionary.h"
23#include "core/fpdfapi/parser/cpdf_document.h"
24#include "core/fpdfapi/parser/cpdf_name.h"
25#include "core/fpdfapi/parser/cpdf_number.h"
26#include "core/fpdfapi/parser/cpdf_reference.h"
27#include "core/fpdfapi/parser/cpdf_stream.h"
28#include "core/fpdfapi/parser/cpdf_string.h"
29#include "core/fxcodec/jpeg/jpegmodule.h"
30#include "core/fxcrt/check.h"
31#include "core/fxcrt/compiler_specific.h"
32#include "core/fxcrt/data_vector.h"
33#include "core/fxcrt/fx_2d_size.h"
34#include "core/fxcrt/fx_stream.h"
35#include "core/fxcrt/numerics/safe_conversions.h"
36#include "core/fxcrt/span_util.h"
37#include "core/fxcrt/stl_util.h"
38#include "core/fxge/dib/cfx_dibitmap.h"
39#include "core/fxge/dib/fx_dib.h"
40
41// static
42bool CPDF_Image::IsValidJpegComponent(int32_t comps) {
43 return comps == 1 || comps == 3 || comps == 4;
44}
45
46// static
47bool CPDF_Image::IsValidJpegBitsPerComponent(int32_t bpc) {
48 return bpc == 1 || bpc == 2 || bpc == 4 || bpc == 8 || bpc == 16;
49}
50
51CPDF_Image::CPDF_Image(CPDF_Document* pDoc) : m_pDocument(pDoc) {
52 DCHECK(m_pDocument);
53}
54
55CPDF_Image::CPDF_Image(CPDF_Document* pDoc, RetainPtr<CPDF_Stream> pStream)
56 : m_bIsInline(true), m_pDocument(pDoc), m_pStream(std::move(pStream)) {
57 DCHECK(m_pDocument);
58 FinishInitialization();
59}
60
61CPDF_Image::CPDF_Image(CPDF_Document* pDoc, uint32_t dwStreamObjNum)
62 : m_pDocument(pDoc),
63 m_pStream(ToStream(pDoc->GetMutableIndirectObject(dwStreamObjNum))) {
64 DCHECK(m_pDocument);
65 FinishInitialization();
66}
67
68CPDF_Image::~CPDF_Image() = default;
69
70void CPDF_Image::FinishInitialization() {
71 RetainPtr<const CPDF_Dictionary> pStreamDict = m_pStream->GetDict();
72 m_pOC = pStreamDict->GetDictFor("OC");
73 m_bIsMask = !pStreamDict->KeyExist("ColorSpace") ||
74 pStreamDict->GetBooleanFor("ImageMask", /*bDefault=*/false);
75 m_bInterpolate = !!pStreamDict->GetIntegerFor("Interpolate");
76 m_Height = pStreamDict->GetIntegerFor("Height");
77 m_Width = pStreamDict->GetIntegerFor("Width");
78}
79
81 CHECK(m_pStream->IsInline());
82 m_pDocument->AddIndirectObject(m_pStream);
83}
84
85RetainPtr<const CPDF_Dictionary> CPDF_Image::GetDict() const {
86 return m_pStream ? m_pStream->GetDict() : nullptr;
87}
88
89RetainPtr<const CPDF_Stream> CPDF_Image::GetStream() const {
90 return m_pStream;
91}
92
93RetainPtr<const CPDF_Dictionary> CPDF_Image::GetOC() const {
94 return m_pOC;
95}
96
97RetainPtr<CPDF_Dictionary> CPDF_Image::InitJPEG(
98 pdfium::span<uint8_t> src_span) {
99 std::optional<JpegModule::ImageInfo> info_opt =
100 JpegModule::LoadInfo(src_span);
101 if (!info_opt.has_value())
102 return nullptr;
103
104 const JpegModule::ImageInfo& info = info_opt.value();
107 return nullptr;
108 }
109
111 CreateXObjectImageDict(info.width, info.height);
112 const char* csname = nullptr;
113 if (info.num_components == 1) {
114 csname = "DeviceGray";
115 } else if (info.num_components == 3) {
116 csname = "DeviceRGB";
117 } else if (info.num_components == 4) {
118 csname = "DeviceCMYK";
119 auto pDecode = pDict->SetNewFor<CPDF_Array>("Decode");
120 for (int n = 0; n < 4; n++) {
121 pDecode->AppendNew<CPDF_Number>(1);
122 pDecode->AppendNew<CPDF_Number>(0);
123 }
124 }
125 pDict->SetNewFor<CPDF_Name>("ColorSpace", csname);
126 pDict->SetNewFor<CPDF_Number>("BitsPerComponent", info.bits_per_components);
127 pDict->SetNewFor<CPDF_Name>("Filter", "DCTDecode");
128 if (!info.color_transform) {
129 auto pParms =
131 pParms->SetNewFor<CPDF_Number>("ColorTransform", 0);
132 }
133 m_bIsMask = false;
134 m_Width = info.width;
135 m_Height = info.height;
136 return pDict;
137}
138
140 uint32_t size = pdfium::checked_cast<uint32_t>(pFile->GetSize());
141 if (!size) {
142 return;
143 }
144
145 uint32_t dwEstimateSize = std::min(size, 8192U);
146 DataVector<uint8_t> data(dwEstimateSize);
147 if (!pFile->ReadBlockAtOffset(data, 0)) {
148 return;
149 }
150
151 RetainPtr<CPDF_Dictionary> dict = InitJPEG(data);
152 if (!dict && size > dwEstimateSize) {
153 data.resize(size);
154 if (pFile->ReadBlockAtOffset(data, 0)) {
155 dict = InitJPEG(data);
156 }
157 }
158 if (!dict) {
159 return;
160 }
161
162 m_pStream =
163 pdfium::MakeRetain<CPDF_Stream>(std::move(pFile), std::move(dict));
164}
165
167 uint32_t size = pdfium::checked_cast<uint32_t>(pFile->GetSize());
168 if (!size) {
169 return;
170 }
171
172 DataVector<uint8_t> data(size);
173 if (!pFile->ReadBlockAtOffset(data, 0)) {
174 return;
175 }
176
177 RetainPtr<CPDF_Dictionary> dict = InitJPEG(data);
178 if (!dict) {
179 return;
180 }
181
182 m_pStream = pdfium::MakeRetain<CPDF_Stream>(std::move(data), std::move(dict));
183}
184
185void CPDF_Image::SetImage(const RetainPtr<CFX_DIBitmap>& pBitmap) {
186 int32_t BitmapWidth = pBitmap->GetWidth();
187 int32_t BitmapHeight = pBitmap->GetHeight();
188 if (BitmapWidth < 1 || BitmapHeight < 1)
189 return;
190
192 CreateXObjectImageDict(BitmapWidth, BitmapHeight);
193 const int32_t bpp = pBitmap->GetBPP();
194 size_t dest_pitch = 0;
195 bool bCopyWithoutAlpha = true;
196 if (bpp == 1) {
197 FX_BGRA_STRUCT<uint8_t> reset_bgra;
198 FX_BGRA_STRUCT<uint8_t> set_bgra;
199 if (!pBitmap->IsMaskFormat()) {
200 reset_bgra = ArgbToBGRAStruct(pBitmap->GetPaletteArgb(0));
201 set_bgra = ArgbToBGRAStruct(pBitmap->GetPaletteArgb(1));
202 }
203 if (set_bgra.alpha == 0 || reset_bgra.alpha == 0) {
204 pDict->SetNewFor<CPDF_Boolean>("ImageMask", true);
205 if (reset_bgra.alpha == 0) {
206 auto pArray = pDict->SetNewFor<CPDF_Array>("Decode");
207 pArray->AppendNew<CPDF_Number>(1);
208 pArray->AppendNew<CPDF_Number>(0);
209 }
210 } else {
211 auto pCS = pDict->SetNewFor<CPDF_Array>("ColorSpace");
212 pCS->AppendNew<CPDF_Name>("Indexed");
213 pCS->AppendNew<CPDF_Name>("DeviceRGB");
214 pCS->AppendNew<CPDF_Number>(1);
215 const uint8_t ct[6] = {reset_bgra.red, reset_bgra.green, reset_bgra.blue,
216 set_bgra.red, set_bgra.green, set_bgra.blue};
217 pCS->AppendNew<CPDF_String>(ct, CPDF_String::DataType::kIsHex);
218 }
219 pDict->SetNewFor<CPDF_Number>("BitsPerComponent", 1);
220 dest_pitch = (BitmapWidth + 7) / 8;
221 } else if (bpp == 8) {
222 size_t palette_size = pBitmap->GetRequiredPaletteSize();
223 if (palette_size > 0) {
224 DCHECK(palette_size <= 256);
225 auto pCS = m_pDocument->NewIndirect<CPDF_Array>();
226 pCS->AppendNew<CPDF_Name>("Indexed");
227 pCS->AppendNew<CPDF_Name>("DeviceRGB");
228 pCS->AppendNew<CPDF_Number>(static_cast<int>(palette_size - 1));
229 DataVector<uint8_t> color_table(Fx2DSizeOrDie(palette_size, 3));
230 auto color_table_span = pdfium::make_span(color_table);
231 for (size_t i = 0; i < palette_size; i++) {
232 uint32_t argb = pBitmap->GetPaletteArgb(i);
233 color_table_span[0] = FXARGB_R(argb);
234 color_table_span[1] = FXARGB_G(argb);
235 color_table_span[2] = FXARGB_B(argb);
236 color_table_span = color_table_span.subspan(3);
237 }
238 auto pNewDict = m_pDocument->New<CPDF_Dictionary>();
239 auto pCTS = m_pDocument->NewIndirect<CPDF_Stream>(std::move(color_table),
240 std::move(pNewDict));
241 pCS->AppendNew<CPDF_Reference>(m_pDocument, pCTS->GetObjNum());
242 pDict->SetNewFor<CPDF_Reference>("ColorSpace", m_pDocument,
243 pCS->GetObjNum());
244 } else {
245 pDict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray");
246 }
247 pDict->SetNewFor<CPDF_Number>("BitsPerComponent", 8);
248 dest_pitch = BitmapWidth;
249 } else {
250 pDict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceRGB");
251 pDict->SetNewFor<CPDF_Number>("BitsPerComponent", 8);
252 dest_pitch = BitmapWidth * 3;
253 bCopyWithoutAlpha = false;
254 }
255
256 RetainPtr<CFX_DIBitmap> pMaskBitmap;
257 if (pBitmap->IsAlphaFormat())
258 pMaskBitmap = pBitmap->CloneAlphaMask();
259
260 if (pMaskBitmap) {
261 const int32_t mask_width = pMaskBitmap->GetWidth();
262 const int32_t mask_height = pMaskBitmap->GetHeight();
263 DataVector<uint8_t> mask_buf;
264 RetainPtr<CPDF_Dictionary> pMaskDict =
265 CreateXObjectImageDict(mask_width, mask_height);
266 pMaskDict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray");
267 pMaskDict->SetNewFor<CPDF_Number>("BitsPerComponent", 8);
268 if (pMaskBitmap->GetFormat() != FXDIB_Format::k1bppMask) {
269 mask_buf.resize(Fx2DSizeOrDie(mask_width, mask_height));
270 for (int32_t a = 0; a < mask_height; a++) {
271 fxcrt::Copy(pMaskBitmap->GetScanline(a).first(mask_width),
272 pdfium::make_span(mask_buf).subspan(a * mask_width));
273 }
274 }
275 pMaskDict->SetNewFor<CPDF_Number>(
276 "Length", pdfium::checked_cast<int>(mask_buf.size()));
277 auto pNewStream = m_pDocument->NewIndirect<CPDF_Stream>(
278 std::move(mask_buf), std::move(pMaskDict));
279 pDict->SetNewFor<CPDF_Reference>("SMask", m_pDocument,
280 pNewStream->GetObjNum());
281 }
282
283 DataVector<uint8_t> dest_buf(Fx2DSizeOrDie(dest_pitch, BitmapHeight));
284 pdfium::span<uint8_t> dest_span = pdfium::make_span(dest_buf);
285 pdfium::span<const uint8_t> src_span = pBitmap->GetBuffer();
286 const int32_t src_pitch = pBitmap->GetPitch();
287 if (bCopyWithoutAlpha) {
288 for (int32_t i = 0; i < BitmapHeight; i++) {
289 dest_span = fxcrt::spancpy(dest_span, src_span.first(dest_pitch));
290 src_span = src_span.subspan(src_pitch);
291 }
292 } else {
293 const size_t src_step = bpp == 24 ? 3 : 4;
294 for (int32_t row = 0; row < BitmapHeight; row++) {
295 uint8_t* dest_ptr = dest_span.data();
296 const uint8_t* src_ptr = src_span.data();
297 for (int32_t column = 0; column < BitmapWidth; column++) {
299 dest_ptr[0] = src_ptr[2];
300 dest_ptr[1] = src_ptr[1];
301 dest_ptr[2] = src_ptr[0];
302 dest_ptr += 3;
303 src_ptr += src_step;
304 });
305 }
306 dest_span = dest_span.subspan(dest_pitch);
307 src_span = src_span.subspan(src_pitch);
308 }
309 }
310
311 m_pStream =
312 pdfium::MakeRetain<CPDF_Stream>(std::move(dest_buf), std::move(pDict));
313 m_bIsMask = pBitmap->IsMaskFormat();
314 m_Width = BitmapWidth;
315 m_Height = BitmapHeight;
316}
317
318void CPDF_Image::ResetCache(CPDF_Page* pPage) {
319 RetainPtr<CPDF_Image> pHolder(this);
321}
322
323void CPDF_Image::WillBeDestroyed() {
324 m_bWillBeDestroyed = true;
325}
326
327RetainPtr<CPDF_DIB> CPDF_Image::CreateNewDIB() const {
328 return pdfium::MakeRetain<CPDF_DIB>(GetDocument(), GetStream());
329}
330
331RetainPtr<CFX_DIBBase> CPDF_Image::LoadDIBBase() const {
332 RetainPtr<CPDF_DIB> source = CreateNewDIB();
333 if (!source->Load())
334 return nullptr;
335
336 if (!source->IsJBigImage())
337 return source;
338
339 CPDF_DIB::LoadState ret = CPDF_DIB::LoadState::kContinue;
340 while (ret == CPDF_DIB::LoadState::kContinue)
341 ret = source->ContinueLoadDIBBase(nullptr);
342 return ret == CPDF_DIB::LoadState::kSuccess ? source : nullptr;
343}
344
346 return std::move(m_pDIBBase);
347}
348
350 return std::move(m_pMask);
351}
352
353bool CPDF_Image::StartLoadDIBBase(const CPDF_Dictionary* pFormResource,
354 const CPDF_Dictionary* pPageResource,
355 bool bStdCS,
356 CPDF_ColorSpace::Family GroupFamily,
357 bool bLoadMask,
358 const CFX_Size& max_size_required) {
359 RetainPtr<CPDF_DIB> source = CreateNewDIB();
360 CPDF_DIB::LoadState ret =
361 source->StartLoadDIBBase(true, pFormResource, pPageResource, bStdCS,
362 GroupFamily, bLoadMask, max_size_required);
363 if (ret == CPDF_DIB::LoadState::kFail) {
364 m_pDIBBase.Reset();
365 return false;
366 }
367 m_pDIBBase = source;
368 if (ret == CPDF_DIB::LoadState::kContinue)
369 return true;
370
371 m_pMask = source->DetachMask();
372 m_MatteColor = source->GetMatteColor();
373 return false;
374}
375
376bool CPDF_Image::Continue(PauseIndicatorIface* pPause) {
377 RetainPtr<CPDF_DIB> pSource = m_pDIBBase.As<CPDF_DIB>();
378 CPDF_DIB::LoadState ret = pSource->ContinueLoadDIBBase(pPause);
379 if (ret == CPDF_DIB::LoadState::kContinue)
380 return true;
381
382 if (ret == CPDF_DIB::LoadState::kSuccess) {
383 m_pMask = pSource->DetachMask();
384 m_MatteColor = pSource->GetMatteColor();
385 } else {
386 m_pDIBBase.Reset();
387 }
388 return false;
389}
390
391RetainPtr<CPDF_Dictionary> CPDF_Image::CreateXObjectImageDict(int width,
392 int height) {
393 auto dict = m_pDocument->New<CPDF_Dictionary>();
394 dict->SetNewFor<CPDF_Name>("Type", "XObject");
395 dict->SetNewFor<CPDF_Name>("Subtype", "Image");
396 dict->SetNewFor<CPDF_Number>("Width", width);
397 dict->SetNewFor<CPDF_Number>("Height", height);
398 return dict;
399}
#define DCHECK
Definition check.h:33
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
Definition cpdf_array.h:29
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
void SetJpegImage(RetainPtr< IFX_SeekableReadStream > pFile)
bool Continue(PauseIndicatorIface *pPause)
RetainPtr< CFX_DIBBase > LoadDIBBase() const
void WillBeDestroyed()
void ResetCache(CPDF_Page *pPage)
RetainPtr< const CPDF_Dictionary > GetOC() const
RetainPtr< const CPDF_Stream > GetStream() const
~CPDF_Image() override
bool StartLoadDIBBase(const CPDF_Dictionary *pFormResource, const CPDF_Dictionary *pPageResource, bool bStdCS, CPDF_ColorSpace::Family GroupFamily, bool bLoadMask, const CFX_Size &max_size_required)
RetainPtr< const CPDF_Dictionary > GetDict() const
void SetJpegImageInline(RetainPtr< IFX_SeekableReadStream > pFile)
RetainPtr< CFX_DIBBase > DetachBitmap()
static bool IsValidJpegBitsPerComponent(int32_t bpc)
void SetImage(const RetainPtr< CFX_DIBitmap > &pBitmap)
RetainPtr< CPDF_DIB > CreateNewDIB() const
static bool IsValidJpegComponent(int32_t comps)
RetainPtr< CFX_DIBBase > DetachMask()
void ConvertStreamToIndirectObject()
void ResetBitmapForImage(RetainPtr< CPDF_Image > pImage)
CPDF_PageImageCache * GetPageImageCache()
Definition cpdf_page.h:83
#define UNSAFE_TODO(...)
CFX_STemplate< int32_t > CFX_Size
#define FXARGB_B(argb)
Definition fx_dib.h:199
#define FXARGB_G(argb)
Definition fx_dib.h:198
#define FXARGB_R(argb)
Definition fx_dib.h:197
FXDIB_Format
Definition fx_dib.h:21
fxcodec::JpegModule JpegModule
Definition jpegmodule.h:64
const char kDecodeParms[]
#define CHECK(cvref)