Commit 8319e7a6 authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Support BI_JPEG and BI_PNG compression formats for BMP.

Bug: 552274
Change-Id: Ieaef52c738965861b31fde06ee9b2d5c9a95f967
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1777120Reviewed-by: default avatarLeon Scroggins <scroggo@chromium.org>
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Auto-Submit: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#692143}
parent d44b8bec
......@@ -30,6 +30,9 @@
#include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.h"
#include "third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h"
#include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"
namespace {
// See comments on lookup_table_addresses_ in the header.
......@@ -78,6 +81,15 @@ BMPImageReader::BMPImageReader(ImageDecoder* parent,
memset(&info_header_, 0, sizeof(info_header_));
}
BMPImageReader::~BMPImageReader() = default;
void BMPImageReader::SetData(SegmentReader* data) {
data_ = data;
fast_reader_.SetData(data);
if (alternate_decoder_)
alternate_decoder_->SetData(data_.get(), parent_->IsAllDataReceived());
}
bool BMPImageReader::DecodeBMP(bool only_size) {
// Defensively clear the FastSharedBufferReader's cache, as another caller
// may have called SharedBuffer::MergeSegmentsIntoBuffer().
......@@ -97,7 +109,10 @@ bool BMPImageReader::DecodeBMP(bool only_size) {
// space is as well. Unfortunately, since the profile appears after
// everything else, this may delay processing until all data is received.
// Luckily, few BMPs have an embedded color profile.
if (info_header_.profile_data && !ProcessEmbeddedColorProfile())
const bool use_alternate_decoder =
(info_header_.compression == JPEG) || (info_header_.compression == PNG);
if (!use_alternate_decoder && info_header_.profile_data &&
!ProcessEmbeddedColorProfile())
return false;
// Set our size if we haven't already. In ICO files, IsDecodedSizeAvailable()
......@@ -111,6 +126,9 @@ bool BMPImageReader::DecodeBMP(bool only_size) {
if (only_size)
return true;
if (use_alternate_decoder)
return DecodeAlternateFormat();
// Read and process the bitmasks, if needed.
if (need_to_process_bitmasks_ && !ProcessBitmasks())
return false;
......@@ -463,8 +481,9 @@ bool BMPImageReader::IsInfoHeaderValid() const {
case JPEG:
case PNG:
// Only valid for Windows V3+.
if (is_os21x_ || is_os22x_ || info_header_.bit_count)
// Only valid for Windows V3+. We don't support embedding these inside
// ICO files.
if (is_os21x_ || is_os22x_ || info_header_.bit_count || !img_data_offset_)
return false;
break;
......@@ -491,24 +510,51 @@ bool BMPImageReader::IsInfoHeaderValid() const {
// decoding. Few other people decode these either, they're unlikely to be
// in much use.
// TODO(pkasting): Consider supporting these someday.
// * Bitmaps larger than 2^16 pixels in either dimension (Windows
// probably doesn't draw these well anyway, and the decoded data would
// take a lot of memory).
// * Bitmaps larger than 2^16 pixels in either dimension.
if ((info_header_.width >= (1 << 16)) || (info_header_.height >= (1 << 16)))
return false;
// * Windows V3+ JPEG-in-BMP and PNG-in-BMP bitmaps (supposedly not found
// in the wild, only used to send data to printers?).
if ((info_header_.compression == JPEG) || (info_header_.compression == PNG))
return false;
// * OS/2 2.x Huffman-encoded monochrome bitmaps (see
// http://www.fileformat.info/mirror/egff/ch09_05.htm , re: "G31D"
// algorithm).
// algorithm; this seems to be used in TIFF files as well).
if (info_header_.compression == HUFFMAN1D)
return false;
return true;
}
bool BMPImageReader::DecodeAlternateFormat() {
// Create decoder if necessary.
if (!alternate_decoder_) {
if (info_header_.compression == JPEG) {
alternate_decoder_ = std::make_unique<JPEGImageDecoder>(
parent_->GetAlphaOption(), parent_->GetColorBehavior(),
parent_->GetMaxDecodedBytes(), img_data_offset_);
} else {
alternate_decoder_ = std::make_unique<PNGImageDecoder>(
parent_->GetAlphaOption(), ImageDecoder::kDefaultBitDepth,
parent_->GetColorBehavior(), parent_->GetMaxDecodedBytes(),
img_data_offset_);
}
alternate_decoder_->SetData(data_.get(), parent_->IsAllDataReceived());
}
// Decode the image.
if (alternate_decoder_->IsSizeAvailable()) {
if (alternate_decoder_->Size() != parent_->Size())
return parent_->SetFailed();
alternate_decoder_->SetMemoryAllocator(buffer_->GetAllocator());
const auto* frame = alternate_decoder_->DecodeFrameBufferAtIndex(0);
alternate_decoder_->SetMemoryAllocator(nullptr);
if (frame)
*buffer_ = *frame;
}
return alternate_decoder_->Failed()
? parent_->SetFailed()
: (buffer_->GetStatus() == ImageFrame::kFrameComplete);
}
bool BMPImageReader::ProcessEmbeddedColorProfile() {
// Ensure we have received the whole profile.
if ((info_header_.profile_data > data_->size()) ||
......
......@@ -64,12 +64,10 @@ class PLATFORM_EXPORT BMPImageReader final {
size_t decoded_and_header_offset,
size_t img_data_offset,
bool is_in_ico);
~BMPImageReader();
void SetBuffer(ImageFrame* buffer) { buffer_ = buffer; }
void SetData(SegmentReader* data) {
data_ = data;
fast_reader_.SetData(data);
}
void SetData(SegmentReader* data);
// Does the actual decoding. If |only_size| is true, decoding only
// progresses as far as necessary to get the image size. Returns
......@@ -182,6 +180,9 @@ class PLATFORM_EXPORT BMPImageReader final {
// Processes any embedded ICC color profile.
bool ProcessEmbeddedColorProfile();
// Decodes the image data for compression types JPEG and PNG.
bool DecodeAlternateFormat();
// For BI_[ALPHA]BITFIELDS images, initializes the bit_masks_[] and
// bit_offsets_[] arrays. ProcessInfoHeader() will initialize these for
// other compression types where needed.
......@@ -335,6 +336,9 @@ class PLATFORM_EXPORT BMPImageReader final {
// The BMP info header.
BitmapInfoHeader info_header_;
// Used only for bitmaps with compression types JPEG or PNG.
std::unique_ptr<ImageDecoder> alternate_decoder_;
// True if this is an OS/2 1.x (aka Windows 2.x) BMP. The struct
// layouts for this type of BMP are slightly different from the later,
// more common formats.
......
......@@ -47,11 +47,7 @@ ICOImageDecoder::ICOImageDecoder(AlphaOption alpha_option,
: ImageDecoder(alpha_option,
ImageDecoder::kDefaultBitDepth,
color_behavior,
max_decoded_bytes),
fast_reader_(nullptr),
decoded_offset_(0),
dir_entries_count_(0),
color_behavior_(color_behavior) {}
max_decoded_bytes) {}
ICOImageDecoder::~ICOImageDecoder() = default;
......
......@@ -147,12 +147,12 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder {
// if the type could be determined.
ImageType ImageTypeAtIndex(size_t);
FastSharedBufferReader fast_reader_;
FastSharedBufferReader fast_reader_{nullptr};
// An index into |data_| representing how much we've already decoded.
// Note that this only tracks data _this_ class decodes; once the
// BMPImageReader takes over this will not be updated further.
size_t decoded_offset_;
size_t decoded_offset_ = 0;
// Which type of file (ICO/CUR) this is.
FileType file_type_;
......@@ -164,7 +164,7 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder {
// Count of directory entries is parsed from header before initializing
// dir_entries_. dir_entries_ is populated only when full header
// information including directory entries is available.
size_t dir_entries_count_;
size_t dir_entries_count_ = 0;
// The image decoders for the various frames.
typedef Vector<std::unique_ptr<BMPImageReader>> BMPReaders;
......@@ -176,9 +176,6 @@ class PLATFORM_EXPORT ICOImageDecoder final : public ImageDecoder {
// for the particular entry being decoded.
IntSize frame_size_;
// Used to pass on to an internally created PNG decoder.
const ColorBehavior color_behavior_;
DISALLOW_COPY_AND_ASSIGN(ICOImageDecoder);
};
......
......@@ -320,6 +320,8 @@ class PLATFORM_EXPORT ImageDecoder {
return premultiply_alpha_ ? kAlphaPremultiplied : kAlphaNotPremultiplied;
}
size_t GetMaxDecodedBytes() const { return max_decoded_bytes_; }
// Sets the "decode failure" flag. For caller convenience (since so
// many callers want to return false after calling this), returns false
// to enable easy tailcalling. Subclasses may override this to also
......
......@@ -340,11 +340,11 @@ class JPEGImageReader final {
USING_FAST_MALLOC(JPEGImageReader);
public:
JPEGImageReader(JPEGImageDecoder* decoder)
JPEGImageReader(JPEGImageDecoder* decoder, size_t initial_offset)
: decoder_(decoder),
needs_restart_(false),
restart_position_(0),
next_read_position_(0),
restart_position_(initial_offset),
next_read_position_(initial_offset),
last_set_byte_(nullptr),
state_(JPEG_HEADER),
samples_(nullptr) {
......@@ -854,11 +854,13 @@ void term_source(j_decompress_ptr jd) {
JPEGImageDecoder::JPEGImageDecoder(AlphaOption alpha_option,
const ColorBehavior& color_behavior,
size_t max_decoded_bytes)
size_t max_decoded_bytes,
size_t offset)
: ImageDecoder(alpha_option,
ImageDecoder::kDefaultBitDepth,
color_behavior,
max_decoded_bytes) {}
max_decoded_bytes),
offset_(offset) {}
JPEGImageDecoder::~JPEGImageDecoder() = default;
......@@ -1184,7 +1186,7 @@ void JPEGImageDecoder::Decode(bool only_size) {
return;
if (!reader_) {
reader_ = std::make_unique<JPEGImageReader>(this);
reader_ = std::make_unique<JPEGImageReader>(this, offset_);
reader_->SetData(data_.get());
}
......
......@@ -36,7 +36,10 @@ class JPEGImageReader;
class PLATFORM_EXPORT JPEGImageDecoder final : public ImageDecoder {
public:
JPEGImageDecoder(AlphaOption, const ColorBehavior&, size_t max_decoded_bytes);
JPEGImageDecoder(AlphaOption,
const ColorBehavior&,
size_t max_decoded_bytes,
size_t offset = 0);
~JPEGImageDecoder() override;
// ImageDecoder:
......@@ -79,6 +82,7 @@ class PLATFORM_EXPORT JPEGImageDecoder final : public ImageDecoder {
void Decode(bool only_size);
std::unique_ptr<JPEGImageReader> reader_;
const size_t offset_;
std::unique_ptr<ImagePlanes> image_planes_;
IntSize decoded_size_;
Vector<SkISize> supported_decode_sizes_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment