与往常一样,最好的选择是找到一个经过良好测试的库。但是,您说这很困难,因此下面是一些在很大程度上未经测试的狡猾代码,它们在相当多的情况下都适用:
using System;using System.Collections.Generic;using System.Drawing;using System.IO;using System.Linq;namespace ImageDimensions{ public static class ImageHelper { const string errorMessage = "Could not recognize image format."; private static Dictionary<byte[], Func<BinaryReader, Size>> imageFormatDeprers = new Dictionary<byte[], Func<BinaryReader, Size>>() { { new byte[]{ 0x42, 0x4D }, DepreBitmap}, { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DepreGif }, { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DepreGif }, { new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DeprePng }, { new byte[]{ 0xff, 0xd8 }, DepreJfif }, }; /// <summary> /// Gets the dimensions of an image. /// </summary> /// <param name="path">The path of the image to get the dimensions of.</param> /// <returns>The dimensions of the specified image.</returns> /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception> public static Size GetDimensions(string path) { using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(path))) { try { return GetDimensions(binaryReader); } catch (ArgumentException e) { if (e.Message.StartsWith(errorMessage)) { throw new ArgumentException(errorMessage, "path", e); } else { throw e; } } } } /// <summary> /// Gets the dimensions of an image. /// </summary> /// <param name="path">The path of the image to get the dimensions of.</param> /// <returns>The dimensions of the specified image.</returns> /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception> public static Size GetDimensions(BinaryReader binaryReader) { int maxMagicBytesLength = imageFormatDeprers.Keys.OrderByDescending(x => x.Length).First().Length; byte[] magicBytes = new byte[maxMagicBytesLength]; for (int i = 0; i < maxMagicBytesLength; i += 1) { magicBytes[i] = binaryReader.ReadByte(); foreach(var kvPair in imageFormatDeprers) { if (magicBytes.StartsWith(kvPair.Key)) { return kvPair.Value(binaryReader); } } } throw new ArgumentException(errorMessage, "binaryReader"); } private static bool StartsWith(this byte[] thisBytes, byte[] thatBytes) { for(int i = 0; i < thatBytes.Length; i+= 1) { if (thisBytes[i] != thatBytes[i]) { return false; } } return true; } private static short ReadLittleEndianInt16(this BinaryReader binaryReader) { byte[] bytes = new byte[sizeof(short)]; for (int i = 0; i < sizeof(short); i += 1) { bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte(); } return BitConverter.ToInt16(bytes, 0); } private static int ReadLittleEndianInt32(this BinaryReader binaryReader) { byte[] bytes = new byte[sizeof(int)]; for (int i = 0; i < sizeof(int); i += 1) { bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte(); } return BitConverter.ToInt32(bytes, 0); } private static Size DepreBitmap(BinaryReader binaryReader) { binaryReader.ReadBytes(16); int width = binaryReader.ReadInt32(); int height = binaryReader.ReadInt32(); return new Size(width, height); } private static Size DepreGif(BinaryReader binaryReader) { int width = binaryReader.ReadInt16(); int height = binaryReader.ReadInt16(); return new Size(width, height); } private static Size DeprePng(BinaryReader binaryReader) { binaryReader.ReadBytes(8); int width = binaryReader.ReadLittleEndianInt32(); int height = binaryReader.ReadLittleEndianInt32(); return new Size(width, height); } private static Size DepreJfif(BinaryReader binaryReader) { while (binaryReader.ReadByte() == 0xff) { byte marker = binaryReader.ReadByte(); short chunkLength = binaryReader.ReadLittleEndianInt16(); if (marker == 0xc0) { binaryReader.ReadByte(); int height = binaryReader.ReadLittleEndianInt16(); int width = binaryReader.ReadLittleEndianInt16(); return new Size(width, height); } binaryReader.ReadBytes(chunkLength - 2); } throw new ArgumentException(errorMessage); } }}希望代码相当明显。要添加新的文件格式,可以将其添加到
imageFormatDeprers其中,其键是“魔术位”数组,该数组出现在给定格式的每个文件的开头,而值是一个从流中提取大小的函数。大多数格式都足够简单,唯一真正的臭味是jpeg。



