Add createImageFromTextureSource method to ui_web (flutter/engine#53483)
Adds createImageFromTextureSource for flutter web, exposed in dart:web_ui. ```dart final ui.Image uiImage = renderer.createImageFromTextureSource(bitmap, width: 150, height: 150, transferOwnership: false); ``` In canvaskit renderer, this will use MakeLazyImageFromTextureSource. In SkWasmRenderer, it will call imageCreateFromTextureSource, which was already implemented in SkWasm for createImageFromImageBitmap to use, but was not exposed in a way that it could be taken advantage of. By default, createImageFromTextureSource will create a copy of the object it is passed, but transferOwnership: true may be specified to allow transferable objects to be transferred to the renderer, avoiding the copy. Fixes: https://github.com/flutter/flutter/issues/150479 Fixes: https://github.com/flutter/flutter/issues/144815
This commit is contained in:
parent
b60c3db4a5
commit
d1e6ca839c
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:js_interop';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
@ -238,6 +239,29 @@ class CanvasKitRenderer implements Renderer {
|
||||
return CkImage(skImage);
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<ui.Image> createImageFromTextureSource(JSAny object,
|
||||
{required int width, required int height, required bool transferOwnership}) async {
|
||||
if (!transferOwnership) {
|
||||
final DomImageBitmap bitmap = await createImageBitmap(object, (x:0, y: 0, width: width, height: height));
|
||||
return createImageFromImageBitmap(bitmap);
|
||||
}
|
||||
final SkImage? skImage = canvasKit.MakeLazyImageFromTextureSourceWithInfo(
|
||||
object,
|
||||
SkPartialImageInfo(
|
||||
width: width.toDouble(),
|
||||
height: height.toDouble(),
|
||||
alphaType: canvasKit.AlphaType.Premul,
|
||||
colorType: canvasKit.ColorType.RGBA_8888,
|
||||
colorSpace: SkColorSpaceSRGB,
|
||||
));
|
||||
|
||||
if (skImage == null) {
|
||||
throw Exception('Failed to convert image bitmap to an SkImage.');
|
||||
}
|
||||
return CkImage(skImage);
|
||||
}
|
||||
|
||||
@override
|
||||
void decodeImageFromPixels(Uint8List pixels, int width, int height,
|
||||
ui.PixelFormat format, ui.ImageDecoderCallback callback,
|
||||
|
@ -371,4 +371,9 @@ class HtmlRenderer implements Renderer {
|
||||
imageElement.src = await canvas.toDataUrl();
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<ui.Image> createImageFromTextureSource(JSAny object, { required int width, required int height, required bool transferOwnership }) {
|
||||
throw Exception('Not implemented for HTML renderer');
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:js_interop';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
@ -129,6 +130,9 @@ abstract class Renderer {
|
||||
|
||||
FutureOr<ui.Image> createImageFromImageBitmap(DomImageBitmap imageSource);
|
||||
|
||||
FutureOr<ui.Image> createImageFromTextureSource(JSAny object,
|
||||
{required int width, required int height, required bool transferOwnership});
|
||||
|
||||
void decodeImageFromPixels(
|
||||
Uint8List pixels,
|
||||
int width,
|
||||
|
@ -472,6 +472,19 @@ class SkwasmRenderer implements Renderer {
|
||||
surface.handle,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
FutureOr<ui.Image> createImageFromTextureSource(JSAny textureSource, { required int width, required int height, required bool transferOwnership }) async {
|
||||
if (!transferOwnership) {
|
||||
textureSource = (await createImageBitmap(textureSource, (x: 0, y: 0, width: width, height: height))).toJSAnyShallow;
|
||||
}
|
||||
return SkwasmImage(imageCreateFromTextureSource(
|
||||
textureSource as JSObject,
|
||||
width,
|
||||
height,
|
||||
surface.handle,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class SkwasmPictureRenderer implements PictureRenderer {
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:js_interop';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
@ -189,4 +190,9 @@ class SkwasmRenderer implements Renderer {
|
||||
ui.Image createImageFromImageBitmap(DomImageBitmap imageSource) {
|
||||
throw UnimplementedError('Skwasm not implemented on this platform.');
|
||||
}
|
||||
|
||||
@override
|
||||
ui.Image createImageFromTextureSource(JSAny object, { required int width, required int height, required bool transferOwnership }) {
|
||||
throw Exception('Skwasm not implemented on this platform.');
|
||||
}
|
||||
}
|
||||
|
@ -44,3 +44,17 @@ FutureOr<ui.Image> createImageFromImageBitmap(JSAny imageSource) {
|
||||
imageSource as DomImageBitmap,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a [ui.Image] from a valid texture source (for example
|
||||
/// HTMLImageElement | HTMLVideoElement | HTMLCanvasElement).
|
||||
///
|
||||
/// By default, [transferOwnership] specifies that the ownership of the texture
|
||||
/// will be not be transferred to the renderer, and a copy of the texture source
|
||||
/// will be made. If this is not desired, the ownership of the object can be
|
||||
/// transferred to the renderer and the engine will take ownership of the
|
||||
/// texture source and consume its contents.
|
||||
FutureOr<ui.Image> createImageFromTextureSource(JSAny object, { required int width, required int height, bool transferOwnership = false }) {
|
||||
return renderer.createImageFromTextureSource(
|
||||
object, width: width, height: height, transferOwnership: transferOwnership
|
||||
);
|
||||
}
|
||||
|
@ -420,6 +420,37 @@ Future<void> testMain() async {
|
||||
});
|
||||
}
|
||||
|
||||
// This API doesn't work in headless Firefox due to requiring WebGL
|
||||
// See https://github.com/flutter/flutter/issues/109265
|
||||
if (!isFirefox && !isHtml) {
|
||||
emitImageTests('svg_image_bitmap_texture_source', () async {
|
||||
final DomBlob svgBlob = createDomBlob(<String>[
|
||||
'''
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150">
|
||||
<path d="M25,75 A50,50 0 1,0 125 75 L75,25 Z" stroke="blue" stroke-width="10" fill="red"></path>
|
||||
</svg>
|
||||
'''
|
||||
], <String, String>{
|
||||
'type': 'image/svg+xml'
|
||||
});
|
||||
final String url = domWindow.URL.createObjectURL(svgBlob);
|
||||
final DomHTMLImageElement image = createDomHTMLImageElement();
|
||||
final Completer<void> completer = Completer<void>();
|
||||
late final DomEventListener loadListener;
|
||||
loadListener = createDomEventListener((DomEvent event) {
|
||||
completer.complete();
|
||||
image.removeEventListener('load', loadListener);
|
||||
});
|
||||
image.addEventListener('load', loadListener);
|
||||
image.src = url;
|
||||
await completer.future;
|
||||
|
||||
final ui.Image uiImage =
|
||||
await renderer.createImageFromTextureSource(image.toJSAnyShallow, width: 150, height: 150, transferOwnership: false);
|
||||
return uiImage;
|
||||
});
|
||||
}
|
||||
|
||||
emitImageTests('codec_list_resized', () async {
|
||||
final ByteBuffer data = await httpFetchByteBuffer('/test_images/mandrill_128.png');
|
||||
final ui.Codec codec = await renderer.instantiateImageCodec(
|
||||
|
Loading…
x
Reference in New Issue
Block a user