Ejemplo n.º 1
0
        internal SavableBitDepths ChooseBitDepth(
            Set <SavableBitDepths> allowedBitDepths,
            Set <SavableBitDepths> losslessBitDepths,
            bool allOpaque,
            bool all0Or255Alpha,
            int uniqueColorCount)
        {
            if (allowedBitDepths.Count == 0)
            {
                throw new ArgumentException("Count must be 1 or more", "allowedBitDepths");
            }

            Tracing.Ping("allowedBitDepths = " + PrintSet(allowedBitDepths));
            Tracing.Ping("losslessBitDepths = " + PrintSet(losslessBitDepths));

            if (allowedBitDepths.Count == 1)
            {
                return(allowedBitDepths.ToArray()[0]);
            }

            // allowedBitDepths.Count >= 2

            Set <SavableBitDepths> bestBitDepths = Set <SavableBitDepths> .Intersect(allowedBitDepths, losslessBitDepths);

            if (bestBitDepths.Count == 1)
            {
                return(bestBitDepths.ToArray()[0]);
            }

            Set <SavableBitDepths> candidates;

            if (bestBitDepths.Count == 0)
            {
                candidates = allowedBitDepths;
            }
            else
            {
                candidates = bestBitDepths;
            }

            // candidates.Count >= 2

            // lossless choices

            if (candidates.Contains(SavableBitDepths.Rgba8) && all0Or255Alpha && uniqueColorCount <= 255)
            {
                return(SavableBitDepths.Rgba8);
            }

            if (candidates.Contains(SavableBitDepths.Rgb8) && allOpaque && uniqueColorCount <= 256)
            {
                return(SavableBitDepths.Rgb8);
            }

            if (candidates.Contains(SavableBitDepths.Rgb24) && allOpaque)
            {
                return(SavableBitDepths.Rgb24);
            }

            if (candidates.Contains(SavableBitDepths.Rgba32))
            {
                return(SavableBitDepths.Rgba32);
            }

            // forced choices -- we wanted Rgba32 but it was not allowed

            if (candidates.IsEqualTo(Set.Create(SavableBitDepths.Rgb8, SavableBitDepths.Rgb24)))
            {
                return(SavableBitDepths.Rgb24);
            }

            if (candidates.IsEqualTo(Set.Create(SavableBitDepths.Rgb8, SavableBitDepths.Rgba8)))
            {
                return(SavableBitDepths.Rgba8);
            }

            if (candidates.IsEqualTo(Set.Create(SavableBitDepths.Rgba8, SavableBitDepths.Rgb24)))
            {
                return(SavableBitDepths.Rgb24);
            }

            throw new ArgumentException("Could not accomodate input values -- internal error?");
        }
Ejemplo n.º 2
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);
        }