|
@@ -1,30 +1,19 @@
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
+using OfficeOpenXml.Drawing;
|
|
|
+using OfficeOpenXml.Packaging.Ionic.Zlib;
|
|
|
+using SixLabors.ImageSharp;
|
|
|
+using SixLabors.ImageSharp.Formats.Bmp;
|
|
|
+using SixLabors.ImageSharp.Formats.Gif;
|
|
|
+using SixLabors.ImageSharp.Formats.Jpeg;
|
|
|
+using SixLabors.ImageSharp.Formats.Png;
|
|
|
+using SixLabors.ImageSharp.Formats.Tiff;
|
|
|
+using SixLabors.ImageSharp.Formats.Webp;
|
|
|
using System.IO;
|
|
|
-using System.Linq;
|
|
|
-using System.Text;
|
|
|
using System.Xml;
|
|
|
-using OfficeOpenXml.Drawing;
|
|
|
-using OfficeOpenXml.Packaging.Ionic.Zlib;
|
|
|
|
|
|
namespace Masuit.Tools.Excel;
|
|
|
|
|
|
public static class ImageDetector
|
|
|
{
|
|
|
- private const float MToInch = 39.3700787F;
|
|
|
- private const float CmToInch = MToInch * 0.01F;
|
|
|
- public 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;
|
|
|
- }
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// 获取图像格式
|
|
|
/// </summary>
|
|
@@ -32,52 +21,55 @@ public static class ImageDetector
|
|
|
/// <returns></returns>
|
|
|
public static ePictureType? GetPictureType(Stream ms)
|
|
|
{
|
|
|
- var br = new BinaryReader(ms);
|
|
|
- if (IsJpg(br))
|
|
|
+ ms.Seek(0, SeekOrigin.Begin);
|
|
|
+ var pictureType = Image.DetectFormat(ms) switch
|
|
|
{
|
|
|
- return ePictureType.Jpg;
|
|
|
- }
|
|
|
- if (IsBmp(br, out _))
|
|
|
+ BmpFormat => ePictureType.Bmp,
|
|
|
+ GifFormat => ePictureType.Gif,
|
|
|
+ JpegFormat => ePictureType.Jpg,
|
|
|
+ PngFormat => ePictureType.Png,
|
|
|
+ TiffFormat => ePictureType.Tif,
|
|
|
+ WebpFormat => ePictureType.WebP,
|
|
|
+ _ => new ePictureType?()
|
|
|
+ };
|
|
|
+ if (pictureType.HasValue)
|
|
|
{
|
|
|
- return ePictureType.Bmp;
|
|
|
- }
|
|
|
- else if (IsGif(br))
|
|
|
- {
|
|
|
- return ePictureType.Gif;
|
|
|
- }
|
|
|
- else if (IsPng(br))
|
|
|
- {
|
|
|
- return ePictureType.Png;
|
|
|
- }
|
|
|
- else if (IsTif(br, out _))
|
|
|
- {
|
|
|
- return ePictureType.Tif;
|
|
|
+ ms.Seek(0, SeekOrigin.Begin);
|
|
|
+ return pictureType;
|
|
|
}
|
|
|
- else if (IsIco(br))
|
|
|
+
|
|
|
+ var br = new BinaryReader(ms);
|
|
|
+ if (IsIco(br))
|
|
|
{
|
|
|
+ ms.Seek(0, SeekOrigin.Begin);
|
|
|
return ePictureType.Ico;
|
|
|
}
|
|
|
- else if (IsWebP(br))
|
|
|
- {
|
|
|
- return ePictureType.WebP;
|
|
|
- }
|
|
|
- else if (IsEmf(br))
|
|
|
+
|
|
|
+ if (IsEmf(br))
|
|
|
{
|
|
|
+ ms.Seek(0, SeekOrigin.Begin);
|
|
|
return ePictureType.Emf;
|
|
|
}
|
|
|
- else if (IsWmf(br))
|
|
|
+
|
|
|
+ if (IsWmf(br))
|
|
|
{
|
|
|
+ ms.Seek(0, SeekOrigin.Begin);
|
|
|
return ePictureType.Wmf;
|
|
|
}
|
|
|
- else if (IsSvg(ms))
|
|
|
+
|
|
|
+ if (IsSvg(ms))
|
|
|
{
|
|
|
+ ms.Seek(0, SeekOrigin.Begin);
|
|
|
return ePictureType.Svg;
|
|
|
}
|
|
|
- else if (IsGZip(br))
|
|
|
+
|
|
|
+ if (IsGZip(br))
|
|
|
{
|
|
|
_ = ExtractImage(ToArray(ms), out ePictureType? pt);
|
|
|
+ ms.Seek(0, SeekOrigin.Begin);
|
|
|
return pt;
|
|
|
}
|
|
|
+
|
|
|
return null;
|
|
|
}
|
|
|
|
|
@@ -109,62 +101,6 @@ public static class ImageDetector
|
|
|
return sign.Length >= 2 && sign[0] == 0x1F && sign[1] == 0x8B;
|
|
|
}
|
|
|
|
|
|
- internal static bool TryGetImageBounds(ePictureType pictureType, 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 (pictureType == ePictureType.Bmp && IsBmp(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (pictureType == ePictureType.Jpg && IsJpg(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (pictureType == ePictureType.Gif && IsGif(ms, ref width, ref height))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (pictureType == ePictureType.Png && IsPng(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (pictureType == ePictureType.Emf && IsEmf(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- if (pictureType == ePictureType.Wmf && IsWmf(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- else if (pictureType == ePictureType.Svg && IsSvg(ms, ref width, ref height))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- else if (pictureType == ePictureType.Tif && IsTif(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- else if (pictureType == ePictureType.WebP && IsWebP(ms, ref width, ref height, ref horizontalResolution, ref verticalResolution))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- else if (pictureType == ePictureType.Ico && IsIcon(ms, ref width, ref height))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
internal static byte[] ExtractImage(byte[] img, out ePictureType? type)
|
|
|
{
|
|
|
if (IsGZip(img))
|
|
@@ -175,207 +111,46 @@ public static class ImageDetector
|
|
|
var msOut = new MemoryStream();
|
|
|
const int bufferSize = 4096;
|
|
|
var buffer = new byte[bufferSize];
|
|
|
- using (var z = new GZipStream(ms, CompressionMode.Decompress))
|
|
|
+ using var z = new GZipStream(ms, CompressionMode.Decompress);
|
|
|
+ int size = 0;
|
|
|
+ do
|
|
|
{
|
|
|
- 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))
|
|
|
+ size = z.Read(buffer, 0, bufferSize);
|
|
|
+ if (size > 0)
|
|
|
{
|
|
|
- type = ePictureType.Emf;
|
|
|
+ msOut.Write(buffer, 0, size);
|
|
|
}
|
|
|
- else if (IsWmf(br))
|
|
|
- {
|
|
|
- type = ePictureType.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)
|
|
|
+ while (size == bufferSize);
|
|
|
+ msOut.Position = 0;
|
|
|
+ var br = new BinaryReader(msOut);
|
|
|
+ if (IsEmf(br))
|
|
|
{
|
|
|
- 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;
|
|
|
- }
|
|
|
+ type = ePictureType.Emf;
|
|
|
}
|
|
|
- }
|
|
|
- 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")
|
|
|
+ else if (IsWmf(br))
|
|
|
{
|
|
|
- br.ReadBytes(12);
|
|
|
- horizontalResolution = br.ReadInt32() / MToInch;
|
|
|
- verticalResolution = br.ReadInt32() / MToInch;
|
|
|
+ type = ePictureType.Wmf;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- horizontalResolution = verticalResolution = 1;
|
|
|
+ type = null;
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
+ msOut.Position = 0;
|
|
|
+ return msOut.ToArray();
|
|
|
}
|
|
|
- }
|
|
|
- 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))
|
|
|
+ catch
|
|
|
{
|
|
|
- var imageCount = br.ReadInt16();
|
|
|
- width = br.ReadByte();
|
|
|
- if (width == 0) width = 256;
|
|
|
- height = br.ReadByte();
|
|
|
- if (height == 0) height = 256;
|
|
|
- br.Close();
|
|
|
- return true;
|
|
|
+ type = null;
|
|
|
+ return img;
|
|
|
}
|
|
|
- br.Close();
|
|
|
- return false;
|
|
|
}
|
|
|
+ type = null;
|
|
|
+ return img;
|
|
|
}
|
|
|
|
|
|
+ #region Ico
|
|
|
+
|
|
|
internal static bool IsIco(BinaryReader br)
|
|
|
{
|
|
|
br.BaseStream.Seek(0, SeekOrigin.Begin);
|
|
@@ -386,269 +161,8 @@ public static class ImageDetector
|
|
|
|
|
|
#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;
|
|
@@ -660,36 +174,6 @@ public static class ImageDetector
|
|
|
|
|
|
#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;
|
|
@@ -699,126 +183,8 @@ public static class ImageDetector
|
|
|
|
|
|
#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
|
|
@@ -841,62 +207,5 @@ public static class ImageDetector
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
- }
|
|
|
}
|