Example #1
0
        public static byte[] EncodeBitmap(ParseContext context, BitmapEncoding encoding, Dialect dialect, IcoFrame source)
        {
            context.LastEncodeError = IcoErrorCode.NoError;

            return((BmpUtil.GetBitDepthForPixelFormat(encoding) < 16)
                ? EncodeIndexedBitmap(context, encoding, dialect, source)
                : EncodeRgbBitmap(source, context, encoding, dialect));
        }
Example #2
0
        private static void ReadBitmap32(ByteReader reader, ParseContext context, int height, int width, IcoFrame source)
        {
            for (var y = height - 1; y >= 0; y--)
            {
                for (var x = 0; x < width; x++)
                {
                    var colorValue = new Bgra32 {
                        PackedValue = reader.NextUint32()
                    };
                    source.CookedData[x, y] = colorValue.ToRgba32();
                }
            }

            source.Encoding.PixelFormat = BmpUtil.IsAnyAlphaChannel(source.CookedData)
                ? BitmapEncoding.Pixel_argb32
                : BitmapEncoding.Pixel_0rgb32;

            ReadBitmapMask(reader, context, height, width, source);
        }
Example #3
0
        private static void EncodeBitmapHeader(IcoFrame source, Dialect dialect, BitmapEncoding encoding, Rgba32[] colorTable, ByteWriter writer, out uint offsetToImageSize)
        {
            if (dialect != Dialect.Ico)
            {
                writer.AddUint16(FileFormatConstants._bitmapFileMagic);
                writer.AddUint32(0); // Size will be filled in later
                writer.AddUint32(0); // Reserved
                writer.AddUint32(0); // Offset will be filled in later
            }

            writer.AddUint32(FileFormatConstants._bitmapInfoHeaderSize);
            writer.AddUint32((uint)source.CookedData.Width);
            writer.AddUint32((uint)source.CookedData.Height * ((dialect == Dialect.Ico) ? 2u : 1u));
            writer.AddUint16(1);                                                                          // biPlanes
            writer.AddUint16((ushort)BmpUtil.GetBitDepthForPixelFormat(encoding));                        // biBitCount
            writer.AddUint32(FileFormatConstants.BI_RGB);                                                 // biCompression
            offsetToImageSize = (uint)writer.SeekOffset;
            writer.AddUint32(0);                                                                          // biSizeImage
            writer.AddUint32((dialect == Dialect.Ico) ? 0u : FileFormatConstants._72dpiInPixelsPerMeter); // biXPelsPerMeter
            writer.AddUint32((dialect == Dialect.Ico) ? 0u : FileFormatConstants._72dpiInPixelsPerMeter); // biYPelsPerMeter
            writer.AddUint32((uint)(colorTable?.Length ?? 0));                                            // biClrUsed
            writer.AddUint32(0);                                                                          // biClrImportant

            if (colorTable != null)
            {
                foreach (var color in colorTable)
                {
                    writer.AddUint8(color.B);
                    writer.AddUint8(color.G);
                    writer.AddUint8(color.R);
                    writer.AddUint8(0);
                }
            }

            if (dialect != Dialect.Ico)
            {
                while (writer.Data.Count % 4 != 0)
                {
                    writer.AddUint8(0);
                }
            }
        }
