Loading...
Willow Media

.NET Everywhere - Windows, Linux, and Beyond - Het einde van System.Drawing is in zicht

Afgelopen weken werd tijdens het DotNet Conference 2021 de nieuwste telg in de .Net familie geïntroduceerd door Microsoft. Veel nieuws was het niet, want het meeste was natuurlijk al lang bekend in de communities. Wel wordt er met .Net 6 de volgende stap in de toekomst gezet. Al het nieuws kan o.a. op YouTube bekeken worden, dus daar zal ik me verder niet over uitweiden.

Een stap naar de toekomst van Microsoft is een unified platform voor grafische applicaties, .Net Maui. Hoewel ze al eerder pogingen gedaan hebben om WinForms uit te bannen (de oudste manier van GUI applicaties maken in .Net, geloof ik), worden de GDI applicaties in Windows 10 en 11 nog steeds ondersteund. In Windows 10 is er zelfs een aardige upgrade aan deze libary gegeven om te zorgen dat deze applicaties enigszins goed getoond werden op schermen waarbij de desktop geschaalt wordt.

Een interessante stap vooruit wordt gemaakt met .Net 6 is System.Drawing(.Common). Waar dit vroeger de manier was om iets grafisch te ondernemen (GDI+), is nu de stap genomen om deze Library als "Windows Only" te bestempelen. Tot voorheen kon mono-libgdiplus van het Mono project gebruikt worden om op andere systemen toch gebruik te maken van System.Drawing. Het was hiermee zelfs mogelijk om sommige Windows Forms (GDI+) applicaties te gebruiken op Linux en MacOS. Overigens heb ik het daar nooit voor gebruikt, maar wel voor het gebruik van de Image en Bitmap classes. Een concreet voorbeeld is het decoderen van QR-Codes vanuit gescande PDF's. Mono-libgdiplus wordt overigens al langere tijd niet meer actief onderhouden.

Met de overstap naar .Net 6 werkt dit niet simpelweg niet meer als je geen Windows gebruikt. Nou zou je kunnen kiezen om delen van de code via .Net 5 laten draaien, maar in de toekomst gaat dit toch echt wel problemen opleveren. Dus maak ik liever de stap om het future-proof te maken.

ImageSharp

Inmiddels zijn er meerdere alternatieven gemaakt voor System.Drawing. Het nadeel is dat dit nooit drop-in-replacements zijn, dus er is wel wat meer werk voor nodig. ImageSharp is zo'n project dat een volledige 'managed' 2D grafische tool wil bieden voor .Net

ImageSharp is a new, fully featured, fully managed, cross-platform, 2D graphics library. Designed to simplify image processing, ImageSharp brings you an incredibly powerful yet beautifully simple API.

ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations.

Built against .NET Standard 1.3, ImageSharp can be used in device, cloud, and embedded/IoT scenarios.

Één van de toepassingen waarvoor ik zo'n Library nodig heb, is het onttrekken van plaatjes vanuit PDF's. Deze PDF's zijn scans van A4 en A3 bladen via een multifunctionele printer. De PDF's worden geopend via ITextSharp. Hierbij kunnen alle objecten in een PDF terug gevonden worden, zo ook de plaatjes. Deze plaatjes zijn echter niet altijd direct te gebruiken, dus zullen ze omgezet moeten worden naar iets bruikbaars. Door ImageSharp te gebruiken wordt dit een stuk simpeler dan voorheen:

using System.IO;
using iTextSharp.text.pdf.parser;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace WillowMedia.Common.Pdf.Reader
{
    public static class PdfImageObjectExtensions
    {
        public static Image<Rgba32> GetDrawingImage(this PdfImageObject pdfImageObject)
        {
            var r = pdfImageObject.GetImageAsBytes();
            if (r == null)
                return null;

            var image = Image.Load(new MemoryStream(r));

            return image.CloneAs<Rgba32>();
        }
    }
}

Image.Load is de ImageSharp functie, die eenvoudig het PDF plaatje als image object omzet. Via CloneAs<Rbga32> krijg ik hierbij een voor mij bruikbaar object terug.

Maar wat heb je eraan als deze objecten door geen andere Library ondersteund worden? In mijn geval is dat niet het geval. ZXing.net snapt de Image object van ImageSharp niet direct, maar via het ZXing.Net.Bindings.ImageSharp Nuget package wordt deze wel ondersteund:

 public IBarcodeReader<Image<Rgba32>> GetQrCodeBarcodeReader()
{
    var reader = new ZXing.BarcodeReader<Image<Rgba32>>(CreateLuminanceSource);
    reader.Options.PossibleFormats = new List<BarcodeFormat>() {
        BarcodeFormat.QR_CODE
    };
    return reader;
}

private BaseLuminanceSource CreateLuminanceSource(Image<Rgba32> image)
{
    return new ImageSharpLuminanceSource<Rgba32>(image);
}

ZXing.net kan hierdoor de plaatjes wel inspecteren en doorzoeken op barcodes. Dit binding project is nog wel in Beta, maar tot zover bekend goed inzetbaar.

.Net 6 neemt hiermee de eerste stappen om het verleden achter ons te laten. We kunnen niet simpelweg door blijven gaan om altijd compatible te blijven met het verleden. Dit zou slecht zijn voor innovatie. Windows zelf heeft dit al heel lang gedaan en uiteraard hoeven ze (en ook niet wenselijk) de ondersteuning niet direct te dumpen. Via een goed alternatief zou het simpel gemaakt moeten worden om over te stappen naar iets nieuws. Of dit .Net Maui zal zijn, moet nog blijken natuurlijk. Ik ben voorlopig weer geholpen.

  • .Net
  • dotnet