blob: c31c184c32961f63711da9fb97900beedeea322c [file] [log] [blame]
// 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