In my project, I need to capture the frame of a flutter animation and save that frame as an image (probably in .png) to Device Storage.
I am using RepaintBoundary to capture the frame, but I can't use the ui.ImageByteFormat.png method because it takes a lot of process time to capture the frame as a .png, and since I need to take a lot of frames it will not be a viable solution. Instead, I am using ui.ImageByteFormat.rawRgba which is super fast but when I save it to Storage the image quality is terrible. It hardly looks like it's the same image I captured.
I am using FFMPEG to convert .raw or .bmp format to png and save it to storage.
Code to Capture the Frame:
Future<Uint8List> _capturePngToUint8List(renderBoxKey) async {
// renderBoxKey is the global key of my RepaintBoundary
// RenderRepaintBoundary boundary =
// renderBoxKey.currentContext.findRenderObject();
RenderRepaintBoundary boundary = renderBoxKey;
// pixelratio allows you to render it at a higher resolution than the actual widget in the application.
ui.Image image = await boundary.toImage(pixelRatio: 3);
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
Uint8List pngBytes = byteData.buffer.asUint8List();
return pngBytes;
}
Saving File Method:
Future<File> _writeFile(
{@required String location, @required Uint8List bytes}) async {
File file = File(location);
return file.writeAsBytes(bytes);
}
Generating .png from raw using FFMPEG:
captureFrameWithBMP(renderBoxKey)async{
var output = await getExternalStorageDirectory();
var bytes = await _capturePngToUint8List(renderBoxKey);
fileWriterFutures.add(_writeFile(
bytes: bytes, location: "${output.path}/" + "frame_1.raw"));
Generating .png using BitMap Package and FFMPEG:
captureFrameWithBMP(renderBoxKey)async{
var dir = await getApplicationDocumentsDirectory();
var output = await getExternalStorageDirectory();
var bytes = await _capturePngToUint8List(renderBoxKey);
Bitmap bitmap = Bitmap.fromHeadless(300, 100, bytes); // Not async
fileWriterFutures.add(_writeFile(
bytes: bitmap.buildHeaded().buffer.asUint8List(), location: "${output.path}/" + "frame_1.bmp"));
}
In both cases, using raw or using BitMap the output image is like this:
But, the Quality of the Image should be like this 
Note: When using ui.ImageByteFormat.png in _capturePngToUnit8List() method, I get a clear image with the right quality. But ui.ImageByteFormat.rawRgba gives a terrible image as shown above. But I have to use rawRgba since png takes a lot time to capture and I want to captures 1000s of frames.
Now, I need help to either get this raw capture saved with quality by using whatever file format doesn't matter or please share if you have any other viable method to capture frames of a flutter animation.
from Flutter ui.ImageByteFormat.rawRgba has terrible Image Quality

No comments:
Post a Comment