未验证 提交 28e9e0f2 编写于 作者: J Jason Simmons 提交者: GitHub

Create images from uncompressed pixel data (#5550)

Fixes https://github.com/flutter/flutter/issues/9184
上级 525dc188
......@@ -1367,6 +1367,26 @@ enum ImageByteFormat {
png,
}
/// The format of pixel data given to [decodeImageFromPixels].
enum PixelFormat {
/// Each pixel is 32 bits, with the highest 8 bits encoding red, the next 8
/// bits encoding green, the next 8 bits encoding blue, and the lowest 8 bits
/// encoding alpha.
rgba8888,
/// Each pixel is 32 bits, with the highest 8 bits encoding blue, the next 8
/// bits encoding green, the next 8 bits encoding red, and the lowest 8 bits
/// encoding alpha.
bgra8888,
}
class _ImageInfo {
_ImageInfo(this.width, this.height, this.format);
int width;
int height;
int format;
}
/// Opaque handle to raw decoded image data (pixels).
///
/// To obtain an [Image] object, use [instantiateImageCodec].
......@@ -1481,14 +1501,14 @@ class Codec extends NativeFieldWrapperClass2 {
/// failed.
Future<Codec> instantiateImageCodec(Uint8List list) {
return _futurize(
(_Callback<Codec> callback) => _instantiateImageCodec(list, callback)
(_Callback<Codec> callback) => _instantiateImageCodec(list, callback, null)
);
}
/// Instantiates a [Codec] object for an image binary data.
///
/// Returns an error message if the instantiation has failed, null otherwise.
String _instantiateImageCodec(Uint8List list, _Callback<Codec> callback)
String _instantiateImageCodec(Uint8List list, _Callback<Codec> callback, _ImageInfo imageInfo)
native 'instantiateImageCodec';
/// Loads a single image frame from a byte array into an [Image] object.
......@@ -1499,12 +1519,31 @@ void decodeImageFromList(Uint8List list, ImageDecoderCallback callback) {
_decodeImageFromListAsync(list, callback);
}
Future<Null> _decodeImageFromListAsync(Uint8List list, ImageDecoderCallback callback) async {
Future<Null> _decodeImageFromListAsync(Uint8List list,
ImageDecoderCallback callback) async {
final Codec codec = await instantiateImageCodec(list);
final FrameInfo frameInfo = await codec.getNextFrame();
callback(frameInfo.image);
}
/// Convert an array of pixel values into an [Image] object.
///
/// [pixels] is the pixel data in the encoding described by [format].
void decodeImageFromPixels(
Uint8List pixels,
int width,
int height,
PixelFormat format,
ImageDecoderCallback callback
) {
final _ImageInfo imageInfo = new _ImageInfo(width, height, format.index);
final Future<Codec> codecFuture = _futurize(
(_Callback<Codec> callback) => _instantiateImageCodec(pixels, callback, imageInfo)
);
codecFuture.then((Codec codec) => codec.getNextFrame())
.then((FrameInfo frameInfo) => callback(frameInfo.image));
}
/// Determines the winding rule that decides how the interior of a [Path] is
/// calculated.
///
......
......@@ -32,6 +32,12 @@ namespace {
static constexpr const char* kInitCodecTraceTag = "InitCodec";
static constexpr const char* kCodecNextFrameTraceTag = "CodecNextFrame";
// This must be kept in sync with the enum in painting.dart
enum PixelFormat {
kRGBA8888,
kBGRA8888,
};
static void InvokeCodecCallback(fxl::RefPtr<Codec> codec,
std::unique_ptr<DartPersistentValue> callback,
size_t trace_id) {
......@@ -104,15 +110,52 @@ fxl::RefPtr<Codec> InitCodec(fml::WeakPtr<GrContext> context,
return fxl::MakeRefCounted<SingleFrameCodec>(std::move(frameInfo));
}
fxl::RefPtr<Codec> InitCodecUncompressed(
fml::WeakPtr<GrContext> context,
sk_sp<SkData> buffer,
SkImageInfo image_info,
fxl::RefPtr<flow::SkiaUnrefQueue> unref_queue,
size_t trace_id) {
TRACE_FLOW_STEP("flutter", kInitCodecTraceTag, trace_id);
TRACE_EVENT0("blink", "InitCodecUncompressed");
if (buffer == nullptr || buffer->isEmpty()) {
FXL_LOG(ERROR) << "InitCodecUncompressed failed - buffer was empty";
return nullptr;
}
sk_sp<SkImage> skImage;
if (context) {
SkPixmap pixmap(image_info, buffer->data(), image_info.minRowBytes());
skImage = SkImage::MakeCrossContextFromPixmap(context.get(), pixmap, false,
nullptr, true);
} else {
skImage = SkImage::MakeRasterData(image_info, std::move(buffer),
image_info.minRowBytes());
}
auto image = CanvasImage::Create();
image->set_image({skImage, unref_queue});
auto frameInfo = fxl::MakeRefCounted<FrameInfo>(std::move(image), 0);
return fxl::MakeRefCounted<SingleFrameCodec>(std::move(frameInfo));
}
void InitCodecAndInvokeCodecCallback(
fxl::RefPtr<fxl::TaskRunner> ui_task_runner,
fml::WeakPtr<GrContext> context,
fxl::RefPtr<flow::SkiaUnrefQueue> unref_queue,
std::unique_ptr<DartPersistentValue> callback,
sk_sp<SkData> buffer,
std::unique_ptr<SkImageInfo> image_info,
size_t trace_id) {
auto codec =
InitCodec(context, std::move(buffer), std::move(unref_queue), trace_id);
fxl::RefPtr<Codec> codec;
if (image_info) {
codec = InitCodecUncompressed(context, std::move(buffer), *image_info,
std::move(unref_queue), trace_id);
} else {
codec =
InitCodec(context, std::move(buffer), std::move(unref_queue), trace_id);
}
ui_task_runner->PostTask(
fxl::MakeCopyable([callback = std::move(callback),
codec = std::move(codec), trace_id]() mutable {
......@@ -120,13 +163,74 @@ void InitCodecAndInvokeCodecCallback(
}));
}
bool ConvertImageInfo(Dart_Handle image_info_handle,
Dart_NativeArguments args,
SkImageInfo* image_info) {
Dart_Handle width_handle = Dart_GetField(image_info_handle, ToDart("width"));
if (!Dart_IsInteger(width_handle)) {
Dart_SetReturnValue(args, ToDart("ImageInfo.width must be an integer"));
return false;
}
Dart_Handle height_handle =
Dart_GetField(image_info_handle, ToDart("height"));
if (!Dart_IsInteger(height_handle)) {
Dart_SetReturnValue(args, ToDart("ImageInfo.height must be an integer"));
return false;
}
Dart_Handle format_handle =
Dart_GetField(image_info_handle, ToDart("format"));
if (!Dart_IsInteger(format_handle)) {
Dart_SetReturnValue(args, ToDart("ImageInfo.format must be an integer"));
return false;
}
PixelFormat pixel_format = static_cast<PixelFormat>(
tonic::DartConverter<int>::FromDart(format_handle));
SkColorType color_type = kUnknown_SkColorType;
switch (pixel_format) {
case kRGBA8888:
color_type = kRGBA_8888_SkColorType;
break;
case kBGRA8888:
color_type = kBGRA_8888_SkColorType;
break;
}
if (color_type == kUnknown_SkColorType) {
Dart_SetReturnValue(args, ToDart("Invalid pixel format"));
return false;
}
*image_info =
SkImageInfo::Make(tonic::DartConverter<int>::FromDart(width_handle),
tonic::DartConverter<int>::FromDart(height_handle),
color_type, kPremul_SkAlphaType);
return true;
}
void InstantiateImageCodec(Dart_NativeArguments args) {
static size_t trace_counter = 1;
const size_t trace_id = trace_counter++;
TRACE_FLOW_BEGIN("flutter", kInitCodecTraceTag, trace_id);
Dart_Handle exception = nullptr;
Dart_Handle callback_handle = Dart_GetNativeArgument(args, 1);
if (!Dart_IsClosure(callback_handle)) {
TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id);
Dart_SetReturnValue(args, ToDart("Callback must be a function"));
return;
}
Dart_Handle image_info_handle = Dart_GetNativeArgument(args, 2);
std::unique_ptr<SkImageInfo> image_info;
if (!Dart_IsNull(image_info_handle)) {
image_info = std::make_unique<SkImageInfo>();
if (!ConvertImageInfo(image_info_handle, args, image_info.get())) {
TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id);
return;
}
}
Dart_Handle exception = nullptr;
tonic::Uint8List list =
tonic::DartConverter<tonic::Uint8List>::FromArguments(args, 0, exception);
if (exception) {
......@@ -135,11 +239,15 @@ void InstantiateImageCodec(Dart_NativeArguments args) {
return;
}
Dart_Handle callback_handle = Dart_GetNativeArgument(args, 1);
if (!Dart_IsClosure(callback_handle)) {
TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id);
Dart_SetReturnValue(args, ToDart("Callback must be a function"));
return;
if (image_info) {
int expected_size = image_info->minRowBytes() * image_info->height();
if (list.num_elements() < expected_size) {
TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id);
list.Release();
Dart_SetReturnValue(
args, ToDart("Pixel buffer size does not match image size"));
return;
}
}
auto buffer = SkData::MakeWithCopy(list.data(), list.num_elements());
......@@ -150,13 +258,14 @@ void InstantiateImageCodec(Dart_NativeArguments args) {
task_runners.GetIOTaskRunner()->PostTask(fxl::MakeCopyable(
[callback = std::make_unique<DartPersistentValue>(
tonic::DartState::Current(), callback_handle),
buffer = std::move(buffer), trace_id,
buffer = std::move(buffer), trace_id, image_info = std::move(image_info),
ui_task_runner = task_runners.GetUITaskRunner(),
context = dart_state->GetResourceContext(),
queue = UIDartState::Current()->GetSkiaUnrefQueue()]() mutable {
InitCodecAndInvokeCodecCallback(std::move(ui_task_runner), context,
std::move(queue), std::move(callback),
std::move(buffer), trace_id);
std::move(buffer),
std::move(image_info), trace_id);
}));
}
......@@ -349,7 +458,7 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) {
void Codec::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({
{"instantiateImageCodec", InstantiateImageCodec, 2, true},
{"instantiateImageCodec", InstantiateImageCodec, 3, true},
});
natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册