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
}
}