Exemplo n.º 1
0
        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);
            }
        }
Exemplo n.º 2
0
        private SavableBitDepths GetBitDepth(Surface scratchSurface, Rectangle bounds)
        {
            bool allOpaque;
            bool all0or255Alpha;
            int  uniqueColorCount;

            Analyze(scratchSurface, bounds, out allOpaque, out all0or255Alpha, out uniqueColorCount);

            SavableBitDepths bitDepth = SavableBitDepths.Rgba32;

            if (allOpaque)
            {
                bitDepth = SavableBitDepths.Rgb24;

                if (uniqueColorCount <= 256)
                {
                    bitDepth = SavableBitDepths.Rgb8;
                }
            }
            else if (all0or255Alpha && uniqueColorCount < 256)
            {
                bitDepth = SavableBitDepths.Rgba8;
            }

            // 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();

                unsafe
                {
                    for (int y = bounds.Top; y < bounds.Bottom; ++y)
                    {
                        ColorBgra *srcPtr = scratchSurface.GetPointAddressUnchecked(bounds.Left, y);
                        ColorBgra *endPtr = srcPtr + bounds.Width;

                        while (srcPtr < endPtr)
                        {
                            if (srcPtr->A < 128 && bitDepth == SavableBitDepths.Rgba8)
                            {
                                *srcPtr = ColorBgra.FromBgra(0, 0, 0, 0);
                            }
                            else
                            {
                                *srcPtr = blendOp.Apply(ColorBgra.White, *srcPtr);
                            }

                            srcPtr++;
                        }
                    }
                }
            }


            return(bitDepth);
        }
Exemplo n.º 3
0
 internal abstract void FinalSave(
     Document input,
     Stream output,
     Surface scratchSurface,
     int ditherLevel,
     SavableBitDepths bitDepth,
     PropertyBasedSaveConfigToken token,
     ProgressEventHandler progressCallback);
Exemplo n.º 4
0
 protected sealed override void OnSaveT(Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback)
 {
     try
     {
         int  num3;
         bool flag;
         bool flag2;
         int  num4;
         int  thresholdFromToken   = this.GetThresholdFromToken(token);
         int  ditherLevelFromToken = this.GetDitherLevelFromToken(token);
         HashSet <SavableBitDepths> allowedBitDepths = this.CreateAllowedBitDepthListFromToken(token);
         if (allowedBitDepths.Count == 0)
         {
             throw new ArgumentException("there must be at least 1 element returned from CreateAllowedBitDepthListFromToken()");
         }
         SavableBitDepths[] items = new SavableBitDepths[] { SavableBitDepths.Rgb8, SavableBitDepths.Rgba8 };
         if (allowedBitDepths.IsSubsetOf(HashSetUtil.Create <SavableBitDepths>(items)))
         {
             num3 = thresholdFromToken;
         }
         else
         {
             num3 = 1;
         }
         this.RenderFlattenedDocument(input, scratchSurface);
         this.Analyze(scratchSurface, out flag, out flag2, out num4);
         HashSet <SavableBitDepths> losslessBitDepths = new HashSet <SavableBitDepths> {
             SavableBitDepths.Rgba32
         };
         if (flag)
         {
             losslessBitDepths.Add(SavableBitDepths.Rgb24);
             if (num4 <= 0x100)
             {
                 losslessBitDepths.Add(SavableBitDepths.Rgb8);
             }
         }
         else if (flag2 && (num4 < 0x100))
         {
             losslessBitDepths.Add(SavableBitDepths.Rgba8);
         }
         double chooseBitDepthProgressLast = 0.0;
         ProgressEventHandler handler      = delegate(object sender, ProgressEventArgs e) {
             chooseBitDepthProgressLast = e.Percent;
             progressCallback(sender, e);
         };
         SavableBitDepths bitDepth = this.ChooseBitDepth(input, scratchSurface, ditherLevelFromToken, num3, token, handler, 0.0, 66.666666666666671, allowedBitDepths, losslessBitDepths, flag, flag2, num4);
         if (((bitDepth == SavableBitDepths.Rgba8) && (num3 == 0)) && (allowedBitDepths.Contains(SavableBitDepths.Rgba8) && allowedBitDepths.Contains(SavableBitDepths.Rgb8)))
         {
             bitDepth = SavableBitDepths.Rgb8;
         }
         this.FinalSave(input, output, scratchSurface, ditherLevelFromToken, num3, bitDepth, token, progressCallback, chooseBitDepthProgressLast, 100.0);
     }
     finally
     {
     }
 }
