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