Browse Source

Move image loading out of constructors and into static methods

pull/143/head
Scott Williams 9 years ago
parent
commit
a3185fd6e7
  1. 2
      ImageSharp.sln
  2. 5
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  3. 15
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  4. 10
      src/ImageSharp/Formats/Gif/GifDecoder.cs
  5. 48
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  6. 4
      src/ImageSharp/Formats/IImageDecoder.cs
  7. 5
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  8. 120
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  9. 10
      src/ImageSharp/Formats/Png/PngDecoder.cs
  10. 39
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  11. 67
      src/ImageSharp/Image.Decode.cs
  12. 148
      src/ImageSharp/Image.FromBytes.cs
  13. 148
      src/ImageSharp/Image.FromFile.cs
  14. 184
      src/ImageSharp/Image.FromStream.cs
  15. 190
      src/ImageSharp/Image.cs
  16. 10
      src/ImageSharp/Image/IImageBase.cs
  17. 10
      src/ImageSharp/Image/IImageBase{TColor}.cs
  18. 41
      src/ImageSharp/Image/ImageBase{TColor}.cs
  19. 296
      src/ImageSharp/Image/Image{TColor}.cs
  20. 44
      src/ImageSharp/MetaData/ImageMetaData.cs
  21. 2
      src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
  22. 2
      tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs
  23. 2
      tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs
  24. 2
      tests/ImageSharp.Benchmarks/Image/DecodeGif.cs
  25. 2
      tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs
  26. 2
      tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs
  27. 2
      tests/ImageSharp.Benchmarks/Image/DecodePng.cs
  28. 2
      tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs
  29. 2
      tests/ImageSharp.Benchmarks/Image/EncodeGif.cs
  30. 2
      tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs
  31. 2
      tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs
  32. 2
      tests/ImageSharp.Benchmarks/Image/EncodePng.cs
  33. 2
      tests/ImageSharp.Benchmarks/Image/MultiImageBenchmarkBase.cs
  34. 2
      tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs
  35. 2
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  36. 6
      tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
  37. 5
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  38. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  39. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs
  40. 341
      tests/ImageSharp.Tests/Image/ImageLoadTests.cs
  41. 10
      tests/ImageSharp.Tests/Image/ImageTests.cs
  42. 6
      tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs
  43. 4
      tests/ImageSharp.Tests/TestFile.cs
  44. 174
      tests/ImageSharp.Tests/TestFormat.cs
  45. 2
      tests/ImageSharp.Tests/TestUtilities/Factories/GenericFactory.cs
  46. 2
      tests/ImageSharp.Tests/TestUtilities/Factories/ImageFactory.cs

2
ImageSharp.sln

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
VisualStudioVersion = 15.0.26228.9
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject

5
src/ImageSharp/Formats/Bmp/BmpDecoder.cs

@ -26,13 +26,12 @@ namespace ImageSharp.Formats
public class BmpDecoder : IImageDecoder
{
/// <inheritdoc/>
public void Decode<TColor>(Image<TColor> image, Stream stream, IDecoderOptions options)
public Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
Guard.NotNull(image, "image");
Guard.NotNull(stream, "stream");
new BmpDecoderCore().Decode(image, stream);
return new BmpDecoderCore().Decode<TColor>(stream);
}
}
}

15
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -48,16 +48,13 @@ namespace ImageSharp.Formats
/// the data to image.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The image, where the data should be set to.
/// Cannot be null (Nothing in Visual Basic).</param>
/// <param name="stream">The stream, where the image should be
/// decoded from. Cannot be null (Nothing in Visual Basic).</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="image"/> is null.</para>
/// <para>- or -</para>
/// <para><paramref name="stream"/> is null.</para>
/// </exception>
public void Decode<TColor>(Image<TColor> image, Stream stream)
/// <returns>The decoded image.</returns>
public Image<TColor> Decode<TColor>(Stream stream)
where TColor : struct, IPixel<TColor>
{
this.currentStream = stream;
@ -110,14 +107,14 @@ namespace ImageSharp.Formats
this.currentStream.Read(palette, 0, colorMapSize);
}
if (this.infoHeader.Width > image.MaxWidth || this.infoHeader.Height > image.MaxHeight)
if (this.infoHeader.Width > Image<TColor>.MaxWidth || this.infoHeader.Height > Image<TColor>.MaxHeight)
{
throw new ArgumentOutOfRangeException(
$"The input bitmap '{this.infoHeader.Width}x{this.infoHeader.Height}' is "
+ $"bigger then the max allowed size '{image.MaxWidth}x{image.MaxHeight}'");
+ $"bigger then the max allowed size '{Image<TColor>.MaxWidth}x{Image<TColor>.MaxHeight}'");
}
image.InitPixels(this.infoHeader.Width, this.infoHeader.Height);
Image<TColor> image = new Image<TColor>(this.infoHeader.Width, this.infoHeader.Height);
using (PixelAccessor<TColor> pixels = image.Lock())
{
@ -151,6 +148,8 @@ namespace ImageSharp.Formats
throw new NotSupportedException("Does not support this kind of bitmap files.");
}
}
return image;
}
catch (IndexOutOfRangeException e)
{

10
src/ImageSharp/Formats/Gif/GifDecoder.cs

@ -14,25 +14,25 @@ namespace ImageSharp.Formats
public class GifDecoder : IImageDecoder
{
/// <inheritdoc/>
public void Decode<TColor>(Image<TColor> image, Stream stream, IDecoderOptions options)
public Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options);
this.Decode(image, stream, gifOptions);
return this.Decode<TColor>(stream, gifOptions);
}
/// <summary>
/// Decodes the image from the specified stream to the <see cref="ImageBase{TColor}"/>.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to decode to.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="options">The options for the decoder.</param>
public void Decode<TColor>(Image<TColor> image, Stream stream, IGifDecoderOptions options)
/// <returns>The image thats been decoded.</returns>
public Image<TColor> Decode<TColor>(Stream stream, IGifDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
new GifDecoderCore<TColor>(options).Decode(image, stream);
return new GifDecoderCore<TColor>(options).Decode(stream);
}
}
}

