Press "Enter" to skip to content

Ridimensionare e Stampare un immagine in WPF e Windows Forms

Un articolo prendi 4 paghi 2 infatti in risposta ad un thread sul forum Microsoft italiano riguardo la stampa di una immagine, ho deciso di fare un paio di test e pubblicare un piccolo How To.

Pertanto in questo articolo vedremo come fare a ridimensionare un immagine Bitmap e come porla su una pagina ed effettuarne la stampa. Siccome so che una parte dei lettori lavora ancora in Windows Forms, ho fatto due mini progetti, uno usando WPF e uno usando WIndows Forms.

Ridimensionare un immagine in WPF

Ridimensionare un’immagine in WPF non è esattamente una cosa banale, perché per ottenere un risultato fatto bene è indispensabile usare vari oggetti creati allo scopo. pertanto iniziamo con la creazione di una mini interfaccia utente per fare poi il test di stampa:

<Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

Per prima cosa definisco una grid con 3 righe, nella prima metterò i componenti per selezionare l’immagine di origine, nella seconda metterò l’immagine, nella terza il pulsante di stampa.

<Grid Grid.Row="0">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto"/>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0"
      Margin="4,2,4,2"
      Text="Immagine selezionata"/>
    <TextBox Grid.Column="1"
      Margin="4,2,4,2"
      Height="24"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Center"
      HorizontalContentAlignment="Left"
      Text="{Binding FileName, UpdateSourceTrigger=PropertyChanged}"/>
    <Button Grid.Column="2"
      Margin="4,2,4,2"
      Padding="10,2,10,2"
      Click="GetFileName_Click">
      <TextBlock Grid.Column="0"
        Margin="4,2,4,2"
        Text="..."/>
    </Button>	
</Grid>

Creiamo una Grid con 3 colonne in cui inseriamo una label per indicare cosa va messo nella Textbox, poi una TextBox e infine un Button che servirà a selezionare e caricare l’immagine che poi potremo stampare.

 

<Grid Grid.Row="1"
    Background="Azure">
    <Image
      Margin="4"
      Stretch="None"
      Source="{Binding BitmapImg, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

Nella seconda riga della Grid principale, aggiungiamo un’altra Grid che contiene al centro un oggetto Image che ospiterà la preview dell’immagine selezionata e ridimensionata. Notate che ho inizializzato l’attributo Stretch a None in modo che l’immagine sia mostrata della dimensione reale. il Binding sulla property BitmapImg ci permette di predisporre la sorgente dell’immagine che andremo a leggere e ridimensionare.

 

<StackPanel Grid.Row="2"
    Orientation="Horizontal"
    FlowDirection="RightToLeft">
      <Button Grid.Column="2"
        Margin="4,2,4,2"
        Padding="10,2,10,2"
        Click="PrintImage_Click">
      <TextBlock Grid.Column="0"
        Margin="4,2,4,2"
        Text="Stampa Immagine"/>
    </Button>
</StackPanel>

Nell’ultima riga mettiamo uno StackPanel dove inseriamo il Button per la stampa.:

Leggere e ridimensionare un immagine

Per leggere e ridimensionare l’immagine, andiamo a guardare il codice dietro al bottone con i 3 puntini

OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Selezionare l'immagine";
ofd.Filter = "Image files (*.bmp,*.jpg,*.png)|*.bmp;*.jpg;*.png|Tutti i file (*.*)|*.*";
bool? opened = ofd.ShowDialog(this);
if (opened.HasValue && opened.Value)
{
...
}

La prima operazione da fare è selezionare il file da aprire, per fare questo, utilizziamo la libreria Microsoft.Win32 che contiene le dialog standard di Windows fra cui OpenFileDialog e SaveFileDialog. Pertanto nella nostra MainWindow abbiamo inserito:

using Microsoft.Win32;

Il codice definito all’interno dell’evento Click del button permette di aprire la Open file dialog di window e selezionare un file di tipo immagine. Se l’utente seleziona il file e chiude la dialog premendo il tasto Open, entriamo all’interno dell’if e per prima cosa creiamo un oggetto BitmapImage a partire dal file dell’immagine:

BitmapImage bmp = new BitmapImage(new Uri(ofd.FileName));

Per leggere un immagine da file, l’oggetto BitmapImage ha un costruttore a cui passiamo l’URI del file, (che non è altro che il suo path).

Visto che una delle richieste nella domanda sul forum riguardava ridimensionare una bitmap, faccio un ridimensionamento arbitrario per fare il test, e per farlo per prima cosa creo le nuove dimensioni dell’immagine riducendola ad 1/4:

double newWidth = Math.Round(bmp.Width / 4,0);
double newHeight = Math.Round(bmp.Height / 4,0);

Divido quindi per 4 le dimensioni del bitmap e arrotondo all’intero superiore il codice qui sopra tradotto significa: prendi la larghezza (o l’altezza) della bitmap dividi per quattro e arrotonda a 0 decimali.

BitmapFrame bf = CreateAndReturnResizedImage(bmp, (int)newWidth, (int)newHeight0);

Usando le dimensioni calcolate ed un oggetto BitmapFrame andiamo a generare un nuovo bitmap delle dimensioni calcolate. Visto che in input riceve due numeri interi, ecco il motivo per cui abbiamo arrotondato le dimensioni del nuovo bitmap.

string newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "TestFile.png");

