我正在尝试使用图像作为着色器的char
。我正在从内存中读取图像,所以我的图像是E
。如何使用内存中的图像创建ImageShader?
ShaderMask
File
出现错误,因为图像类型错误(我需要ui.Image,但我不知道如何创建)。
如何从File imageFile;
Image image = Image.file(imageFile)
ShaderMask(
shaderCallback: (bounds) {
Float64List matrix4 = new Matrix4.identity().storage; // <--- DO I NEED THIS OR THE BOUNDS?
return ImageShader(image, TileMode.mirror, TileMode.mirror, matrix4);
},
child: child
)
图像创建ImageShader
?
PS:ImageShader
是正确的还是应该以某种方式使用边界?
答案 0 :(得分:2)
要知道的重要一点是ImageShader
使用的是dart:ui
包中的图片,而不是Image
小部件的实例。没有直接的操作或构造函数可用于从网络位置,文件或资产创建ui.Image
的实例,因此您需要一些代码来完成它。
在查找许多资源并深入研究代码后,Image
小部件如何加载原始图像时,我想到的最好的通用解决方案是使用ImageProvider
作为源。抽象ImageProvider
具有NetworkImage
,FileImage
,ExactAssetImage
和MemoryImage
之类的实现,可以从所需的任何资源中加载图像。
首先,您使用ImageStream
方法获得一个ImageProvider.resolve
。 resolve
方法采用ImageConfiguration
类型的参数,该参数应填充代码位置可用的尽可能多的信息。在大多数情况下,您可以使用全局createLocalImageConfiguration
函数,但是请注意,当您在StatefulWidget的initState
方法中创建着色器时,此功能将无效。
在已解析的ImageStream
上,您可以附加一个ImageStreamListener
并将其作为第一个参数的ImageListener
。加载图像后,将使用ImageInfo
调用回调,该回调将在image
属性上提供请求的图像。
您可以将ImageShader
的两个切片模式都构造为TileMode.clamp
和一个简单的单位矩阵,可以手动创建或采用Matrix4
类提供的那个矩阵。如果您需要图像着色器小于提供的图像大小,则可以将提供程序包装在ResizeProvider
中,并指定所需的宽度和高度。
下面我将实现ImageMask
小部件作为参考,该标准可用于掩盖任何类型的小部件。
class ImageMask extends StatefulWidget {
final ImageProvider image;
final double width;
final double height;
final Widget child;
const ImageMask({@required this.image, this.width, this.height, @required this.child});
@override
_ImageMaskState createState() => _ImageMaskState();
}
class _ImageMaskState extends State<ImageMask> {
Future<Shader> _shader;
@override
void initState() {
super.initState();
_shader = _loadShader(context);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _shader,
builder: (_, AsyncSnapshot<Shader> snapshot) {
return snapshot.connectionState != ConnectionState.done || snapshot.hasError
? SizedBox(width: widget.width, height: widget.height)
: ShaderMask(
blendMode: BlendMode.dstATop,
shaderCallback: (bounds) => snapshot.data,
child: widget.child,
);
},
);
}
Future<Shader> _loadShader(BuildContext context) async {
final completer = Completer<ImageInfo>();
// use the ResizeImage provider to resolve the image in the required size
ResizeImage(widget.image, width: widget.width.toInt(), height: widget.height.toInt())
.resolve(ImageConfiguration(size: Size(widget.width, widget.height)))
.addListener(ImageStreamListener((info, _) => completer.complete(info)));
final info = await completer.future;
return ImageShader(
info.image,
TileMode.clamp,
TileMode.clamp,
Float64List.fromList(Matrix4.identity().storage),
);
}
}