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