示例#1
0
        public static void EmitIco(string outputPath, ParseContext context)
        {
            var writer = new ByteWriter(ByteOrder.LittleEndian);

            writer.AddUint16(FileFormatConstants._iconMagicHeader);
            writer.AddUint16(FileFormatConstants._iconMagicType);
            writer.AddUint16((ushort)context.GeneratedFrames.Count);

            var offsets = new Queue <uint>();

            foreach (var frame in context.GeneratedFrames)
            {
                var width    = frame.Encoding.ClaimedWidth;
                var height   = frame.Encoding.ClaimedHeight;
                var bitDepth = frame.Encoding.ClaimedBitDepth;

                writer.AddUint8((byte)(width >= 256 ? 0 : width));               // bWidth
                writer.AddUint8((byte)(height >= 256 ? 0 : height));             // bHeight
                writer.AddUint8((byte)(bitDepth < 8 ? 1u << (int)bitDepth : 0)); // bColorCount
                writer.AddUint8(0);                                              // bReserved
                writer.AddUint16(1);                                             // wPlanes
                writer.AddUint16((ushort)bitDepth);                              // wBitCount
                writer.AddUint32((uint)frame.RawData.Length);                    // dwBytesInRes

                offsets.Enqueue((uint)writer.SeekOffset);
                writer.AddUint32(0); // dwImageOffset (will fix later)
            }

            foreach (var frame in context.GeneratedFrames)
            {
                var currentOffset = writer.SeekOffset;
                writer.SeekOffset = (int)offsets.Dequeue();
                writer.AddUint32((uint)currentOffset); // dwImageOffset
                writer.SeekOffset = currentOffset;

                writer.AddBlob(frame.RawData);

                frame.TotalDiskUsage = (uint)frame.RawData.Length + /* sizeof(ICONDIRENTRY) */ 16;
            }

            File.WriteAllBytes(outputPath, writer.Data.ToArray());
        }
示例#2
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);
                }
            }
        }
示例#3
0
        private static byte[] FinalizeBitmap(IcoFrame source, BitmapEncoding encoding, Dialect dialect, ByteWriter writer, uint offsetToData, uint offsetToImageSize)
        {
            var offsetToEndOfData = writer.SeekOffset;

            if (dialect == Dialect.Ico)
            {
                var padding = writer.Data.Count % 4;

                var inferMaskFromAlpha = (source.Encoding.PixelFormat == BitmapEncoding.Pixel_argb32 && encoding != BitmapEncoding.Pixel_argb32);

                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 mask = inferMaskFromAlpha
                            ? (source.CookedData[x, y].A == 0)
                            : source.Mask[x, y];

                        bits.AddBit1((byte)(mask ? 1 : 0));
                    }

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

            if (dialect != Dialect.Ico)
            {
                writer.SeekOffset = 2;
                writer.AddUint32((uint)writer.Data.Count);

                writer.SeekOffset = 10;
                writer.AddUint32(offsetToData);
            }

            writer.SeekOffset = (int)offsetToImageSize;
            writer.AddUint32((uint)(offsetToEndOfData - offsetToData)); // biSizeImage

            return(writer.Data.ToArray());
        }
示例#4
0
        private static byte[] EncodeRgbBitmap(IcoFrame source, ParseContext context, BitmapEncoding encoding, Dialect dialect)
        {
            var writer = new ByteWriter(ByteOrder.LittleEndian);

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

            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:
                        case StrictnessPolicy.Loose:
                            color = new Rgba32(0, 0, 0, 0);
                            break;

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

                    switch (encoding)
                    {
                    case BitmapEncoding.Pixel_rgb15:
                        var value = X8To5(color.R) << 10 | X8To5(color.G) << 5 | X8To5(color.B);
                        writer.AddUint16((ushort)value);
                        break;

                    case BitmapEncoding.Pixel_rgb24:
                        writer.AddUint8(color.B);
                        writer.AddUint8(color.G);
                        writer.AddUint8(color.R);
                        break;

                    case BitmapEncoding.Pixel_0rgb32:
                        writer.AddUint8(color.B);
                        writer.AddUint8(color.G);
                        writer.AddUint8(color.R);
                        writer.AddUint8(0);
                        break;

                    case BitmapEncoding.Pixel_argb32:
                        writer.AddUint8(color.B);
                        writer.AddUint8(color.G);
                        writer.AddUint8(color.R);
                        writer.AddUint8(color.A);
                        break;
                    }
                }

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

            return(FinalizeBitmap(source, encoding, dialect, writer, offsetToData, offsetToImageSize));
        }
示例#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));
        }