| // Copyright 2016 The PDFium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| #include "core/fpdfapi/page/cpdf_transferfuncdib.h" | |
| #include <utility> | |
| #include "build/build_config.h" | |
| #include "core/fxcrt/check.h" | |
| #include "core/fxcrt/zip.h" | |
| #include "core/fxge/calculate_pitch.h" | |
| #if defined(PDF_USE_SKIA) | |
| #include "core/fxcrt/notreached.h" | |
| #endif | |
| namespace { | |
| CFX_DIBBase::kPlatformRGBStruct MakePlatformRGBStruct(uint8_t red, | |
| uint8_t green, | |
| uint8_t blue) { | |
| // Note that the return value may have an alpha value that will be set to 0. | |
| return { | |
| .blue = blue, | |
| .green = green, | |
| .red = red, | |
| }; | |
| } | |
| } // namespace | |
| CPDF_TransferFuncDIB::CPDF_TransferFuncDIB( | |
| RetainPtr<const CFX_DIBBase> src, | |
| RetainPtr<CPDF_TransferFunc> transfer_func) | |
| : src_(std::move(src)), | |
| transfer_func_(std::move(transfer_func)), | |
| r_samples_(transfer_func_->GetSamplesR()), | |
| g_samples_(transfer_func_->GetSamplesG()), | |
| b_samples_(transfer_func_->GetSamplesB()) { | |
| SetWidth(src_->GetWidth()); | |
| SetHeight(src_->GetHeight()); | |
| SetFormat(GetDestFormat()); | |
| SetPitch(fxge::CalculatePitch32OrDie(GetBPP(), GetWidth())); | |
| scanline_.resize(GetPitch()); | |
| CHECK(!HasPalette()); | |
| } | |
| CPDF_TransferFuncDIB::~CPDF_TransferFuncDIB() = default; | |
| FXDIB_Format CPDF_TransferFuncDIB::GetDestFormat() const { | |
| if (src_->IsMaskFormat()) { | |
| return FXDIB_Format::k8bppMask; | |
| } | |
| if (src_->IsAlphaFormat()) { | |
| // TODO(crbug.com/355676038): Consider adding support for | |
| // `FXDIB_Format::kBgraPremul` | |
| return FXDIB_Format::kBgra; | |
| } | |
| return CFX_DIBBase::kPlatformRGBFormat; | |
| } | |
| void CPDF_TransferFuncDIB::TranslateScanline( | |
| pdfium::span<const uint8_t> src_span) const { | |
| auto scanline_span = pdfium::span(scanline_); | |
| switch (src_->GetFormat()) { | |
| case FXDIB_Format::kInvalid: { | |
| break; | |
| } | |
| case FXDIB_Format::k1bppRgb: { | |
| const auto color0 = | |
| MakePlatformRGBStruct(r_samples_[0], g_samples_[0], b_samples_[0]); | |
| const auto color1 = MakePlatformRGBStruct( | |
| r_samples_[255], g_samples_[255], b_samples_[255]); | |
| auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span); | |
| for (int i = 0; i < GetWidth(); i++) { | |
| const bool is_on = (src_span[i / 8] & (1 << (7 - i % 8))); | |
| dest[i] = is_on ? color1 : color0; | |
| } | |
| break; | |
| } | |
| case FXDIB_Format::k1bppMask: { | |
| const int m0 = r_samples_[0]; | |
| const int m1 = r_samples_[255]; | |
| for (int i = 0; i < GetWidth(); i++) { | |
| const bool is_on = (src_span[i / 8] & (1 << (7 - i % 8))); | |
| scanline_[i] = is_on ? m1 : m0; | |
| } | |
| break; | |
| } | |
| case FXDIB_Format::k8bppRgb: { | |
| pdfium::span<const uint32_t> src_palette = src_->GetPaletteSpan(); | |
| auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span); | |
| auto zip = | |
| fxcrt::Zip(src_span.first(static_cast<size_t>(GetWidth())), dest); | |
| if (src_->HasPalette()) { | |
| for (auto [input, output] : zip) { | |
| const FX_ARGB src_argb = src_palette[input]; | |
| output = MakePlatformRGBStruct(r_samples_[FXARGB_B(src_argb)], | |
| g_samples_[FXARGB_G(src_argb)], | |
| b_samples_[FXARGB_R(src_argb)]); | |
| } | |
| } else { | |
| for (auto [input, output] : zip) { | |
| output = MakePlatformRGBStruct(r_samples_[input], g_samples_[input], | |
| b_samples_[input]); | |
| } | |
| } | |
| break; | |
| } | |
| case FXDIB_Format::k8bppMask: { | |
| for (auto [input, output] : | |
| fxcrt::Zip(src_span.first(static_cast<size_t>(GetWidth())), | |
| scanline_span)) { | |
| output = r_samples_[input]; | |
| } | |
| break; | |
| } | |
| case FXDIB_Format::kBgr: { | |
| auto src = | |
| fxcrt::reinterpret_span<const FX_BGR_STRUCT<uint8_t>>(src_span); | |
| auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span); | |
| for (auto [input, output] : | |
| fxcrt::Zip(src.first(static_cast<size_t>(GetWidth())), dest)) { | |
| output = MakePlatformRGBStruct(r_samples_[input.red], | |
| g_samples_[input.green], | |
| b_samples_[input.blue]); | |
| } | |
| break; | |
| } | |
| case FXDIB_Format::kBgrx: { | |
| auto src = | |
| fxcrt::reinterpret_span<const FX_BGRA_STRUCT<uint8_t>>(src_span); | |
| auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span); | |
| for (auto [input, output] : | |
| fxcrt::Zip(src.first(static_cast<size_t>(GetWidth())), dest)) { | |
| output = MakePlatformRGBStruct(r_samples_[input.red], | |
| g_samples_[input.green], | |
| b_samples_[input.blue]); | |
| } | |
| break; | |
| } | |
| case FXDIB_Format::kBgra: { | |
| auto src = | |
| fxcrt::reinterpret_span<const FX_BGRA_STRUCT<uint8_t>>(src_span); | |
| auto dest = | |
| fxcrt::reinterpret_span<FX_BGRA_STRUCT<uint8_t>>(scanline_span); | |
| for (auto [input, output] : | |
| fxcrt::Zip(src.first(static_cast<size_t>(GetWidth())), dest)) { | |
| output = { | |
| .blue = b_samples_[input.blue], | |
| .green = g_samples_[input.green], | |
| .red = r_samples_[input.red], | |
| .alpha = input.alpha, | |
| }; | |
| } | |
| break; | |
| } | |
| #if defined(PDF_USE_SKIA) | |
| case FXDIB_Format::kBgraPremul: { | |
| // TODO(crbug.com/355676038): Consider adding support for | |
| // `FXDIB_Format::kBgraPremul` | |
| NOTREACHED(); | |
| } | |
| #endif | |
| } | |
| } | |
| pdfium::span<const uint8_t> CPDF_TransferFuncDIB::GetScanline(int line) const { | |
| TranslateScanline(src_->GetScanline(line)); | |
| return scanline_; | |
| } |