Skip to content

Commit

Permalink
Update Code to use ImageSharpV2 and add generic type for all classes
Browse files Browse the repository at this point in the history
  • Loading branch information
baltermia committed Jun 24, 2022
1 parent f3f6c30 commit eca58b2
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public class ImageSharpBarcodeReader_Tests
private const string CodeText = "ImageSharpBarcodeReader";
private readonly string FolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "codes");

private BarcodeReader reader1D;
private BarcodeReader readerQR;
private BarcodeReader<Rgba32> reader1D;
private BarcodeReader<Rgba32> readerQR;

private Image<Rgba32> barcodeImage;
private Image<Rgba32> qrcodeImage;
Expand All @@ -38,8 +38,8 @@ public void Setup()
barcodeBytes = Convert.FromBase64String(barcodeBase64.Split(',')[1]);
qrcodeBytes = Convert.FromBase64String(qrcodeBase64.Split(',')[1]);

reader1D = new BarcodeReader();
readerQR = new BarcodeReader(types: ZXing.BarcodeFormat.QR_CODE);
reader1D = new BarcodeReader<Rgba32>();
readerQR = new BarcodeReader<Rgba32>(types: ZXing.BarcodeFormat.QR_CODE);
}

[Test]
Expand Down Expand Up @@ -128,11 +128,11 @@ public async Task DecodeWithEventAsync()
}
}

