I'm using multi_image_picker package to pick images and upload to server, but before uploading I want to resize images. I'm trying to accomplish it using dart.ui but having a problem:
//assets is List<Asset> from MultiImagePicker.pickImages
assets.forEach((asset) {
Future<ByteData> byteData = asset.getByteData();
byteData.then((d) async {
List<int> imageData = d.buffer.asUint8List();
String b64 =base64Encode(imageData);
print(b64); // prints [/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE...
//if i send b64 to server then decode it and save as img it's working well
//Resize
ui.instantiateImageCodec(imageData,targetHeight: 800, targetWidth: 600)
.then((codec) {
codec.getNextFrame().then((frameInfo) async {
ui.Image i = frameInfo.image;
ByteData bytes = await i.toByteData();
List<int> resizedImageData = bytes.buffer.asUint8List();
String rb64 = base64Encode(resizedImageData);
print(rb64); // prints too many backslashes:[k5KO/5qWk/+ZlZL/mpaT/5uXlP+alpP/mJSR/5iUkf+YlJH/mZSR/5uWk/+blpP/n5qX/6GcmP+gm5f/oZyY/6GcmP+fmpb/nZi..
//If i send rb64 to server then server cannot decode and save it.
});
});
});
});
This is the function I normally use to resize:
import 'dart:ui' as skia;
Future<skia.Image> resizeImage(String path, {int width, int height}) async {
Uint8List data = await File(path).readAsBytes();
final codec = await skia.instantiateImageCodec(data, targetWidth: width, targetHeight: height);
final frame = await codec.getNextFrame();
return frame.image;
}
As I mentioned in the comment, this is currently not working in Flutter Web but it's due to a bug that will be fixed soon, hopefully.
Related
I am creating custom images with flutters canvas and need them to be saved as 24 bit (rgb) pngs without the alpha channel.
I am using the flutter_file_dialog package for the image export.
But the final images are saved in the 32 bit format (rgba).
I have searched the flutter documentation but have not found an easy way to remove the alpha channel.
Would I have to do the removal myself by changing the uint8list?
import 'dart:ui' as ui;
Future<void> createImage() async {
final recorder = ui.PictureRecorder();
const Size size = Size(2000, 2000);
final Rect rect = Rect.fromLTRB(0, 0, size.width, size.height);
final canvas = Canvas(recorder, rect);
// canvas design ...
// capture canvas and save it as image
final picture = recorder.endRecording();
ui.Image newImage = await picture.toImage(size.width.toInt(), size.height.toInt());
ByteData pngBytes = await newImage.toByteData(format: ui.ImageByteFormat.png);
Uint8List uint8list = Uint8List.view(pngBytes.buffer);
// export the image
final params = SaveFileDialogParams(fileName: "image.png", data: uint8list);
final filePath = await FlutterFileDialog.saveFile(params: params);
}
This question already has answers here:
What is a Future and how do I use it?
(6 answers)
Closed 3 months ago.
I'm making a watermark image using flutter and I need to convert Future to Uint8List.
This is the code where the problem happens.
child: Image.memory(putWatermarkOnImage(asset))
The child is in the Container widget and the result of the putWatermarkOnImage function has to be Uint8List type not a future type.
Future<Uint8List> putWatermarkOnImage(asset) async {
final assetFile = await asset.file;
var imageBytes = await assetFile!.readAsBytes();
ByteData watermarkImgByteData = await rootBundle.load('assets/images/ournow_logo.png');
Uint8List watermarkImgBytes = watermarkImgByteData.buffer.asUint8List();
Uint8List imageUint8List = Uint8List.fromList(imageBytes);
Uint8List watermarkedImg = await ImageWatermark.addImageWatermark(
originalImageBytes: imageUint8List,
waterkmarkImageBytes: watermarkImgBytes,
imgHeight: 200,
imgWidth: 200,
dstY: 400,
dstX: 400);
return watermarkedImg;
}
How can I solve this problem?
I have taken your code and wrote it the way I do to avoid confusions, so I created a class for you on the side to collect all bytes transformation related methods and called them "BytesHandlers"
then I re-organized the code as follows,,, I believe it will work
please test it and tell me if something is going wrong
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:wechat_camera_picker/wechat_camera_picker.dart';
Future<Uint8List> putWatermarkOnImage(AssetEntity asset) async {
Uint8List _output;
if (asset != null){
final File assetFile = await asset.file;
final ByteData watermarkImgByteData = await BytesHandlers.getByteDataFromPath('assets/images/ournow_logo.png');
_output = await BytesHandlers.getUint8ListFromFile(assetFile);
_output = await ImageWatermark.addImageWatermark(
originalImageBytes: _output,
waterkmarkImageBytes: watermarkImgByteData,
imgHeight: 200,
imgWidth: 200,
dstY: 400,
dstX: 400
);
}
return _output;
}
class BytesHandlers {
// --------------------
BytesHandlers();
// --------------------
static Future<ByteData> getByteDataFromPath(String assetPath) async {
/// NOTE : Asset path can be local path or url
ByteData _byteData;
if (assetPath != null){
_byteData = await rootBundle.load(assetPath);
}
return _byteData;
}
// --------------------
static Future<Uint8List> getUint8ListFromFile(File file) async {
Uint8List _uInt;
if (file != null){
_uInt = await file.readAsBytes();
}
return _uInt;
}
// --------------------
}
then you get to call it like this
final Uint8List _ImageWithWatermark = await putWatermarkOnImage(_inputFile);
I'm able to print out my images on receipt paper, but the problem I faced is that the image is line by line which is a problem.
Below is my code
final ByteData data = await rootBundle.load('assets/logo1.png');
final Uint8List buffer= data.buffer.asUint8List();
final image = decodeImage(buffer);
bytes += generator.image(image);
Here is the result of printing it out.
Use this function:
initSavetoPath() async {
//read and write
//image max 300px X 300px
final filename = 'logo_a.png';
var bytes = await rootBundle.load("assets/images/logo_a.png");
String dir = (await getApplicationDocumentsDirectory()).path;
writeToFile(bytes, '$dir/$filename');
setState(() {
pathImage = '$dir/$filename';
});
}
Check out this package: Click here!
Trying to generate an Thumbnail image from video , the file is created but , errors as Invalid image on load .Using this package video_thumbnail
Creating thumbnail ,
Future<File> genThumbnail(url) async {
//WidgetsFlutterBinding.ensureInitialized();
Uint8List bytes;
final Completer<ThumbnailResult> completer = Completer();
bytes = await VideoThumbnail.thumbnailData(
video: url,
imageFormat: ImageFormat.JPEG,
maxHeight: 250,
maxWidth: 300,
timeMs: 0,
quality: 0);
int _imageDataSize = bytes.length;
print("image size: $_imageDataSize");
//final _image = Image.memory(bytes);
//var _file =File.fromRawPath(bytes);
Directory tempDir = await getTemporaryDirectory();
var uint8list = bytes;
var buffer = uint8list.buffer;
ByteData byteData = ByteData.view(buffer);
File file = await File('${tempDir.path}/img/THUMBNAIL${DateTime.now().toIso8601String()}.JPEG').writeAsBytes(
buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
Saving to firestore
await genThumbnail(fileurl).then((_thumbFIle) async{
String Thumbfileurl = await uploadFile(_thumbFIle, 'thumbnailOf${filenamewithoutExtension}.JPEG', 'videothumbnail');
await sendFileToFirestoreChat(fileType, fileurl, filenamewithoutExtension,Thumbfileurl);
return fileurl;
});
The Saved Image ,
https://firebasestorage.googleapis.com/v0/b/proj-inhouse.appspot.com/o/videos%2Fvideothumbnails%2FthumbnailOfVID-20210301-WA0006.JPEG?alt=media&token=fa4f23c1-601f-486b-97d1-c63e221166af
Posting this as a Community Wiki as it's based on #pskink comments.
To resolve, add the writeAsBytes(bytes) instead of writeAsBytes(buffer.asUint8List()). There is no need for any buffer.
I have the network url of image and I need to get Uint8List. How can I convert it?
I check answers in like question, but those ways don't work.
How to get a Flutter Uint8List from a Network Image?
Try this:
Uint8List bytes = (await NetworkAssetBundle(Uri.parse(url)).load(url))
.buffer
.asUint8List();
Uint8List yourVar;
final DecoderCallback callback = (Uint8List bytes, {int cacheWidth, int cacheHeight}) {
yourVar = bytes.buffer.asUint8List();
return instantiateImageCodec(bytes, targetWidth: cacheWidth, targetHeight: cacheHeight);
};
ImageProvider provider = NetworkImage(yourImageUrl);
provider.obtainKey(createLocalImageConfiguration(context)).then((key) {
provider.load(key, callback);
});
this did the trick for me:
import 'dart:typed_data';
import 'package:flutter/services.dart';
//Get the image from the URL and then convert it to Uint8List
Uint8List bytes = (await NetworkAssetBundle(Uri.parse('https://some_image_url.png'))
.load('https://some_image_url.png'))
.buffer
.asUint8List();
This works on me (using flutter web) with a library file_saver.
Uri uri = Uri.parse(url);
Uint8List bytes = await readBytes(uri);
await FileSaver.instance.saveFile(filename, bytes, 'jpg',
mimeType: MimeType.JPEG); // specify your vars
I'm having the same problem in Flutter web, I had to use the extended_image library, and I found inside your example that has a method that allows you to convert an ImageProvider to Bytes.
https://github.com/fluttercandies/extended_image/blob/master/example/lib/pages/simple/image_editor_demo.dart.
/// it may be failed, due to Cross-domain
Future<Uint8List> _loadNetwork(ExtendedNetworkImageProvider key) async {
try {
final Response response = await HttpClientHelper.get(Uri.parse(key.url),
headers: key.headers,
timeLimit: key.timeLimit,
timeRetry: key.timeRetry,
retries: key.retries,
cancelToken: key.cancelToken);
return response.bodyBytes;
} on OperationCanceledError catch (_) {
print('User cancel request ${key.url}.');
return Future<Uint8List>.error(
StateError('User cancel request ${key.url}.'));
} catch (e) {
return Future<Uint8List>.error(StateError('failed load ${key.url}. \n $e'));
}
}