| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "impeller/image/decompressed_image.h" |
| |
| #include <limits> |
| |
| #include "flutter/fml/mapping.h" |
| #include "impeller/base/allocation.h" |
| |
| namespace impeller { |
| |
| DecompressedImage::DecompressedImage() = default; |
| |
| DecompressedImage::DecompressedImage( |
| ISize size, |
| Format format, |
| std::shared_ptr<const fml::Mapping> allocation) |
| : size_(size), format_(format), allocation_(std::move(allocation)) { |
| if (!allocation_ || !size.IsPositive() || format_ == Format::kInvalid) { |
| return; |
| } |
| is_valid_ = true; |
| } |
| |
| DecompressedImage::~DecompressedImage() = default; |
| |
| bool DecompressedImage::IsValid() const { |
| return is_valid_; |
| } |
| |
| const ISize& DecompressedImage::GetSize() const { |
| return size_; |
| } |
| |
| DecompressedImage::Format DecompressedImage::GetFormat() const { |
| return format_; |
| } |
| |
| const std::shared_ptr<const fml::Mapping>& DecompressedImage::GetAllocation() |
| const { |
| return allocation_; |
| } |
| |
| static size_t GetBytesPerPixel(DecompressedImage::Format format) { |
| switch (format) { |
| case DecompressedImage::Format::kInvalid: |
| return 0u; |
| case DecompressedImage::Format::kGrey: |
| return 1u; |
| case DecompressedImage::Format::kGreyAlpha: |
| return 1u; |
| case DecompressedImage::Format::kRGB: |
| return 3u; |
| case DecompressedImage::Format::kRGBA: |
| return 4; |
| } |
| return 0u; |
| } |
| |
| DecompressedImage DecompressedImage::ConvertToRGBA() const { |
| if (!is_valid_) { |
| return {}; |
| } |
| |
| if (format_ == Format::kRGBA) { |
| return DecompressedImage{size_, format_, allocation_}; |
| } |
| |
| const auto bpp = GetBytesPerPixel(format_); |
| const auto source_byte_size = size_.Area() * bpp; |
| if (allocation_->GetSize() < source_byte_size) { |
| return {}; |
| } |
| |
| auto rgba_allocation = std::make_shared<Allocation>(); |
| if (!rgba_allocation->Truncate(size_.Area() * 4u, false)) { |
| return {}; |
| } |
| |
| const uint8_t* source = allocation_->GetMapping(); |
| uint8_t* dest = rgba_allocation->GetBuffer(); |
| |
| for (size_t i = 0, j = 0; i < source_byte_size; i += bpp, j += 4u) { |
| switch (format_) { |
| case DecompressedImage::Format::kGrey: |
| dest[j + 0] = source[i]; |
| dest[j + 1] = source[i]; |
| dest[j + 2] = source[i]; |
| dest[j + 3] = std::numeric_limits<uint8_t>::max(); |
| break; |
| case DecompressedImage::Format::kGreyAlpha: |
| dest[j + 0] = std::numeric_limits<uint8_t>::max(); |
| dest[j + 1] = std::numeric_limits<uint8_t>::max(); |
| dest[j + 2] = std::numeric_limits<uint8_t>::max(); |
| dest[j + 3] = source[i]; |
| break; |
| case DecompressedImage::Format::kRGB: |
| dest[j + 0] = source[i + 0]; |
| dest[j + 1] = source[i + 1]; |
| dest[j + 2] = source[i + 2]; |
| dest[j + 3] = std::numeric_limits<uint8_t>::max(); |
| break; |
| case DecompressedImage::Format::kInvalid: |
| case DecompressedImage::Format::kRGBA: |
| // Should never happen. The necessary checks have already been |
| // performed. |
| FML_CHECK(false); |
| break; |
| } |
| } |
| |
| return DecompressedImage{ |
| size_, Format::kRGBA, |
| std::make_shared<fml::NonOwnedMapping>( |
| rgba_allocation->GetBuffer(), // |
| rgba_allocation->GetLength(), // |
| [rgba_allocation](auto, auto) {}) // |
| }; |
| } |
| |
| } // namespace impeller |