Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/ImageSharp/Advanced/AdvancedImageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ public static class AdvancedImageExtensions
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image.</param>
/// <returns>Returns the configuration.</returns>
public static Configuration GetConfiguration<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
public static Configuration GetConfiguration(this Image source)
=> GetConfiguration((IConfigurable)source);

/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions src/ImageSharp/Formats/Bmp/BmpDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
return new BmpDecoderCore(configuration, this).Decode<TPixel>(stream);
}

public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);

/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream)
{
Expand Down
2 changes: 2 additions & 0 deletions src/ImageSharp/Formats/Gif/GifDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,7 @@ public IImageInfo Identify(Configuration configuration, Stream stream)
var decoder = new GifDecoderCore(configuration, this);
return decoder.Identify(stream);
}

public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
}
}
2 changes: 2 additions & 0 deletions src/ImageSharp/Formats/IImageDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ public interface IImageDecoder
/// <returns>The decoded image</returns>
Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>;

Image Decode(Configuration configuration, Stream stream);
}
}
2 changes: 2 additions & 0 deletions src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,7 @@ public IImageInfo Identify(Configuration configuration, Stream stream)
return decoder.Identify(stream);
}
}

public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will become Rgb24 yes?

Copy link
Member Author

@antonfirsov antonfirsov May 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will delegate into a method of JpegDecoderCore which can then decide what pixel type to use in the resulting Image<T>. For grayscale jpegs we can return Image<Gray8> (if worth).

Designing the code sharing between the specialized (generic) and the "native pixel type" (non-generic) methods is an interesting question. Probably even more challenging for PngDecoder.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Thinking about it shouldn’t be too bad for png either.

}
}
4 changes: 4 additions & 0 deletions src/ImageSharp/Formats/PixelTypeInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System.Runtime.CompilerServices;

namespace SixLabors.ImageSharp.Formats
{
/// <summary>
Expand All @@ -21,5 +23,7 @@ internal PixelTypeInfo(int bitsPerPixel)
/// Gets color depth, in number of bits per pixel.
/// </summary>
public int BitsPerPixel { get; }

internal static PixelTypeInfo Create<TPixel>() => new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
}
}
2 changes: 2 additions & 0 deletions src/ImageSharp/Formats/Png/PngDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,7 @@ public IImageInfo Identify(Configuration configuration, Stream stream)
var decoder = new PngDecoderCore(configuration, this);
return decoder.Identify(stream);
}

public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
}
}
14 changes: 13 additions & 1 deletion src/ImageSharp/Image.Decode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the decoding of new images.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// Creates an <see cref="Image{TPixel}"/> instance backed by an uninitialized memory buffer.
Expand Down Expand Up @@ -102,6 +102,18 @@ private static (Image<TPixel> img, IImageFormat format) Decode<TPixel>(Stream st
Image<TPixel> img = decoder.Decode<TPixel>(config, stream);
return (img, format);
}

private static (Image img, IImageFormat format) Decode(Stream stream, Configuration config)
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
if (decoder is null)
{
return (null, null);
}

Image img = decoder.Decode(config, stream);
return (img, format);
}

/// <summary>
/// Reads the raw image information from the specified stream.
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Image.FromBytes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from a byte array.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// By reading the header on the provided byte array this calculates the images format.
Expand Down
32 changes: 14 additions & 18 deletions src/ImageSharp/Image.FromFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from a given file.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// By reading the header on the provided file this calculates the images mime type.
Expand Down Expand Up @@ -46,7 +46,7 @@ public static IImageFormat DetectFormat(Configuration config, string filePath)
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path) => Load<Rgba32>(path);
public static Image Load(string path) => Load(path);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
Expand All @@ -57,7 +57,7 @@ public static IImageFormat DetectFormat(Configuration config, string filePath)
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path, out IImageFormat format) => Load<Rgba32>(path, out format);
public static Image Load(string path, out IImageFormat format) => Load(path, out format);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
Expand All @@ -68,19 +68,7 @@ public static IImageFormat DetectFormat(Configuration config, string filePath)
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path) => Load<Rgba32>(config, path);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path, out IImageFormat format) => Load<Rgba32>(config, path, out format);
public static Image Load(Configuration config, string path) => Load(config, path);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
Expand All @@ -92,7 +80,7 @@ public static IImageFormat DetectFormat(Configuration config, string filePath)
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path, IImageDecoder decoder) => Load<Rgba32>(config, path, decoder);
public static Image Load(Configuration config, string path, IImageDecoder decoder) => Load(config, path, decoder);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
Expand All @@ -103,7 +91,7 @@ public static IImageFormat DetectFormat(Configuration config, string filePath)
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path, IImageDecoder decoder) => Load<Rgba32>(path, decoder);
public static Image Load(string path, IImageDecoder decoder) => Load(path, decoder);

/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
Expand Down Expand Up @@ -174,6 +162,14 @@ public static Image<TPixel> Load<TPixel>(Configuration config, string path, out
return Load<TPixel>(config, stream, out format);
}
}

public static Image Load(Configuration config, string path, out IImageFormat format)
{
using (Stream stream = config.FileSystem.OpenRead(path))
{
return Load(config, stream, out format);
}
}

