// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Collections.Generic; using System.IO; using System.Text; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp { /// /// Adds static methods allowing the creation of new image from a given stream. /// public abstract partial class Image { /// /// By reading the header on the provided stream this calculates the images format type. /// /// The image stream to read the header from. /// Thrown if the stream is not readable. /// The format type or null if none found. public static IImageFormat DetectFormat(Stream stream) => DetectFormat(Configuration.Default, stream); /// /// By reading the header on the provided stream this calculates the images format type. /// /// The configuration. /// The image stream to read the header from. /// Thrown if the stream is not readable. /// The format type or null if none found. public static IImageFormat DetectFormat(Configuration config, Stream stream) => WithSeekableStream(config, stream, s => InternalDetectFormat(s, config)); /// /// By reading the header on the provided stream this reads the raw image information. /// /// The image stream to read the header from. /// Thrown if the stream is not readable. /// /// The or null if suitable info detector not found. /// public static IImageInfo Identify(Stream stream) => Identify(stream, out IImageFormat _); /// /// By reading the header on the provided stream this reads the raw image information. /// /// The image stream to read the header from. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// /// The or null if suitable info detector not found. /// public static IImageInfo Identify(Stream stream, out IImageFormat format) => Identify(Configuration.Default, stream, out format); /// /// Reads the raw image information from the specified stream without fully decoding it. /// /// The configuration. /// The image stream to read the information from. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// /// The or null if suitable info detector is not found. /// public static IImageInfo Identify(Configuration config, Stream stream, out IImageFormat format) { (IImageInfo info, IImageFormat format) data = WithSeekableStream(config, stream, s => InternalIdentity(s, config ?? Configuration.Default)); format = data.format; return data.info; } /// /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// /// The stream containing image information. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The . public static Image Load(Stream stream, out IImageFormat format) => Load(Configuration.Default, stream, out format); /// /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// /// The stream containing image information. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The . public static Image Load(Stream stream) => Load(Configuration.Default, stream); /// /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// /// The stream containing image information. /// The decoder. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The . public static Image Load(Stream stream, IImageDecoder decoder) => Load(Configuration.Default, stream, decoder); /// /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// /// The config for the decoder. /// The stream containing image information. /// The decoder. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// A new .> public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) => WithSeekableStream(config, stream, s => decoder.Decode(config, s)); /// /// Decode a new instance of the class from the given stream. /// /// The config for the decoder. /// The stream containing image information. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// A new .> public static Image Load(Configuration config, Stream stream) => Load(config, stream, out _); /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> public static Image Load(Stream stream) where TPixel : struct, IPixel => Load(null, stream); /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> public static Image Load(Stream stream, out IImageFormat format) where TPixel : struct, IPixel => Load(null, stream, out format); /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. /// The decoder. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> public static Image Load(Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel => WithSeekableStream(Configuration.Default, stream, s => decoder.Decode(Configuration.Default, s)); /// /// Create a new instance of the class from the given stream. /// /// The Configuration. /// The stream containing image information. /// The decoder. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel => WithSeekableStream(config, stream, s => decoder.Decode(config, s)); /// /// Create a new instance of the class from the given stream. /// /// The configuration options. /// The stream containing image information. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> public static Image Load(Configuration config, Stream stream) where TPixel : struct, IPixel => Load(config, stream, out IImageFormat _); /// /// Create a new instance of the class from the given stream. /// /// The configuration options. /// The stream containing image information. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> public static Image Load(Configuration config, Stream stream, out IImageFormat format) where TPixel : struct, IPixel { config = config ?? Configuration.Default; (Image img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode(s, config)); format = data.format; if (data.img != null) { return data.img; } var sb = new StringBuilder(); sb.AppendLine("Image cannot be loaded. Available decoders:"); foreach (KeyValuePair val in config.ImageFormatsManager.ImageDecoders) { sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } throw new UnknownImageFormatException(sb.ToString()); } /// /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// /// The configuration options. /// The stream containing image information. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// A new . public static Image Load(Configuration config, Stream stream, out IImageFormat format) { config = config ?? Configuration.Default; (Image img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode(s, config)); format = data.format; if (data.img != null) { return data.img; } var sb = new StringBuilder(); sb.AppendLine("Image cannot be loaded. Available decoders:"); foreach (KeyValuePair val in config.ImageFormatsManager.ImageDecoders) { sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } throw new UnknownImageFormatException(sb.ToString()); } private static T WithSeekableStream(Configuration config, Stream stream, Func action) { if (!stream.CanRead) { throw new NotSupportedException("Cannot read from the stream."); } if (stream.CanSeek) { if (config.ReadOrigin == ReadOrigin.Begin) { stream.Position = 0; } return action(stream); } // We want to be able to load images from things like HttpContext.Request.Body using (var memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); memoryStream.Position = 0; return action(memoryStream); } } } }