diff --git a/src/ImageSharp/Image/PixelArea{TColor}.cs b/src/ImageSharp/Image/PixelArea{TColor}.cs index 2f631f66e..673fe5500 100644 --- a/src/ImageSharp/Image/PixelArea{TColor}.cs +++ b/src/ImageSharp/Image/PixelArea{TColor}.cs @@ -79,6 +79,17 @@ namespace ImageSharp this.PixelBase = (byte*)this.dataPointer.ToPointer(); } + /// + /// Initializes a new instance of the class. + /// + /// The width. + /// The height. + /// The component order. + public PixelArea(int width, int height, ComponentOrder componentOrder) + : this(width, height, componentOrder, 0) + { + } + /// /// Initializes a new instance of the class. /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs index 08efe5c89..6e0977541 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs @@ -8,6 +8,8 @@ using Xunit.Abstractions; namespace ImageSharp.Tests.Formats.Jpg { + using ImageSharp.Tests.TestUtilities; + public class JpegTests { @@ -19,60 +21,43 @@ namespace ImageSharp.Tests.Formats.Jpg { Output = output; } + public static IEnumerable AllJpegFiles => TestImages.Jpeg.All; - protected string CreateTestOutputFile(string fileName) - { - if (!Directory.Exists(TestOutputDirectory)) - { - Directory.CreateDirectory(TestOutputDirectory); - } - - //string id = Guid.NewGuid().ToString().Substring(0, 4); - - string ext = Path.GetExtension(fileName); - fileName = Path.GetFileNameWithoutExtension(fileName); - - return $"{TestOutputDirectory}/{fileName}{ext}"; - } - - protected Stream CreateOutputStream(string fileName) - { - fileName = CreateTestOutputFile(fileName); - Output?.WriteLine("Opened for write: "+fileName); - return File.OpenWrite(fileName); - } - - public static IEnumerable AllJpegFiles - => TestImages.Jpeg.All.Select(file => new object[] {TestFile.Create(file)}); - + // TODO: Turned off PixelTypes.All to be CI-friendly, what should be the practice? [Theory] - [MemberData(nameof(AllJpegFiles))] - public void OpenJpeg_SaveBmp(TestFile file) + //[WithFileCollection(nameof(AllJpegFiles), PixelTypes.All)] + [WithFileCollection(nameof(AllJpegFiles), PixelTypes.Color | PixelTypes.Argb)] + public void OpenJpeg_SaveBmp(TestImageFactory factory) + where TColor : struct, IPackedPixel, IEquatable { - string bmpFileName = file.FileNameWithoutExtension + ".bmp"; + var image = factory.Create(); - var image = file.CreateImage(); - - using (var outputStream = CreateOutputStream(bmpFileName)) - { - image.Save(outputStream, new BmpFormat()); - } + factory.Utility.SaveTestOutputFile(image, "bmp"); } - public static IEnumerable AllBmpFiles - => TestImages.Bmp.All.Select(file => new object[] { TestFile.Create(file) }); + + public static IEnumerable AllBmpFiles => TestImages.Bmp.All; [Theory] - [MemberData(nameof(AllBmpFiles))] - public void OpenBmp_SaveJpeg(TestFile file) + [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.Argb, JpegSubsample.Ratio420, 75)] + [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.Argb, JpegSubsample.Ratio444, 75)] + public void OpenBmp_SaveJpeg(TestImageFactory factory, JpegSubsample subSample, int quality) + where TColor : struct, IPackedPixel, IEquatable { - string jpegPath = file.FileNameWithoutExtension + ".jpeg"; + var image = factory.Create(); - var image = file.CreateImage(); + var utility = factory.Utility; + utility.TestName += "_" + subSample + "_Q" + quality; - using (var outputStream = CreateOutputStream(jpegPath)) + using (var outputStream = File.OpenWrite(utility.GetTestOutputFileName("jpg"))) { - image.Save(outputStream, new JpegFormat()); + var encoder = new JpegEncoder() + { + Subsample = subSample, + Quality = quality + }; + + image.Save(outputStream, encoder); } } } diff --git a/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs b/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs index e47678d0c..39503d1da 100644 --- a/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs +++ b/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs @@ -6,6 +6,9 @@ namespace ImageSharp.Tests { using System; + using System.Numerics; + + using ImageSharp.Tests.TestUtilities; using Xunit; @@ -14,6 +17,114 @@ namespace ImageSharp.Tests /// public class PixelAccessorTests { + public static Image CreateTestImage() + where TColor : struct, IPackedPixel, IEquatable + { + Image image = new Image(10, 10); + + using (var pixels = image.Lock()) + { + for (int i = 0; i < 10; i++) + { + for (int j = 0; j < 10; j++) + { + Vector4 v = new Vector4(i, j, 0, 1); + v /= 10; + + TColor color = default(TColor); + color.PackFromVector4(v); + + pixels[i, j] = color; + } + } + } + return image; + } + + [Theory] + [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.XYZ)] + [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.ZYX)] + [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.XYZW)] + [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.ZYXW)] + public void CopyTo_Then_CopyFrom_OnFullImageRect(TestImageFactory factory, ComponentOrder order) + where TColor : struct, IPackedPixel, IEquatable + { + var src = factory.Create(); + + var dest = new Image(src.Width, src.Height); + + using (PixelArea area = new PixelArea(src.Width, src.Height, order)) + { + using (var srcPixels = src.Lock()) + { + srcPixels.CopyTo(area, 0, 0); + } + + using (var destPixels = dest.Lock()) + { + destPixels.CopyFrom(area, 0, 0); + } + } + + Assert.True(src.IsEquivalentTo(dest, false)); + } + + // TODO: Need a processor in the library with this signature + private static void Fill(Image image, Rectangle region, TColor color) + where TColor : struct, IPackedPixel, IEquatable + { + using (var pixels = image.Lock()) + { + for (int y = region.Top; y < region.Bottom; y++) + { + for (int x = region.Left; x < region.Right; x++) + { + pixels[x, y] = color; + } + } + } + } + + [Theory] + [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.XYZ)] + [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.ZYX)] + [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.XYZW)] + [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.ZYXW)] + public void CopyTo_Then_CopyFrom_WithOffset(TestImageFactory factory, ComponentOrder order) + where TColor : struct, IPackedPixel, IEquatable + + { + var srcImage = factory.Create(); + + var color = default(TColor); + color.PackFromBytes(255, 0, 0, 255); + + Fill(srcImage, new Rectangle(4, 4, 8, 8), color); + + var destImage = new Image(8, 8); + + using (var srcPixels = srcImage.Lock()) + { + using (var area = new PixelArea(8, 8, order)) + { + srcPixels.CopyTo(area, 4, 4); + + using (var destPixels = destImage.Lock()) + { + destPixels.CopyFrom(area, 0, 0); + } + } + } + + factory.Utility.SourceFileOrDescription = order.ToString(); + factory.Utility.SaveTestOutputFile(destImage, "bmp"); + + var expectedImage = new Image(8, 8).Fill(color); + + Assert.True(destImage.IsEquivalentTo(expectedImage)); + } + + [Fact] public void CopyFromZYX() { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 798e397bd..5c41ca248 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -18,18 +18,18 @@ namespace ImageSharp.Tests.TestUtilities public class ImagingTestCaseUtility { /// - /// Name of the TColor in the owner + /// Name of the TColor in the owner /// public string PixelTypeName { get; set; } = string.Empty; /// - /// The name of the file which is provided by + /// The name of the file which is provided by /// Or a short string describing the image in the case of a non-file based image provider. /// public string SourceFileOrDescription { get; set; } = string.Empty; /// - /// The name of the test class (by default) + /// By default this is the name of the test class, but it's possible to change it /// public string TestGroupName { get; set; } = string.Empty; @@ -75,7 +75,7 @@ namespace ImageSharp.Tests.TestUtilities string pixName = this.PixelTypeName; if (pixName != string.Empty) { - pixName = '_' + pixName + ' '; + pixName = '_' + pixName; } return $"{this.GetTestOutputDir()}/{this.TestName}{pixName}{fn}{extension}";