Closed mbfakourii closed 1 week ago
Yeah, the quantizers do not support alpha channel.
Yeah, the quantizers do not support alpha channel.
Is it possible to support?
I haven't had a lot of time for the Dart libraries recently, and probably for a little while. I feel bad about it, but life has been really busy.
This isn't an ideal solution of course, but maybe you could manually do some palette manipulation to get gif transparency (untested).
List<int> encodeGifWIthTransparency(Image srcImage, { int transparencyThreshold = 128 }) {
final newImage = quantize(srcImage);
var palette = newImage.palette;
// Quantized palette has 3 channels...manually make a 4 channel palette
if (palette.numChannels == 3) {
final newPalette = new 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);
}
palette = newPalette;
}
// GifEncoder will use palette colors with a 0 alpha as transparent. Look at the pixels
// of the original image and set the alpha of the palette color to 0 if the pixel is below
// a transparency threshold.
for (final p in srcImage) {
if (p.alpha < transparencyThreshold) {
final p2 = newImage.getPixel(p.x, p.y);
final i = p2.index; // palette index of the pixel
palette.setAlpha(i, 0); // Set the palette color alpha to 0
}
}
newImage.data!.palette = palette;
return encodeGif(newImage);
}
@brendan-duncan
I tried to use your code but in
final p2 = newImage.getPixel(p.x, p.y);
The image
class does not have x
and y
values
Also, my srcImage
is empty and it gets an error in the following section
my code
static Future<List<int>?> _exportGif(List<RawFrame> frames) async {
Image aa = Image.empty();
for (final frame in frames) {
final iAsBytes = frame.image.buffer.asUint8List();
final decodedImage = decodePng(iAsBytes);
if (decodedImage == null) {
print('Skipped frame while enconding');
continue;
}
decodedImage.frameDuration = frame.durationInMillis;
aa.frames.add(decodedImage);
}
return encodeGifWIthTransparency(aa);
}
static List<int> encodeGifWIthTransparency(Image srcImage, { int transparencyThreshold = 128 }) {
final newImage = quantize(srcImage);
var palette = newImage.palette;
// Quantized palette has 3 channels...manually make a 4 channel palette
if (palette!.numChannels == 3) {
final newPalette = new 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);
}
palette = newPalette;
}
// // GifEncoder will use palette colors with a 0 alpha as transparent. Look at the pixels
// // of the original image and set the alpha of the palette color to 0 if the pixel is below
// // a transparency threshold.
// for (final Image p in srcImage.frames) {
// if (p.alpha < transparencyThreshold) {
// getColorIndex
// final p2 = newImage.getPixel(p.x, p.y);
// final num i = p2.index; // palette index of the pixel
// palette.setAlpha(i.toInt(), 0); // Set the palette color alpha to 0
// }
// }
newImage.data!.palette = palette;
return encodeGif(newImage);
}
My example code was a pixel iterator, not a frame iterator. To iterate each pixel of each frame,
static PaletteUint8 convertPalette(Palette palette) {
final newPalette = 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);
}
return newPalette;
}
static List<int> encodeGifWIthTransparency(Image srcImage, { int transparencyThreshold = 128 }) {
final newImage = quantize(srcImage);
// // GifEncoder will use palette colors with a 0 alpha as transparent. Look at the pixels
// // of the original image and set the alpha of the palette color to 0 if the pixel is below
// // a transparency threshold.
final numFrames = srcImage.frames.length;
for (var frameIndex = 0; frameIndex < numFrames; frameIndex++) {
final srcFrame = srcImage.frames[frameIndex];
final newFrame = newImage.frames[frameIndex];
final palette = convertPalette(newImage.palette);
for (final srcPixel in srcFrame) {
if (srcPixel.alpha < transparencyThreshold) {
final newPixel = newFrame.getPixel(srcPixel.x, srcPixel.y);
final paletteIndex = newPixel.index; // palette index of the pixel
palette.setAlpha(i.toInt(), 0); // Set the palette color alpha to 0
}
}
newFrame.data!.palette = palette;
}
return encodeGif(newImage);
}
My example code was a pixel iterator, not a frame iterator. To iterate each pixel of each frame,
static PaletteUint8 convertPalette(Palette palette) { final newPalette = 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); } return newPalette; } static List<int> encodeGifWIthTransparency(Image srcImage, { int transparencyThreshold = 128 }) { final newImage = quantize(srcImage); // // GifEncoder will use palette colors with a 0 alpha as transparent. Look at the pixels // // of the original image and set the alpha of the palette color to 0 if the pixel is below // // a transparency threshold. final numFrames = srcImage.frames.length; for (var frameIndex = 0; frameIndex < numFrames; frameIndex++) { final srcFrame = srcImage.frames[frameIndex]; final newFrame = newImage.frames[frameIndex]; final palette = convertPalette(newImage.palette); for (final srcPixel in srcFrame) { if (srcPixel.alpha < transparencyThreshold) { final newPixel = newFrame.getPixel(srcPixel.x, srcPixel.y); final paletteIndex = newPixel.index; // palette index of the pixel palette.setAlpha(i.toInt(), 0); // Set the palette color alpha to 0 } } newFrame.data!.palette = palette; } return encodeGif(newImage); }
The Pixel class does not have an alpha
value
Also, the code in quantize(srcImage);
It has a problem
I'm typing this code without running or testing it, I'm not at a place where I can do that. You'll need to extrapolate the missing pieces.
Pixel derives from Color, and the getter for alpha is a
not alpha
, so use srcPixel.a
.
Thank you very much for your help ❤️❤️, my problem was solved as follows
static Future<List<int>?> _exportGif(List<RawFrame> frames) async {
Image aa = Image.empty();
for (final frame in frames) {
final iAsBytes = frame.image.buffer.asUint8List();
final decodedImage = decodePng(iAsBytes);
if (decodedImage == null) {
print('Skipped frame while enconding');
continue;
}
decodedImage.frameDuration = frame.durationInMillis;
aa.frames.add(encodeGifWIthTransparency(decodedImage));
}
return encodeGif(aa);
}
static PaletteUint8 convertPalette(Palette palette) {
final newPalette = 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);
}
return newPalette;
}
static Image encodeGifWIthTransparency(Image srcImage,
{int transparencyThreshold = 128}) {
final newImage = quantize(srcImage);
// // GifEncoder will use palette colors with a 0 alpha as transparent. Look at the pixels
// // of the original image and set the alpha of the palette color to 0 if the pixel is below
// // a transparency threshold.
final numFrames = srcImage.frames.length;
for (var frameIndex = 0; frameIndex < numFrames; frameIndex++) {
final srcFrame = srcImage.frames[frameIndex];
final newFrame = newImage.frames[frameIndex];
final palette = convertPalette(newImage.palette!);
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
}
}
newFrame.data!.palette = palette;
}
return newImage;
}
I have a problem with black background after output gif.
After checking, I realized that none of the quantizers like
NeuralQuantizer
,OctreeQuantizer
, andBinaryQuantizer
support channel 4 and argb!