Posts
256
Comments
330
Trackbacks
7
luglio 2008 Entries
Piccolo tool: generatore di thumbnail e gallerie fotografiche

Volevo condividere questo piccolo tool per la generazione di thumbnail e gallerie fotografiche. Non è un progetto recentissimo ed è stato scritto in VB.NET, ma è tornato utile in diverse situazioni. L'applicazione si presenta come un'unica finestra composta da un TabControl con due TabPage in una Windows Form.

image

Com'è facile intuire, il campo "Percorso immagini" specifica il percorso dove risiedono le immagini da cui bisogna partire per creare i thumbnail o la galleria fotografica. I campi presenti nel TabPage "Thumbnail" sono:

Mantieni proporzioni foto - Blocca il ridimensionamento fisso. Viene abilitato il ridimensionamento in percentuale e vengono rispettate le proporzioni tra i lati delle foto.

Ridimensionamento fisso - In questi campi viene specificata la dimensione dell'altezza e della larghezza delle thumbnail generate. Non viene rispettata la proporzione tra la larghezza e l'altezza delle immagini di origine. Piccola osservazione, se l'immagine originale ha dimensioni 100x100, un ridimensionamento al 20% produce un immagine 20x20

Qualità thumbnail - Specifica la qualità (jpg) delle thumbnail generate.

Il secondo TabPage, "Galleria Fotografica", è leggermente più complesso.

image

La galleria fotografica è intesa come una serie di pagine HTML, ognuna contenente un certo numero di miniature (le thumbnail) , sulle quali agendo con il mouse mediante click o passaggio del cursorse, permette la visualizzazione dell'immagine corrispondente a dimensioni maggiori. In ogni pagina, il numero di miniature è prestabilito. Per abilitare la creazione delle gallerie fotografiche è necessario impostare il flag sul CheckBox Crea galleria fotografica. Il campo Template galleria (a scelta multipla, mediante ComboBox) contiene un'elenco  dei template disponibili per la creazione delle gallerie. La lista dei template e il file con la lista utilizzata per popolare il ComboBox  risiedono nella stessa directory dell'eseguibile, all'interno della directory Templates. Ogni template è a sua volta composto da una sottodirectory denominata "Template_0","Template_1" etc... Il file della lista che descrive i nomi dei template è un semplice file di testo (List.txt) contenete una riga per ogni modello, ad esempio:

Classico

Troposfera

La prima voce nell'elenco corrisponde a "Template_0", la seconda a "Template_1" etc...

All'interno di ogni directory-modello sono presenti quattro file:

CSSTemplate.txt - Contiene il CSS globale utilizzato per la creazione della galleria.

CSSItemTemplate.txt - Contiene la specifica del CSS utilizzato per la visualizzazione dei thumbnail nella pagina HTML

PageTemplate.txt - Contiene il modello della pagina HTML che ospita la galleria

PageItemTemplate.txt - Contiene il modello dell'HTML utilizzato per la visualizzazione dei thumbnail nella pagina HTML

"Giocando" con questi file è possibile generare gallerie fotografiche secondo le proprie esigenze senza mettere mani al codice (si spera :-)). Ovviamente si possono aggiungere altri template e personalizzare il codice. Nel TabPage delle gallerie fotografiche, il significato dei campi esposti è leggermente diverso:

Dimensioni thumbnail - Specifica le dimensioni fisse dei thumbail della galleria fotografica. In linea teorica con un click o un mouseover su di esse, dovrebbero essere visualizzate le rispettive immagini a dimensioni originali

Dimensione immagine - Specifica le dimensioni in percentuale (quindi rispettando le proporzioni) delle immagini che sono visualizzate agendo opportunamente  sui corrispondenti thumbnail

Qualità immagine - Questa volta la qualità dell'immagine jpg è riferita alle immagini della galleria fotografica e non ai thumbnail

Nome pagina base - Nome base delle pagine HTML che compongono la galleria. Se il nome base fosse "Galleria", secondo il numero di foto ed il valore del campo Immagini per pagina, verrebbero create un certo numero di pagine denominate "Galleria_1.html", "Galleria_2.html","Galleria_3.html" navigabili,

Un esempio del risultato che si ottiene utilizzando il template "Classico" è il seguente:

image

Piccole osservazioni:

Se ad esempio il percorso contenente le foto da cui creare le thumbnail o la galleria fotografica è C:\Foto, le sole thumbnail sono generate nella sottodirectory C:\Foto\Dest, mentre la galleria fotografica in C:\Foto\Gallery. Il contenuto di questa cartella può essere utilizzato semplicemtene copiando ed incollando essendo autocontenuta.

