Browse Source

增加图像格式检测函数

懒得勤快 3 years ago
parent
commit
74bdecaf84

+ 1 - 1
Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj

@@ -4,7 +4,7 @@
     <LangVersion>latest</LangVersion>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <CodeAnalysisRuleSet />
-    <Version>2.5.1</Version>
+    <Version>2.5.2</Version>
     <Authors>懒得勤快</Authors>
     <Description>Masuit.Tools基础公共库,包含一些常用的操作类,大都是静态类,加密解密,反射操作,Excel简单导出,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载和FTP客户端,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断点续传,集合扩展等常用封装。</Description>
     <Copyright>懒得勤快,长空X</Copyright>

+ 914 - 0
Masuit.Tools.Abstractions/Media/ImageDetectExt.cs

@@ -0,0 +1,914 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Text;
+using System.Xml;
+
+namespace Masuit.Tools.Media;
+
+public static class ImageDetectExt
+{
+    private const float MToInch = 39.3700787F;
+    private const float CmToInch = MToInch * 0.01F;
+    private const float MmToInch = CmToInch * 0.1F;
+    private const float HundredthThMmToInch = MmToInch * 0.01F;
+    internal const float StandardDPI = 96f;
+
+    internal struct TifIfd
+    {
+        public short Tag;
+        public short Type;
+        public int Count;
+        public int ValueOffset;
+    }
+
+    public static bool IsImage(this Stream s)
+    {
+        return GetImageType(s) != null;
+    }
+
+    /// <summary>
+    /// 获取图像格式
+    /// </summary>
+    /// <param name="ms"></param>
+    /// <returns></returns>
+    public static ImageFormat? GetImageType(this Stream ms)
+    {
+        using var br = new BinaryReader(ms);
+        if (IsJpg(br))
+        {
+            return ImageFormat.Jpg;
+        }
+        if (IsBmp(br, out _))
+        {
+            return ImageFormat.Bmp;
+        }
+
+        if (IsGif(br))
+        {
+            return ImageFormat.Gif;
+        }
+
+        if (IsPng(br))
+        {
+            return ImageFormat.Png;
+        }
+
+        if (IsTif(br, out _))
+        {
+            return ImageFormat.Tif;
+        }
+
+        if (IsIco(br))
+        {
+            return ImageFormat.Ico;
+        }
+
+        if (IsWebP(br))
+        {
+            return ImageFormat.WebP;
+        }
+
+        if (IsEmf(br))
+        {
+            return ImageFormat.Emf;
+        }
+
+        if (IsWmf(br))
+        {
+            return ImageFormat.Wmf;
+        }
+
+        if (IsSvg(ms))
+        {
+            return ImageFormat.Svg;
+        }
+
+        if (IsGZip(br))
+        {
+            _ = ExtractImage(ToArray(ms), out ImageFormat? pt);
+            return pt;
+        }
+
+        return null;
+    }
+
+    /// <summary>
+    ///
+    /// </summary>
+    /// <param name="stream"></param>
+    /// <returns></returns>
+    public static byte[] ToArray(Stream stream)
+    {
+        stream.Position = 0;
+        byte[] bytes = new byte[stream.Length];
+        stream.Read(bytes, 0, bytes.Length);
+
+        // 设置当前流的位置为流的开始
+        stream.Seek(0, SeekOrigin.Begin);
+        return bytes;
+    }
+
+    private static bool IsGZip(BinaryReader br)
+    {
+        br.BaseStream.Position = 0;
+        var sign = br.ReadBytes(2);
+        return IsGZip(sign);
+    }
+
+    private static bool IsGZip(byte[] sign)
+    {
+        return sign.Length >= 2 && sign[0] == 0x1F && sign[1] == 0x8B;
+    }
+
+    internal static bool TryGetImageBounds(ImageFormat imageFormat, MemoryStream ms, ref double width, ref double height, out double horizontalResolution, out double verticalResolution)
+    {
+        width = 0;
+        height = 0;
+        horizontalResolution = verticalResolution = StandardDPI;
+        try
+        {
+            ms.Seek(0, SeekOrigin.Begin);
+            if (imageFormat == ImageFormat.Bmp && IsBmp(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
+            {
+                return true;
+            }
+            if (imageFormat == ImageFormat.Jpg && IsJpg(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
+            {
+                return true;
+            }
+            if (imageFormat == ImageFormat.Gif && IsGif(ms, ref width, ref height))
+            {
+                return true;
+            }
+            if (imageFormat == ImageFormat.Png && IsPng(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
+            {
+                return true;
+            }
+            if (imageFormat == ImageFormat.Emf && IsEmf(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
+            {
+                return true;
+            }
+            if (imageFormat == ImageFormat.Wmf && IsWmf(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
+            {
+                return true;
+            }
+            else if (imageFormat == ImageFormat.Svg && IsSvg(ms, ref width, ref height))
+            {
+                return true;
+            }
+            else if (imageFormat == ImageFormat.Tif && IsTif(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
+            {
+                return true;
+            }
+            else if (imageFormat == ImageFormat.WebP && IsWebP(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
+            {
+                return true;
+            }
+            else if (imageFormat == ImageFormat.Ico && IsIcon(ms, ref width, ref height))
+            {
+                return true;
+            }
+            return false;
+        }
+        catch
+        {
+            return false;
+        }
+    }
+
+    internal static byte[] ExtractImage(byte[] img, out ImageFormat? type)
+    {
+        if (IsGZip(img))
+        {
+            try
+            {
+                var ms = new MemoryStream(img);
+                var msOut = new MemoryStream();
+                const int bufferSize = 4096;
+                var buffer = new byte[bufferSize];
+                using var z = new GZipStream(ms, CompressionMode.Decompress);
+                int size = 0;
+                do
+                {
+                    size = z.Read(buffer, 0, bufferSize);
+                    if (size > 0)
+                    {
+                        msOut.Write(buffer, 0, size);
+                    }
+                }
+                while (size == bufferSize);
+                msOut.Position = 0;
+                var br = new BinaryReader(msOut);
+                if (IsEmf(br))
+                {
+                    type = ImageFormat.Emf;
+                }
+                else if (IsWmf(br))
+                {
+                    type = ImageFormat.Wmf;
+                }
+                else
+                {
+                    type = null;
+                }
+                msOut.Position = 0;
+                return msOut.ToArray();
+            }
+            catch
+            {
+                type = null;
+                return img;
+            }
+        }
+        type = null;
+        return img;
+    }
+
+    private static bool IsJpg(MemoryStream ms, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            if (IsJpg(br))
+            {
+                float xDensity = 1, yDensity = 1;
+                while (ms.Position < ms.Length)
+                {
+                    var id = GetUInt16BigEndian(br);
+                    var length = (int)GetInt16BigEndian(br);
+                    switch (id)
+                    {
+                        case 0xFFE0:
+                            var identifier = br.ReadBytes(5); //JFIF\0
+                            var version = br.ReadBytes(2);
+                            var unit = br.ReadByte();
+                            xDensity = (int)GetInt16BigEndian(br);
+                            yDensity = (int)GetInt16BigEndian(br);
+
+                            if (unit == 1)
+                            {
+                                horizontalResolution = xDensity;
+                                verticalResolution = yDensity;
+                            }
+                            else if (unit == 2)
+                            {
+                                horizontalResolution = xDensity * CmToInch;
+                                verticalResolution = yDensity * CmToInch;
+                            }
+
+                            ms.Position += length - 14;
+                            break;
+
+                        case 0xFFE1:
+                            var pos = ms.Position;
+                            identifier = br.ReadBytes(6); //EXIF\0\0 or //EXIF\FF\FF
+                            double w = 0, h = 0;
+                            ReadTiffHeader(br, ref w, ref h, ref horizontalResolution, ref verticalResolution);
+                            ms.Position = pos + length - 2;
+                            break;
+
+                        case 0xFFC0:
+                        case 0xFFC1:
+                        case 0xFFC2:
+                            var precision = br.ReadByte(); //Bits
+                            height = GetUInt16BigEndian(br);
+                            width = GetUInt16BigEndian(br);
+                            br.Close();
+                            return true;
+
+                        case 0xFFD9:
+                            return height != 0 && width != 0;
+
+                        default:
+                            ms.Position += length - 2;
+                            break;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    private static bool IsJpg(BinaryReader br)
+    {
+        br.BaseStream.Position = 0;
+        var sign = br.ReadBytes(2);    //FF D8
+        return sign.Length >= 2 && sign[0] == 0xFF && sign[1] == 0xD8;
+    }
+
+    private static bool IsGif(MemoryStream ms, ref double width, ref double height)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            if (IsGif(br))
+            {
+                width = br.ReadUInt16();
+                height = br.ReadUInt16();
+                br.Close();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static bool IsGif(BinaryReader br)
+    {
+        br.BaseStream.Seek(0, SeekOrigin.Begin);
+        var b = br.ReadBytes(6);
+        return b[0] == 0x47 && b[1] == 0x49 && b[2] == 0x46;    //byte 4-6 contains the version, but we don't check them here.
+    }
+
+    private static bool IsBmp(MemoryStream ms, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            if (IsBmp(br, out string sign))
+            {
+                var size = br.ReadInt32();
+                var reserved = br.ReadBytes(4);
+                var offsetData = br.ReadInt32();
+
+                //Info Header
+                var ihSize = br.ReadInt32(); //Should be 40
+                width = br.ReadInt32();
+                height = br.ReadInt32();
+
+                if (sign == "BM")
+                {
+                    br.ReadBytes(12);
+                    horizontalResolution = br.ReadInt32() / MToInch;
+                    verticalResolution = br.ReadInt32() / MToInch;
+                }
+                else
+                {
+                    horizontalResolution = verticalResolution = 1;
+                }
+
+                return true;
+            }
+        }
+        return false;
+    }
+
+    internal static bool IsBmp(BinaryReader br, out string sign)
+    {
+        try
+        {
+            br.BaseStream.Seek(0, SeekOrigin.Begin);
+            sign = Encoding.ASCII.GetString(br.ReadBytes(2));    //BM for a Windows bitmap
+            return (sign == "BM" || sign == "BA" || sign == "CI" || sign == "CP" || sign == "IC" || sign == "PT");
+        }
+        catch
+        {
+            sign = null;
+            return false;
+        }
+    }
+
+    #region Ico
+
+    private static bool IsIcon(MemoryStream ms, ref double width, ref double height)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            if (IsIco(br))
+            {
+                var imageCount = br.ReadInt16();
+                width = br.ReadByte();
+                if (width == 0) width = 256;
+                height = br.ReadByte();
+                if (height == 0) height = 256;
+                br.Close();
+                return true;
+            }
+            br.Close();
+            return false;
+        }
+    }
+
+    internal static bool IsIco(BinaryReader br)
+    {
+        br.BaseStream.Seek(0, SeekOrigin.Begin);
+        var type0 = br.ReadInt16();
+        var type1 = br.ReadInt16();
+        return type0 == 0 && type1 == 1;
+    }
+
+    #endregion Ico
+
+    #region WebP
+
+    private static bool IsWebP(MemoryStream ms, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        width = height = 0;
+        horizontalResolution = verticalResolution = StandardDPI * (1 + 1 / 3); //Excel seems to render webp at 1 1/3 size.
+        using (var br = new BinaryReader(ms))
+        {
+            if (IsWebP(br))
+            {
+                var vp8 = Encoding.ASCII.GetString(br.ReadBytes(4));
+                switch (vp8)
+                {
+                    case "VP8 ":
+                        var b = br.ReadBytes(10);
+                        var w = br.ReadInt16();
+                        width = w & 0x3FFF;
+                        var hScale = w >> 14;
+                        var h = br.ReadInt16();
+                        height = h & 0x3FFF;
+                        hScale = h >> 14;
+                        break;
+
+                    case "VP8X":
+                        br.ReadBytes(8);
+                        b = br.ReadBytes(6);
+                        width = BitConverter.ToInt32(new byte[] { b[0], b[1], b[2], 0 }, 0) + 1;
+                        height = BitConverter.ToInt32(new byte[] { b[3], b[4], b[5], 0 }, 0) + 1;
+                        break;
+
+                    case "VP8L":
+                        br.ReadBytes(5);
+                        b = br.ReadBytes(4);
+                        width = (b[0] | (b[1] & 0x3F) << 8) + 1;
+                        height = (b[1] >> 6 | b[2] << 2 | (b[3] & 0x0F) << 10) + 1;
+                        break;
+                }
+            }
+        }
+        return width != 0 && height != 0;
+    }
+
+    internal static bool IsWebP(BinaryReader br)
+    {
+        try
+        {
+            br.BaseStream.Seek(0, SeekOrigin.Begin);
+            var riff = Encoding.ASCII.GetString(br.ReadBytes(4));
+            var length = GetInt32BigEndian(br);
+            var webP = Encoding.ASCII.GetString(br.ReadBytes(4));
+
+            return riff == "RIFF" && webP == "WEBP";
+        }
+        catch
+        {
+            return false;
+        }
+    }
+
+    #endregion WebP
+
+    #region Tiff
+
+    private static bool IsTif(MemoryStream ms, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            return ReadTiffHeader(br, ref width, ref height, ref horizontalResolution, ref verticalResolution);
+        }
+    }
+
+    private static bool ReadTiffHeader(BinaryReader br, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        var ms = br.BaseStream;
+        var pos = ms.Position;
+        if (IsTif(br, out bool isBigEndian, false))
+        {
+            var offset = GetTifInt32(br, isBigEndian);
+            ms.Position = pos + offset;
+            var numberOfIdf = GetTifInt16(br, isBigEndian);
+            var ifds = new List<TifIfd>();
+            for (int i = 0; i < numberOfIdf; i++)
+            {
+                var ifd = new TifIfd()
+                {
+                    Tag = GetTifInt16(br, isBigEndian),
+                    Type = GetTifInt16(br, isBigEndian),
+                    Count = GetTifInt32(br, isBigEndian),
+                };
+                if (ifd.Type == 1 || ifd.Type == 2 || ifd.Type == 6 || ifd.Type == 7)
+                {
+                    ifd.ValueOffset = br.ReadByte();
+                    br.ReadBytes(3);
+                }
+                else if (ifd.Type == 3 || ifd.Type == 8)
+                {
+                    ifd.ValueOffset = GetTifInt16(br, isBigEndian);
+                    br.ReadBytes(2);
+                }
+                else
+                {
+                    ifd.ValueOffset = GetTifInt32(br, isBigEndian);
+                }
+                ifds.Add(ifd);
+            }
+
+            int resolutionUnit = 2;
+            foreach (var ifd in ifds)
+            {
+                switch (ifd.Tag)
+                {
+                    case 0x100:
+                        width = ifd.ValueOffset;
+                        break;
+
+                    case 0x101:
+                        height = ifd.ValueOffset;
+                        break;
+
+                    case 0x11A:
+                        ms.Position = ifd.ValueOffset + pos;
+                        var l1 = GetTifInt32(br, isBigEndian);
+                        var l2 = GetTifInt32(br, isBigEndian);
+                        horizontalResolution = l1 / l2;
+                        break;
+
+                    case 0x11B:
+                        ms.Position = ifd.ValueOffset + pos;
+                        l1 = GetTifInt32(br, isBigEndian);
+                        l2 = GetTifInt32(br, isBigEndian);
+                        verticalResolution = l1 / l2;
+                        break;
+
+                    case 0x128:
+                        resolutionUnit = ifd.ValueOffset;
+                        break;
+                }
+            }
+            if (resolutionUnit == 1)
+            {
+                horizontalResolution *= CmToInch;
+                verticalResolution *= CmToInch;
+            }
+        }
+        return width != 0 && height != 0;
+    }
+
+    private static bool IsTif(BinaryReader br, out bool isBigEndian, bool resetPos = false)
+    {
+        try
+        {
+            if (resetPos)
+            {
+                br.BaseStream.Position = 0;
+            }
+            var b = br.ReadBytes(2);
+            isBigEndian = Encoding.ASCII.GetString(b) == "MM";
+            var identifier = GetTifInt16(br, isBigEndian);
+            if (identifier == 42)
+            {
+                return true;
+            }
+        }
+        catch
+        {
+            isBigEndian = false;
+            return false;
+        }
+        return false;
+    }
+
+    private static short GetTifInt16(BinaryReader br, bool isBigEndian)
+    {
+        if (isBigEndian)
+        {
+            return GetInt16BigEndian(br);
+        }
+        else
+        {
+            return br.ReadInt16();
+        }
+    }
+
+    private static int GetTifInt32(BinaryReader br, bool isBigEndian)
+    {
+        if (isBigEndian)
+        {
+            return GetInt32BigEndian(br);
+        }
+        else
+        {
+            return br.ReadInt32();
+        }
+    }
+
+    #endregion Tiff
+
+    #region Emf
+
+    private static bool IsEmf(MemoryStream ms, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            if (IsEmf(br))
+            {
+                var length = br.ReadInt32();
+                var bounds = new int[4];
+                bounds[0] = br.ReadInt32();
+                bounds[1] = br.ReadInt32();
+                bounds[2] = br.ReadInt32();
+                bounds[3] = br.ReadInt32();
+                var frame = new int[4];
+                frame[0] = br.ReadInt32();
+                frame[1] = br.ReadInt32();
+                frame[2] = br.ReadInt32();
+                frame[3] = br.ReadInt32();
+
+                var signatureBytes = br.ReadBytes(4);
+                var signature = Encoding.ASCII.GetString(signatureBytes);
+                if (signature.Trim() == "EMF")
+                {
+                    var version = br.ReadUInt32();
+                    var size = br.ReadUInt32();
+                    var records = br.ReadUInt32();
+                    var handles = br.ReadUInt16();
+                    var reserved = br.ReadUInt16();
+
+                    var nDescription = br.ReadUInt32();
+                    var offDescription = br.ReadUInt32();
+                    var nPalEntries = br.ReadUInt32();
+                    var device = new uint[2];
+                    device[0] = br.ReadUInt32();
+                    device[1] = br.ReadUInt32();
+
+                    var mm = new uint[2];
+                    mm[0] = br.ReadUInt32();
+                    mm[1] = br.ReadUInt32();
+
+                    //Extension 1
+                    var cbPixelFormat = br.ReadUInt32();
+                    var offPixelFormat = br.ReadUInt32();
+                    var bOpenGL = br.ReadUInt32();
+
+                    //Extension 2
+                    var hr = br.ReadUInt32();
+                    var vr = br.ReadUInt32();
+
+                    var id = br.ReadInt32();
+                    var size2 = br.ReadInt32();
+
+                    width = (bounds[2] - bounds[0] + 1);
+                    height = (bounds[3] - bounds[1] + 1);
+
+                    horizontalResolution = width / ((frame[2] - frame[0]) * HundredthThMmToInch * StandardDPI) * StandardDPI;
+                    verticalResolution = height / ((frame[3] - frame[1]) * HundredthThMmToInch * StandardDPI) * StandardDPI;
+
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static bool IsEmf(BinaryReader br)
+    {
+        br.BaseStream.Position = 0;
+        var type = br.ReadInt32();
+        return type == 1;
+    }
+
+    #endregion Emf
+
+    #region Wmf
+
+    private const double PIXELS_PER_TWIPS = 1D / 15D;
+    private const double DEFAULT_TWIPS = 1440D;
+
+    private static bool IsWmf(MemoryStream ms, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            if (IsWmf(br))
+            {
+                var HWmf = br.ReadInt16();
+                var bounds = new ushort[4];
+                bounds[0] = br.ReadUInt16();
+                bounds[1] = br.ReadUInt16();
+                bounds[2] = br.ReadUInt16();
+                bounds[3] = br.ReadUInt16();
+
+                var inch = br.ReadInt16();
+                width = bounds[2] - bounds[0];
+                height = bounds[3] - bounds[1];
+                if (inch != 0)
+                {
+                    width *= (DEFAULT_TWIPS / inch) * PIXELS_PER_TWIPS;
+                    height *= (DEFAULT_TWIPS / inch) * PIXELS_PER_TWIPS;
+                }
+                return width != 0 && height != 0;
+            }
+        }
+        return false;
+    }
+
+    private static bool IsWmf(BinaryReader br)
+    {
+        br.BaseStream.Position = 0;
+        var key = br.ReadUInt32();
+        return key == 0x9AC6CDD7;
+    }
+
+    #endregion Wmf
+
+    #region Png
+
+    private static bool IsPng(MemoryStream ms, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution)
+    {
+        using (var br = new BinaryReader(ms))
+        {
+            return IsPng(br, ref width, ref height, ref horizontalResolution, ref verticalResolution);
+        }
+    }
+
+    private static bool IsPng(BinaryReader br, ref double width, ref double height, ref double horizontalResolution, ref double verticalResolution, long fileEndPosition = long.MinValue)
+    {
+        if (IsPng(br))
+        {
+            if (fileEndPosition == long.MinValue)
+            {
+                fileEndPosition = br.BaseStream.Length;
+            }
+            while (br.BaseStream.Position < fileEndPosition)
+            {
+                var chunkType = ReadPngChunkHeader(br, out int length);
+                switch (chunkType)
+                {
+                    case "IHDR":
+                        width = GetInt32BigEndian(br);
+                        height = GetInt32BigEndian(br);
+                        br.ReadBytes(5); //Ignored bytes, Depth compression etc.
+                        break;
+
+                    case "pHYs":
+                        horizontalResolution = GetInt32BigEndian(br);
+                        verticalResolution = GetInt32BigEndian(br);
+                        var unitSpecifier = br.ReadByte();
+                        if (unitSpecifier == 1)
+                        {
+                            horizontalResolution /= MToInch;
+                            verticalResolution /= MToInch;
+                        }
+
+                        br.Close();
+                        return true;
+
+                    default:
+                        br.ReadBytes(length);
+                        break;
+                }
+                var crc = br.ReadInt32();
+            }
+        }
+        br.Close();
+        return width != 0 && height != 0;
+    }
+
+    private static bool IsPng(BinaryReader br)
+    {
+        br.BaseStream.Position = 0;
+        var signature = br.ReadBytes(8);
+        return signature.SequenceEqual(new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 });
+    }
+
+    private static string ReadPngChunkHeader(BinaryReader br, out int length)
+    {
+        length = GetInt32BigEndian(br);
+        var b = br.ReadBytes(4);
+        var type = Encoding.ASCII.GetString(b);
+        return type;
+    }
+
+    #endregion Png
+
+    #region Svg
+
+    private static bool IsSvg(MemoryStream ms, ref double width, ref double height)
+    {
+        try
+        {
+            var reader = new XmlTextReader(ms);
+            while (reader.Read())
+            {
+                if (reader.LocalName == "svg" && reader.NodeType == XmlNodeType.Element)
+                {
+                    var w = reader.GetAttribute("width");
+                    var h = reader.GetAttribute("height");
+                    var vb = reader.GetAttribute("viewBox");
+                    reader.Close();
+                    if (w == null || h == null)
+                    {
+                        if (vb == null)
+                        {
+                            return false;
+                        }
+                        var bounds = vb.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
+                        if (bounds.Length < 4)
+                        {
+                            return false;
+                        }
+                        if (string.IsNullOrEmpty(w))
+                        {
+                            w = bounds[2];
+                        }
+                        if (string.IsNullOrEmpty(h))
+                        {
+                            h = bounds[3];
+                        }
+                    }
+                    width = GetSvgUnit(w);
+                    if (double.IsNaN(width)) return false;
+                    height = GetSvgUnit(h);
+                    if (double.IsNaN(height)) return false;
+                    return true;
+                }
+            }
+            return false;
+        }
+        catch
+        {
+            return false;
+        }
+    }
+
+    private static bool IsSvg(Stream ms)
+    {
+        try
+        {
+            ms.Position = 0;
+            var reader = new XmlTextReader(ms);
+            while (reader.Read())
+            {
+                if (reader.LocalName == "svg" && reader.NodeType == XmlNodeType.Element)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+        catch
+        {
+            return false;
+        }
+    }
+
+    private static double GetSvgUnit(string v)
+    {
+        var factor = 1D;
+        if (v.EndsWith("px", StringComparison.OrdinalIgnoreCase))
+        {
+            v = v.Substring(0, v.Length - 2);
+        }
+        else if (v.EndsWith("pt", StringComparison.OrdinalIgnoreCase))
+        {
+            factor = 1.25;
+            v = v.Substring(0, v.Length - 2);
+        }
+        else if (v.EndsWith("pc", StringComparison.OrdinalIgnoreCase))
+        {
+            factor = 15;
+            v = v.Substring(0, v.Length - 2);
+        }
+        else if (v.EndsWith("mm", StringComparison.OrdinalIgnoreCase))
+        {
+            factor = 3.543307;
+            v = v.Substring(0, v.Length - 2);
+        }
+        else if (v.EndsWith("cm", StringComparison.OrdinalIgnoreCase))
+        {
+            factor = 35.43307;
+            v = v.Substring(0, v.Length - 2);
+        }
+        else if (v.EndsWith("in", StringComparison.OrdinalIgnoreCase))
+        {
+            factor = 90;
+            v = v.Substring(0, v.Length - 2);
+        }
+        if (double.TryParse(v, out double value))
+        {
+            return value * factor;
+        }
+        return double.NaN;
+    }
+
+    #endregion Svg
+
+    private static ushort GetUInt16BigEndian(BinaryReader br)
+    {
+        var b = br.ReadBytes(2);
+        return BitConverter.ToUInt16(new byte[] { b[1], b[0] }, 0);
+    }
+
+    private static short GetInt16BigEndian(BinaryReader br)
+    {
+        var b = br.ReadBytes(2);
+        return BitConverter.ToInt16(new byte[] { b[1], b[0] }, 0);
+    }
+
+    private static int GetInt32BigEndian(BinaryReader br)
+    {
+        var b = br.ReadBytes(4);
+        return BitConverter.ToInt32(new byte[] { b[3], b[2], b[1], b[0] }, 0);
+    }
+}

+ 20 - 0
Masuit.Tools.Abstractions/Media/ImageFormat.cs

@@ -0,0 +1,20 @@
+namespace Masuit.Tools.Media;
+
+/// <summary>
+/// 图片格式
+/// </summary>
+public enum ImageFormat
+{
+    Bmp,
+    Jpg,
+    Gif,
+    Png,
+    Emf,
+    Tif,
+    Wmf,
+    Svg,
+    WebP,
+    Ico,
+    Emz,
+    Wmz,
+}

+ 1 - 1
Masuit.Tools.AspNetCore/Masuit.Tools.AspNetCore.csproj

@@ -18,7 +18,7 @@
         <LangVersion>latest</LangVersion>
         <RepositoryType>Github</RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-        <Version>1.1.1</Version>
+        <Version>1.1.2</Version>
         <FileVersion>1.0</FileVersion>
         <Company>masuit.com</Company>
         <AssemblyVersion>1.0</AssemblyVersion>

+ 1 - 1
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -18,7 +18,7 @@ github:https://github.com/ldqk/Masuit.Tools
         <UserSecretsId>830c282f-f7c1-42be-8651-4cd06ac8e73f</UserSecretsId>
         <RepositoryType>Github</RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-        <Version>2.5.1</Version>
+        <Version>2.5.2</Version>
         <FileVersion>2.4.5.6</FileVersion>
         <Company>masuit.com</Company>
         <AssemblyVersion>2.4.5.6</AssemblyVersion>

+ 31 - 33
Masuit.Tools.Excel/ImageDetector.cs

@@ -775,45 +775,43 @@ public static class ImageDetector
     {
         try
         {
-            using (var reader = new XmlTextReader(ms))
+            var reader = new XmlTextReader(ms);
+            while (reader.Read())
             {
-                while (reader.Read())
+                if (reader.LocalName == "svg" && reader.NodeType == XmlNodeType.Element)
                 {
-                    if (reader.LocalName == "svg" && reader.NodeType == XmlNodeType.Element)
+                    var w = reader.GetAttribute("width");
+                    var h = reader.GetAttribute("height");
+                    var vb = reader.GetAttribute("viewBox");
+                    reader.Close();
+                    if (w == null || h == null)
                     {
-                        var w = reader.GetAttribute("width");
-                        var h = reader.GetAttribute("height");
-                        var vb = reader.GetAttribute("viewBox");
-                        reader.Close();
-                        if (w == null || h == null)
+                        if (vb == null)
                         {
-                            if (vb == null)
-                            {
-                                return false;
-                            }
-                            var bounds = vb.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
-                            if (bounds.Length < 4)
-                            {
-                                return false;
-                            }
-                            if (string.IsNullOrEmpty(w))
-                            {
-                                w = bounds[2];
-                            }
-                            if (string.IsNullOrEmpty(h))
-                            {
-                                h = bounds[3];
-                            }
+                            return false;
+                        }
+                        var bounds = vb.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
+                        if (bounds.Length < 4)
+                        {
+                            return false;
+                        }
+                        if (string.IsNullOrEmpty(w))
+                        {
+                            w = bounds[2];
+                        }
+                        if (string.IsNullOrEmpty(h))
+                        {
+                            h = bounds[3];
                         }
-                        width = GetSvgUnit(w);
-                        if (double.IsNaN(width)) return false;
-                        height = GetSvgUnit(h);
-                        if (double.IsNaN(height)) return false;
-                        return true;
                     }
+                    width = GetSvgUnit(w);
+                    if (double.IsNaN(width)) return false;
+                    height = GetSvgUnit(h);
+                    if (double.IsNaN(height)) return false;
+                    return true;
                 }
-                return false;
             }
+            return false;
         }
         catch
         {
@@ -826,7 +824,7 @@ public static class ImageDetector
         try
         {
             ms.Position = 0;
-            using var reader = new XmlTextReader(ms);
+            var reader = new XmlTextReader(ms);
             while (reader.Read())
             {
                 if (reader.LocalName == "svg" && reader.NodeType == XmlNodeType.Element)
@@ -901,4 +899,4 @@ public static class ImageDetector
         var b = br.ReadBytes(4);
         return BitConverter.ToInt32(new byte[] { b[3], b[2], b[1], b[0] }, 0);
     }
-}
+}

+ 1 - 1
Masuit.Tools.Excel/Masuit.Tools.Excel.csproj

@@ -3,7 +3,7 @@
         <TargetFrameworks>netstandard2.0;netstandard2.1;net461;net5;net6</TargetFrameworks>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>1.2</Version>
+        <Version>1.2.1</Version>
         <Authors>懒得勤快</Authors>
         <Description>Masuit.Tools.Excel导出库,支持一些简单数据的导出,支持图片列</Description>
         <Copyright>懒得勤快</Copyright>

+ 6 - 0
Masuit.Tools.Net45/Masuit.Tools.Net45.csproj

@@ -139,6 +139,12 @@
     <Compile Include="..\Masuit.Tools.Abstractions\Maths\Vector2D.cs">
       <Link>Maths\Vector2D.cs</Link>
     </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Media\ImageDetector.cs">
+      <Link>Media\ImageDetector.cs</Link>
+    </Compile>
+    <Compile Include="..\Masuit.Tools.Abstractions\Media\ImageFormat.cs">
+      <Link>Media\ImageFormat.cs</Link>
+    </Compile>
     <Compile Include="..\Masuit.Tools.Abstractions\Media\ThumbnailCutMode.cs">
       <Link>Media\ThumbnailCutMode.cs</Link>
     </Compile>

+ 1 - 1
Masuit.Tools.Net45/package.nuspec

@@ -2,7 +2,7 @@
 <package>
   <metadata>
     <id>Masuit.Tools.Net45</id>
-    <version>2.5.0.2</version>
+    <version>2.5.2</version>
     <title>Masuit.Tools</title>
     <authors>懒得勤快</authors>
     <owners>masuit.com</owners>

+ 1 - 0
Masuit.Tools/Masuit.Tools.csproj

@@ -163,6 +163,7 @@
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Numerics" />
     <Reference Include="System.Web" />
+    <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="DnsClient">

+ 1 - 1
Masuit.Tools/package.nuspec

@@ -2,7 +2,7 @@
 <package>
   <metadata>
     <id>Masuit.Tools.Net</id>
-    <version>2.5.1</version>
+    <version>2.5.2</version>
     <title>Masuit.Tools</title>
     <authors>懒得勤快</authors>
     <owners>masuit.com</owners>