4

Can we export custom painter used animation controller to a gif image or continuous images or event a video such as mp4 file?

ChildhoodAndy
  • 436
  • 3
  • 11

2 Answers2

4

Yes I did it one time (2 years ago) and I converted a Flutter Animation to a mp4 file. unfortunately I couldn't find the code. please follow the steps to make what you want.

  1. capture your widget with RenderRepaintBoundary like below code https://api.flutter.dev/flutter/rendering/RenderRepaintBoundary/toImage.html

     class PngHome extends StatefulWidget {
       const PngHome({super.key});
    
       @override
       State<PngHome> createState() => _PngHomeState();
     }
    
     class _PngHomeState extends State<PngHome> {
       GlobalKey globalKey = GlobalKey();
    
       Future<void> _capturePng() async {
         final RenderRepaintBoundary boundary = globalKey.currentContext!.findRenderObject()! as RenderRepaintBoundary;
         final ui.Image image = await boundary.toImage();
         final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
         final Uint8List pngBytes = byteData!.buffer.asUint8List();
         print(pngBytes);
       }
    
       @override
       Widget build(BuildContext context) {
         return RepaintBoundary(
           key: globalKey,
           child: Center(
             child: TextButton(
               onPressed: _capturePng,
               child: const Text('Hello World', textDirection: TextDirection.ltr),
             ),
           ),
         );
       }
    
     }
    
  2. save each image like this

    import 'package:path_provider/path_provider.dart';
    import 'dart:io';
    
    Uint8List imageInUnit8List = // store unit8List image here ;
    final tempDir = await getTemporaryDirectory();
    File file = await File('${tempDir.path}/image.png').create();
    file.writeAsBytesSync(imageInUnit8List);
    

  1. you need to capture each frame of your Animation and save it to a directory. with special naming for example (1.png,2.png .... 1000.png)

     @override
     Widget build(BuildContext context) {
     return AnimatedBuilder(
       animation: _controller,
       child: theChildWidet() // important use child for performance 
       builder: (BuildContext context, Widget? child) {
    
         CaptureScreenAndSave(_controller.value) /// <- capture each frame
    
         return Transform.rotate(
           angle: _controller.value * 2.0 * math.pi,
           child: child,
         );
       },
     );
     }
    
  2. install ffmpeg https://pub.dev/packages/ffmpeg_kit_flutter and use it to execute FFMPEG command

    import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart';
    
    FFmpegKit.execute('your command').then((session) async {
    final returnCode = await session.getReturnCode();
    
    if (ReturnCode.isSuccess(returnCode)) {
    
     // SUCCESS
    
    } else if (ReturnCode.isCancel(returnCode)) {
    
     // CANCEL
    
    } else {
    
     // ERROR
    
    }
    });
    
  3. search for a command to convert your images with ffmpeg to Gif Or Mp4 (some thing like these Example1 or Example2)

Sajjad
  • 2,593
  • 16
  • 26
  • Thank you for the response. In the second step, does that mean I have to create a loop to run 1000 times and capture images each time? Should I have a delay set with each loop? Also, doesn't that take a lot of time to process - just to run the loop? – Danny Feb 21 '23 at 04:15
  • 1
    your welcome !,@Danny , in your Animation builder in Builder method, you can call captureAndSave method. because build method calls on each frame of your animation. I updated the answer – Sajjad Feb 22 '23 at 08:32
  • 1
    we need 25 Frame per second but Flutter renders 60 frame per second, so I think we can improve performance with skipping some frame and using compute for multithreading https://api.flutter.dev/flutter/foundation/compute-constant.html – Sajjad Feb 22 '23 at 08:43
  • 1
    what I tested isn't heavy . so I think multithreading is enough . no need to skip frames. – Sajjad Feb 22 '23 at 08:45
  • Thank you again! I will look into it. I wasn't aware of `compute constant`. I think this is a good way to go. – Danny Feb 22 '23 at 08:49
0

you can use screenshot library. by wrapping the parent container with Screenshot library you can convert widget to multiple images and those images can be converted to a gif but I think it is tricky, not efficient, and difficult to implement. you can give it a try.

Nikhil Biju
  • 645
  • 7
  • 8