Example #4
0
        public static void DoPngEntry(ByteReader bitmapHeader, ParseContext context, IcoFrame source)
        {
            if (source.Encoding.ClaimedBitDepth != 32)
            {
                context.Reporter.WarnLine(IcoErrorCode.PngNot32Bit, $"PNG-encoded image with bit depth {source.Encoding.ClaimedBitDepth} (expected 32).", context.DisplayedPath, context.ImageDirectoryIndex.Value);
            }

            using (var stream = new MemoryStream(bitmapHeader.Data.ToArray()))
            {
                var decoder = new SixLabors.ImageSharp.Formats.Png.PngDecoder();
                source.CookedData = decoder.Decode <Rgba32>(new Configuration(), stream);
            }

            source.Encoding.Type        = IcoEncodingType.Png;
            source.Encoding.PixelFormat = BmpUtil.IsAnyPartialTransparency(source.CookedData) ? BitmapEncoding.Pixel_argb32 : BitmapEncoding.Pixel_0rgb32;
            source.Mask = GenerateMaskFromAlpha(source.CookedData);

            // Conservatively assume that the output wouldn't have used palette trimming, if it had been a bmp frame.
            if (source.Encoding.ClaimedBitDepth < 16)
            {
                source.Encoding.PaletteSize = 1u << (int)source.Encoding.ClaimedBitDepth;
            }

            var encoding = GetPngFileEncoding(bitmapHeader.Data);

            if (encoding.ColorType != PngColorType.RGBA)
            {
                context.Reporter.WarnLine(IcoErrorCode.PngNotRGBA32, $"ICO files require the embedded PNG image to be encoded in RGBA32 format; this is {encoding.ColorType}", context.DisplayedPath, context.ImageDirectoryIndex.Value);
            }
            else if (encoding.BitsPerChannel != 8)
            {
                context.Reporter.WarnLine(IcoErrorCode.PngNotRGBA32, $"ICO files require the embedded PNG image to be encoded in RGBA32 format; this is RGBA{encoding.BitsPerChannel * 4}", context.DisplayedPath, context.ImageDirectoryIndex.Value);
            }

            uint numChannels = 0;

            switch (encoding.ColorType)
            {
            case PngColorType.Grayscale:
                numChannels = 1;
                break;

            case PngColorType.RGB:
                numChannels = 3;
                break;

            case PngColorType.GrayscaleAlpha:
                numChannels = 2;
                break;

            case PngColorType.RGBA:
                numChannels = 4;
                break;

            case PngColorType.Palette:
            default:
                break;
            }

            source.Encoding.ActualHeight   = encoding.Height;
            source.Encoding.ActualWidth    = encoding.Width;
            source.Encoding.ActualBitDepth = encoding.BitsPerChannel * numChannels;
        }
Example #5
0
        private static byte[] EncodeIndexedBitmap(ParseContext context, BitmapEncoding encoding, Dialect dialect, IcoFrame source)
        {
            var numBits = BmpUtil.GetBitDepthForPixelFormat(encoding);

            var colorTable = BuildColorTable(1u << numBits, context, source);

            if (colorTable == null)
            {
                context.LastEncodeError = IcoErrorCode.TooManyColorsForBitDepth;
                return(null);
            }

            var writer = new ByteWriter(ByteOrder.LittleEndian);

            EncodeBitmapHeader(source, dialect, encoding, colorTable, writer, out var offsetToImageSize);

            var reverseTable = new Dictionary <Rgba32, int>();

            for (var i = 0; i < colorTable.Length; i++)
            {
                if (!reverseTable.ContainsKey(colorTable[i]))
                {
                    reverseTable.Add(colorTable[i], i);
                }
            }

            var offsetToData = (uint)writer.Data.Count;
            var padding      = writer.Data.Count % 4;

            for (var y = source.CookedData.Height - 1; y >= 0; y--)
            {
                var bits = new BitWriter(writer);

                for (var x = 0; x < source.CookedData.Width; x++)
                {
                    var color = source.CookedData[x, y];

                    if (source.Mask[x, y])
                    {
                        switch (context.MaskedImagePixelEmitOptions)
                        {
                        case StrictnessPolicy.Compliant:
                            color = new Rgba32(0, 0, 0, 255);
                            break;

                        case StrictnessPolicy.PreserveSource:
                            // Pass through whatever the original pixel was.
                            break;

                        case StrictnessPolicy.Loose:
                            color = colorTable.First();
                            break;
                        }
                    }

                    color.A = 255;

                    var index = reverseTable[color];
                    bits.AddBits((uint)numBits, (byte)index);
                }

                while ((writer.Data.Count % 4) != padding)
                {
                    writer.AddUint8(0);
                }
            }

            return(FinalizeBitmap(source, encoding, dialect, writer, offsetToData, offsetToImageSize));
        }