Exemplo n.º 5
0
 private long GetSavableBitDepthFileLength(SavableBitDepths bitDepth, Document input, Surface scratchSurface, int ditherLevel, int threshold, PropertyBasedSaveConfigToken token, ProgressEventHandler progressCallback, double progressStart, double progressEnd)
 {
     scratchSurface.Clear(ColorBgra.Zero);
     using (SegmentedMemoryStream stream = new SegmentedMemoryStream())
     {
         this.FinalSave(input, stream, scratchSurface, ditherLevel, threshold, bitDepth, token, progressCallback, progressStart, progressEnd);
         stream.Flush();
         return(stream.Length);
     }
 }
Exemplo n.º 6
0
        private void SaveTga(Surface input, Stream output, SavableBitDepths bitDepth, bool rleCompress, ProgressEventHandler progressCallback)
        {
            TgaHeader header = new TgaHeader();

            header.idLength      = 0;
            header.cmapType      = 0;
            header.imageType     = rleCompress ? TgaType.RleRgb : TgaType.Rgb;
            header.cmapIndex     = 0;
            header.cmapLength    = 0;
            header.cmapEntrySize = 0; // if bpp=8, set this to 24
            header.xOrigin       = 0;
            header.yOrigin       = 0;
            header.imageWidth    = (ushort)input.Width;
            header.imageHeight   = (ushort)input.Height;

            header.imageDesc = 0;

            switch (bitDepth)
            {
            case SavableBitDepths.Rgba32:
                header.pixelDepth = 32;
                header.imageDesc |= 8;
                break;

            case SavableBitDepths.Rgb24:
                header.pixelDepth = 24;
                break;

            default:
                throw new InvalidEnumArgumentException("bitDepth", (int)bitDepth, typeof(SavableBitDepths));
            }

            header.Write(output);

            // write palette if doing 8-bit
            // ... todo?

            for (int y = input.Height - 1; y >= 0; --y)
            {
                // non-rle output
                if (rleCompress)
                {
                    SaveTgaRowRle(output, input, ref header, y);
                }
                else
                {
                    SaveTgaRowRaw(output, input, ref header, y);
                }

                if (progressCallback != null)
                {
                    progressCallback(this, new ProgressEventArgs(100.0 * ((double)(input.Height - y) / (double)input.Height)));
                }
            }
        }
Exemplo n.º 7
0
        internal override void FinalSave(
            Document input,
            Stream output,
            Surface scratchSurface,
            int ditherLevel,
            SavableBitDepths bitDepth,
            PropertyBasedSaveConfigToken token,
            ProgressEventHandler progressCallback)
        {
            bool rleCompress = token.GetProperty <BooleanProperty>(PropertyNames.RleCompress).Value;

            SaveTga(scratchSurface, output, bitDepth, rleCompress, progressCallback);
        }
Exemplo n.º 8
0
        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));
            }
        }
