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
progressive_decoder.cpp
Go to the documentation of this file.
1// Copyright 2014 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/fxcodec/progressive_decoder.h"
8
9#include <algorithm>
10#include <memory>
11#include <utility>
12
13#include "build/build_config.h"
14#include "core/fxcodec/cfx_codec_memory.h"
15#include "core/fxcodec/jpeg/jpeg_progressive_decoder.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/check_op.h"
18#include "core/fxcrt/compiler_specific.h"
19#include "core/fxcrt/fx_2d_size.h"
20#include "core/fxcrt/fx_memcpy_wrappers.h"
21#include "core/fxcrt/fx_safe_types.h"
22#include "core/fxcrt/fx_stream.h"
23#include "core/fxcrt/fx_system.h"
24#include "core/fxcrt/notreached.h"
25#include "core/fxcrt/numerics/safe_conversions.h"
26#include "core/fxcrt/span_util.h"
27#include "core/fxcrt/stl_util.h"
28#include "core/fxge/dib/cfx_cmyk_to_srgb.h"
29#include "core/fxge/dib/cfx_dibitmap.h"
30#include "core/fxge/dib/fx_dib.h"
31
32#ifdef PDF_ENABLE_XFA_BMP
33#include "core/fxcodec/bmp/bmp_progressive_decoder.h"
34#endif // PDF_ENABLE_XFA_BMP
35
36#ifdef PDF_ENABLE_XFA_GIF
37#include "core/fxcodec/gif/gif_progressive_decoder.h"
38#endif // PDF_ENABLE_XFA_GIF
39
40#ifdef PDF_ENABLE_XFA_TIFF
41#include "core/fxcodec/tiff/tiff_decoder.h"
42#endif // PDF_ENABLE_XFA_TIFF
43
44namespace fxcodec {
45
46namespace {
47
48constexpr size_t kBlockSize = 4096;
49
50#ifdef PDF_ENABLE_XFA_PNG
51#if BUILDFLAG(IS_APPLE)
52const double kPngGamma = 1.7;
53#else
54const double kPngGamma = 2.2;
55#endif // BUILDFLAG(IS_APPLE)
56#endif // PDF_ENABLE_XFA_PNG
57
58void RGB2BGR(uint8_t* buffer, int width = 1) {
59 if (buffer && width > 0) {
60 uint8_t temp;
61 int i = 0;
62 int j = 0;
64 for (; i < width; i++, j += 3) {
65 temp = buffer[j];
66 buffer[j] = buffer[j + 2];
67 buffer[j + 2] = temp;
68 }
69 });
70 }
71}
72
73} // namespace
74
75ProgressiveDecoder::ProgressiveDecoder() = default;
76
77ProgressiveDecoder::~ProgressiveDecoder() = default;
78
79#ifdef PDF_ENABLE_XFA_PNG
81 int height,
82 int bpc,
83 int pass,
84 int* color_type,
85 double* gamma) {
86 if (!m_pDeviceBitmap) {
89 m_SrcBPC = bpc;
91 switch (*color_type) {
92 case 0:
94 break;
95 case 4:
97 break;
98 case 2:
100 break;
101 case 3:
102 case 6:
103 m_SrcComponents = 4;
104 break;
105 default:
106 m_SrcComponents = 0;
107 break;
108 }
109 return false;
110 }
111 switch (m_pDeviceBitmap->GetFormat()) {
118 case FXDIB_Format::kBgr:
119 *color_type = 2;
120 break;
121 case FXDIB_Format::kBgrx:
122 case FXDIB_Format::kBgra:
123 *color_type = 6;
124 break;
125#if defined(PDF_USE_SKIA)
127 // TODO(crbug.com/355630556): Consider adding support for
128 // `FXDIB_Format::kBgraPremul`
130#endif
131 }
132 *gamma = kPngGamma;
133 return true;
134}
135
137 CHECK_GE(line, 0);
146 return m_DecodeBuf.data();
147}
148
150 if (line < 0 || line >= m_SrcHeight) {
151 return;
152 }
153
160}
161#endif // PDF_ENABLE_XFA_PNG
162
163#ifdef PDF_ENABLE_XFA_GIF
167 return m_offSet - remain_size;
168}
169
172 const FX_RECT& img_rc,
175 bool interlace) {
177
181 return false;
182
183 if (pal_span.empty()) {
185 }
186 if (pal_span.empty()) {
187 return false;
188 }
190 for (size_t i = 0; i < pal_span.size(); i++) {
191 m_SrcPalette[i] =
192 ArgbEncode(0xff, pal_span[i].r, pal_span[i].g, pal_span[i].b);
193 }
196 m_SrcPassNumber = interlace ? 4 : 1;
199 if (trans_index >= static_cast<int>(pal_span.size())) {
200 trans_index = -1;
201 }
202 if (trans_index != -1) {
203 m_SrcPalette[trans_index] &= 0x00ffffff;
204 if (pDevice->IsAlphaFormat()) {
206 }
207 }
208 if (pal_index >= static_cast<int>(pal_span.size())) {
209 return false;
210 }
211 int startX = 0;
212 int startY = 0;
213 int sizeX = m_SrcWidth;
214 int sizeY = m_SrcHeight;
215 const int bytes_per_pixel = pDevice->GetBPP() / 8;
217 for (int row = 0; row < sizeY; row++) {
220 switch (m_TransMethod) {
224 for (int col = 0; col < sizeX; col++) {
225 *pScanline++ = FXARGB_B(argb);
226 *pScanline++ = FXARGB_G(argb);
227 *pScanline++ = FXARGB_R(argb);
229 }
230 });
231 break;
232 }
236 for (int col = 0; col < sizeX; col++) {
238 pScanline += 4;
239 }
240 });
241 break;
242 }
243 default:
244 break;
245 }
246 }
247 return true;
248}
249
255 if (!pDIBitmap->IsAlphaFormat()) {
257 for (int i = 0; i < img_width; i++) {
260 }
262 }
263 }
267 }
272
274 if (line < 0 || line >= m_SrcHeight) {
275 return;
276 }
277
279}
280#endif // PDF_ENABLE_XFA_GIF
281
282#ifdef PDF_ENABLE_XFA_BMP
287}
288
290 pdfium::span<const uint8_t> row_buf) {
293
295
296 if (row_num >= static_cast<uint32_t>(m_SrcHeight)) {
297 return;
298 }
299
301}
302
306 BmpDecoder::StartDecode(this);
308
309 pdfium::span<const FX_ARGB> palette;
317 return false;
318 }
322 }
323
326 return false;
327 }
328
330 switch (m_SrcComponents) {
331 case 1:
334 break;
335 case 3:
338 break;
339 case 4:
342 break;
343 default:
345 return false;
346 }
347
348 // Set to 0 to make CalculatePitchAndSize() calculate it.
349 constexpr uint32_t kNoPitch = 0;
352 kNoPitch);
353 if (!needed_data.has_value()) {
355 return false;
356 }
357
363 return false;
364 }
365
366 m_SrcBPC = 8;
368 if (!palette.empty()) {
371 } else {
373 }
374 return true;
375}
376
381 err_status);
382}
383
393 return m_status;
394}
395
398 while (read_res == BmpDecoder::Status::kContinue) {
401 m_pDeviceBitmap = nullptr;
402 m_pFile = nullptr;
404 return m_status;
405 }
407 }
408
409 m_pDeviceBitmap = nullptr;
410 m_pFile = nullptr;
414 return m_status;
415}
416#endif // PDF_ENABLE_XFA_BMP
417
418#ifdef PDF_ENABLE_XFA_GIF
421 err_status);
422}
423
427 m_SrcComponents = 1;
434 m_pGifContext = nullptr;
436 return false;
437 }
438 readResult =
441 }
443 m_SrcBPC = 8;
444 return true;
445 }
446 m_pGifContext = nullptr;
448 return false;
449}
450
460 m_FrameCur = 0;
462 return m_status;
463}
464
468 while (readRes == GifDecoder::Status::kUnfinished) {
471 m_pDeviceBitmap = nullptr;
472 m_pFile = nullptr;
474 return m_status;
475 }
477 }
478
480 m_pDeviceBitmap = nullptr;
481 m_pFile = nullptr;
483 return m_status;
484 }
485
486 m_pDeviceBitmap = nullptr;
487 m_pFile = nullptr;
489 return m_status;
490}
491#endif // PDF_ENABLE_XFA_GIF
492
493bool ProgressiveDecoder::JpegReadMoreData(FXCODEC_STATUS* err_status) {
494 return ReadMoreData(JpegProgressiveDecoder::GetInstance(),
495 m_pJpegContext.get(), err_status);
496}
497
498bool ProgressiveDecoder::JpegDetectImageTypeInBuffer(
499 CFX_DIBAttribute* pAttribute) {
500 m_pJpegContext = JpegProgressiveDecoder::Start();
501 if (!m_pJpegContext) {
502 m_status = FXCODEC_STATUS::kError;
503 return false;
504 }
505 JpegProgressiveDecoder::GetInstance()->Input(m_pJpegContext.get(),
506 m_pCodecMemory);
507
508 // Setting jump marker before calling ReadHeader, since a longjmp to
509 // the marker indicates a fatal error.
510 if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
511 m_pJpegContext.reset();
512 m_status = FXCODEC_STATUS::kError;
513 return false;
514 }
515
516 int32_t readResult = JpegProgressiveDecoder::ReadHeader(
517 m_pJpegContext.get(), &m_SrcWidth, &m_SrcHeight, &m_SrcComponents,
518 pAttribute);
519 while (readResult == 2) {
521 if (!JpegReadMoreData(&error_status)) {
522 m_status = error_status;
523 return false;
524 }
525 readResult = JpegProgressiveDecoder::ReadHeader(
526 m_pJpegContext.get(), &m_SrcWidth, &m_SrcHeight, &m_SrcComponents,
527 pAttribute);
528 }
529 if (!readResult) {
530 m_SrcBPC = 8;
531 return true;
532 }
533 m_pJpegContext.reset();
534 m_status = FXCODEC_STATUS::kError;
535 return false;
536}
537
538FXCODEC_STATUS ProgressiveDecoder::JpegStartDecode() {
539 // Setting jump marker before calling StartScanLine, since a longjmp to
540 // the marker indicates a fatal error.
541 if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
542 m_pJpegContext.reset();
543 m_status = FXCODEC_STATUS::kError;
545 }
546
547 bool start_status =
548 JpegProgressiveDecoder::StartScanline(m_pJpegContext.get());
549 while (!start_status) {
551 if (!JpegReadMoreData(&error_status)) {
552 m_pDeviceBitmap = nullptr;
553 m_pFile = nullptr;
554 m_status = error_status;
555 return m_status;
556 }
557
558 start_status = JpegProgressiveDecoder::StartScanline(m_pJpegContext.get());
559 }
560 m_DecodeBuf.resize(FxAlignToBoundary<4>(m_SrcWidth * m_SrcComponents));
561 FXDIB_ResampleOptions options;
562 options.bInterpolateBilinear = true;
563 m_WeightHorz.CalculateWeights(m_SrcWidth, 0, m_SrcWidth, m_SrcWidth, 0,
564 m_SrcWidth, options);
565 switch (m_SrcComponents) {
566 case 1:
567 m_SrcFormat = FXCodec_8bppGray;
568 break;
569 case 3:
570 m_SrcFormat = FXCodec_Rgb;
571 break;
572 case 4:
573 m_SrcFormat = FXCodec_Cmyk;
574 break;
575 }
576 SetTransMethod();
578 return m_status;
579}
580
581FXCODEC_STATUS ProgressiveDecoder::JpegContinueDecode() {
582 // JpegModule* pJpegModule = m_pCodecMgr->GetJpegModule();
583 // Setting jump marker before calling ReadScanLine, since a longjmp to
584 // the marker indicates a fatal error.
585 if (setjmp(JpegProgressiveDecoder::GetJumpMark(m_pJpegContext.get())) == -1) {
586 m_pJpegContext.reset();
587 m_status = FXCODEC_STATUS::kError;
589 }
590
591 while (true) {
592 bool readRes = JpegProgressiveDecoder::ReadScanline(m_pJpegContext.get(),
593 m_DecodeBuf.data());
594 while (!readRes) {
596 if (!JpegReadMoreData(&error_status)) {
597 m_pDeviceBitmap = nullptr;
598 m_pFile = nullptr;
599 m_status = error_status;
600 return m_status;
601 }
602 readRes = JpegProgressiveDecoder::ReadScanline(m_pJpegContext.get(),
603 m_DecodeBuf.data());
604 }
605 if (m_SrcFormat == FXCodec_Rgb) {
606 RGB2BGR(UNSAFE_TODO(m_DecodeBuf.data()), m_SrcWidth);
607 }
608 if (m_SrcRow >= m_SrcHeight) {
609 m_pDeviceBitmap = nullptr;
610 m_pFile = nullptr;
612 return m_status;
613 }
614 Resample(m_pDeviceBitmap, m_SrcRow, m_DecodeBuf.data(), m_SrcFormat);
615 m_SrcRow++;
616 }
617}
618
619#ifdef PDF_ENABLE_XFA_PNG
623 if (!m_pPngContext) {
625 return false;
626 }
628 pAttribute)) {
631 if (input_size == 0) {
634 return false;
635 }
638
642 return false;
643 }
645 }
647 if (m_SrcPassNumber == 0) {
649 return false;
650 }
651 return true;
652}
653
656 if (!m_pPngContext) {
657 m_pDeviceBitmap = nullptr;
658 m_pFile = nullptr;
660 return m_status;
661 }
662 m_offSet = 0;
664 m_SrcComponents = 4;
670 return m_status;
671}
672
674 while (true) {
677 if (input_size == 0) {
679 m_pDeviceBitmap = nullptr;
680 m_pFile = nullptr;
682 return m_status;
683 }
686
689 if (!bResult) {
690 m_pDeviceBitmap = nullptr;
691 m_pFile = nullptr;
693 return m_status;
694 }
697 nullptr);
698 if (!bResult) {
699 m_pDeviceBitmap = nullptr;
700 m_pFile = nullptr;
702 return m_status;
703 }
704 }
705}
706#endif // PDF_ENABLE_XFA_PNG
707
708#ifdef PDF_ENABLE_XFA_TIFF
712 if (!m_pTiffContext) {
714 return false;
715 }
720 m_SrcComponents = 4;
721 if (!ret) {
724 return false;
725 }
726 return true;
727}
728
730 // TODO(crbug.com/355630556): Consider adding support for
731 // `FXDIB_Format::kBgraPremul`
733 m_status =
737 m_pFile = nullptr;
738 return m_status;
739}
740#endif // PDF_ENABLE_XFA_TIFF
741
742bool ProgressiveDecoder::DetectImageType(FXCODEC_IMAGE_TYPE imageType,
743 CFX_DIBAttribute* pAttribute) {
744#ifdef PDF_ENABLE_XFA_TIFF
745 if (imageType == FXCODEC_IMAGE_TIFF)
746 return TiffDetectImageTypeFromFile(pAttribute);
747#endif // PDF_ENABLE_XFA_TIFF
748
749 size_t size = pdfium::checked_cast<size_t>(
750 std::min<FX_FILESIZE>(m_pFile->GetSize(), kBlockSize));
751 m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(size);
752 m_offSet = 0;
753 if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBufferSpan().first(size),
754 m_offSet)) {
755 m_status = FXCODEC_STATUS::kError;
756 return false;
757 }
758 m_offSet += size;
759
760 if (imageType == FXCODEC_IMAGE_JPG)
761 return JpegDetectImageTypeInBuffer(pAttribute);
762
763#ifdef PDF_ENABLE_XFA_BMP
764 if (imageType == FXCODEC_IMAGE_BMP)
765 return BmpDetectImageTypeInBuffer(pAttribute);
766#endif // PDF_ENABLE_XFA_BMP
767
768#ifdef PDF_ENABLE_XFA_GIF
769 if (imageType == FXCODEC_IMAGE_GIF)
770 return GifDetectImageTypeInBuffer();
771#endif // PDF_ENABLE_XFA_GIF
772
773#ifdef PDF_ENABLE_XFA_PNG
774 if (imageType == FXCODEC_IMAGE_PNG)
775 return PngDetectImageTypeInBuffer(pAttribute);
776#endif // PDF_ENABLE_XFA_PNG
777
778 m_status = FXCODEC_STATUS::kError;
779 return false;
780}
781
782bool ProgressiveDecoder::ReadMoreData(
785 FXCODEC_STATUS* err_status) {
786 // Check for EOF.
787 if (m_offSet >= static_cast<uint32_t>(m_pFile->GetSize()))
788 return false;
789
790 // Try to get whatever remains.
791 uint32_t dwBytesToFetchFromFile =
792 pdfium::checked_cast<uint32_t>(m_pFile->GetSize() - m_offSet);
793
794 // Figure out if the codec stopped processing midway through the buffer.
795 size_t dwUnconsumed;
796 FX_SAFE_SIZE_T avail_input = pModule->GetAvailInput(pContext);
797 if (!avail_input.AssignIfValid(&dwUnconsumed))
798 return false;
799
800 if (dwUnconsumed == m_pCodecMemory->GetSize()) {
801 // Codec couldn't make any progress against the bytes in the buffer.
802 // Increase the buffer size so that there might be enough contiguous
803 // bytes to allow whatever operation is having difficulty to succeed.
804 dwBytesToFetchFromFile =
805 std::min<uint32_t>(dwBytesToFetchFromFile, kBlockSize);
806 size_t dwNewSize = m_pCodecMemory->GetSize() + dwBytesToFetchFromFile;
807 if (!m_pCodecMemory->TryResize(dwNewSize)) {
808 *err_status = FXCODEC_STATUS::kError;
809 return false;
810 }
811 } else {
812 // TODO(crbug.com/pdfium/1904): Simplify the `CFX_CodecMemory` API so we
813 // don't need to do this awkward dance to free up exactly enough buffer
814 // space for the next read.
815 size_t dwConsumable = m_pCodecMemory->GetSize() - dwUnconsumed;
816 dwBytesToFetchFromFile = pdfium::checked_cast<uint32_t>(
817 std::min<size_t>(dwBytesToFetchFromFile, dwConsumable));
818 m_pCodecMemory->Consume(dwBytesToFetchFromFile);
819 m_pCodecMemory->Seek(dwConsumable - dwBytesToFetchFromFile);
820 dwUnconsumed += m_pCodecMemory->GetPosition();
821 }
822
823 // Append new data past the bytes not yet processed by the codec.
824 if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBufferSpan().subspan(
825 dwUnconsumed, dwBytesToFetchFromFile),
826 m_offSet)) {
827 *err_status = FXCODEC_STATUS::kError;
828 return false;
829 }
830 m_offSet += dwBytesToFetchFromFile;
831 return pModule->Input(pContext, m_pCodecMemory);
832}
833
834FXCODEC_STATUS ProgressiveDecoder::LoadImageInfo(
836 FXCODEC_IMAGE_TYPE imageType,
837 CFX_DIBAttribute* pAttribute,
838 bool bSkipImageTypeCheck) {
839 DCHECK(pAttribute);
840
841 switch (m_status) {
849 break;
850 }
851 m_pFile = std::move(pFile);
852 if (!m_pFile) {
853 m_status = FXCODEC_STATUS::kError;
854 return m_status;
855 }
856 m_offSet = 0;
857 m_SrcWidth = 0;
858 m_SrcHeight = 0;
859 m_SrcComponents = 0;
860 m_SrcBPC = 0;
861 m_SrcPassNumber = 0;
862 if (imageType != FXCODEC_IMAGE_UNKNOWN &&
863 DetectImageType(imageType, pAttribute)) {
864 m_imageType = imageType;
866 return m_status;
867 }
868 // If we got here then the image data does not match the requested decoder.
869 // If we're skipping the type check then bail out at this point and return
870 // the failed status.
871 if (bSkipImageTypeCheck)
872 return m_status;
873
874 for (int type = FXCODEC_IMAGE_UNKNOWN + 1; type < FXCODEC_IMAGE_MAX; type++) {
875 if (DetectImageType(static_cast<FXCODEC_IMAGE_TYPE>(type), pAttribute)) {
876 m_imageType = static_cast<FXCODEC_IMAGE_TYPE>(type);
878 return m_status;
879 }
880 }
881 m_status = FXCODEC_STATUS::kError;
882 m_pFile = nullptr;
883 return m_status;
884}
885
886void ProgressiveDecoder::SetTransMethod() {
887 switch (m_pDeviceBitmap->GetFormat()) {
888 case FXDIB_Format::kInvalid:
889 case FXDIB_Format::k1bppMask:
890 case FXDIB_Format::k1bppRgb:
891 case FXDIB_Format::k8bppMask:
892 case FXDIB_Format::k8bppRgb:
894 case FXDIB_Format::kBgr: {
895 switch (m_SrcFormat) {
896 case FXCodec_Invalid:
897 m_TransMethod = TransformMethod::kInvalid;
898 break;
899 case FXCodec_8bppGray:
900 m_TransMethod = TransformMethod::k8BppGrayToRgbMaybeAlpha;
901 break;
902 case FXCodec_8bppRgb:
903 m_TransMethod = TransformMethod::k8BppRgbToRgbNoAlpha;
904 break;
905 case FXCodec_Rgb:
906 case FXCodec_Rgb32:
907 case FXCodec_Argb:
908 m_TransMethod = TransformMethod::kRgbMaybeAlphaToRgbMaybeAlpha;
909 break;
910 case FXCodec_Cmyk:
911 m_TransMethod = TransformMethod::kCmykToRgbMaybeAlpha;
912 break;
913 }
914 break;
915 }
916 case FXDIB_Format::kBgrx:
917 case FXDIB_Format::kBgra: {
918 switch (m_SrcFormat) {
919 case FXCodec_Invalid:
920 m_TransMethod = TransformMethod::kInvalid;
921 break;
922 case FXCodec_8bppGray:
923 m_TransMethod = TransformMethod::k8BppGrayToRgbMaybeAlpha;
924 break;
925 case FXCodec_8bppRgb:
926 if (m_pDeviceBitmap->GetFormat() == FXDIB_Format::kBgra) {
927 m_TransMethod = TransformMethod::k8BppRgbToArgb;
928 } else {
929 m_TransMethod = TransformMethod::k8BppRgbToRgbNoAlpha;
930 }
931 break;
932 case FXCodec_Rgb:
933 case FXCodec_Rgb32:
934 m_TransMethod = TransformMethod::kRgbMaybeAlphaToRgbMaybeAlpha;
935 break;
936 case FXCodec_Cmyk:
937 m_TransMethod = TransformMethod::kCmykToRgbMaybeAlpha;
938 break;
939 case FXCodec_Argb:
940 m_TransMethod = TransformMethod::kArgbToArgb;
941 break;
942 }
943 break;
944 }
945#if defined(PDF_USE_SKIA)
946 case FXDIB_Format::kBgraPremul:
947 // TODO(crbug.com/355630556): Consider adding support for
948 // `FXDIB_Format::kBgraPremul`
949 NOTREACHED_NORETURN();
950#endif
951 }
952}
953
954void ProgressiveDecoder::ResampleScanline(
955 const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
956 int dest_line,
957 pdfium::span<uint8_t> src_span,
958 FXCodec_Format src_format) {
959 uint8_t* src_scan = src_span.data();
960 uint8_t* dest_scan = pDeviceBitmap->GetWritableScanline(dest_line).data();
961 const int src_bytes_per_pixel = (src_format & 0xff) / 8;
962 const int dest_bytes_per_pixel = pDeviceBitmap->GetBPP() / 8;
963 for (int dest_col = 0; dest_col < m_SrcWidth; dest_col++) {
964 CStretchEngine::PixelWeight* pPixelWeights =
965 m_WeightHorz.GetPixelWeight(dest_col);
966 switch (m_TransMethod) {
967 case TransformMethod::kInvalid:
968 return;
969 case TransformMethod::k8BppGrayToRgbMaybeAlpha: {
971 uint32_t dest_g = 0;
972 for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
973 j++) {
974 uint32_t pixel_weight =
975 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
976 dest_g += pixel_weight * src_scan[j];
977 }
979 dest_scan += dest_bytes_per_pixel;
980 break;
981 });
982 }
983 case TransformMethod::k8BppRgbToRgbNoAlpha: {
985 uint32_t dest_r = 0;
986 uint32_t dest_g = 0;
987 uint32_t dest_b = 0;
988 for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
989 j++) {
990 uint32_t pixel_weight =
991 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
992 uint32_t argb = m_SrcPalette[src_scan[j]];
993 dest_r += pixel_weight * FXARGB_R(argb);
994 dest_g += pixel_weight * FXARGB_G(argb);
995 dest_b += pixel_weight * FXARGB_B(argb);
996 }
997 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
998 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
999 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1000 dest_scan += dest_bytes_per_pixel - 3;
1001 break;
1002 });
1003 }
1004 case TransformMethod::k8BppRgbToArgb: {
1005#ifdef PDF_ENABLE_XFA_BMP
1006 if (m_pBmpContext) {
1007 UNSAFE_TODO({
1008 uint32_t dest_r = 0;
1009 uint32_t dest_g = 0;
1010 uint32_t dest_b = 0;
1011 for (int j = pPixelWeights->m_SrcStart;
1012 j <= pPixelWeights->m_SrcEnd; j++) {
1013 uint32_t pixel_weight =
1014 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1015 uint32_t argb = m_SrcPalette[src_scan[j]];
1016 dest_r += pixel_weight * FXARGB_R(argb);
1017 dest_g += pixel_weight * FXARGB_G(argb);
1018 dest_b += pixel_weight * FXARGB_B(argb);
1019 }
1020 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1021 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1022 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1023 *dest_scan++ = 0xFF;
1024 break;
1025 });
1026 }
1027#endif // PDF_ENABLE_XFA_BMP
1028 UNSAFE_TODO({
1029 uint32_t dest_a = 0;
1030 uint32_t dest_r = 0;
1031 uint32_t dest_g = 0;
1032 uint32_t dest_b = 0;
1033 for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1034 j++) {
1035 uint32_t pixel_weight =
1036 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1037 FX_ARGB argb = m_SrcPalette[src_scan[j]];
1038 dest_a += pixel_weight * FXARGB_A(argb);
1039 dest_r += pixel_weight * FXARGB_R(argb);
1040 dest_g += pixel_weight * FXARGB_G(argb);
1041 dest_b += pixel_weight * FXARGB_B(argb);
1042 }
1043 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1044 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1045 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1046 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_a);
1047 break;
1048 });
1049 }
1050 case TransformMethod::kRgbMaybeAlphaToRgbMaybeAlpha: {
1051 UNSAFE_TODO({
1052 uint32_t dest_b = 0;
1053 uint32_t dest_g = 0;
1054 uint32_t dest_r = 0;
1055 for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1056 j++) {
1057 uint32_t pixel_weight =
1058 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1059 const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
1060 dest_b += pixel_weight * (*src_pixel++);
1061 dest_g += pixel_weight * (*src_pixel++);
1062 dest_r += pixel_weight * (*src_pixel);
1063 }
1064 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1065 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1066 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1067 dest_scan += dest_bytes_per_pixel - 3;
1068 break;
1069 });
1070 }
1071 case TransformMethod::kCmykToRgbMaybeAlpha: {
1072 UNSAFE_TODO({
1073 uint32_t dest_b = 0;
1074 uint32_t dest_g = 0;
1075 uint32_t dest_r = 0;
1076 for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1077 j++) {
1078 uint32_t pixel_weight =
1079 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1080 const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
1081 FX_RGB_STRUCT<uint8_t> src_rgb =
1082 AdobeCMYK_to_sRGB1(255 - src_pixel[0], 255 - src_pixel[1],
1083 255 - src_pixel[2], 255 - src_pixel[3]);
1084 dest_b += pixel_weight * src_rgb.blue;
1085 dest_g += pixel_weight * src_rgb.green;
1086 dest_r += pixel_weight * src_rgb.red;
1087 }
1088 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1089 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1090 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1091 dest_scan += dest_bytes_per_pixel - 3;
1092 break;
1093 });
1094 }
1095 case TransformMethod::kArgbToArgb: {
1096 UNSAFE_TODO({
1097 uint32_t dest_alpha = 0;
1098 uint32_t dest_r = 0;
1099 uint32_t dest_g = 0;
1100 uint32_t dest_b = 0;
1101 for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
1102 j++) {
1103 uint32_t pixel_weight =
1104 pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];
1105 const uint8_t* src_pixel = src_scan + j * src_bytes_per_pixel;
1106 pixel_weight = pixel_weight * src_pixel[3] / 255;
1107 dest_b += pixel_weight * (*src_pixel++);
1108 dest_g += pixel_weight * (*src_pixel++);
1109 dest_r += pixel_weight * (*src_pixel);
1110 dest_alpha += pixel_weight;
1111 }
1112 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_b);
1113 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_g);
1114 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_r);
1115 *dest_scan++ = CStretchEngine::PixelFromFixed(dest_alpha * 255);
1116 break;
1117 });
1118 }
1119 }
1120 }
1121}
1122
1123void ProgressiveDecoder::Resample(const RetainPtr<CFX_DIBitmap>& pDeviceBitmap,
1124 int32_t src_line,
1125 uint8_t* src_scan,
1126 FXCodec_Format src_format) {
1127 if (src_line < 0 || src_line >= m_SrcHeight) {
1128 return;
1129 }
1130
1131 ResampleScanline(pDeviceBitmap, src_line, m_DecodeBuf, src_format);
1132}
1133
1134FXDIB_Format ProgressiveDecoder::GetBitmapFormat() const {
1135 switch (m_imageType) {
1136 case FXCODEC_IMAGE_JPG:
1137#ifdef PDF_ENABLE_XFA_BMP
1138 case FXCODEC_IMAGE_BMP:
1139#endif // PDF_ENABLE_XFA_BMP
1140 return GetBitsPerPixel() <= 24 ? FXDIB_Format::kBgr : FXDIB_Format::kBgrx;
1141#ifdef PDF_ENABLE_XFA_PNG
1142 case FXCODEC_IMAGE_PNG:
1143#endif // PDF_ENABLE_XFA_PNG
1144#ifdef PDF_ENABLE_XFA_TIFF
1145 case FXCODEC_IMAGE_TIFF:
1146#endif // PDF_ENABLE_XFA_TIFF
1147 default:
1148 // TODO(crbug.com/355630556): Consider adding support for
1149 // `FXDIB_Format::kBgraPremul`
1150 return FXDIB_Format::kBgra;
1151 }
1152}
1153
1154std::pair<FXCODEC_STATUS, size_t> ProgressiveDecoder::GetFrames() {
1155 if (!(m_status == FXCODEC_STATUS::kFrameReady ||
1157 return {FXCODEC_STATUS::kError, 0};
1158 }
1159
1160 switch (m_imageType) {
1161#ifdef PDF_ENABLE_XFA_BMP
1162 case FXCODEC_IMAGE_BMP:
1163#endif // PDF_ENABLE_XFA_BMP
1164 case FXCODEC_IMAGE_JPG:
1165#ifdef PDF_ENABLE_XFA_PNG
1166 case FXCODEC_IMAGE_PNG:
1167#endif // PDF_ENABLE_XFA_PNG
1168#ifdef PDF_ENABLE_XFA_TIFF
1169 case FXCODEC_IMAGE_TIFF:
1170#endif // PDF_ENABLE_XFA_TIFF
1171 m_FrameNumber = 1;
1173 return {m_status, 1};
1174#ifdef PDF_ENABLE_XFA_GIF
1175 case FXCODEC_IMAGE_GIF: {
1176 while (true) {
1177 GifDecoder::Status readResult;
1178 std::tie(readResult, m_FrameNumber) =
1179 GifDecoder::LoadFrameInfo(m_pGifContext.get());
1180 while (readResult == GifDecoder::Status::kUnfinished) {
1181 FXCODEC_STATUS error_status = FXCODEC_STATUS::kError;
1182 if (!GifReadMoreData(&error_status))
1183 return {error_status, 0};
1184
1185 std::tie(readResult, m_FrameNumber) =
1186 GifDecoder::LoadFrameInfo(m_pGifContext.get());
1187 }
1188 if (readResult == GifDecoder::Status::kSuccess) {
1189 m_status = FXCODEC_STATUS::kDecodeReady;
1190 return {m_status, m_FrameNumber};
1191 }
1192 m_pGifContext = nullptr;
1193 m_status = FXCODEC_STATUS::kError;
1194 return {m_status, 0};
1195 }
1196 }
1197#endif // PDF_ENABLE_XFA_GIF
1198 default:
1199 return {FXCODEC_STATUS::kError, 0};
1200 }
1201}
1202
1203FXCODEC_STATUS ProgressiveDecoder::StartDecode(RetainPtr<CFX_DIBitmap> bitmap) {
1204 CHECK(bitmap);
1205 CHECK_EQ(bitmap->GetWidth(), m_SrcWidth);
1206 CHECK_EQ(bitmap->GetHeight(), m_SrcHeight);
1207 CHECK_GT(m_SrcWidth, 0);
1208 CHECK_GT(m_SrcHeight, 0);
1209
1210 const FXDIB_Format format = bitmap->GetFormat();
1211 CHECK(format == FXDIB_Format::kBgra || format == FXDIB_Format::kBgr ||
1212 format == FXDIB_Format::kBgrx);
1213
1214 if (m_status != FXCODEC_STATUS::kDecodeReady) {
1216 }
1217
1218 if (m_FrameNumber == 0) {
1220 }
1221
1222 if (bitmap->GetWidth() > 65535 || bitmap->GetHeight() > 65535) {
1224 }
1225
1226 m_FrameCur = 0;
1227 m_pDeviceBitmap = std::move(bitmap);
1228 switch (m_imageType) {
1229#ifdef PDF_ENABLE_XFA_BMP
1230 case FXCODEC_IMAGE_BMP:
1231 return BmpStartDecode();
1232#endif // PDF_ENABLE_XFA_BMP
1233#ifdef PDF_ENABLE_XFA_GIF
1234 case FXCODEC_IMAGE_GIF:
1235 return GifStartDecode();
1236#endif // PDF_ENABLE_XFA_GIF
1237 case FXCODEC_IMAGE_JPG:
1238 return JpegStartDecode();
1239#ifdef PDF_ENABLE_XFA_PNG
1240 case FXCODEC_IMAGE_PNG:
1241 return PngStartDecode();
1242#endif // PDF_ENABLE_XFA_PNG
1243#ifdef PDF_ENABLE_XFA_TIFF
1244 case FXCODEC_IMAGE_TIFF:
1245 m_status = FXCODEC_STATUS::kDecodeToBeContinued;
1246 return m_status;
1247#endif // PDF_ENABLE_XFA_TIFF
1248 default:
1250 }
1251}
1252
1253FXCODEC_STATUS ProgressiveDecoder::ContinueDecode() {
1256
1257 switch (m_imageType) {
1258 case FXCODEC_IMAGE_JPG:
1259 return JpegContinueDecode();
1260#ifdef PDF_ENABLE_XFA_BMP
1261 case FXCODEC_IMAGE_BMP:
1262 return BmpContinueDecode();
1263#endif // PDF_ENABLE_XFA_BMP
1264#ifdef PDF_ENABLE_XFA_GIF
1265 case FXCODEC_IMAGE_GIF:
1266 return GifContinueDecode();
1267#endif // PDF_ENABLE_XFA_GIF
1268#ifdef PDF_ENABLE_XFA_PNG
1269 case FXCODEC_IMAGE_PNG:
1270 return PngContinueDecode();
1271#endif // PDF_ENABLE_XFA_PNG
1272#ifdef PDF_ENABLE_XFA_TIFF
1273 case FXCODEC_IMAGE_TIFF:
1274 return TiffContinueDecode();
1275#endif // PDF_ENABLE_XFA_TIFF
1276 default:
1278 }
1279}
1280
1281} // namespace fxcodec
#define DCHECK
Definition check.h:33
#define CHECK_GT(x, y)
Definition check_op.h:13
#define CHECK_EQ(x, y)
Definition check_op.h:10
static uint8_t PixelFromFixed(uint32_t fixed)
virtual FX_FILESIZE GetAvailInput(Context *pContext) const =0
FXCODEC_STATUS StartDecode(RetainPtr< CFX_DIBitmap > bitmap)
std::pair< FXCODEC_STATUS, size_t > GetFrames()
FXCODEC_STATUS LoadImageInfo(RetainPtr< IFX_SeekableReadStream > pFile, FXCODEC_IMAGE_TYPE imageType, CFX_DIBAttribute *pAttribute, bool bSkipImageTypeCheck)
#define UNSAFE_TODO(...)
FXCODEC_STATUS
uint32_t FX_ARGB
Definition fx_dib.h:36
#define FXARGB_B(argb)
Definition fx_dib.h:199
#define FXARGB_G(argb)
Definition fx_dib.h:198
#define FXARGB_A(argb)
Definition fx_dib.h:196
#define FXARGB_R(argb)
Definition fx_dib.h:197
FXDIB_Format
Definition fx_dib.h:21
UNSAFE_BUFFER_USAGE void * FXSYS_memset(void *ptr1, int val, size_t len)
#define FX_FILESIZE
Definition fx_types.h:19
#define NOTREACHED_NORETURN()
Definition notreached.h:22
#define CHECK(cvref)