protected override void OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback) { GifSaveConfigToken gsct = (GifSaveConfigToken)token; // Flatten and pre-process the image scratchSurface.Clear(ColorBgra.FromBgra(255, 255, 255, 0)); using (RenderArgs ra = new RenderArgs(scratchSurface)) { input.Render(ra, true); } for (int y = 0; y < scratchSurface.Height; ++y) { unsafe { ColorBgra *ptr = scratchSurface.GetRowAddressUnchecked(y); for (int x = 0; x < scratchSurface.Width; ++x) { if (ptr->A < gsct.Threshold) { ptr->Bgra = 0; } else { if (gsct.PreMultiplyAlpha) { int r = ((ptr->R * ptr->A) + (255 * (255 - ptr->A))) / 255; int g = ((ptr->G * ptr->A) + (255 * (255 - ptr->A))) / 255; int b = ((ptr->B * ptr->A) + (255 * (255 - ptr->A))) / 255; int a = 255; *ptr = ColorBgra.FromBgra((byte)b, (byte)g, (byte)r, (byte)a); } else { ptr->Bgra |= 0xff000000; } } ++ptr; } } } using (Bitmap quantized = Quantize(scratchSurface, gsct.DitherLevel, 255, progressCallback)) { quantized.Save(output, ImageFormat.Gif); } }
protected GifSaveConfigToken(GifSaveConfigToken cloneMe) { this.threshold = cloneMe.threshold; this.preMultiplyAlpha = cloneMe.preMultiplyAlpha; this.ditherLevel = cloneMe.ditherLevel; }