private static IcoFrame GenerateFrame(CommandLineOptions opts, ParseContext context) { var frame = new IcoFrame { Encoding = new IcoFrameEncoding(), }; var sourceFile = File.ReadAllBytes(opts.SourceImagePath); var reader = new ByteReader(sourceFile, ByteOrder.LittleEndian); var signature = reader.NextUint64(); var sourceEncoding = PngDecoder.IsProbablyPngFile(ByteOrderConverter.To(ByteOrder.NetworkEndian, signature)) ? IcoEncodingType.Png : IcoEncodingType.Bitmap; bool canSourceBePreserved = false; switch (sourceEncoding) { case IcoEncodingType.Bitmap: ReadBmpFile(opts, context, frame, sourceFile); break; case IcoEncodingType.Png: ReadPngFile(opts, context, frame, sourceFile, out canSourceBePreserved); break; } frame.Encoding.ActualHeight = (uint)frame.CookedData.Height; frame.Encoding.ClaimedHeight = (uint)frame.CookedData.Height; frame.Encoding.ActualWidth = (uint)frame.CookedData.Width; frame.Encoding.ClaimedWidth = (uint)frame.CookedData.Width; var outputEncoding = opts.EncodingOverride ?? sourceEncoding; if (outputEncoding != IcoEncodingType.Bitmap && opts.BitmapEncodingOverride.HasValue) { Reporter.WarnLine(IcoErrorCode.OnlySupportedOnBitmaps, "Ignoring bitmap encoding configuration because we're not emitting a bitmap frame"); } if (outputEncoding != sourceEncoding) { canSourceBePreserved = false; } if (canSourceBePreserved || opts.KeepRawFrameData) { frame.RawData = sourceFile; } else { switch (outputEncoding) { case IcoEncodingType.Bitmap: WriteBmpFrame(opts, context, frame); break; case IcoEncodingType.Png: WritePngFrame(opts, context, frame); break; } } if (opts.BitDepthOverride.HasValue) { frame.Encoding.ClaimedBitDepth = (uint)opts.BitDepthOverride.Value; } return(frame); }
private static IcoFrame ProcessIcoFrame(ByteReader reader, ParseContext context) { var bWidth = reader.NextUint8(); var bHeight = reader.NextUint8(); var bColorCount = reader.NextUint8(); var bReserved = reader.NextUint8(); var wPlanes = reader.NextUint16(); var wBitCount = reader.NextUint16(); var dwBytesInRes = reader.NextUint32(); var dwImageOffset = reader.NextUint32(); if (bWidth != bHeight) { context.Reporter.WarnLine(IcoErrorCode.NotSquare, $"Icon is not square ({bWidth}x{bHeight}).", context.DisplayedPath, context.ImageDirectoryIndex.Value); } if (bReserved != FileFormatConstants._iconEntryReserved) { throw new InvalidIcoFileException(IcoErrorCode.InvalidFrameHeader_bReserved, $"ICONDIRECTORY.bReserved should be {FileFormatConstants._iconEntryReserved}, was {bReserved}.", context); } if (wPlanes > 1) { throw new InvalidIcoFileException(IcoErrorCode.InvalidFrameHeader_wPlanes, $"ICONDIRECTORY.wPlanes is {wPlanes}. Only single-plane bitmaps are supported.", context); } if (dwBytesInRes > int.MaxValue) { throw new InvalidIcoFileException(IcoErrorCode.InvalidFrameHeader_dwBytesInRes, $"ICONDIRECTORY.dwBytesInRes == {dwBytesInRes}, which is unreasonably large.", context); } if (dwImageOffset > int.MaxValue) { throw new InvalidIcoFileException(IcoErrorCode.InvalidFrameHeader_dwImageOffset, $"ICONDIRECTORY.dwImageOffset == {dwImageOffset}, which is unreasonably large.", context); } var source = new IcoFrame { TotalDiskUsage = dwBytesInRes + /* sizeof(ICONDIRENTRY) */ 16, Encoding = new IcoFrameEncoding { ClaimedBitDepth = wBitCount, ClaimedHeight = bHeight > 0 ? bHeight : 256u, ClaimedWidth = bWidth > 0 ? bWidth : 256u, }, }; source.RawData = reader.Data.Slice((int)dwImageOffset, (int)dwBytesInRes).ToArray(); var bitmapHeader = new ByteReader(source.RawData, ByteOrder.LittleEndian); var signature = bitmapHeader.NextUint64(); bitmapHeader.SeekOffset = 0; if (PngDecoder.IsProbablyPngFile(ByteOrderConverter.To(ByteOrder.NetworkEndian, signature))) { PngDecoder.DoPngEntry(bitmapHeader, context, source); } else { BmpDecoder.DoBitmapEntry(bitmapHeader, context, source); } return(source); }
public static PngFileEncoding GetPngFileEncoding(Memory <byte> data) { var reader = new ByteReader(data, ByteOrder.NetworkEndian); if (FileFormatConstants._pngHeader != reader.NextUint64()) { throw new InvalidPngFileException(IcoErrorCode.NotPng, $"Data stream does not begin with the PNG magic constant"); } var chunkLength = reader.NextUint32(); var chunkType = reader.NextUint32(); if (chunkType != _ihdrChunkName) { throw new InvalidPngFileException(IcoErrorCode.PngBadIHDR, $"PNG file should begin with IHDR chunk; found {chunkType} instead"); } if (chunkLength < 13) { throw new InvalidPngFileException(IcoErrorCode.PngBadIHDR, $"IHDR chunk is invalid length {chunkLength}; expected at least 13 bytes"); } var result = new PngFileEncoding { Width = reader.NextUint32(), Height = reader.NextUint32(), BitsPerChannel = reader.NextUint8(), ColorType = (PngColorType)reader.NextUint8(), }; if (result.Width == 0 || result.Height == 0) { throw new InvalidPngFileException(IcoErrorCode.PngIllegalInputDimensions, $"Illegal Width x Height of {result.Width} x {result.Height}"); } switch (result.BitsPerChannel) { case 1: case 2: case 4: case 8: case 16: break; default: throw new InvalidPngFileException(IcoErrorCode.PngIllegalInputDepth, $"Illegal bits per color channel / palette entry of {result.BitsPerChannel}"); } switch (result.ColorType) { case PngColorType.Grayscale: case PngColorType.RGB: case PngColorType.Palette: case PngColorType.GrayscaleAlpha: case PngColorType.RGBA: break; default: throw new InvalidPngFileException(IcoErrorCode.PngIllegalColorType, $"Illegal color type {result.ColorType}"); } return(result); }