export_video_frame 0.0.5+4

  • Readme
  • Changelog
  • Example
  • Installing
  • 48

Export Video frame for Flutter #

A Flutter plugin for iOS and Android for exporting picture from video file.

Installation #

add export_video_frame as a dependency in your pubspec.yaml file.

Usage #


/// Returns whether clean success
  static Future<bool> cleanImageCache() async {
    final String result = await _channel.invokeMethod('cleanImageCache');
    if (result == "success") {
      return true;
    }
    return false;
  }

  /// Save image to album
  ///
  /// - parameters:
  ///    - file: file of video
  ///    - albumName: save the album name
  ///    - waterMark:assetName "images/water_mark.png"
  ///    - alignment: [0,0]represents the center of the rectangle. 
  ///      from -1.0 to +1.0 is the distance from one side of the rectangle to the other side of the rectangle.
  ///      Default value [1,1] repesent right bottom
  ///    - scale: the scale ratio with respect water image size.Default value is 1.0
  /// Returns whether save success
  static Future<bool> saveImage(File file, String albumName,{String waterMark,Alignment alignment,double scale}) async {
    Map<String,dynamic> para = {"filePath":file.path,"albumName":albumName};
    if (waterMark != null) {
      para.addAll({"waterMark":waterMark});
      if (alignment != null) {
        para.addAll({"alignment":{"x":alignment.x,"y":alignment.y}});
      } else {
        para.addAll({"alignment":{"x":1,"y":1}});
      }
      if (scale != null) {
        para.addAll({"scale":scale});
      } else {
        para.addAll({"scale":1.0});
      }
    }
    final bool result =
        await _channel.invokeMethod('saveImage', para);
    return result;
  }

  /// Returns the file list of the exporting image
  ///
  /// - parameters:
  ///    - filePath: file path of video
  ///    - number: export the number of frames
  ///    - quality: scale of export frame."0" is lowest,"1" is origin.("0" is scale for 0.1 in android) 
  static Future<List<File>> exportImage(String filePath, int number,double quality) async {
    var para = {"filePath":filePath,"number":number,"quality":quality};
    final List<dynamic> list =
        await _channel.invokeMethod('exportImage', para);
    var result = list
        .cast<String>()
        .map((path) => File.fromUri(Uri.file(path)))
        .toList();
    return result;
  }

  /// Returns the file list of the exporting image
  ///
  /// - parameters:
  ///    - file: file of video
  ///    - duration: export the duration of frames
  ///    - radian: rotation the frame ,which will export frame.Rotation is clockwise.
  static Future<File> exportImageBySeconds(File file, Duration duration,double radian) async {
    var milli = duration.inMilliseconds;
    var para = {"filePath":file.path,"duration":milli,"radian":radian};
    final String path = await _channel
        .invokeMethod('exportImageBySeconds', para);
    try {
      var result = File.fromUri(Uri.file(path));
      return result;
    } catch (e) {
      throw e;
    }
  }

  /// Returns the file list of the exporting frame for gif file
  ///
  /// - parameters:
  ///    - filePath: file path of video
  ///    - quality: scale of export frame."0" is lowest,"1" is origin.("0" is scale for 0.1 in android) 
  static Future<List<File>> exportGifImage(String filePath, double quality) async {
    var para = {"filePath":filePath,"quality":quality};
    final List<dynamic> list =
        await _channel.invokeMethod('exportGifImagePathList', para);
    var result = list
        .cast<String>()
        .map((path) => File.fromUri(Uri.file(path)))
        .toList();
    return result;
  }

ios #

If there will be an error when compile ios app.Because flutter use swift is 4.0. located in ios/Podfile Edit your Podfile as follows:


target 'Runner' do
  use_frameworks! # <--- add this
  ...
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['ENABLE_BITCODE'] = 'NO'
      config.build_settings['SWIFT_VERSION'] = '4.2' # <--- add this
    end
  end
end

If you use saveAblum api,you need add the add the following keys to your Info.plist file, located ios/Runner/Info.plist:


<key>NSPhotoLibraryUsageDescription</key>
<string>Use Ablum For your purpose</string>

Android #

Make sure you add the needed permissions to your Android Manifest Permission.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Example Demo

CHANGELOG #

0.0.1 #

two interface

  • Export Image according to total number image
  • clean cache image

0.02 #

new add two interface

  • Export Image according to duration
  • save image to album

0.0.2+2 #

  • fix ios export image error sometimes

0.0.2+3 #

  • fix some android device get album path error.

