martedì 8 novembre 2011

[VB.NET] Stampare Immagini con PrintDocument

Descrizione :
Un esempio pratico di stampa immagini / etichette usando PrintDocument e PrintPreviewDialog.

+ Articolo :

Si tratta di stampare un certo numero prefissato di immagini / etichette prendendo nomi e quantità da una lista in un DataGridView.

Nel foglio deve essere possibile determinare :
--> Numero di Righe e Colonne ( numero immagini per foglio ).
--> Alcune misure necessarie per l'adattamento alle varie situazioni ( come il cambiamento delle dimensioni immagini ).

Le immagini / etichette devono sempre riempire ogni Foglio alla sua capienza massima possibile ( economizzare carta... ), anche se su uno stesso foglio dovessero trovarsene di tipi diversi.

Come sempre, un'immagine per rendere subito l'idea del risultato desiderato ( Preview di Stampa ) :


Per replicare questa soluzione basta creare una nuova Applicazione Windows Forms con una sola Form "FormMain".
Tutto quello che serve a design è la FormMain ( Form di avvio ) con un DataGridView "DGV", e un Button "cmd_stampa".


--> Codice completo per FormMain :
Public Class FormMain

    'Cartella Immagini : modificare...
    Private percorsoImmagini As String = Application.StartupPath & "\Immagini\"

    Private WithEvents PD As New Printing.PrintDocument
    Private rigaDoc As Integer 'indice riga 
    Private colonnaDoc As Integer 'indice colonna
    Private nomiImgs As New List(Of String)
    Private indiceImg As Integer
    Private nuovaPag As Boolean
    Private bmpTemp As Bitmap

    'Variabili di controllo : posizionamento e quantità immagini su foglio...
    Private stepRiga As Integer = CP(60) 'distanza tra righe
    Private stepColonna As Integer = CP(70) 'distanza tra colonne
    Private scartoX As Integer = CP(15) 'scarto iniziale sinistro
    Private scartoY As Integer = CP(10) 'scarto iniziale superiore
    Private maxRigheDoc As Integer = 5 'max righe per pag.
    Private maxColonneDoc As Integer = 3 'max colonne per pag.

    Private Function CP(ByVal millimetri As Integer) As Integer 'CP = Centesimi di Pollice
        Return millimetri * 100 / 25.4
    End Function

    Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim r1() As Object = {"150", "BarCode", "A", "5"}
        Dim r2() As Object = {"150", "BarCode", "B", "8"}
        Dim r3() As Object = {"150", "BarCode", "C", "15"}

        With DGV
            .Columns.Add("Size", "Size")
            .Columns.Add("Categoria", "Categoria")
            .Columns.Add("Nome", "Nome")
            .Columns.Add("Quantità", "Quantità")

            .Rows.Add(r1)
            .Rows.Add(r2)
            .Rows.Add(r3)
        End With

    End Sub

    Private Sub cmd_stampa_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_stampa.Click

        'Caricamento nomiImgs
        'Qui eventuali controlli su reale esistenza directory e files...
        Dim nomeImg As String
        Dim qta As Integer
        nomiImgs.Clear()

        For i As Integer = 0 To DGV.RowCount - 1
            nomeImg = percorsoImmagini & DGV(2, i).Value & ".jpg"
            '... Eventuale controllo su esistenza nomeImg ...
            qta = DGV(3, i).Value
            For j As Integer = 1 To qta
                nomiImgs.Add(nomeImg)
            Next
        Next

        If nomiImgs.Count = 0 Then Exit Sub

        'Preview
        Dim PPD As New PrintPreviewDialog
        PPD.Document = PD
        PPD.Show()

        'Stampa diretta
        'PD.Print()

    End Sub

    Private Sub PD_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PD.BeginPrint

        'Inizializzo valori di partenza per PD_PrintPage
        indiceImg = 0
        rigaDoc = 1
        colonnaDoc = 1
        nuovaPag = False
        bmpTemp = New Bitmap(nomiImgs(0))

    End Sub

    Private Sub PD_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PD.PrintPage

        Do

            'Disegno Img
            e.Graphics.DrawImageUnscaled(bmpTemp, (colonnaDoc - 1) * stepColonna + scartoX, (rigaDoc - 1) * stepRiga + scartoY)

            'Controlli / avanzamento righe, colonne, pagine
            If indiceImg = nomiImgs.Count - 1 Then
                nuovaPag = False
                Exit Do
            Else
                indiceImg += 1
                'Caricamento da disco solo se l'immagine è cambiata rispetto alla precedente
                If nomiImgs(indiceImg) <> nomiImgs(indiceImg - 1) Then bmpTemp = New Bitmap(nomiImgs(indiceImg))
                If colonnaDoc = maxColonneDoc Then
                    colonnaDoc = 1
                    If rigaDoc = maxRigheDoc Then
                        rigaDoc = 1
                        nuovaPag = True
                        Exit Do
                    Else
                        rigaDoc += 1
                    End If
                Else
                    colonnaDoc += 1
                End If
            End If

        Loop

        e.HasMorePages = nuovaPag

    End Sub

End Class

Note :

--> In questo test il caricamento dati in DGV è ovviamente fittizio e avviene nel Form_Load().

--> Viene sempre usato un solo oggetto Bitmap e viene caricato da disco una volta sola per tipo di immagine.

--> Da segnalare l'uso opportuno dell'Evento BeginPrint() : il posto giusto in cui inserire le varie istruzioni di reset delle variabili che controllano la stampa.

--> Il processo è personalizzabile a piacere : l'ultimo blocco di dichiarazioni "Variabili di controllo" permette di definire in millimetri ( Function CP() ) tutte le misure necessarie per adattare la stampa alle dimensioni delle immagini, al numero di righe / colonne desiderato e agli spazi inter-riga e inter-colonna desiderati.

Nel mio caso ho usato 3 Immagini jpg 150x150 pixel.
Le immagini usate nel test erano esattamente queste :































-->
Per testare più precisamente la disposizione delle immagini su foglio ovviamente meglio usare immagini con riquadro, e inoltre va ricordato di non trascurare i margini di stampa, che possono variare da stampante a stampante...
Passo successivo potrebbe essere riportare su Form il controllo diretto su queste variabili con NumericUpDown ecc...

--> PD.Print() è volutamente commentato : si può provare sia la preview di stampa, sia la stampa diretta su carta, sia la stampa indiretta tramite la PPD.

+ Fine Articolo.

Un Click su "Mi Piace" è il modo migliore per ringraziare l'autore di questo articolo.



2 commenti:

Milo ha detto...

Codice bello, pulito..bravo
Grazie mille per queste chicche
Michele

MarcoGG ha detto...

Prego ! :)

Posta un commento

 
Design by Free WordPress Themes Modificato da MarcoGG