7#include "core/fpdfapi/page/cpdf_dib.h"
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/icc/icc_transform.h"
32#include "core/fxcodec/jbig2/jbig2_decoder.h"
33#include "core/fxcodec/jpeg/jpegmodule.h"
34#include "core/fxcodec/jpx/cjpx_decoder.h"
35#include "core/fxcodec/scanlinedecoder.h"
36#include "core/fxcrt/data_vector.h"
37#include "core/fxcrt/fx_safe_types.h"
38#include "core/fxcrt/span_util.h"
39#include "core/fxge/calculate_pitch.h"
40#include "core/fxge/dib/cfx_dibitmap.h"
41#include "third_party/base/check.h"
42#include "third_party/base/check_op.h"
46bool IsValidDimension(
int value) {
47 constexpr int kMaxImageDimension = 0x01FFFF;
48 return value > 0 && value <= kMaxImageDimension;
51unsigned int GetBits8(
const uint8_t* pData, uint64_t bitpos, size_t nbits) {
52 DCHECK(nbits == 1 || nbits == 2 || nbits == 4 || nbits == 8 || nbits == 16);
53 DCHECK_EQ((bitpos & (nbits - 1)), 0u);
54 unsigned int byte = pData[bitpos / 8];
59 return byte * 256 + pData[bitpos / 8 + 1];
61 return (byte >> (8 - nbits - (bitpos % 8))) & ((1 << nbits) - 1);
64bool GetBitValue(
const uint8_t* pSrc, uint32_t pos) {
65 return pSrc[pos / 8] & (1 << (7 - pos % 8));
69bool IsMaybeValidBitsPerComponent(
int bpc) {
70 return bpc >= 0 && bpc <= 16;
73bool IsAllowedBitsPerComponent(
int bpc) {
74 return bpc == 1 || bpc == 2 || bpc == 4 || bpc == 8 || bpc == 16;
77bool IsColorIndexOutOfBounds(uint8_t index,
const DIB_COMP_DATA& comp_datum) {
81bool AreColorIndicesOutOfBounds(
const uint8_t* indices,
84 for (size_t i = 0; i < count; ++i) {
85 if (IsColorIndexOutOfBounds(indices[i], comp_data[i]))
91int CalculateBitsPerPixel(uint32_t bpc, uint32_t comps) {
92 uint32_t bpp = bpc * comps;
110enum class JpxDecodeAction {
122JpxDecodeAction GetJpxDecodeActionFromColorSpaces(
125 if (pdf_colorspace ==
129 return JpxDecodeAction::kFail;
131 return JpxDecodeAction::kUseGray;
134 if (pdf_colorspace ==
138 return JpxDecodeAction::kFail;
144 return JpxDecodeAction::kConvertArgbToRgb;
146 return JpxDecodeAction::kUseRgb;
149 if (pdf_colorspace ==
153 return JpxDecodeAction::kFail;
155 return JpxDecodeAction::kUseCmyk;
158 return JpxDecodeAction::kDoNothing;
161JpxDecodeAction GetJpxDecodeActionFromImageColorSpace(
164 case OPJ_CLRSPC_SYCC:
165 case OPJ_CLRSPC_EYCC:
166 case OPJ_CLRSPC_UNKNOWN:
167 case OPJ_CLRSPC_UNSPECIFIED:
168 return JpxDecodeAction::kDoNothing;
170 case OPJ_CLRSPC_SRGB:
172 return JpxDecodeAction::kConvertArgbToRgb;
175 return JpxDecodeAction::kUseRgb;
177 case OPJ_CLRSPC_GRAY:
178 return JpxDecodeAction::kUseGray;
180 case OPJ_CLRSPC_CMYK:
181 return JpxDecodeAction::kUseCmyk;
187 if (pdf_colorspace) {
188 return GetJpxDecodeActionFromColorSpaces(jpx_info, pdf_colorspace);
192 return GetJpxDecodeActionFromImageColorSpace(jpx_info);
195int GetComponentCountFromOpjColorSpace(OPJ_COLOR_SPACE colorspace) {
196 switch (colorspace) {
197 case OPJ_CLRSPC_GRAY:
200 case OPJ_CLRSPC_SRGB:
201 case OPJ_CLRSPC_SYCC:
202 case OPJ_CLRSPC_EYCC:
205 case OPJ_CLRSPC_CMYK:
216 : m_pDocument(pDoc), m_pStream(std::move(pStream)) {}
220CPDF_DIB::JpxSMaskInlineData::JpxSMaskInlineData() =
default;
222CPDF_DIB::JpxSMaskInlineData::~JpxSMaskInlineData() =
default;
225 if (!LoadInternal(
nullptr,
nullptr))
231 return ContinueInternal();
234bool CPDF_DIB::ContinueToLoadMask() {
235 if (m_pColorSpace && m_bStdCS)
236 m_pColorSpace->EnableStdConversion(
true);
238 return ContinueInternal();
241bool CPDF_DIB::ContinueInternal() {
245 if (!m_bpc || !m_nComponents)
251 absl::optional<uint32_t> pitch =
252 fxge::CalculatePitch32(GetBppFromFormat(m_Format), m_Width);
253 if (!pitch.has_value())
256 m_LineBuf = DataVector<uint8_t>(pitch.value());
260 pitch = fxge::CalculatePitch32(GetBppFromFormat(m_Format), m_Width);
261 if (!pitch.has_value())
263 m_MaskBuf = DataVector<uint8_t>(pitch.value());
265 m_Pitch = pitch.value();
271 const CPDF_Dictionary* pFormResources,
272 const CPDF_Dictionary* pPageResources,
276 const CFX_Size& max_size_required) {
278 m_bHasMask = bHasMask;
279 m_GroupFamily = GroupFamily;
280 m_bLoadMask = bLoadMask;
282 if (!m_pStream->IsInline())
283 pFormResources =
nullptr;
285 if (!LoadInternal(pFormResources, pPageResources))
288 uint8_t resolution_levels_to_skip = 0;
289 if (max_size_required.width != 0 && max_size_required.height != 0) {
290 resolution_levels_to_skip =
static_cast<uint8_t>(
292 m_Height / max_size_required.height))));
295 LoadState iCreatedDecoder = CreateDecoder(resolution_levels_to_skip);
299 if (!ContinueToLoadMask())
310 if (m_pColorSpace && m_bStdCS)
311 m_pColorSpace->EnableStdConversion(
false);
317 return ContinueLoadMaskDIB(pPause);
319 ByteString decoder = m_pStreamAcc->GetImageDecoder();
320 if (decoder
== "JPXDecode")
323 if (decoder
!= "JBIG2Decode")
330 if (!m_pJbig2Context) {
331 m_pJbig2Context = std::make_unique<Jbig2Context>();
332 if (m_pStreamAcc->GetImageParam()) {
334 m_pStreamAcc->GetImageParam()->GetStreamFor(
"JBIG2Globals");
336 m_pGlobalAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pGlobals));
337 m_pGlobalAcc->LoadAllDataFiltered();
340 uint64_t nSrcKey = 0;
341 pdfium::span<
const uint8_t> pSrcSpan;
343 pSrcSpan = m_pStreamAcc->GetSpan();
344 nSrcKey = m_pStreamAcc->KeyForCache();
346 uint64_t nGlobalKey = 0;
347 pdfium::span<
const uint8_t> pGlobalSpan;
349 pGlobalSpan = m_pGlobalAcc->GetSpan();
350 nGlobalKey = m_pGlobalAcc->KeyForCache();
352 iDecodeStatus = Jbig2Decoder::StartDecode(
353 m_pJbig2Context.get(), m_pDocument->GetOrCreateCodecContext(), m_Width,
354 m_Height, pSrcSpan, nSrcKey, pGlobalSpan, nGlobalKey,
355 m_pCachedBitmap->GetWritableBuffer(), m_pCachedBitmap->GetPitch(),
358 iDecodeStatus = Jbig2Decoder::ContinueDecode(m_pJbig2Context.get(), pPause);
362 m_pJbig2Context.reset();
363 m_pCachedBitmap.Reset();
364 m_pGlobalAcc.Reset();
380 if (m_pColorSpace && m_bStdCS)
381 m_pColorSpace->EnableStdConversion(
false);
382 return iContinueStatus;
385bool CPDF_DIB::LoadColorInfo(
const CPDF_Dictionary* pFormResources,
386 const CPDF_Dictionary* pPageResources) {
387 absl::optional<DecoderArray> decoder_array = GetDecoderArray(m_pDict);
388 if (!decoder_array.has_value())
391 m_bpc_orig = m_pDict->GetIntegerFor(
"BitsPerComponent");
392 if (!IsMaybeValidBitsPerComponent(m_bpc_orig))
395 m_bImageMask = m_pDict->GetBooleanFor(
"ImageMask",
false);
397 if (m_bImageMask || !m_pDict->KeyExist(
"ColorSpace")) {
398 if (!m_bImageMask && !decoder_array.value().empty()) {
399 const ByteString& filter = decoder_array.value().back().first;
400 if (filter
== "JPXDecode") {
401 m_bDoBpcCheck =
false;
406 m_bpc = m_nComponents = 1;
407 RetainPtr<
const CPDF_Array> pDecode = m_pDict->GetArrayFor(
"Decode");
408 m_bDefaultDecode = !pDecode || !pDecode->GetIntegerAt(0);
413 m_pDict->GetDirectObjectFor(
"ColorSpace");
417 auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pDocument);
419 m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pFormResources);
421 m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pPageResources);
429 m_nComponents = m_pColorSpace->CountComponents();
430 m_Family = m_pColorSpace->GetFamily();
432 ByteString cs = pCSObj->GetString();
433 if (cs
== "DeviceGray")
435 else if (cs
== "DeviceRGB")
437 else if (cs
== "DeviceCMYK")
442 if (!decoder_array.value().empty())
443 filter = decoder_array.value().back().first;
445 if (!ValidateDictParam(filter))
448 return GetDecodeAndMaskArray();
451bool CPDF_DIB::GetDecodeAndMaskArray() {
455 m_CompData.resize(m_nComponents);
456 int max_data = (1 << m_bpc) - 1;
457 RetainPtr<
const CPDF_Array> pDecode = m_pDict->GetArrayFor(
"Decode");
459 for (uint32_t i = 0; i < m_nComponents; i++) {
460 m_CompData[i].m_DecodeMin = pDecode->GetFloatAt(i * 2);
461 float max = pDecode->GetFloatAt(i * 2 + 1);
462 m_CompData[i].m_DecodeStep = (max - m_CompData[i].m_DecodeMin) / max_data;
466 m_pColorSpace->GetDefaultValue(i, &def_value, &def_min, &def_max);
469 if (def_min != m_CompData[i].m_DecodeMin || def_max != max)
470 m_bDefaultDecode =
false;
473 for (uint32_t i = 0; i < m_nComponents; i++) {
475 m_pColorSpace->GetDefaultValue(i, &def_value, &m_CompData[i].m_DecodeMin,
476 &m_CompData[i].m_DecodeStep);
477 if (m_Family == CPDF_ColorSpace::Family::kIndexed)
478 m_CompData[i].m_DecodeStep = max_data;
479 m_CompData[i].m_DecodeStep =
480 (m_CompData[i].m_DecodeStep - m_CompData[i].m_DecodeMin) / max_data;
483 if (m_pDict->KeyExist(
"SMask"))
490 if (
const CPDF_Array* pArray = pMask->AsArray()) {
491 if (pArray->size() >= m_nComponents * 2) {
492 for (uint32_t i = 0; i < m_nComponents; i++) {
493 int min_num = pArray->GetIntegerAt(i * 2);
494 int max_num = pArray->GetIntegerAt(i * 2 + 1);
495 m_CompData[i].m_ColorKeyMin = std::max(min_num, 0);
496 m_CompData[i].m_ColorKeyMax = std::min(max_num, max_data);
504CPDF_DIB::
LoadState CPDF_DIB::CreateDecoder(uint8_t resolution_levels_to_skip) {
505 ByteString decoder = m_pStreamAcc->GetImageDecoder();
509 if (m_bDoBpcCheck && m_bpc == 0)
512 if (decoder
== "JPXDecode") {
513 m_pCachedBitmap = LoadJpxBitmap(resolution_levels_to_skip);
514 return m_pCachedBitmap ? LoadState::kSuccess : LoadState::kFail;
517 if (decoder
== "JBIG2Decode") {
518 m_pCachedBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
519 if (!m_pCachedBitmap->Create(
521 m_bImageMask ? FXDIB_Format::k1bppMask : FXDIB_Format::k1bppRgb)) {
522 m_pCachedBitmap.Reset();
529 pdfium::span<
const uint8_t> src_span = m_pStreamAcc->GetSpan();
530 RetainPtr<
const CPDF_Dictionary> pParams = m_pStreamAcc->GetImageParam();
531 if (decoder
== "CCITTFaxDecode") {
532 m_pDecoder = CreateFaxDecoder(src_span, m_Width, m_Height, pParams);
533 }
else if (decoder
== "FlateDecode") {
534 m_pDecoder = CreateFlateDecoder(src_span, m_Width, m_Height, m_nComponents,
536 }
else if (decoder
== "RunLengthDecode") {
537 m_pDecoder = BasicModule::CreateRunLengthDecoder(
538 src_span, m_Width, m_Height, m_nComponents, m_bpc);
539 }
else if (decoder
== "DCTDecode") {
540 if (!CreateDCTDecoder(src_span, pParams))
546 const absl::optional<uint32_t> requested_pitch =
547 fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width);
548 if (!requested_pitch.has_value())
550 const absl::optional<uint32_t> provided_pitch = fxge::CalculatePitch8(
551 m_pDecoder->GetBPC(), m_pDecoder->CountComps(), m_pDecoder->GetWidth());
552 if (!provided_pitch.has_value())
554 if (provided_pitch.value() < requested_pitch.value())
559bool CPDF_DIB::CreateDCTDecoder(pdfium::span<
const uint8_t> src_span,
560 const CPDF_Dictionary* pParams) {
561 m_pDecoder = JpegModule::CreateDecoder(
562 src_span, m_Width, m_Height, m_nComponents,
563 !pParams || pParams->GetIntegerFor(
"ColorTransform", 1));
567 absl::optional<JpegModule::ImageInfo> info_opt =
568 JpegModule::LoadInfo(src_span);
569 if (!info_opt.has_value())
572 const JpegModule::
ImageInfo& info = info_opt.value();
583 m_pDecoder = JpegModule::CreateDecoder(src_span, m_Width, m_Height,
584 m_nComponents, info.color_transform);
591 uint32_t colorspace_comps = m_pColorSpace->CountComponents();
597 if (colorspace_comps < dwMinComps || m_nComponents < dwMinComps)
602 if (m_nComponents != 3 || colorspace_comps < 3)
609 colorspace_comps < m_nComponents) {
615 if (colorspace_comps != m_nComponents)
624 if (!GetDecodeAndMaskArray())
628 m_pDecoder = JpegModule::CreateDecoder(src_span, m_Width, m_Height,
629 m_nComponents, info.color_transform);
633RetainPtr<CFX_DIBitmap> CPDF_DIB::LoadJpxBitmap(
634 uint8_t resolution_levels_to_skip) {
635 std::unique_ptr<CJPX_Decoder> decoder =
636 CJPX_Decoder::Create(m_pStreamAcc->GetSpan(),
637 ColorSpaceOptionFromColorSpace(m_pColorSpace.Get()),
638 resolution_levels_to_skip);
642 m_Height >>= resolution_levels_to_skip;
643 m_Width >>= resolution_levels_to_skip;
645 if (!decoder->StartDecode())
655 bool swap_rgb =
false;
656 bool convert_argb_to_rgb =
false;
657 auto action = GetJpxDecodeAction(image_info, m_pColorSpace.Get());
659 case JpxDecodeAction::kFail:
662 case JpxDecodeAction::kDoNothing:
665 case JpxDecodeAction::kUseGray:
667 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray);
670 case JpxDecodeAction::kUseRgb:
671 DCHECK(image_info.channels >= 3);
673 m_pColorSpace =
nullptr;
676 case JpxDecodeAction::kUseCmyk:
678 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK);
681 case JpxDecodeAction::kConvertArgbToRgb:
683 convert_argb_to_rgb =
true;
684 m_pColorSpace.Reset();
689 if (original_colorspace) {
690 DCHECK_NE(0u, m_nComponents);
692 DCHECK_EQ(0u, m_nComponents);
693 m_nComponents = GetComponentCountFromOpjColorSpace(image_info
.colorspace);
694 if (m_nComponents == 0) {
700 if (action == JpxDecodeAction::kUseGray) {
702 }
else if (action == JpxDecodeAction::kUseRgb && image_info
.channels == 3) {
704 }
else if (action == JpxDecodeAction::kConvertArgbToRgb &&
707 }
else if (action == JpxDecodeAction::kUseRgb && image_info
.channels == 4) {
714 auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
715 if (!result_bitmap->Create(image_info
.width, image_info
.height, format))
718 result_bitmap->Clear(0xFFFFFFFF);
719 if (!decoder->Decode(result_bitmap->GetWritableBuffer(),
720 result_bitmap->GetPitch(), swap_rgb, m_nComponents)) {
724 if (convert_argb_to_rgb) {
725 DCHECK_EQ(3u, m_nComponents);
726 auto rgb_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
731 if (m_pDict->GetIntegerFor(
"SMaskInData") == 1) {
734 DCHECK(m_JpxInlineData.data.empty());
735 m_JpxInlineData.width = image_info.width;
736 m_JpxInlineData.height = image_info.height;
737 m_JpxInlineData.data.reserve(image_info.width * image_info.height);
738 for (uint32_t row = 0; row < image_info
.height; ++row) {
739 const uint8_t* src = result_bitmap->GetScanline(row).data();
740 uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data();
741 for (uint32_t col = 0; col < image_info
.width; ++col) {
743 m_JpxInlineData.data.push_back(a);
744 uint8_t na = 255 - a;
745 uint8_t b = (src[0] * a + 255 * na) / 255;
746 uint8_t g = (src[1] * a + 255 * na) / 255;
747 uint8_t r = (src[2] * a + 255 * na) / 255;
757 for (uint32_t row = 0; row < image_info
.height; ++row) {
758 const uint8_t* src = result_bitmap->GetScanline(row).data();
759 uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data();
760 for (uint32_t col = 0; col < image_info
.width; ++col) {
761 memcpy(dest, src, 3);
767 result_bitmap =
std::move(rgb_bitmap);
768 }
else if (m_pColorSpace &&
769 m_pColorSpace->GetFamily() == CPDF_ColorSpace::Family::kIndexed &&
771 int scale = 8 - m_bpc;
772 for (uint32_t row = 0; row < image_info
.height; ++row) {
773 uint8_t* scanline = result_bitmap->GetWritableScanline(row).data();
774 for (uint32_t col = 0; col < image_info
.width; ++col) {
775 *scanline = (*scanline) >> scale;
785 return result_bitmap;
788bool CPDF_DIB::LoadInternal(
const CPDF_Dictionary* pFormResources,
789 const CPDF_Dictionary* pPageResources) {
793 m_pDict = m_pStream->GetDict();
797 m_Width = m_pDict->GetIntegerFor(
"Width");
798 m_Height = m_pDict->GetIntegerFor(
"Height");
802 if (!LoadColorInfo(pFormResources, pPageResources))
805 if (m_bDoBpcCheck && (m_bpc == 0 || m_nComponents == 0))
808 const absl::optional<uint32_t> maybe_size =
809 fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width);
810 if (!maybe_size.has_value())
813 FX_SAFE_UINT32 src_size = maybe_size.value();
815 if (!src_size.IsValid())
818 m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream);
819 m_pStreamAcc->LoadAllDataImageAcc(src_size.ValueOrDie());
820 return !m_pStreamAcc->GetSpan().empty();
823CPDF_DIB::
LoadState CPDF_DIB::StartLoadMask() {
824 m_MatteColor = 0XFFFFFFFF;
826 if (!m_JpxInlineData.data.empty()) {
827 auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
828 dict->SetNewFor<CPDF_Name>(
"Type",
"XObject");
829 dict->SetNewFor<CPDF_Name>(
"Subtype",
"Image");
830 dict->SetNewFor<CPDF_Name>(
"ColorSpace",
"DeviceGray");
831 dict->SetNewFor<CPDF_Number>(
"Width", m_JpxInlineData.width);
832 dict->SetNewFor<CPDF_Number>(
"Height", m_JpxInlineData.height);
833 dict->SetNewFor<CPDF_Number>(
"BitsPerComponent", 8);
835 return StartLoadMaskDIB(
836 pdfium::MakeRetain<CPDF_Stream>(m_JpxInlineData.data, std::move(dict)));
839 RetainPtr<
const CPDF_Stream> mask(m_pDict->GetStreamFor(
"SMask"));
841 mask = ToStream(m_pDict->GetDirectObjectFor(
"Mask"));
845 RetainPtr<
const CPDF_Array> pMatte = mask->GetDict()->GetArrayFor(
"Matte");
846 if (pMatte && m_pColorSpace &&
847 m_Family != CPDF_ColorSpace::Family::kPattern &&
848 pMatte->size() == m_nComponents &&
849 m_pColorSpace->CountComponents() <= m_nComponents) {
850 std::vector<
float> colors =
851 ReadArrayElementsToVector(pMatte.Get(), m_nComponents);
856 m_pColorSpace->GetRGB(colors, &R, &G, &B);
860 return StartLoadMaskDIB(
std::move(mask));
867 LoadState ret = m_pMask->ContinueLoadDIBBase(pPause);
871 if (m_pColorSpace && m_bStdCS)
872 m_pColorSpace->EnableStdConversion(
false);
882 return std::move(m_pMask);
886 return m_pStreamAcc->GetImageDecoder() ==
"JBIG2Decode";
889CPDF_DIB::
LoadState CPDF_DIB::StartLoadMaskDIB(
890 RetainPtr<
const CPDF_Stream> mask_stream) {
891 m_pMask = pdfium::MakeRetain<CPDF_DIB>(m_pDocument, std::move(mask_stream));
892 LoadState ret = m_pMask->StartLoadDIBBase(
false,
nullptr,
nullptr,
true,
893 CPDF_ColorSpace::Family::kUnknown,
900 if (ret == LoadState::kFail)
905void CPDF_DIB::LoadPalette() {
906 if (!m_pColorSpace || m_Family == CPDF_ColorSpace::Family::kPattern)
914 FX_SAFE_UINT32 safe_bits = m_bpc;
915 safe_bits *= m_nComponents;
916 uint32_t bits = safe_bits.ValueOrDefault(255);
925 if (m_pColorSpace->CountComponents() > 3) {
928 float color_values[3];
929 std::fill(std::begin(color_values), std::end(color_values),
930 m_CompData[0].m_DecodeMin);
935 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
940 const CPDF_IndexedCS* indexed_cs = m_pColorSpace->AsIndexedCS();
947 color_values[0] += m_CompData[0].m_DecodeStep;
948 color_values[1] += m_CompData[0].m_DecodeStep;
949 color_values[2] += m_CompData[0].m_DecodeStep;
950 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
955 if (argb0 != 0xFF000000 || argb1 != 0xFFFFFFFF) {
961 if (m_bpc == 8 && m_bDefaultDecode &&
963 CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)) {
967 int palette_count = 1 << bits;
969 std::vector<
float> color_values(std::max(m_nComponents, 16u));
970 for (
int i = 0; i < palette_count; i++) {
972 for (uint32_t j = 0; j < m_nComponents; j++) {
973 int encoded_component = color_data % (1 << m_bpc);
974 color_data /= 1 << m_bpc;
975 color_values[j] = m_CompData[j].m_DecodeMin +
976 m_CompData[j].m_DecodeStep * encoded_component;
981 if (m_nComponents == 1 && m_Family == CPDF_ColorSpace::Family::kICCBased &&
982 m_pColorSpace->CountComponents() > 1) {
983 int nComponents = m_pColorSpace->CountComponents();
984 std::vector<
float> temp_buf(nComponents);
985 for (
int k = 0; k < nComponents; ++k)
986 temp_buf[k] = color_values[0];
987 m_pColorSpace->GetRGB(temp_buf, &R, &G, &B);
989 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
996bool CPDF_DIB::ValidateDictParam(
const ByteString& filter) {
1002 if (filter
== "JPXDecode") {
1003 m_bDoBpcCheck =
false;
1007 if (filter
== "CCITTFaxDecode" || filter
== "JBIG2Decode") {
1010 }
else if (filter
== "DCTDecode") {
1014 if (!IsAllowedBitsPerComponent(m_bpc)) {
1021void CPDF_DIB::TranslateScanline24bpp(
1022 pdfium::span<uint8_t> dest_scan,
1023 pdfium::span<
const uint8_t> src_scan)
const {
1027 if (TranslateScanline24bppDefaultDecode(dest_scan, src_scan))
1031 std::vector<
float> color_values(std::max(m_nComponents, 16u));
1035 uint64_t src_bit_pos = 0;
1036 uint64_t src_byte_pos = 0;
1037 size_t dest_byte_pos = 0;
1038 const bool bpp8 = m_bpc == 8;
1039 for (
int column = 0; column <
m_Width; column++) {
1040 for (uint32_t color = 0; color < m_nComponents; color++) {
1042 uint8_t data = src_scan[src_byte_pos++];
1043 color_values[color] = m_CompData[color].m_DecodeMin +
1044 m_CompData[color].m_DecodeStep * data;
1046 unsigned int data = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1047 color_values[color] = m_CompData[color].m_DecodeMin +
1048 m_CompData[color].m_DecodeStep * data;
1049 src_bit_pos += m_bpc;
1054 float k = 1.0f - color_values[3];
1055 R = (1.0f - color_values[0]) * k;
1056 G = (1.0f - color_values[1]) * k;
1057 B = (1.0f - color_values[2]) * k;
1059 m_pColorSpace->GetRGB(color_values, &R, &G, &B);
1061 R =
std::clamp(R, 0.0f, 1.0f);
1062 G =
std::clamp(G, 0.0f, 1.0f);
1063 B =
std::clamp(B, 0.0f, 1.0f);
1064 dest_scan[dest_byte_pos] =
static_cast<uint8_t>(B * 255);
1065 dest_scan[dest_byte_pos + 1] =
static_cast<uint8_t>(G * 255);
1066 dest_scan[dest_byte_pos + 2] =
static_cast<uint8_t>(R * 255);
1071bool CPDF_DIB::TranslateScanline24bppDefaultDecode(
1072 pdfium::span<uint8_t> dest_scan,
1073 pdfium::span<
const uint8_t> src_scan)
const {
1074 if (!m_bDefaultDecode)
1082 if (m_nComponents == m_pColorSpace->CountComponents()) {
1083 m_pColorSpace->TranslateImageLine(dest_scan, src_scan, m_Width, m_Width,
1084 m_Height, TransMask());
1089 if (m_nComponents != 3)
1092 uint8_t* dest_pos = dest_scan.data();
1093 const uint8_t* src_pos = src_scan.data();
1096 for (
int column = 0; column <
m_Width; column++) {
1097 *dest_pos++ = src_pos[2];
1098 *dest_pos++ = src_pos[1];
1099 *dest_pos++ = *src_pos;
1104 for (
int col = 0; col <
m_Width; col++) {
1105 *dest_pos++ = src_pos[4];
1106 *dest_pos++ = src_pos[2];
1107 *dest_pos++ = *src_pos;
1112 const unsigned int max_data = (1 << m_bpc) - 1;
1113 uint64_t src_bit_pos = 0;
1114 size_t dest_byte_pos = 0;
1115 for (
int column = 0; column <
m_Width; column++) {
1116 unsigned int R = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1117 src_bit_pos += m_bpc;
1118 unsigned int G = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1119 src_bit_pos += m_bpc;
1120 unsigned int B = GetBits8(src_scan.data(), src_bit_pos, m_bpc);
1121 src_bit_pos += m_bpc;
1122 R =
std::min(R, max_data);
1123 G =
std::min(G, max_data);
1124 B =
std::min(B, max_data);
1125 dest_pos[dest_byte_pos] = B * 255 / max_data;
1126 dest_pos[dest_byte_pos + 1] = G * 255 / max_data;
1127 dest_pos[dest_byte_pos + 2] = R * 255 / max_data;
1137 return pdfium::span<
const uint8_t>();
1139 const absl::optional<uint32_t> src_pitch =
1140 fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width);
1141 if (!src_pitch.has_value())
1142 return pdfium::span<
const uint8_t>();
1144 uint32_t src_pitch_value = src_pitch.value();
1147 DataVector<uint8_t> temp_buffer;
1148 pdfium::span<
const uint8_t> pSrcLine;
1150 if (m_pCachedBitmap && src_pitch_value <= m_pCachedBitmap->GetPitch()) {
1151 if (line >= m_pCachedBitmap->GetHeight())
1152 line = m_pCachedBitmap->GetHeight() - 1;
1153 pSrcLine = m_pCachedBitmap->GetScanline(line);
1154 }
else if (m_pDecoder) {
1155 pSrcLine = m_pDecoder->GetScanline(line);
1156 }
else if (m_pStreamAcc->GetSize() > line * src_pitch_value) {
1157 pdfium::span<
const uint8_t> remaining_bytes =
1158 m_pStreamAcc->GetSpan().subspan(line * src_pitch_value);
1159 if (remaining_bytes.size() >= src_pitch_value) {
1160 pSrcLine = remaining_bytes.first(src_pitch_value);
1162 temp_buffer = DataVector<uint8_t>(src_pitch_value);
1163 pdfium::span<uint8_t> result = temp_buffer;
1164 fxcrt::spancpy(result, remaining_bytes);
1169 if (pSrcLine.empty()) {
1170 pdfium::span<uint8_t> result = !m_MaskBuf.empty() ? m_MaskBuf : m_LineBuf;
1171 fxcrt::spanset(result, 0);
1174 if (m_bpc * m_nComponents == 1) {
1175 if (m_bImageMask && m_bDefaultDecode) {
1176 for (uint32_t i = 0; i < src_pitch_value; i++) {
1178 m_LineBuf[i] = ~pSrcLine.data()[i];
1180 return pdfium::make_span(m_LineBuf).first(src_pitch_value);
1183 pdfium::span<uint8_t> result = m_LineBuf;
1184 fxcrt::spancpy(result, pSrcLine.first(src_pitch_value));
1185 return result.first(src_pitch_value);
1187 uint32_t reset_argb = Get1BitResetValue();
1188 uint32_t set_argb = Get1BitSetValue();
1189 uint32_t* dest_scan =
reinterpret_cast<uint32_t*>(m_MaskBuf.data());
1190 for (
int col = 0; col <
m_Width; col++, dest_scan++) {
1191 *dest_scan = GetBitValue(pSrcLine.data(), col) ? set_argb : reset_argb;
1193 return pdfium::make_span(m_MaskBuf).first(m_Width *
sizeof(uint32_t));
1195 if (m_bpc * m_nComponents <= 8) {
1196 pdfium::span<uint8_t> result = m_LineBuf;
1198 fxcrt::spancpy(result, pSrcLine.first(src_pitch_value));
1199 result = result.first(src_pitch_value);
1201 uint64_t src_bit_pos = 0;
1202 for (
int col = 0; col <
m_Width; col++) {
1203 unsigned int color_index = 0;
1204 for (uint32_t color = 0; color < m_nComponents; color++) {
1205 unsigned int data = GetBits8(pSrcLine.data(), src_bit_pos, m_bpc);
1206 color_index |= data << (color * m_bpc);
1207 src_bit_pos += m_bpc;
1209 m_LineBuf[col] = color_index;
1211 result = result.first(
m_Width);
1216 uint8_t* pDestPixel = m_MaskBuf.data();
1217 const uint8_t* pSrcPixel = m_LineBuf.data();
1218 pdfium::span<
const uint32_t> palette = GetPaletteSpan();
1220 for (
int col = 0; col <
m_Width; col++) {
1221 uint8_t index = *pSrcPixel++;
1222 *pDestPixel++ =
FXARGB_B(palette[index]);
1223 *pDestPixel++ =
FXARGB_G(palette[index]);
1224 *pDestPixel++ =
FXARGB_R(palette[index]);
1226 IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
1229 for (
int col = 0; col <
m_Width; col++) {
1230 uint8_t index = *pSrcPixel++;
1231 *pDestPixel++ = index;
1232 *pDestPixel++ = index;
1233 *pDestPixel++ = index;
1235 IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
1238 return pdfium::make_span(m_MaskBuf).first(4 * m_Width);
1241 if (m_nComponents == 3 && m_bpc == 8) {
1242 uint8_t* alpha_channel = m_MaskBuf.data() + 3;
1243 for (
int col = 0; col <
m_Width; col++) {
1244 const uint8_t* pPixel = pSrcLine.data() + col * 3;
1245 alpha_channel[col * 4] =
1246 AreColorIndicesOutOfBounds(pPixel, m_CompData.data(), 3) ? 0xFF : 0;
1249 fxcrt::spanset(pdfium::make_span(m_MaskBuf), 0xFF);
1252 if (m_pColorSpace) {
1253 TranslateScanline24bpp(m_LineBuf, pSrcLine);
1254 src_pitch_value = 3 *
m_Width;
1255 pSrcLine = pdfium::make_span(m_LineBuf).first(src_pitch_value);
1261 const uint8_t* pSrcPixel = pSrcLine.data();
1262 uint8_t* pDestPixel = m_MaskBuf.data();
1263 for (
int col = 0; col <
m_Width; col++) {
1264 *pDestPixel++ = *pSrcPixel++;
1265 *pDestPixel++ = *pSrcPixel++;
1266 *pDestPixel++ = *pSrcPixel++;
1269 return pdfium::make_span(m_MaskBuf).first(4 * m_Width);
1273 return m_pDecoder && m_pDecoder->SkipToScanline(line, pPause);
1277 return m_pCachedBitmap ? m_pCachedBitmap->GetEstimatedImageMemoryBurden() : 0;
1280bool CPDF_DIB::TransMask()
const {
1285void CPDF_DIB::SetMaskProperties() {
1291uint32_t CPDF_DIB::Get1BitSetValue()
const {
1292 if (m_CompData[0].m_ColorKeyMax == 1)
1294 return HasPalette() ? GetPaletteSpan()[1] : 0xFFFFFFFF;
1297uint32_t CPDF_DIB::Get1BitResetValue()
const {
1298 if (m_CompData[0].m_ColorKeyMin == 0)
1300 return HasPalette() ? GetPaletteSpan()[0] : 0xFF000000;
void SetPaletteArgb(int index, uint32_t color)
static uint32_t ComponentsForFamily(Family family)
static RetainPtr< CPDF_ColorSpace > GetStockCS(Family family)
RetainPtr< CPDF_DIB > DetachMask()
size_t GetEstimatedImageMemoryBurden() const override
bool SkipToScanline(int line, PauseIndicatorIface *pPause) const override
LoadState ContinueLoadDIBBase(PauseIndicatorIface *pPause)
pdfium::span< const uint8_t > GetScanline(int line) const override
LoadState 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)
static bool IsValidJpegBitsPerComponent(int32_t bpc)
static bool IsValidJpegComponent(int32_t comps)
bool operator==(const char *ptr) const
bool operator!=(const char *ptr) const
FXDIB_Format MakeRGBFormat(int bpp)
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
int FXSYS_roundf(float f)