internal override Set <SavableBitDepths> CreateAllowedBitDepthListFromToken(PropertyBasedSaveConfigToken token) { PngBitDepthUIChoices bitDepthFromToken = (PngBitDepthUIChoices)token.GetProperty <StaticListChoiceProperty>(PropertyNames.BitDepth).Value; Set <SavableBitDepths> bitDepths = new Set <SavableBitDepths>(); switch (bitDepthFromToken) { case PngBitDepthUIChoices.AutoDetect: bitDepths.AddRange(SavableBitDepths.Rgb24, SavableBitDepths.Rgb8, SavableBitDepths.Rgba32, SavableBitDepths.Rgba8); break; case PngBitDepthUIChoices.Bpp24: bitDepths.AddRange(SavableBitDepths.Rgb24); break; case PngBitDepthUIChoices.Bpp32: bitDepths.AddRange(SavableBitDepths.Rgba32); break; case PngBitDepthUIChoices.Bpp8: bitDepths.AddRange(SavableBitDepths.Rgb8, SavableBitDepths.Rgba8); break; default: throw new InvalidEnumArgumentException("bitDepthFromToken", (int)bitDepthFromToken, typeof(PngBitDepthUIChoices)); } return(bitDepths); }
protected override bool IsReflexive(PropertyBasedSaveConfigToken token) { PngBitDepthUIChoices bitDepth = (PngBitDepthUIChoices)token.GetProperty <StaticListChoiceProperty>(PropertyNames.BitDepth).Value; // Only 32-bit is reflexive return(bitDepth == PngBitDepthUIChoices.Bpp32); }
internal override void FinalSave( Document input, Stream output, Surface scratchSurface, int ditherLevel, SavableBitDepths bitDepth, PropertyBasedSaveConfigToken token, ProgressEventHandler progressCallback) { bool enableAlpha; switch (bitDepth) { case SavableBitDepths.Rgb8: enableAlpha = false; break; case SavableBitDepths.Rgba8: enableAlpha = true; break; default: throw new InvalidEnumArgumentException("bitDepth", (int)bitDepth, typeof(SavableBitDepths)); } using (Bitmap quantized = Quantize(scratchSurface, ditherLevel, 256, enableAlpha, progressCallback)) { quantized.Save(output, ImageFormat.Gif); } }
internal abstract void FinalSave( Document input, Stream output, Surface scratchSurface, int ditherLevel, SavableBitDepths bitDepth, PropertyBasedSaveConfigToken token, ProgressEventHandler progressCallback);
internal override Set <SavableBitDepths> CreateAllowedBitDepthListFromToken(PropertyBasedSaveConfigToken token) { var bitDepths = new Set <SavableBitDepths>(); bitDepths.Add(SavableBitDepths.Rgb8); bitDepths.Add(SavableBitDepths.Rgba8); return(bitDepths); }
internal override void FinalSave( Document input, Stream output, Surface scratchSurface, int ditherLevel, SavableBitDepths bitDepth, PropertyBasedSaveConfigToken token, ProgressEventHandler progressCallback) { // finally, do the save. if (bitDepth == SavableBitDepths.Rgb24) { // In order to save memory, we 'squish' the 32-bit bitmap down to 24-bit in-place // instead of allocating a new bitmap and copying it over. SquishSurfaceTo24Bpp(scratchSurface); ImageCodecInfo icf = GdiPlusFileType.GetImageCodecInfo(ImageFormat.Bmp); EncoderParameters parms = new EncoderParameters(1); EncoderParameter parm = new EncoderParameter(Encoder.ColorDepth, 24); parms.Param[0] = parm; using (Bitmap bitmap = CreateAliased24BppBitmap(scratchSurface)) { GdiPlusFileType.LoadProperties(bitmap, input); bitmap.Save(output, icf, parms); } } else if (bitDepth == SavableBitDepths.Rgb8) { using (Bitmap quantized = Quantize(scratchSurface, ditherLevel, 256, false, progressCallback)) { ImageCodecInfo icf = GdiPlusFileType.GetImageCodecInfo(ImageFormat.Bmp); EncoderParameters parms = new EncoderParameters(1); EncoderParameter parm = new EncoderParameter(Encoder.ColorDepth, 8); parms.Param[0] = parm; GdiPlusFileType.LoadProperties(quantized, input); quantized.Save(output, icf, parms); } } else { throw new InvalidEnumArgumentException("bitDepth", (int)bitDepth, typeof(SavableBitDepths)); } }
protected override void OnSaveT(Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback) { int quality = token.GetProperty <Int32Property>(PropertyNames.Quality).Value; ImageCodecInfo icf = GdiPlusFileType.GetImageCodecInfo(ImageFormat.Jpeg); EncoderParameters parms = new EncoderParameters(1); EncoderParameter parm = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality); parms.Param[0] = parm; scratchSurface.Clear(ColorBgra.White); using (RenderArgs ra = new RenderArgs(scratchSurface)) { input.Render(ra, false); } using (Bitmap bitmap = scratchSurface.CreateAliasedBitmap()) { GdiPlusFileType.LoadProperties(bitmap, input); bitmap.Save(output, icf, parms); } }
internal override int GetDitherLevelFromToken(PropertyBasedSaveConfigToken token) { int ditherLevel = token.GetProperty <Int32Property>(PropertyNames.DitherLevel).Value; return(ditherLevel); }
internal override int GetThresholdFromToken(PropertyBasedSaveConfigToken token) { int threshold = token.GetProperty <Int32Property>(PropertyNames.Threshold).Value; return(threshold); }
internal override int GetThresholdFromToken(PropertyBasedSaveConfigToken token) { return(0); }
private PropertyBasedSaveConfigToken(PropertyBasedSaveConfigToken copyMe) : base(copyMe) { this.properties = copyMe.properties.Clone(); }
protected unsafe override sealed void OnSaveT( Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback) { // flatten the document -- render w/ transparent background scratchSurface.Clear(ColorBgra.Transparent); using (RenderArgs ra = new RenderArgs(scratchSurface)) { input.Render(ra, false); } // load properties from token int thresholdFromToken = GetThresholdFromToken(token); int ditherLevel = GetDitherLevelFromToken(token); Set <SavableBitDepths> allowedBitDepths = CreateAllowedBitDepthListFromToken(token); if (allowedBitDepths.Count == 0) { throw new ArgumentException("there must be at least 1 element returned from CreateAllowedBitDepthListFromToken()"); } // allowedBitDepths.Count >= 1 // set to 1 unless allowedBitDepths contains only Rgb8 and Rgba8 int threshold; if (allowedBitDepths.IsSubsetOf(Set.Create(SavableBitDepths.Rgb8, SavableBitDepths.Rgba8))) { threshold = thresholdFromToken; } else { threshold = 1; } // Analyze image, try to detect what bit-depth or whatever to use, based on allowedBitDepths bool allOpaque; bool all0or255Alpha; int uniqueColorCount; Analyze(scratchSurface, out allOpaque, out all0or255Alpha, out uniqueColorCount); Set <SavableBitDepths> losslessBitDepths = new Set <SavableBitDepths>(); losslessBitDepths.Add(SavableBitDepths.Rgba32); if (allOpaque) { losslessBitDepths.Add(SavableBitDepths.Rgb24); if (uniqueColorCount <= 256) { losslessBitDepths.Add(SavableBitDepths.Rgb8); } } else if (all0or255Alpha && uniqueColorCount < 256) { losslessBitDepths.Add(SavableBitDepths.Rgba8); } SavableBitDepths bitDepth = ChooseBitDepth(allowedBitDepths, losslessBitDepths, allOpaque, all0or255Alpha, uniqueColorCount); if (bitDepth == SavableBitDepths.Rgba8 && threshold == 0 && allowedBitDepths.Contains(SavableBitDepths.Rgba8) && allowedBitDepths.Contains(SavableBitDepths.Rgb8)) { // threshold of 0 should effectively force full 256 color palette, instead of 255+1 transparent bitDepth = SavableBitDepths.Rgb8; } // if bit depth is 24 or 8, then we have to do away with the alpha channel // for 8-bit, we must have pixels that have either 0 or 255 alpha if (bitDepth == SavableBitDepths.Rgb8 || bitDepth == SavableBitDepths.Rgba8 || bitDepth == SavableBitDepths.Rgb24) { UserBlendOps.NormalBlendOp blendOp = new UserBlendOps.NormalBlendOp(); for (int y = 0; y < scratchSurface.Height; ++y) { for (int x = 0; x < scratchSurface.Width; ++x) { ColorBgra p = scratchSurface[x, y]; if (p.A < threshold && bitDepth == SavableBitDepths.Rgba8) { p = ColorBgra.FromBgra(0, 0, 0, 0); } else { p = blendOp.Apply(ColorBgra.White, p); } scratchSurface[x, y] = p; } } } Tracing.Ping("Chose " + bitDepth + ", ditherLevel=" + ditherLevel + ", threshold=" + threshold); // finally, do the save. FinalSave(input, output, scratchSurface, ditherLevel, bitDepth, token, progressCallback); }
internal abstract int GetDitherLevelFromToken(PropertyBasedSaveConfigToken token);
internal abstract int GetThresholdFromToken(PropertyBasedSaveConfigToken token);
internal abstract Set <SavableBitDepths> CreateAllowedBitDepthListFromToken(PropertyBasedSaveConfigToken token);