From a3185fd6e787f9d0479de3d38dec04bd773cab85 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Mon, 20 Mar 2017 17:27:01 +0000 Subject: [PATCH 01/14] Move image loading out of constructors and into static methods --- ImageSharp.sln | 2 +- src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 5 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 15 +- src/ImageSharp/Formats/Gif/GifDecoder.cs | 10 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 48 ++- src/ImageSharp/Formats/IImageDecoder.cs | 4 +- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 5 +- .../Formats/Jpeg/JpegDecoderCore.cs | 120 +++--- src/ImageSharp/Formats/Png/PngDecoder.cs | 10 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 39 +- src/ImageSharp/Image.Decode.cs | 67 ++++ src/ImageSharp/Image.FromBytes.cs | 148 ++++++++ src/ImageSharp/Image.FromFile.cs | 148 ++++++++ src/ImageSharp/Image.FromStream.cs | 184 ++++++++++ src/ImageSharp/Image.cs | 190 +--------- src/ImageSharp/Image/IImageBase.cs | 10 - src/ImageSharp/Image/IImageBase{TColor}.cs | 10 - src/ImageSharp/Image/ImageBase{TColor}.cs | 41 +-- src/ImageSharp/Image/Image{TColor}.cs | 296 +-------------- src/ImageSharp/MetaData/ImageMetaData.cs | 44 ++- .../MetaData/Profiles/Exif/ExifProfile.cs | 2 +- .../ImageSharp.Benchmarks/Image/DecodeBmp.cs | 2 +- .../Image/DecodeFilteredPng.cs | 2 +- .../ImageSharp.Benchmarks/Image/DecodeGif.cs | 2 +- .../ImageSharp.Benchmarks/Image/DecodeJpeg.cs | 2 +- .../Image/DecodeJpegMultiple.cs | 2 +- .../ImageSharp.Benchmarks/Image/DecodePng.cs | 2 +- .../ImageSharp.Benchmarks/Image/EncodeBmp.cs | 2 +- .../ImageSharp.Benchmarks/Image/EncodeGif.cs | 2 +- .../Image/EncodeIndexedPng.cs | 2 +- .../ImageSharp.Benchmarks/Image/EncodeJpeg.cs | 2 +- .../ImageSharp.Benchmarks/Image/EncodePng.cs | 2 +- .../Image/MultiImageBenchmarkBase.cs | 2 +- .../Samplers/DetectEdges.cs | 2 +- .../Formats/GeneralFormatTests.cs | 2 +- .../Formats/Gif/GifEncoderTests.cs | 6 +- .../Formats/Jpg/JpegDecoderTests.cs | 5 +- .../Formats/Jpg/JpegEncoderTests.cs | 4 +- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 2 +- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 341 ++++++++++++++++++ tests/ImageSharp.Tests/Image/ImageTests.cs | 10 +- .../Profiles/Exif/ExifProfileTests.cs | 6 +- tests/ImageSharp.Tests/TestFile.cs | 4 +- tests/ImageSharp.Tests/TestFormat.cs | 174 +++++++++ .../TestUtilities/Factories/GenericFactory.cs | 2 +- .../TestUtilities/Factories/ImageFactory.cs | 2 +- 46 files changed, 1293 insertions(+), 689 deletions(-) create mode 100644 src/ImageSharp/Image.Decode.cs create mode 100644 src/ImageSharp/Image.FromBytes.cs create mode 100644 src/ImageSharp/Image.FromFile.cs create mode 100644 src/ImageSharp/Image.FromStream.cs create mode 100644 tests/ImageSharp.Tests/Image/ImageLoadTests.cs create mode 100644 tests/ImageSharp.Tests/TestFormat.cs diff --git a/ImageSharp.sln b/ImageSharp.sln index 9c729493b2..628fa70153 100644 --- a/ImageSharp.sln +++ b/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 diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 9f490a3a9b..2bc1c8cc30 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -26,13 +26,12 @@ namespace ImageSharp.Formats public class BmpDecoder : IImageDecoder { /// - public void Decode(Image image, Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options) where TColor : struct, IPixel { - Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); - new BmpDecoderCore().Decode(image, stream); + return new BmpDecoderCore().Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index a75031ea19..adfa4b6ace 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -48,16 +48,13 @@ namespace ImageSharp.Formats /// the data to image. /// /// The pixel format. - /// The image, where the data should be set to. - /// Cannot be null (Nothing in Visual Basic). /// The stream, where the image should be /// decoded from. Cannot be null (Nothing in Visual Basic). /// - /// is null. - /// - or - /// is null. /// - public void Decode(Image image, Stream stream) + /// The decoded image. + public Image Decode(Stream stream) where TColor : struct, IPixel { 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.MaxWidth || this.infoHeader.Height > Image.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.MaxWidth}x{Image.MaxHeight}'"); } - image.InitPixels(this.infoHeader.Width, this.infoHeader.Height); + Image image = new Image(this.infoHeader.Width, this.infoHeader.Height); using (PixelAccessor 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) { diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index b1e8ba928d..16b036e684 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -14,25 +14,25 @@ namespace ImageSharp.Formats public class GifDecoder : IImageDecoder { /// - public void Decode(Image image, Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options) where TColor : struct, IPixel { IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options); - this.Decode(image, stream, gifOptions); + return this.Decode(stream, gifOptions); } /// /// Decodes the image from the specified stream to the . /// /// The pixel format. - /// The to decode to. /// The containing image data. /// The options for the decoder. - public void Decode(Image image, Stream stream, IGifDecoderOptions options) + /// The image thats been decoded. + public Image Decode(Stream stream, IGifDecoderOptions options) where TColor : struct, IPixel { - new GifDecoderCore(options).Decode(image, stream); + return new GifDecoderCore(options).Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index ab1edc2c76..22a26345fe 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -27,11 +27,6 @@ namespace ImageSharp.Formats /// private readonly IGifDecoderOptions options; - /// - /// The image to decode the information to. - /// - private Image decodedImage; - /// /// The currently loaded stream. /// @@ -67,6 +62,16 @@ namespace ImageSharp.Formats /// private GifGraphicsControlExtension graphicsControlExtension; + /// + /// The metadata + /// + private ImageMetaData metaData; + + /// + /// The image to decode the information to. + /// + private Image image; + /// /// Initializes a new instance of the class. /// @@ -79,13 +84,13 @@ namespace ImageSharp.Formats /// /// Decodes the stream to the image. /// - /// The image to decode to. /// The stream containing image data. - public void Decode(Image image, Stream stream) + /// The decoded image + public Image Decode(Stream stream) { try { - this.decodedImage = image; + this.metaData = new ImageMetaData(); this.currentStream = stream; @@ -144,6 +149,8 @@ namespace ImageSharp.Formats ArrayPool.Shared.Return(this.globalColorTable); } } + + return this.image; } /// @@ -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.MaxWidth || this.logicalScreenDescriptor.Height > Image.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.MaxWidth}x{Image.MaxHeight}'"); } + */ } /// @@ -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(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 pixelAccessor = frame.Lock()) { diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index df98870ddd..c4a9cf8c3c 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -17,10 +17,10 @@ namespace ImageSharp.Formats /// Decodes the image from the specified stream to the . /// /// The pixel format. - /// The to decode to. /// The containing image data. /// The options for the decoder. - void Decode(Image image, Stream stream, IDecoderOptions options) + /// The decoded image + Image Decode(Stream stream, IDecoderOptions options) where TColor : struct, IPixel; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index eeb371d1e7..3a91f8010e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -14,15 +14,14 @@ namespace ImageSharp.Formats public class JpegDecoder : IImageDecoder { /// - public void Decode(Image image, Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options) where TColor : struct, IPixel { - Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); using (JpegDecoderCore decoder = new JpegDecoderCore(options)) { - decoder.Decode(image, stream, false); + return decoder.Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index f1b85fa0bf..fa656e71e8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -180,18 +180,30 @@ namespace ImageSharp.Formats /// the data to image. /// /// The pixel format. - /// The image, where the data should be set to. /// The stream, where the image should be. - /// Whether to decode metadata only. - public void Decode(Image image, Stream stream, bool metadataOnly) + /// The decoded image. + public Image Decode(Stream stream) where TColor : struct, IPixel { - this.ProcessStream(image, stream, metadataOnly); - if (!metadataOnly) - { - this.ProcessBlocksIntoJpegImageChannels(); - this.ConvertJpegPixelsToImagePixels(image); - } + ImageMetaData metadata = new ImageMetaData(); + this.ProcessStream(metadata, stream, false); + this.ProcessBlocksIntoJpegImageChannels(); + Image image = this.ConvertJpegPixelsToImagePixels(metadata); + + return image; + } + + /// + /// Decodes the image from the specified and sets + /// the data to image. + /// + /// The stream, where the image should be. + /// The image metadata. + public ImageMetaData DecodeMetaData(Stream stream) + { + ImageMetaData metadata = new ImageMetaData(); + this.ProcessStream(metadata, stream, true); + return metadata; } /// @@ -276,12 +288,10 @@ namespace ImageSharp.Formats /// /// Read metadata from stream and read the blocks in the scans into . /// - /// The pixel type - /// The + /// The metadata /// The stream /// Whether to decode metadata only. - private void ProcessStream(Image image, Stream stream, bool metadataOnly) - where TColor : struct, IPixel + 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 and/or into pixels of /// /// The pixel type - /// The destination image - private void ConvertJpegPixelsToImagePixels(Image image) + /// The metadata for the image. + /// The decoded image. + private Image ConvertJpegPixelsToImagePixels(ImageMetaData metadata) where TColor : struct, IPixel { + Image image = new Image(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. /// /// The pixel format. - /// The image width. - /// The image height. /// The image. - private void ConvertFromCmyk(int width, int height, Image image) + private void ConvertFromCmyk(Image image) where TColor : struct, IPixel { int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; - image.InitPixels(width, height); - using (PixelAccessor 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. /// /// The pixel format. - /// The image width. - /// The image height. /// The image. - private void ConvertFromGrayScale(int width, int height, Image image) + private void ConvertFromGrayScale(Image image) where TColor : struct, IPixel { - image.InitPixels(width, height); - using (PixelAccessor 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. /// /// The pixel format. - /// The image width. - /// The height. /// The image. - private void ConvertFromRGB(int width, int height, Image image) + private void ConvertFromRGB(Image image) where TColor : struct, IPixel { int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; - image.InitPixels(width, height); using (PixelAccessor 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. /// /// The pixel format. - /// The image width. - /// The image height. /// The image. - private void ConvertFromYCbCr(int width, int height, Image image) + private void ConvertFromYCbCr(Image image) where TColor : struct, IPixel { int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; - image.InitPixels(width, height); - using (PixelAccessor 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. /// /// The pixel format. - /// The image width. - /// The image height. /// The image. - private void ConvertFromYcck(int width, int height, Image image) + private void ConvertFromYcck(Image image) where TColor : struct, IPixel { int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; - image.InitPixels(width, height); - using (PixelAccessor 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 /// /// Processes the App1 marker retrieving any stored metadata /// - /// The pixel format. /// The remaining bytes in the segment block. - /// The image. - private void ProcessApp1Marker(int remaining, Image image) - where TColor : struct, IPixel + /// The image. + 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); } } diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index d527e1654d..5b7d97fc70 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -31,25 +31,25 @@ namespace ImageSharp.Formats public class PngDecoder : IImageDecoder { /// - public void Decode(Image image, Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options) where TColor : struct, IPixel { IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); - this.Decode(image, stream, pngOptions); + return this.Decode(stream, pngOptions); } /// /// Decodes the image from the specified stream to the . /// /// The pixel format. - /// The to decode to. /// The containing image data. /// The options for the decoder. - public void Decode(Image image, Stream stream, IPngDecoderOptions options) + /// The decoded image. + public Image Decode(Stream stream, IPngDecoderOptions options) where TColor : struct, IPixel { - new PngDecoderCore(options).Decode(image, stream); + return new PngDecoderCore(options).Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index fd03ed39b8..dadf7ab7d6 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -148,7 +148,6 @@ namespace ImageSharp.Formats /// Decodes the stream to the image. /// /// The pixel format. - /// The image to decode to. /// The stream containing image data. /// /// Thrown if the stream does not contain and end chunk. @@ -156,10 +155,11 @@ namespace ImageSharp.Formats /// /// Thrown if the image is larger than the maximum allowable size. /// - public void Decode(Image image, Stream stream) + /// The decoded image + public Image Decode(Stream stream) where TColor : struct, IPixel { - Image 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.MaxWidth || this.header.Height > Image.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.MaxWidth}x{Image.MaxHeight}'"); } - image.InitPixels(this.header.Width, this.header.Height); + Image image = new Image(this.header.Width, this.header.Height); + image.MetaData.LoadFrom(metadata); using (PixelAccessor pixels = image.Lock()) { this.ReadScanlines(dataStream, pixels); } + + return image; } } @@ -270,18 +273,16 @@ namespace ImageSharp.Formats /// /// Reads the data chunk containing physical dimension data. /// - /// The pixel format. - /// The image to read to. + /// The metadata to read to. /// The data containing physical data. - private void ReadPhysicalChunk(Image image, byte[] data) - where TColor : struct, IPixel + 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; } /// @@ -768,12 +769,10 @@ namespace ImageSharp.Formats /// /// Reads a text chunk containing image properties from the data. /// - /// The pixel format. - /// The image to decode to. + /// The metadata to decode to. /// The containing data. /// The maximum length to read. - private void ReadTextChunk(Image image, byte[] data, int length) - where TColor : struct, IPixel + 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)); } /// diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs new file mode 100644 index 0000000000..f31f2c0a55 --- /dev/null +++ b/src/ImageSharp/Image.Decode.cs @@ -0,0 +1,67 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Buffers; + using System.Diagnostics; + using System.IO; + using System.Linq; + using System.Text; + using Formats; + + /// + /// 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. + /// + public sealed partial class Image + { + /// + /// Decodes the image stream to the current image. + /// + /// The pixel format. + /// The stream. + /// The options for the decoder. + /// the configuration. + /// The decoded image + /// + /// [true] if can successfull decode the image otherwise [false]. + /// + private static bool Decode(Stream stream, IDecoderOptions options, Configuration config, out Image img) + where TColor : struct, IPixel + { + img = null; + int maxHeaderSize = config.MaxHeaderSize; + if (maxHeaderSize <= 0) + { + return false; + } + + IImageFormat format; + byte[] header = ArrayPool.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.Shared.Return(header); + } + + if (format == null) + { + return false; + } + + img = format.Decoder.Decode(stream, options); + img.CurrentImageFormat = format; + return true; + } + } +} diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs new file mode 100644 index 0000000000..e68a57fe70 --- /dev/null +++ b/src/ImageSharp/Image.FromBytes.cs @@ -0,0 +1,148 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Buffers; + using System.Diagnostics; + using System.IO; + using System.Linq; + using System.Text; + using Formats; + + /// + /// 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. + /// + public sealed partial class Image + { + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream) + { + return Load(stream, null, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream, IDecoderOptions options) + { + return Load(stream, options, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The config for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream, Configuration config) + { + return Load(stream, null, config); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The options for the decoder. + /// The configuration options. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream, IDecoderOptions options, Configuration config) + { + using (MemoryStream ms = new MemoryStream(stream)) + { + return Load(ms, options, config); + } + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream) + where TColor : struct, IPixel + { + return Load(stream, null, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream, IDecoderOptions options) + where TColor : struct, IPixel + { + return Load(stream, options, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The config for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream, Configuration config) + where TColor : struct, IPixel + { + return Load(stream, null, config); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The options for the decoder. + /// The configuration options. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] stream, IDecoderOptions options, Configuration config) + where TColor : struct, IPixel + { + using (MemoryStream ms = new MemoryStream(stream)) + { + return Load(ms, options, config); + } + } + } +} diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs new file mode 100644 index 0000000000..b0adb1f96f --- /dev/null +++ b/src/ImageSharp/Image.FromFile.cs @@ -0,0 +1,148 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Buffers; + using System.Diagnostics; + using System.IO; + using System.Linq; + using System.Text; + using Formats; + +#if !NETSTANDARD1_1 + /// + /// 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. + /// + public sealed partial class Image + { + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream) + { + return Load(stream, null, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream, IDecoderOptions options) + { + return Load(stream, options, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The config for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream, Configuration config) + { + return Load(stream, null, config); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The options for the decoder. + /// The configuration options. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream, IDecoderOptions options, Configuration config) + { + return new Image(Image.Load(stream, options, config)); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream) + where TColor : struct, IPixel + { + return Load(stream, null, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream, IDecoderOptions options) + where TColor : struct, IPixel + { + return Load(stream, options, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The config for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream, Configuration config) + where TColor : struct, IPixel + { + return Load(stream, null, config); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The options for the decoder. + /// The configuration options. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string stream, IDecoderOptions options, Configuration config) + where TColor : struct, IPixel + { + config = config ?? Configuration.Default; + using (Stream s = config.FileSystem.OpenRead(stream)) + { + return Load(s, options, config); + } + } + } +#endif +} diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs new file mode 100644 index 0000000000..36309db5b5 --- /dev/null +++ b/src/ImageSharp/Image.FromStream.cs @@ -0,0 +1,184 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Buffers; + using System.Diagnostics; + using System.IO; + using System.Linq; + using System.Text; + using Formats; + + /// + /// 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. + /// + public sealed partial class Image + { + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream) + { + return Load(stream, null, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IDecoderOptions options) + { + return Load(stream, options, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The config for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, Configuration config) + { + return Load(stream, null, config); + } + + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The options for the decoder. + /// The configuration options. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IDecoderOptions options, Configuration config) + { + return new Image(Load(stream, options, config)); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream) + where TColor : struct, IPixel + { + return Load(stream, null, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IDecoderOptions options) + where TColor : struct, IPixel + { + return Load(stream, options, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The config for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, Configuration config) + where TColor : struct, IPixel + { + return Load(stream, null, config); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The options for the decoder. + /// The configuration options. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IDecoderOptions options, Configuration config) + where TColor : struct, IPixel + { + 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 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 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()); + } + } +} diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index 8bfd8ee1a3..352107021a 100644 --- a/src/ImageSharp/Image.cs +++ b/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. /// [DebuggerDisplay("Image: {Width}x{Height}")] - public sealed class Image : Image + public sealed partial class Image : Image { /// /// Initializes a new instance of the class @@ -26,190 +27,19 @@ namespace ImageSharp /// /// The configuration providing initialization code which allows extending the library. /// - public Image(int width, int height, Configuration configuration = null) + public Image(int width, int height, Configuration configuration) : base(width, height, configuration) { } /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// Thrown if the is null. - public Image(Stream stream) - : base(stream, null, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// - /// The options for the decoder. - /// - /// Thrown if the is null. - public Image(Stream stream, IDecoderOptions options) - : base(stream, options, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(Stream stream, Configuration configuration) - : base(stream, null, configuration) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// - /// The options for the decoder. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(Stream stream, IDecoderOptions options, Configuration configuration) - : base(stream, options, configuration) - { - } - -#if !NETSTANDARD1_1 - /// - /// Initializes a new instance of the class. - /// - /// - /// A file path to read image information. - /// - /// Thrown if the is null. - public Image(string filePath) - : base(filePath, null, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// A file path to read image information. - /// - /// - /// The options for the decoder. - /// - /// Thrown if the is null. - public Image(string filePath, IDecoderOptions options) - : base(filePath, options, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// A file path to read image information. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(string filePath, Configuration configuration) - : base(filePath, null, configuration) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// A file path to read image information. - /// - /// - /// The options for the decoder. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(string filePath, IDecoderOptions options, Configuration configuration) - : base(filePath, options, configuration) - { - } -#endif - - /// - /// Initializes a new instance of the class. - /// - /// - /// The byte array containing image information. - /// - /// Thrown if the is null. - public Image(byte[] bytes) - : base(bytes, null, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The byte array containing image information. - /// - /// - /// The options for the decoder. - /// - /// Thrown if the is null. - public Image(byte[] bytes, IDecoderOptions options) - : base(bytes, options, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The byte array containing image information. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(byte[] bytes, Configuration configuration) - : base(bytes, null, configuration) - { - } - - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class + /// with the height and the width of the image. /// - /// - /// The byte array containing image information. - /// - /// - /// The options for the decoder. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(byte[] bytes, IDecoderOptions options, Configuration configuration) - : base(bytes, options, configuration) + /// The width of the image in pixels. + /// The height of the image in pixels. + public Image(int width, int height) + : this(width, height, null) { } @@ -219,7 +49,7 @@ namespace ImageSharp /// /// The other image, where the clone should be made from. /// is null. - public Image(Image other) + internal Image(Image other) : base(other) { } diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs index 707fea235d..393d83077a 100644 --- a/src/ImageSharp/Image/IImageBase.cs +++ b/src/ImageSharp/Image/IImageBase.cs @@ -15,16 +15,6 @@ namespace ImageSharp /// Rectangle Bounds { get; } - /// - /// Gets or sets the maximum allowable width in pixels. - /// - int MaxWidth { get; set; } - - /// - /// Gets or sets the maximum allowable height in pixels. - /// - int MaxHeight { get; set; } - /// /// Gets the width in pixels. /// diff --git a/src/ImageSharp/Image/IImageBase{TColor}.cs b/src/ImageSharp/Image/IImageBase{TColor}.cs index e894fba4a8..14bdffc672 100644 --- a/src/ImageSharp/Image/IImageBase{TColor}.cs +++ b/src/ImageSharp/Image/IImageBase{TColor}.cs @@ -21,16 +21,6 @@ namespace ImageSharp /// TColor[] Pixels { get; } - /// - /// Sets the size of the pixel array of the image to the given width and height. - /// - /// The new width of the image. Must be greater than zero. - /// The new height of the image. Must be greater than zero. - /// - /// Thrown if either or are less than or equal to 0. - /// - void InitPixels(int width, int height); - /// /// Locks the image providing access to the pixels. /// diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 878ba09b39..cfce7184b6 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -18,6 +18,16 @@ namespace ImageSharp public abstract class ImageBase : IImageBase where TColor : struct, IPixel { + /// + /// Gets or sets the maximum allowable width in pixels. + /// + public const int MaxWidth = int.MaxValue; + + /// + /// Gets or sets the maximum allowable height in pixels. + /// + public const int MaxHeight = int.MaxValue; + /// /// The image pixels /// @@ -40,7 +50,7 @@ namespace ImageSharp /// /// The configuration providing initialization code which allows extending the library. /// - protected ImageBase(Configuration configuration = null) + protected ImageBase(Configuration configuration) { this.Configuration = configuration ?? Configuration.Default; } @@ -56,10 +66,15 @@ namespace ImageSharp /// /// Thrown if either or are less than or equal to 0. /// - 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 is null. /// protected ImageBase(ImageBase other) + : this(other.Configuration) { Guard.NotNull(other, nameof(other), "Other image cannot be null."); @@ -90,12 +106,6 @@ namespace ImageSharp } } - /// - public int MaxWidth { get; set; } = int.MaxValue; - - /// - public int MaxHeight { get; set; } = int.MaxValue; - /// public TColor[] Pixels => this.pixelBuffer; @@ -139,17 +149,6 @@ namespace ImageSharp GC.SuppressFinalize(this); } - /// - 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(); - } - /// public PixelAccessor Lock() { diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 34724cc977..82991948cb 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -35,7 +35,7 @@ namespace ImageSharp /// /// The configuration providing initialization code which allows extending the library. /// - 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(); } /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// Thrown if the is null. - public Image(Stream stream) - : this(stream, null, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// - /// The options for the decoder. - /// - /// Thrown if the is null. - public Image(Stream stream, IDecoderOptions options) - : this(stream, options, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(Stream stream, Configuration configuration) - : this(stream, null, configuration) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The stream containing image information. - /// - /// - /// The options for the decoder. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(Stream stream, IDecoderOptions options, Configuration configuration) - : base(configuration) - { - Guard.NotNull(stream, nameof(stream)); - this.Load(stream, options); - } - -#if !NETSTANDARD1_1 - /// - /// Initializes a new instance of the class. - /// - /// - /// The file containing image information. - /// - /// Thrown if the is null. - public Image(string filePath) - : this(filePath, null, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The file containing image information. - /// - /// - /// The options for the decoder. - /// - /// Thrown if the is null. - public Image(string filePath, IDecoderOptions options) - : this(filePath, options, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The file containing image information. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(string filePath, Configuration configuration) - : this(filePath, null, configuration) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The file containing image information. - /// - /// - /// The options for the decoder. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - 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 - - /// - /// Initializes a new instance of the class. - /// - /// - /// The byte array containing image information. - /// - /// Thrown if the is null. - public Image(byte[] bytes) - : this(bytes, null, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The byte array containing image information. - /// - /// - /// The options for the decoder. - /// - /// Thrown if the is null. - public Image(byte[] bytes, IDecoderOptions options) - : this(bytes, options, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The byte array containing image information. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(byte[] bytes, Configuration configuration) - : this(bytes, null, configuration) - { - } - - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class + /// with the height and the width of the image. /// - /// - /// The byte array containing image information. - /// - /// - /// The options for the decoder. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// Thrown if the is null. - public Image(byte[] bytes, IDecoderOptions options, Configuration configuration) - : base(configuration) + /// The width of the image in pixels. + /// The height of the image in pixels. + 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); - } } /// @@ -271,7 +87,6 @@ namespace ImageSharp public Image(ImageBase other) : base(other) { - this.CopyProperties(other); } /// @@ -588,103 +403,8 @@ namespace ImageSharp /// private void CopyProperties(IImage other) { - base.CopyProperties(other); - this.CurrentImageFormat = other.CurrentImageFormat; this.MetaData = new ImageMetaData(other.MetaData); } - - /// - /// Loads the image from the given stream. - /// - /// The stream containing image information. - /// The options for the decoder. - /// - /// Thrown if the stream is not readable nor seekable. - /// - 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()); - } - - /// - /// Decodes the image stream to the current image. - /// - /// The stream. - /// The options for the decoder. - /// - /// The . - /// - private bool Decode(Stream stream, IDecoderOptions options) - { - int maxHeaderSize = this.Configuration.MaxHeaderSize; - if (maxHeaderSize <= 0) - { - return false; - } - - IImageFormat format; - byte[] header = ArrayPool.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.Shared.Return(header); - } - - if (format == null) - { - return false; - } - - format.Decoder.Decode(this, stream, options); - this.CurrentImageFormat = format; - return true; - } } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index de1e424769..d7d5e88b5f 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -5,6 +5,7 @@ namespace ImageSharp { + using System; using System.Collections.Generic; /// @@ -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); } /// @@ -143,5 +130,32 @@ namespace ImageSharp { this.ExifProfile?.Sync(this); } + + /// + /// Sets the current metadata values based on a previous metadata object. + /// + /// Meta data object to copy values from. + 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; + } + } } } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index b363286b00..c4a94c5ff1 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/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(memStream); + return Image.Load(memStream); } } diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs b/tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs index 431bbeb079..acde8e0dbe 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs b/tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs index 517915bacb..6786cfdc0f 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeGif.cs b/tests/ImageSharp.Benchmarks/Image/DecodeGif.cs index cb70213dac..a9bb4c7b3a 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeGif.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs index cbbe9c9f23..6ce2303703 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs index c79d615384..5c3c1e115b 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeJpegMultiple.cs +++ b/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) ); } diff --git a/tests/ImageSharp.Benchmarks/Image/DecodePng.cs b/tests/ImageSharp.Benchmarks/Image/DecodePng.cs index 79c8dbc23e..620a48a3b1 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodePng.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs b/tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs index b0a3b44999..6ed5773388 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Image/EncodeGif.cs index 0810f3fe17..fabeba1bde 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeGif.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs index ba383873c2..1318c1674a 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs +++ b/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; } } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs index f835f9666f..7649812ecc 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeJpeg.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs index 0bb0e922c5..4c1feb6c2a 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Image/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Image/MultiImageBenchmarkBase.cs index 4fee634f5f..a084ca025c 100644 --- a/tests/ImageSharp.Benchmarks/Image/MultiImageBenchmarkBase.cs +++ b/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); } diff --git a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs index 28bec5124d..28661b9d63 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs +++ b/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); } } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index ae795c2ecc..1ecd04690a 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/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); diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index a140b7a3cf..897778bc3a 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/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); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 5723f9b234..416c88a500 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/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 mirror = provider.Factory.CreateImage(1, 1); + using (JpegDecoderCore decoder = new JpegDecoderCore(null)) { - decoder.Decode(mirror, ms, true); + Image mirror = decoder.Decode(ms); Assert.Equal(decoder.ImageWidth, image.Width); Assert.Equal(decoder.ImageHeight, image.Height); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index c97eb14619..0833cb8680 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/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); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index 50e678bf08..28a64a765c 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/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}"); diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs new file mode 100644 index 0000000000..2c97ea06fd --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -0,0 +1,341 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.IO; + using System.Linq; + using ImageSharp.Formats; + using ImageSharp.IO; + using Moq; + using Xunit; + + /// + /// Tests the class. + /// + public class ImageLoadTests : IDisposable + { + private readonly Mock fileSystem; + private readonly IDecoderOptions decoderOptions; + private Image returnImage; + private Mock localDecoder; + private Mock 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(1, 1); + + this.localDecoder = new Mock(); + this.localFormat = new Mock(); + this.localFormat.Setup(x => x.Decoder).Returns(this.localDecoder.Object); + this.localFormat.Setup(x => x.Encoder).Returns(new Mock().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())).Returns(true); + this.localFormat.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); + this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) + .Callback((s, o) => { + using (var ms = new MemoryStream()) + { + s.CopyTo(ms); + this.DecodedData = ms.ToArray(); + } + }) + .Returns(this.returnImage); + + this.fileSystem = new Mock(); + + 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().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 img = Image.Load(this.DataStream); + + Assert.NotNull(img); + Assert.Equal(TestFormat.GlobalTestFormat.Sample(), 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 img = Image.Load(this.DataStream, this.decoderOptions); + + Assert.NotNull(img); + Assert.Equal(TestFormat.GlobalTestFormat.Sample(), 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(stream, null)); + } + + [Fact] + public void LoadFromStreamWithTypeAndConfig() + { + Stream stream = new MemoryStream(); + Image img = Image.Load(stream, this.LocalConfiguration); + + Assert.NotNull(img); + Assert.Equal(this.returnImage, img); + Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); + this.localDecoder.Verify(x => x.Decode(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(stream, this.decoderOptions)); + } + + [Fact] + public void LoadFromStreamWithTypeAndConfigAndOptions() + { + Stream stream = new MemoryStream(); + Image img = Image.Load(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(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 img = Image.Load(this.DataStream.ToArray()); + + Assert.NotNull(img); + Assert.Equal(TestFormat.GlobalTestFormat.Sample(), 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 img = Image.Load(this.DataStream.ToArray(), this.decoderOptions); + + Assert.NotNull(img); + Assert.Equal(TestFormat.GlobalTestFormat.Sample(), 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(It.IsAny(), null)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + + [Fact] + public void LoadFromBytesWithTypeAndConfig() + { + Image img = Image.Load(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(It.IsAny(), 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(It.IsAny(), this.decoderOptions)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + + [Fact] + public void LoadFromBytesWithTypeAndConfigAndOptions() + { + Image img = Image.Load(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(It.IsAny(), 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 img = Image.Load(this.DataStream); + + Assert.NotNull(img); + Assert.Equal(TestFormat.GlobalTestFormat.Sample(), 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 img = Image.Load(this.DataStream, this.decoderOptions); + + Assert.NotNull(img); + Assert.Equal(TestFormat.GlobalTestFormat.Sample(), 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(this.DataStream, null)); + } + + [Fact] + public void LoadFromFileWithTypeAndConfig() + { + Image img = Image.Load(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(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(this.DataStream, this.decoderOptions)); + } + + [Fact] + public void LoadFromFileWithTypeAndConfigAndOptions() + { + Image img = Image.Load(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(this.DataStream, this.decoderOptions)); + } + + public void Dispose() + { + // clean up the global object; + this.returnImage?.Dispose(); + } + } +} diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index b0a031a780..02b0e5ad9b 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -21,11 +21,11 @@ namespace ImageSharp.Tests { Assert.Throws(() => { - 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( () => { - new Image(Guid.NewGuid().ToString()); + Image.Load(Guid.NewGuid().ToString()); }); } @@ -59,7 +59,7 @@ namespace ImageSharp.Tests ArgumentNullException ex = Assert.Throws( () => { - new Image((string) null); + Image.Load((string) null); }); } diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 785d9dcfc2..1bc31286da 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/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); } } diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index 701025e871..eedc0d306a 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/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); } /// @@ -139,7 +139,7 @@ namespace ImageSharp.Tests /// public Image CreateImage(IDecoderOptions options) { - return new Image(this.Bytes, options); + return Image.Load(this.Bytes, options); } /// diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs new file mode 100644 index 0000000000..3a40ed4201 --- /dev/null +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -0,0 +1,174 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +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; + + /// + /// A test image file. + /// + 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 DecodeCalls { get; } = new List(); + + 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 _sampleImages = new Dictionary(); + + 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 Sample() + where TColor : struct, IPixel + { + lock (this._sampleImages) + { + if (!this._sampleImages.ContainsKey(typeof(TColor))) + { + this._sampleImages.Add(typeof(TColor), new Image(1, 1)); + } + + return (Image)this._sampleImages[typeof(TColor)]; + } + } + + public string MimeType => "img/test"; + + public string Extension => "test_ext"; + + public IEnumerable 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 Decode(Stream stream, IDecoderOptions options) where TColor : struct, IPixel + { + 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(); + } + } + + public class TestEncoder : ImageSharp.Formats.IImageEncoder + { + private TestFormat testFormat; + + public TestEncoder(TestFormat testFormat) + { + this.testFormat = testFormat; + } + + public void Encode(Image image, Stream stream, IEncoderOptions options) where TColor : struct, IPixel + { + // TODO record this happend so we an verify it. + } + } + } +} diff --git a/tests/ImageSharp.Tests/TestUtilities/Factories/GenericFactory.cs b/tests/ImageSharp.Tests/TestUtilities/Factories/GenericFactory.cs index 87b7ace6ae..c2fe0dc5c2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Factories/GenericFactory.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Factories/GenericFactory.cs @@ -21,7 +21,7 @@ namespace ImageSharp.Tests public virtual Image CreateImage(byte[] bytes) { - return new Image(bytes); + return Image.Load(bytes); } public virtual Image CreateImage(Image other) diff --git a/tests/ImageSharp.Tests/TestUtilities/Factories/ImageFactory.cs b/tests/ImageSharp.Tests/TestUtilities/Factories/ImageFactory.cs index a8d398c1e8..2361bc01ce 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Factories/ImageFactory.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Factories/ImageFactory.cs @@ -7,7 +7,7 @@ namespace ImageSharp.Tests { public class ImageFactory : GenericFactory { - public override Image CreateImage(byte[] bytes) => new Image(bytes); + public override Image CreateImage(byte[] bytes) => Image.Load(bytes); public override Image CreateImage(int width, int height) => new Image(width, height); From 04dd7056648d8fbbb71f2f99dad25e94ce98fb4a Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 21 Mar 2017 18:37:45 +0000 Subject: [PATCH 02/14] fix parameter names --- src/ImageSharp/Image.FromBytes.cs | 64 +++++++++++++++---------------- src/ImageSharp/Image.FromFile.cs | 64 +++++++++++++++---------------- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index e68a57fe70..3f1a3031c0 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -20,126 +20,126 @@ namespace ImageSharp public sealed partial class Image { /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// - /// The stream containing image information. + /// The byte array containing image data. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream) + public static Image Load(byte[] data) { - return Load(stream, null, null); + return Load(data, null, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// - /// The stream containing image information. + /// The byte array containing image data. /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream, IDecoderOptions options) + public static Image Load(byte[] data, IDecoderOptions options) { - return Load(stream, options, null); + return Load(data, options, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// - /// The stream containing image information. + /// The byte array containing image data. /// The config for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream, Configuration config) + public static Image Load(byte[] data, Configuration config) { - return Load(stream, null, config); + return Load(data, null, config); } /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// - /// The stream containing image information. + /// The byte array containing image data. /// The options for the decoder. /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream, IDecoderOptions options, Configuration config) + public static Image Load(byte[] data, IDecoderOptions options, Configuration config) { - using (MemoryStream ms = new MemoryStream(stream)) + using (MemoryStream ms = new MemoryStream(data)) { return Load(ms, options, config); } } /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// /// The pixel format. - /// The stream containing image information. + /// The byte array containing image data. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream) + public static Image Load(byte[] data) where TColor : struct, IPixel { - return Load(stream, null, null); + return Load(data, null, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// /// The pixel format. - /// The stream containing image information. + /// The byte array containing image data. /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream, IDecoderOptions options) + public static Image Load(byte[] data, IDecoderOptions options) where TColor : struct, IPixel { - return Load(stream, options, null); + return Load(data, options, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// /// The pixel format. - /// The stream containing image information. + /// The byte array containing image data. /// The config for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream, Configuration config) + public static Image Load(byte[] data, Configuration config) where TColor : struct, IPixel { - return Load(stream, null, config); + return Load(data, null, config); } /// - /// Loads the image from the given stream. + /// Loads the image from the given byte array. /// /// The pixel format. - /// The stream containing image information. + /// The byte array containing image data. /// The options for the decoder. /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] stream, IDecoderOptions options, Configuration config) + public static Image Load(byte[] data, IDecoderOptions options, Configuration config) where TColor : struct, IPixel { - using (MemoryStream ms = new MemoryStream(stream)) + using (MemoryStream ms = new MemoryStream(data)) { return Load(ms, options, config); } diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index b0adb1f96f..9b8ba83ded 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -21,124 +21,124 @@ namespace ImageSharp public sealed partial class Image { /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// - /// The stream containing image information. + /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream) + public static Image Load(string path) { - return Load(stream, null, null); + return Load(path, null, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// - /// The stream containing image information. + /// The file path to the image. /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream, IDecoderOptions options) + public static Image Load(string path, IDecoderOptions options) { - return Load(stream, options, null); + return Load(path, options, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// - /// The stream containing image information. + /// The file path to the image. /// The config for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream, Configuration config) + public static Image Load(string path, Configuration config) { - return Load(stream, null, config); + return Load(path, null, config); } /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// - /// The stream containing image information. + /// The file path to the image. /// The options for the decoder. /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream, IDecoderOptions options, Configuration config) + public static Image Load(string path, IDecoderOptions options, Configuration config) { - return new Image(Image.Load(stream, options, config)); + return new Image(Load(path, options, config)); } /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// /// The pixel format. - /// The stream containing image information. + /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream) + public static Image Load(string path) where TColor : struct, IPixel { - return Load(stream, null, null); + return Load(path, null, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// /// The pixel format. - /// The stream containing image information. + /// The file path to the image. /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream, IDecoderOptions options) + public static Image Load(string path, IDecoderOptions options) where TColor : struct, IPixel { - return Load(stream, options, null); + return Load(path, options, null); } /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// /// The pixel format. - /// The stream containing image information. + /// The file path to the image. /// The config for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream, Configuration config) + public static Image Load(string path, Configuration config) where TColor : struct, IPixel { - return Load(stream, null, config); + return Load(path, null, config); } /// - /// Loads the image from the given stream. + /// Loads the image from the given file. /// /// The pixel format. - /// The stream containing image information. + /// The file path to the image. /// The options for the decoder. /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string stream, IDecoderOptions options, Configuration config) + public static Image Load(string path, IDecoderOptions options, Configuration config) where TColor : struct, IPixel { config = config ?? Configuration.Default; - using (Stream s = config.FileSystem.OpenRead(stream)) + using (Stream s = config.FileSystem.OpenRead(path)) { return Load(s, options, config); } From 1343c78411010268a092ec0d83b3f4574daf4269 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 22 Mar 2017 06:58:16 +0000 Subject: [PATCH 03/14] Add IImageDecoder overloads Adds overloads the the Image.Load(..) methods that take an IImageDecoder. --- src/ImageSharp/Image.Decode.cs | 40 +++--- src/ImageSharp/Image.FromBytes.cs | 72 +++++++++- src/ImageSharp/Image.FromFile.cs | 70 ++++++++- src/ImageSharp/Image.FromStream.cs | 108 +++++++++++--- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 133 +++++++++++++++++- tests/ImageSharp.Tests/TestFileSystem.cs | 72 ++++++++++ 6 files changed, 449 insertions(+), 46 deletions(-) create mode 100644 tests/ImageSharp.Tests/TestFileSystem.cs diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index f31f2c0a55..c95b71b1e8 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -19,25 +19,12 @@ namespace ImageSharp /// public sealed partial class Image { - /// - /// Decodes the image stream to the current image. - /// - /// The pixel format. - /// The stream. - /// The options for the decoder. - /// the configuration. - /// The decoded image - /// - /// [true] if can successfull decode the image otherwise [false]. - /// - private static bool Decode(Stream stream, IDecoderOptions options, Configuration config, out Image img) - where TColor : struct, IPixel + private static IImageFormat DiscoverFormat(Stream stream, IDecoderOptions options, Configuration config) { - img = null; int maxHeaderSize = config.MaxHeaderSize; if (maxHeaderSize <= 0) { - return false; + return null; } IImageFormat format; @@ -54,14 +41,31 @@ namespace ImageSharp ArrayPool.Shared.Return(header); } + return format; + } + + /// + /// Decodes the image stream to the current image. + /// + /// The pixel format. + /// The stream. + /// The options for the decoder. + /// the configuration. + /// + /// The decoded image + /// + private static Image Decode(Stream stream, IDecoderOptions options, Configuration config) + where TColor : struct, IPixel + { + IImageFormat format = DiscoverFormat(stream, options, config); if (format == null) { - return false; + return null; } - img = format.Decoder.Decode(stream, options); + Image img = format.Decoder.Decode(stream, options); img.CurrentImageFormat = format; - return true; + return img; } } } diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 3f1a3031c0..8e0ac04a5a 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -29,7 +29,7 @@ namespace ImageSharp /// The image public static Image Load(byte[] data) { - return Load(data, null, null); + return Load(data, null, (Configuration)null); } /// @@ -60,6 +60,20 @@ namespace ImageSharp return Load(data, null, config); } + /// + /// Loads the image from the given byte array. + /// + /// The byte array containing image data. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] data, IImageDecoder decoder) + { + return Load(data, decoder, null); + } + /// /// Loads the image from the given byte array. /// @@ -78,6 +92,24 @@ namespace ImageSharp } } + /// + /// Loads the image from the given byte array. + /// + /// The byte array containing image data. + /// The decoder. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) + { + using (MemoryStream ms = new MemoryStream(data)) + { + return Load(ms, decoder, options); + } + } + /// /// Loads the image from the given byte array. /// @@ -90,7 +122,7 @@ namespace ImageSharp public static Image Load(byte[] data) where TColor : struct, IPixel { - return Load(data, null, null); + return Load(data, null, (Configuration)null); } /// @@ -125,6 +157,22 @@ namespace ImageSharp return Load(data, null, config); } + /// + /// Loads the image from the given byte array. + /// + /// The pixel format. + /// The byte array containing image data. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] data, IImageDecoder decoder) + where TColor : struct, IPixel + { + return Load(data, decoder, null); + } + /// /// Loads the image from the given byte array. /// @@ -144,5 +192,25 @@ namespace ImageSharp return Load(ms, options, config); } } + + /// + /// Loads the image from the given byte array. + /// + /// The pixel format. + /// The byte array containing image data. + /// The decoder. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) + where TColor : struct, IPixel + { + using (MemoryStream ms = new MemoryStream(data)) + { + return Load(ms, decoder, options); + } + } } } diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index 9b8ba83ded..e9015eaa9d 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -30,7 +30,7 @@ namespace ImageSharp /// The image public static Image Load(string path) { - return Load(path, null, null); + return Load(path, null, (Configuration)null); } /// @@ -61,6 +61,35 @@ namespace ImageSharp return Load(path, null, config); } + /// + /// Loads the image from the given file. + /// + /// The file path to the image. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string path, IImageDecoder decoder) + { + return Load(path, decoder, null); + } + + /// + /// Loads the image from the given file. + /// + /// The file path to the image. + /// The decoder. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options) + { + return new Image(Load(path, decoder, options)); + } + /// /// Loads the image from the given file. /// @@ -88,7 +117,7 @@ namespace ImageSharp public static Image Load(string path) where TColor : struct, IPixel { - return Load(path, null, null); + return Load(path, null, (Configuration)null); } /// @@ -123,6 +152,22 @@ namespace ImageSharp return Load(path, null, config); } + /// + /// Loads the image from the given file. + /// + /// The pixel format. + /// The file path to the image. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string path, IImageDecoder decoder) + where TColor : struct, IPixel + { + return Load(path, decoder, null); + } + /// /// Loads the image from the given file. /// @@ -143,6 +188,27 @@ namespace ImageSharp return Load(s, options, config); } } + + /// + /// Loads the image from the given file. + /// + /// The pixel format. + /// The file path to the image. + /// The decoder. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options) + where TColor : struct, IPixel + { + Configuration config = Configuration.Default; + using (Stream s = config.FileSystem.OpenRead(path)) + { + return Load(s, decoder, options); + } + } } #endif } diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 36309db5b5..b40aa62cd9 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -29,7 +29,7 @@ namespace ImageSharp /// The image public static Image Load(Stream stream) { - return Load(stream, null, null); + return Load(stream, null, (Configuration)null); } /// @@ -60,6 +60,20 @@ namespace ImageSharp return Load(stream, null, config); } + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IImageDecoder decoder) + { + return Load(stream, decoder, null); + } + /// /// Loads the image from the given stream. /// @@ -75,6 +89,21 @@ namespace ImageSharp return new Image(Load(stream, options, config)); } + /// + /// Loads the image from the given stream. + /// + /// The stream containing image information. + /// The decoder. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) + { + return new Image(Load(stream, decoder, options)); + } + /// /// Loads the image from the given stream. /// @@ -87,7 +116,7 @@ namespace ImageSharp public static Image Load(Stream stream) where TColor : struct, IPixel { - return Load(stream, null, null); + return Load(stream, null, (Configuration)null); } /// @@ -122,6 +151,39 @@ namespace ImageSharp return Load(stream, null, config); } + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IImageDecoder decoder) + where TColor : struct, IPixel + { + return Load(stream, decoder, null); + } + + /// + /// Loads the image from the given stream. + /// + /// The pixel format. + /// The stream containing image information. + /// The decoder. + /// The options for the decoder. + /// + /// Thrown if the stream is not readable nor seekable. + /// + /// The image + public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) + where TColor : struct, IPixel + { + return WithSeekableStream(stream, s => decoder.Decode(s, options)); + } + /// /// Loads the image from the given stream. /// @@ -138,11 +200,29 @@ namespace ImageSharp { config = config ?? Configuration.Default; - if (!config.ImageFormats.Any()) + Image img = WithSeekableStream(stream, s => + { + return Decode(stream, options, config); + }); + + if (img != null) + { + return img; + } + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Image cannot be loaded. Available formats:"); + + foreach (IImageFormat format in config.ImageFormats) { - throw new InvalidOperationException("No image formats have been configured."); + stringBuilder.AppendLine("-" + format); } + throw new NotSupportedException(stringBuilder.ToString()); + } + + private static T WithSeekableStream(Stream stream, Func action) + { if (!stream.CanRead) { throw new NotSupportedException("Cannot read from the stream."); @@ -150,10 +230,7 @@ namespace ImageSharp if (stream.CanSeek) { - if (Decode(stream, options, config, out Image img)) - { - return img; - } + return action(stream); } else { @@ -163,22 +240,9 @@ namespace ImageSharp stream.CopyTo(ms); ms.Position = 0; - if (Decode(ms, options, config, out Image img)) - { - return img; - } + return action(stream); } } - - 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()); } } } diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index 2c97ea06fd..da3d2fb069 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -66,6 +66,9 @@ namespace ImageSharp.Tests this.FilePath = Guid.NewGuid().ToString(); this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); + + TestFileSystem.RegisterGloablTestFormat(); + TestFileSystem.Global.AddFile(this.FilePath, this.DataStream); } [Fact] @@ -157,6 +160,50 @@ namespace ImageSharp.Tests this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions)); } + + + [Fact] + public void LoadFromStreamWithDecoder() + { + Stream stream = new MemoryStream(); + Image img = Image.Load(stream, this.localDecoder.Object); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(stream, null)); + } + + [Fact] + public void LoadFromStreamWithTypeAndDecoder() + { + Stream stream = new MemoryStream(); + Image img = Image.Load(stream, this.localDecoder.Object); + + Assert.NotNull(img); + Assert.Equal(this.returnImage, img); + this.localDecoder.Verify(x => x.Decode(stream, null)); + } + + [Fact] + public void LoadFromStreamWithDecoderAndOptions() + { + Stream stream = new MemoryStream(); + Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions)); + } + + [Fact] + public void LoadFromStreamWithTypeAndDecoderAndOptions() + { + Stream stream = new MemoryStream(); + Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); + + Assert.NotNull(img); + Assert.Equal(this.returnImage, img); + this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions)); + } + [Fact] public void LoadFromBytes() { @@ -246,7 +293,50 @@ namespace ImageSharp.Tests this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } - + + + [Fact] + public void LoadFromBytesWithDecoder() + { + Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), null)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + + [Fact] + public void LoadFromBytesWithTypeAndDecoder() + { + Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); + + Assert.NotNull(img); + Assert.Equal(this.returnImage, img); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), null)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + + [Fact] + public void LoadFromBytesWithDecoderAndOptions() + { + Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + + [Fact] + public void LoadFromBytesWithTypeAndDecoderAndOptions() + { + Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); + + Assert.NotNull(img); + Assert.Equal(this.returnImage, img); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); + } + [Fact] public void LoadFromFile() { @@ -324,7 +414,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFileWithTypeAndConfigAndOptions() { - Image img = Image.Load(FilePath, this.decoderOptions, this.LocalConfiguration); + Image img = Image.Load(this.FilePath, this.decoderOptions, this.LocalConfiguration); Assert.NotNull(img); Assert.Equal(this.returnImage, img); @@ -332,6 +422,45 @@ namespace ImageSharp.Tests this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions)); } + + [Fact] + public void LoadFromFileWithDecoder() + { + Image img = Image.Load(this.FilePath, this.localDecoder.Object); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(this.DataStream, null)); + } + + [Fact] + public void LoadFromFileWithTypeAndDecoder() + { + Image img = Image.Load(this.FilePath, this.localDecoder.Object); + + Assert.NotNull(img); + Assert.Equal(this.returnImage, img); + this.localDecoder.Verify(x => x.Decode(this.DataStream, null)); + } + + [Fact] + public void LoadFromFileWithDecoderAndOptions() + { + Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); + + Assert.NotNull(img); + this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions)); + } + + [Fact] + public void LoadFromFileWithTypeAndDecoderAndOptions() + { + Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); + + Assert.NotNull(img); + Assert.Equal(this.returnImage, img); + this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions)); + } + public void Dispose() { // clean up the global object; diff --git a/tests/ImageSharp.Tests/TestFileSystem.cs b/tests/ImageSharp.Tests/TestFileSystem.cs new file mode 100644 index 0000000000..78499ac8ee --- /dev/null +++ b/tests/ImageSharp.Tests/TestFileSystem.cs @@ -0,0 +1,72 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +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; + + /// + /// A test image file. + /// + public class TestFileSystem : ImageSharp.IO.IFileSystem + { + + public static TestFileSystem Global { get; } = new TestFileSystem(); + + public static void RegisterGloablTestFormat() + { + Configuration.Default.FileSystem = Global; + } + + Dictionary fileSystem = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public void AddFile(string path, Stream data) + { + fileSystem.Add(path, data); + } + + public Stream Create(string path) + { + MemoryStream stream = new MemoryStream(); + lock (fileSystem) + { + if (fileSystem.ContainsKey(path)) + { + fileSystem[path] = stream; + } + else + { + fileSystem.Add(path, stream); + } + } + return stream; + } + + + public Stream OpenRead(string path) + { + lock (fileSystem) + { + if (fileSystem.ContainsKey(path)) + { + + Stream stream = fileSystem[path]; + stream.Position = 0; + return stream; + } + } + + return File.OpenRead(path); + } + } +} + From cfce9d2efc8bf3210dfc2b1f823b2c2c136ff51a Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 22 Mar 2017 07:09:43 +0000 Subject: [PATCH 04/14] remove decode metadata only it has no tests and nothing called it --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index fa656e71e8..3f946fb790 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -193,19 +193,6 @@ namespace ImageSharp.Formats return image; } - /// - /// Decodes the image from the specified and sets - /// the data to image. - /// - /// The stream, where the image should be. - /// The image metadata. - public ImageMetaData DecodeMetaData(Stream stream) - { - ImageMetaData metadata = new ImageMetaData(); - this.ProcessStream(metadata, stream, true); - return metadata; - } - /// /// Dispose /// From 53bba0269aa741148c33342816c276d1c696afcb Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 22 Mar 2017 09:56:22 +0000 Subject: [PATCH 05/14] pass configuration & ensure only single image created --- src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 5 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 14 +- src/ImageSharp/Formats/Gif/GifDecoder.cs | 10 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 11 +- src/ImageSharp/Formats/IImageDecoder.cs | 3 +- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 4 +- .../Formats/Jpeg/JpegDecoderCore.cs | 12 +- src/ImageSharp/Formats/Png/PngDecoder.cs | 10 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 11 +- src/ImageSharp/Image.Create.cs | 46 +++++++ src/ImageSharp/Image.Decode.cs | 6 +- src/ImageSharp/Image.FromFile.cs | 6 +- src/ImageSharp/Image.FromStream.cs | 2 +- .../Formats/Jpg/JpegDecoderTests.cs | 2 +- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 128 ++++++++++++------ tests/ImageSharp.Tests/TestFormat.cs | 23 +++- 16 files changed, 221 insertions(+), 72 deletions(-) create mode 100644 src/ImageSharp/Image.Create.cs diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 2bc1c8cc30..8414807e0c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -26,12 +26,13 @@ namespace ImageSharp.Formats public class BmpDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + where TColor : struct, IPixel { Guard.NotNull(stream, "stream"); - return new BmpDecoderCore().Decode(stream); + return new BmpDecoderCore(configuration).Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index adfa4b6ace..18e4e858b8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -43,6 +43,17 @@ namespace ImageSharp.Formats /// private BmpInfoHeader infoHeader; + private Configuration configuration; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + public BmpDecoderCore(Configuration configuration) + { + this.configuration = configuration; + } + /// /// Decodes the image from the specified this._stream and sets /// the data to image. @@ -114,8 +125,7 @@ namespace ImageSharp.Formats + $"bigger then the max allowed size '{Image.MaxWidth}x{Image.MaxHeight}'"); } - Image image = new Image(this.infoHeader.Width, this.infoHeader.Height); - + Image image = Image.Create(this.infoHeader.Width, this.infoHeader.Height, this.configuration); using (PixelAccessor pixels = image.Lock()) { switch (this.infoHeader.Compression) diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 16b036e684..2e56b0baba 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -14,12 +14,13 @@ namespace ImageSharp.Formats public class GifDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + where TColor : struct, IPixel { IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options); - return this.Decode(stream, gifOptions); + return this.Decode(stream, gifOptions, configuration); } /// @@ -28,11 +29,12 @@ namespace ImageSharp.Formats /// The pixel format. /// The containing image data. /// The options for the decoder. + /// The configuration. /// The image thats been decoded. - public Image Decode(Stream stream, IGifDecoderOptions options) + public Image Decode(Stream stream, IGifDecoderOptions options, Configuration configuration) where TColor : struct, IPixel { - return new GifDecoderCore(options).Decode(stream); + return new GifDecoderCore(options, configuration).Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 22a26345fe..79348a7aba 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -27,6 +27,11 @@ namespace ImageSharp.Formats /// private readonly IGifDecoderOptions options; + /// + /// The global configuration. + /// + private readonly Configuration configuration; + /// /// The currently loaded stream. /// @@ -76,9 +81,11 @@ namespace ImageSharp.Formats /// Initializes a new instance of the class. /// /// The decoder options. - public GifDecoderCore(IGifDecoderOptions options) + /// The configuration. + public GifDecoderCore(IGifDecoderOptions options, Configuration configuration) { this.options = options ?? new GifDecoderOptions(); + this.configuration = configuration ?? Configuration.Default; } /// @@ -355,7 +362,7 @@ namespace ImageSharp.Formats this.metaData.Quality = colorTableLength / 3; // This initializes the image to become fully transparent because the alpha channel is zero. - this.image = new Image(imageWidth, imageHeight); + this.image = Image.Create(imageWidth, imageHeight, this.configuration); this.image.MetaData.LoadFrom(this.metaData); this.SetFrameDelay(this.metaData); diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index c4a9cf8c3c..8da23d499f 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -19,8 +19,9 @@ namespace ImageSharp.Formats /// The pixel format. /// The containing image data. /// The options for the decoder. + /// The configuration for the image. /// The decoded image - Image Decode(Stream stream, IDecoderOptions options) + Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) where TColor : struct, IPixel; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 3a91f8010e..254506af05 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -14,12 +14,12 @@ namespace ImageSharp.Formats public class JpegDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) where TColor : struct, IPixel { Guard.NotNull(stream, "stream"); - using (JpegDecoderCore decoder = new JpegDecoderCore(options)) + using (JpegDecoderCore decoder = new JpegDecoderCore(options, configuration)) { return decoder.Decode(stream); } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 3f946fb790..fc9506b546 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -42,6 +42,11 @@ namespace ImageSharp.Formats /// private readonly IDecoderOptions options; + /// + /// The global configuration + /// + private readonly Configuration configuration; + /// /// The App14 marker color-space /// @@ -91,8 +96,10 @@ namespace ImageSharp.Formats /// Initializes a new instance of the class. /// /// The decoder options. - public JpegDecoderCore(IDecoderOptions options) + /// The configuration. + public JpegDecoderCore(IDecoderOptions options, Configuration configuration) { + this.configuration = configuration ?? Configuration.Default; this.options = options ?? new DecoderOptions(); this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees(); this.QuantizationTables = new Block8x8F[MaxTq + 1]; @@ -498,7 +505,8 @@ namespace ImageSharp.Formats private Image ConvertJpegPixelsToImagePixels(ImageMetaData metadata) where TColor : struct, IPixel { - Image image = new Image(this.ImageWidth, this.ImageHeight); + Image image = Image.Create(this.ImageWidth, this.ImageHeight, this.configuration); + image.MetaData.LoadFrom(metadata); if (this.grayImage.IsInitialized) diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 5b7d97fc70..bf17ad1428 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -31,12 +31,13 @@ namespace ImageSharp.Formats public class PngDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options) + public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + where TColor : struct, IPixel { IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); - return this.Decode(stream, pngOptions); + return this.Decode(stream, pngOptions, configuration); } /// @@ -45,11 +46,12 @@ namespace ImageSharp.Formats /// The pixel format. /// The containing image data. /// The options for the decoder. + /// The configuration for the image. /// The decoded image. - public Image Decode(Stream stream, IPngDecoderOptions options) + public Image Decode(Stream stream, IPngDecoderOptions options, Configuration configuration) where TColor : struct, IPixel { - return new PngDecoderCore(options).Decode(stream); + return new PngDecoderCore(options, configuration).Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index dadf7ab7d6..7705e95492 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -74,6 +74,11 @@ namespace ImageSharp.Formats /// private readonly Crc32 crc = new Crc32(); + /// + /// The global configuration. + /// + private readonly Configuration configuration; + /// /// The stream to decode from. /// @@ -134,8 +139,10 @@ namespace ImageSharp.Formats /// Initializes a new instance of the class. /// /// The decoder options. - public PngDecoderCore(IPngDecoderOptions options) + /// The configuration. + public PngDecoderCore(IPngDecoderOptions options, Configuration configuration) { + this.configuration = configuration ?? Configuration.Default; this.options = options ?? new PngDecoderOptions(); } @@ -213,7 +220,7 @@ namespace ImageSharp.Formats 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}'"); } - Image image = new Image(this.header.Width, this.header.Height); + Image image = Image.Create(this.header.Width, this.header.Height, this.configuration); image.MetaData.LoadFrom(metadata); using (PixelAccessor pixels = image.Lock()) diff --git a/src/ImageSharp/Image.Create.cs b/src/ImageSharp/Image.Create.cs new file mode 100644 index 0000000000..bc430724a6 --- /dev/null +++ b/src/ImageSharp/Image.Create.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Diagnostics; + using System.IO; + + using Formats; + + /// + /// 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. + /// + public sealed partial class Image + { + /// + /// Create a new instance of the class + /// with the height and the width of the image. + /// + /// The pixel format. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// + /// A new unless is in which case it returns + /// + internal static Image Create(int width, int height, Configuration configuration) + where TColor : struct, IPixel + { + if (typeof(TColor) == typeof(Color)) + { + return new Image(width, height, configuration) as Image; + } + else + { + return new Image(width, height, configuration); + } + } + } +} diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index c95b71b1e8..32943ead58 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -19,7 +19,7 @@ namespace ImageSharp /// public sealed partial class Image { - private static IImageFormat DiscoverFormat(Stream stream, IDecoderOptions options, Configuration config) + private static IImageFormat DiscoverFormat(Stream stream, Configuration config) { int maxHeaderSize = config.MaxHeaderSize; if (maxHeaderSize <= 0) @@ -57,13 +57,13 @@ namespace ImageSharp private static Image Decode(Stream stream, IDecoderOptions options, Configuration config) where TColor : struct, IPixel { - IImageFormat format = DiscoverFormat(stream, options, config); + IImageFormat format = DiscoverFormat(stream, config); if (format == null) { return null; } - Image img = format.Decoder.Decode(stream, options); + Image img = format.Decoder.Decode(stream, options, config); img.CurrentImageFormat = format; return img; } diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index e9015eaa9d..b7fb0eef59 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -102,7 +102,11 @@ namespace ImageSharp /// The image public static Image Load(string path, IDecoderOptions options, Configuration config) { - return new Image(Load(path, options, config)); + config = config ?? Configuration.Default; + using (Stream s = config.FileSystem.OpenRead(path)) + { + return Load(s, options, config); + } } /// diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index b40aa62cd9..e995c47997 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -181,7 +181,7 @@ namespace ImageSharp public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) where TColor : struct, IPixel { - return WithSeekableStream(stream, s => decoder.Decode(s, options)); + return WithSeekableStream(stream, s => decoder.Decode(s, options, Configuration.Default)); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 416c88a500..cdd892dcee 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -90,7 +90,7 @@ namespace ImageSharp.Tests image.Save(ms, new JpegEncoder()); ms.Seek(0, SeekOrigin.Begin); - using (JpegDecoderCore decoder = new JpegDecoderCore(null)) + using (JpegDecoderCore decoder = new JpegDecoderCore(null, null)) { Image mirror = decoder.Decode(ms); diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index da3d2fb069..52b8f6ee28 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -32,7 +32,7 @@ namespace ImageSharp.Tests public ImageLoadTests() { - this.returnImage = new Image(1, 1); + this.returnImage = new Image(1, 1); this.localDecoder = new Mock(); this.localFormat = new Mock(); @@ -43,8 +43,10 @@ namespace ImageSharp.Tests this.localFormat.Setup(x => x.HeaderSize).Returns(1); this.localFormat.Setup(x => x.IsSupportedFileFormat(It.IsAny())).Returns(true); this.localFormat.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); - this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) - .Callback((s, o) => { + + this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny(), It.IsAny())) + + .Callback((s, o, c) => { using (var ms = new MemoryStream()) { s.CopyTo(ms); @@ -79,7 +81,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + } [Fact] @@ -90,7 +94,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + } [Fact] @@ -100,7 +106,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + } [Fact] @@ -111,7 +119,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + } [Fact] @@ -122,7 +132,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, null)); + + this.localDecoder.Verify(x => x.Decode(stream, null, this.LocalConfiguration)); + } [Fact] @@ -134,7 +146,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, null)); + + this.localDecoder.Verify(x => x.Decode(stream, null, this.LocalConfiguration)); + } [Fact] @@ -145,7 +159,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions)); + + this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, this.LocalConfiguration)); + } [Fact] @@ -157,7 +173,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions)); + + this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, this.LocalConfiguration)); + } @@ -169,7 +187,7 @@ namespace ImageSharp.Tests Image img = Image.Load(stream, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(stream, null)); + this.localDecoder.Verify(x => x.Decode(stream, null, Configuration.Default)); } [Fact] @@ -180,7 +198,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(stream, null)); + this.localDecoder.Verify(x => x.Decode(stream, null, Configuration.Default)); } [Fact] @@ -190,7 +208,7 @@ namespace ImageSharp.Tests Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, Configuration.Default)); } [Fact] @@ -201,7 +219,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, Configuration.Default)); } [Fact] @@ -212,7 +230,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + } [Fact] @@ -223,7 +243,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + } [Fact] @@ -233,7 +255,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + } [Fact] @@ -244,7 +268,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + } [Fact] @@ -254,7 +280,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null)); + + this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, this.LocalConfiguration)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -267,7 +295,9 @@ namespace ImageSharp.Tests Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null)); + + this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, this.LocalConfiguration)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -278,7 +308,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions)); + + this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, this.LocalConfiguration)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -290,7 +322,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions)); + + this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, this.LocalConfiguration)); + Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -301,7 +335,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null)); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, Configuration.Default)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -312,7 +346,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null)); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, Configuration.Default)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -322,7 +356,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, Configuration.Default)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -333,7 +367,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, Configuration.Default)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -345,7 +379,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + } [Fact] @@ -356,7 +392,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + } [Fact] @@ -366,7 +404,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + } [Fact] @@ -377,7 +417,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions); + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + } [Fact] @@ -387,7 +429,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null)); + + this.localDecoder.Verify(x => x.Decode(this.DataStream, null, this.LocalConfiguration)); + } [Fact] @@ -398,7 +442,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null)); + + this.localDecoder.Verify(x => x.Decode(this.DataStream, null, this.LocalConfiguration)); + } [Fact] @@ -408,7 +454,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions)); + + this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, this.LocalConfiguration)); + } [Fact] @@ -419,7 +467,9 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions)); + + this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, this.LocalConfiguration)); + } @@ -429,7 +479,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.FilePath, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null)); + this.localDecoder.Verify(x => x.Decode(this.DataStream, null, Configuration.Default)); } [Fact] @@ -439,7 +489,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null)); + this.localDecoder.Verify(x => x.Decode(this.DataStream, null, Configuration.Default)); } [Fact] @@ -448,7 +498,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, Configuration.Default)); } [Fact] @@ -458,7 +508,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, Configuration.Default)); } public void Dispose() diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 3a40ed4201..5894151dca 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -55,9 +55,11 @@ namespace ImageSharp.Tests Dictionary _sampleImages = new Dictionary(); - public void VerifyDecodeCall(byte[] marker, IDecoderOptions options) + + public void VerifyDecodeCall(byte[] marker, IDecoderOptions options, Configuration config) { - DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, options)).ToArray(); + DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, options, config)).ToArray(); + Assert.True(discovered.Any(), "No calls to decode on this formate with the proveded options happend"); @@ -107,10 +109,16 @@ namespace ImageSharp.Tests { public byte[] marker; public IDecoderOptions options; + internal Configuration config; - public bool IsMatch(byte[] testMarker, IDecoderOptions testOptions) + public bool IsMatch(byte[] testMarker, IDecoderOptions testOptions, Configuration config) { - if(this.options != testOptions) + if (this.options != testOptions) + { + return false; + } + + if (this.config != config) { return false; } @@ -140,7 +148,9 @@ namespace ImageSharp.Tests this.testFormat = testFormat; } - public Image Decode(Stream stream, IDecoderOptions options) where TColor : struct, IPixel + + public Image Decode(Stream stream, IDecoderOptions options, Configuration config) where TColor : struct, IPixel + { var ms = new MemoryStream(); stream.CopyTo(ms); @@ -148,7 +158,8 @@ namespace ImageSharp.Tests this.testFormat.DecodeCalls.Add(new DecodeOperation { marker = marker, - options = options + options = options, + config = config }); // TODO record this happend so we an verify it. From fb5899f0fdfed6a3ad8bb15dfa5ed165e2a41933 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 22 Mar 2017 10:14:13 +0000 Subject: [PATCH 06/14] fix test filesystem to prevent it breaking existing tests --- tests/ImageSharp.Tests/TestFileSystem.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/ImageSharp.Tests/TestFileSystem.cs b/tests/ImageSharp.Tests/TestFileSystem.cs index 78499ac8ee..d43b989f10 100644 --- a/tests/ImageSharp.Tests/TestFileSystem.cs +++ b/tests/ImageSharp.Tests/TestFileSystem.cs @@ -36,29 +36,28 @@ namespace ImageSharp.Tests public Stream Create(string path) { - MemoryStream stream = new MemoryStream(); + // if we have injected a fake file use it instead lock (fileSystem) { if (fileSystem.ContainsKey(path)) { - fileSystem[path] = stream; - } - else - { - fileSystem.Add(path, stream); + Stream stream = fileSystem[path]; + stream.Position = 0; + return stream; } } - return stream; + + return File.Create(path); } public Stream OpenRead(string path) { + // if we have injected a fake file use it instead lock (fileSystem) { if (fileSystem.ContainsKey(path)) { - Stream stream = fileSystem[path]; stream.Position = 0; return stream; From 9ec4ae84bb1f53682a9ff0d3034bf0d26887c3c9 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 25 Mar 2017 07:28:02 +0000 Subject: [PATCH 07/14] make constructor public --- src/ImageSharp/Image.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index 352107021a..195af60563 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -49,7 +49,7 @@ namespace ImageSharp /// /// The other image, where the clone should be made from. /// is null. - internal Image(Image other) + public Image(Image other) : base(other) { } From 2e4c1cd1b0e59516aea5d47dfe5aa102befbe7e8 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 25 Mar 2017 07:28:35 +0000 Subject: [PATCH 08/14] Clean up usings and add comments --- src/ImageSharp/Image.Decode.cs | 10 +++++++--- src/ImageSharp/Image.FromBytes.cs | 4 ---- src/ImageSharp/Image.FromFile.cs | 6 +----- src/ImageSharp/Image.FromStream.cs | 16 +++++++--------- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 32943ead58..a86a6e948d 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -5,12 +5,9 @@ namespace ImageSharp { - using System; using System.Buffers; - using System.Diagnostics; using System.IO; using System.Linq; - using System.Text; using Formats; /// @@ -19,8 +16,15 @@ namespace ImageSharp /// public sealed partial class Image { + /// + /// By reading the header on the provided stream this calculates the images format. + /// + /// The image stream to read the header from. + /// The configuration. + /// The image format or null if none found. private static IImageFormat DiscoverFormat(Stream stream, Configuration config) { + // This is probably a candidate for making into a public API in the future! int maxHeaderSize = config.MaxHeaderSize; if (maxHeaderSize <= 0) { diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 8e0ac04a5a..d23d0baeed 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -6,11 +6,7 @@ namespace ImageSharp { using System; - using System.Buffers; - using System.Diagnostics; using System.IO; - using System.Linq; - using System.Text; using Formats; /// diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index b7fb0eef59..1710909e18 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -5,15 +5,11 @@ namespace ImageSharp { +#if !NETSTANDARD1_1 using System; - using System.Buffers; - using System.Diagnostics; using System.IO; - using System.Linq; - using System.Text; using Formats; -#if !NETSTANDARD1_1 /// /// 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. diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index e995c47997..16793e16c7 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -6,10 +6,7 @@ namespace ImageSharp { using System; - using System.Buffers; - using System.Diagnostics; using System.IO; - using System.Linq; using System.Text; using Formats; @@ -86,7 +83,9 @@ namespace ImageSharp /// The image public static Image Load(Stream stream, IDecoderOptions options, Configuration config) { - return new Image(Load(stream, options, config)); + Image image = Load(stream, options, config); + + return image as Image ?? new Image(image); } /// @@ -101,7 +100,9 @@ namespace ImageSharp /// The image public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) { - return new Image(Load(stream, decoder, options)); + Image image = new Image(Load(stream, decoder, options)); + + return image as Image ?? new Image(image); } /// @@ -200,10 +201,7 @@ namespace ImageSharp { config = config ?? Configuration.Default; - Image img = WithSeekableStream(stream, s => - { - return Decode(stream, options, config); - }); + Image img = WithSeekableStream(stream, s => Decode(stream, options, config)); if (img != null) { From 0aa20b66e9ff854ac7e841a943dfa2b776b2ffbf Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 26 Mar 2017 09:31:45 +0100 Subject: [PATCH 09/14] Move metadata loading into constructor/creator. --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 3 +- .../Formats/Jpeg/JpegDecoderCore.cs | 4 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 +- src/ImageSharp/Image.Create.cs | 26 ++++++++-- src/ImageSharp/Image.cs | 15 ++++++ src/ImageSharp/Image/Image{TColor}.cs | 34 ++++++++++---- src/ImageSharp/MetaData/ImageMetaData.cs | 47 ++++++++----------- 7 files changed, 85 insertions(+), 47 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 79348a7aba..4c119ca737 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -362,8 +362,7 @@ namespace ImageSharp.Formats this.metaData.Quality = colorTableLength / 3; // This initializes the image to become fully transparent because the alpha channel is zero. - this.image = Image.Create(imageWidth, imageHeight, this.configuration); - this.image.MetaData.LoadFrom(this.metaData); + this.image = Image.Create(imageWidth, imageHeight, this.metaData, this.configuration); this.SetFrameDelay(this.metaData); diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index fc9506b546..33533aa12b 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -505,9 +505,7 @@ namespace ImageSharp.Formats private Image ConvertJpegPixelsToImagePixels(ImageMetaData metadata) where TColor : struct, IPixel { - Image image = Image.Create(this.ImageWidth, this.ImageHeight, this.configuration); - - image.MetaData.LoadFrom(metadata); + Image image = Image.Create(this.ImageWidth, this.ImageHeight, metadata, this.configuration); if (this.grayImage.IsInitialized) { diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 7705e95492..d6529940e2 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -220,8 +220,7 @@ namespace ImageSharp.Formats 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}'"); } - Image image = Image.Create(this.header.Width, this.header.Height, this.configuration); - image.MetaData.LoadFrom(metadata); + Image image = Image.Create(this.header.Width, this.header.Height, metadata, this.configuration); using (PixelAccessor pixels = image.Lock()) { diff --git a/src/ImageSharp/Image.Create.cs b/src/ImageSharp/Image.Create.cs index bc430724a6..fcecefd7b7 100644 --- a/src/ImageSharp/Image.Create.cs +++ b/src/ImageSharp/Image.Create.cs @@ -24,23 +24,43 @@ namespace ImageSharp /// The pixel format. /// The width of the image in pixels. /// The height of the image in pixels. + /// The images matadata to preload. /// /// The configuration providing initialization code which allows extending the library. /// /// /// A new unless is in which case it returns /// - internal static Image Create(int width, int height, Configuration configuration) + internal static Image Create(int width, int height, ImageMetaData metadata, Configuration configuration) where TColor : struct, IPixel { if (typeof(TColor) == typeof(Color)) { - return new Image(width, height, configuration) as Image; + return new Image(width, height, metadata, configuration) as Image; } else { - return new Image(width, height, configuration); + return new Image(width, height, metadata, configuration); } } + + /// + /// Create a new instance of the class + /// with the height and the width of the image. + /// + /// The pixel format. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// + /// A new unless is in which case it returns + /// + internal static Image Create(int width, int height, Configuration configuration) + where TColor : struct, IPixel + { + return Image.Create(width, height, null, configuration); + } } } diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index 195af60563..00688afc96 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -53,5 +53,20 @@ namespace ImageSharp : base(other) { } + + /// + /// Initializes a new instance of the class + /// with the height and the width of the image. + /// + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The metadata. + /// + /// The configuration providing initialization code which allows extending the library. + /// + internal Image(int width, int height, ImageMetaData metadata, Configuration configuration) + : base(width, height, metadata, configuration) + { + } } } diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 82991948cb..d063c3ff16 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -36,15 +36,8 @@ namespace ImageSharp /// The configuration providing initialization code which allows extending the library. /// public Image(int width, int height, Configuration configuration) - : base(width, height, configuration) + : this(width, height, new ImageMetaData(), configuration) { - if (!this.Configuration.ImageFormats.Any()) - { - throw new InvalidOperationException("No image formats have been configured."); - } - - this.MetaData = new ImageMetaData(); - this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } /// @@ -87,12 +80,35 @@ namespace ImageSharp public Image(ImageBase other) : base(other) { + this.MetaData = new ImageMetaData(); + } + + /// + /// Initializes a new instance of the class + /// with the height and the width of the image. + /// + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The images metadata. + /// + /// The configuration providing initialization code which allows extending the library. + /// + internal Image(int width, int height, ImageMetaData metadata, Configuration configuration) + : base(width, height, configuration) + { + if (!this.Configuration.ImageFormats.Any()) + { + throw new InvalidOperationException("No image formats have been configured."); + } + + this.MetaData = metadata ?? new ImageMetaData(); + this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } /// /// Gets the meta data of the image. /// - public ImageMetaData MetaData { get; private set; } = new ImageMetaData(); + public ImageMetaData MetaData { get; private set; } /// /// Gets the width of the image in inches. It is calculated as the width of the image diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index d7d5e88b5f..aed6efa2cb 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -48,7 +48,25 @@ namespace ImageSharp { DebugGuard.NotNull(other, nameof(other)); - this.LoadFrom(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; + } } /// @@ -130,32 +148,5 @@ namespace ImageSharp { this.ExifProfile?.Sync(this); } - - /// - /// Sets the current metadata values based on a previous metadata object. - /// - /// Meta data object to copy values from. - 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; - } - } } } From c1a061194a72ae4dd76e4017ad9182aa6167875d Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 26 Mar 2017 12:44:23 +0100 Subject: [PATCH 10/14] Move config argument to be first argument --- src/ImageSharp/Image.FromBytes.cs | 32 +++++++++---------- src/ImageSharp/Image.FromFile.cs | 32 +++++++++---------- src/ImageSharp/Image.FromStream.cs | 30 ++++++++--------- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 24 +++++++------- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index d23d0baeed..b2f9854f22 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -25,7 +25,7 @@ namespace ImageSharp /// The image public static Image Load(byte[] data) { - return Load(data, null, (Configuration)null); + return Load(null, data, null); } /// @@ -39,21 +39,21 @@ namespace ImageSharp /// The image public static Image Load(byte[] data, IDecoderOptions options) { - return Load(data, options, null); + return Load(null, data, options); } /// /// Loads the image from the given byte array. /// - /// The byte array containing image data. /// The config for the decoder. + /// The byte array containing image data. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] data, Configuration config) + public static Image Load(Configuration config, byte[] data) { - return Load(data, null, config); + return Load(config, data, null); } /// @@ -73,18 +73,18 @@ namespace ImageSharp /// /// Loads the image from the given byte array. /// + /// The configuration options. /// The byte array containing image data. /// The options for the decoder. - /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] data, IDecoderOptions options, Configuration config) + public static Image Load(Configuration config, byte[] data, IDecoderOptions options) { using (MemoryStream ms = new MemoryStream(data)) { - return Load(ms, options, config); + return Load(config, ms, options); } } @@ -118,7 +118,7 @@ namespace ImageSharp public static Image Load(byte[] data) where TColor : struct, IPixel { - return Load(data, null, (Configuration)null); + return Load(null, data, null); } /// @@ -134,23 +134,23 @@ namespace ImageSharp public static Image Load(byte[] data, IDecoderOptions options) where TColor : struct, IPixel { - return Load(data, options, null); + return Load(null, data, options); } /// /// Loads the image from the given byte array. /// /// The pixel format. - /// The byte array containing image data. /// The config for the decoder. + /// The byte array containing image data. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] data, Configuration config) + public static Image Load(Configuration config, byte[] data) where TColor : struct, IPixel { - return Load(data, null, config); + return Load(config, data, null); } /// @@ -173,19 +173,19 @@ namespace ImageSharp /// Loads the image from the given byte array. /// /// The pixel format. + /// The configuration options. /// The byte array containing image data. /// The options for the decoder. - /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(byte[] data, IDecoderOptions options, Configuration config) + public static Image Load(Configuration config, byte[] data, IDecoderOptions options) where TColor : struct, IPixel { using (MemoryStream ms = new MemoryStream(data)) { - return Load(ms, options, config); + return Load(config, ms, options); } } diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index 1710909e18..40cdfe3eff 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -26,7 +26,7 @@ namespace ImageSharp /// The image public static Image Load(string path) { - return Load(path, null, (Configuration)null); + return Load(null, path, null); } /// @@ -40,21 +40,21 @@ namespace ImageSharp /// The image public static Image Load(string path, IDecoderOptions options) { - return Load(path, options, null); + return Load(null, path, options); } /// /// Loads the image from the given file. /// - /// The file path to the image. /// The config for the decoder. + /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string path, Configuration config) + public static Image Load(Configuration config, string path) { - return Load(path, null, config); + return Load(config, path, null); } /// @@ -89,19 +89,19 @@ namespace ImageSharp /// /// Loads the image from the given file. /// + /// The configuration options. /// The file path to the image. /// The options for the decoder. - /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string path, IDecoderOptions options, Configuration config) + public static Image Load(Configuration config, string path, IDecoderOptions options) { config = config ?? Configuration.Default; using (Stream s = config.FileSystem.OpenRead(path)) { - return Load(s, options, config); + return Load(config, s, options); } } @@ -117,7 +117,7 @@ namespace ImageSharp public static Image Load(string path) where TColor : struct, IPixel { - return Load(path, null, (Configuration)null); + return Load(null, path, null); } /// @@ -133,23 +133,23 @@ namespace ImageSharp public static Image Load(string path, IDecoderOptions options) where TColor : struct, IPixel { - return Load(path, options, null); + return Load(null, path, options); } /// /// Loads the image from the given file. /// /// The pixel format. - /// The file path to the image. /// The config for the decoder. + /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string path, Configuration config) + public static Image Load(Configuration config, string path) where TColor : struct, IPixel { - return Load(path, null, config); + return Load(config, path, null); } /// @@ -172,20 +172,20 @@ namespace ImageSharp /// Loads the image from the given file. /// /// The pixel format. + /// The configuration options. /// The file path to the image. /// The options for the decoder. - /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(string path, IDecoderOptions options, Configuration config) + public static Image Load(Configuration config, string path, IDecoderOptions options) where TColor : struct, IPixel { config = config ?? Configuration.Default; using (Stream s = config.FileSystem.OpenRead(path)) { - return Load(s, options, config); + return Load(config, s, options); } } diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 16793e16c7..be807aef44 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -26,7 +26,7 @@ namespace ImageSharp /// The image public static Image Load(Stream stream) { - return Load(stream, null, (Configuration)null); + return Load(null, stream, null); } /// @@ -40,21 +40,21 @@ namespace ImageSharp /// The image public static Image Load(Stream stream, IDecoderOptions options) { - return Load(stream, options, null); + return Load(null, stream, options); } /// /// Loads the image from the given stream. /// - /// The stream containing image information. /// The config for the decoder. + /// The stream containing image information. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(Stream stream, Configuration config) + public static Image Load(Configuration config, Stream stream) { - return Load(stream, null, config); + return Load(config, stream, null); } /// @@ -74,16 +74,16 @@ namespace ImageSharp /// /// Loads the image from the given stream. /// + /// The configuration options. /// The stream containing image information. /// The options for the decoder. - /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(Stream stream, IDecoderOptions options, Configuration config) + public static Image Load(Configuration config, Stream stream, IDecoderOptions options) { - Image image = Load(stream, options, config); + Image image = Load(config, stream, options); return image as Image ?? new Image(image); } @@ -117,7 +117,7 @@ namespace ImageSharp public static Image Load(Stream stream) where TColor : struct, IPixel { - return Load(stream, null, (Configuration)null); + return Load(null, stream, null); } /// @@ -133,23 +133,23 @@ namespace ImageSharp public static Image Load(Stream stream, IDecoderOptions options) where TColor : struct, IPixel { - return Load(stream, options, null); + return Load(null, stream, options); } /// /// Loads the image from the given stream. /// /// The pixel format. - /// The stream containing image information. /// The config for the decoder. + /// The stream containing image information. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(Stream stream, Configuration config) + public static Image Load(Configuration config, Stream stream) where TColor : struct, IPixel { - return Load(stream, null, config); + return Load(config, stream, null); } /// @@ -189,14 +189,14 @@ namespace ImageSharp /// Loads the image from the given stream. /// /// The pixel format. + /// The configuration options. /// The stream containing image information. /// The options for the decoder. - /// The configuration options. /// /// Thrown if the stream is not readable nor seekable. /// /// The image - public static Image Load(Stream stream, IDecoderOptions options, Configuration config) + public static Image Load(Configuration config, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { config = config ?? Configuration.Default; diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index 52b8f6ee28..91b907e192 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -128,7 +128,7 @@ namespace ImageSharp.Tests public void LoadFromStreamWithConfig() { Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, stream); Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); @@ -141,7 +141,7 @@ namespace ImageSharp.Tests public void LoadFromStreamWithTypeAndConfig() { Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, stream); Assert.NotNull(img); Assert.Equal(this.returnImage, img); @@ -155,7 +155,7 @@ namespace ImageSharp.Tests public void LoadFromStreamWithConfigAndOptions() { Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.decoderOptions, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, stream, this.decoderOptions); Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); @@ -168,7 +168,7 @@ namespace ImageSharp.Tests public void LoadFromStreamWithTypeAndConfigAndOptions() { Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.decoderOptions, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, stream, this.decoderOptions); Assert.NotNull(img); Assert.Equal(this.returnImage, img); @@ -276,7 +276,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromBytesWithConfig() { - Image img = Image.Load(this.DataStream.ToArray(), this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); @@ -289,7 +289,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromBytesWithTypeAndConfig() { - Image img = Image.Load(this.DataStream.ToArray(), this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); Assert.NotNull(img); Assert.Equal(this.returnImage, img); @@ -304,7 +304,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromBytesWithConfigAndOptions() { - Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); @@ -317,7 +317,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromBytesWithTypeAndConfigAndOptions() { - Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); Assert.NotNull(img); Assert.Equal(this.returnImage, img); @@ -425,7 +425,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFileWithConfig() { - Image img = Image.Load(this.FilePath, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.FilePath); Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); @@ -437,7 +437,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFileWithTypeAndConfig() { - Image img = Image.Load(this.FilePath, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.FilePath); Assert.NotNull(img); Assert.Equal(this.returnImage, img); @@ -450,7 +450,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFileWithConfigAndOptions() { - Image img = Image.Load(this.FilePath, this.decoderOptions, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.FilePath, this.decoderOptions); Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); @@ -462,7 +462,7 @@ namespace ImageSharp.Tests [Fact] public void LoadFromFileWithTypeAndConfigAndOptions() { - Image img = Image.Load(this.FilePath, this.decoderOptions, this.LocalConfiguration); + Image img = Image.Load(this.LocalConfiguration, this.FilePath, this.decoderOptions); Assert.NotNull(img); Assert.Equal(this.returnImage, img); From a8901f3c9cec097c850b7c8ff989ca07eb80318f Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 26 Mar 2017 15:01:58 +0100 Subject: [PATCH 11/14] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 576ed76d07..86ce5ddd4d 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Here's an example of the code required to resize an image using the default Bicu On platforms supporting netstandard 1.3+ ```csharp -using (Image image = new Image("foo.jpg")) +using (Image image = Image.Load("foo.jpg")) { image.Resize(image.Width / 2, image.Height / 2) .Grayscale() @@ -85,7 +85,7 @@ on netstandard 1.1 - 1.2 ```csharp using (FileStream stream = File.OpenRead("foo.jpg")) using (FileStream output = File.OpenWrite("bar.jpg")) -using (Image image = new Image(stream)) +using (Image image = Image.Load(stream)) { image.Resize(image.Width / 2, image.Height / 2) .Grayscale() From 79ca3c430fde8387540888d0c4787848da748286 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 26 Mar 2017 15:02:13 +0100 Subject: [PATCH 12/14] Increment version --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 2 +- src/ImageSharp/ImageSharp.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index e15bfe74ba..351764bb95 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -2,7 +2,7 @@ An extension to ImageSharp that allows the drawing of images, paths, and text. ImageSharp.Drawing - 1.0.0-alpha4 + 1.0.0-alpha5 James Jackson-South and contributors netstandard1.1 true diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 63cb081c33..c51c0833a0 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp - 1.0.0-alpha4 + 1.0.0-alpha5 James Jackson-South and contributors netstandard1.3;netstandard1.1 true From da1dffd5cccfb634cdfec66518a07d1a48751d4e Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 26 Mar 2017 15:12:14 +0100 Subject: [PATCH 13/14] decoder configuration argument order --- ImageSharp.sln | 3 ++ src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoder.cs | 8 +-- src/ImageSharp/Formats/IImageDecoder.cs | 4 +- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoder.cs | 8 +-- src/ImageSharp/Image.Decode.cs | 2 +- src/ImageSharp/Image.FromStream.cs | 2 +- src/README.md | 7 +++ .../ImageSharp.Tests/Image/ImageLoadTests.cs | 50 +++++++++---------- tests/ImageSharp.Tests/TestFormat.cs | 2 +- 11 files changed, 50 insertions(+), 40 deletions(-) create mode 100644 src/README.md diff --git a/ImageSharp.sln b/ImageSharp.sln index 628fa70153..6e389421e7 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -22,6 +22,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}" + ProjectSection(SolutionItems) = preProject + src\README.md = src\README.md + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{56801022-D71A-4FBE-BC5B-CBA08E2284EC}" EndProject diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 8414807e0c..da5d246372 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -26,7 +26,7 @@ namespace ImageSharp.Formats public class BmpDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 2e56b0baba..2eb89de8ff 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -14,24 +14,24 @@ namespace ImageSharp.Formats public class GifDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options); - return this.Decode(stream, gifOptions, configuration); + return this.Decode(configuration, stream, gifOptions); } /// /// Decodes the image from the specified stream to the . /// /// The pixel format. + /// The configuration. /// The containing image data. /// The options for the decoder. - /// The configuration. /// The image thats been decoded. - public Image Decode(Stream stream, IGifDecoderOptions options, Configuration configuration) + public Image Decode(Configuration configuration, Stream stream, IGifDecoderOptions options) where TColor : struct, IPixel { return new GifDecoderCore(options, configuration).Decode(stream); diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index 8da23d499f..c85fbef101 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -17,11 +17,11 @@ namespace ImageSharp.Formats /// Decodes the image from the specified stream to the . /// /// The pixel format. + /// The configuration for the image. /// The containing image data. /// The options for the decoder. - /// The configuration for the image. /// The decoded image - Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) where TColor : struct, IPixel; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 254506af05..0aac316035 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -14,7 +14,7 @@ namespace ImageSharp.Formats public class JpegDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { Guard.NotNull(stream, "stream"); diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index bf17ad1428..d0a820c17f 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -31,24 +31,24 @@ namespace ImageSharp.Formats public class PngDecoder : IImageDecoder { /// - public Image Decode(Stream stream, IDecoderOptions options, Configuration configuration) + public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); - return this.Decode(stream, pngOptions, configuration); + return this.Decode(configuration, stream, pngOptions); } /// /// Decodes the image from the specified stream to the . /// /// The pixel format. + /// The configuration for the image. /// The containing image data. /// The options for the decoder. - /// The configuration for the image. /// The decoded image. - public Image Decode(Stream stream, IPngDecoderOptions options, Configuration configuration) + public Image Decode(Configuration configuration, Stream stream, IPngDecoderOptions options) where TColor : struct, IPixel { return new PngDecoderCore(options, configuration).Decode(stream); diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index a86a6e948d..c1c1371220 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -67,7 +67,7 @@ namespace ImageSharp return null; } - Image img = format.Decoder.Decode(stream, options, config); + Image img = format.Decoder.Decode(config, stream, options); img.CurrentImageFormat = format; return img; } diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index be807aef44..41ac7757e7 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -182,7 +182,7 @@ namespace ImageSharp public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) where TColor : struct, IPixel { - return WithSeekableStream(stream, s => decoder.Decode(s, options, Configuration.Default)); + return WithSeekableStream(stream, s => decoder.Decode(Configuration.Default, s, options)); } /// diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000000..3764e03cb8 --- /dev/null +++ b/src/README.md @@ -0,0 +1,7 @@ +# ImageSharp core libraries + +## Coding conventions + +### Argument ordering + +- When passing a `Configuration` object it should be the first argument \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index 91b907e192..a7f57ca1c3 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -44,7 +44,7 @@ namespace ImageSharp.Tests this.localFormat.Setup(x => x.IsSupportedFileFormat(It.IsAny())).Returns(true); this.localFormat.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); - this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny(), It.IsAny())) + this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny(), It.IsAny())) .Callback((s, o, c) => { using (var ms = new MemoryStream()) @@ -133,7 +133,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, null, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, null)); } @@ -147,7 +147,7 @@ namespace ImageSharp.Tests Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, null, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, null)); } @@ -160,7 +160,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, this.decoderOptions)); } @@ -174,7 +174,7 @@ namespace ImageSharp.Tests Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, this.decoderOptions)); } @@ -187,7 +187,7 @@ namespace ImageSharp.Tests Image img = Image.Load(stream, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(stream, null, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, null)); } [Fact] @@ -198,7 +198,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(stream, null, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, null)); } [Fact] @@ -208,7 +208,7 @@ namespace ImageSharp.Tests Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, this.decoderOptions)); } [Fact] @@ -219,7 +219,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(stream, this.decoderOptions, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, this.decoderOptions)); } [Fact] @@ -281,7 +281,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), null)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -296,7 +296,7 @@ namespace ImageSharp.Tests Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), null)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -309,7 +309,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), this.decoderOptions)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -323,7 +323,7 @@ namespace ImageSharp.Tests Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), this.decoderOptions)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -335,7 +335,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), null)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -346,7 +346,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), null, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), null)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -356,7 +356,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), this.decoderOptions)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -367,7 +367,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(It.IsAny(), this.decoderOptions, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), this.decoderOptions)); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -430,7 +430,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, null)); } @@ -443,7 +443,7 @@ namespace ImageSharp.Tests Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, null)); } @@ -455,7 +455,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, this.decoderOptions)); } @@ -468,7 +468,7 @@ namespace ImageSharp.Tests Assert.Equal(this.returnImage, img); Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, this.LocalConfiguration)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, this.decoderOptions)); } @@ -479,7 +479,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.FilePath, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, null)); } [Fact] @@ -489,7 +489,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, null, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, null)); } [Fact] @@ -498,7 +498,7 @@ namespace ImageSharp.Tests Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, this.decoderOptions)); } [Fact] @@ -508,7 +508,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(this.DataStream, this.decoderOptions, Configuration.Default)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, this.decoderOptions)); } public void Dispose() diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 5894151dca..084ad59938 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -149,7 +149,7 @@ namespace ImageSharp.Tests } - public Image Decode(Stream stream, IDecoderOptions options, Configuration config) where TColor : struct, IPixel + public Image Decode(Configuration config, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { var ms = new MemoryStream(); From c5c33a730e5b70dc78184e0328812ac8cf5b1e9b Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 26 Mar 2017 17:55:17 +0100 Subject: [PATCH 14/14] fix broken tests --- tests/ImageSharp.Tests/Image/ImageLoadTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index a7f57ca1c3..ddb9414cc4 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -46,7 +46,7 @@ namespace ImageSharp.Tests this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((s, o, c) => { + .Callback((c, s, o) => { using (var ms = new MemoryStream()) { s.CopyTo(ms);