0.0.2+4 #

  • That save the image to the ablum move to the main thread in android

0.0.2+5 #

  • fix bug : after save image to ablum ,but cann't immediately show .
  • That save the image to the ablum recover the sub thread

0.0.2+6 #

  • optimize the performance,which export image by number in ios platform

0.0.3 #

  • add parameter for export frame.That can configure the quality,rotation of the frame

0.0.3+1 #

  • fix rotation image direct problem in ios device.Guarantee rotation is clockwise.

0.0.4 #

add new api

  • Export Image frame for gif file

0.0.4+1 #

  • Export Image for gif file in Android

0.0.5 #

  • Can add watermark when save Image to ablum

0.0.5+1 #

  • set watermark position

0.0.5+2 #

  • set watermark alignment and scale

0.0.5+3 #

  • fix no water mark export fail bug

0.0.5+4 #

  • android call back to main thread

example/README.md

export_video_frame_example #

Demonstrates how to use the export_video_frame plugin.

Getting Started #

  1. need add image_picker as a dependency in your Demo pubspec.yaml file for example.
  2. add the follow code in example

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:export_video_frame/export_video_frame.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Plugin Example App",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(images: <Image>[]),
    );
  }
}

class ImageItem extends StatelessWidget {
  ImageItem({this.image}) : super(key: ObjectKey(image));
  final Image image;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: image
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.images}) : super(key: key);

  final List<Image> images;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var _isClean = false;
  Future _getImages() async {
    var file = await ImagePicker.pickVideo(source: ImageSource.gallery);
    var images = await ExportVideoFrame.exportImage(file.path,10,0);
    var result = images.map((file) => Image.file(file)).toList();
    setState(() {
      widget.images.addAll(result);
      _isClean = true;
    });
  }

  Future _getImagesByDuration() async {
    var file = await ImagePicker.pickVideo(source: ImageSource.gallery);
    var duration = Duration(seconds: 1);
    var image = await ExportVideoFrame.exportImageBySeconds(file, duration,pi/2);
    setState(() {
      widget.images.add(Image.file(image));
      _isClean = true;
    });
    await ExportVideoFrame.saveImage(image, "Video Export Demo");
  }

  Future _cleanCache() async {
    var result = await ExportVideoFrame.cleanImageCache();
    print(result);
    setState(() {
      widget.images.clear();
      _isClean = false;
    });
  }

  Future _handleClickFirst() async {
    if (_isClean) {
      await _cleanCache();
    } else {
      await _getImages();
    }
  }

  Future _handleClickSecond() async {
    if (_isClean) {
      await _cleanCache();
    } else {
      await _getImagesByDuration();
    }
  }
  
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text("Export Image"),
      ),
      body: Container(
        padding: EdgeInsets.zero,
        child: Column(
          children: <Widget>[
            Expanded(
              flex: 1,
              child: 
                GridView.extent(
                maxCrossAxisExtent: 400,
                childAspectRatio: 1.0,
                padding: const EdgeInsets.all(4),
                mainAxisSpacing: 4,
                crossAxisSpacing: 4,
                children: widget.images.length > 0 ? widget.images.map((image) => ImageItem(image:image)).toList() : [Container()]
              ),
            ),
            Expanded(
              flex: 0,
              child: Center(
                child: MaterialButton(
                  padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
                  height: 40,
                  minWidth: 100,
                  onPressed: () {
                    _handleClickFirst();
                  },
                  color: Colors.orange,
                  child: Text(_isClean ? "Clean" : "Export image list"),
                ),
              ),
            ),
            Expanded(
              flex: 0,
              child: Center(
                child: MaterialButton(
                  padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
                  height: 40,
                  minWidth: 150,
                  onPressed: () {
                    _handleClickSecond();
                  },
                  color: Colors.orange,
                  child: Text(_isClean ? "Clean" : "Export one image and save"),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

iOS #

Add the following keys to your Info.plist file, located in 'yourproject/ios/Runner/Info.plist': NSPhotoLibraryUsageDescription - describe why your app needs permission for the photo library. This is called Privacy - Photo Library Usage Description in the visual editor.

Android #

Make sure you add the needed permissions to your Android Manifest Permission.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  export_video_frame: ^0.0.5+4

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:export_video_frame/export_video_frame.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
48
Learn more about scoring.

We analyzed this package on Nov 15, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.6.0
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.6

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Format lib/export_video_frame.dart.

Run flutter format to format lib/export_video_frame.dart.

Maintenance suggestions

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.7 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test