Exemplo n.º 9
0
 internal SavableBitDepths ChooseBitDepth(Document input, Surface scratchSurface, int ditherLevel, int threshold, PropertyBasedSaveConfigToken token, ProgressEventHandler progressCallback, double progressStart, double progressEnd, HashSet <SavableBitDepths> allowedBitDepths, HashSet <SavableBitDepths> losslessBitDepths, bool allOpaque, bool all0Or255Alpha, int uniqueColorCount)
 {
     if (allowedBitDepths.Count == 0)
     {
         throw new ArgumentException("Count must be 1 or more", "allowedBitDepths");
     }
     try
     {
         HashSet <SavableBitDepths> set2;
         if (allowedBitDepths.Count == 1)
         {
             return(allowedBitDepths.First <SavableBitDepths>());
         }
         HashSet <SavableBitDepths> source = HashSetUtil.Intersect <SavableBitDepths>(allowedBitDepths, losslessBitDepths);
         if (source.Count == 1)
         {
             return(source.First <SavableBitDepths>());
         }
         if (source.Count == 0)
         {
             set2 = allowedBitDepths;
         }
         else
         {
             set2 = source;
         }
         long num = input.Width * input.Height;
         if (((all0Or255Alpha && (uniqueColorCount <= 0xff)) && ((num <= 0x10000L) && set2.Contains(SavableBitDepths.Rgb8))) && set2.Contains(SavableBitDepths.Rgb24))
         {
             long num2 = 0L;
             long num3 = 0L;
             try
             {
                 num2 = this.GetSavableBitDepthFileLength(SavableBitDepths.Rgb8, input, scratchSurface, ditherLevel, threshold, token, progressCallback, 0.0, 50.0);
                 num3 = this.GetSavableBitDepthFileLength(SavableBitDepths.Rgb24, input, scratchSurface, ditherLevel, threshold, token, progressCallback, 50.0, 100.0);
             }
             catch (OutOfMemoryException)
             {
                 return(SavableBitDepths.Rgb8);
             }
             if (num2 < num3)
             {
                 return(SavableBitDepths.Rgb8);
             }
             return(SavableBitDepths.Rgb24);
         }
         if (((all0Or255Alpha && (uniqueColorCount <= 0xff)) && ((num < 0x10000L) && set2.Contains(SavableBitDepths.Rgba8))) && set2.Contains(SavableBitDepths.Rgba32))
         {
             long num4 = 0L;
             long num5 = 0L;
             try
             {
                 num4 = this.GetSavableBitDepthFileLength(SavableBitDepths.Rgba8, input, scratchSurface, ditherLevel, threshold, token, progressCallback, 0.0, 50.0);
                 num5 = this.GetSavableBitDepthFileLength(SavableBitDepths.Rgba32, input, scratchSurface, ditherLevel, threshold, token, progressCallback, 50.0, 100.0);
             }
             catch (OutOfMemoryException)
             {
                 return(SavableBitDepths.Rgba8);
             }
             if (num4 < num5)
             {
                 return(SavableBitDepths.Rgba8);
             }
             return(SavableBitDepths.Rgba32);
         }
         if ((set2.Contains(SavableBitDepths.Rgb8) & allOpaque) && (uniqueColorCount <= 0x100))
         {
             return(SavableBitDepths.Rgb8);
         }
         if ((set2.Contains(SavableBitDepths.Rgba8) & all0Or255Alpha) && (uniqueColorCount <= 0xff))
         {
             return(SavableBitDepths.Rgba8);
         }
         if (!(set2.Contains(SavableBitDepths.Rgb24) & allOpaque))
         {
             if (set2.Contains(SavableBitDepths.Rgba32))
             {
                 return(SavableBitDepths.Rgba32);
             }
             SavableBitDepths[] items = new SavableBitDepths[] { SavableBitDepths.Rgb8, SavableBitDepths.Rgb24 };
             if (set2.SetEquals(HashSetUtil.Create <SavableBitDepths>(items)))
             {
                 return(SavableBitDepths.Rgb24);
             }
             SavableBitDepths[] depthsArray2 = new SavableBitDepths[] { SavableBitDepths.Rgb8, SavableBitDepths.Rgba8 };
             if (set2.SetEquals(HashSetUtil.Create <SavableBitDepths>(depthsArray2)))
             {
                 return(SavableBitDepths.Rgba8);
             }
             SavableBitDepths[] depthsArray3 = new SavableBitDepths[] { SavableBitDepths.Rgba8, SavableBitDepths.Rgb24 };
             if (!set2.SetEquals(HashSetUtil.Create <SavableBitDepths>(depthsArray3)))
             {
                 throw new ArgumentException("Could not accomodate input values -- internal error?");
             }
         }
         return(SavableBitDepths.Rgb24);
     }
     finally
     {
     }
 }