Ovviamente sono già presenti numerosi tool commericali e free che eseguono queste operazioni, per le mie esigenze avevo bisogno di tool ad hoc e veloce. Del resto siamo sviluppatori di applicazioni o no? Altrimenti non ci si divertirebbe... Penso comunque di aggiornare il codice , ottimizzando le routine  e magari eseguendo il porting in C# (forse utilizzando WPF).

In allegato, il progetto Visual Studio completo.

Thumbnail.zip

posted @ giovedì 31 luglio 2008 20.06 | Feedback (0)
WPF: Binding tra controlli

Post dopo studio. Un interessante funzionalità del motore di binding in WPF è quella di permettere il binding tra proprietà di elementi. Ad esempio, supponiamo di avere una Window Form VPW  con due controlli TextBox (txtOne e txtTwo). Vogliamo che al cambiare del Background della prima, venga cambiato automaticatimente anche il Background della seconda (senza scrivere una riga di codice C#/VB.NET). Il codice XAML che effettua questa "magia" è il seguente:

 

1 <TextBox Margin="57,127,53,112" Name="txtOne" Background="Sienna" /> 2 <TextBox Margin="57,156,53,83" Name="txtTwo" Background="{Binding Path=Background, ElementName=txtOne}" />

 

Il risultato del binding che si ottiene può essere verificato anche a design-time cambiando il colore di background di txtOne. Proviamo a complicarci la vita. Supponiamo che i due controlli TextBox siano utilizzati come campi contenenti valori da sommare. Vogliamo impostare il background di un terzo controllo Textbox (txtResult) secondo che il risultato della somma sia minore-uguale o maggiore di un certo valore soglia, ad esempio 100. Per completare questo obiettivo abbiamo la necessità di utilizzare  un Converter , o meglio costruire una classe che implementi l'interfaccia IValueConverter. Utilizzando questa interfaccia, possiamo applicare del codice custom alla logica di binding. Ad esempio nel nostro esempio dobbiamo convertire un valore intero in un'istanza di oggetto Brush.  E' necessario implementare i due metodi esposti dall'interfaccia IValueConverter: Convert e ConvertBack. Il primo entra in gioco, chiamato in causa dal binding engine, quando un valore deve essere propagato (converito) dalla sorgente al  binding al target. Questo metodo ritorna il valore convertito o null. Il metodo ConvertBack, come suggerisce il nomestesso, esegue il processo contrario a quello di Convert.

Per Convert e ConvertBack, il valore di ritorno, invece di essere null, può anche essere DependencyProperty.UnsetValue, se la conversione non ha prodotto valore e si vuole utilizzare  la proprietà FallBackValue (se disponisbile) o il valore di default. Per l'esempio corrente  non  è necessario eseguire nessuna conversione dal target al source ,  quindi non scriviamo nessun codice per il metodo ConvertBack, ma è sufficiente ritornrare il valore  DependencyProperty.UnsetValue o null.

Il codice della classe che esegue la conversione tra Binding Source e Binding Target è il seguente:

 

1 public class MyValueConverter : IValueConverter
2 {
3 #region IValueConverter Members 4 5 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
6 {
7 try 8 {
9 int result = 0;
10 if (int.TryParse(value.ToString(), out result))
11 {
12 return (result>100 ? Brushes.Red : Brushes.Green );
13 }
14 else 15 return DependencyProperty.UnsetValue;
16 }
17 catch
18 {
19 return DependencyProperty.UnsetValue;
20 }
21 }
22 23 public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
24 {
25 return DependencyProperty.UnsetValue;
26 }
27 28 #endregion 29 }

 

Creiamo un'istanza della classe MyValueConverter direttamente nel codice XAML, aggiungendola alla collezione delle risorse della nostra Window WPF:

 

1 <local:MyValueConverter x:Key="MyConverter" />

 

A questo punto non ci resta che impostare il binding del controllo TextBox (txtResult) tra la proprietà Text (source) e Background (Target) del controllo stesso

 

1 <TextBox Height="23" Margin="57,0,53,54" Name="txtResult" VerticalAlignment="Bottom"
2 Background="{Binding Path=Text, ElementName=txtResult, Converter={StaticResource MyConverter}}"
3 TextAlignment="Right" Foreground="White" />

 

Per eseguire la somma dei valori contenuti nei due TextBox, utilizziamo un controllo Button con associato il seguente codice C#:

1 int a = int.Parse(txtOne.Text);
2 int b = int.Parse(txtTwo.Text);
3 int r = a + b;
4 txtResult.Text = r.ToString();

In questo modo, il  Background di txtResult cambierà in base al valore della somma ottenuta.

posted @ martedì 29 luglio 2008 9.26 | Feedback (0)
[OT] Per una password...

Non so se qualcuno di voi ha letto questa notizia...devo ammetterlo, mi ha strappato un sorriso...

posted @ giovedì 24 luglio 2008 12.47 | Feedback (0)
System.Security.Cryptography.Rijndael

Una classe Helper per l'algoritmo di cifratura simmetrico System.Security.Cryptography.Rijndael , magari può tornare utile:

1 public class RijndaelHelper 2 { 3 private byte[] _IV = null; 4 private byte[] _key = null; 5 private Rijndael _rijndael = null; 6 private string _lastExceptionDescription = ""; 7 8 public string LastExceptionDescription 9 { 10 get { return _lastExceptionDescription; } 11 } 12 13 public RijndaelHelper() 14 { 15 _rijndael = Rijndael.Create(); 16 } 17 18 public RijndaelHelper(byte[] key, byte[] IV) 19 { 20 this._key = key; 21 this._IV = IV; 22 _rijndael = Rijndael.Create(); 23 } 24 25 26 /// <summary> 27 /// Esegue la cifratura dei dati 28 /// </summary> 29 /// <param name="data">Array di byte con i dati che devono essere cifrati</param> 30 /// <returns>Array di byte con i dati cifrati</returns> 31 public byte[] EncryptData(byte[] data) 32 { 33 try 34 { 35 byte[] encryptedData = null; 36 37 _lastExceptionDescription = ""; 38 39 using (MemoryStream memStream = new MemoryStream()) 40 { 41 42 //Crea un'istanza di oggetto Cryptographic per l'esecuzione dell'algoritmo di Rijndael 43 _rijndael = Rijndael.Create(); 44 45 //Crea una nuova istanza CrypoStream in modalità scrittura 46 CryptoStream cryptoStream = new CryptoStream(memStream, 47 _rijndael.CreateEncryptor(_key, _IV), CryptoStreamMode.Write); 48 49 //Scrive i dati cifrati 50 cryptoStream.Write(data, 0, data.Length); 51 cryptoStream.FlushFinalBlock(); 52 53 encryptedData = memStream.ToArray(); 54 55 //Chiude gli stream 56 cryptoStream.Close(); 57 memStream.Close(); 58 } 59 60 return encryptedData; 61 } 62 catch (CryptographicException ex) 63 { 64 _lastExceptionDescription = ex.Message; 65 return null; 66 } 67 catch (System.Exception ex) 68 { 69 _lastExceptionDescription = ex.Message; 70 return null; 71 } 72 } 73 74 /// <summary> 75 /// Esegue la decifratura dei dati 76 /// </summary> 77 /// <param name="encryptedData">Array di byte contenente i dati da decifrare</param> 78 /// <returns>Array di byte con i dati decifrati</returns> 79 public byte[] DecryptData(byte[] encryptedData) 80 { 81 try 82 { 83 byte[] decryptedData = new byte[encryptedData.Length]; 84 using (MemoryStream memStream = new MemoryStream(encryptedData, 0, encryptedData.Length)) 85 { 86 _rijndael = Rijndael.Create(); 87 88 //Crea una nuova istanza CrypoStream in modalità lettura 89 CryptoStream cryptoStream = new CryptoStream(memStream, 90 _rijndael.CreateDecryptor(_key, _IV), CryptoStreamMode.Read); 91 92 //Decifra i dati nell'array decryptedData 93 cryptoStream.Read(decryptedData, 0, encryptedData.Length); 94 95 //Chiude gli stream 96 cryptoStream.Close(); 97 memStream.Close(); 98 } 99 100 return decryptedData; 101 } 102 catch (CryptographicException ex) 103 { 104 _lastExceptionDescription = ex.Message; 105 return null; 106 } 107 catch (System.Exception ex) 108 { 109 _lastExceptionDescription = ex.Message; 110 return null; 111 } 112 } 113 }

Esempio di utilizzo:

1 byte[] iv = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 15, 16}; 2 byte[] k = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 3 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }; 4 5 RijndaelHelper helper = new RijndaelHelper(k, iv); 6 7 byte[] a = helper.EncryptData(System.Text.UTF8Encoding.UTF8.GetBytes ("Che bella cosa è na jurnata e sole")); 8 MessageBox.Show(System.Text.UTF8Encoding.UTF8.GetString (helper.DecryptData(a)));

 

posted @ mercoledì 23 luglio 2008 10.30 | Feedback (0)
Ultimo acquisto...FAT32 e convert

Oggi mi sono deciso ad acquistare per diversi motivi un nuovo disco esterno, la mia attenzione è stata catturata da  un My Book Western Digital 500GB. Molto bello esteticamente, silenzioso, tanto spazio di archiviazione, ma non capisco una cosa: è possibile mai che il file system dei dischi esterni sia sempre di tipo FAT32 ?!? Passi un'unica partizione, ma FAT32 proprio no...

Comunque grazie all'utility convert richiamabile da riga di comando (convert volumne /FS:NTFS /X) la conversione del file system da FAT32 a NTFS è stata rapida e indolore :-D.

posted @ martedì 22 luglio 2008 15.34 | Feedback (14)
How I Got Started in Software Development

Non potevo certo rifiutare l'invito di Rosalba:

How old were you when you started programming?
A quale età hai cominciato a programmare?

Più o meno quando avevo 9 anni, mi ero stancato di giocare con  il Commodore 64, volevo fare qualcosa di "diverso" .

How did you get started in programming?
Come hai cominciato a programmare?

Ero curioso di capire quale arcano mistero si nascondesse dietro le formule magiche 10 PRINT... e soprattutto vedere la mongolfiera con il logo Commodore volare sul mio schermo :-D

What was your first language?
Qual’è stato il tuo primo linguaggio di programmazione?
BASIC del Commodore

What was the first real program you wrote?
Qual’è stato il primo programma vero che hai scritto?
Un programma scritto in VB 5 per il recupero delle informazioni del PC: Versione del sistema operativo, Capacità del disco, RAM etc...

What languages have you used since you started programming?
Quali linguaggi hai usato da quando hai cominciato a programmare?

Basic, QBasic, Pascal, C , Visual Basic (5,6), Visual Basic .Net, C#, Java, PHP, ASP

What was your first professional programming gig?
Quando è stato il tuo primo vero lavoro da programmatore?

Un software gestionale per la contabilità e la gestione del magazzino

If you knew then what you know now, would you have started programming?
Con il senno di poi, rifaresti lo stesso il programmatore? Ricominceresti a programmare?

Senza ombra di dubbio.

If there is one thing you learned along the way that you would tell new developers, what would it be?
Se ci fosse una cosa che hai imparato nella tua carriera e che vorresti dire ai giovani programmatori, cosa diresti?

Non ho una lunghissima carriera, ma direi che per fare bene questo lavoro ci vuole passione e coscienza che ogni giorno ci sarà un nuovo problema da risolvere o una nuova sfida da vincere, il tutto "divertendosi", soprattutto se si lavora in un bel team.

What's the most fun you've ever had ... programming?
Qual’è la cosa più divertente che hai programmato?

Un software per la stampa delle copertine dei CD-Rom in Visual Basic.Net

Now, let’s tag someone else…
Adesso è l’ora di taggare qualcun’altro…

Penso che ormai siano stati taggati tutti...

posted @ sabato 19 luglio 2008 7.54 | Feedback (0)
[OT] Se avete bisogno di una mano...

....questo robot fa per voi!. Si muove da solo, riconosce gli oggetti e serve da bere. Se non ha mai visto un oggetto, basta addestrarlo a riconoscerlo. E' possibile impartire comandi tramite touchscreen e comandi vocali. Il costo non è indicato :-(, peccato ;-).

posted @ domenica 13 luglio 2008 17.12 | Feedback (0)
LocalPrintServer

Studiavo le proprietà di questa classe,  la quale rappresenta, cito la documentazione MSDN : "il server di stampa locale (il computer sul quale l'applicazione è in esecuzione)" . Quest'oggetto molto interessante, permette la gestione delle code di stampa oltre a poter ottenere l'insieme delle stampanti locali con relative proprietà. Per questo semplice compito sono sufficienti poche righe di codice :

1 private void Window_Loaded(object sender, RoutedEventArgs e) 2 { 3 LocalPrintServer ps = new LocalPrintServer(); 4 5 PrintQueueCollection printCollection = ps.GetPrintQueues(); 6 7 IEnumerable<PrintQueue> pq = from p in printCollection 8 orderby p.Name 9 select p; 10 11 lstPrinters.ItemsSource = pq; 12 }

Se poi uniamo il tutto a del semplice codice XAML:

1 <Window.Resources> 2 <Style x:Key="StretchedListBoxItem" TargetType="{x:Type ListBoxItem}"> 3 <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 4 </Style> 5 </Window.Resources> 6 <Grid> 7 <ListBox Name="lstPrinters" Margin="24,24,24,17" ItemContainerStyle="{StaticResource StretchedListBoxItem}"> 8 <ListBox.ItemTemplate> 9 <DataTemplate> 10 <Border Margin="1,1,1,1" BorderThickness="1" CornerRadius="6,6,6,6" BorderBrush="Blue"> 11 <Grid HorizontalAlignment="Stretch"> 12 <Grid.ColumnDefinitions> 13 <ColumnDefinition Width="80" /> 14 <ColumnDefinition Width="*" /> 15 </Grid.ColumnDefinitions> 16 <Grid.RowDefinitions> 17 <RowDefinition Height="40" /> 18 <RowDefinition Height="40" /> 19 </Grid.RowDefinitions> 20 <Image Grid.RowSpan="2" Margin="6,9,7,9" Name="imgPrint" Stretch="Fill" Source="Printer.png"/> 21 <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding FullName}" Margin="8,13,10,0"/> 22 <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Description}" Margin="8,4,10,0"/> 23 </Grid> 24 </Border> 25 </DataTemplate> 26 </ListBox.ItemTemplate> 27 28 </ListBox> 29 30 </Grid>

