1 // Copyright 2017 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_dib.h"
8
9 #include <stdint.h>
10
11 #include <algorithm>
12 #include <memory>
13 #include <utility>
14 #include <vector>
15
16 #include "core/fpdfapi/page/cpdf_colorspace.h"
17 #include "core/fpdfapi/page/cpdf_docpagedata.h"
18 #include "core/fpdfapi/page/cpdf_image.h"
19 #include "core/fpdfapi/page/cpdf_imageobject.h"
20 #include "core/fpdfapi/page/cpdf_indexedcs.h"
21 #include "core/fpdfapi/parser/cpdf_array.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_stream.h"
27 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
28 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
29 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
30 #include "core/fxcodec/basic/basicmodule.h"
31 #include "core/fxcodec/jbig2/jbig2_decoder.h"
32 #include "core/fxcodec/jpeg/jpegmodule.h"
33 #include "core/fxcodec/jpx/cjpx_decoder.h"
34 #include "core/fxcodec/scanlinedecoder.h"
35 #include "core/fxcrt/data_vector.h"
36 #include "core/fxcrt/fx_safe_types.h"
37 #include "core/fxcrt/span_util.h"
38 #include "core/fxge/calculate_pitch.h"
39 #include "core/fxge/dib/cfx_dibitmap.h"
40 #include "third_party/base/check.h"
41 #include "third_party/base/check_op.h"
42
43 namespace {
44
IsValidDimension(int value)45 bool IsValidDimension(int value) {
46 constexpr int kMaxImageDimension = 0x01FFFF;
47 return value > 0 && value <= kMaxImageDimension;
48 }
49
GetBits8(const uint8_t * pData,uint64_t bitpos,size_t nbits)50 unsigned int GetBits8(const uint8_t* pData, uint64_t bitpos, size_t nbits) {
51 DCHECK(nbits == 1 || nbits == 2 || nbits == 4 || nbits == 8 || nbits == 16);
52 DCHECK_EQ((bitpos & (nbits - 1)), 0u);
53 unsigned int byte = pData[bitpos / 8];
54 if (nbits == 8)
55 return byte;
56
57 if (nbits == 16)
58 return byte * 256 + pData[bitpos / 8 + 1];
59
60 return (byte >> (8 - nbits - (bitpos % 8))) & ((1 << nbits) - 1);
61 }
62
GetBitValue(const uint8_t * pSrc,uint32_t pos)63 bool GetBitValue(const uint8_t* pSrc, uint32_t pos) {
64 return pSrc[pos / 8] & (1 << (7 - pos % 8));
65 }
66
67 // Just to sanity check and filter out obvious bad values.
IsMaybeValidBitsPerComponent(int bpc)68 bool IsMaybeValidBitsPerComponent(int bpc) {
69 return bpc >= 0 && bpc <= 16;
70 }
71
IsAllowedBitsPerComponent(int bpc)72 bool IsAllowedBitsPerComponent(int bpc) {
73 return bpc == 1 || bpc == 2 || bpc == 4 || bpc == 8 || bpc == 16;
74 }
75
IsColorIndexOutOfBounds(uint8_t index,const DIB_COMP_DATA & comp_datum)76 bool IsColorIndexOutOfBounds(uint8_t index, const DIB_COMP_DATA& comp_datum) {
77 return index < comp_datum.m_ColorKeyMin || index > comp_datum.m_ColorKeyMax;
78 }
79
AreColorIndicesOutOfBounds(const uint8_t * indices,const DIB_COMP_DATA * comp_data,size_t count)80 bool AreColorIndicesOutOfBounds(const uint8_t* indices,
81 const DIB_COMP_DATA* comp_data,
82 size_t count) {
83 for (size_t i = 0; i < count; ++i) {
84 if (IsColorIndexOutOfBounds(indices[i], comp_data[i]))
85 return true;
86 }
87 return false;
88 }
89
CalculateBitsPerPixel(uint32_t bpc,uint32_t comps)90 int CalculateBitsPerPixel(uint32_t bpc, uint32_t comps) {
91 // TODO(thestig): Can |bpp| be 0 here? Add an DCHECK() or handle it?
92 uint32_t bpp = bpc * comps;
93 if (bpp == 1)
94 return 1;
95 if (bpp <= 8)
96 return 8;
97 return 24;
98 }
99
ColorSpaceOptionFromColorSpace(CPDF_ColorSpace * pCS)100 CJPX_Decoder::ColorSpaceOption ColorSpaceOptionFromColorSpace(
101 CPDF_ColorSpace* pCS) {
102 if (!pCS)
103 return CJPX_Decoder::kNoColorSpace;
104 if (pCS->GetFamily() == CPDF_ColorSpace::Family::kIndexed)
105 return CJPX_Decoder::kIndexedColorSpace;
106 return CJPX_Decoder::kNormalColorSpace;
107 }
108
109 enum class JpxDecodeAction {
110 kFail,
111 kDoNothing,
112 kUseGray,
113 kUseRgb,
114 kUseCmyk,
115 kConvertArgbToRgb,
116 };
117
118 // Decides which JpxDecodeAction to use based on the colorspace information from
119 // the PDF and the JPX image. Called only when the PDF's image object contains a
120 // "/ColorSpace" entry.
GetJpxDecodeActionFromColorSpaces(const CJPX_Decoder::JpxImageInfo & jpx_info,const CPDF_ColorSpace * pdf_colorspace)121 JpxDecodeAction GetJpxDecodeActionFromColorSpaces(
122 const CJPX_Decoder::JpxImageInfo& jpx_info,
123 const CPDF_ColorSpace* pdf_colorspace) {
124 if (pdf_colorspace ==
125 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)) {
126 if (jpx_info.colorspace != OPJ_CLRSPC_GRAY &&
127 jpx_info.colorspace != OPJ_CLRSPC_UNSPECIFIED) {
128 return JpxDecodeAction::kFail;
129 }
130 return JpxDecodeAction::kUseGray;
131 }
132
133 if (pdf_colorspace ==
134 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB)) {
135 if (jpx_info.colorspace != OPJ_CLRSPC_SRGB &&
136 jpx_info.colorspace != OPJ_CLRSPC_UNSPECIFIED) {
137 return JpxDecodeAction::kFail;
138 }
139
140 // The channel count of a JPX image can be different from the PDF color
141 // space's component count.
142 if (jpx_info.channels > 3) {
143 return JpxDecodeAction::kConvertArgbToRgb;
144 }
145 return JpxDecodeAction::kUseRgb;
146 }
147
148 if (pdf_colorspace ==
149 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK)) {
150 if (jpx_info.colorspace != OPJ_CLRSPC_CMYK &&
151 jpx_info.colorspace != OPJ_CLRSPC_UNSPECIFIED) {
152 return JpxDecodeAction::kFail;
153 }
154 return JpxDecodeAction::kUseCmyk;
155 }
156
157 return JpxDecodeAction::kDoNothing;
158 }
159
GetJpxDecodeActionFromImageColorSpace(const CJPX_Decoder::JpxImageInfo & jpx_info)160 JpxDecodeAction GetJpxDecodeActionFromImageColorSpace(
161 const CJPX_Decoder::JpxImageInfo& jpx_info) {
162 switch (jpx_info.colorspace) {
163 case OPJ_CLRSPC_SYCC:
164 case OPJ_CLRSPC_EYCC:
165 case OPJ_CLRSPC_UNKNOWN:
166 case OPJ_CLRSPC_UNSPECIFIED:
167 return JpxDecodeAction::kDoNothing;
168
169 case OPJ_CLRSPC_SRGB:
170 if (jpx_info.channels > 3) {
171 return JpxDecodeAction::kConvertArgbToRgb;
172 }
173
174 return JpxDecodeAction::kUseRgb;
175
176 case OPJ_CLRSPC_GRAY:
177 return JpxDecodeAction::kUseGray;
178
179 case OPJ_CLRSPC_CMYK:
180 return JpxDecodeAction::kUseCmyk;
181 }
182 }
183
GetJpxDecodeAction(const CJPX_Decoder::JpxImageInfo & jpx_info,const CPDF_ColorSpace * pdf_colorspace)184 JpxDecodeAction GetJpxDecodeAction(const CJPX_Decoder::JpxImageInfo& jpx_info,
185 const CPDF_ColorSpace* pdf_colorspace) {
186 if (pdf_colorspace) {
187 return GetJpxDecodeActionFromColorSpaces(jpx_info, pdf_colorspace);
188 }
189
190 // When PDF does not provide a color space, check the image color space.
191 return GetJpxDecodeActionFromImageColorSpace(jpx_info);
192 }
193
GetComponentCountFromOpjColorSpace(OPJ_COLOR_SPACE colorspace)194 int GetComponentCountFromOpjColorSpace(OPJ_COLOR_SPACE colorspace) {
195 switch (colorspace) {
196 case OPJ_CLRSPC_GRAY:
197 return 1;
198
199 case OPJ_CLRSPC_SRGB:
200 case OPJ_CLRSPC_SYCC:
201 case OPJ_CLRSPC_EYCC:
202 return 3;
203
204 case OPJ_CLRSPC_CMYK:
205 return 4;
206
207 default:
208 return 0;
209 }
210 }
211
212 } // namespace
213
CPDF_DIB(CPDF_Document * pDoc,RetainPtr<const CPDF_Stream> pStream)214 CPDF_DIB::CPDF_DIB(CPDF_Document* pDoc, RetainPtr<const CPDF_Stream> pStream)
215 : m_pDocument(pDoc), m_pStream(std::move(pStream)) {}
216
217 CPDF_DIB::~CPDF_DIB() = default;
218
219 CPDF_DIB::JpxSMaskInlineData::JpxSMaskInlineData() = default;
220
221 CPDF_DIB::JpxSMaskInlineData::~JpxSMaskInlineData() = default;
222
Load()223 bool CPDF_DIB::Load() {
224 if (!LoadInternal(nullptr, nullptr))
225 return false;
226
227 if (CreateDecoder(0) == LoadState::kFail)
228 return false;
229
230 return ContinueInternal();
231 }
232
ContinueToLoadMask()233 bool CPDF_DIB::ContinueToLoadMask() {
234 if (m_pColorSpace && m_bStdCS)
235 m_pColorSpace->EnableStdConversion(true);
236
237 return ContinueInternal();
238 }
239
ContinueInternal()240 bool CPDF_DIB::ContinueInternal() {
241 if (m_bImageMask) {
242 SetMaskProperties();
243 } else {
244 if (!m_bpc || !m_nComponents)
245 return false;
246
247 m_Format = MakeRGBFormat(CalculateBitsPerPixel(m_bpc, m_nComponents));
248 }
249
250 absl::optional<uint32_t> pitch =
251 fxge::CalculatePitch32(GetBppFromFormat(m_Format), m_Width);
252 if (!pitch.has_value())
253 return false;
254
255 m_LineBuf = DataVector<uint8_t>(pitch.value());
256 LoadPalette();
257 if (m_bColorKey) {
258 m_Format = FXDIB_Format::kArgb;
259 pitch = fxge::CalculatePitch32(GetBppFromFormat(m_Format), m_Width);
260 if (!pitch.has_value())
261 return false;
262 m_MaskBuf = DataVector<uint8_t>(pitch.value());
263 }
264 m_Pitch = pitch.value();
265 return true;
266 }
267
StartLoadDIBBase(bool bHasMask,const CPDF_Dictionary * pFormResources,const CPDF_Dictionary * pPageResources,bool bStdCS,CPDF_ColorSpace::Family GroupFamily,bool bLoadMask,const CFX_Size & max_size_required)268 CPDF_DIB::LoadState CPDF_DIB::StartLoadDIBBase(
269 bool bHasMask,
270 const CPDF_Dictionary* pFormResources,
271 const CPDF_Dictionary* pPageResources,
272 bool bStdCS,
273 CPDF_ColorSpace::Family GroupFamily,
274 bool bLoadMask,
275 const CFX_Size& max_size_required) {
276 m_bStdCS = bStdCS;
277 m_bHasMask = bHasMask;
278 m_GroupFamily = GroupFamily;
279 m_bLoadMask = bLoadMask;
280
281 if (!m_pStream->IsInline())
282 pFormResources = nullptr;
283
284 if (!LoadInternal(pFormResources, pPageResources))
285 return LoadState::kFail;
286
287 uint8_t resolution_levels_to_skip = 0;
288 if (max_size_required.width != 0 && max_size_required.height != 0) {
289 resolution_levels_to_skip = static_cast<uint8_t>(
290 std::log2(std::max(1, std::min(m_Width / max_size_required.width,
291 m_Height / max_size_required.height))));
292 }
293
294 LoadState iCreatedDecoder = CreateDecoder(resolution_levels_to_skip);
295 if (iCreatedDecoder == LoadState::kFail)
296 return LoadState::kFail;
297
298 if (!ContinueToLoadMask())
299 return LoadState::kFail;
300
301 LoadState iLoadedMask = m_bHasMask ? StartLoadMask() : LoadState::kSuccess;
302 if (iCreatedDecoder == LoadState::kContinue ||
303 iLoadedMask == LoadState::kContinue) {
304 return LoadState::kContinue;
305 }
306
307 DCHECK_EQ(iCreatedDecoder, LoadState::kSuccess);
308 DCHECK_EQ(iLoadedMask, LoadState::kSuccess);
309 if (m_pColorSpace && m_bStdCS)
310 m_pColorSpace->EnableStdConversion(false);
311 return LoadState::kSuccess;
312 }
313
ContinueLoadDIBBase(PauseIndicatorIface * pPause)314 CPDF_DIB::LoadState CPDF_DIB::ContinueLoadDIBBase(PauseIndicatorIface* pPause) {
315 if (m_Status == LoadState::kContinue)
316 return ContinueLoadMaskDIB(pPause);
317
318 ByteString decoder = m_pStreamAcc->GetImageDecoder();
319 if (decoder == "JPXDecode")
320 return LoadState::kFail;
321
322 if (decoder != "JBIG2Decode")
323 return LoadState::kSuccess;
324
325 if (m_Status == LoadState::kFail)
326 return LoadState::kFail;
327
328 FXCODEC_STATUS iDecodeStatus;
329 if (!m_pJbig2Context) {
330 m_pJbig2Context = std::make_unique<Jbig2Context>();
331 if (m_pStreamAcc->GetImageParam()) {
332 RetainPtr<const CPDF_Stream> pGlobals =
333 m_pStreamAcc->GetImageParam()->GetStreamFor("JBIG2Globals");
334 if (pGlobals) {
335 m_pGlobalAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pGlobals));
336 m_pGlobalAcc->LoadAllDataFiltered();
337 }
338 }
339 uint64_t nSrcKey = 0;
340 pdfium::span<const uint8_t> pSrcSpan;
341 if (m_pStreamAcc) {
342 pSrcSpan = m_pStreamAcc->GetSpan();
343 nSrcKey = m_pStreamAcc->KeyForCache();
344 }
345 uint64_t nGlobalKey = 0;
346 pdfium::span<const uint8_t> pGlobalSpan;
347 if (m_pGlobalAcc) {
348 pGlobalSpan = m_pGlobalAcc->GetSpan();
349 nGlobalKey = m_pGlobalAcc->KeyForCache();
350 }
351 iDecodeStatus = Jbig2Decoder::StartDecode(
352 m_pJbig2Context.get(), m_pDocument->GetOrCreateCodecContext(), m_Width,
353 m_Height, pSrcSpan, nSrcKey, pGlobalSpan, nGlobalKey,
354 m_pCachedBitmap->GetWritableBuffer(), m_pCachedBitmap->GetPitch(),
355 pPause);
356 } else {
357 iDecodeStatus = Jbig2Decoder::ContinueDecode(m_pJbig2Context.get(), pPause);
358 }
359
360 if (iDecodeStatus == FXCODEC_STATUS::kError) {
361 m_pJbig2Context.reset();
362 m_pCachedBitmap.Reset();
363 m_pGlobalAcc.Reset();
364 return LoadState::kFail;
365 }
366 if (iDecodeStatus == FXCODEC_STATUS::kDecodeToBeContinued)
367 return LoadState::kContinue;
368
369 LoadState iContinueStatus = LoadState::kSuccess;
370 if (m_bHasMask) {
371 if (ContinueLoadMaskDIB(pPause) == LoadState::kContinue) {
372 iContinueStatus = LoadState::kContinue;
373 m_Status = LoadState::kContinue;
374 }
375 }
376 if (iContinueStatus == LoadState::kContinue)
377 return LoadState::kContinue;
378
379 if (m_pColorSpace && m_bStdCS)
380 m_pColorSpace->EnableStdConversion(false);
381 return iContinueStatus;
382 }
383
LoadColorInfo(const CPDF_Dictionary * pFormResources,const CPDF_Dictionary * pPageResources)384 bool CPDF_DIB::LoadColorInfo(const CPDF_Dictionary* pFormResources,
385 const CPDF_Dictionary* pPageResources) {
386 absl::optional<DecoderArray> decoder_array = GetDecoderArray(m_pDict);
387 if (!decoder_array.has_value())
388 return false;
389
390 m_bpc_orig = m_pDict->GetIntegerFor("BitsPerComponent");
391 if (!IsMaybeValidBitsPerComponent(m_bpc_orig))
392 return false;
393
394 m_bImageMask = m_pDict->GetBooleanFor("ImageMask", /*bDefault=*/false);
395
396 if (m_bImageMask || !m_pDict->KeyExist("ColorSpace")) {
397 if (!m_bImageMask && !decoder_array.value().empty()) {
398 const ByteString& filter = decoder_array.value().back().first;
399 if (filter == "JPXDecode") {
400 m_bDoBpcCheck = false;
401 return true;
402 }
403 }
404 m_bImageMask = true;
405 m_bpc = m_nComponents = 1;
406 RetainPtr<const CPDF_Array> pDecode = m_pDict->GetArrayFor("Decode");
407 m_bDefaultDecode = !pDecode || !pDecode->GetIntegerAt(0);
408 return true;
409 }
410
411 RetainPtr<const CPDF_Object> pCSObj =
412 m_pDict->GetDirectObjectFor("ColorSpace");
413 if (!pCSObj)
414 return false;
415
416 auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pDocument);
417 if (pFormResources)
418 m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pFormResources);
419 if (!m_pColorSpace)
420 m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pPageResources);
421 if (!m_pColorSpace)
422 return false;
423
424 // If the checks above failed to find a colorspace, and the next line to set
425 // |m_nComponents| does not get reached, then a decoder can try to set
426 // |m_nComponents| based on the number of channels in the image being
427 // decoded.
428 m_nComponents = m_pColorSpace->CountComponents();
429 m_Family = m_pColorSpace->GetFamily();
430 if (m_Family == CPDF_ColorSpace::Family::kICCBased && pCSObj->IsName()) {
431 ByteString cs = pCSObj->GetString();
432 if (cs == "DeviceGray")
433 m_nComponents = 1;
434 else if (cs == "DeviceRGB")
435 m_nComponents = 3;
436 else if (cs == "DeviceCMYK")
437 m_nComponents = 4;
438 }
439
440 ByteString filter;
441 if (!decoder_array.value().empty())
442 filter = decoder_array.value().back().first;
443
444 if (!ValidateDictParam(filter))
445 return false;
446
447 return GetDecodeAndMaskArray();
448 }
449
GetDecodeAndMaskArray()450 bool CPDF_DIB::GetDecodeAndMaskArray() {
451 if (!m_pColorSpace)
452 return false;
453
454 m_CompData.resize(m_nComponents);
455 int max_data = (1 << m_bpc) - 1;
456 RetainPtr<const CPDF_Array> pDecode = m_pDict->GetArrayFor("Decode");
457 if (pDecode) {
458 for (uint32_t i = 0; i < m_nComponents; i++) {
459 m_CompData[i].m_DecodeMin = pDecode->GetFloatAt(i * 2);
460 float max = pDecode->GetFloatAt(i * 2 + 1);
461 m_CompData[i].m_DecodeStep = (max - m_CompData[i].m_DecodeMin) / max_data;
462 float def_value;
463 float def_min;
464 float def_max;
465 m_pColorSpace->GetDefaultValue(i, &def_value, &def_min, &def_max);
466 if (m_Family == CPDF_ColorSpace::Family::kIndexed)
467 def_max = max_data;
468 if (def_min != m_CompData[i].m_DecodeMin || def_max != max)
469 m_bDefaultDecode = false;
470 }
471 } else {
472 for (uint32_t i = 0; i < m_nComponents; i++) {
473 float def_value;
474 m_pColorSpace->GetDefaultValue(i, &def_value, &m_CompData[i].m_DecodeMin,
475 &m_CompData[i].m_DecodeStep);
476 if (m_Family == CPDF_ColorSpace::Family::kIndexed)
477 m_CompData[i].m_DecodeStep = max_data;
478 m_CompData[i].m_DecodeStep =
479 (m_CompData[i].m_DecodeStep - m_CompData[i].m_DecodeMin) / max_data;
480 }
481 }
482 if (m_pDict->KeyExist("SMask"))
483 return true;
484
485 RetainPtr<const CPDF_Object> pMask = m_pDict->GetDirectObjectFor("Mask");
486 if (!pMask)
487 return true;
488
489 if (const CPDF_Array* pArray = pMask->AsArray()) {
490 if (pArray->size() >= m_nComponents * 2) {
491 for (uint32_t i = 0; i < m_nComponents; i++) {
492 int min_num = pArray->GetIntegerAt(i * 2);
493 int max_num = pArray->GetIntegerAt(i * 2 + 1);
494 m_CompData[i].m_ColorKeyMin = std::max(min_num, 0);
495 m_CompData[i].m_ColorKeyMax = std::min(max_num, max_data);
496 }
497 }
498 m_bColorKey = true;
499 }
500 return true;
501 }
502
CreateDecoder(uint8_t resolution_levels_to_skip)503 CPDF_DIB::LoadState CPDF_DIB::CreateDecoder(uint8_t resolution_levels_to_skip) {
504 ByteString decoder = m_pStreamAcc->GetImageDecoder();
505 if (decoder.IsEmpty())
506 return LoadState::kSuccess;
507
508 if (m_bDoBpcCheck && m_bpc == 0)
509 return LoadState::kFail;
510
511 if (decoder == "JPXDecode") {
512 m_pCachedBitmap = LoadJpxBitmap(resolution_levels_to_skip);
513 return m_pCachedBitmap ? LoadState::kSuccess : LoadState::kFail;
514 }
515
516 if (decoder == "JBIG2Decode") {
517 m_pCachedBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
518 if (!m_pCachedBitmap->Create(
519 m_Width, m_Height,
520 m_bImageMask ? FXDIB_Format::k1bppMask : FXDIB_Format::k1bppRgb)) {
521 m_pCachedBitmap.Reset();
522 return LoadState::kFail;
523 }
524 m_Status = LoadState::kSuccess;
525 return LoadState::kContinue;
526 }
527
528 pdfium::span<const uint8_t> src_span = m_pStreamAcc->GetSpan();
529 RetainPtr<const CPDF_Dictionary> pParams = m_pStreamAcc->GetImageParam();
530 if (decoder == "CCITTFaxDecode") {
531 m_pDecoder = CreateFaxDecoder(src_span, m_Width, m_Height, pParams);
532 } else if (decoder == "FlateDecode") {
533 m_pDecoder = CreateFlateDecoder(src_span, m_Width, m_Height, m_nComponents,
534 m_bpc, pParams);
535 } else if (decoder == "RunLengthDecode") {
536 m_pDecoder = BasicModule::CreateRunLengthDecoder(
537 src_span, m_Width, m_Height, m_nComponents, m_bpc);
538 } else if (decoder == "DCTDecode") {
539 if (!CreateDCTDecoder(src_span, pParams))
540 return LoadState::kFail;
541 }
542 if (!m_pDecoder)
543 return LoadState::kFail;
544
545 const absl::optional<uint32_t> requested_pitch =
546 fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width);
547 if (!requested_pitch.has_value())
548 return LoadState::kFail;
549 const absl::optional<uint32_t> provided_pitch = fxge::CalculatePitch8(
550 m_pDecoder->GetBPC(), m_pDecoder->CountComps(), m_pDecoder->GetWidth());
551 if (!provided_pitch.has_value())
552 return LoadState::kFail;
553 if (provided_pitch.value() < requested_pitch.value())
554 return LoadState::kFail;
555 return LoadState::kSuccess;
556 }
557
CreateDCTDecoder(pdfium::span<const uint8_t> src_span,const CPDF_Dictionary * pParams)558 bool CPDF_DIB::CreateDCTDecoder(pdfium::span<const uint8_t> src_span,
559 const CPDF_Dictionary* pParams) {
560 m_pDecoder = JpegModule::CreateDecoder(
561 src_span, m_Width, m_Height, m_nComponents,
562 !pParams || pParams->GetIntegerFor("ColorTransform", 1));
563 if (m_pDecoder)
564 return true;
565
566 absl::optional<JpegModule::ImageInfo> info_opt =
567 JpegModule::LoadInfo(src_span);
568 if (!info_opt.has_value())
569 return false;
570
571 const JpegModule::ImageInfo& info = info_opt.value();
572 m_Width = info.width;
573 m_Height = info.height;
574
575 if (!CPDF_Image::IsValidJpegComponent(info.num_components) ||
576 !CPDF_Image::IsValidJpegBitsPerComponent(info.bits_per_components)) {
577 return false;
578 }
579
580 if (m_nComponents == static_cast<uint32_t>(info.num_components)) {
581 m_bpc = info.bits_per_components;
582 m_pDecoder = JpegModule::CreateDecoder(src_span, m_Width, m_Height,
583 m_nComponents, info.color_transform);
584 return true;
585 }
586
587 m_nComponents = static_cast<uint32_t>(info.num_components);
588 m_CompData.clear();
589 if (m_pColorSpace) {
590 uint32_t colorspace_comps = m_pColorSpace->CountComponents();
591 switch (m_Family) {
592 case CPDF_ColorSpace::Family::kDeviceGray:
593 case CPDF_ColorSpace::Family::kDeviceRGB:
594 case CPDF_ColorSpace::Family::kDeviceCMYK: {
595 uint32_t dwMinComps = CPDF_ColorSpace::ComponentsForFamily(m_Family);
596 if (colorspace_comps < dwMinComps || m_nComponents < dwMinComps)
597 return false;
598 break;
599 }
600 case CPDF_ColorSpace::Family::kLab: {
601 if (m_nComponents != 3 || colorspace_comps < 3)
602 return false;
603 break;
604 }
605 case CPDF_ColorSpace::Family::kICCBased: {
606 if (!CPDF_ColorSpace::IsValidIccComponents(colorspace_comps) ||
607 !CPDF_ColorSpace::IsValidIccComponents(m_nComponents) ||
608 colorspace_comps < m_nComponents) {
609 return false;
610 }
611 break;
612 }
613 default: {
614 if (colorspace_comps != m_nComponents)
615 return false;
616 break;
617 }
618 }
619 } else {
620 if (m_Family == CPDF_ColorSpace::Family::kLab && m_nComponents != 3)
621 return false;
622 }
623 if (!GetDecodeAndMaskArray())
624 return false;
625
626 m_bpc = info.bits_per_components;
627 m_pDecoder = JpegModule::CreateDecoder(src_span, m_Width, m_Height,
628 m_nComponents, info.color_transform);
629 return true;
630 }
631
LoadJpxBitmap(uint8_t resolution_levels_to_skip)632 RetainPtr<CFX_DIBitmap> CPDF_DIB::LoadJpxBitmap(
633 uint8_t resolution_levels_to_skip) {
634 std::unique_ptr<CJPX_Decoder> decoder =
635 CJPX_Decoder::Create(m_pStreamAcc->GetSpan(),
636 ColorSpaceOptionFromColorSpace(m_pColorSpace.Get()),
637 resolution_levels_to_skip);
638 if (!decoder)
639 return nullptr;
640
641 m_Height >>= resolution_levels_to_skip;
642 m_Width >>= resolution_levels_to_skip;
643
644 if (!decoder->StartDecode())
645 return nullptr;
646
647 CJPX_Decoder::JpxImageInfo image_info = decoder->GetInfo();
648 if (static_cast<int>(image_info.width) < m_Width ||
649 static_cast<int>(image_info.height) < m_Height) {
650 return nullptr;
651 }
652
653 RetainPtr<CPDF_ColorSpace> original_colorspace = m_pColorSpace;
654 bool swap_rgb = false;
655 bool convert_argb_to_rgb = false;
656 auto action = GetJpxDecodeAction(image_info, m_pColorSpace.Get());
657 switch (action) {
658 case JpxDecodeAction::kFail:
659 return nullptr;
660
661 case JpxDecodeAction::kDoNothing:
662 break;
663
664 case JpxDecodeAction::kUseGray:
665 m_pColorSpace =
666 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray);
667 break;
668
669 case JpxDecodeAction::kUseRgb:
670 DCHECK(image_info.channels >= 3);
671 swap_rgb = true;
672 m_pColorSpace = nullptr;
673 break;
674
675 case JpxDecodeAction::kUseCmyk:
676 m_pColorSpace =
677 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK);
678 break;
679
680 case JpxDecodeAction::kConvertArgbToRgb:
681 swap_rgb = true;
682 convert_argb_to_rgb = true;
683 m_pColorSpace.Reset();
684 }
685
686 // If |original_colorspace| exists, then LoadColorInfo() already set
687 // |m_nComponents|.
688 if (original_colorspace) {
689 DCHECK_NE(0u, m_nComponents);
690 } else {
691 DCHECK_EQ(0u, m_nComponents);
692 m_nComponents = GetComponentCountFromOpjColorSpace(image_info.colorspace);
693 if (m_nComponents == 0) {
694 return nullptr;
695 }
696 }
697
698 FXDIB_Format format;
699 if (action == JpxDecodeAction::kUseGray) {
700 format = FXDIB_Format::k8bppRgb;
701 } else if (action == JpxDecodeAction::kUseRgb && image_info.channels == 3) {
702 format = FXDIB_Format::kRgb;
703 } else if (action == JpxDecodeAction::kConvertArgbToRgb &&
704 image_info.channels == 4) {
705 format = FXDIB_Format::kRgb32;
706 } else if (action == JpxDecodeAction::kUseRgb && image_info.channels == 4) {
707 format = FXDIB_Format::kRgb32;
708 } else {
709 image_info.width = (image_info.width * image_info.channels + 2) / 3;
710 format = FXDIB_Format::kRgb;
711 }
712
713 auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
714 if (!result_bitmap->Create(image_info.width, image_info.height, format))
715 return nullptr;
716
717 result_bitmap->Clear(0xFFFFFFFF);
718 if (!decoder->Decode(result_bitmap->GetWritableBuffer(),
719 result_bitmap->GetPitch(), swap_rgb, m_nComponents)) {
720 return nullptr;
721 }
722
723 if (convert_argb_to_rgb) {
724 DCHECK_EQ(3u, m_nComponents);
725 auto rgb_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
726 if (!rgb_bitmap->Create(image_info.width, image_info.height,
727 FXDIB_Format::kRgb)) {
728 return nullptr;
729 }
730 if (m_pDict->GetIntegerFor("SMaskInData") == 1) {
731 // TODO(thestig): Acrobat does not support "/SMaskInData 1" combined with
732 // filters. Check for that and fail early.
733 DCHECK(m_JpxInlineData.data.empty());
734 m_JpxInlineData.width = image_info.width;
735 m_JpxInlineData.height = image_info.height;
736 m_JpxInlineData.data.reserve(image_info.width * image_info.height);
737 for (uint32_t row = 0; row < image_info.height; ++row) {
738 const uint8_t* src = result_bitmap->GetScanline(row).data();
739 uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data();
740 for (uint32_t col = 0; col < image_info.width; ++col) {
741 uint8_t a = src[3];
742 m_JpxInlineData.data.push_back(a);
743 uint8_t na = 255 - a;
744 uint8_t b = (src[0] * a + 255 * na) / 255;
745 uint8_t g = (src[1] * a + 255 * na) / 255;
746 uint8_t r = (src[2] * a + 255 * na) / 255;
747 dest[0] = b;
748 dest[1] = g;
749 dest[2] = r;
750 src += 4;
751 dest += 3;
752 }
753 }
754 } else {
755 // TODO(thestig): Is there existing code that does this already?
756 for (uint32_t row = 0; row < image_info.height; ++row) {
757 const uint8_t* src = result_bitmap->GetScanline(row).data();
758 uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data();
759 for (uint32_t col = 0; col < image_info.width; ++col) {
760 memcpy(dest, src, 3);
761 src += 4;
762 dest += 3;
763 }
764 }
765 }
766 result_bitmap = std::move(rgb_bitmap);
767 } else if (m_pColorSpace &&
768 m_pColorSpace->GetFamily() == CPDF_ColorSpace::Family::kIndexed &&
769 m_bpc < 8) {
770 int scale = 8 - m_bpc;
771 for (uint32_t row = 0; row < image_info.height; ++row) {
772 uint8_t* scanline = result_bitmap->GetWritableScanline(row).data();
773 for (uint32_t col = 0; col < image_info.width; ++col) {
774 *scanline = (*scanline) >> scale;
775 ++scanline;
776 }
777 }
778 }
779
780 // TODO(crbug.com/pdfium/1747): Handle SMaskInData entries for different
781 // color space types.
782
783 m_bpc = 8;
784 return result_bitmap;
785 }
786
LoadInternal(const CPDF_Dictionary * pFormResources,const CPDF_Dictionary * pPageResources)787 bool CPDF_DIB::LoadInternal(const CPDF_Dictionary* pFormResources,
788 const CPDF_Dictionary* pPageResources) {
789 if (!m_pStream)
790 return false;
791
792 m_pDict = m_pStream->GetDict();
793 if (!m_pDict)
794 return false;
795
796 m_Width = m_pDict->GetIntegerFor("Width");
797 m_Height = m_pDict->GetIntegerFor("Height");
798 if (!IsValidDimension(m_Width) || !IsValidDimension(m_Height))
799 return false;
800
801 if (!LoadColorInfo(pFormResources, pPageResources))
802 return false;
803
804 if (m_bDoBpcCheck && (m_bpc == 0 || m_nComponents == 0))
805 return false;
806
807 const absl::optional<uint32_t> maybe_size =
808 fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width);
809 if (!maybe_size.has_value())
810 return false;
811
812 FX_SAFE_UINT32 src_size = maybe_size.value();
813 src_size *= m_Height;
814 if (!src_size.IsValid())
815 return false;
816
817 m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream);
818 m_pStreamAcc->LoadAllDataImageAcc(src_size.ValueOrDie());
819 return !m_pStreamAcc->GetSpan().empty();
820 }
821
StartLoadMask()822 CPDF_DIB::LoadState CPDF_DIB::StartLoadMask() {
823 m_MatteColor = 0XFFFFFFFF;
824
825 if (!m_JpxInlineData.data.empty()) {
826 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
827 dict->SetNewFor<CPDF_Name>("Type", "XObject");
828 dict->SetNewFor<CPDF_Name>("Subtype", "Image");
829 dict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray");
830 dict->SetNewFor<CPDF_Number>("Width", m_JpxInlineData.width);
831 dict->SetNewFor<CPDF_Number>("Height", m_JpxInlineData.height);
832 dict->SetNewFor<CPDF_Number>("BitsPerComponent", 8);
833
834 return StartLoadMaskDIB(
835 pdfium::MakeRetain<CPDF_Stream>(m_JpxInlineData.data, std::move(dict)));
836 }
837
838 RetainPtr<const CPDF_Stream> mask(m_pDict->GetStreamFor("SMask"));
839 if (!mask) {
840 mask = ToStream(m_pDict->GetDirectObjectFor("Mask"));
841 return mask ? StartLoadMaskDIB(std::move(mask)) : LoadState::kSuccess;
842 }
843
844 RetainPtr<const CPDF_Array> pMatte = mask->GetDict()->GetArrayFor("Matte");
845 if (pMatte && m_pColorSpace &&
846 m_Family != CPDF_ColorSpace::Family::kPattern &&
847 pMatte->size() == m_nComponents &&
848 m_pColorSpace->CountComponents() <= m_nComponents) {
849 std::vector<float> colors =
850 ReadArrayElementsToVector(pMatte.Get(), m_nComponents);
851
852 float R;
853 float G;
854 float B;
855 m_pColorSpace->GetRGB(colors, &R, &G, &B);
856 m_MatteColor = ArgbEncode(0, FXSYS_roundf(R * 255), FXSYS_roundf(G * 255),
857 FXSYS_roundf(B * 255));
858 }
859 return StartLoadMaskDIB(std::move(mask));
860 }
861
ContinueLoadMaskDIB(PauseIndicatorIface * pPause)862 CPDF_DIB::LoadState CPDF_DIB::ContinueLoadMaskDIB(PauseIndicatorIface* pPause) {
863 if (!m_pMask)
864 return LoadState::kSuccess;
865
866 LoadState ret = m_pMask->ContinueLoadDIBBase(pPause);
867 if (ret == LoadState::kContinue)
868 return LoadState::kContinue;
869
870 if (m_pColorSpace && m_bStdCS)
871 m_pColorSpace->EnableStdConversion(false);
872
873 if (ret == LoadState::kFail) {
874 m_pMask.Reset();
875 return LoadState::kFail;
876 }
877 return LoadState::kSuccess;
878 }
879
DetachMask()880 RetainPtr<CPDF_DIB> CPDF_DIB::DetachMask() {
881 return std::move(m_pMask);
882 }
883
IsJBigImage() const884 bool CPDF_DIB::IsJBigImage() const {
885 return m_pStreamAcc->GetImageDecoder() == "JBIG2Decode";
886 }
887
StartLoadMaskDIB(RetainPtr<const CPDF_Stream> mask_stream)888 CPDF_DIB::LoadState CPDF_DIB::StartLoadMaskDIB(
889 RetainPtr<const CPDF_Stream> mask_stream) {
890 m_pMask = pdfium::MakeRetain<CPDF_DIB>(m_pDocument, std::move(mask_stream));
891 LoadState ret = m_pMask->StartLoadDIBBase(false, nullptr, nullptr, true,
892 CPDF_ColorSpace::Family::kUnknown,
893 false, {0, 0});
894 if (ret == LoadState::kContinue) {
895 if (m_Status == LoadState::kFail)
896 m_Status = LoadState::kContinue;
897 return LoadState::kContinue;
898 }
899 if (ret == LoadState::kFail)
900 m_pMask.Reset();
901 return LoadState::kSuccess;
902 }
903
LoadPalette()904 void CPDF_DIB::LoadPalette() {
905 if (!m_pColorSpace || m_Family == CPDF_ColorSpace::Family::kPattern)
906 return;
907
908 if (m_bpc == 0)
909 return;
910
911 // Use FX_SAFE_UINT32 just to be on the safe side, in case |m_bpc| or
912 // |m_nComponents| somehow gets a bad value.
913 FX_SAFE_UINT32 safe_bits = m_bpc;
914 safe_bits *= m_nComponents;
915 uint32_t bits = safe_bits.ValueOrDefault(255);
916 if (bits > 8)
917 return;
918
919 if (bits == 1) {
920 if (m_bDefaultDecode && (m_Family == CPDF_ColorSpace::Family::kDeviceGray ||
921 m_Family == CPDF_ColorSpace::Family::kDeviceRGB)) {
922 return;
923 }
924 if (m_pColorSpace->CountComponents() > 3) {
925 return;
926 }
927 float color_values[3];
928 std::fill(std::begin(color_values), std::end(color_values),
929 m_CompData[0].m_DecodeMin);
930
931 float R = 0.0f;
932 float G = 0.0f;
933 float B = 0.0f;
934 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
935
936 FX_ARGB argb0 = ArgbEncode(255, FXSYS_roundf(R * 255),
937 FXSYS_roundf(G * 255), FXSYS_roundf(B * 255));
938 FX_ARGB argb1;
939 const CPDF_IndexedCS* indexed_cs = m_pColorSpace->AsIndexedCS();
940 if (indexed_cs && indexed_cs->GetMaxIndex() == 0) {
941 // If an indexed color space's hival value is 0, only 1 color is specified
942 // in the lookup table. Another color should be set to 0xFF000000 by
943 // default to set the range of the color space.
944 argb1 = 0xFF000000;
945 } else {
946 color_values[0] += m_CompData[0].m_DecodeStep;
947 color_values[1] += m_CompData[0].m_DecodeStep;
948 color_values[2] += m_CompData[0].m_DecodeStep;
949 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
950 argb1 = ArgbEncode(255, FXSYS_roundf(R * 255), FXSYS_roundf(G * 255),
951 FXSYS_roundf(B * 255));
952 }
953
954 if (argb0 != 0xFF000000 || argb1 != 0xFFFFFFFF) {
955 SetPaletteArgb(0, argb0);
956 SetPaletteArgb(1, argb1);
957 }
958 return;
959 }
960 if (m_bpc == 8 && m_bDefaultDecode &&
961 m_pColorSpace ==
962 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)) {
963 return;
964 }
965
966 int palette_count = 1 << bits;
967 // Using at least 16 elements due to the call m_pColorSpace->GetRGB().
968 std::vector<float> color_values(std::max(m_nComponents, 16u));
969 for (int i = 0; i < palette_count; i++) {
970 int color_data = i;
971 for (uint32_t j = 0; j < m_nComponents; j++) {
972 int encoded_component = color_data % (1 << m_bpc);
973 color_data /= 1 << m_bpc;
974 color_values[j] = m_CompData[j].m_DecodeMin +
975 m_CompData[j].m_DecodeStep * encoded_component;
976 }
977 float R = 0;
978 float G = 0;
979 float B = 0;
980 if (m_nComponents == 1 && m_Family == CPDF_ColorSpace::Family::kICCBased &&
981 m_pColorSpace->CountComponents() > 1) {
982 int nComponents = m_pColorSpace->CountComponents();
983 std::vector<float> temp_buf(nComponents);
984 for (int k = 0; k < nComponents; ++k)
985 temp_buf[k] = color_values[0];
986 m_pColorSpace->GetRGB(temp_buf, &R, &G, &B);
987 } else {
988 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
989 }
990 SetPaletteArgb(i, ArgbEncode(255, FXSYS_roundf(R * 255),
991 FXSYS_roundf(G * 255), FXSYS_roundf(B * 255)));
992 }
993 }
994
ValidateDictParam(const ByteString & filter)995 bool CPDF_DIB::ValidateDictParam(const ByteString& filter) {
996 m_bpc = m_bpc_orig;
997
998 // Per spec, |m_bpc| should always be 8 for RunLengthDecode, but too many
999 // documents do not conform to it. So skip this check.
1000
1001 if (filter == "JPXDecode") {
1002 m_bDoBpcCheck = false;
1003 return true;
1004 }
1005
1006 if (filter == "CCITTFaxDecode" || filter == "JBIG2Decode") {
1007 m_bpc = 1;
1008 m_nComponents = 1;
1009 } else if (filter == "DCTDecode") {
1010 m_bpc = 8;
1011 }
1012
1013 if (!IsAllowedBitsPerComponent(m_bpc)) {
1014 m_bpc = 0;
1015 return false;
1016 }
1017 return true;
1018 }
1019
TranslateScanline24bpp(pdfium::span<uint8_t> dest_scan,pdfium::span<const uint8_t> src_scan) const1020 void CPDF_DIB::TranslateScanline24bpp(
1021 pdfium::span<uint8_t> dest_scan,
1022 pdfium::span<const uint8_t> src_scan) const {
1023 if (m_bpc == 0)
1024 return;
1025
1026 if (TranslateScanline24bppDefaultDecode(dest_scan, src_scan))
1027 return;
1028
1029 // Using at least 16 elements due to the call m_pColorSpace->GetRGB().
1030 std::vector<float> color_values(std::max(m_nComponents, 16u));
1031 float R = 0.0f;
1032 float G = 0.0f;
1033 float B = 0.0f;
1034 uint64_t src_bit_pos = 0;
1035 uint64_t src_byte_pos = 0;
1036 size_t dest_byte_pos = 0;
1037 const bool bpp8 = m_bpc == 8;
1038 for (int column = 0; column < m_Width; column++) {
1039 for (uint32_t color = 0; color < m_nComponents; color++) {
1040 if (bpp8) {
1041 uint8_t data = src_scan[src_byte_pos++];
1042 color_values[color] = m_CompData[color].m_DecodeMin +
1043 m_CompData[color].m_DecodeStep * data;
1044 } else {
1045 unsigned int data = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1046 color_values[color] = m_CompData[color].m_DecodeMin +
1047 m_CompData[color].m_DecodeStep * data;
1048 src_bit_pos += m_bpc;
1049 }
1050 }
1051
1052 if (TransMask()) {
1053 float k = 1.0f - color_values[3];
1054 R = (1.0f - color_values[0]) * k;
1055 G = (1.0f - color_values[1]) * k;
1056 B = (1.0f - color_values[2]) * k;
1057 } else if (m_Family != CPDF_ColorSpace::Family::kPattern) {
1058 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
1059 }
1060 R = std::clamp(R, 0.0f, 1.0f);
1061 G = std::clamp(G, 0.0f, 1.0f);
1062 B = std::clamp(B, 0.0f, 1.0f);
1063 dest_scan[dest_byte_pos] = static_cast<uint8_t>(B * 255);
1064 dest_scan[dest_byte_pos + 1] = static_cast<uint8_t>(G * 255);
1065 dest_scan[dest_byte_pos + 2] = static_cast<uint8_t>(R * 255);
1066 dest_byte_pos += 3;
1067 }
1068 }
1069
TranslateScanline24bppDefaultDecode(pdfium::span<uint8_t> dest_scan,pdfium::span<const uint8_t> src_scan) const1070 bool CPDF_DIB::TranslateScanline24bppDefaultDecode(
1071 pdfium::span<uint8_t> dest_scan,
1072 pdfium::span<const uint8_t> src_scan) const {
1073 if (!m_bDefaultDecode)
1074 return false;
1075
1076 if (m_Family != CPDF_ColorSpace::Family::kDeviceRGB &&
1077 m_Family != CPDF_ColorSpace::Family::kCalRGB) {
1078 if (m_bpc != 8)
1079 return false;
1080
1081 if (m_nComponents == m_pColorSpace->CountComponents()) {
1082 m_pColorSpace->TranslateImageLine(dest_scan, src_scan, m_Width, m_Width,
1083 m_Height, TransMask());
1084 }
1085 return true;
1086 }
1087
1088 if (m_nComponents != 3)
1089 return true;
1090
1091 uint8_t* dest_pos = dest_scan.data();
1092 const uint8_t* src_pos = src_scan.data();
1093 switch (m_bpc) {
1094 case 8:
1095 for (int column = 0; column < m_Width; column++) {
1096 *dest_pos++ = src_pos[2];
1097 *dest_pos++ = src_pos[1];
1098 *dest_pos++ = *src_pos;
1099 src_pos += 3;
1100 }
1101 break;
1102 case 16:
1103 for (int col = 0; col < m_Width; col++) {
1104 *dest_pos++ = src_pos[4];
1105 *dest_pos++ = src_pos[2];
1106 *dest_pos++ = *src_pos;
1107 src_pos += 6;
1108 }
1109 break;
1110 default:
1111 const unsigned int max_data = (1 << m_bpc) - 1;
1112 uint64_t src_bit_pos = 0;
1113 size_t dest_byte_pos = 0;
1114 for (int column = 0; column < m_Width; column++) {
1115 unsigned int R = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1116 src_bit_pos += m_bpc;
1117 unsigned int G = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1118 src_bit_pos += m_bpc;
1119 unsigned int B = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1120 src_bit_pos += m_bpc;
1121 R = std::min(R, max_data);
1122 G = std::min(G, max_data);
1123 B = std::min(B, max_data);
1124 dest_pos[dest_byte_pos] = B * 255 / max_data;
1125 dest_pos[dest_byte_pos + 1] = G * 255 / max_data;
1126 dest_pos[dest_byte_pos + 2] = R * 255 / max_data;
1127 dest_byte_pos += 3;
1128 }
1129 break;
1130 }
1131 return true;
1132 }
1133
GetBuffer() const1134 pdfium::span<const uint8_t> CPDF_DIB::GetBuffer() const {
1135 return m_pCachedBitmap ? m_pCachedBitmap->GetBuffer()
1136 : pdfium::span<const uint8_t>();
1137 }
1138
GetScanline(int line) const1139 pdfium::span<const uint8_t> CPDF_DIB::GetScanline(int line) const {
1140 if (m_bpc == 0)
1141 return pdfium::span<const uint8_t>();
1142
1143 const absl::optional<uint32_t> src_pitch =
1144 fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width);
1145 if (!src_pitch.has_value())
1146 return pdfium::span<const uint8_t>();
1147
1148 uint32_t src_pitch_value = src_pitch.value();
1149 // This is used as the buffer of `pSrcLine` when the stream is truncated,
1150 // and the remaining bytes count is less than `src_pitch_value`
1151 DataVector<uint8_t> temp_buffer;
1152 pdfium::span<const uint8_t> pSrcLine;
1153
1154 if (m_pCachedBitmap && src_pitch_value <= m_pCachedBitmap->GetPitch()) {
1155 if (line >= m_pCachedBitmap->GetHeight())
1156 line = m_pCachedBitmap->GetHeight() - 1;
1157 pSrcLine = m_pCachedBitmap->GetScanline(line);
1158 } else if (m_pDecoder) {
1159 pSrcLine = m_pDecoder->GetScanline(line);
1160 } else if (m_pStreamAcc->GetSize() > line * src_pitch_value) {
1161 pdfium::span<const uint8_t> remaining_bytes =
1162 m_pStreamAcc->GetSpan().subspan(line * src_pitch_value);
1163 if (remaining_bytes.size() >= src_pitch_value) {
1164 pSrcLine = remaining_bytes.first(src_pitch_value);
1165 } else {
1166 temp_buffer = DataVector<uint8_t>(src_pitch_value);
1167 pdfium::span<uint8_t> result = temp_buffer;
1168 fxcrt::spancpy(result, remaining_bytes);
1169 pSrcLine = result;
1170 }
1171 }
1172
1173 if (pSrcLine.empty()) {
1174 pdfium::span<uint8_t> result = !m_MaskBuf.empty() ? m_MaskBuf : m_LineBuf;
1175 fxcrt::spanset(result, 0);
1176 return result;
1177 }
1178 if (m_bpc * m_nComponents == 1) {
1179 if (m_bImageMask && m_bDefaultDecode) {
1180 for (uint32_t i = 0; i < src_pitch_value; i++) {
1181 // TODO(tsepez): Bounds check if cost is acceptable.
1182 m_LineBuf[i] = ~pSrcLine.data()[i];
1183 }
1184 return pdfium::make_span(m_LineBuf).first(src_pitch_value);
1185 }
1186 if (!m_bColorKey) {
1187 pdfium::span<uint8_t> result = m_LineBuf;
1188 fxcrt::spancpy(result, pSrcLine.first(src_pitch_value));
1189 return result.first(src_pitch_value);
1190 }
1191 uint32_t reset_argb = Get1BitResetValue();
1192 uint32_t set_argb = Get1BitSetValue();
1193 uint32_t* dest_scan = reinterpret_cast<uint32_t*>(m_MaskBuf.data());
1194 for (int col = 0; col < m_Width; col++, dest_scan++) {
1195 *dest_scan = GetBitValue(pSrcLine.data(), col) ? set_argb : reset_argb;
1196 }
1197 return pdfium::make_span(m_MaskBuf).first(m_Width * sizeof(uint32_t));
1198 }
1199 if (m_bpc * m_nComponents <= 8) {
1200 pdfium::span<uint8_t> result = m_LineBuf;
1201 if (m_bpc == 8) {
1202 fxcrt::spancpy(result, pSrcLine.first(src_pitch_value));
1203 result = result.first(src_pitch_value);
1204 } else {
1205 uint64_t src_bit_pos = 0;
1206 for (int col = 0; col < m_Width; col++) {
1207 unsigned int color_index = 0;
1208 for (uint32_t color = 0; color < m_nComponents; color++) {
1209 unsigned int data = GetBits8(pSrcLine.data(), src_bit_pos, m_bpc);
1210 color_index |= data << (color * m_bpc);
1211 src_bit_pos += m_bpc;
1212 }
1213 m_LineBuf[col] = color_index;
1214 }
1215 result = result.first(m_Width);
1216 }
1217 if (!m_bColorKey)
1218 return result;
1219
1220 uint8_t* pDestPixel = m_MaskBuf.data();
1221 const uint8_t* pSrcPixel = m_LineBuf.data();
1222 pdfium::span<const uint32_t> palette = GetPaletteSpan();
1223 if (HasPalette()) {
1224 for (int col = 0; col < m_Width; col++) {
1225 uint8_t index = *pSrcPixel++;
1226 *pDestPixel++ = FXARGB_B(palette[index]);
1227 *pDestPixel++ = FXARGB_G(palette[index]);
1228 *pDestPixel++ = FXARGB_R(palette[index]);
1229 *pDestPixel++ =
1230 IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
1231 }
1232 } else {
1233 for (int col = 0; col < m_Width; col++) {
1234 uint8_t index = *pSrcPixel++;
1235 *pDestPixel++ = index;
1236 *pDestPixel++ = index;
1237 *pDestPixel++ = index;
1238 *pDestPixel++ =
1239 IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
1240 }
1241 }
1242 return pdfium::make_span(m_MaskBuf).first(4 * m_Width);
1243 }
1244 if (m_bColorKey) {
1245 if (m_nComponents == 3 && m_bpc == 8) {
1246 uint8_t* alpha_channel = m_MaskBuf.data() + 3;
1247 for (int col = 0; col < m_Width; col++) {
1248 const uint8_t* pPixel = pSrcLine.data() + col * 3;
1249 alpha_channel[col * 4] =
1250 AreColorIndicesOutOfBounds(pPixel, m_CompData.data(), 3) ? 0xFF : 0;
1251 }
1252 } else {
1253 fxcrt::spanset(pdfium::make_span(m_MaskBuf), 0xFF);
1254 }
1255 }
1256 if (m_pColorSpace) {
1257 TranslateScanline24bpp(m_LineBuf, pSrcLine);
1258 src_pitch_value = 3 * m_Width;
1259 pSrcLine = pdfium::make_span(m_LineBuf).first(src_pitch_value);
1260 }
1261 if (!m_bColorKey)
1262 return pSrcLine;
1263
1264 // TODO(tsepez): Bounds check if cost is acceptable.
1265 const uint8_t* pSrcPixel = pSrcLine.data();
1266 uint8_t* pDestPixel = m_MaskBuf.data();
1267 for (int col = 0; col < m_Width; col++) {
1268 *pDestPixel++ = *pSrcPixel++;
1269 *pDestPixel++ = *pSrcPixel++;
1270 *pDestPixel++ = *pSrcPixel++;
1271 pDestPixel++;
1272 }
1273 return pdfium::make_span(m_MaskBuf).first(4 * m_Width);
1274 }
1275
SkipToScanline(int line,PauseIndicatorIface * pPause) const1276 bool CPDF_DIB::SkipToScanline(int line, PauseIndicatorIface* pPause) const {
1277 return m_pDecoder && m_pDecoder->SkipToScanline(line, pPause);
1278 }
1279
GetEstimatedImageMemoryBurden() const1280 size_t CPDF_DIB::GetEstimatedImageMemoryBurden() const {
1281 return m_pCachedBitmap ? m_pCachedBitmap->GetEstimatedImageMemoryBurden() : 0;
1282 }
1283
TransMask() const1284 bool CPDF_DIB::TransMask() const {
1285 return m_bLoadMask && m_GroupFamily == CPDF_ColorSpace::Family::kDeviceCMYK &&
1286 m_Family == CPDF_ColorSpace::Family::kDeviceCMYK;
1287 }
1288
SetMaskProperties()1289 void CPDF_DIB::SetMaskProperties() {
1290 m_bpc = 1;
1291 m_nComponents = 1;
1292 m_Format = FXDIB_Format::k1bppMask;
1293 }
1294
Get1BitSetValue() const1295 uint32_t CPDF_DIB::Get1BitSetValue() const {
1296 if (m_CompData[0].m_ColorKeyMax == 1)
1297 return 0x00000000;
1298 return HasPalette() ? GetPaletteSpan()[1] : 0xFFFFFFFF;
1299 }
1300
Get1BitResetValue() const1301 uint32_t CPDF_DIB::Get1BitResetValue() const {
1302 if (m_CompData[0].m_ColorKeyMin == 0)
1303 return 0x00000000;
1304 return HasPalette() ? GetPaletteSpan()[0] : 0xFF000000;
1305 }
1306