diff --git a/.github/workflows/dotnet-windows.yml b/.github/workflows/dotnet-windows.yml index 1c215b3..ef3fb2c 100644 --- a/.github/workflows/dotnet-windows.yml +++ b/.github/workflows/dotnet-windows.yml @@ -40,19 +40,19 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 # Install the .NET workload - name: Install .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x + dotnet-version: 9.0.x # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@2008f912f56e61277eefaac6d1888b750582aa16 + uses: microsoft/setup-msbuild@v2 env: ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' diff --git a/LICENSE b/LICENSE index 0db21e2..1408380 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Alan Barr +Copyright (c) 2020-2024 Alan Barr Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c59cba2..153beae 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Image Processing Library -This image processing library is a lightweight open source library targeting **.NET Standard v2.0**. +This image processing library is a lightweight open source library targeting [.NET Standard v2.0](https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0). This library may be used as an educational tool on how such image processing methods can be implemented, or used within your own projects that require some form of image processing. @@ -8,7 +8,7 @@ See the appropriate section for details on each image processing class and their You are welcome to use/update this software under the terms of the **MIT license**. Notes: -1. **.NET Standard** libraries can be used in **.NET Full Framework** and **.NET Core** (now **.NET 6.0**) projects. +1. **.NET Standard v2.0** libraries can be used in **.NET Full Framework** and **.NET Core** (now known simply as **.NET**) projects. 2. The image processing library is only supported on **Windows OS** due to the dependency on Microsoft's [System.Drawing.Common](https://www.nuget.org/packages/System.Drawing.Common) NuGet package.
@@ -16,25 +16,26 @@ Notes: The published package is available for download on [nuget.org](https://www.nuget.org/packages/Freedom35.ImageProcessing). |Date|Version|Release Notes| |:---|:---:|:----| -|2022/06/16|[1.4.1](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.4.1)|Updated System.Drawing.Common package dependency to v6.0.0.| -|2021/07/30|[1.4.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.4.0)|Added overload methods for converting color images to grayscale.
Added overload methods for converting images to black & white.| -|2021/07/28|[1.3.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.3.0)|Added support for applying sepia filter to images.| -|2021/07/08|[1.2.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.2.0)|Fixed issue with stride padded images causing an *index out of bounds* exception when enhancing contrast.
Fixed issue with RGB color filters not working correctly for images with stride padding and alpha bytes.
Fixed issue with processing images with stride padding and alpha bytes.
Fixed issue where max threshold value was not correctly applied to the red (RGB) byte for color images.
Revision to combine images using bitwise OR.| -|2021/03/24|[1.1.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.1.0)|Added support for applying EXIF orientation data to images.| -|2021/01/26|[1.0.2](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.0.2)|Revision to return rounded value for ImageBytes.GetAverageValue.| -|2021/01/25|[1.0.1](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.0.1)|Revision to add enum description attribute for 'Mexican Hat' smoothing filter.| -|2020/10/02|[1.0.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.0.0)|Initial release.| +|2024-12-28|[1.5.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.5.0)|Updated System.Drawing.Common package dependency to v9.0.0.| +|2022-06-16|[1.4.1](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.4.1)|Updated System.Drawing.Common package dependency to v6.0.0.| +|2021-07-30|[1.4.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.4.0)|Added overload methods for converting color images to grayscale.
Added overload methods for converting images to black & white.| +|2021-07-28|[1.3.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.3.0)|Added support for applying sepia filter to images.| +|2021-07-08|[1.2.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.2.0)|Fixed issue with stride padded images causing an *index out of bounds* exception when enhancing contrast.
Fixed issue with RGB color filters not working correctly for images with stride padding and alpha bytes.
Fixed issue with processing images with stride padding and alpha bytes.
Fixed issue where max threshold value was not correctly applied to the red (RGB) byte for color images.
Revision to combine images using bitwise OR.| +|2021-03-24|[1.1.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.1.0)|Added support for applying EXIF orientation data to images.| +|2021-01-26|[1.0.2](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.0.2)|Revision to return rounded value for ImageBytes.GetAverageValue.| +|2021-01-25|[1.0.1](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.0.1)|Revision to add enum description attribute for 'Mexican Hat' smoothing filter.| +|2020-10-02|[1.0.0](https://www.nuget.org/packages/Freedom35.ImageProcessing/1.0.0)|Initial release.|

# Sample Solutions -The repository contains some sample [Visual Studio](https://visualstudio.microsoft.com) solutions described below. +The repository contains some [Visual Studio](https://visualstudio.microsoft.com) solutions described below. |Name|Description| |-----|-----| |Freedom35.ImageProcessing.sln|Base solution containing image processing library and unit tests.| -|Freedom35.ImageProcessing.WindowsDesktop.sln|Extended solution containing projects from base solution, plus an Image Viewer app for Windows desktop.| +|Freedom35.ImageProcessing.WindowsDesktop.sln|Extended solution containing projects from base solution, plus an **Image Viewer app** for Windows desktop.|

@@ -52,7 +53,7 @@ The **Bitmap** class used is **System.Drawing.Bitmap**. ## Usage in Projects Note: Examples are in C#, but the library may also be used in other .NET language projects. -1. Add the **Image Processing Library** NuGet package to your .NET project. +1. Add the [Image Processing Library](https://www.nuget.org/packages/Freedom35.ImageProcessing) NuGet package to your .NET project. 2. Include the namespace for the Image Processing Library at the top of your code file. ```csharp diff --git a/src/Freedom35.ImageProcessing/Freedom35.ImageProcessing.csproj b/src/Freedom35.ImageProcessing/Freedom35.ImageProcessing.csproj index 84f1f97..12f6814 100644 --- a/src/Freedom35.ImageProcessing/Freedom35.ImageProcessing.csproj +++ b/src/Freedom35.ImageProcessing/Freedom35.ImageProcessing.csproj @@ -5,7 +5,7 @@ .NET Standard library for image processing. Alan Barr (GitHub: freedom35) Alan Barr (GitHub: freedom35) - Copyright © Alan Barr 2022 + Copyright © 2022-2024 Alan Barr https://github.com/freedom35/image-processing false false @@ -15,11 +15,11 @@ git MIT icon.png - 1.4.1 + 1.5.0 - + diff --git a/src/Freedom35.ImageProcessing/ImageConvolution.cs b/src/Freedom35.ImageProcessing/ImageConvolution.cs index db8fef6..12fbe7b 100644 --- a/src/Freedom35.ImageProcessing/ImageConvolution.cs +++ b/src/Freedom35.ImageProcessing/ImageConvolution.cs @@ -115,7 +115,7 @@ public static Bitmap ApplyKernelsThenCombine(Bitmap bitmap, params ConvolutionTy } // Combine to create a new image - bitmap = ImageCombine.All(bitmaps); + Bitmap combinedBitmap = ImageCombine.All(bitmaps); // No longer needed foreach (Bitmap bmp in bitmaps) @@ -123,7 +123,7 @@ public static Bitmap ApplyKernelsThenCombine(Bitmap bitmap, params ConvolutionTy bmp.Dispose(); } - return bitmap; + return combinedBitmap; } /// diff --git a/src/Freedom35.ImageProcessing/ImageFormatting.cs b/src/Freedom35.ImageProcessing/ImageFormatting.cs index 80d2d92..50c83af 100644 --- a/src/Freedom35.ImageProcessing/ImageFormatting.cs +++ b/src/Freedom35.ImageProcessing/ImageFormatting.cs @@ -106,12 +106,7 @@ public static Image ToJPEG(Image image, long compressionLevel) ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); // Find JPEG codec - ImageCodecInfo jpegEncoder = codecs.FirstOrDefault(c => c.FormatID == ImageFormat.Jpeg.Guid); - - if (jpegEncoder == null) - { - throw new Exception("JPEG image encoder not found."); - } + ImageCodecInfo jpegEncoder = codecs.FirstOrDefault(c => c.FormatID == ImageFormat.Jpeg.Guid) ?? throw new Exception("JPEG image encoder not found."); // Create compression parameters EncoderParameters encParams = new EncoderParameters(1); diff --git a/src/ImageViewerApp/EnumConverter.cs b/src/ImageViewerApp/EnumConverter.cs index 9cbd7ee..62e32d3 100644 --- a/src/ImageViewerApp/EnumConverter.cs +++ b/src/ImageViewerApp/EnumConverter.cs @@ -6,6 +6,7 @@ using System.Reflection; using Freedom35.ImageProcessing; +using System.Diagnostics.CodeAnalysis; namespace ImageViewerApp { @@ -35,20 +36,22 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu throw new NotSupportedException(); } - public static T GetValueFromDescription(string description) where T : Enum + public static bool TryGetValueFromDescription(string description, [NotNullWhen(true)] out T? enumValue) where T : Enum { FieldInfo[] fields = typeof(T).GetFields(); - FieldInfo field = fields.FirstOrDefault(f => Attribute.GetCustomAttribute(f, typeof(DescriptionAttribute)) is DescriptionAttribute attr && attr.Description == description); + // Note: Matching enum description attribute (not name) + FieldInfo? field = fields.FirstOrDefault(f => Attribute.GetCustomAttribute(f, typeof(DescriptionAttribute)) is DescriptionAttribute attr && attr.Description == description); if (field != null) { - return (T)field.GetValue(null); - } - else - { - return default; + enumValue = (T?)field.GetValue(null); + return enumValue != null; } + + // Must init + enumValue = default; + return false; } } } diff --git a/src/ImageViewerApp/ImageConverter.cs b/src/ImageViewerApp/ImageConverter.cs index 739c947..e92e4de 100644 --- a/src/ImageViewerApp/ImageConverter.cs +++ b/src/ImageViewerApp/ImageConverter.cs @@ -15,7 +15,7 @@ namespace ImageViewerApp [ValueConversion(typeof(Image), typeof(ImageSource))] internal sealed class ImageConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is Image img) { @@ -33,7 +33,7 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu throw new NotSupportedException(); } - public static BitmapImage ConvertImageToBitmapSource(Image image) + public static BitmapImage? ConvertImageToBitmapSource(Image image) { // First convert to stream using MemoryStream stream = new(); @@ -42,9 +42,9 @@ public static BitmapImage ConvertImageToBitmapSource(Image image) return ConvertStreamToBitmapSource(stream); } - public static BitmapImage ConvertStreamToBitmapSource(MemoryStream stream) + public static BitmapImage? ConvertStreamToBitmapSource(MemoryStream stream) { - BitmapImage bmp = null; + BitmapImage? bmp = null; if (stream != null && stream.CanSeek && stream.CanRead) { diff --git a/src/ImageViewerApp/ImageViewerApp.csproj b/src/ImageViewerApp/ImageViewerApp.csproj index b760203..36ba1b7 100644 --- a/src/ImageViewerApp/ImageViewerApp.csproj +++ b/src/ImageViewerApp/ImageViewerApp.csproj @@ -2,14 +2,15 @@ WinExe - net6.0-windows + net9.0-windows true .NET Core Windows app for demonstrating image processing functions. Alan Barr (GitHub: freedom35) https://github.com/freedom35/image-processing MIT - 1.6.0 + 2.0.0 + enable diff --git a/src/ImageViewerApp/MainWindow.xaml.cs b/src/ImageViewerApp/MainWindow.xaml.cs index b8a2b1b..391e44b 100644 --- a/src/ImageViewerApp/MainWindow.xaml.cs +++ b/src/ImageViewerApp/MainWindow.xaml.cs @@ -2,8 +2,6 @@ using System; using System.Drawing; using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; using System.Drawing.Imaging; using System.Linq; @@ -23,13 +21,13 @@ public MainWindow() private const string SaveFileFilter = "Bitmap|*.bmp|JPEG|*.jpg|PNG|*.png|TIFF|*.tif"; - private Image originalImage = null; - private Image currentImage = null; - private Image previousImage= null; + private Image? originalImage = null; + private Image? currentImage = null; + private Image? previousImage= null; private System.Windows.Point zoomStartPoint = new(-1, -1); - private System.Windows.Input.Cursor defaultCursor = null; + private System.Windows.Input.Cursor? defaultCursor = null; #endregion @@ -49,14 +47,17 @@ private void Window_Loaded(object sender, EventArgs e) { // Check command line args for any 'Open With...' images. // (First arg will be app path) - string imageName = Environment.GetCommandLineArgs().Skip(1).FirstOrDefault(); + string? imageName = Environment.GetCommandLineArgs().Skip(1).FirstOrDefault(); - string[] SupportedImageTypes = { "bmp", "jpg", "png", "tif" }; - - // Open image if valid file type - if (!string.IsNullOrEmpty(imageName) && SupportedImageTypes.Any(t => imageName.EndsWith(t, StringComparison.OrdinalIgnoreCase))) + if (!string.IsNullOrEmpty(imageName)) { - OpenImage(imageName); + string[] SupportedImageTypes = ["bmp", "jpg", "png", "tif"]; + + // Open image if valid file type + if (SupportedImageTypes.Any(t => imageName.EndsWith(t, StringComparison.OrdinalIgnoreCase))) + { + OpenImage(imageName); + } } } @@ -192,8 +193,8 @@ private static void DisplayHistogram(Image sourceImage, System.Windows.Controls. // Create histogram of image Image histogram = ImageHistogram.Create(sourceImage, new System.Drawing.Size((int)targetPictureBox.DesiredSize.Width - 20, (int)targetPictureBox.DesiredSize.Height), - System.Drawing.Color.DodgerBlue, - System.Drawing.Color.White); + Color.DodgerBlue, + Color.White); // Display histogram targetPictureBox.Source = ImageConverter.ConvertImageToBitmapSource(histogram); @@ -258,7 +259,7 @@ private void Button_RestoreImage_Click(object sender, RoutedEventArgs e) } } - private void Button_UndoImageChange_Click(object sender, RoutedEventArgs e) + private void Button_UndoImageChange_Click(object? sender, RoutedEventArgs? e) { if (previousImage != null) { @@ -268,19 +269,25 @@ private void Button_UndoImageChange_Click(object sender, RoutedEventArgs e) private void Button_ApplyConvolution_Click(object sender, RoutedEventArgs e) { - if (currentImage != null && cmbConvolution.SelectedIndex > -1) + // Check an image is loaded + if (currentImage == null) { - string strValue = cmbConvolution.SelectedItem as string; - - ConvolutionType type = EnumConverter.GetValueFromDescription(strValue); + return; + } - try - { - DisplayImage(ImageConvolution.ApplyKernel(currentImage, type)); - } - catch (Exception ex) + // Check a valid filter is selected + if (cmbConvolution.SelectedIndex > -1 && cmbConvolution.SelectedItem is string strValue) + { + if (EnumConverter.TryGetValueFromDescription(strValue, out ConvolutionType type)) { - ReportException(ex); + try + { + DisplayImage(ImageConvolution.ApplyKernel(currentImage, type)); + } + catch (Exception ex) + { + ReportException(ex); + } } } } diff --git a/tests/Freedom35.ImageProcessing.Tests/Freedom35.ImageProcessing.Tests.csproj b/tests/Freedom35.ImageProcessing.Tests/Freedom35.ImageProcessing.Tests.csproj index 0582481..a9441af 100644 --- a/tests/Freedom35.ImageProcessing.Tests/Freedom35.ImageProcessing.Tests.csproj +++ b/tests/Freedom35.ImageProcessing.Tests/Freedom35.ImageProcessing.Tests.csproj @@ -1,14 +1,15 @@ - net6.0-windows + net9.0-windows false Alan Barr (GitHub: freedom35) Alan Barr (GitHub: freedom35) Unit tests for Freedom35.ImageProcessing.dll. - Copyright © Alan Barr + Copyright © 2022-2024 Alan Barr https://github.com/freedom35/image-processing - 1.5.0 + 2.0.0 + enable @@ -30,9 +31,9 @@ - - - + + + diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImage.cs b/tests/Freedom35.ImageProcessing.Tests/TestImage.cs index 5318760..a484733 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImage.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImage.cs @@ -11,7 +11,7 @@ static class TestImage public static Image FromResource(string resourcePath) { // Keep stream open for processing - Stream resourceStream = System.Reflection.Assembly.GetCallingAssembly().GetManifestResourceStream(resourcePath); + Stream? resourceStream = System.Reflection.Assembly.GetCallingAssembly().GetManifestResourceStream(resourcePath) ?? throw new FileNotFoundException($"Unable to load resource: {resourcePath}"); return Image.FromStream(resourceStream); } diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageBinary.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageBinary.cs index 6037673..4724a69 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageBinary.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageBinary.cs @@ -17,15 +17,13 @@ public void TestAsBytes(string sourceResourcePath) // Load source image using Image sourceImage = TestImage.FromResource(sourceResourcePath); - Assert.IsNotNull(sourceImage); - const byte Threshold = 0x7F; // Get bytes for image byte[] imageBytes = ImageBinary.AsBytes(sourceImage, Threshold); // Check we have some bytes - Assert.IsNotNull(imageBytes); + Assert.IsTrue(imageBytes.Length > 0); // Check all converted to binary (0 or 1) Assert.IsTrue(imageBytes.All(b => b < 0x02)); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageBytes.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageBytes.cs index 836910c..cb825b7 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageBytes.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageBytes.cs @@ -17,8 +17,6 @@ public void TestFromResource(string resourcePath) { byte[] imageBytes = ImageBytes.FromResource(resourcePath); - Assert.IsNotNull(imageBytes); - // Check not an empty array Assert.IsTrue(imageBytes.Length > 0); @@ -29,19 +27,19 @@ public void TestFromResource(string resourcePath) [TestMethod] public void TestBytesToBits() { - byte[] byteValues = new byte[] - { + byte[] byteValues = + [ 0xD5, 0x3C - }; + ]; byte[] bitValues = ImageBytes.BytesToBits(byteValues); - byte[] expectedBitValues = new byte[] - { + byte[] expectedBitValues = + [ 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, - }; + ]; // Check expected number in array Assert.AreEqual(expectedBitValues.Length, bitValues.Length); @@ -56,19 +54,19 @@ public void TestBytesToBits() [TestMethod] public void TestBitsToBytes() { - byte[] bitValues = new byte[] - { + byte[] bitValues = + [ 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, - }; + ]; byte[] byteValues = ImageBytes.BitsToBytes(bitValues); - byte[] expectedByteValues = new byte[] - { + byte[] expectedByteValues = + [ 0xD5, 0x3C - }; + ]; // Check expected number in array Assert.AreEqual(expectedByteValues.Length, byteValues.Length); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageColor.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageColor.cs index e17622d..fe2ecf9 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageColor.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageColor.cs @@ -22,7 +22,7 @@ private static byte[] CreateColorImage4x4(out BitmapData bitmapData) PixelFormat = PixelFormat.Format24bppRgb }; - List listBytes = new(); + List listBytes = []; for (int i = 0; i < bitmapData.Width * bitmapData.Height; i++) { @@ -32,7 +32,7 @@ private static byte[] CreateColorImage4x4(out BitmapData bitmapData) listBytes.Add(150); } - return listBytes.ToArray(); + return [.. listBytes]; } [TestMethod] @@ -42,7 +42,6 @@ public void TestConvertToGrayscale() byte[] convertedImage = ImageColor.ToGrayscale(imageBytes, bitmapData); - Assert.IsNotNull(convertedImage); Assert.AreEqual(convertedImage.Length, imageBytes.Length / 3); Assert.AreEqual(convertedImage[0], imageBytes.Average(b => b)); } @@ -62,7 +61,7 @@ public void TestConvertInvalidImageToGrayscale() [TestMethod] public void TestConvertNoImageToGrayscale() { - byte[] imageBytes = Array.Empty(); + byte[] imageBytes = []; BitmapData bitmapData = new() { @@ -79,11 +78,11 @@ public void TestConvertNoImageToGrayscale() [TestMethod] public void TestConvertToBackAndWhite() { - byte[] imageBytes = { + byte[] imageBytes = [ 50, 100, 150 - }; + ]; byte[] convertedImage = ImageColor.ToBlackAndWhite(imageBytes); @@ -103,11 +102,11 @@ public void TestConvertToBackAndWhiteWithThreshold() [TestMethod] public void TestConvertToNegative() { - byte[] imageBytes = { + byte[] imageBytes = [ 0x01, 0xf0, 0x3c - }; + ]; ImageColor.ToNegative(imageBytes); @@ -119,10 +118,10 @@ public void TestConvertToNegative() [TestMethod] public void TestConvertMonochromeToNegative() { - byte[] imageBytes = { + byte[] imageBytes = [ 1, 0 - }; + ]; ImageColor.MonochromeToNegative(imageBytes); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageCombine.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageCombine.cs index d9a24c9..8109774 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageCombine.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageCombine.cs @@ -10,7 +10,7 @@ public class TestImageCombine [TestMethod] public void TestCombineAllNone() { - Bitmap combinedImage = ImageCombine.All(Array.Empty()); + Bitmap? combinedImage = ImageCombine.All(Array.Empty()); Assert.IsNull(combinedImage); } @@ -18,16 +18,14 @@ public void TestCombineAllNone() public void TestCombineAllMixedColor() { using Image colorImage = TestImage.FromResource("Freedom35.ImageProcessing.Tests.Resources.clock.bmp"); - Assert.IsNotNull(colorImage); - + using Image bwImage = TestImage.FromResource("Freedom35.ImageProcessing.Tests.Resources.clock-bw.bmp"); - Assert.IsNotNull(bwImage); - - Image[] imagesToCombine = new Image[] - { + + Image[] imagesToCombine = + [ colorImage, bwImage - }; + ]; Assert.ThrowsException(() => ImageCombine.All(imagesToCombine)); } @@ -36,15 +34,15 @@ public void TestCombineAllMixedColor() public void TestCombineAllOne() { using Image sourceImage = TestImage.FromResource("Freedom35.ImageProcessing.Tests.Resources.clock.bmp"); - Assert.IsNotNull(sourceImage); - - Image[] imagesToCombine = new Image[] - { + + Image[] imagesToCombine = + [ sourceImage - }; + ]; // Combine - Bitmap combinedBitmap = ImageCombine.All(imagesToCombine); + Bitmap? combinedBitmap = ImageCombine.All(imagesToCombine); + Assert.IsNotNull(combinedBitmap); // Convert for byte comparison byte[] sourceBytes = ImageBytes.FromImage(sourceImage); @@ -64,19 +62,18 @@ public void TestCombineAllSame() // Load source image using Image sourceImage = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImage); - + using Image sourceImageCopy = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImageCopy); - - Image[] imagesToCombine = new Image[] - { + + Image[] imagesToCombine = + [ sourceImage, sourceImageCopy - }; + ]; // Combine - Bitmap combinedImage = ImageCombine.All(imagesToCombine); + Bitmap? combinedImage = ImageCombine.All(imagesToCombine); + Assert.IsNotNull(combinedImage); // Convert for byte comparison Bitmap sourceBitmap = ImageFormatting.ToBitmap(sourceImage); @@ -92,18 +89,17 @@ public void TestCombineAllWithNegative() // Load source image using Image sourceImage = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImage); - + using Image negativeCopy = ImageColor.ToNegative(sourceImage); - Assert.IsNotNull(negativeCopy); - - Image[] imagesToCombine = new Image[] - { + + Image[] imagesToCombine = + [ sourceImage, negativeCopy - }; + ]; - Bitmap combinedImage = ImageCombine.All(imagesToCombine); + Bitmap? combinedImage = ImageCombine.All(imagesToCombine); + Assert.IsNotNull(combinedImage); // Get bytes for images byte[] combinedBytes = ImageBytes.FromImage(combinedImage); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageConvolution.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageConvolution.cs index a9a4cfd..f93a136 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageConvolution.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageConvolution.cs @@ -10,12 +10,12 @@ public class TestImageConvolution public void TestApplyKernelGrayscale() { // 4x5 image - byte[] imageBytes = { + byte[] imageBytes = [ 1, 1, 3, 3, 4, 1, 1, 4, 4, 3, 2, 1, 3, 3, 3, 1, 1, 1, 4, 4 - }; + ]; // Grayscale image BitmapData bmpData = new() @@ -34,21 +34,13 @@ public void TestApplyKernelGrayscale() // Apply kernel to bytes byte[] resultBytes = ImageConvolution.ApplyKernel(imageBytes, bmpData, kernelMatrix); - // Edge cases retain original values - //byte[] expectedBytes = { - // 2, 5, 7, 6, 4, - // 2, 4, 7, 7, 3, - // 3, 2, 7, 7, 3, - // 1, 1, 1, 4, 4 - //}; - // Edge cases assigned black value - byte[] expectedBytes = { + byte[] expectedBytes = [ 2, 5, 7, 6, 0, 2, 4, 7, 7, 0, 3, 2, 7, 7, 0, 0, 0, 0, 0, 0 - }; + ]; // Check arrays are same length Assert.AreEqual(expectedBytes.Length, resultBytes.Length); @@ -64,12 +56,12 @@ public void TestApplyKernelGrayscale() public void TestApplyKernelColor() { // 4x5 image (RGB) - byte[] imageBytes = { + byte[] imageBytes = [ 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4 - }; + ]; // Color image BitmapData bmpData = new() @@ -89,12 +81,12 @@ public void TestApplyKernelColor() byte[] resultBytes = ImageConvolution.ApplyKernel(imageBytes, bmpData, kernelMatrix); // Edge cases assigned black value - byte[] expectedBytes = { + byte[] expectedBytes = [ 2, 2, 2, 5, 5, 5, 7, 7, 7, 6, 6, 6, 0, 0, 0, 2, 2, 2, 4, 4, 4, 7, 7, 7, 7, 7, 7, 0, 0, 0, 3, 3, 3, 2, 2, 2, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; + ]; // Check arrays are same length Assert.AreEqual(expectedBytes.Length, resultBytes.Length); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageCopy.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageCopy.cs index c928e09..60cf01b 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageCopy.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageCopy.cs @@ -11,7 +11,7 @@ public class TestImageCopy public void TestFromSourceToDestination(string resourcePath) { // Load source image - using Bitmap sourceBitmap = TestImage.FromResource(resourcePath) as Bitmap; + using Bitmap? sourceBitmap = TestImage.FromResource(resourcePath) as Bitmap; Assert.IsNotNull(sourceBitmap); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageCrop.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageCrop.cs index 21541b0..873d2f0 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageCrop.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageCrop.cs @@ -16,15 +16,11 @@ public void TestByRegion(string resourcePath) // Load source image using Image sourceImage = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImage); - Rectangle region = new(0, 0, sourceImage.Width / 2, sourceImage.Height / 2); // Crop region of image using Image croppedImage = ImageCrop.ByRegion(sourceImage, region); - Assert.IsNotNull(croppedImage); - // Check size Assert.AreEqual(region.Width, croppedImage.Width); Assert.AreEqual(region.Height, croppedImage.Height); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageResize.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageResize.cs index ebd731c..6d2786c 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageResize.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageResize.cs @@ -13,9 +13,7 @@ public void TestImageResizeAsNew(string resourcePath) // Load source image using Image sourceImage = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImage); - - Bitmap bitmap = sourceImage as Bitmap; + Bitmap? bitmap = sourceImage as Bitmap; Assert.IsNotNull(bitmap); @@ -25,7 +23,6 @@ public void TestImageResizeAsNew(string resourcePath) using Image resizedImage = ImageResize.ResizeAsNew(bitmap, width, height); - Assert.IsNotNull(resizedImage); Assert.AreEqual(width, resizedImage.Width); Assert.AreEqual(height, resizedImage.Height); } @@ -37,15 +34,12 @@ public void TestImageResizeAsNewByRatio(string resourcePath) // Load source image using Image sourceImage = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImage); - - Bitmap bitmap = sourceImage as Bitmap; + Bitmap? bitmap = sourceImage as Bitmap; Assert.IsNotNull(bitmap); using Image resizedImage = ImageResize.ResizeAsNew(bitmap, 2.0); - Assert.IsNotNull(resizedImage); Assert.AreEqual(bitmap.Width * 2, resizedImage.Width); Assert.AreEqual(bitmap.Height * 2, resizedImage.Height); } @@ -57,9 +51,7 @@ public void TestImageResizeOriginal(string resourcePath) // Load source image Image sourceImage = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImage); - - Bitmap bitmap = sourceImage as Bitmap; + Bitmap? bitmap = sourceImage as Bitmap; Assert.IsNotNull(bitmap); @@ -83,9 +75,7 @@ public void TestImageResizeOriginalByRatio(string resourcePath) // Load source image Image sourceImage = TestImage.FromResource(resourcePath); - Assert.IsNotNull(sourceImage); - - Bitmap bitmap = sourceImage as Bitmap; + Bitmap? bitmap = sourceImage as Bitmap; Assert.IsNotNull(bitmap); diff --git a/tests/Freedom35.ImageProcessing.Tests/TestImageThreshold.cs b/tests/Freedom35.ImageProcessing.Tests/TestImageThreshold.cs index 41ddc89..c5853ae 100644 --- a/tests/Freedom35.ImageProcessing.Tests/TestImageThreshold.cs +++ b/tests/Freedom35.ImageProcessing.Tests/TestImageThreshold.cs @@ -14,18 +14,12 @@ public void TestApplyThreshold(string sourceResourcePath, string resultResourceP // Load source image using Image sourceImage = TestImage.FromResource(sourceResourcePath); - Assert.IsNotNull(sourceImage); - // Apply Thresholding - currently uses Otsu as default using Image thresholdImage = ImageThreshold.Apply(sourceImage); - Assert.IsNotNull(thresholdImage); - // Load correct result image using Image resultImage = TestImage.FromResource(resultResourcePath); - Assert.IsNotNull(resultImage); - // Compare images Assert.IsTrue(TestImage.Compare(thresholdImage, resultImage)); } @@ -37,18 +31,12 @@ public void TestOtsuThreshold(string sourceResourcePath, string resultResourcePa // Load source image using Image sourceImage = TestImage.FromResource(sourceResourcePath); - Assert.IsNotNull(sourceImage); - // Apply Thresholding using Image thresholdImage = ImageThreshold.ApplyOtsuMethod(sourceImage); - Assert.IsNotNull(thresholdImage); - // Load correct result image using Image resultImage = TestImage.FromResource(resultResourcePath); - Assert.IsNotNull(resultImage); - // Compare images Assert.IsTrue(TestImage.Compare(thresholdImage, resultImage)); } @@ -63,12 +51,9 @@ public void TestApplyThresholdValue(string sourceResourcePath) // Load source image using Image sourceImage = TestImage.FromResource(sourceResourcePath); - Assert.IsNotNull(sourceImage); - // Apply threshold using Image thresholdImage = ImageThreshold.Apply(sourceImage, 0x40); - Assert.IsNotNull(thresholdImage); - + byte[] withoutAlphaBytes = RemoveAlphaLayerBytes(ImageBytes.FromImage(thresholdImage), sourceImage.PixelFormat); // Check bytes thresholded @@ -85,13 +70,9 @@ public void TestApplyMin(string sourceResourcePath) // Load source image using Image sourceImage = TestImage.FromResource(sourceResourcePath); - Assert.IsNotNull(sourceImage); - // Apply min value using Image minImage = ImageThreshold.ApplyMin(sourceImage, 0x20); - Assert.IsNotNull(minImage); - byte[] withoutAlphaBytes = RemoveAlphaLayerBytes(ImageBytes.FromImage(minImage), sourceImage.PixelFormat); // Check all greater than value @@ -108,13 +89,9 @@ public void TestApplyMax(string sourceResourcePath) // Load source image using Image sourceImage = TestImage.FromResource(sourceResourcePath); - Assert.IsNotNull(sourceImage); - // Apply max value using Image maxImage = ImageThreshold.ApplyMax(sourceImage, 0xD0); - Assert.IsNotNull(maxImage); - byte[] withoutAlphaBytes = RemoveAlphaLayerBytes(ImageBytes.FromImage(maxImage), sourceImage.PixelFormat); // Check all less than value @@ -131,13 +108,9 @@ public void TestApplyMinMax(string sourceResourcePath) // Load source image using Image sourceImage = TestImage.FromResource(sourceResourcePath); - Assert.IsNotNull(sourceImage); - // Apply min/max value using Image minMaxImage = ImageThreshold.ApplyMinMax(sourceImage, 0x25, 0xc3); - Assert.IsNotNull(minMaxImage); - byte[] withoutAlphaBytes = RemoveAlphaLayerBytes(ImageBytes.FromImage(minMaxImage), sourceImage.PixelFormat); // Check all within range