Possiamo ottenere un gradevole effetto di presentazione:

image

Penso  che la classe meriti uno studio approfondito date le potenzialità offerte.

Technorati Tag:
posted @ venerdì 11 luglio 2008 13.32 | Feedback (0)
Spellchecking

In WPF, i controlli TextBox e Richtextbox, integrano un servizio di Spellchecking, simile a quello di Microsoft Word (la classica linea rossa ad onde visualizzata quando si sbaglia a digitare del testo per la lingua impostata). E' possibile abilitare queste funzionalità impostando le relative proprietà nel file XAML:

1 <TextBox Margin="16,152,24,51" xml:lang="EN" Name="textBox1" AcceptsReturn="True" SpellCheck.IsEnabled= "True"/>

Oppure nel code-behind:

1 txtSpell.Language = System.Windows.Markup.XmlLanguage.GetLanguage("EN"); 2 txtSpell.SpellCheck.IsEnabled = true;

Se come nell'esempio impostiamo la lingua inglese, digitando  Helllo Worlld! Nella TextBox, a video il controllo si presenterà come:

image

Technorati Tag:
posted @ mercoledì 9 luglio 2008 9.06 | Feedback (0)
[OT] Ferrari

E' stata una giornata no per la Ferrari, direi anche per la strategia non proprio ottima (oltre alla pioggia intermittente). Classifica:

