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