48
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -27,11 +27,6 @@ namespace ImageSharp.Formats
/// </summary>
private readonly IGifDecoderOptions options;
/// <summary>
/// The image to decode the information to.
/// </summary>
private Image<TColor> decodedImage;
/// <summary>
/// The currently loaded stream.
/// </summary>
@ -67,6 +62,16 @@ namespace ImageSharp.Formats
/// </summary>
private GifGraphicsControlExtension graphicsControlExtension;
/// <summary>
/// The metadata
/// </summary>
private ImageMetaData metaData;
/// <summary>
/// The image to decode the information to.
/// </summary>
private Image<TColor> image;
/// <summary>
/// Initializes a new instance of the <see cref="GifDecoderCore{TColor}"/> class.
/// </summary>
@ -79,13 +84,13 @@ namespace ImageSharp.Formats
/// <summary>
/// Decodes the stream to the image.
/// </summary>
/// <param name="image">The image to decode to.</param>
/// <param name="stream">The stream containing image data. </param>
public void Decode(Image<TColor> image, Stream stream)
/// <returns>The decoded image</returns>
public Image<TColor> Decode(Stream stream)
{
try
{
this.decodedImage = image;
this.metaData = new ImageMetaData();
this.currentStream = stream;
@ -144,6 +149,8 @@ namespace ImageSharp.Formats
ArrayPool<byte>.Shared.Return(this.globalColorTable);
}
}
return this.image;
}
/// <summary>
@ -212,11 +219,13 @@ namespace ImageSharp.Formats
throw new ImageFormatException($"Invalid gif colormap size '{this.logicalScreenDescriptor.GlobalColorTableSize}'");
}
if (this.logicalScreenDescriptor.Width > this.decodedImage.MaxWidth || this.logicalScreenDescriptor.Height > this.decodedImage.MaxHeight)
/* // No point doing this as the max width/height is always int.Max and that always bigger than the max size of a gif which is stored in a short.
if (this.logicalScreenDescriptor.Width > Image<TColor>.MaxWidth || this.logicalScreenDescriptor.Height > Image<TColor>.MaxHeight)
{
throw new ArgumentOutOfRangeException(
$"The input gif '{this.logicalScreenDescriptor.Width}x{this.logicalScreenDescriptor.Height}' is bigger then the max allowed size '{this.decodedImage.MaxWidth}x{this.decodedImage.MaxHeight}'");
$"The input gif '{this.logicalScreenDescriptor.Width}x{this.logicalScreenDescriptor.Height}' is bigger then the max allowed size '{Image<TColor>.MaxWidth}x{Image<TColor>.MaxHeight}'");
}
*/
}
/// <summary>
@ -261,7 +270,7 @@ namespace ImageSharp.Formats
{
this.currentStream.Read(commentsBuffer, 0, length);
string comments = this.options.TextEncoding.GetString(commentsBuffer, 0, length);
this.decodedImage.MetaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments));
this.metaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments));
}
finally
{
@ -343,14 +352,15 @@ namespace ImageSharp.Formats
if (this.previousFrame == null)
{
this.decodedImage.MetaData.Quality = colorTableLength / 3;
this.metaData.Quality = colorTableLength / 3;
// This initializes the image to become fully transparent because the alpha channel is zero.
this.decodedImage.InitPixels(imageWidth, imageHeight);
this.image = new Image<TColor>(imageWidth, imageHeight);
this.image.MetaData.LoadFrom(this.metaData);
this.SetFrameDelay(this.decodedImage.MetaData);
this.SetFrameDelay(this.metaData);
image = this.decodedImage;
image = this.image;
}
else
{
@ -368,7 +378,7 @@ namespace ImageSharp.Formats
this.RestoreToBackground(image);
this.decodedImage.Frames.Add(currentFrame);
this.image.Frames.Add(currentFrame);
}
int i = 0;
@ -441,7 +451,7 @@ namespace ImageSharp.Formats
return;
}
this.previousFrame = currentFrame == null ? this.decodedImage.ToFrame() : currentFrame;
this.previousFrame = currentFrame == null ? this.image.ToFrame() : currentFrame;
if (this.graphicsControlExtension != null &&
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
@ -462,8 +472,8 @@ namespace ImageSharp.Formats
}
// Optimization for when the size of the frame is the same as the image size.
if (this.restoreArea.Value.Width == this.decodedImage.Width &&
this.restoreArea.Value.Height == this.decodedImage.Height)
if (this.restoreArea.Value.Width == this.image.Width &&
this.restoreArea.Value.Height == this.image.Height)
{
using (PixelAccessor<TColor> pixelAccessor = frame.Lock())
{

4
src/ImageSharp/Formats/IImageDecoder.cs

@ -17,10 +17,10 @@ namespace ImageSharp.Formats
/// Decodes the image from the specified stream to the <see cref="ImageBase{TColor}"/>.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to decode to.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="options">The options for the decoder.</param>
void Decode<TColor>(Image<TColor> image, Stream stream, IDecoderOptions options)
/// <returns>The decoded image</returns>
Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>;
}
}

5
src/ImageSharp/Formats/Jpeg/JpegDecoder.cs

@ -14,15 +14,14 @@ namespace ImageSharp.Formats
public class JpegDecoder : IImageDecoder
{
/// <inheritdoc/>
public void Decode<TColor>(Image<TColor> image, Stream stream, IDecoderOptions options)
public Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
Guard.NotNull(image, "image");
Guard.NotNull(stream, "stream");
using (JpegDecoderCore decoder = new JpegDecoderCore(options))
{
decoder.Decode(image, stream, false);
return decoder.Decode<TColor>(stream);
}
}
}