Exemplo n.º 10
0
        private unsafe void FinalSave(Document input, Stream output, Surface scratchSurface, int ditherLevel, int threshold, SavableBitDepths bitDepth, PropertyBasedSaveConfigToken token, ProgressEventHandler progressCallback, double progressStart, double progressEnd)
        {
            this.RenderFlattenedDocument(input, scratchSurface);
            if (((bitDepth == SavableBitDepths.Rgb8) || (bitDepth == SavableBitDepths.Rgba8)) || (bitDepth == SavableBitDepths.Rgb24))
            {
                ColorBgra white = ColorBgra.White;
                Work.ParallelFor(WaitType.Blocking, 0, scratchSurface.Height, delegate(int y) {
                    int width             = scratchSurface.Width;
                    ColorBgra *rowAddress = scratchSurface.GetRowAddress(y);
                    for (int j = 0; j < width; j++)
                    {
                        ColorBgra rhs = rowAddress[0];
                        if ((bitDepth == SavableBitDepths.Rgba8) && (rhs.A < threshold))
                        {
                            rowAddress->Bgra = 0;
                        }
                        else
                        {
                            rowAddress->Bgra = CompositionOps.Normal.ApplyStatic(white, rhs).Bgra;
                        }
                        rowAddress++;
                    }
                }, WorkItemQueuePriority.Normal, null);
            }
            ProgressEventHandler handler = (sender, e) => progressCallback(sender, new ProgressEventArgs(progressStart + ((progressEnd - progressStart) * (e.Percent / 100.0))));

            this.OnFinalSave(input, output, scratchSurface, ditherLevel, bitDepth, token, handler);
        }
Exemplo n.º 11
0
        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));
            }
        }
Exemplo n.º 12
0
        private void SaveTga(Surface input, Stream output, SavableBitDepths bitDepth, bool rleCompress, ProgressEventHandler progressCallback)
        {
            TgaHeader header = new TgaHeader();

            header.idLength = 0;
            header.cmapType = 0;
            header.imageType = rleCompress ? TgaType.RleRgb : TgaType.Rgb;
            header.cmapIndex = 0;
            header.cmapLength = 0;
            header.cmapEntrySize = 0; // if bpp=8, set this to 24
            header.xOrigin = 0;
            header.yOrigin = 0;
            header.imageWidth = (ushort)input.Width;
            header.imageHeight = (ushort)input.Height;

            header.imageDesc = 0;

            switch (bitDepth)
            {
                case SavableBitDepths.Rgba32:
                    header.pixelDepth = 32;
                    header.imageDesc |= 8;
                    break;

                case SavableBitDepths.Rgb24:
                    header.pixelDepth = 24;
                    break;

                default:
                    throw new InvalidEnumArgumentException("bitDepth", (int)bitDepth, typeof(SavableBitDepths));
            }

            header.Write(output);

            // write palette if doing 8-bit
            // ... todo?

            for (int y = input.Height - 1; y >= 0; --y)
            {
                // non-rle output
                if (rleCompress)
                {
                    SaveTgaRowRle(output, input, ref header, y);
                }
                else
                {
                    SaveTgaRowRaw(output, input, ref header, y);
                }

                if (progressCallback != null)
                {
                    progressCallback(this, new ProgressEventArgs(100.0 * ((double)(input.Height - y) / (double)input.Height)));
                }
            }
        }
