giovedì 16 marzo 2023

C# .Net 7 lettura e creazione barcode anche nei file PDF




In questo articolo vedremo come utilizzare la libreria Zxing, per la generazione e lettura dei codici a barra e della libreria gratuita PdfSharp che permette la gestione dei file pdf.
L’articolo vuole fornire al lettore la creazione e lettura dei codice a barre, detti barcode, tramite applicazioni di tipo “Windows Application” con la versione del Framework 7, utilizzando l’ambiente di sviluppo Visual Studio 2022 Community ed il linguaggio di programmazione C#.
In particolare vedremo come si creano codici a barra dal testo e come leggere codici a barra da un file immagine o direttamente da un file di tipo Pdf.

Creazione del progetto

Si crea un nuovo progetto di tipo “App  Windows Forms”, assegnando un nome al progetto ed una determinata cartella (anche quella di default va bene) e selezionando come versione del Framework la 7.
Dopo aver creato il progetto posizioniamo nella form, due caselle di testo, tre controlli di tipo button, ed un controllo picturebox1, il tutto come mostrato in figura 1.
Figura 1 – La finestra con la generazione del codice a barra

Terminata la fase di posizionamento dei controlli, non resta che aggiungere al nostro progetto i riferimenti Nuget, delle librerie, in particolare della libreria Zxing, che al momento scriviamo è la 0.16.8 (https://www.nuget.org/packages/ZXing.Net/0.16.8) e due librerie per gestire i riferimenti grafici, che sono ZXing.Net.Bindings.ImageSharp e ZXing.Net.Bindings.Windows.Compatibility queste per gestire i codici a barra, mentre per i file pdf, la libreria PdfSharp https://www.nuget.org/packages/PDFsharp/1.50.5147 che al momento della pubblicazione dell’articolo è la versione 1.50.5147 , i componenti da installare devono essere quelli presenti in figura 2.

Figura 2 - La finestra Nuget con i componenti installati.

Terminata l’installazione dei componenti non resta che scrivere il codice.

Stesura del codice

Passiamo in visualizzazione codice in modo che possiamo scrivere le prime istruzioni di codice, in particolar modo aggiungere lo spazio dei nomi delle classi delle librerie.
Per passare in visualizzazione codice, o tramite la voce “Visualizzazione codice (tasto F7) “ oppure tramite doppio click sulla form, in modo da passare nell’evento load della form.
In alto sopra ad ogni dichiarazione, dobbiamo scrivere lo spazio dei nomi per la gestione del barcode e dei file pdf, tramite le librerie aggiunte prima.
Sopra aggiungiamo i seguenti nomi di spazio.


C#

using PdfSharp.Pdf;

using PdfSharp.Pdf.Advanced;

using PdfSharp.Pdf.IO;

using System.Drawing;

using ZXing;

using ZXing.Client.Result;

using ZXing.Common;

using ZXing.ImageSharp;

using ZXing.PDF417.Internal;

using ZXing.QrCode;

using ZXing.QrCode.Internal;

using ZXing.Rendering;

using ZXing.Windows.Compatibility;





Terminata questa parte, passiamo in visualizzazione grafica e facciamo doppio click sul primo pulsante, quello in alto, che permetterà di generare il barcode e visualizzarlo nel controllo picturebox.
Al doppio click sul pulsante, si passerà in visualizzazione codice, dell’evento click del pulsante, tramite la classe barcodeWriter, impostando alcune proprietà come il formato, il tipo di immagine bitmap e le dimensioni andremo ad impostare il formato del barcode, mentre con il metodo “Write” passando il testo presente nella casella di testo, andremo generare un oggetto di tipo Bitmap con l’immagine delle barre del testo passato. 
L’immagine Bitmap verrà salvata anche sul pc in un determinato percorso ed in formato “Jpeg”,
Di seguito si riporta il codice delle suddette operazioni.


C#

private void BtnGenera_Click(object sender, EventArgs e)

        {

            try

            {

 

 

                var GeneraBarcode = new BarcodeWriter

                {

                    Format = BarcodeFormat.CODE_128,

                    Options = new EncodingOptions

                    {

                        Height = 100,

                        Width = 100

                    },

                    Renderer = (IBarcodeRenderer<Bitmap>)Activator.CreateInstance(Renderer)

                };

                var risultato = GeneraBarcode.Write(TxtTesto.Text);

                var barcodeBitmap = new Bitmap(risultato);

                pictureBox1.Image = risultato;

                barcodeBitmap.Save(@"C:\Varie\Barcode2.Jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);

 

 

 

 

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

 

 

 

        }


Ora non resta che testare il codice appena scritto, facendo attenzione a cambiare il percorso dove salvare il file, per testare quanto scritto.
Appurato la correttezza del codice, non resta che scrivere il codice per la selezione del file per la lettura del codice a barra.
Nel pulsante che si trova accanto alla seconda casella di testo, che è stata denominata “BtnCerca”, verrà una visualizzata una dialog per selezionare il file immagine o pdf al quale estrapolare il testo presente nell’immagine del barcode.
Facciamo doppio click su tale pulsante, in modo da passare in visualizzazione codice dell’evento del pulsante, utilizzando la classe dialog, impostando un filtro, riporteremo nella casella accanto, il percorso e nome del file selezionato.
Qui di seguito il frammento di codice delle suddette operazioni.


C#

  private void BtnCerca_Click(object sender, EventArgs e)

        {

             using (OpenFileDialog openDlg = new OpenFileDialog())

            {

                openDlg.FileName = TxtPercorsoNomeFile.Text;

                openDlg.Multiselect = false;

                openDlg.Filter = "PNG Files (*.png)|*.png|BMP Files (*.bmp)|*.bmp|TIFF Files (*.tif)|*.tif|JPG Files (*.jpg)|*.jpg|JEPG Files (*.jpeg)|*.jpeg|PDF Files (*.pdf)|*.pdf|Tutti Files (*.*)|*.*";

                if (openDlg.ShowDialog(this) == DialogResult.OK)

                {

                    TxtPercorsoNomeFile.Text = openDlg.FileName;

                }

             }

        }





Terminata la stesura della selezione dei file, non resta che scrivere il codice di alcune funzioni per la lettura del codice a barre delle immagini presenti nel file di tipo “Pdf”. Rimanendo sempre in visualizzazione codice, scriviamo una funzione che dato un oggetto di tipo “PdfDictionary” restituisce un oggetto di tipo Bitmap.
Si riporta qui di seguito il frammento della funzione.


C#

private   Bitmap EsportaImmagineJpeg(PdfDictionary image)

        {

            byte[] stream = image.Stream.Value;

            using (var memoryStream = new MemoryStream())

            {

                using (var binaryWriter = new BinaryWriter(memoryStream))

                {

                    binaryWriter.Write(stream);

                    memoryStream.Position = 0;

                    var result = (Bitmap)Bitmap.FromStream(memoryStream);

                    binaryWriter.Close();

 

                    return result;

                }

            }

        }


Continuando a rimanere in visualizzazione codice scriviamo una funzione che richiama quella precedente, in base al tipo di oggetto rilevato nel file pdf.
Di seguito si riporta il codice della funzione che estrapola da un oggetto di tipo PdfDictionary un oggetto di tipo immagine

C#

  Bitmap EsportaImmagine(PdfDictionary Immagine)

        {

            var TipoImmagine = string.Empty;

            var objFilter = Immagine.Elements.GetObject("/Filter");

            if (objFilter is PdfArray)

            {

                TipoImmagine = ((PdfArray)objFilter).Elements.GetName(0);

                 

            }

            else

            {

                TipoImmagine = Immagine.Elements.GetName("/Filter");

            }

            switch (TipoImmagine)

            {

                case "/DCTDecode":

                    return EsportaImmagineJpeg(Immagine);

 

                case "/FlateDecode":

                    break

 

                case "/JBIG2Decode":

                    break;

            }

            return null;

        }

 

Ora dobbiamo scrivere un’ultima funzione che effettua la lettura di tutte le pagine in cerca di oggetti che possono essere immagini.
La funzione qui di seguito, effettua su tutte le pagine presenti nel file “Pdf” la lettura dei vari oggetti, e verificare se l’oggetto individuato è di tipo immagine, su questa, ne estrapola l’immagine e poi tramite la classe per la gestione del barcode estrapola il testo qualora è un’immagine barcode.
La gestione dei file pdf avviene tramite le classi presenti nella libreria PdfSharp.

Di seguito si riporta il frammento di codice della funzione per la lettura dei vari oggetti presenti nel file pdf.


C#

public IEnumerable<Bitmap> OttieniImmaginiDaPdf(string PercorsoNomeFile)

        {

            PdfDocument document = PdfReader.Open(PercorsoNomeFile);

 

            //Effettuo un ciclo su tutte le pagine

            foreach (PdfPage pagina in document.Pages)

            {

                //Ottengo la risorsa per ogni  pagina

                PdfDictionary resources = pagina.Elements.GetDictionary("/Resources");

                if (resources != null)

                {

                    //Rilevo l'oggetto per la risorsa

                    PdfDictionary xObjects = resources.Elements.GetDictionary("/XObject");

                    if (xObjects != null)

                    {

                        var Elementi = xObjects.Elements.Values;

                        //Ciclo per ogni elemento trovato

                        foreach (PdfItem item in Elementi)

                        {

                            PdfReference pdfRefence = item as PdfReference;

                            if (pdfRefence != null)

                            {

                                PdfDictionary pdfDictionary = pdfRefence.Value as PdfDictionary;

                                 //Verifico che è un immagine

 

                                if (pdfDictionary != null && pdfDictionary.Elements.GetString("/Subtype") == "/Image")

                                {

                                    var bitmap = EsportaImmagine(pdfDictionary);

                                    if (bitmap != null)

                                    {

                                        yield return bitmap;

                                    }

                                }

                            }

                        }

                    }

                }

            }

        }




Ora passiamo in visualizzazione grafica in modo da fare doppio click sul pulsante situato sotto la seconda casella di testo, l’ultimo rimasto, che utilizzeremo per rilevare il testo presente nel barcode.
Passando in visualizzazione codice dell’evento click del pulsante, dobbiamo scrivere il codice che estrapola il testo dal file immagine, in particolar modo tramite il metodo “Decode” della classe “BarcodeReader” estrapoliamo il testo presente nell’immagine. Prima di utilizzare questo codice, verifichiamo se il file è un pdf oppure immagine, in caso che è un file, rileva le varie immagini ed estrapola il testo, qualora non siano codici a barre, verrà restituito null, altrimenti il testo presente nel codice a   barra.
Tramite la proprietà “Text” dell’oggetto restituito del metodo “Decode”, verrà riportato nella casella di testo, il contenuto del barcode.
Di seguito si riporta il frammento di codice delle suddette operazioni da inserire nell’evento click del pulsante.


C#

private void BtnLeggi_Click(object sender, EventArgs e)

        {

            try

            {

 

                 

                BarcodeReader barcodeReader = new BarcodeReader();

                 

                if (TxtPercorsoNomeFile.Text.Contains(".pdf"))

                {

                    var immagini = OttieniImmaginiDaPdf(TxtPercorsoNomeFile.Text);

                    foreach (var immagine in immagini)

                    {

                         

                        var testoRilevato = barcodeReader.Decode(immagine);

                        if (testoRilevato != null)

                        {

                            TxtTesto.Text = testoRilevato.Text;

                        }

 

                    }

                }

                else

                {

                    Bitmap bitmap = new Bitmap(TxtPercorsoNomeFile.Text);

                    var testoRilevato = barcodeReader.Decode(bitmap);

 

                    if (testoRilevato != null)

                    {

                        TxtTesto.Text = testoRilevato.Text;

                    }

                }

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

        }

 





Prima di effettuare le prove, dobbiamo creare un file immagine con barcode, che possiamo utilizzare quello con cui abbiamo scritto il codice per la creazione, mentre per il file pdf, possiamo creare un file tramite Word o altro programma che permette la creazione dei file pdf, aggiungendo il file immagine del barcode creato in precedenza.

Conclusioni

L’articolo ha voluto fornite al lettore un’ampia gestione dei barcode utilizzando le librerie gratuite utilizzabili anche in ambito commerciale come la libreria PdfSharp.
Il lettore dalla base tecnica fornito può ampliare con funzionalità avanzate o scenari più complessi l’utilizzo di queste librerie.
Il frammento di codice si può utilizzare anche con altre versione del Framework, precedenti alla 7, quale la 6 o 5 ed anche in ambito Web, come la tecnologia Asp.Net, apportando le modifiche richieste per lo scenario web.
La libreria PdfSharp offre una serie di classi, offrendo al programmatore funzionalità anche avanzate e soprattutto facilitando nella stesura del codice.

Nessun commento: