예제 #1
0
        private static void WriteBmpFrame(CommandLineOptions opts, ParseContext context, IcoFrame frame)
        {
            var encoding = opts.BitmapEncodingOverride ?? BmpUtil.GetIdealBitmapEncoding(frame.CookedData, hasIcoMask: true);

            if (opts.MaskImagePath != null)
            {
                var maskSource = File.ReadAllBytes(opts.MaskImagePath);
                using (var stream = new MemoryStream(maskSource))
                {
                    var decoder = new SixLabors.ImageSharp.Formats.Bmp.BmpDecoder();
                    var mask    = decoder.Decode <Rgba32>(new Configuration(), stream);
                    if (mask.Width != frame.CookedData.Width || mask.Height != frame.CookedData.Height)
                    {
                        Reporter.ErrorLine(
                            IcoErrorCode.BitmapMaskWrongDimensions,
                            $"The mask's dimentions {mask.Height}x{mask.Width} don't match "
                            + $"the frame dimensions {frame.CookedData.Height}x{frame.CookedData.Width}.",
                            opts.MaskImagePath);
                        throw new ArgumentException();
                    }

                    for (var x = 0; x < mask.Width; x++)
                    {
                        for (var y = 0; y < mask.Height; y++)
                        {
                            if (mask[x, y].PackedValue != 0xffffffff && mask[x, y].PackedValue != 0x000000ff)
                            {
                                Reporter.ErrorLine(
                                    IcoErrorCode.BitampMaskWrongColors,
                                    $"The mask must be comprised entirely of black and white pixels (where black means transparent).",
                                    opts.MaskImagePath);
                                throw new ArgumentException();
                            }
                        }
                    }

                    frame.Mask = BmpUtil.CreateMaskFromImage(mask, blackIsTransparent: true);
                }
            }
            else
            {
                frame.Mask = BmpUtil.CreateMaskFromImage(frame.CookedData, blackIsTransparent: false);
            }

            frame.RawData = BmpEncoder.EncodeBitmap(context, encoding, BmpEncoder.Dialect.Ico, frame);
            if (frame.RawData == null)
            {
                Reporter.ErrorLine(context.LastEncodeError, $"Cannot encode the source image as a bitmap of type: {encoding}. Try reducing the number of colors, or changing the bitmap encoding.", opts.SourceImagePath);
                throw new ArgumentException();
            }

            frame.Encoding.ClaimedBitDepth = (uint)BmpUtil.GetBitDepthForPixelFormat(encoding);
            frame.Encoding.ActualBitDepth  = frame.Encoding.ClaimedBitDepth;
        }
예제 #2
0
        private static IcoFrame GetBestEncodingForFrame(ParseContext context, CommandLineOptions opts, IcoFrame source)
        {
            var result = new IcoFrameEncoding
            {
                ClaimedBitDepth = source.Encoding.ClaimedBitDepth,
                ClaimedHeight   = source.Encoding.ClaimedHeight,
                ClaimedWidth    = source.Encoding.ClaimedWidth,
                ActualHeight    = (uint)source.CookedData.Height,
                ActualWidth     = (uint)source.CookedData.Width,
            };

            byte[] png    = null;
            byte[] bitmap = null;

            var policy = opts.BestFormatPolicy;

            if (policy == BestFormatPolicy.Inherited)
            {
                policy = BestFormatPolicy.PreserveSource;
            }

            if (source.Encoding.ClaimedHeight == 16 &&
                source.Encoding.ClaimedWidth == 16 &&
                source.Encoding.ClaimedBitDepth == 32 &&
                opts.BestFormatPolicy16x16x32 != BestFormatPolicy.Inherited)
            {
                policy = opts.BestFormatPolicy16x16x32;
            }

            if (source.Encoding.ClaimedHeight == 32 &&
                source.Encoding.ClaimedWidth == 32 &&
                source.Encoding.ClaimedBitDepth == 32 &&
                opts.BestFormatPolicy32x32x32 != BestFormatPolicy.Inherited)
            {
                policy = opts.BestFormatPolicy32x32x32;
            }

            if (policy != BestFormatPolicy.AlwaysBmp &&
                (source.Encoding.ClaimedBitDepth == 32 || opts.BestFormatPolicy == BestFormatPolicy.AlwaysPng))
            {
                png = EncodePng(source, context);

                if (opts.PngToolPath != null)
                {
                    png = ReprocessPngFile(png, context, opts);
                }
            }

            if (opts.BestFormatPolicy != BestFormatPolicy.AlwaysPng)
            {
                foreach (var encoding in _allEncodings)
                {
                    if (encoding == BitmapEncoding.Pixel_indexed2)
                    {
                        switch (opts.Emit2BitBitmaps)
                        {
                        case StrictnessPolicy.Compliant:
                            continue;

                        case StrictnessPolicy.PreserveSource:
                            if (source.Encoding.PixelFormat != BitmapEncoding.Pixel_indexed2)
                            {
                                continue;
                            }

                            break;

                        case StrictnessPolicy.Loose:
                            break;
                        }
                    }

                    if (encoding == BitmapEncoding.Pixel_rgb24)
                    {
                        switch (opts.Emit24BitBitmaps)
                        {
                        case StrictnessPolicy.Compliant:
                            continue;

                        case StrictnessPolicy.PreserveSource:
                            if (source.Encoding.PixelFormat != BitmapEncoding.Pixel_rgb24)
                            {
                                continue;
                            }

                            break;

                        case StrictnessPolicy.Loose:
                            break;
                        }
                    }

                    if (source.Encoding.PixelFormat != encoding)
                    {
                        if (!opts.AllowDownsample)
                        {
                            continue;
                        }

                        // Going to rgb15 can lose some color data, due to rounding.  Avoid unless the source
                        // was already in rgb15.
                        if (encoding == BitmapEncoding.Pixel_rgb15)
                        {
                            continue;
                        }

                        // Don't lose the per-pixel alpha channel, if one was in the source.
                        if (source.Encoding.PixelFormat == BitmapEncoding.Pixel_argb32 && BmpUtil.IsAlphaSignificant(source))
                        {
                            continue;
                        }
                    }

                    bitmap = BmpEncoder.EncodeBitmap(context, encoding, BmpEncoder.Dialect.Ico, source);
                    if (bitmap != null)
                    {
                        result.PixelFormat = encoding;
                        break;
                    }
                }
            }

            switch (opts.BestFormatPolicy)
            {
            case BestFormatPolicy.PreserveSource:
                result.Type = source.Encoding.Type;
                break;

            case BestFormatPolicy.MinimizeStorage:
                result.Type = (bitmap.Length < ((png?.Length ?? 0) + opts.PngSizePenalty))
                        ? IcoEncodingType.Bitmap
                        : IcoEncodingType.Png;
                break;

            case BestFormatPolicy.PngLargeImages:
                result.Type = (source.CookedData.Width >= opts.LargeImagePixelThreshold)
                        ? IcoEncodingType.Png
                        : IcoEncodingType.Bitmap;
                break;

            case BestFormatPolicy.AlwaysPng:
                result.Type = IcoEncodingType.Png;
                break;

            case BestFormatPolicy.AlwaysBmp:
                result.Type = IcoEncodingType.Bitmap;
                break;

            default:
                break;
            }

            if (png == null && result.Type == IcoEncodingType.Png)
            {
                result.Type = IcoEncodingType.Bitmap;
            }

            var finalData = (result.Type == IcoEncodingType.Bitmap) ? bitmap : png;

            return(new IcoFrame {
                Encoding = result, RawData = finalData
            });
        }