2

enter image description here

I am using ImageSharp to save a half transparent image into GIF, but gif is saved with white background, no transparency.

var gifEnc = new SixLabors.ImageSharp.Formats.Gif.GifEncoder();
edited.Save(cache, gifEnc);

Gif Output, white background, instead of transparent:

enter image description here

AVEbrahimi
  • 17,993
  • 23
  • 107
  • 210
  • Just as a comment rather than an answer because I cannot tell the solution purely in ImageSharp. Is it possible to get the backing bitmap data as an array or unmanaged buffer in whatever pixel format from your `edited` instance? If so, you can use my [drawing libraries](https://github.com/koszeggy/KGySoft.Drawing) that happens to have a [GIF Encoder](https://docs.kgysoft.net/drawing/html/T_KGySoft_Drawing_Imaging_GifEncoder.htm) that [handles](https://github.com/NickeManarin/ScreenToGif/issues/1069) alpha fairly well. Let me know if you are interested in such a solution/answer. – György Kőszeg Feb 22 '23 at 09:22
  • 1
    GIF does not support half transparency. It only allows you to specify one color in the palette to be *fully* transparent. – Cobra_Fast Feb 22 '23 at 10:48
  • @Cobra_Fast Ok, but ImageSharp does not allow to specify that transparent color. – AVEbrahimi Feb 22 '23 at 13:40
  • 1
    Maybe you should ask this in the GitHub discussions for the library? ImageSharp handles transparency in gifs well and given the lack of information in the question it's impossible to see what is going on. – James South Feb 24 '23 at 13:47

1 Answers1

1

Encouraged by your confirmation in the comments now I'm adding a non-ImageSharp solution. Instead, it uses my GIF Encoder from this NuGet package.

1. Obtain an IReadableBitmapData instance from your image

Assuming you work with ImageSharp images:

using SixLabors.ImageSharp;
using KGySoft.Drawing.Imaging;

// [...]

// Loading your image as an ImageSharp image with a specific pixel format.
// If you have a non-generic Image instance use the CloneAs<Bgra32>() method.
using var img = Image.Load<Bgra32>(fileName);

// Copying the raw pixel data into an array
// Now it's Bgra32[] but you can use a byte array, too
var asArray = new Bgra32[img.Width * img.Height]; // * 4 if byte[]
img.CopyPixelDataTo(asArray);

// Obtaining a bitmap data from the array
using IReadableBitmapData bitmapData = BitmapDataFactory.CreateBitmapData(
    asArray, new System.Drawing.Size(img.Width, img.Height),
    stride: img.Width * 4,
    pixelFormat: KnownPixelFormat.Format32bppArgb);

// TODO: work with bitmapData

If performance is crucial you can try to spare copying pixels and just access the image buffer directly by DangerousTryGetSinglePixelMemory if possible. You have a better chance if you load the image with new Configuration { PreferContiguousImageBuffers = true }.

// If it returns true no copying is necessary
if (img.DangerousTryGetSinglePixelMemory(out Memory<Bgra32> memory))
{
    // please note that the memory gets unpinned after leaving the scope
    // so bitmapData must be used in the same scope to prevent corruption
    using MemoryHandle handle = memory.Pin();
    using IReadableBitmapData bitmapData = BitmapDataFactory.CreateBitmapData(
        (IntPtr)handle.Pointer, new System.Drawing.Size(img.Width, img.Height),
            stride: img.Width * 4,
            pixelFormat: KnownPixelFormat.Format32bppArgb);

    // TODO: work with bitmapData that uses the same memory as the image
}

Alternatively, if you are not tied to ImageSharp you can use one of the specialized packages of the directly supported frameworks. Then obtaining a bitmap data is as simple as follows:

using IReadableBitmapData bitmapData = myBitmap.GetReadableBitmapData();
// TODO: work with bitmapData

2. Encode GIF

Once you have the bitmap data, this is really simple. Ideally, the solution is a single line:

// using KGySoft.Imaging.GifEncoder with default configuration:
GifEncoder.EncodeImage(bitmapData, myStream);

For the 32bpp pixel format selected above the EncodeImage method will use the Wu quantizer with alpha threshold = 128. This must work as requested but if you want to adjust transparency you can pass a non-null quantizer to the method. And, if your sources are high color images you also may want to specify the ditherer parameter to preserve the details better. See more details about quantizing and dithering here.

György Kőszeg
  • 17,093
  • 6
  • 37
  • 65
  • Although it added a couple of DLLs to project, but worked. – AVEbrahimi Feb 23 '23 at 05:16
  • This isn't a good answer. It bypasses the library in question which fully supports transparent gif. Given that the OP did not provide meaningful detail in their question, an answer involving the library cannot be provided. – James South Feb 26 '23 at 04:43
  • @JamesSouth: first I didn't intend to add this answer, see the comments under the question. My library is explicitly designed to be able to cooperate with any 3rd party bitmap representation of any custom pixel formats so declaring this as bad answer per se (after confirming that a pure ImageSharp solution is not a constraint) doesn't seem to be correct. I created my GIF encoder because I wasn't satisfied with the [results](https://github.com/NickeManarin/ScreenToGif/issues/1069) of other libraries. But fortunately this is SO where a _better_ answer always can be added, even for old questions. – György Kőszeg Feb 26 '23 at 09:29