7#include "core/fxcodec/bmp/cfx_bmpdecompressor.h"
15#include "core/fxcodec/bmp/cfx_bmpcontext.h"
16#include "core/fxcodec/cfx_codec_memory.h"
17#include "core/fxcrt/byteorder.h"
18#include "core/fxcrt/compiler_specific.h"
19#include "core/fxcrt/data_vector.h"
20#include "core/fxcrt/fx_safe_types.h"
21#include "core/fxcrt/numerics/safe_math.h"
22#include "core/fxcrt/span_util.h"
23#include "core/fxcrt/stl_util.h"
24#include "core/fxge/calculate_pitch.h"
30constexpr size_t kBmpCoreHeaderSize = 12;
31constexpr size_t kBmpInfoHeaderSize = 40;
34 "BmpCoreHeader has wrong size");
36 "BmpInfoHeader has wrong size");
38constexpr uint16_t kBmpSignature = 0x4D42;
39constexpr uint8_t kRleMarker = 0;
40constexpr uint8_t kRleEol = 0;
41constexpr uint8_t kRleEoi = 1;
42constexpr uint8_t kRleDelta = 2;
43constexpr uint32_t kBmpRgb = 0L;
44constexpr uint32_t kBmpRle8 = 1L;
45constexpr uint32_t kBmpRle4 = 2L;
46constexpr uint32_t kBmpBitfields = 3L;
49constexpr uint32_t kBmpMaxImageDimension = 65535;
51uint8_t HalfRoundUp(uint8_t value) {
52 uint16_t value16 = value;
53 return static_cast<uint8_t>((value16 + 1) / 2);
64 uint32_t row = img_tb_flag_ ? row_num_ : (height_ - 1 - row_num_);
65 context_->m_pDelegate->BmpReadScanline(row, out_row_buffer_);
70 return context_->m_pDelegate->BmpInputImagePositionBuf(rcd_pos);
74 if (decode_status_ == DecodeStatus::kHeader) {
80 if (decode_status_ != DecodeStatus::kPal)
83 if (compress_flag_ == kBmpBitfields)
84 return ReadBmpBitfields();
86 return ReadBmpPalette();
92 pdfium::as_writable_bytes(pdfium::span_from_ref(bmp_header)))) {
99 if (bmp_header
.bfType != kBmpSignature)
102 size_t pos = input_buffer_->GetPosition();
104 pdfium::as_writable_bytes(pdfium::span_from_ref(img_ifh_size_)))) {
107 if (!input_buffer_->Seek(pos))
111 pal_type_ = PalType::kNew;
116 return ReadBmpHeaderDimensions();
120 if (img_ifh_size_ == kBmpCoreHeaderSize) {
121 pal_type_ = PalType::kOld;
123 if (!ReadAllOrNone(pdfium::as_writable_bytes(
124 pdfium::span_from_ref(bmp_core_header)))) {
131 compress_flag_ = kBmpRgb;
132 img_tb_flag_ =
false;
136 if (img_ifh_size_ == kBmpInfoHeaderSize) {
138 if (!ReadAllOrNone(pdfium::as_writable_bytes(
139 pdfium::span_from_ref(bmp_info_header)))) {
153 if (!SetHeight(signed_height)) {
162 FX_SAFE_SIZE_T new_pos = input_buffer_->GetPosition();
165 pdfium::as_writable_bytes(pdfium::span_from_ref(bmp_info_header)))) {
169 new_pos += img_ifh_size_;
170 if (!new_pos.IsValid())
173 if (!input_buffer_->Seek(new_pos.ValueOrDie()))
184 if (!SetHeight(signed_height)) {
188 if (compress_flag_ != kBmpRgb || bi_planes != 1 || color_used_ != 0) {
195 if (width_ > kBmpMaxImageDimension || height_ > kBmpMaxImageDimension ||
196 compress_flag_ > kBmpBitfields) {
200 switch (bit_counts_) {
206 if (color_used_ > 1U << bit_counts_)
215 std::optional<uint32_t> stride = fxge::CalculatePitch32(bit_counts_, width_);
216 if (!stride.has_value())
219 src_row_bytes_ = stride.value();
220 switch (bit_counts_) {
225 if (!stride.has_value())
227 out_row_bytes_ = stride.value();
233 if (!stride.has_value())
235 out_row_bytes_ = stride.value();
239 out_row_bytes_ = src_row_bytes_;
243 out_row_buffer_.clear();
245 if (out_row_bytes_ <= 0)
248 out_row_buffer_.resize(out_row_bytes_);
249 SaveDecodingStatus(DecodeStatus::kPal);
254 if (bit_counts_ != 16 && bit_counts_ != 32)
258 if (!ReadAllOrNone(pdfium::as_writable_byte_span(masks))) {
265 if (mask_red_ & mask_green_ || mask_red_ & mask_blue_ ||
266 mask_green_ & mask_blue_) {
269 header_offset_ =
std::max(header_offset_, 26 + img_ifh_size_);
270 SaveDecodingStatus(DecodeStatus::kDataPre);
275 if (bit_counts_ == 16) {
277 mask_green_ = 0x03E0;
280 uint32_t palette_entries = 0;
281 if (bit_counts_ < 16) {
282 palette_entries = 1 << bit_counts_;
283 if (color_used_ != 0) {
284 palette_entries = color_used_;
286 size_t pal_bytes = palette_entries * PaletteChannelCount();
287 DataVector<uint8_t> src_pal(pal_bytes);
288 if (!ReadAllOrNone(src_pal))
291 palette_.resize(palette_entries);
292 if (pal_type_ == PalType::kOld) {
294 fxcrt::reinterpret_span<FX_BGR_STRUCT<uint8_t>, uint8_t>(src_pal);
295 for (
auto& dest : palette_) {
296 const auto& entry = src_pal_data.front();
297 dest = ArgbEncode(0x00, entry.red, entry.green, entry.blue);
298 src_pal_data = src_pal_data.subspan(1);
302 fxcrt::reinterpret_span<FX_BGRA_STRUCT<uint8_t>, uint8_t>(src_pal);
303 for (
auto& dest : palette_) {
304 const auto& entry = src_pal_data.front();
305 dest = ArgbEncode(entry.alpha, entry.red, entry.green, entry.blue);
306 src_pal_data = src_pal_data.subspan(1);
311 std::max(header_offset_,
312 14 + img_ifh_size_ + palette_entries * PaletteChannelCount());
313 SaveDecodingStatus(DecodeStatus::kDataPre);
318 switch (compress_flag_) {
330 if (decode_status_ == DecodeStatus::kDataPre) {
333 data_offset_ =
std::max(header_offset_, data_offset_);
335 input_buffer_->Seek(input_buffer_->GetSize());
336 if (!GetDataPosition(data_offset_)) {
337 decode_status_ = DecodeStatus::kTail;
342 SaveDecodingStatus(DecodeStatus::kData);
344 if (decode_status_ != DecodeStatus::kData || !ValidateFlag())
347 switch (compress_flag_) {
361 return val < palette_.size();
365 DataVector<uint8_t> dest_buf(src_row_bytes_);
366 while (row_num_ < height_) {
368 if (!ReadAllOrNone(dest_buf))
371 SaveDecodingStatus(DecodeStatus::kData);
372 switch (bit_counts_) {
374 for (uint32_t col = 0; col < width_; ++col) {
376 dest_buf[col >> 3] & (0x80 >> (col % 8)) ? 0x01 : 0x00;
377 if (!ValidateColorIndex(index))
379 out_row_buffer_[idx++] = index;
384 for (uint32_t col = 0; col < width_; ++col) {
385 uint8_t index = (col & 0x01) ? (dest_buf[col >> 1] & 0x0F)
386 : ((dest_buf[col >> 1] & 0xF0) >> 4);
387 if (!ValidateColorIndex(index))
389 out_row_buffer_[idx++] = index;
394 for (uint32_t col = 0; col < width_; ++col) {
395 uint8_t index = dest_buf[col];
396 if (!ValidateColorIndex(index))
398 out_row_buffer_[idx++] = index;
404 fxcrt::reinterpret_span<uint16_t>(pdfium::make_span(dest_buf));
405 uint8_t blue_bits = 0;
406 uint8_t green_bits = 0;
407 uint8_t red_bits = 0;
408 for (int32_t i = 0; i < 16; i++) {
409 if ((mask_blue_ >> i) & 0x01)
411 if ((mask_green_ >> i) & 0x01)
413 if ((mask_red_ >> i) & 0x01)
416 green_bits += blue_bits;
417 red_bits += green_bits;
418 if (blue_bits > 8 || green_bits < 8 || red_bits < 8)
420 blue_bits = 8 - blue_bits;
423 for (uint32_t col = 0; col < width_; ++col) {
425 out_row_buffer_[idx++] =
426 static_cast<uint8_t>((buf.front() & mask_blue_) << blue_bits);
427 out_row_buffer_[idx++] =
428 static_cast<uint8_t>((buf.front() & mask_green_) >> green_bits);
429 out_row_buffer_[idx++] =
430 static_cast<uint8_t>((buf.front() & mask_red_) >> red_bits);
431 buf = buf.subspan(1);
438 fxcrt::Copy(pdfium::make_span(dest_buf).first(src_row_bytes_),
440 idx += src_row_bytes_;
445 SaveDecodingStatus(DecodeStatus::kTail);
453 if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
457 switch (first_part) {
459 if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
463 switch (first_part) {
465 if (row_num_ >= height_) {
466 SaveDecodingStatus(DecodeStatus::kTail);
472 fxcrt::Fill(out_row_buffer_, 0);
473 SaveDecodingStatus(DecodeStatus::kData);
477 if (row_num_ < height_)
479 SaveDecodingStatus(DecodeStatus::kTail);
484 if (!ReadAllOrNone(delta))
487 col_num_ += delta[0];
488 size_t bmp_row_num__next = row_num_ + delta[1];
489 if (col_num_ >= out_row_bytes_ || bmp_row_num__next >= height_)
492 while (row_num_ < bmp_row_num__next) {
493 fxcrt::Fill(out_row_buffer_, 0);
500 pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
501 if (!avail_size ||
static_cast<int32_t>(first_part) > avail_size)
504 size_t second_part_size =
505 first_part & 1 ? first_part + 1 : first_part;
506 DataVector<uint8_t> second_part(second_part_size);
507 if (!ReadAllOrNone(second_part))
510 fxcrt::Copy(pdfium::make_span(second_part).first(first_part),
511 pdfium::make_span(out_row_buffer_).subspan(col_num_));
513 for (size_t i = col_num_; i < col_num_ + first_part; ++i) {
514 if (!ValidateColorIndex(out_row_buffer_[i]))
517 col_num_ += first_part;
524 pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
525 if (!avail_size ||
static_cast<int32_t>(first_part) > avail_size)
529 if (!ReadAllOrNone(pdfium::span_from_ref(second_part))) {
534 pdfium::make_span(out_row_buffer_).subspan(col_num_, first_part),
537 if (!ValidateColorIndex(out_row_buffer_[col_num_]))
539 col_num_ += first_part;
549 if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
553 switch (first_part) {
555 if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
559 switch (first_part) {
561 if (row_num_ >= height_) {
562 SaveDecodingStatus(DecodeStatus::kTail);
568 fxcrt::Fill(out_row_buffer_, 0);
569 SaveDecodingStatus(DecodeStatus::kData);
573 if (row_num_ < height_)
575 SaveDecodingStatus(DecodeStatus::kTail);
580 if (!ReadAllOrNone(delta))
583 col_num_ += delta[0];
584 size_t bmp_row_num__next = row_num_ + delta[1];
585 if (col_num_ >= out_row_bytes_ || bmp_row_num__next >= height_)
588 while (row_num_ < bmp_row_num__next) {
589 fxcrt::Fill(out_row_buffer_, 0);
596 pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
599 uint8_t size = HalfRoundUp(first_part);
600 if (
static_cast<int32_t>(first_part) > avail_size) {
601 if (size + (col_num_ >> 1) > src_row_bytes_)
604 first_part = avail_size - 1;
606 size_t second_part_size = size & 1 ? size + 1 : size;
607 DataVector<uint8_t> second_part(second_part_size);
608 uint8_t* second_part_data = second_part.data();
609 if (!ReadAllOrNone(second_part))
612 for (uint8_t i = 0; i < first_part; i++) {
613 uint8_t color = (i & 0x01)
615 : (*second_part_data & 0xF0) >> 4;
616 if (!ValidateColorIndex(color)) {
619 out_row_buffer_[col_num_++] = color;
627 pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
631 if (
static_cast<int32_t>(first_part) > avail_size) {
632 uint8_t size = HalfRoundUp(first_part);
633 if (size + (col_num_ >> 1) > src_row_bytes_)
636 first_part = avail_size - 1;
639 if (!ReadAllOrNone(pdfium::span_from_ref(second_part))) {
643 for (uint8_t i = 0; i < first_part; i++) {
644 uint8_t second_byte = second_part;
646 i & 0x01 ? (second_byte & 0x0F) : (second_byte & 0xF0) >> 4;
647 if (!ValidateColorIndex(second_byte))
650 out_row_buffer_[col_num_++] = second_byte;
661 size_t original_position = input_buffer_->GetPosition();
662 size_t read = input_buffer_->ReadBlock(buf);
663 if (read < buf.size()) {
664 input_buffer_->Seek(original_position);
672 decode_status_ = status;
676 RetainPtr<CFX_CodecMemory> codec_memory) {
677 input_buffer_ = std::move(codec_memory);
684 return input_buffer_->GetSize() - input_buffer_->GetPosition();
688 if (signed_height >= 0) {
689 height_ = signed_height;
692 if (signed_height !=
std::numeric_limits<
int>::min()) {
693 height_ = -signed_height;
FX_FILESIZE GetAvailInput() const
BmpDecoder::Status DecodeImage()
CFX_BmpDecompressor(const CFX_BmpContext *context)
BmpDecoder::Status ReadHeader()
void SetInputBuffer(RetainPtr< CFX_CodecMemory > codec_memory)
uint32_t FromLE32(uint32_t x)
uint16_t FromLE16(uint16_t x)
std::optional< uint32_t > CalculatePitch32(int bits_per_pixel, int width_in_pixels)