Exemplo n.º 13
0
 internal override void FinalSave(
     Document input, 
     Stream output, 
     Surface scratchSurface, 
     int ditherLevel, 
     SavableBitDepths bitDepth, 
     PropertyBasedSaveConfigToken token, 
     ProgressEventHandler progressCallback)
 {
     bool rleCompress = token.GetProperty<BooleanProperty>(PropertyNames.RleCompress).Value;
     SaveTga(scratchSurface, output, bitDepth, rleCompress, progressCallback);
 }
Exemplo n.º 14
0
        protected override void OnSaveT(Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)
        {
            int width  = input.Width;
            int height = input.Height;

            using (RenderArgs args = new RenderArgs(scratchSurface))
            {
                input.Render(args, true);
            }

            int tileHeight = token.GetProperty <Int32Property>(PropertyNames.TileHeight).Value;
            int tileWidth  = token.GetProperty <Int32Property>(PropertyNames.TileWidth).Value;

            List <Rectangle> rects = new List <Rectangle>();

            for (int y = 0; y < height; y += tileHeight)
            {
                for (int x = 0; x < width; x += tileWidth)
                {
                    Rectangle bounds = new Rectangle(x, y, Math.Min(tileWidth, width - x), Math.Min(tileHeight, height - y));
                    rects.Add(bounds);
                }
            }

            double progressPercentage = 0.0;
            double progressDelta      = (1.0 / rects.Count) * 100.0;

            using (ZipOutputStream zipStream = new ZipOutputStream(output, true))
            {
                int count = rects.Count;

                ImageCodecInfo    codec         = GetImageCodecInfo(ImageFormat.Png);
                EncoderParameters encoderParams = new EncoderParameters(1);

                for (int i = 0; i < count; i++)
                {
                    Rectangle bounds = rects[i];

                    SavableBitDepths bitDepth = GetBitDepth(scratchSurface, bounds);

                    zipStream.PutNextEntry(string.Format("Image{0}.png", (i + 1)));
                    if (bitDepth == SavableBitDepths.Rgba32)
                    {
                        encoderParams.Param[0] = new EncoderParameter(Encoder.ColorDepth, 32);

                        using (Bitmap temp = scratchSurface.CreateAliasedBitmap(bounds, true))
                        {
                            temp.Save(zipStream, codec, encoderParams);
                        }
                    }
                    else if (bitDepth == SavableBitDepths.Rgb24)
                    {
                        encoderParams.Param[0] = new EncoderParameter(Encoder.ColorDepth, 24);

                        using (Surface surface = new Surface(bounds.Width, bounds.Height))
                        {
                            surface.CopySurface(scratchSurface, bounds); // Make a new surface so we do not clobber the stride of the scratchSurface.
                            SquishSurfaceTo24Bpp(surface);

                            using (Bitmap temp = CreateAliased24BppBitmap(surface))
                            {
                                temp.Save(zipStream, codec, encoderParams);
                            }
                        }
                    }
                    else if (bitDepth == SavableBitDepths.Rgb8)
                    {
                        encoderParams.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);

                        using (Surface surface = scratchSurface.CreateWindow(bounds))
                        {
                            using (Bitmap temp = Quantize(surface, 7, 256, false, null))
                            {
                                temp.Save(zipStream, codec, encoderParams);
                            }
                        }
                    }
                    else if (bitDepth == SavableBitDepths.Rgba8)
                    {
                        encoderParams.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);

                        using (Surface surface = scratchSurface.CreateWindow(bounds))
                        {
                            using (Bitmap temp = Quantize(surface, 7, 256, true, null))
                            {
                                temp.Save(zipStream, codec, encoderParams);
                            }
                        }
                    }

                    progressPercentage += progressDelta;

                    callback(this, new ProgressEventArgs(progressPercentage));
                }
            }
        }
Exemplo n.º 15
0
        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);
        }
Exemplo n.º 16
0
        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);
            }
        }