120
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -180,18 +180,30 @@ namespace ImageSharp.Formats
/// the data to image.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The image, where the data should be set to.</param>
/// <param name="stream">The stream, where the image should be.</param>
/// <param name="metadataOnly">Whether to decode metadata only.</param>
public void Decode<TColor>(Image<TColor> image, Stream stream, bool metadataOnly)
/// <returns>The decoded image.</returns>
public Image<TColor> Decode<TColor>(Stream stream)
where TColor : struct, IPixel<TColor>
{
this.ProcessStream(image, stream, metadataOnly);
if (!metadataOnly)
{
this.ProcessBlocksIntoJpegImageChannels<TColor>();
this.ConvertJpegPixelsToImagePixels(image);
}
ImageMetaData metadata = new ImageMetaData();
this.ProcessStream(metadata, stream, false);
this.ProcessBlocksIntoJpegImageChannels<TColor>();
Image<TColor> image = this.ConvertJpegPixelsToImagePixels<TColor>(metadata);
return image;
}
/// <summary>
/// Decodes the image from the specified <see cref="Stream"/> and sets
/// the data to image.
/// </summary>
/// <param name="stream">The stream, where the image should be.</param>
/// <returns>The image metadata.</returns>
public ImageMetaData DecodeMetaData(Stream stream)
{
ImageMetaData metadata = new ImageMetaData();
this.ProcessStream(metadata, stream, true);
return metadata;
}
/// <summary>
@ -276,12 +288,10 @@ namespace ImageSharp.Formats
/// <summary>
/// Read metadata from stream and read the blocks in the scans into <see cref="DecodedBlocks"/>.
/// </summary>
/// <typeparam name="TColor">The pixel type</typeparam>
/// <param name="image">The <see cref="Image{TColor}"/></param>
/// <param name="metadata">The metadata</param>
/// <param name="stream">The stream</param>
/// <param name="metadataOnly">Whether to decode metadata only.</param>
private void ProcessStream<TColor>(Image<TColor> image, Stream stream, bool metadataOnly)
where TColor : struct, IPixel<TColor>
private void ProcessStream(ImageMetaData metadata, Stream stream, bool metadataOnly)
{
this.InputStream = stream;
this.InputProcessor = new InputProcessor(stream, this.Temp);
@ -429,7 +439,7 @@ namespace ImageSharp.Formats
this.ProcessApplicationHeader(remaining);
break;
case JpegConstants.Markers.APP1:
this.ProcessApp1Marker(remaining, image);
this.ProcessApp1Marker(remaining, metadata);
break;
case JpegConstants.Markers.APP14:
this.ProcessApp14Marker(remaining);
@ -496,13 +506,18 @@ namespace ImageSharp.Formats
/// Convert the pixel data in <see cref="YCbCrImage"/> and/or <see cref="JpegPixelArea"/> into pixels of <see cref="Image{TColor}"/>
/// </summary>
/// <typeparam name="TColor">The pixel type</typeparam>
/// <param name="image">The destination image</param>
private void ConvertJpegPixelsToImagePixels<TColor>(Image<TColor> image)
/// <param name="metadata">The metadata for the image.</param>
/// <returns>The decoded image.</returns>
private Image<TColor> ConvertJpegPixelsToImagePixels<TColor>(ImageMetaData metadata)
where TColor : struct, IPixel<TColor>
{
Image<TColor> image = new Image<TColor>(this.ImageWidth, this.ImageHeight);
image.MetaData.LoadFrom(metadata);
if (this.grayImage.IsInitialized)
{
this.ConvertFromGrayScale(this.ImageWidth, this.ImageHeight, image);
this.ConvertFromGrayScale(image);
return image;
}
else if (this.ycbcrImage != null)
{
@ -519,27 +534,27 @@ namespace ImageSharp.Formats
// TODO: YCbCrA?
if (this.adobeTransform == JpegConstants.Adobe.ColorTransformYcck)
{
this.ConvertFromYcck(this.ImageWidth, this.ImageHeight, image);
this.ConvertFromYcck(image);
}
else if (this.adobeTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
// Assume CMYK
this.ConvertFromCmyk(this.ImageWidth, this.ImageHeight, image);
this.ConvertFromCmyk(image);
}
return;
return image;
}
if (this.ComponentCount == 3)
{
if (this.IsRGB())
{
this.ConvertFromRGB(this.ImageWidth, this.ImageHeight, image);
return;
this.ConvertFromRGB(image);
return image;
}
this.ConvertFromYCbCr(this.ImageWidth, this.ImageHeight, image);
return;
this.ConvertFromYCbCr(image);
return image;
}
throw new ImageFormatException("JpegDecoder only supports RGB, CMYK and Grayscale color spaces.");
@ -582,28 +597,24 @@ namespace ImageSharp.Formats
/// Converts the image from the original CMYK image pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <param name="image">The image.</param>
private void ConvertFromCmyk<TColor>(int width, int height, Image<TColor> image)
private void ConvertFromCmyk<TColor>(Image<TColor> image)
where TColor : struct, IPixel<TColor>
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
image.InitPixels(width, height);
using (PixelAccessor<TColor> pixels = image.Lock())
{
Parallel.For(
0,
height,
image.Height,
y =>
{
// TODO: Simplify + optimize + share duplicate code across converter methods
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
for (int x = 0; x < width; x++)
for (int x = 0; x < image.Width; x++)
{
byte cyan = this.ycbcrImage.YChannel.Pixels[yo + x];
byte magenta = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@ -623,24 +634,20 @@ namespace ImageSharp.Formats
/// Converts the image from the original grayscale image pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <param name="image">The image.</param>
private void ConvertFromGrayScale<TColor>(int width, int height, Image<TColor> image)
private void ConvertFromGrayScale<TColor>(Image<TColor> image)
where TColor : struct, IPixel<TColor>
{
image.InitPixels(width, height);
using (PixelAccessor<TColor> pixels = image.Lock())
{
Parallel.For(
0,
height,
image.Height,
image.Configuration.ParallelOptions,
y =>
{
int yoff = this.grayImage.GetRowOffset(y);
for (int x = 0; x < width; x++)
for (int x = 0; x < image.Width; x++)
{
byte rgb = this.grayImage.Pixels[yoff + x];
@ -658,20 +665,17 @@ namespace ImageSharp.Formats
/// Converts the image from the original RBG image pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="width">The image width.</param>
/// <param name="height">The height.</param>
/// <param name="image">The image.</param>
private void ConvertFromRGB<TColor>(int width, int height, Image<TColor> image)
private void ConvertFromRGB<TColor>(Image<TColor> image)
where TColor : struct, IPixel<TColor>
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
image.InitPixels(width, height);
using (PixelAccessor<TColor> pixels = image.Lock())
{
Parallel.For(
0,
height,
image.Height,
image.Configuration.ParallelOptions,
y =>
{
@ -679,7 +683,7 @@ namespace ImageSharp.Formats
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
for (int x = 0; x < width; x++)
for (int x = 0; x < image.Width; x++)
{
byte red = this.ycbcrImage.YChannel.Pixels[yo + x];
byte green = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@ -699,20 +703,16 @@ namespace ImageSharp.Formats
/// Converts the image from the original YCbCr image pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <param name="image">The image.</param>
private void ConvertFromYCbCr<TColor>(int width, int height, Image<TColor> image)
private void ConvertFromYCbCr<TColor>(Image<TColor> image)
where TColor : struct, IPixel<TColor>
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
image.InitPixels(width, height);
using (PixelAccessor<TColor> pixels = image.Lock())
{
Parallel.For(
0,
height,
image.Height,
image.Configuration.ParallelOptions,
y =>
{
@ -720,7 +720,7 @@ namespace ImageSharp.Formats
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
for (int x = 0; x < width; x++)
for (int x = 0; x < image.Width; x++)
{
byte yy = this.ycbcrImage.YChannel.Pixels[yo + x];
byte cb = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@ -740,28 +740,24 @@ namespace ImageSharp.Formats
/// Converts the image from the original YCCK image pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <param name="image">The image.</param>
private void ConvertFromYcck<TColor>(int width, int height, Image<TColor> image)
private void ConvertFromYcck<TColor>(Image<TColor> image)
where TColor : struct, IPixel<TColor>
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
image.InitPixels(width, height);
using (PixelAccessor<TColor> pixels = image.Lock())
{
Parallel.For(
0,
height,
image.Height,
y =>
{
// TODO: Simplify + optimize + share duplicate code across converter methods
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
for (int x = 0; x < width; x++)
for (int x = 0; x < image.Width; x++)
{
byte yy = this.ycbcrImage.YChannel.Pixels[yo + x];
byte cb = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@ -959,11 +955,9 @@ namespace ImageSharp.Formats
/// <summary>
/// Processes the App1 marker retrieving any stored metadata
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="remaining">The remaining bytes in the segment block.</param>
/// <param name="image">The image.</param>
private void ProcessApp1Marker<TColor>(int remaining, Image<TColor> image)
where TColor : struct, IPixel<TColor>
/// <param name="metadata">The image.</param>
private void ProcessApp1Marker(int remaining, ImageMetaData metadata)
{
if (remaining < 6 || this.options.IgnoreMetadata)
{
@ -978,7 +972,7 @@ namespace ImageSharp.Formats
&& profile[5] == '\0')
{
this.isExif = true;
image.MetaData.ExifProfile = new ExifProfile(profile);
metadata.ExifProfile = new ExifProfile(profile);
}
}

10
src/ImageSharp/Formats/Png/PngDecoder.cs

@ -31,25 +31,25 @@ namespace ImageSharp.Formats
public class PngDecoder : IImageDecoder
{
/// <inheritdoc/>
public void Decode<TColor>(Image<TColor> image, Stream stream, IDecoderOptions options)
public Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options);
this.Decode(image, stream, pngOptions);
return this.Decode<TColor>(stream, pngOptions);
}
/// <summary>
/// Decodes the image from the specified stream to the <see cref="ImageBase{TColor}"/>.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to decode to.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="options">The options for the decoder.</param>
public void Decode<TColor>(Image<TColor> image, Stream stream, IPngDecoderOptions options)
/// <returns>The decoded image.</returns>
public Image<TColor> Decode<TColor>(Stream stream, IPngDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
new PngDecoderCore(options).Decode(image, stream);
return new PngDecoderCore(options).Decode<TColor>(stream);
}
}
}

39
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -148,7 +148,6 @@ namespace ImageSharp.Formats
/// Decodes the stream to the image.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The image to decode to.</param>
/// <param name="stream">The stream containing image data. </param>
/// <exception cref="ImageFormatException">
/// Thrown if the stream does not contain and end chunk.
@ -156,10 +155,11 @@ namespace ImageSharp.Formats
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown if the image is larger than the maximum allowable size.
/// </exception>
public void Decode<TColor>(Image<TColor> image, Stream stream)
/// <returns>The decoded image</returns>
public Image<TColor> Decode<TColor>(Stream stream)
where TColor : struct, IPixel<TColor>
{
Image<TColor> currentImage = image;
ImageMetaData metadata = new ImageMetaData();
this.currentStream = stream;
this.currentStream.Skip(8);
@ -177,7 +177,7 @@ namespace ImageSharp.Formats
this.ValidateHeader();
break;
case PngChunkTypes.Physical:
this.ReadPhysicalChunk(currentImage, currentChunk.Data);
this.ReadPhysicalChunk(metadata, currentChunk.Data);
break;
case PngChunkTypes.Data:
dataStream.Write(currentChunk.Data, 0, currentChunk.Length);
@ -186,7 +186,7 @@ namespace ImageSharp.Formats
byte[] pal = new byte[currentChunk.Length];
Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length);
this.palette = pal;
image.MetaData.Quality = pal.Length / 3;
metadata.Quality = pal.Length / 3;
break;
case PngChunkTypes.PaletteAlpha:
byte[] alpha = new byte[currentChunk.Length];
@ -194,7 +194,7 @@ namespace ImageSharp.Formats
this.paletteAlpha = alpha;
break;
case PngChunkTypes.Text:
this.ReadTextChunk(currentImage, currentChunk.Data, currentChunk.Length);
this.ReadTextChunk(metadata, currentChunk.Data, currentChunk.Length);
break;
case PngChunkTypes.End:
this.isEndChunkReached = true;
@ -208,17 +208,20 @@ namespace ImageSharp.Formats
}
}
if (this.header.Width > image.MaxWidth || this.header.Height > image.MaxHeight)
if (this.header.Width > Image<TColor>.MaxWidth || this.header.Height > Image<TColor>.MaxHeight)
{
throw new ArgumentOutOfRangeException($"The input png '{this.header.Width}x{this.header.Height}' is bigger than the max allowed size '{image.MaxWidth}x{image.MaxHeight}'");
throw new ArgumentOutOfRangeException($"The input png '{this.header.Width}x{this.header.Height}' is bigger than the max allowed size '{Image<TColor>.MaxWidth}x{Image<TColor>.MaxHeight}'");
}
image.InitPixels(this.header.Width, this.header.Height);
Image<TColor> image = new Image<TColor>(this.header.Width, this.header.Height);
image.MetaData.LoadFrom(metadata);
using (PixelAccessor<TColor> pixels = image.Lock())
{
this.ReadScanlines(dataStream, pixels);
}
return image;
}
}
@ -270,18 +273,16 @@ namespace ImageSharp.Formats
/// <summary>
/// Reads the data chunk containing physical dimension data.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The image to read to.</param>
/// <param name="metadata">The metadata to read to.</param>
/// <param name="data">The data containing physical data.</param>
private void ReadPhysicalChunk<TColor>(Image<TColor> image, byte[] data)
where TColor : struct, IPixel<TColor>
private void ReadPhysicalChunk(ImageMetaData metadata, byte[] data)
{
data.ReverseBytes(0, 4);
data.ReverseBytes(4, 4);
// 39.3700787 = inches in a meter.
image.MetaData.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d;
image.MetaData.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d;
metadata.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d;
metadata.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d;
}
/// <summary>
@ -768,12 +769,10 @@ namespace ImageSharp.Formats
/// <summary>
/// Reads a text chunk containing image properties from the data.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The image to decode to.</param>
/// <param name="metadata">The metadata to decode to.</param>
/// <param name="data">The <see cref="T:byte[]"/> containing data.</param>
/// <param name="length">The maximum length to read.</param>
private void ReadTextChunk<TColor>(Image<TColor> image, byte[] data, int length)
where TColor : struct, IPixel<TColor>
private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length)
{
if (this.options.IgnoreMetadata)
{
@ -794,7 +793,7 @@ namespace ImageSharp.Formats
string name = this.options.TextEncoding.GetString(data, 0, zeroIndex);
string value = this.options.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1);
image.MetaData.Properties.Add(new ImageProperty(name, value));
metadata.Properties.Add(new ImageProperty(name, value));
}
/// <summary>

67
src/ImageSharp/Image.Decode.cs

@ -0,0 +1,67 @@
// <copyright file="Image.Decode.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Formats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
{
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">the configuration.</param>
/// <param name="img">The decoded image</param>
/// <returns>
/// [true] if can successfull decode the image otherwise [false].
/// </returns>
private static bool Decode<TColor>(Stream stream, IDecoderOptions options, Configuration config, out Image<TColor> img)
where TColor : struct, IPixel<TColor>
{
img = null;
int maxHeaderSize = config.MaxHeaderSize;
if (maxHeaderSize <= 0)
{
return false;
}
IImageFormat format;
byte[] header = ArrayPool<byte>.Shared.Rent(maxHeaderSize);
try
{
long startPosition = stream.Position;
stream.Read(header, 0, maxHeaderSize);
stream.Position = startPosition;
format = config.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header));
}
finally
{
ArrayPool<byte>.Shared.Return(header);
}
if (format == null)
{
return false;
}
img = format.Decoder.Decode<TColor>(stream, options);
img.CurrentImageFormat = format;
return true;
}
}
}

148
src/ImageSharp/Image.FromBytes.cs

@ -0,0 +1,148 @@
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Formats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
{
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] stream)
{
return Load(stream, null, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] stream, IDecoderOptions options)
{
return Load(stream, options, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="config">The config for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] stream, Configuration config)
{
return Load(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">The configuration options.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] stream, IDecoderOptions options, Configuration config)
{
using (MemoryStream ms = new MemoryStream(stream))
{
return Load(ms, options, config);
}
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(byte[] stream)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, null, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(byte[] stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, options, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="config">The config for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(byte[] stream, Configuration config)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">The configuration options.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(byte[] stream, IDecoderOptions options, Configuration config)
where TColor : struct, IPixel<TColor>
{
using (MemoryStream ms = new MemoryStream(stream))
{
return Load<TColor>(ms, options, config);
}
}
}
}

148
src/ImageSharp/Image.FromFile.cs

@ -0,0 +1,148 @@
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Formats;
#if !NETSTANDARD1_1
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
{
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string stream)
{
return Load(stream, null, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string stream, IDecoderOptions options)
{
return Load(stream, options, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="config">The config for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string stream, Configuration config)
{
return Load(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">The configuration options.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string stream, IDecoderOptions options, Configuration config)
{
return new Image(Image.Load<Color>(stream, options, config));
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(string stream)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, null, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(string stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, options, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="config">The config for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(string stream, Configuration config)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">The configuration options.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(string stream, IDecoderOptions options, Configuration config)
where TColor : struct, IPixel<TColor>
{
config = config ?? Configuration.Default;
using (Stream s = config.FileSystem.OpenRead(stream))
{
return Load<TColor>(s, options, config);
}
}
}
#endif
}

184
src/ImageSharp/Image.FromStream.cs

@ -0,0 +1,184 @@
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Formats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
{
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream)
{
return Load(stream, null, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, IDecoderOptions options)
{
return Load(stream, options, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="config">The config for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, Configuration config)
{
return Load(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">The configuration options.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, IDecoderOptions options, Configuration config)
{
return new Image(Load<Color>(stream, options, config));
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(Stream stream)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, null, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, options, null);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="config">The config for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(Stream stream, Configuration config)
where TColor : struct, IPixel<TColor>
{
return Load<TColor>(stream, null, config);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">The configuration options.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image<TColor> Load<TColor>(Stream stream, IDecoderOptions options, Configuration config)
where TColor : struct, IPixel<TColor>
{
config = config ?? Configuration.Default;
if (!config.ImageFormats.Any())
{
throw new InvalidOperationException("No image formats have been configured.");
}
if (!stream.CanRead)
{
throw new NotSupportedException("Cannot read from the stream.");
}
if (stream.CanSeek)
{
if (Decode(stream, options, config, out Image<TColor> img))
{
return img;
}
}
else
{
// We want to be able to load images from things like HttpContext.Request.Body
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0;
if (Decode(ms, options, config, out Image<TColor> img))
{
return img;
}
}
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Image cannot be loaded. Available formats:");
foreach (IImageFormat format in config.ImageFormats)
{
stringBuilder.AppendLine("-" + format);
}
throw new NotSupportedException(stringBuilder.ToString());
}
}
}

190
src/ImageSharp/Image.cs

@ -5,6 +5,7 @@
namespace ImageSharp
{
using System;
using System.Diagnostics;
using System.IO;
@ -15,7 +16,7 @@ namespace ImageSharp
/// packed into a single unsigned integer value.
/// </summary>
[DebuggerDisplay("Image: {Width}x{Height}")]
public sealed class Image : Image<Color>
public sealed partial class Image : Image<Color>
{
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class
@ -26,190 +27,19 @@ namespace ImageSharp
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
public Image(int width, int height, Configuration configuration = null)
public Image(int width, int height, Configuration configuration)
: base(width, height, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream)
: base(stream, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream, IDecoderOptions options)
: base(stream, options, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream, Configuration configuration)
: base(stream, null, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream, IDecoderOptions options, Configuration configuration)
: base(stream, options, configuration)
{
}
#if !NETSTANDARD1_1
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="filePath">
/// A file path to read image information.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath)
: base(filePath, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="filePath">
/// A file path to read image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath, IDecoderOptions options)
: base(filePath, options, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="filePath">
/// A file path to read image information.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath, Configuration configuration)
: base(filePath, null, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="filePath">
/// A file path to read image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath, IDecoderOptions options, Configuration configuration)
: base(filePath, options, configuration)
{
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes)
: base(bytes, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes, IDecoderOptions options)
: base(bytes, options, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes, Configuration configuration)
: base(bytes, null, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// Initializes a new instance of the <see cref="Image"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes, IDecoderOptions options, Configuration configuration)
: base(bytes, options, configuration)
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public Image(int width, int height)
: this(width, height, null)
{
}
@ -219,7 +49,7 @@ namespace ImageSharp
/// </summary>
/// <param name="other">The other image, where the clone should be made from.</param>
/// <exception cref="System.ArgumentNullException"><paramref name="other"/> is null.</exception>
public Image(Image other)
internal Image(Image<Color> other)
: base(other)
{
}

10
src/ImageSharp/Image/IImageBase.cs

@ -15,16 +15,6 @@ namespace ImageSharp
/// </summary>
Rectangle Bounds { get; }
/// <summary>
/// Gets or sets the maximum allowable width in pixels.
/// </summary>
int MaxWidth { get; set; }
/// <summary>
/// Gets or sets the maximum allowable height in pixels.
/// </summary>
int MaxHeight { get; set; }
/// <summary>
/// Gets the width in pixels.
/// </summary>

10
src/ImageSharp/Image/IImageBase{TColor}.cs

@ -21,16 +21,6 @@ namespace ImageSharp
/// </summary>
TColor[] Pixels { get; }
/// <summary>
/// Sets the size of the pixel array of the image to the given width and height.
/// </summary>
/// <param name="width">The new width of the image. Must be greater than zero.</param>
/// <param name="height">The new height of the image. Must be greater than zero.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
/// </exception>
void InitPixels(int width, int height);
/// <summary>
/// Locks the image providing access to the pixels.
/// <remarks>

41
src/ImageSharp/Image/ImageBase{TColor}.cs

@ -18,6 +18,16 @@ namespace ImageSharp
public abstract class ImageBase<TColor> : IImageBase<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Gets or sets the maximum allowable width in pixels.
/// </summary>
public const int MaxWidth = int.MaxValue;
/// <summary>
/// Gets or sets the maximum allowable height in pixels.
/// </summary>
public const int MaxHeight = int.MaxValue;
/// <summary>
/// The image pixels
/// </summary>
@ -40,7 +50,7 @@ namespace ImageSharp
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
protected ImageBase(Configuration configuration = null)
protected ImageBase(Configuration configuration)
{
this.Configuration = configuration ?? Configuration.Default;
}
@ -56,10 +66,15 @@ namespace ImageSharp
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
/// </exception>
protected ImageBase(int width, int height, Configuration configuration = null)
protected ImageBase(int width, int height, Configuration configuration)
: this(configuration)
{
this.Configuration = configuration ?? Configuration.Default;
this.InitPixels(width, height);
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
this.Width = width;
this.Height = height;
this.RentPixels();
this.ClearPixels();
}
@ -73,6 +88,7 @@ namespace ImageSharp
/// Thrown if the given <see cref="ImageBase{TColor}"/> is null.
/// </exception>
protected ImageBase(ImageBase<TColor> other)
: this(other.Configuration)
{
Guard.NotNull(other, nameof(other), "Other image cannot be null.");
@ -90,12 +106,6 @@ namespace ImageSharp
}
}
/// <inheritdoc/>
public int MaxWidth { get; set; } = int.MaxValue;
/// <inheritdoc/>
public int MaxHeight { get; set; } = int.MaxValue;
/// <inheritdoc/>
public TColor[] Pixels => this.pixelBuffer;
@ -139,17 +149,6 @@ namespace ImageSharp
GC.SuppressFinalize(this);
}
/// <inheritdoc/>
public void InitPixels(int width, int height)
{
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
this.Width = width;
this.Height = height;
this.RentPixels();
}
/// <inheritdoc/>
public PixelAccessor<TColor> Lock()
{

296
src/ImageSharp/Image/Image{TColor}.cs

@ -35,7 +35,7 @@ namespace ImageSharp
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
public Image(int width, int height, Configuration configuration = null)
public Image(int width, int height, Configuration configuration)
: base(width, height, configuration)
{
if (!this.Configuration.ImageFormats.Any())
@ -43,203 +43,19 @@ namespace ImageSharp
throw new InvalidOperationException("No image formats have been configured.");
}
this.MetaData = new ImageMetaData();
this.CurrentImageFormat = this.Configuration.ImageFormats.First();
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream)
: this(stream, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream, IDecoderOptions options)
: this(stream, options, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream, Configuration configuration)
: this(stream, null, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream, IDecoderOptions options, Configuration configuration)
: base(configuration)
{
Guard.NotNull(stream, nameof(stream));
this.Load(stream, options);
}
#if !NETSTANDARD1_1
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="filePath">
/// The file containing image information.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath)
: this(filePath, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="filePath">
/// The file containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath, IDecoderOptions options)
: this(filePath, options, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="filePath">
/// The file containing image information.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath, Configuration configuration)
: this(filePath, null, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="filePath">
/// The file containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="filePath"/> is null.</exception>
public Image(string filePath, IDecoderOptions options, Configuration configuration)
: base(configuration)
{
Guard.NotNull(filePath, nameof(filePath));
using (Stream fs = this.Configuration.FileSystem.OpenRead(filePath))
{
this.Load(fs, options);
}
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes)
: this(bytes, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes, IDecoderOptions options)
: this(bytes, options, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes, Configuration configuration)
: this(bytes, null, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class.
/// Initializes a new instance of the <see cref="Image{TColor}"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="bytes">
/// The byte array containing image information.
/// </param>
/// <param name="options">
/// The options for the decoder.
/// </param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="bytes"/> is null.</exception>
public Image(byte[] bytes, IDecoderOptions options, Configuration configuration)
: base(configuration)
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public Image(int width, int height)
: this(width, height, null)
{
Guard.NotNull(bytes, nameof(bytes));
using (MemoryStream stream = new MemoryStream(bytes, false))
{
this.Load(stream, options);
}
}
/// <summary>
@ -271,7 +87,6 @@ namespace ImageSharp
public Image(ImageBase<TColor> other)
: base(other)
{
this.CopyProperties(other);
}
/// <summary>
@ -588,103 +403,8 @@ namespace ImageSharp
/// </param>
private void CopyProperties(IImage other)
{
base.CopyProperties(other);
this.CurrentImageFormat = other.CurrentImageFormat;
this.MetaData = new ImageMetaData(other.MetaData);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
private void Load(Stream stream, IDecoderOptions options)
{
if (!this.Configuration.ImageFormats.Any())
{
throw new InvalidOperationException("No image formats have been configured.");
}
if (!stream.CanRead)
{
throw new NotSupportedException("Cannot read from the stream.");
}
if (stream.CanSeek)
{
if (this.Decode(stream, options))
{
return;
}
}
else
{
// We want to be able to load images from things like HttpContext.Request.Body
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0;
if (this.Decode(ms, options))
{
return;
}
}
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Image cannot be loaded. Available formats:");
foreach (IImageFormat format in this.Configuration.ImageFormats)
{
stringBuilder.AppendLine("-" + format);
}
throw new NotSupportedException(stringBuilder.ToString());
}
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="options">The options for the decoder.</param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
private bool Decode(Stream stream, IDecoderOptions options)
{
int maxHeaderSize = this.Configuration.MaxHeaderSize;
if (maxHeaderSize <= 0)
{
return false;
}
IImageFormat format;
byte[] header = ArrayPool<byte>.Shared.Rent(maxHeaderSize);
try
{
long startPosition = stream.Position;
stream.Read(header, 0, maxHeaderSize);
stream.Position = startPosition;
format = this.Configuration.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header));
}
finally
{
ArrayPool<byte>.Shared.Return(header);
}
if (format == null)
{
return false;
}
format.Decoder.Decode(this, stream, options);
this.CurrentImageFormat = format;
return true;
}
}
}

44
src/ImageSharp/MetaData/ImageMetaData.cs

@ -5,6 +5,7 @@
namespace ImageSharp
{
using System;
using System.Collections.Generic;
/// <summary>
@ -47,21 +48,7 @@ namespace ImageSharp
{
DebugGuard.NotNull(other, nameof(other));
this.HorizontalResolution = other.HorizontalResolution;
this.VerticalResolution = other.VerticalResolution;
this.Quality = other.Quality;
this.FrameDelay = other.FrameDelay;
this.RepeatCount = other.RepeatCount;
foreach (ImageProperty property in other.Properties)
{
this.Properties.Add(new ImageProperty(property));
}
if (other.ExifProfile != null)
{
this.ExifProfile = new ExifProfile(other.ExifProfile);
}
this.LoadFrom(other);
}
/// <summary>
@ -143,5 +130,32 @@ namespace ImageSharp
{
this.ExifProfile?.Sync(this);
}
/// <summary>
/// Sets the current metadata values based on a previous metadata object.
/// </summary>
/// <param name="other">Meta data object to copy values from.</param>
internal void LoadFrom(ImageMetaData other)
{
this.HorizontalResolution = other.HorizontalResolution;
this.VerticalResolution = other.VerticalResolution;
this.Quality = other.Quality;
this.FrameDelay = other.FrameDelay;
this.RepeatCount = other.RepeatCount;
foreach (ImageProperty property in other.Properties)
{
this.Properties.Add(new ImageProperty(property));
}
if (other.ExifProfile != null)
{
this.ExifProfile = new ExifProfile(other.ExifProfile);
}
else
{
this.ExifProfile = null;
}
}
}
}

2
src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs

@ -137,7 +137,7 @@ namespace ImageSharp
using (MemoryStream memStream = new MemoryStream(this.data, this.thumbnailOffset, this.thumbnailLength))
{
return new Image<TColor>(memStream);
return Image.Load<TColor>(memStream);
}
}

2
tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs

@ -43,7 +43,7 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.bmpBytes))
{
using (CoreImage image = new CoreImage(memoryStream))
using (CoreImage image = CoreImage.Load(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}

2
tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs

@ -31,7 +31,7 @@ namespace ImageSharp.Benchmarks.Image
private Size LoadPng(MemoryStream stream)
{
using (Image image = new Image(stream))
using (Image image = Image.Load(stream))
{
return new Size(image.Width, image.Height);
}

2
tests/ImageSharp.Benchmarks/Image/DecodeGif.cs

@ -43,7 +43,7 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.gifBytes))
{
using (CoreImage image = new CoreImage(memoryStream))
using (CoreImage image = CoreImage.Load(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}

2
tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs

@ -43,7 +43,7 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes))
{
using (CoreImage image = new CoreImage(memoryStream))
using (CoreImage image = CoreImage.Load(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}

2
tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs

@ -25,7 +25,7 @@ namespace ImageSharp.Benchmarks.Image
public void DecodeJpegImageSharp()
{
this.ForEachStream(
ms => new ImageSharp.Image(ms)
ms => ImageSharp.Image.Load(ms)
);
}

2
tests/ImageSharp.Benchmarks/Image/DecodePng.cs

@ -43,7 +43,7 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream(this.pngBytes))
{
using (CoreImage image = new CoreImage(memoryStream))
using (CoreImage image = CoreImage.Load(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}

2
tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs

@ -25,7 +25,7 @@ namespace ImageSharp.Benchmarks.Image
if (this.bmpStream == null)
{
this.bmpStream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp");
this.bmpCore = new CoreImage(this.bmpStream);
this.bmpCore = CoreImage.Load(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream);
}

2
tests/ImageSharp.Benchmarks/Image/EncodeGif.cs

@ -25,7 +25,7 @@ namespace ImageSharp.Benchmarks.Image
if (this.bmpStream == null)
{
this.bmpStream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp");
this.bmpCore = new CoreImage(this.bmpStream);
this.bmpCore = CoreImage.Load(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream);
}

2
tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs

@ -34,7 +34,7 @@ namespace ImageSharp.Benchmarks.Image
? "../ImageSharp.Tests/TestImages/Formats/Jpg/baseline/jpeg420exif.jpg"
: "../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp";
this.bmpStream = File.OpenRead(path);
this.bmpCore = new Image(this.bmpStream);
this.bmpCore = Image.Load(this.bmpStream);
this.bmpStream.Position = 0;
}
}

2
tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs

@ -25,7 +25,7 @@ namespace ImageSharp.Benchmarks.Image
if (this.bmpStream == null)
{
this.bmpStream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp");
this.bmpCore = new CoreImage(this.bmpStream);
this.bmpCore = CoreImage.Load(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream);
}

2
tests/ImageSharp.Benchmarks/Image/EncodePng.cs

@ -38,7 +38,7 @@ namespace ImageSharp.Benchmarks.Image
? "../ImageSharp.Tests/TestImages/Formats/Jpg/baseline/jpeg420exif.jpg"
: "../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp";
this.bmpStream = File.OpenRead(path);
this.bmpCore = new CoreImage(this.bmpStream);
this.bmpCore = CoreImage.Load(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream);
}

2
tests/ImageSharp.Benchmarks/Image/MultiImageBenchmarkBase.cs

@ -154,7 +154,7 @@ namespace ImageSharp.Benchmarks.Image
using (MemoryStream ms1 = new MemoryStream(bytes))
{
this.FileNamesToImageSharpImages[fn] = new Image(ms1);
this.FileNamesToImageSharpImages[fn] = Image.Load(ms1);
}

2
tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs

@ -23,7 +23,7 @@ namespace ImageSharp.Benchmarks
{
using (FileStream stream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp"))
{
this.image = new CoreImage(stream);
this.image = CoreImage.Load(stream);
}
}
}

2
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -150,7 +150,7 @@ namespace ImageSharp.Tests
serialized = memoryStream.ToArray();
}
using (Image image2 = new Image(serialized))
using (Image image2 = Image.Load(serialized))
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{
image2.Save(output);

6
tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs

@ -29,7 +29,7 @@ namespace ImageSharp.Tests
input.Save(memStream, new GifFormat(), options);
memStream.Position = 0;
using (Image output = new Image(memStream))
using (Image output = Image.Load(memStream))
{
Assert.Equal(1, output.MetaData.Properties.Count);
Assert.Equal("Comments", output.MetaData.Properties[0].Name);
@ -56,7 +56,7 @@ namespace ImageSharp.Tests
input.SaveAsGif(memStream, options);
memStream.Position = 0;
using (Image output = new Image(memStream))
using (Image output = Image.Load(memStream))
{
Assert.Equal(0, output.MetaData.Properties.Count);
}
@ -77,7 +77,7 @@ namespace ImageSharp.Tests
input.Save(memStream, new GifFormat());
memStream.Position = 0;
using (Image output = new Image(memStream))
using (Image output = Image.Load(memStream))
{
Assert.Equal(1, output.MetaData.Properties.Count);
Assert.Equal("Comments", output.MetaData.Properties[0].Name);

5
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -89,11 +89,10 @@ namespace ImageSharp.Tests
{
image.Save(ms, new JpegEncoder());
ms.Seek(0, SeekOrigin.Begin);
Image<TColor> mirror = provider.Factory.CreateImage(1, 1);
using (JpegDecoderCore decoder = new JpegDecoderCore(null))
{
decoder.Decode(mirror, ms, true);
Image<TColor> mirror = decoder.Decode<TColor>(ms);
Assert.Equal(decoder.ImageWidth, image.Width);
Assert.Equal(decoder.ImageHeight, image.Height);

4
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -88,7 +88,7 @@ namespace ImageSharp.Tests
input.Save(memStream, new JpegFormat(), options);
memStream.Position = 0;
using (Image output = new Image(memStream))
using (Image output = Image.Load(memStream))
{
Assert.NotNull(output.MetaData.ExifProfile);
}
@ -113,7 +113,7 @@ namespace ImageSharp.Tests
input.SaveAsJpeg(memStream, options);
memStream.Position = 0;
using (Image output = new Image(memStream))
using (Image output = Image.Load(memStream))
{
Assert.Null(output.MetaData.ExifProfile);
}

2
tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs

@ -50,7 +50,7 @@ namespace ImageSharp.Tests
ExecutionCount,
() =>
{
Image img = new Image(bytes);
Image img = Image.Load(bytes);
},
// ReSharper disable once ExplicitCallerInfoArgument
$"Decode {fileName}");

341
tests/ImageSharp.Tests/Image/ImageLoadTests.cs

@ -0,0 +1,341 @@
// <copyright file="PixelAccessorTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System;
using System.IO;
using System.Linq;
using ImageSharp.Formats;
using ImageSharp.IO;
using Moq;
using Xunit;
/// <summary>
/// Tests the <see cref="Image"/> class.
/// </summary>
public class ImageLoadTests : IDisposable
{
private readonly Mock<IFileSystem> fileSystem;
private readonly IDecoderOptions decoderOptions;
private Image<Color> returnImage;
private Mock<IImageDecoder> localDecoder;
private Mock<IImageFormat> localFormat;
private readonly string FilePath;
public Configuration LocalConfiguration { get; private set; }
public byte[] Marker { get; private set; }
public MemoryStream DataStream { get; private set; }
public byte[] DecodedData { get; private set; }
public ImageLoadTests()
{
this.returnImage = new Image<Color>(1, 1);
this.localDecoder = new Mock<IImageDecoder>();
this.localFormat = new Mock<IImageFormat>();
this.localFormat.Setup(x => x.Decoder).Returns(this.localDecoder.Object);
this.localFormat.Setup(x => x.Encoder).Returns(new Mock<IImageEncoder>().Object);
this.localFormat.Setup(x => x.MimeType).Returns("img/test");
this.localFormat.Setup(x => x.Extension).Returns("png");
this.localFormat.Setup(x => x.HeaderSize).Returns(1);
this.localFormat.Setup(x => x.IsSupportedFileFormat(It.IsAny<byte[]>())).Returns(true);
this.localFormat.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" });
this.localDecoder.Setup(x => x.Decode<Color>(It.IsAny<Stream>(), It.IsAny<IDecoderOptions>()))
.Callback<Stream, IDecoderOptions>((s, o) => {
using (var ms = new MemoryStream())
{
s.CopyTo(ms);
this.DecodedData = ms.ToArray();
}
})
.Returns(this.returnImage);
this.fileSystem = new Mock<IFileSystem>();
this.LocalConfiguration = new Configuration(this.localFormat.Object)
{
FileSystem = this.fileSystem.Object
};
TestFormat.RegisterGloablTestFormat();
this.Marker = Guid.NewGuid().ToByteArray();
this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker);
this.decoderOptions = new Mock<IDecoderOptions>().Object;
this.FilePath = Guid.NewGuid().ToString();
this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream);
}
[Fact]
public void LoadFromStream()
{
Image img = Image.Load(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null);
}
[Fact]
public void LoadFromStreamWithType()
{
Image<Color> img = Image.Load<Color>(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null);
}
[Fact]
public void LoadFromStreamWithOptions()
{
Image img = Image.Load(this.DataStream, this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions);
}
[Fact]
public void LoadFromStreamWithTypeAndOptions()
{
Image<Color> img = Image.Load<Color>(this.DataStream, this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions);
}
[Fact]
public void LoadFromStreamWithConfig()
{
Stream stream = new MemoryStream();
Image img = Image.Load(stream, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(stream, null));
}
[Fact]
public void LoadFromStreamWithTypeAndConfig()
{
Stream stream = new MemoryStream();
Image<Color> img = Image.Load<Color>(stream, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(stream, null));
}
[Fact]
public void LoadFromStreamWithConfigAndOptions()
{
Stream stream = new MemoryStream();
Image img = Image.Load(stream, this.decoderOptions, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(stream, this.decoderOptions));
}
[Fact]
public void LoadFromStreamWithTypeAndConfigAndOptions()
{
Stream stream = new MemoryStream();
Image<Color> img = Image.Load<Color>(stream, this.decoderOptions, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(stream, this.decoderOptions));
}
[Fact]
public void LoadFromBytes()
{
Image img = Image.Load(this.DataStream.ToArray());
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null);
}
[Fact]
public void LoadFromBytesWithType()
{
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray());
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null);
}
[Fact]
public void LoadFromBytesWithOptions()
{
Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions);
}
[Fact]
public void LoadFromBytesWithTypeAndOptions()
{
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions);
}
[Fact]
public void LoadFromBytesWithConfig()
{
Image img = Image.Load(this.DataStream.ToArray(), this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), null));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndConfig()
{
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), null));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithConfigAndOptions()
{
Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), this.decoderOptions));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndConfigAndOptions()
{
Image<Color> img = Image.Load<Color>(this.DataStream.ToArray(), this.decoderOptions, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(It.IsAny<Stream>(), this.decoderOptions));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromFile()
{
Image img = Image.Load(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null);
}
[Fact]
public void LoadFromFileWithType()
{
Image<Color> img = Image.Load<Color>(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null);
}
[Fact]
public void LoadFromFileWithOptions()
{
Image img = Image.Load(this.DataStream, this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions);
}
[Fact]
public void LoadFromFileWithTypeAndOptions()
{
Image<Color> img = Image.Load<Color>(this.DataStream, this.decoderOptions);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Color>(), img);
Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions);
}
[Fact]
public void LoadFromFileWithConfig()
{
Image img = Image.Load(this.FilePath, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, null));
}
[Fact]
public void LoadFromFileWithTypeAndConfig()
{
Image<Color> img = Image.Load<Color>(this.FilePath, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, null));
}
[Fact]
public void LoadFromFileWithConfigAndOptions()
{
Image img = Image.Load(this.FilePath, this.decoderOptions, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, this.decoderOptions));
}
[Fact]
public void LoadFromFileWithTypeAndConfigAndOptions()
{
Image<Color> img = Image.Load<Color>(FilePath, this.decoderOptions, this.LocalConfiguration);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
Assert.Equal(this.localFormat.Object, img.CurrentImageFormat);
this.localDecoder.Verify(x => x.Decode<Color>(this.DataStream, this.decoderOptions));
}
public void Dispose()
{
// clean up the global object;
this.returnImage?.Dispose();
}
}
}

10
tests/ImageSharp.Tests/Image/ImageTests.cs

@ -21,11 +21,11 @@ namespace ImageSharp.Tests
{
Assert.Throws<ArgumentNullException>(() =>
{
new Image((byte[])null);
Image.Load((byte[])null);
});
TestFile file = TestFile.Create(TestImages.Bmp.Car);
using (Image image = new Image(file.Bytes))
using (Image image = Image.Load(file.Bytes))
{
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
@ -36,7 +36,7 @@ namespace ImageSharp.Tests
public void ConstructorFileSystem()
{
TestFile file = TestFile.Create(TestImages.Bmp.Car);
using (Image image = new Image(file.FilePath))
using (Image image = Image.Load(file.FilePath))
{
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
@ -49,7 +49,7 @@ namespace ImageSharp.Tests
System.IO.FileNotFoundException ex = Assert.Throws<System.IO.FileNotFoundException>(
() =>
{
new Image(Guid.NewGuid().ToString());
Image.Load(Guid.NewGuid().ToString());
});
}
@ -59,7 +59,7 @@ namespace ImageSharp.Tests
ArgumentNullException ex = Assert.Throws<ArgumentNullException>(
() =>
{
new Image((string) null);
Image.Load((string) null);
});
}

6
tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs

@ -73,7 +73,7 @@ namespace ImageSharp.Tests
image.SaveAsJpeg(memStream);
memStream.Position = 0;
image = new Image(memStream);
image = Image.Load(memStream);
profile = image.MetaData.ExifProfile;
Assert.NotNull(profile);
@ -91,7 +91,7 @@ namespace ImageSharp.Tests
image.SaveAsJpeg(memStream);
memStream.Position = 0;
image = new Image(memStream);
image = Image.Load(memStream);
profile = image.MetaData.ExifProfile;
Assert.NotNull(profile);
@ -286,7 +286,7 @@ namespace ImageSharp.Tests
image.Dispose();
memStream.Position = 0;
return new Image(memStream);
return Image.Load(memStream);
}
}

4
tests/ImageSharp.Tests/TestFile.cs

@ -46,7 +46,7 @@ namespace ImageSharp.Tests
this.file = file;
this.Bytes = File.ReadAllBytes(file);
this.image = new Image(this.Bytes);
this.image = Image.Load(this.Bytes);
}
/// <summary>
@ -139,7 +139,7 @@ namespace ImageSharp.Tests
/// </returns>
public Image CreateImage(IDecoderOptions options)
{
return new Image(this.Bytes, options);
return Image.Load(this.Bytes, options);
}
/// <summary>

174
tests/ImageSharp.Tests/TestFormat.cs

@ -0,0 +1,174 @@
// <copyright file="TestImage.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using ImageSharp.Formats;
using Xunit;
/// <summary>
/// A test image file.
/// </summary>
public class TestFormat : ImageSharp.Formats.IImageFormat
{
public static TestFormat GlobalTestFormat { get; } = new TestFormat();
public static void RegisterGloablTestFormat()
{
Configuration.Default.AddImageFormat(GlobalTestFormat);
}
public TestFormat()
{
this.Encoder = new TestEncoder(this); ;
this.Decoder = new TestDecoder(this); ;
}
public List<DecodeOperation> DecodeCalls { get; } = new List<DecodeOperation>();
public IImageEncoder Encoder { get; }
public IImageDecoder Decoder { get; }
private byte[] header = Guid.NewGuid().ToByteArray();
public MemoryStream CreateStream(byte[] marker = null)
{
MemoryStream ms = new MemoryStream();
byte[] data = this.header;
ms.Write(data, 0, data.Length);
if (marker != null)
{
ms.Write(marker, 0, marker.Length);
}
ms.Position = 0;
return ms;
}
Dictionary<Type, object> _sampleImages = new Dictionary<Type, object>();
public void VerifyDecodeCall(byte[] marker, IDecoderOptions options)
{
DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, options)).ToArray();
Assert.True(discovered.Any(), "No calls to decode on this formate with the proveded options happend");
foreach (DecodeOperation d in discovered) {
this.DecodeCalls.Remove(d);
}
}
public Image<TColor> Sample<TColor>()
where TColor : struct, IPixel<TColor>
{
lock (this._sampleImages)
{
if (!this._sampleImages.ContainsKey(typeof(TColor)))
{
this._sampleImages.Add(typeof(TColor), new Image<TColor>(1, 1));
}
return (Image<TColor>)this._sampleImages[typeof(TColor)];
}
}
public string MimeType => "img/test";
public string Extension => "test_ext";
public IEnumerable<string> SupportedExtensions => new[] { "test_ext" };
public int HeaderSize => this.header.Length;
public bool IsSupportedFileFormat(byte[] header)
{
if (header.Length < this.header.Length)
{
return false;
}
for (int i = 0; i < this.header.Length; i++)
{
if (header[i] != this.header[i])
{
return false;
}
}
return true;
}
public struct DecodeOperation
{
public byte[] marker;
public IDecoderOptions options;
public bool IsMatch(byte[] testMarker, IDecoderOptions testOptions)
{
if(this.options != testOptions)
{
return false;
}
if (testMarker.Length != this.marker.Length)
{
return false;
}
for (int i = 0; i < this.marker.Length; i++)
{
if (testMarker[i] != this.marker[i])
{
return false;
}
}
return true;
}
}
public class TestDecoder : ImageSharp.Formats.IImageDecoder
{
private TestFormat testFormat;
public TestDecoder(TestFormat testFormat)
{
this.testFormat = testFormat;
}
public Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options) where TColor : struct, IPixel<TColor>
{
var ms = new MemoryStream();
stream.CopyTo(ms);
var marker = ms.ToArray().Skip(this.testFormat.header.Length).ToArray();
this.testFormat.DecodeCalls.Add(new DecodeOperation
{
marker = marker,
options = options
});
// TODO record this happend so we an verify it.
return this.testFormat.Sample<TColor>();
}
}
public class TestEncoder : ImageSharp.Formats.IImageEncoder
{
private TestFormat testFormat;
public TestEncoder(TestFormat testFormat)
{
this.testFormat = testFormat;
}
public void Encode<TColor>(Image<TColor> image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel<TColor>
{
// TODO record this happend so we an verify it.
}
}
}
}

2
tests/ImageSharp.Tests/TestUtilities/Factories/GenericFactory.cs

@ -21,7 +21,7 @@ namespace ImageSharp.Tests
public virtual Image<TColor> CreateImage(byte[] bytes)
{
return new Image<TColor>(bytes);
return Image.Load<TColor>(bytes);
}
public virtual Image<TColor> CreateImage(Image<TColor> other)

2
tests/ImageSharp.Tests/TestUtilities/Factories/ImageFactory.cs

@ -7,7 +7,7 @@ namespace ImageSharp.Tests
{
public class ImageFactory : GenericFactory<Color>
{
public override Image<Color> CreateImage(byte[] bytes) => new Image(bytes);
public override Image<Color> CreateImage(byte[] bytes) => Image.Load(bytes);
public override Image<Color> CreateImage(int width, int height) => new Image(width, height);

Loading…
Cancel
Save