diff --git a/DisCatSharp/ImageTool.cs b/DisCatSharp/ImageTool.cs index 52cabb268..09a740eb9 100644 --- a/DisCatSharp/ImageTool.cs +++ b/DisCatSharp/ImageTool.cs @@ -1,244 +1,239 @@ // This file is part of the DisCatSharp project, based off DSharpPlus. // // Copyright (c) 2021-2022 AITSYS // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using System; using System.IO; using System.Text; using DisCatSharp.Entities; namespace DisCatSharp { /// /// Tool to detect image formats and convert from binary data to base64 strings. /// public sealed class ImageTool : IDisposable { /// /// The png magic . /// private const ulong PNG_MAGIC = 0x0A1A_0A0D_474E_5089; /// /// The jpeg magic 1. /// private const ushort JPEG_MAGIC_1 = 0xD8FF; /// /// The jpeg magic 2. /// private const ushort JPEG_MAGIC_2 = 0xD9FF; /// /// The gif magic 1 /// private const ulong GIF_MAGIC_1 = 0x0000_6139_3846_4947; /// /// The gif magic 2. /// private const ulong GIF_MAGIC_2 = 0x0000_6137_3846_4947; /// /// The webp magic 1. /// private const uint WEBP_MAGIC_1 = 0x4646_4952; /// /// The webp magic 2. /// private const uint WEBP_MAGIC_2 = 0x5042_4557; /// /// The gif mask. /// private const ulong GIF_MASK = 0x0000_FFFF_FFFF_FFFF; /// /// The mask 32. /// private const ulong MASK32 = 0x0000_0000_FFFF_FFFF; /// /// The mask 16. /// private const uint MASK16 = 0x0000_FFFF; /// /// Gets the stream this tool is operating on. /// public Stream SourceStream { get; } private ImageFormat _ifcache; private string _b64Cache; /// /// Creates a new image tool from given stream. /// /// Stream to work with. public ImageTool(Stream stream) { if (stream == null) throw new ArgumentNullException(nameof(stream)); if (!stream.CanRead || !stream.CanSeek) throw new ArgumentException("The stream needs to be both readable and seekable.", nameof(stream)); this.SourceStream = stream; this.SourceStream.Seek(0, SeekOrigin.Begin); this._ifcache = 0; this._b64Cache = null; } /// /// Detects the format of this image. /// /// Detected format. public ImageFormat GetFormat() { if (this._ifcache != ImageFormat.Unknown) return this._ifcache; using (var br = new BinaryReader(this.SourceStream, Utilities.UTF8, true)) { var bgn64 = br.ReadUInt64(); if (bgn64 == PNG_MAGIC) return this._ifcache = ImageFormat.Png; bgn64 &= GIF_MASK; if (bgn64 == GIF_MAGIC_1 || bgn64 == GIF_MAGIC_2) return this._ifcache = ImageFormat.Gif; var bgn32 = (uint)(bgn64 & MASK32); if (bgn32 == WEBP_MAGIC_1 && br.ReadUInt32() == WEBP_MAGIC_2) return this._ifcache = ImageFormat.WebP; var bgn16 = (ushort)(bgn32 & MASK16); if (bgn16 == JPEG_MAGIC_1) { this.SourceStream.Seek(-2, SeekOrigin.End); if (br.ReadUInt16() == JPEG_MAGIC_2) return this._ifcache = ImageFormat.Jpeg; } } throw new InvalidDataException("The data within the stream was not valid image data."); } /// /// Converts this image into base64 data format string. /// /// Data-scheme base64 string. public string GetBase64() { if (this._b64Cache != null) return this._b64Cache; var fmt = this.GetFormat(); var sb = new StringBuilder(); sb.Append("data:image/") .Append(fmt.ToString().ToLowerInvariant()) .Append(";base64,"); this.SourceStream.Seek(0, SeekOrigin.Begin); var buff = new byte[this.SourceStream.Length]; var br = 0; while (br < buff.Length) br += this.SourceStream.Read(buff, br, (int)this.SourceStream.Length - br); sb.Append(Convert.ToBase64String(buff)); return this._b64Cache = sb.ToString(); } /// /// Disposes this image tool. /// public void Dispose() { if (this.SourceStream != null) this.SourceStream.Dispose(); } /// /// Utility function to convert an image stream into a base 64 string. /// /// The stream. /// The base 64 string. public static string Base64FromStream(Stream stream) { using var imgtool = new ImageTool(stream); return imgtool.GetBase64(); } /// /// Utility function to convert an optional image stream into an optional base 64 string. /// /// The optional stream. /// The optional base 64 string. public static Optional Base64FromStream(Optional stream) { if (stream.HasValue) { var val = stream.Value; - if (val != null) - { - return Base64FromStream(val); - } - - return null; + return val != null ? (Optional)Base64FromStream(val) : (Optional)null; } return Optional.None; } } /// /// Represents format of an image. /// public enum ImageFormat : int { /// /// The format is unknown /// Unknown = 0, /// /// The format is a jpeg /// Jpeg = 1, /// /// The format is a png /// Png = 2, /// /// The format is a gif /// Gif = 3, /// /// The format is a webp /// WebP = 4, /// /// The format will be automatically detected /// Auto = 5 } }