private static void Test(Func<BarcodeResult> func)
private static void Test(Func<BarcodeResult<Rgba32>> func)
{
try
{
BarcodeResult result = func.Invoke();
BarcodeResult<Rgba32> result = func.Invoke();

switch (result.Status)
{
Expand Down
15 changes: 4 additions & 11 deletions BarcodeReader.ImageSharp/BarcodeEventArgs.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
using System;
using SixLabors.ImageSharp.PixelFormats;
using System;

namespace BarcodeReader.ImageSharp
{
/// <summary>
/// EventArgs for BarcodeDetectedEvents but also other events using Barcodes
/// </summary>
public class BarcodeEventArgs : EventArgs
public class BarcodeEventArgs<T> : EventArgs where T : unmanaged, IPixel<T>
{
/// <summary>
/// Decoded value from the barcode as a string
/// </summary>
public BarcodeResult Result { get; }

/// <summary>
/// Creates a new instance of the BarcodeEventArgs class
/// </summary>
public BarcodeEventArgs(BarcodeResult result)
{
Result = result;
}
public BarcodeResult<T> Result { get; set; }
}
}
56 changes: 35 additions & 21 deletions BarcodeReader.ImageSharp/BarcodeReader.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
using System;
using SixLabors;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp;
using ZXing.Common;
using ZXing;
using System;
using System.Threading.Tasks;
using ZXing;
using ZXing.Common;

namespace BarcodeReader.ImageSharp
{
public class BarcodeReader
public class BarcodeReader<T> where T : unmanaged, IPixel<T>
{
/// <summary>
/// Represents the method that will handle the event raised when a barcode is detected
/// </summary>
/// <param name="sender">The object which raises the event</param>
/// <param name="e">Arguments such as the barcode value and bitmap are given through the EventArgs</param>
public delegate void BarcodeDetectedEventHandler(object sender, BarcodeEventArgs e);
public delegate void BarcodeDetectedEventHandler<U>(object sender, BarcodeEventArgs<U> e) where U : unmanaged, IPixel<U>;

/// <summary>
/// Event which is raised when a barcode is detected. It is only raised with the Status Found (0).
/// </summary>
public event BarcodeDetectedEventHandler DetectedBarcode;
public event BarcodeDetectedEventHandler<T> DetectedBarcode;

/// <summary>
/// ZXing BarcodeReader object which is being used for decoding possible barcodes in a bitmap
/// </summary>
private readonly ZXing.ImageSharp.BarcodeReader<Rgba32> reader;
private readonly ZXing.ImageSharp.BarcodeReader<T> reader;

/// <summary>
/// Creates a new instance of the BarcodeReader class. The Constructor will set any settings for decoding barcodes with the Decode() method
Expand All @@ -34,7 +33,7 @@ public class BarcodeReader
/// <param name="performanceMode">The decoder will take less resources to search for the barcodes. By default the mode is set to performance</param>
public BarcodeReader(bool performanceMode = true, params BarcodeFormat[] types)
{
reader = new ZXing.ImageSharp.BarcodeReader<Rgba32>()
reader = new ZXing.ImageSharp.BarcodeReader<T>()
{
AutoRotate = !performanceMode,
Options = new DecodingOptions()
Expand All @@ -53,7 +52,7 @@ public BarcodeReader(bool performanceMode = true, params BarcodeFormat[] types)
/// <param name="type">What type of barcode the provided bitmap should be searched for. By defualt all one-dimensional barcodes will be detected</param>
public BarcodeReader(bool tryHarder, bool autoRotate, params BarcodeFormat[] types)
{
reader = new ZXing.ImageSharp.BarcodeReader<Rgba32>()
reader = new ZXing.ImageSharp.BarcodeReader<T>()
{
AutoRotate = autoRotate,
Options = new DecodingOptions()
Expand All @@ -68,7 +67,7 @@ public BarcodeReader(bool tryHarder, bool autoRotate, params BarcodeFormat[] typ
/// Decodes a barcode from the provided ImageSharp.Image
/// </summary>
/// <returns>Result holding the value if a barcode is found or the error message</returns>
public BarcodeResult Decode(Image<Rgba32> image)
public BarcodeResult<T> Decode(Image<T> image)
{
try
{
Expand All @@ -78,60 +77,75 @@ public BarcodeResult Decode(Image<Rgba32> image)

if (result?.Text != null)
{
BarcodeResult barcodeResult = new BarcodeResult(result.Text, Status.Found, "Barcode found in image", image);
BarcodeResult<T> barcodeResult = new BarcodeResult<T>
{
Message = result.Text,
Status = Status.Found,
Value = result.Text,
Image = image
};

// '?.Invoke' is needed as oherwise an exception would be thrown if ther are no subscribers to the DetectedBarcode event
DetectedBarcode?.Invoke(this, new BarcodeEventArgs(barcodeResult));
DetectedBarcode?.Invoke(this, new BarcodeEventArgs<T> { Result = barcodeResult});

return barcodeResult;
}
else
{
return new BarcodeResult(null, Status.NotFound, "The provided image did not contain a readable barcode", image);
return new BarcodeResult<T>
{
Message = "The provided image did not contain a readable barcode",
Status = Status.NotFound,
Image = image
};
}
}
}
catch (Exception ex)
{
image?.Dispose();

return new BarcodeResult(null, Status.Error, ex.Message, null);
return new BarcodeResult<T>
{
Message = ex.Message,
Status = Status.Error
};
}
}

/// <summary>
/// Decodes a barcode asynchronously from the provided ImageSharp.Image. Make sure to await this method
/// </summary>
/// <returns>Result holding the value if a barcode is found or the error message</returns>
public Task<BarcodeResult> DecodeAsync(Image<Rgba32> image) => Task.Run(() => Decode(image));
public Task<BarcodeResult<T>> DecodeAsync(Image<T> image) => Task.Run(() => Decode(image));

/// <summary>
/// Decodes a barcode from the provided ImageSharp.Image
/// </summary>
/// <param name="data">Array of bytes representing the image</param>
/// <returns>Result holding the value if a barcode is found or the error message</returns>
public BarcodeResult Decode(byte[] data) => Decode(Image.Load(data));
public BarcodeResult<T> Decode(byte[] data) => Decode(Image.Load<T>(data));

/// <summary>
/// Decodes a barcode from the provided ImageSharp.Image
/// </summary>
/// <param name="data">Array of bytes representing the image</param>
/// <returns>Result holding the value if a barcode is found or the error message</returns>
public Task<BarcodeResult> DecodeAsync(byte[] data) => DecodeAsync(Image.Load(data));
public Task<BarcodeResult<T>> DecodeAsync(byte[] data) => DecodeAsync(Image.Load<T>(data));

/// <summary>
/// Decodes a barcode from the provided ImageSharp.Image
/// </summary>
/// <param name="data">Base64 string representing the image</param>
/// <returns>Result holding the value if a barcode is found or the error message</returns>
public BarcodeResult Decode(string data) => Decode(Convert.FromBase64String(RemoveBase64Prefix(data)));
public BarcodeResult<T> Decode(string data) => Decode(Convert.FromBase64String(RemoveBase64Prefix(data)));

/// <summary>
/// Decodes a barcode asynchronously from the provided ImageSharp.Image. Make sure to await this method
/// </summary>
/// <param name="data">Base64 string representing the image</param>
/// <returns>Result holding the value if a barcode is found or the error message</returns>
public Task<BarcodeResult> DecodeAsync(string data) => DecodeAsync(Image.Load(Convert.FromBase64String(RemoveBase64Prefix(data))));
public Task<BarcodeResult<T>> DecodeAsync(string data) => DecodeAsync(Image.Load<T>(Convert.FromBase64String(RemoveBase64Prefix(data))));

/// <summary>
/// Cuts off the prefix of a base64 image string if it has one
Expand Down
21 changes: 5 additions & 16 deletions BarcodeReader.ImageSharp/BarcodeResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,27 @@ namespace BarcodeReader.ImageSharp
/// <summary>
/// Class representing the results after (trying) decoding a barcode from a image
/// </summary>
public class BarcodeResult
public class BarcodeResult<T> where T : unmanaged, IPixel<T>
{
/// <summary>
/// String value of the barcode if one could be decoded
/// </summary>
public string Value { get; }
public string Value { get; set; }

/// <summary>
/// Status of the operation
/// </summary>
public Status Status { get; }
public Status Status { get; set; }

/// <summary>
/// The message. Only really usefull if the Status is Error (2)
/// </summary>
public string Message { get; }
public string Message { get; set; }

/// <summary>
/// The image
/// </summary>
public Image<Rgba32> Image { get; }

/// <summary>
/// Creates a new instance of BarcodeResult
/// </summary>
public BarcodeResult(string value, Status status, string message, Image<Rgba32> image)
{
Value = value;
Status = status;
Message = message;
Image = image;
}
public Image<T> Image { get; set; }
}

/// <summary>
Expand Down

0 comments on commit eca58b2

Please sign in to comment.