diff --git a/lib/src/exporter.dart b/lib/src/exporter.dart index ebfbeb0..f6a4951 100644 --- a/lib/src/exporter.dart +++ b/lib/src/exporter.dart @@ -2,6 +2,7 @@ import 'dart:ui' as ui show ImageByteFormat; import 'package:flutter/foundation.dart'; import 'package:image/image.dart' as image; + import 'frame.dart'; class Exporter { @@ -30,8 +31,7 @@ class Exporter { } final bytesImages = []; for (final frame in _frames) { - final bytesImage = - await frame.image.toByteData(format: ui.ImageByteFormat.png); + final bytesImage = await frame.image.toByteData(format: ui.ImageByteFormat.png); if (frame.image.width >= _maxWidthFrame) { _maxWidthFrame = frame.image.width; @@ -50,31 +50,46 @@ class Exporter { return bytesImages; } - Future?> exportGif() async { + Future?> exportGif({ + bool singleFrame = false, + int repeat = 0, + int samplingFactor = 10, + image.DitherKernel dither = image.DitherKernel.floydSteinberg, + bool ditherSerpentine = false, + }) async { final frames = await exportFrames(); if (frames == null) { return null; } return compute( - _exportGif, DataHolder(frames, _maxWidthFrame, _maxHeightFrame)); + _exportGif, + DataHolder( + frames, + _maxWidthFrame, + _maxHeightFrame, + singleFrame: singleFrame, + repeat: repeat, + samplingFactor: samplingFactor, + dither: dither, + ditherSerpentine: ditherSerpentine, + ), + ); } static Future?> _exportGif(DataHolder data) async { - List frames = data.frames; - int width = data.width; - int height = data.height; + final frames = data.frames; + final width = data.width; + final height = data.height; image.Image mainImage = image.Image.empty(); for (final frame in frames) { - final iAsBytes = frame.image.buffer.asUint8List(); - final decodedImage = image.decodePng(iAsBytes); + final decodedImage = image.decodePng(frame.image.buffer.asUint8List()); + + if (decodedImage == null) continue; - if (decodedImage == null) { - debugPrint('Skipped frame while enconding'); - continue; - } decodedImage.frameDuration = frame.durationInMillis; + mainImage.frames.add( _encodeGifWIthTransparency( image.copyExpandCanvas( @@ -92,20 +107,25 @@ class Exporter { ); } - return image.encodeGif(mainImage); + return image.encodeGif( + mainImage, + singleFrame: data.singleFrame, + repeat: data.repeat, + samplingFactor: data.samplingFactor, + dither: data.dither, + ditherSerpentine: data.ditherSerpentine, + ); } static image.PaletteUint8 _convertPalette(image.Palette palette) { final newPalette = image.PaletteUint8(palette.numColors, 4); for (var i = 0; i < palette.numColors; i++) { - newPalette.setRgba( - i, palette.getRed(i), palette.getGreen(i), palette.getBlue(i), 255); + newPalette.setRgba(i, palette.getRed(i), palette.getGreen(i), palette.getBlue(i), 255); } return newPalette; } - static image.Image _encodeGifWIthTransparency(image.Image srcImage, - {int transparencyThreshold = 1}) { + static image.Image _encodeGifWIthTransparency(image.Image srcImage, {int transparencyThreshold = 1}) { final newImage = image.quantize(srcImage); // GifEncoder will use palette colors with a 0 alpha as transparent. Look at the pixels @@ -121,8 +141,7 @@ class Exporter { for (final srcPixel in srcFrame) { if (srcPixel.a < transparencyThreshold) { final newPixel = newFrame.getPixel(srcPixel.x, srcPixel.y); - palette.setAlpha( - newPixel.index.toInt(), 0); // Set the palette color alpha to 0 + palette.setAlpha(newPixel.index.toInt(), 0); // Set the palette color alpha to 0 } } @@ -141,10 +160,24 @@ class RawFrame { } class DataHolder { - DataHolder(this.frames, this.width, this.height); - - List frames; - - int width; - int height; + DataHolder( + this.frames, + this.width, + this.height, { + this.singleFrame = false, + this.repeat = 0, + this.samplingFactor = 10, + this.dither = image.DitherKernel.floydSteinberg, + this.ditherSerpentine = false, + }); + + final List frames; + final int width; + final int height; + + final bool singleFrame; + final int repeat; + final int samplingFactor; + final image.DitherKernel dither; + final bool ditherSerpentine; }