Dart 绘制从远程服务器下载的图像
我需要做以下工作:Dart 绘制从远程服务器下载的图像,dart,flutter,Dart,Flutter,我需要做以下工作: 从服务器下载PNG资源 在该图像上绘制几个矩形,根据状态使用不同的颜色 在可缩放图像视图中显示该图像 我在一个使用Canvas的Android应用程序中有一个工作代码,但我不知道如何使用Flutter来实现这一点 以下是下载资源的代码: static Future<File> getImageFromUrl(String url) async { final directory = await getApplicationDocumentsDirectory();
static Future<File> getImageFromUrl(String url) async {
final directory = await getApplicationDocumentsDirectory();
final file = File("$directory/${_getSHA(url)}.png");
if (await file.exists()) {
// Returns the cached file
} else {
final response = await http.get(url);
if (response.statusCode >= 200 && response.statusCode < 300) {
await file.writeAsBytes(response.bodyBytes);
} else {
return null;
}
}
return file;
}
静态未来getImageFromUrl(字符串url)异步{
最终目录=等待getApplicationDocumentsDirectory();
final file=file(“$directory/${{u getSHA(url)}.png”);
if(wait file.exists()){
//返回缓存文件
}否则{
最终响应=等待http.get(url);
如果(response.statusCode>=200&&response.statusCode<300){
wait file.writeAsBytes(response.bodyBytes);
}否则{
返回null;
}
}
返回文件;
}
接下来我该怎么办?我尝试使用PictureRecorder和Canvas,但我找不到一种方法从这些画布上的文件中绘制图像,然后将其转换为图像,因为我无法从文件中提取宽度和高度
编辑:
下面是我想在flifter中实现的Android代码
// Here we have a bitmap from a file
Bitmap mapBitmap = getBitmap();
Canvas mapCanvas = new Canvas(mapBitmap);
mapDrawable.setBounds(0, 0, mapCanvas.getWidth(), mapCanvas.getHeight());
mapDrawable.draw(mapCanvas);
canvasWidth = mapCanvas.getWidth();
canvasHeight = mapCanvas.getHeight();
Paint paint = new Paint();
for (java.util.Map.Entry<String, MapObject> entry : this.mapObjects.entrySet()) {
MapObject mapObject = entry.getValue();
paint.setColor(getContext().getResources().getColor(mapObject.getBackgroundColor()));
paint.setAlpha(100);
mapCanvas.drawRect((int) (mapObject.getPosX() * scaleX),
(int) (mapObject.getPosY() * scaleY),
(int) ((mapObject.getPosX() + mapObject.getWidth()) * scaleX),
(int) ((mapObject.getPosY() + mapObject.getHeight()) * scaleY),
paint);
}
photoView.setImageBitmap(mapBitmap);
//这里有一个文件中的位图
位图mapBitmap=getBitmap();
Canvas mapCanvas=新画布(mapBitmap);
mapDrawable.setBounds(0,0,mapCanvas.getWidth(),mapCanvas.getHeight());
mapDrawable.draw(mapCanvas);
canvasWidth=mapCanvas.getWidth();
canvasHeight=mapCanvas.getHeight();
油漆=新油漆();
for(java.util.Map.Entry:this.mapObjects.entrySet()){
MapObject MapObject=entry.getValue();
setColor(getContext().getResources().getColor(mapObject.getBackgroundColor());
油漆。setAlpha(100);
mapCanvas.drawRect((int)(mapObject.getPosX()*scaleX),
(int)(mapObject.getPosY()*scaleY),
(int)((mapObject.getPosX()+mapObject.getWidth())*scaleX),
(int)((mapObject.getPosY()+mapObject.getHeight())*scaleY),
油漆);
}
设置图像位图(mapBitmap);
通常,要简单地显示来自internet的图像,可以使用构造函数。如果要进一步自定义交互,例如根据加载状态显示矩形,可以使用该类并将a传递给其构造函数。NetworkImage
允许您监听加载和错误事件
要在图像上方绘制,我只建议使用小部件
如果您想在图像中添加缩放功能,您应该考虑使用OR包替换下面代码中的<代码>图像<代码>。 此外,如果需要缓存,您可以使用软件包中的
CachedNetworkImageProvider
下面的示例显示加载图像上的黄色矩形、完全加载图像上的绿色矩形以及加载崩溃时的红色矩形。这是一个完整的应用程序,您可以复制并粘贴到IDE中,然后试用
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Network Image Download',
theme: ThemeData(),
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => MainPageState();
}
class MainPageState extends State<MainPage> {
ImageProvider provider;
bool loaded;
bool error;
@override
void initState() {
super.initState();
loaded = false;
error = false;
provider = NetworkImage('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
provider.resolve(ImageConfiguration()).addListener((_, __) {
setState(() {
loaded = true;
});
}, onError: (_, __) {
setState(() {
error = true;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Image(image: provider),
Container(
width: 75.0,
height: 75.0,
color: colorByState(),
)
],
),
),
);
}
Color colorByState() {
if (error) {
return Colors.red;
} else if (loaded) {
return Colors.green;
} else {
return Colors.yellow;
}
}
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“网络图像下载”,
主题:主题数据(),
主页:主页(),
);
}
}
类MainPage扩展了StatefulWidget{
@凌驾
State createState()=>MainPageState();
}
类MainPageState扩展状态{
图像提供者;
bool-loaded;
布尔误差;
@凌驾
void initState(){
super.initState();
加载=错误;
错误=错误;
提供者=网络映像('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
provider.resolve(ImageConfiguration()).addListener((){
设置状态(){
加载=真;
});
},一个错误:(u,uu){
设置状态(){
错误=真;
});
});
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
正文:中(
子:堆栈(
对齐:对齐.center,
儿童:[
图像(图像:提供者),
容器(
宽度:75.0,
身高:75.0,
颜色:colorByState(),
)
],
),
),
);
}
Color colorByState(){
如果(错误){
返回颜色。红色;
}否则,如果(已加载){
返回颜色。绿色;
}否则{
返回颜色。黄色;
}
}
}
我终于解决了这个问题
我创建了一个渲染器,用于创建一个合成图像(来自远程资源的背景,并在前景中添加矩形)
渲染器:
class MapRenderer {
ui.Image _mapBackgroundImage;
Future<ui.Codec> renderMap(String url, List<Sensor> sensors) async {
await _loadMapBackground(url);
var renderedMapImage = await _updateSensors(sensors);
var byteD = await renderedMapImage.toByteData(
format: ui.ImageByteFormat.png);
return ui.instantiateImageCodec(Uint8List.view(byteD.buffer));
}
Future<ui.Image> _updateSensors(List<Sensor> sensors) async {
ui.PictureRecorder recorder = ui.PictureRecorder();
Canvas c = Canvas(recorder);
var paint = ui.Paint();
c.drawImage(_mapBackgroundImage, ui.Offset(0.0, 0.0), paint);
for (Sensor s in sensors) {
paint.color = (s.availability ? CustomColors.npSensorFree : CustomColors
.npSensorOccupied);
c.drawRect(
ui.Rect.fromPoints(ui.Offset(s.posX, s.posY),
ui.Offset(s.posX + s.width, s.posY + s.height)),
paint,
);
}
return recorder
.endRecording()
.toImage(_mapBackgroundImage.width, _mapBackgroundImage.height);
}
Future<void> _loadMapBackground(String url) async {
var imageBytes = await _getLocalCopyOrLoadFromUrl(url);
if (imageBytes != null) {
_mapBackgroundImage = await _getImageFromBytes(imageBytes);
} else {
return null;
}
}
Future<ui.Image> _getImageFromBytes(Uint8List bytes) async {
var imageCodec = await ui.instantiateImageCodec(bytes);
var frame = await imageCodec.getNextFrame();
return frame.image;
}
Future<Uint8List> _getLocalCopyOrLoadFromUrl(String url) async {
final directory = await getApplicationDocumentsDirectory();
final file = File("${directory.path}/${_getSHA(url)}.png");
if (await file.exists()) {
return await file.readAsBytes();
} else {
Uint8List resourceBytes = await _loadFromUrl(url);
if (resourceBytes != null) {
await file.writeAsBytes(resourceBytes);
return resourceBytes;
} else {
return null;
}
}
}
Future<Uint8List> _loadFromUrl(String url) async {
final response = await http.get(url);
if (response.statusCode >= 200 && response.statusCode < 300) {
return response.bodyBytes;
} else {
return null;
}
}
String _getSHA(String sth) {
var bytes = utf8.encode(sth);
var digest = sha1.convert(bytes);
return digest.toString();
}
void dispose() {
_mapBackgroundImage.dispose();
}
}
类映射渲染器{
ui.Image\u映射背景图像;
未来的renderMap(字符串url,列表传感器)异步{
wait_loadMapBackground(url);
var renderedMapImage=等待更新传感器(传感器);
var byteD=wait renderedMapImage.toByteData(
格式:ui.ImageByteFormat.png);
返回ui.instantialeimagecodec(Uint8List.view(byteD.buffer));
}
未来更新传感器(列表传感器)异步{
ui.PictureRecorder记录器=ui.PictureRecorder();
画布c=画布(记录器);
var paint=ui.paint();
c、 drawImage(_mapBackgroundImage,ui.Offset(0.0,0.0),绘制);
用于(传感器中的传感器){
paint.color=(s.availability?CustomColor.npSensorFree:CustomColor)
.1(已占用);
c、 drawRect(
ui.Rect.fromPoints(ui.Offset(s.posX,s.posY),
ui.偏移量(s.posX+s.width,s.posY+s.height)),
油漆,
);
}
回程记录器
.endRecording()
.toImage(_-mapBackgroundImage.width,_-mapBackgroundImage.height);
}
Future\u loadMapBackground(字符串url)异步{
var imageBytes=wait_getLocalCopyOrLoadFromUrl(url);
if(imageBytes!=null){
_mapBackgroundImage=Wait_getImageFromBytes(imageBytes);
}否则{
返回null;
}
}
傅
class MapImageProvider extends ImageProvider<MapImageProvider> {
final String url;
final List<Sensor> sensors;
final MapRenderer mapRenderer = MapRenderer();
MapImageProvider(this.url, this.sensors);
@override
ImageStreamCompleter load(MapImageProvider key) {
return MultiFrameImageStreamCompleter(
codec: _loadAsync(key),
scale: 1.0,
informationCollector: (StringBuffer information) {
information.writeln('Image provider: $this');
information.write('Image key: $key');
});
}
Future<ui.Codec> _loadAsync(MapImageProvider key) async {
assert(key == this);
return await mapRenderer.renderMap(url, sensors);
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is MapImageProvider &&
runtimeType == other.runtimeType &&
url == other.url;
@override
int get hashCode => url.hashCode;
@override
String toString() => '$runtimeType("$url")';
@override
Future<MapImageProvider> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<MapImageProvider>(this);
}
}