Creata l’immagine piccola, la salviamo su un file, potremmo chiedere all’utente il nome del nuovo file, ma per questo test ho deciso per un nome arbitrario e la cartella delle immagini dell’utente. Pertanto per prima cosa creo il nome della nuova immagine.

using (var fileStream = new FileStream(newFileFileMode.Create))
{
	BitmapEncoder encoder = new PngBitmapEncoder();
	encoder.Frames.Add(bf);
	encoder.Save(fileStream);
}

Per creare il file a partire dal BitmapFrame, creiamo per prima cosa uno Stream o meglio un FileStream per generare il file, poi utilizziamo un Encoder per generare una Png andando ad aggiungervi il BitmapFrame generato e salvandolo.

FileName = newFile;
bmp = new BitmapImage(new Uri(newFile));
BitmapImg = bmp;

Per visualizzare l’immagine, rileggiamo il nuovo file generato e poniamo il nome del file nella Property che fa da DataSource alla Textbox con il nome file e la BitmapImage nella variabile che fa da DataSource al controllo Image che abbiamo inserito sulla Window.

Adesso che abbiamo caricato l’immagine, possiamo stamparla.

var vis = new DrawingVisual();
using (var dc = vis.RenderOpen())
{
	dc.DrawImage(BitmapImgnew Rect { Width = BitmapImg.WidthHeight = BitmapImg.Height });
}

Il primo step da compiere per stampare un’immagine è disegnarla su un rettangolo all’interno di un oggetto fatto apposta per la stampa, in questo caso utilizziamo il DrawingVisual, in cui creiamo il rettangolo su cui Disegnamo l’immagine.

var pdialog = new PrintDialog();
if (pdialog.ShowDialog() == true)
{
	pdialog.PrintVisual(vis"Immagine stampata");
}

Completiamo la stampa utilizzndo un oggetto PrintDialog per visualizzare la finestra di selezione della stampante e procedere con la stampa.

E questo è tutto per la versione WPF adesso vediamo come facciamo lo stesso in Windows Forms.

Come leggere, ridimensionare e stampare un immagine in Windows Forms

Creato un progetto Windows Forms, ho modificato la Form1 generata dal template per inserire controlli paritetici a quelli di WPF pertanto una Label, una Textbox, un Button per la selezione del file immagine, una PictureBox per ospitare l’immagine ed un secondo Button per la stampa. In questo caso ho usato il designer ed ottenuto questo risultato:

Ho modificato la PictureBox  nel seguente modo:

  • Name=pcxImage
  • SizeMode=AutoSize

In questo modo l’immagine caricata avrà le dimensioni della bitmap di origine. 

Andiamo ora a vedere il codice dietro all’event handler del click dei 2 Button.

OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Selezionare l'immagine";
ofd.Filter = "Image files (*.bmp,*.jpg,*.png)|*.bmp;*.jpg;*.png|Tutti i file (*.*)|*.*";
DialogResult opened = ofd.ShowDialog(this);
if (opened == DialogResult.OK)
{
...
}

La parte di acquisizione del nome del file immagine come vedete è identica, infatti utilizziamo la stessa dialog di Windows.

string newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "TestFileWF.png");
 
Image img = Bitmap.FromFile(ofd.FileName);
int newHeight = img.Height / 4;
int newWidth = img.Width / 4;

Generiamo il nome della immagine ridimensionata e leggiamo l’immagine. In Windows Forms, utilizziamo l’ogggetto Image e l’oggetto Bitmap che può essere assegnato ad Image perché è una sua classe Derivata. Bitmap ha un metodo che permette di leggere l’immagine dal nome del file.

Bitmap bmp = new Bitmap(imgnew Size(newWidthnewHeight));
bmp.Save(newFile);
 
textBox1.Text = newFile;
pcxImage.Image = bmp;

Completiamo l’opera generando l’immagine ridimensionata e salvandola sul nuovo file, oltre a questo, assegnamo il nome del file prodotto alla property Text fella TextBox e l’immagine alla pictureBox che abbiamo generato per renderla visibile.

A questo punto vediamo come stampare l’immagine anche da windows forms quindi andiamo a guardare il codice scritto nell’event handler del Click del bottone di stampa.

PrintDialog prn = new PrintDialog();
DialogResult printed = prn.ShowDialog(this);
if (printed == DialogResult.OK)
{
	PrintDocument pd = new PrintDocument();
	pd.PrinterSettings = prn.PrinterSettings;
	pd.PrintPage += PrintPage;
	pd.DefaultPageSettings.Margins = new Margins(0000);
	pd.PrintPage += new PrintPageEventHandler(PrintPage);
	pd.DefaultPageSettings.Landscape = false;
	pd.Print();				
}

Per stampare la bitmap in questo caso per prima cosa scegliamo la stampante usando la PrintDialog, poi creiamo un PrintDocument e lo predisponiamo per la stampa, notate che generiamo un event handler per l’evento PrintPage, in questo evento andremo a creare la pagina da stampare.

string newFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "TestFileWF.png");
Image image = Image.FromFile(newFile);
e.Graphics.DrawImage(image1010image.Widthimage.Height);

Nell’Event handler PrintPage, andiamo a leggere l’immagine generata e poi andiamo a disegnarla sull’oggetto Graphics che rappresenta la pagina di stampa, che è un rettangolo in cui possiamo posizionare uno o più oggetti, in questo caso un oggetto Image. Volendo è possibile cambiare al volo la dimensione di stampa dell’immagine se necessario.

E direi che con questo è tutto, di seguito il link per scaricare il progetto esempio collegato.