diff --git a/README.md b/README.md index 049f241..67e4e40 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,36 @@ # thumbnails -A Flutter Plugin to generate thumbnails from videos on Android devices +A Flutter Plugin to generate thumbnails from videos. -## Getting Started +## Compatibility +Android OS only -For help getting started with Flutter, view our online -[documentation](https://flutter.io/). +## Usage -For help on editing plugin code, view the [documentation](https://flutter.io/developing-packages/#edit-plugin-package). +#### Depend on it +add `thumbnails` as a dependency in your pubspec.yaml file. + +#### Add import statement +Import the library via +``` dart +import 'package:thumbnails/thumbnails.dart'; +``` + +#### Examples +``` dart + // Fetch thumbnail, store in a specified output folder and return file path + String thumb = await Thumbnails.getThumbnail( + thumbOutputFile: + '[YOUR OUTPUT FILE HERE]', + videoFile: '[VIDEO PATH HERE]', + imageType: ThumbFormat.PNG, + quality: 30); + + +// Fetch thumbnail, store in app's Temporary directory output folder and return file path + String thumb = await Thumbnails.getThumbnail( + videoFile: 'VIDEO PATH HERE', + imageType: ThumbFormat.JPEG, + quality: 45); + +``` \ No newline at end of file diff --git a/android/src/main/java/com/asapjay/thumbnails/ThumbnailsPlugin.java b/android/src/main/java/com/asapjay/thumbnails/ThumbnailsPlugin.java index 6d5bf00..e5833c0 100644 --- a/android/src/main/java/com/asapjay/thumbnails/ThumbnailsPlugin.java +++ b/android/src/main/java/com/asapjay/thumbnails/ThumbnailsPlugin.java @@ -2,6 +2,7 @@ import android.graphics.Bitmap; import android.media.ThumbnailUtils; +import android.net.Uri; import android.provider.MediaStore; import android.util.Log; @@ -23,9 +24,15 @@ public class ThumbnailsPlugin implements MethodCallHandler { /** * Plugin registration. */ + private Registrar mRegistrar; + + private ThumbnailsPlugin(Registrar mRegistrar) { + this.mRegistrar = mRegistrar; + } + public static void registerWith(Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), "thumbnails"); - channel.setMethodCallHandler(new ThumbnailsPlugin()); + channel.setMethodCallHandler(new ThumbnailsPlugin(registrar)); } @Override @@ -38,8 +45,8 @@ public void onMethodCall(MethodCall call, Result result) { int imageType = (int) arguments.get("thumbnailFormat"); int quality = (int) arguments.get("thumbnailQuality"); try { - buildThumbnail(videoFile, thumbOutputFile, imageType, quality); - result.success("success"); + String thumbnailPath = buildThumbnail(videoFile, thumbOutputFile, imageType, quality); + result.success(thumbnailPath); } catch (Throwable throwable) { throwable.printStackTrace(); } @@ -48,25 +55,73 @@ public void onMethodCall(MethodCall call, Result result) { } } - private void buildThumbnail(String vidPath, String thumbPath, int type, int quality) { + private String buildThumbnail(String vidPath, String thumbPath, int type, int quality) { + if (vidPath == null || vidPath.equals("")) { + Log.println(Log.INFO, "WARNING", "Thumbnails: Video Path must not be null or empty!"); + return null; + } + return thumbPath == null ? cacheDirectory(vidPath, type, quality) : userDirectory(vidPath, thumbPath, type, quality); + + } + + private String cacheDirectory(String vidPath, int type, int quality) { + Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(vidPath, MediaStore.Video.Thumbnails.MINI_KIND); + String sourceFileName = Uri.parse(vidPath).getLastPathSegment(); + String thumbDirPath = mRegistrar.context().getExternalCacheDir() + File.separator + "ThumbFiles" + File.separator; + String tempFile = thumbDirPath + sourceFileName; + File tempDir = new File(thumbDirPath); - if (vidPath == null || vidPath == "") { - Log.println(Log.INFO, "WARNING", "Thumbnails: Video Path must not be null or empty"); - return; + if (tempDir.exists()) { + clearThumbnails(); + } else { + tempDir.mkdirs(); } - if (thumbPath == null || thumbPath == "") { - Log.println(Log.INFO, "WARNING", "Thumbnails: Thumbnail Path must not be null or empty"); - return; + + switch (type) { + case 1: + try { + FileOutputStream out = new FileOutputStream(new File(tempFile + ".jpg")); + bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out); + out.flush(); + out.close(); + return tempFile + ".jpg"; + } catch (IOException e) { + e.printStackTrace(); + } + case 2: + try { + FileOutputStream out = new FileOutputStream(new File(tempFile + ".png")); + bitmap.compress(Bitmap.CompressFormat.PNG, quality, out); + out.flush(); + out.close(); + return tempFile + ".png"; + } catch (IOException e) { + e.printStackTrace(); + } + case 3: + try { + FileOutputStream out = new FileOutputStream(new File(tempFile + ".webp")); + bitmap.compress(Bitmap.CompressFormat.WEBP, quality, out); + out.flush(); + out.close(); + return tempFile + ".webp"; + } catch (IOException e) { + e.printStackTrace(); + } } + return ""; + } + private String userDirectory(String vidPath, String thumbPath, int type, int quality) { Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(vidPath, MediaStore.Video.Thumbnails.MINI_KIND); switch (type) { case 1: try { - FileOutputStream out = new FileOutputStream(new File(thumbPath)); + FileOutputStream out = new FileOutputStream(new File(thumbPath + ".jpg")); bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out); out.flush(); out.close(); + return thumbPath + ".jpg"; } catch (IOException e) { e.printStackTrace(); } @@ -74,25 +129,39 @@ private void buildThumbnail(String vidPath, String thumbPath, int type, int qual case 2: try { - FileOutputStream out = new FileOutputStream(new File(thumbPath)); + FileOutputStream out = new FileOutputStream(new File(thumbPath + ".png")); bitmap.compress(Bitmap.CompressFormat.PNG, quality, out); out.flush(); out.close(); + return thumbPath + ".png"; } catch (IOException e) { e.printStackTrace(); } break; case 3: try { - FileOutputStream out = new FileOutputStream(new File(thumbPath)); + FileOutputStream out = new FileOutputStream(new File(thumbPath + "webp")); bitmap.compress(Bitmap.CompressFormat.WEBP, quality, out); out.flush(); out.close(); + return thumbPath + ".webp"; } catch (IOException e) { e.printStackTrace(); } break; + } + return ""; + } + private void clearThumbnails() { + String tempDirPath = mRegistrar.context().getExternalCacheDir() + + File.separator + "TempFiles" + File.separator; + File tempDir = new File(tempDirPath); + if (tempDir.exists()) { + String[] children = tempDir.list(); + for (String file : children) { + new File(tempDir, file).delete(); + } } } } diff --git a/example/lib/main.dart b/example/lib/main.dart index 10fd477..b4e6e10 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,7 +1,4 @@ import 'package:flutter/material.dart'; -import 'dart:async'; - -import 'package:flutter/services.dart'; import 'package:thumbnails/thumbnails.dart'; void main() => runApp(new MyApp()); @@ -12,33 +9,24 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - - @override - void initState() { - super.initState(); - // initPlatformState(); - } - - // Platform messages are asynchronous, so we initialize in an async method. - Future initPlatformState() async { - String platformVersion; - // Platform messages may fail, so we use a try/catch PlatformException. - try { - await Thumbnails.getThumbnail( - thumbOutputFile: '/storage/emulated/0/Whatsapp/Media/Test${TimeOfDay.now()}.jpg', + // Fetch thumbnail and store in a specified output folder + void _buildThumbToFile() async { + String thumb = await Thumbnails.getThumbnail( + thumbOutputFile: + '/storage/emulated/0/Whatsapp/Media/Test${TimeOfDay.now()}.jpg', videoFile: '/storage/emulated/0/Whatsapp/Media/.Statuses/Testvid.mp4', imageType: ThumbFormat.PNG, - quality: 30 - ); - } on PlatformException { - platformVersion = 'Failed to get platform version.'; - } - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - if (!mounted) return; + quality: 30); + print(thumb); + } +// Fetch thumbnail and stores in app temporary directory (this is volatile) + void _buildThumbToCache() async { + String thumb = await Thumbnails.getThumbnail( + videoFile: '/storage/emulated/0/Whatsapp/Media/.Statuses/Testvid.mp4', + imageType: ThumbFormat.JPEG, + quality: 30); + print(thumb); } @override @@ -49,9 +37,13 @@ class _MyAppState extends State { title: const Text('Plugin example app'), ), body: new Center( - child: FlatButton( - onPressed: ()=> initPlatformState(), - child: Text('Press Me'), + child: Column( + children: [ + RaisedButton( + onPressed: _buildThumbToFile, child: Text('Build To File')), + RaisedButton( + onPressed: _buildThumbToCache, child: Text('Build to Cache')), + ], ), ), ), diff --git a/lib/thumbnails.dart b/lib/thumbnails.dart index 7018256..70a2086 100644 --- a/lib/thumbnails.dart +++ b/lib/thumbnails.dart @@ -5,23 +5,13 @@ import 'package:flutter/services.dart'; import 'package:thumbnails/validators.dart'; enum ThumbFormat { PNG, JPEG, WEBP } -class Thumbnails { - String videoFile; - String thumbOutputFile; - int imageType; - int quality; - - Thumbnails( - {@required this.videoFile, - @required this.thumbOutputFile, - this.imageType, - this.quality}); +class Thumbnails { static const MethodChannel _channel = const MethodChannel('thumbnails'); - static Future getThumbnail( + static Future getThumbnail( {@required String videoFile, - @required String thumbOutputFile, + String thumbOutputFile, ThumbFormat imageType, int quality}) async { var utilMap = { @@ -30,10 +20,7 @@ class Thumbnails { 'thumbnailFormat': validateType(imageType), 'thumbnailQuality': validateQuality(quality) }; - await _channel.invokeMethod('getThumbnail', utilMap); - print('done!!'); + String thumbnailPath = await _channel.invokeMethod('getThumbnail', utilMap); + return thumbnailPath; } - - - } diff --git a/lib/validators.dart b/lib/validators.dart index 11d1a7e..ece8ddf 100644 --- a/lib/validators.dart +++ b/lib/validators.dart @@ -1,4 +1,3 @@ - import 'package:thumbnails/thumbnails.dart'; const DEFAULT_THUMB_QUALITY = 50;