mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Avoid depending on STB in //flutter/impeller/image. (flutter/engine#47)
This commit is contained in:
parent
85f5829abb
commit
f5f03da988
@ -5,14 +5,19 @@
|
||||
import("//flutter/impeller/tools/impeller.gni")
|
||||
|
||||
impeller_component("image") {
|
||||
sources = [
|
||||
"compressed_image.cc",
|
||||
public = [
|
||||
"compressed_image.h",
|
||||
"decompressed_image.cc",
|
||||
"decompressed_image.h",
|
||||
]
|
||||
|
||||
deps = [ "../third_party/stb" ]
|
||||
sources = [
|
||||
"backends/skia/compressed_image_skia.cc",
|
||||
"backends/skia/compressed_image_skia.h",
|
||||
"compressed_image.cc",
|
||||
"decompressed_image.cc",
|
||||
]
|
||||
|
||||
deps = [ "//third_party/skia" ]
|
||||
|
||||
public_deps = [
|
||||
"../base",
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
// 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/backends/skia/compressed_image_skia.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "impeller/base/validation.h"
|
||||
#include "third_party/skia/include/core/SkData.h"
|
||||
#include "third_party/skia/include/core/SkImageGenerator.h"
|
||||
#include "third_party/skia/include/core/SkPixmap.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
CompressedImageSkia::CompressedImageSkia(
|
||||
std::shared_ptr<const fml::Mapping> allocation)
|
||||
: CompressedImage(std::move(allocation)) {}
|
||||
|
||||
CompressedImageSkia::~CompressedImageSkia() = default;
|
||||
|
||||
// |CompressedImage|
|
||||
DecompressedImage CompressedImageSkia::Decode() const {
|
||||
if (!IsValid()) {
|
||||
return {};
|
||||
}
|
||||
if (source_->GetSize() == 0u) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto src = new std::shared_ptr<const fml::Mapping>(source_);
|
||||
auto sk_data = SkData::MakeWithProc(
|
||||
source_->GetMapping(), source_->GetSize(),
|
||||
[](const void* ptr, void* context) {
|
||||
delete reinterpret_cast<decltype(src)>(context);
|
||||
},
|
||||
src);
|
||||
|
||||
auto generator = SkImageGenerator::MakeFromEncoded(sk_data);
|
||||
if (!generator) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto info = SkImageInfo::MakeN32Premul(generator->getInfo().dimensions());
|
||||
|
||||
auto bitmap = std::make_shared<SkBitmap>();
|
||||
if (!bitmap->tryAllocPixels(info)) {
|
||||
VALIDATION_LOG << "Could not allocate arena for decompressing image.";
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!generator->getPixels(bitmap->pixmap())) {
|
||||
VALIDATION_LOG << "Could not decompress image into arena.";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto mapping = std::make_shared<fml::NonOwnedMapping>(
|
||||
reinterpret_cast<const uint8_t*>(bitmap->pixmap().addr()), // data
|
||||
bitmap->pixmap().rowBytes() * bitmap->pixmap().height(), // size
|
||||
[bitmap](const uint8_t* data, size_t size) mutable {
|
||||
bitmap.reset();
|
||||
} // proc
|
||||
);
|
||||
|
||||
return {
|
||||
{bitmap->pixmap().dimensions().fWidth,
|
||||
bitmap->pixmap().dimensions().fHeight}, // size
|
||||
DecompressedImage::Format::kRGBA, // format
|
||||
mapping // allocation
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,25 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/image/compressed_image.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class CompressedImageSkia final : public CompressedImage {
|
||||
public:
|
||||
CompressedImageSkia(std::shared_ptr<const fml::Mapping> allocation);
|
||||
|
||||
~CompressedImageSkia() override;
|
||||
|
||||
// |CompressedImage|
|
||||
DecompressedImage Decode() const override;
|
||||
|
||||
private:
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CompressedImageSkia);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -4,83 +4,24 @@
|
||||
|
||||
#include "impeller/image/compressed_image.h"
|
||||
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/image/backends/skia/compressed_image_skia.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
CompressedImage::CompressedImage(
|
||||
std::shared_ptr<const fml::Mapping> sourceAllocation)
|
||||
: source_(std::move(sourceAllocation)) {}
|
||||
std::shared_ptr<CompressedImage> CompressedImage::Create(
|
||||
std::shared_ptr<const fml::Mapping> allocation) {
|
||||
// There is only one backend today.
|
||||
if (!allocation) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<CompressedImageSkia>(std::move(allocation));
|
||||
}
|
||||
|
||||
CompressedImage::CompressedImage(std::shared_ptr<const fml::Mapping> allocation)
|
||||
: source_(std::move(allocation)) {}
|
||||
|
||||
CompressedImage::~CompressedImage() = default;
|
||||
|
||||
DecompressedImage CompressedImage::Decode() const {
|
||||
if (!source_) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int comps = 0;
|
||||
|
||||
stbi_uc* decoded =
|
||||
::stbi_load_from_memory(source_->GetMapping(), // Source Data
|
||||
source_->GetSize(), // Source Data Size
|
||||
&width, // Out: Width
|
||||
&height, // Out: Height
|
||||
&comps, // Out: Components
|
||||
STBI_default);
|
||||
|
||||
if (decoded == nullptr) {
|
||||
VALIDATION_LOG << "Could not decode image from host memory.";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto dest_allocation = std::make_shared<const fml::NonOwnedMapping>(
|
||||
decoded, // bytes
|
||||
width * height * comps * sizeof(stbi_uc), // byte size
|
||||
[](const uint8_t* data, size_t size) {
|
||||
::stbi_image_free(const_cast<uint8_t*>(data));
|
||||
} // release proc
|
||||
);
|
||||
|
||||
/*
|
||||
* Make sure we got a valid component set.
|
||||
*/
|
||||
auto components = DecompressedImage::Format::kInvalid;
|
||||
|
||||
switch (comps) {
|
||||
case STBI_grey:
|
||||
components = DecompressedImage::Format::kGrey;
|
||||
break;
|
||||
case STBI_grey_alpha:
|
||||
components = DecompressedImage::Format::kGreyAlpha;
|
||||
break;
|
||||
case STBI_rgb:
|
||||
components = DecompressedImage::Format::kRGB;
|
||||
break;
|
||||
case STBI_rgb_alpha:
|
||||
components = DecompressedImage::Format::kRGBA;
|
||||
break;
|
||||
default:
|
||||
components = DecompressedImage::Format::kInvalid;
|
||||
break;
|
||||
}
|
||||
|
||||
if (components == DecompressedImage::Format::kInvalid) {
|
||||
VALIDATION_LOG << "Could not detect image components when decoding.";
|
||||
return {};
|
||||
}
|
||||
|
||||
return DecompressedImage{
|
||||
ISize{width, height}, // size
|
||||
components, // components
|
||||
std::move(dest_allocation) // allocation
|
||||
};
|
||||
}
|
||||
|
||||
bool CompressedImage::IsValid() const {
|
||||
return static_cast<bool>(source_);
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "impeller/geometry/size.h"
|
||||
@ -15,16 +17,19 @@ class ImageSource;
|
||||
|
||||
class CompressedImage {
|
||||
public:
|
||||
CompressedImage(std::shared_ptr<const fml::Mapping> sourceAllocation);
|
||||
static std::shared_ptr<CompressedImage> Create(
|
||||
std::shared_ptr<const fml::Mapping> allocation);
|
||||
|
||||
~CompressedImage();
|
||||
virtual ~CompressedImage();
|
||||
|
||||
[[nodiscard]] DecompressedImage Decode() const;
|
||||
[[nodiscard]] virtual DecompressedImage Decode() const = 0;
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<const fml::Mapping> source_;
|
||||
protected:
|
||||
const std::shared_ptr<const fml::Mapping> source_;
|
||||
|
||||
CompressedImage(std::shared_ptr<const fml::Mapping> allocation);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -195,14 +195,18 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) {
|
||||
|
||||
std::shared_ptr<Texture> Playground::CreateTextureForFixture(
|
||||
const char* fixture_name) const {
|
||||
CompressedImage compressed_image(
|
||||
auto compressed_image = CompressedImage::Create(
|
||||
flutter::testing::OpenFixtureAsMapping(fixture_name));
|
||||
if (!compressed_image) {
|
||||
VALIDATION_LOG << "Could not create compressed image.";
|
||||
return nullptr;
|
||||
}
|
||||
// The decoded image is immediately converted into RGBA as that format is
|
||||
// known to be supported everywhere. For image sources that don't need 32
|
||||
// bit pixel strides, this is overkill. Since this is a test fixture we
|
||||
// aren't necessarily trying to eke out memory savings here and instead
|
||||
// favor simplicity.
|
||||
auto image = compressed_image.Decode().ConvertToRGBA();
|
||||
auto image = compressed_image->Decode().ConvertToRGBA();
|
||||
if (!image.IsValid()) {
|
||||
VALIDATION_LOG << "Could not find fixture named " << fixture_name;
|
||||
return nullptr;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user