Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 59 additions & 26 deletions lib/src/exporter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -30,8 +31,7 @@ class Exporter {
}
final bytesImages = <RawFrame>[];
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;
Expand All @@ -50,31 +50,46 @@ class Exporter {
return bytesImages;
}

Future<List<int>?> exportGif() async {
Future<List<int>?> 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<List<int>?> _exportGif(DataHolder data) async {
List<RawFrame> 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(
Expand All @@ -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
Expand All @@ -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
}
}

Expand All @@ -141,10 +160,24 @@ class RawFrame {
}

class DataHolder {
DataHolder(this.frames, this.width, this.height);

List<RawFrame> 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<RawFrame> frames;
final int width;
final int height;

final bool singleFrame;
final int repeat;
final int samplingFactor;
final image.DitherKernel dither;
final bool ditherSerpentine;
}