如何在 Flutter/Dart 中读取(从磁盘)和调整图像大小
How can I read (from disk) and resize an image, in Flutter/Dart
在 Flutter/Dart 中,如何执行以下 3 个步骤:
- 从磁盘读取图像,
- 读取其原始尺寸(宽度和高度),
- 调整大小。
注意:我必须能够使用常规的 Flutter Image 小部件显示最终结果。
澄清:我不想保存图像,但我确实想在内存中实际调整它的大小。
您可以使用 image.file 构造函数从磁盘读取图像。
如需更多功能,您可以使用 Image library
A Dart library providing the ability to load, save and manipulate
images in a variety of different file formats.
文档中的示例 examples
Load a jpeg, resize it and save it as a png
import 'dart:io' as Io;
import 'package:image/image.dart';
void main() {
// Read a jpeg image from file.
Image image = decodeImage(new Io.File('test.jpg').readAsBytesSync());
// Resize the image to a 120x? thumbnail (maintaining the aspect ratio).
Image thumbnail = copyResize(image, width: 120);
// Save the thumbnail as a PNG.
new Io.File('out/thumbnail-test.png')
..writeAsBytesSync(encodePng(thumbnail));
}
要调整在 pubspec.yaml 中定义的图像的大小,请使用 "BoxFit":
@override
Widget build(BuildContext context) {
return (new Container(
width: 250.0,
height: 250.0,
alignment: Alignment.center,
decoration: new BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/Launcher_Icon.png'),
fit: BoxFit.fill
),
),
));
}
另请参阅如何访问图像:https://flutter.io/assets-and-images/
您可以使用飞镖 image
包:https://pub.dartlang.org/packages/image.
该软件包提供各种服务,例如调整大小、裁剪和旋转。
虽然这个包确实有效,但不幸的是它非常慢。
通过图片库调整图片大小不是很好的方法,因为它会阻塞 ui 线程,并且会带来非常糟糕的用户体验。
image_picker
lib中有一个maxWidth
参数,你可以设置它,所以在某些情况下这些写入文件操作是不必要的。
这是一个示例 Thumbnail
小部件,它在航班上执行此操作
它使用 Isolate
将 CPU-intensive 工作卸载到后台线程并有 UI 个线程 jank-free
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as IMG;
import 'package:path/path.dart';
class Thumbnail extends StatefulWidget {
final Size size;
final File image;
const Thumbnail({Key key, this.size, this.image}) : super(key: key);
@override
_ThumbnailState createState() => _ThumbnailState();
}
class _ThumbnailState extends State<Thumbnail> {
List<int> imgBytes;
Isolate isolate;
@override
void initState() {
_asyncInit();
super.initState();
}
static _isolateEntry(dynamic d) async {
final ReceivePort receivePort = ReceivePort();
d.send(receivePort.sendPort);
final config = await receivePort.first;
print(config);
final file = File(config['path']);
final bytes = await file.readAsBytes();
IMG.Image image = IMG.decodeImage(bytes);
IMG.Image thumbnail = IMG.copyResize(
image,
width: config['size'].width.toInt(),
);
d.send(IMG.encodeNamedImage(thumbnail, basename(config['path'])));
}
_asyncInit() async {
final ReceivePort receivePort = ReceivePort();
isolate = await Isolate.spawn(_isolateEntry, receivePort.sendPort);
receivePort.listen((dynamic data) {
if (data is SendPort) {
if (mounted) {
data.send({
'path': widget.image.path,
'size': widget.size,
});
}
} else {
if (mounted) {
setState(() {
imgBytes = data;
});
}
}
});
}
@override
void dispose() {
if (isolate != null) {
isolate.kill();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: widget.size.height,
width: widget.size.width,
child: imgBytes != null
? Image.memory(
imgBytes,
fit: BoxFit.cover,
)
: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.grey[100], Colors.grey[300]],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
),
);
}
}
您可以在脚手架小部件中使用图像小部件,
首先你需要在根目录下创建assets文件夹并添加一个images文件夹,然后添加,
flutter:
assets:
- assets/images/
到pubspec.yaml文件,之后
new Image(
image: AssetImage('assets/images/pizzaFont.png'),
height: 12,
width:12, ......
)
您可以使用宽度和高度来更改图像的大小。
更多信息请关注,
https://medium.com/@suragch/how-to-include-images-in-your-flutter-app-863889fc0b29
您可以使用 dart ui 库中的图像 class,使用 intantiateImageCodec 中的 frameInfo 获取具有所需宽度和高度的图像对象,然后将其保存在所需路径中
import 'dart:ui' as ui;
Uint8List m = File(path).readAsBytesSync();
ui.Image x = await decodeImageFromList(m);
ByteData bytes = await x.toByteData();
print('height is ${x.height}'); //height of original image
print('width is ${x.width}'); //width of oroginal image
print('array is $m');
print('original image size is ${bytes.lengthInBytes}');
ui.instantiateImageCodec(m, targetHeight: 800, targetWidth: 600)
.then((codec) {
codec.getNextFrame().then((frameInfo) async {
ui.Image i = frameInfo.image;
print('image width is ${i.width}');//height of resized image
print('image height is ${i.height}');//width of resized image
ByteData bytes = await i.toByteData();
File(path).writeAsBytes(bytes.buffer.asUint32List());
print('resized image size is ${bytes.lengthInBytes}');
});
});
使用 ResizeImage
图片提供程序。
如果您想使用许多功能,或者如果您不能以其他方式使用,那么使用单独的包是个不错的选择。但只是依赖于某些东西而不是框架本身(及其底层图形引擎)可以轻松完成的事情......:-)
如果您现在有 ImageProvider
,比如说,要显示内存中字节的图像:
Image(image: MemoryImage(bytes))
只需将它包裹在 ResizeImage
:
Image(image: ResizeImage(MemoryImage(bytes), width: 50, height: 100))
如果您想要更多的控制权,只需基于这个的源代码创建您自己的图像提供程序。
final pickedFile = await picker.getImage(
source: ImageSource.gallery,
imageQuality: 25,
maxHeight: 1024,
maxWidth: 1024);
有很多解决方案:
使用ResizeImageclass
ResizeImage class 指示 Flutter 以指定尺寸而不是原始尺寸解码图像。
用法: 用 ResizeImage class
包装你的 ImageProvider
示例:
Image(image: ResizeImage(AssetImage('eg.png'), width: 70, height: 80)),
ImageProvider includes AssetImage
, NetworkImage
, FileImage
and MemoryImage
.
在 Image widget
中使用 cacheHeight
和 cacheWidth
属性
这些属性创建了一个显示从资产、网络、内存或文件中获取的 [ImageStream] 的小部件。
示例:
Image.asset('assets/image.png', cacheHeight:120 , cacheWidth: 150),
There are these properties in Image.asset
,Image.network
, Image.file
and
Image.memory
我会说使用 dart image
包。
import 'package:image/image.dart' as image show
decodedImage, copyResize //, encodePng
;
import 'dart:convert' as convert show
base64encode
;
void resizeImage() async {
List<int> fileBytes = await file.readAsBytes();
image.Image decodedImage = image.decodeImage(fileBytes) as image.Image;
image.Image thumbnail = image.copyResize(decodedImage, width: 60);
List<int> resizedIntList = thumbnail.getBytes();
// Or compress as a PNG image
// List<int> resizedIntList = image.encodePng(thumbnail, level: 6);
String resizedBase64Image = convert.base64Encode(resizedIntList);
}
如果不想包的开销,也可以参考下面的代码
import 'dart:ui' as ui show
Codec, instantiateImageCodec, FrameInfo;
import 'dart:typed_data' as typedData show
ByteData, Uint8List
;
import 'dart:convert' as convert show
base64Encode
;
void resizeImage() async {
typedData.Uint8List fileBytes = await file.readAsBytes();
// Resize image
// ----------
ui.Codec codec = await ui.instantiateImageCodec(
fileBytes,
targetWidth: 60
);
ui.FrameInfo frameInfo = await codec.getNextFrame();
ui.Image resizedImage = frameInfo.image;
// ----------
// Convert to List<int>
// ----------
typedData.ByteData resizedByteData = await resizedImage.toByteData() as typedData.ByteData;
typedData.Uint8List resizedUint8List = resizedByteData.buffer
.asUint8List(resizedByteData.offsetInBytes, resizedByteData.lengthInBytes);
List<int> resizedIntList = resizedUint8List.cast<int>();
// ----------
String resizedBase64Image = convert.base64Encode(resizedIntList);
}
在 Flutter/Dart 中,如何执行以下 3 个步骤:
- 从磁盘读取图像,
- 读取其原始尺寸(宽度和高度),
- 调整大小。
注意:我必须能够使用常规的 Flutter Image 小部件显示最终结果。
澄清:我不想保存图像,但我确实想在内存中实际调整它的大小。
您可以使用 image.file 构造函数从磁盘读取图像。
如需更多功能,您可以使用 Image library
A Dart library providing the ability to load, save and manipulate images in a variety of different file formats.
文档中的示例 examples
Load a jpeg, resize it and save it as a png
import 'dart:io' as Io;
import 'package:image/image.dart';
void main() {
// Read a jpeg image from file.
Image image = decodeImage(new Io.File('test.jpg').readAsBytesSync());
// Resize the image to a 120x? thumbnail (maintaining the aspect ratio).
Image thumbnail = copyResize(image, width: 120);
// Save the thumbnail as a PNG.
new Io.File('out/thumbnail-test.png')
..writeAsBytesSync(encodePng(thumbnail));
}
要调整在 pubspec.yaml 中定义的图像的大小,请使用 "BoxFit":
@override
Widget build(BuildContext context) {
return (new Container(
width: 250.0,
height: 250.0,
alignment: Alignment.center,
decoration: new BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/Launcher_Icon.png'),
fit: BoxFit.fill
),
),
));
}
另请参阅如何访问图像:https://flutter.io/assets-and-images/
您可以使用飞镖 image
包:https://pub.dartlang.org/packages/image.
该软件包提供各种服务,例如调整大小、裁剪和旋转。
虽然这个包确实有效,但不幸的是它非常慢。
通过图片库调整图片大小不是很好的方法,因为它会阻塞 ui 线程,并且会带来非常糟糕的用户体验。
image_picker
lib中有一个maxWidth
参数,你可以设置它,所以在某些情况下这些写入文件操作是不必要的。
这是一个示例 Thumbnail
小部件,它在航班上执行此操作
它使用 Isolate
将 CPU-intensive 工作卸载到后台线程并有 UI 个线程 jank-free
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as IMG;
import 'package:path/path.dart';
class Thumbnail extends StatefulWidget {
final Size size;
final File image;
const Thumbnail({Key key, this.size, this.image}) : super(key: key);
@override
_ThumbnailState createState() => _ThumbnailState();
}
class _ThumbnailState extends State<Thumbnail> {
List<int> imgBytes;
Isolate isolate;
@override
void initState() {
_asyncInit();
super.initState();
}
static _isolateEntry(dynamic d) async {
final ReceivePort receivePort = ReceivePort();
d.send(receivePort.sendPort);
final config = await receivePort.first;
print(config);
final file = File(config['path']);
final bytes = await file.readAsBytes();
IMG.Image image = IMG.decodeImage(bytes);
IMG.Image thumbnail = IMG.copyResize(
image,
width: config['size'].width.toInt(),
);
d.send(IMG.encodeNamedImage(thumbnail, basename(config['path'])));
}
_asyncInit() async {
final ReceivePort receivePort = ReceivePort();
isolate = await Isolate.spawn(_isolateEntry, receivePort.sendPort);
receivePort.listen((dynamic data) {
if (data is SendPort) {
if (mounted) {
data.send({
'path': widget.image.path,
'size': widget.size,
});
}
} else {
if (mounted) {
setState(() {
imgBytes = data;
});
}
}
});
}
@override
void dispose() {
if (isolate != null) {
isolate.kill();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: widget.size.height,
width: widget.size.width,
child: imgBytes != null
? Image.memory(
imgBytes,
fit: BoxFit.cover,
)
: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.grey[100], Colors.grey[300]],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
),
);
}
}
您可以在脚手架小部件中使用图像小部件,
首先你需要在根目录下创建assets文件夹并添加一个images文件夹,然后添加,
flutter:
assets:
- assets/images/
到pubspec.yaml文件,之后
new Image(
image: AssetImage('assets/images/pizzaFont.png'),
height: 12,
width:12, ......
)
您可以使用宽度和高度来更改图像的大小。
更多信息请关注,
https://medium.com/@suragch/how-to-include-images-in-your-flutter-app-863889fc0b29
您可以使用 dart ui 库中的图像 class,使用 intantiateImageCodec 中的 frameInfo 获取具有所需宽度和高度的图像对象,然后将其保存在所需路径中
import 'dart:ui' as ui;
Uint8List m = File(path).readAsBytesSync();
ui.Image x = await decodeImageFromList(m);
ByteData bytes = await x.toByteData();
print('height is ${x.height}'); //height of original image
print('width is ${x.width}'); //width of oroginal image
print('array is $m');
print('original image size is ${bytes.lengthInBytes}');
ui.instantiateImageCodec(m, targetHeight: 800, targetWidth: 600)
.then((codec) {
codec.getNextFrame().then((frameInfo) async {
ui.Image i = frameInfo.image;
print('image width is ${i.width}');//height of resized image
print('image height is ${i.height}');//width of resized image
ByteData bytes = await i.toByteData();
File(path).writeAsBytes(bytes.buffer.asUint32List());
print('resized image size is ${bytes.lengthInBytes}');
});
});
使用 ResizeImage
图片提供程序。
如果您想使用许多功能,或者如果您不能以其他方式使用,那么使用单独的包是个不错的选择。但只是依赖于某些东西而不是框架本身(及其底层图形引擎)可以轻松完成的事情......:-)
如果您现在有 ImageProvider
,比如说,要显示内存中字节的图像:
Image(image: MemoryImage(bytes))
只需将它包裹在 ResizeImage
:
Image(image: ResizeImage(MemoryImage(bytes), width: 50, height: 100))
如果您想要更多的控制权,只需基于这个的源代码创建您自己的图像提供程序。
final pickedFile = await picker.getImage(
source: ImageSource.gallery,
imageQuality: 25,
maxHeight: 1024,
maxWidth: 1024);
有很多解决方案:
使用ResizeImageclass
ResizeImage class 指示 Flutter 以指定尺寸而不是原始尺寸解码图像。
用法: 用 ResizeImage class
包装你的 ImageProvider示例:
Image(image: ResizeImage(AssetImage('eg.png'), width: 70, height: 80)),
ImageProvider includes
AssetImage
,NetworkImage
,FileImage
andMemoryImage
.
在 Image widget
中使用cacheHeight
和 cacheWidth
属性
这些属性创建了一个显示从资产、网络、内存或文件中获取的 [ImageStream] 的小部件。
示例:
Image.asset('assets/image.png', cacheHeight:120 , cacheWidth: 150),
There are these properties in
Image.asset
,Image.network
,Image.file
andImage.memory
我会说使用 dart image
包。
import 'package:image/image.dart' as image show
decodedImage, copyResize //, encodePng
;
import 'dart:convert' as convert show
base64encode
;
void resizeImage() async {
List<int> fileBytes = await file.readAsBytes();
image.Image decodedImage = image.decodeImage(fileBytes) as image.Image;
image.Image thumbnail = image.copyResize(decodedImage, width: 60);
List<int> resizedIntList = thumbnail.getBytes();
// Or compress as a PNG image
// List<int> resizedIntList = image.encodePng(thumbnail, level: 6);
String resizedBase64Image = convert.base64Encode(resizedIntList);
}
如果不想包的开销,也可以参考下面的代码
import 'dart:ui' as ui show
Codec, instantiateImageCodec, FrameInfo;
import 'dart:typed_data' as typedData show
ByteData, Uint8List
;
import 'dart:convert' as convert show
base64Encode
;
void resizeImage() async {
typedData.Uint8List fileBytes = await file.readAsBytes();
// Resize image
// ----------
ui.Codec codec = await ui.instantiateImageCodec(
fileBytes,
targetWidth: 60
);
ui.FrameInfo frameInfo = await codec.getNextFrame();
ui.Image resizedImage = frameInfo.image;
// ----------
// Convert to List<int>
// ----------
typedData.ByteData resizedByteData = await resizedImage.toByteData() as typedData.ByteData;
typedData.Uint8List resizedUint8List = resizedByteData.buffer
.asUint8List(resizedByteData.offsetInBytes, resizedByteData.lengthInBytes);
List<int> resizedIntList = resizedUint8List.cast<int>();
// ----------
String resizedBase64Image = convert.base64Encode(resizedIntList);
}