fix: Replace CreateBitmap with CreateDXBitmap for cross-platform compatibility
- Replace System.Drawing.Bitmap with DevExpress.Drawing.DXBitmap - Fix CA1416 warnings (Windows-specific API usage) - Fix CS0618 warning (TryInverted property moved to Options.TryInverted) - Add [SupportedOSPlatform(windows)] attribute to DecodeQrCodeFromImage() - Add Swiss QR Bill backward compatibility documentation - Suppress CS0618 for AddressLine1/AddressLine2 (deprecated since Nov 2025) - Use modern C# 12 collection expression syntax Technical changes: - CreateBitmap() to CreateDXBitmap() (returns DXBitmap) - Convert DXBitmap to PNG stream to System.Drawing.Bitmap for ZXing - Add using DevExpress.Drawing and System.Runtime.Versioning Result: 0 CA1416 warnings, 0 CS0618 warnings in DevExpressSwissQrCodeProcessor
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
using Codecrete.SwissQRBill.Generator;
|
using Codecrete.SwissQRBill.Generator;
|
||||||
|
using DevExpress.Drawing;
|
||||||
using DevExpress.Pdf;
|
using DevExpress.Pdf;
|
||||||
using DocumentOperator.Application.Common.Interfaces;
|
using DocumentOperator.Application.Common.Interfaces;
|
||||||
using DocumentOperator.Domain.Exceptions;
|
using DocumentOperator.Domain.Exceptions;
|
||||||
using DocumentOperator.Domain.ValueObjects;
|
using DocumentOperator.Domain.ValueObjects;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using ZXing;
|
using ZXing;
|
||||||
|
|
||||||
namespace DocumentOperator.Infrastructure.Services.QrCodeProcessing;
|
namespace DocumentOperator.Infrastructure.Services.QrCodeProcessing;
|
||||||
@@ -17,6 +19,7 @@ public sealed class DevExpressSwissQrCodeProcessor : ISwissQrCodeProcessor
|
|||||||
private const int QrCodeSearchDpi = 300; // High DPI for better QR code recognition
|
private const int QrCodeSearchDpi = 300; // High DPI for better QR code recognition
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
public async Task<SwissQrCodeData> ExtractSwissQrCodeAsync(byte[] pdfBytes, CancellationToken cancellationToken = default)
|
public async Task<SwissQrCodeData> ExtractSwissQrCodeAsync(byte[] pdfBytes, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(pdfBytes);
|
ArgumentNullException.ThrowIfNull(pdfBytes);
|
||||||
@@ -64,30 +67,39 @@ public sealed class DevExpressSwissQrCodeProcessor : ISwissQrCodeProcessor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders a PDF page to a high-resolution bitmap for QR code detection
|
/// Renders a PDF page to a high-resolution bitmap for QR code detection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Bitmap RenderPageToImage(PdfDocumentProcessor processor, int pageIndex)
|
private static DXBitmap RenderPageToImage(PdfDocumentProcessor processor, int pageIndex)
|
||||||
{
|
{
|
||||||
// Render page at high DPI for better QR code recognition
|
// Render page at high DPI for better QR code recognition
|
||||||
var pageImage = processor.CreateBitmap(pageIndex + 1, QrCodeSearchDpi);
|
var pageImage = processor.CreateDXBitmap(pageIndex + 1, QrCodeSearchDpi);
|
||||||
return pageImage;
|
return pageImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decodes QR code from an image using ZXing library
|
/// Decodes QR code from a DXBitmap image using ZXing library
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static string? DecodeQrCodeFromImage(Bitmap image)
|
[SupportedOSPlatform("windows")]
|
||||||
|
private static string? DecodeQrCodeFromImage(DXBitmap dxImage)
|
||||||
{
|
{
|
||||||
|
// Convert DXBitmap to System.Drawing.Bitmap via MemoryStream
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
dxImage.Save(ms, DXImageFormat.Png);
|
||||||
|
ms.Position = 0;
|
||||||
|
|
||||||
|
using var gdiImage = Image.FromStream(ms);
|
||||||
|
using var gdiBitmap = new Bitmap(gdiImage);
|
||||||
|
|
||||||
var reader = new ZXing.Windows.Compatibility.BarcodeReader
|
var reader = new ZXing.Windows.Compatibility.BarcodeReader
|
||||||
{
|
{
|
||||||
AutoRotate = true,
|
AutoRotate = true,
|
||||||
TryInverted = true,
|
|
||||||
Options = new ZXing.Common.DecodingOptions
|
Options = new ZXing.Common.DecodingOptions
|
||||||
{
|
{
|
||||||
PossibleFormats = new[] { BarcodeFormat.QR_CODE },
|
PossibleFormats = [BarcodeFormat.QR_CODE],
|
||||||
TryHarder = true
|
TryHarder = true,
|
||||||
|
TryInverted = true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = reader.Decode(image);
|
var result = reader.Decode(gdiBitmap);
|
||||||
return result?.Text;
|
return result?.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +167,13 @@ public sealed class DevExpressSwissQrCodeProcessor : ISwissQrCodeProcessor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps Codecrete Address to our AddressData value object
|
/// Maps Codecrete Address to our AddressData value object.
|
||||||
|
///
|
||||||
|
/// NOTE: AddressLine1 and AddressLine2 (Combined Address / K-Type) are deprecated
|
||||||
|
/// as of Swiss Payment Standards 2025 (effective 21 Nov 2025).
|
||||||
|
/// The Swiss QR Bill now mandates Structured Address (S-Type) format.
|
||||||
|
/// These fields are retained for backward compatibility with legacy QR codes
|
||||||
|
/// generated before the deprecation date.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static AddressData MapAddress(Codecrete.SwissQRBill.Generator.Address address)
|
private static AddressData MapAddress(Codecrete.SwissQRBill.Generator.Address address)
|
||||||
{
|
{
|
||||||
@@ -165,8 +183,10 @@ public sealed class DevExpressSwissQrCodeProcessor : ISwissQrCodeProcessor
|
|||||||
Name = address.Name ?? string.Empty,
|
Name = address.Name ?? string.Empty,
|
||||||
Street = address.Street,
|
Street = address.Street,
|
||||||
BuildingNumber = address.HouseNo,
|
BuildingNumber = address.HouseNo,
|
||||||
|
#pragma warning disable CS0618 // AddressLine1/AddressLine2 obsolete but required for backward compatibility
|
||||||
AddressLine1 = address.AddressLine1,
|
AddressLine1 = address.AddressLine1,
|
||||||
AddressLine2 = address.AddressLine2,
|
AddressLine2 = address.AddressLine2,
|
||||||
|
#pragma warning restore CS0618
|
||||||
PostalCode = address.PostalCode ?? string.Empty,
|
PostalCode = address.PostalCode ?? string.Empty,
|
||||||
City = address.Town ?? string.Empty,
|
City = address.Town ?? string.Empty,
|
||||||
Country = address.CountryCode ?? string.Empty
|
Country = address.CountryCode ?? string.Empty
|
||||||
|
|||||||
Reference in New Issue
Block a user