1° Hamilton, 2° Heidfeld, 3° Barrichello.

Raikkonen 4°, ultimo Massa :-(

Si spera nel gran premio di Germania.

posted @ domenica 6 luglio 2008 13.52 | Feedback (3)
Fine di un "mito"?

Forse tutti lo sanno, tranne io, ma il 30 giugno 2008 Microsoft ha terminato la vendita di Microsoft Windows XP (anche se leggendo le risposte alle domande presenti in questo documento, per System Builder il termine è fissato a gennaio 2009 mentre per la vendita di Ultra-Low Cost PC giugno 2010). Il supporto rimane garantito fino al 2014. E' giunta "la fine" di un "mito"? Penso proprio di si.

posted @ venerdì 4 luglio 2008 7.59 | Feedback (4)
Abilitare "l'ibernazione"

Post a titolo di promemoria. Per abilitare da riga di comando "l'ibernazione" del sistema, è sufficiente digitare (avendo gli opportuni privilegi):

powercfg /hibernate on

Altre opzioni di powercfg e approfondimenti qui

posted @ giovedì 3 luglio 2008 13.05 | Feedback (2)
"sindrome dei contenuti in perenne ritardo"

Un collega mi ha inviato un link ad un articolo  riguardante la gestione dei contenuti del web. E' stata una piacevole lettura, forse può interessare ad altri.

posted @ martedì 1 luglio 2008 19.20 | Feedback (0)
News

View Pietro Libro's profile on LinkedIn

DomusDotNet
   DomusDotNet

Pietro Libro