/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
Expand Down
43 changes: 27 additions & 16 deletions src/ImageSharp/Image.FromStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from a given stream.
/// </content>
public static partial class Image
public abstract partial class Image
{
/// <summary>
/// By reading the header on the provided stream this calculates the images mime type.
Expand Down Expand Up @@ -62,15 +62,15 @@ public static IImageInfo Identify(Configuration config, Stream stream)
/// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, out IImageFormat format) => Load<Rgba32>(stream, out format);
public static Image Load(Stream stream, out IImageFormat format) => Load(stream, out format);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream) => Load<Rgba32>(stream);
public static Image Load(Stream stream) => Load(stream);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
Expand All @@ -79,7 +79,7 @@ public static IImageInfo Identify(Configuration config, Stream stream)
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, IImageDecoder decoder) => Load<Rgba32>(stream, decoder);
public static Image Load(Stream stream, IImageDecoder decoder) => Load(stream, decoder);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
Expand All @@ -88,18 +88,7 @@ public static IImageInfo Identify(Configuration config, Stream stream)
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Configuration config, Stream stream) => Load<Rgba32>(config, stream);

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="format">the mime type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Configuration config, Stream stream, out IImageFormat format)
=> Load<Rgba32>(config, stream, out format);
public static Image Load(Configuration config, Stream stream) => Load(config, stream);

/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
Expand Down Expand Up @@ -193,6 +182,28 @@ public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream, ou

throw new NotSupportedException(sb.ToString());
}
private 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<IImageFormat, IImageDecoder> val in config.ImageFormatsManager.ImageDecoders)
{
sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
}

throw new NotSupportedException(sb.ToString());
}

private static T WithSeekableStream<T>(Configuration config, Stream stream, Func<Stream, T> action)
{
Expand Down
85 changes: 85 additions & 0 deletions src/ImageSharp/Image.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System.IO;

using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp
{
internal interface IImageVisitor
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this.

{
void Visit<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>;
}

public abstract partial class Image : IImage, IConfigurable
{
protected readonly Configuration configuration;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private


/// <inheritdoc/>
public PixelTypeInfo PixelType { get; }

/// <inheritdoc />
public abstract int Width { get; }

/// <inheritdoc />
public abstract int Height { get; }

/// <inheritdoc/>
public ImageMetadata Metadata { get; }

/// <summary>
/// Gets the pixel buffer.
/// </summary>
Configuration IConfigurable.Configuration => this.configuration;

protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata metadata)
{
this.configuration = configuration ?? Configuration.Default;
this.PixelType = pixelType;
this.Metadata = metadata ?? new ImageMetadata();
}

public abstract void Dispose();

internal abstract void AcceptVisitor(IImageVisitor visitor);

/// <summary>
/// Saves the image to the given stream using the given image encoder.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream or encoder is null.</exception>
public void Save(Stream stream, IImageEncoder encoder)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoder, nameof(encoder));

EncodeVisitor visitor = new EncodeVisitor(encoder, stream);
this.AcceptVisitor(visitor);
}

class EncodeVisitor : IImageVisitor
{
private readonly IImageEncoder encoder;

private readonly Stream stream;

public EncodeVisitor(IImageEncoder encoder, Stream stream)
{
this.encoder = encoder;
this.stream = stream;
}

public void Visit<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
this.encoder.Encode(image, this.stream);
}
}
}
}
9 changes: 3 additions & 6 deletions src/ImageSharp/ImageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ public static partial class ImageExtensions
/// <param name="source">The source image.</param>
/// <param name="filePath">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, string filePath)
where TPixel : struct, IPixel<TPixel>
public static void Save(this Image source, string filePath)
{
Guard.NotNullOrWhiteSpace(filePath, nameof(filePath));

Expand Down Expand Up @@ -67,8 +66,7 @@ public static void Save<TPixel>(this Image<TPixel> source, string filePath)
/// <param name="filePath">The file path to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="ArgumentNullException">Thrown if the encoder is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, string filePath, IImageEncoder encoder)
where TPixel : struct, IPixel<TPixel>
public static void Save(this Image source, string filePath, IImageEncoder encoder)
{
Guard.NotNull(encoder, nameof(encoder));
using (Stream fs = source.GetConfiguration().FileSystem.Create(filePath))
Expand All @@ -85,8 +83,7 @@ public static void Save<TPixel>(this Image<TPixel> source, string filePath, IIma
/// <param name="stream">The stream to save the image to.</param>
/// <param name="format">The format to save the image in.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, Stream stream, IImageFormat format)
where TPixel : struct, IPixel<TPixel>
public static void Save(this Image source, Stream stream, IImageFormat format)
{
Guard.NotNull(format, nameof(format));
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/ImageSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

<ItemGroup>
<AdditionalFiles Include="..\..\standards\stylecop.json" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-rc.114" PrivateAssets="All" />
<!--<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-rc.114" PrivateAssets="All" />-->
<PackageReference Include="SixLabors.Core" Version="1.0.0-dev000101" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />
</ItemGroup>
Expand Down
Loading