Passa ai contenuti principali

DataURI e le immagini dinamiche in ASP.NET

In questo post vorrei proporvi un modo per creare immagini dinamiche  (in maniera analoga a quanto già proposto in questo post) all’interno delle nostre pagine ASPX utilizzando il DataURI.

Partiamo dal definire cosa è il DataURI.

Il DataURI (o più esattamente lo schema data URI), la cui definizione esatta è rintracciabile seguendo il link,  rappresenta un modo per includere all’interno delle nostre pagine web delle risorse (ad esempio grafiche, ma non solo).

Lo schema data URI compare già nelle specifiche dell’HTML 4.01.

I vantaggi di utilizzare lo schema data URI sono i seguenti:

  • le risorse incorporate nella pagina non richiedono differenti chiamate al server come accadrebbe se le risorse fossero indicate con un normale URL. Si ha quindi un risparmi nel numero di richieste e si elimina il traffico dell’header delle stesse;
  • per files di piccole dimensioni si ha un guadagno di tempo, poichè, generalmente, l’avvio della comunicazione TCP è lento;
  • nelle comunicazioni HTTPS, il browser, di solito, richiede che tutti gli elementi della pagina siano scaricati in connessione sicura (pena la comunicazione all’utente che ci sono elementi non “sicuri”) e l’HTTPS aggiunge un ulteriore overhead alla trasmissione;
  • i messaggi email possono, in questo modo contanere immagini senza che queste appaiano come degli allegati;
  • se il browser ha un numero basso di connessioni simultanee, si ha un vantaggio di tempo.

Lo schema data URI, però, ha anche degli svantaggi:

  • le risorse incorporate come data URI non sono cachate come le comuni risorse (ad esempio immagini) referenziate con un comune URL;
  • alcuni browser ancora in circolazione (ad esempio IE7 con circa il 27% della distribuzione sul mercato a luglio 2010) non lo supportano;
  • alcuni browser hanno una limitazione sulla lunghezza massima del data URI (ad esempio IE8 ha una limitazione a 32KB);
  • l’encoding del data URI (in base 64) è mediamente 1/3 più largo dell’equivalente encoding binario;
  • i software che si occupano di controllare la sicurezza dei siti lavorano male sui dati contanuti nello schema data URI.

Il formato di una risorsa espressa secondo lo schema data URI è il seguente:

data:[<MIME-type>][;charset=<encoding>][;base64],<data>

Se non si indica il base64, si intende che i dati sono espressi in ASCII.

Ad esempio, un’immagine in HTML è espressa nel seguente modo:

  1. <img src="data:image/png;base64,
  2.         iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
  3.         C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
  4.         AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
  5.         REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
  6.         ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
  7.         vr4MkhoXe0rZigAAAABJRU5ErkJggg==" alt="Red dot" />

Lo schema data URI può essere utilizzato anche all’interno di un CSS (per i browser che lo supportano) o per includere del JavaScript.

Capito cosa è lo schema data URI vediamo come possiamo utilizzarlo  nelle nostre pagine ASPX.

Innanzitutto vediamo cosa si ottiene in termini di richieste e dati trasferiti quando includiamo delle immagini tramite data URI e in maniera classica.

Per fare questo realizziamo due pagine all’interno delle quali visualizzeremo le immagini contenute in una cartella nelle due modalità.

Il code behind della pagina che utilizza la tecnica standard è la seguente:

  1. Imports System.IO
  2.  
  3. Public Class MultiImageStandard
  4.     Inherits System.Web.UI.Page
  5.  
  6.     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  7.         If Not IsPostBack Then
  8.             CreateImages(10)
  9.         End If
  10.     End Sub
  11.  
  12.     Private Sub CreateImages(ByVal numImages As Integer)
  13.         Dim imagePath = Server.MapPath("/images")
  14.         Dim imageRep = New ImageRepository()
  15.         Dim imageFiles = imageRep.GetAllImages(imagePath)
  16.         For Each imageFile In imageFiles
  17.             Dim image = New Image()
  18.             Dim fi = New FileInfo(imageFile)
  19.             image.ImageUrl = String.Format("/images/{0}", fi.Name)
  20.             Me.Controls.Add(image)
  21.         Next
  22.     End Sub
  23. End Class

La classe ImageRepository enumera le immagini presenti nella cartella.

In sostanza creiamo un oggetto Image (web control) per ogni immagine ed impostiamo il sui ImageUrl. Il risultato ottenuto è il seguente:

image

Utilizzando IE9 e la developer toolbar (tasto F12) possiamo osservare il numero di chiamate eseguite verso il server per recuperare la pagina e le 12 immagini visualizzate.

Il code behind della pagina che utilizza lo schema data URI è il seguente:

  1. Public Class MultiImageDataUri
  2.     Inherits System.Web.UI.Page
  3.  
  4.     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  5.         If Not IsPostBack Then
  6.             CreateImages(10)
  7.         End If
  8.  
  9.     End Sub
  10.  
  11.     Private Sub CreateImages(ByVal numImages As Integer)
  12.         Dim imagePath = Server.MapPath("/images")
  13.         Dim imageRep = New ImageRepository()
  14.         Dim imageFiles = imageRep.GetAllImages(imagePath)
  15.         For Each imageFile In imageFiles
  16.             Dim image = New Image()
  17.             image.ImageUrl = CreateDataUri(imageFile)
  18.             Me.Controls.Add(Image)
  19.         Next
  20.     End Sub
  21.  
  22.     Private Function CreateDataUri(ByVal imagePath As String) As String
  23.         Dim image = New Drawing.Bitmap(imagePath)
  24.         Dim base64String As String
  25.         Using ms As New IO.MemoryStream
  26.             image.Save(ms, image.RawFormat)
  27.             base64String = Convert.ToBase64String(ms.ToArray())
  28.         End Using
  29.         Return String.Format("data:image/png;base64,{0}", base64String)
  30.     End Function
  31.  
  32. End Class

In questo caso, per ogni immagine da visualizzare, craiamo un oggetto Bitmap, ne ricaviamo la sua rappresentazione come array di Byte e, quindi, lo encodiamo in base64.

Il risultato, in questo caso, è il seguente:

image

Osserviamo una sola connessione per recuperare l’intera pagina.

Un altro utilizzo dello schema data URI può essere quello di visualizzare delle immagini dinamiche.

Supponiamo di voler fare in modo che data un’immagine venga applicata su di essa una scritta di watermark (esattamente come già avevamo fatto nel post).

Per realizzare tutto ciò è sufficiente creare un immagine bitmap a partire dall’immagine su cui applicare il watermark, recuperare il suo contesto grafico, disegnare il watermark su di essa e, infine encodarla in base64.

In sostanza possiamo scrivere:

  1. Imports System.Drawing
  2.  
  3. Public Class DynamicImage
  4.     Inherits System.Web.UI.Page
  5.  
  6.     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  7.         If Not IsPostBack Then
  8.             CreateImage("/images/BigImage/DominicanRepublic_DE-DE1561561743.jpg", "CodeTailor", Image1)
  9.         End If
  10.     End Sub
  11.  
  12.     Private Sub CreateImage(ByVal imagePath As String,
  13.                             ByVal watermark As String,
  14.                             ByVal imageControl As System.Web.UI.WebControls.Image)
  15.  
  16.         Dim imageFullPath = HttpContext.Current.Server.MapPath(imagePath)
  17.         Dim image As New Bitmap(imageFullPath)
  18.         Dim gr = Graphics.FromImage(image)
  19.         Dim watermarkFont = New Font(FontFamily.GenericMonospace, _
  20.             10, FontStyle.Regular, GraphicsUnit.Pixel)
  21.         Dim textSize = gr.MeasureString(watermark, watermarkFont)
  22.         Dim x = 0
  23.         While x < image.Width
  24.             Dim y = 0
  25.             While y < image.Height
  26.                 gr.DrawString(watermark, watermarkFont, Brushes.White, x, y)
  27.                 y = CInt(y + (3 / 2 * textSize.Height))
  28.             End While
  29.             x = CInt(x + (3 / 2 * textSize.Width))
  30.         End While
  31.         Dim base64String As String
  32.         Using ms As New IO.MemoryStream
  33.             image.Save(ms, image.RawFormat)
  34.             base64String = Convert.ToBase64String(ms.ToArray())
  35.         End Using
  36.         imageControl.ImageUrl = String.Format("data:image/png;base64,{0}", base64String)
  37.     End Sub
  38. End Class

Il risultato che otteniamo è il seguente:

image



Commenti

Post popolari in questo blog

VB.NET : Aggregare stringhe con LINQ

Tip facile facile, ma a qualcuno potrebbe servire. Supponiamo di avere una lista di stringhe (magari come risultato di una query LINQ) e di voler ottenere una stringa con la concatenazione delle stesse: Dim list = CreateList() Dim concatStr = (From s In list _ Select s).Aggregate( Function (currentString, nextString) currentString + nextString) MessageBox.Show(concatStr) Il metodo CreateList non ci interessa, in questo momento, ma crea una lista di oggetti String. Protected Function CreateList() As IEnumerable( Of String ) Dim list As String () = {" stringa1 ", " stringa2 ", " stringa3 ", " stringa4 ", " stringa5 "} Return list.AsEnumerable() End Function Questo metodo potrebbe restituire una qualsiasi lista di oggetti di cui, nella select successiva recuperiamo solo stringhe. La stessa tecnica è utilizzabile per concatenare stringhe inserendovi un carattere separatore Dim list = CreateList() Dim

VB.NET: SplashScreen con effetto fade-in

In questo post vorrei proporvi un modo per realizzare una splash screen per le nostre applicazioni Windows Form che appare progressivamente con un effetto fade. Supponiamo di avere il nostro progetto VB.NET in una soluzione Visual Studio 2008 in cui abbiamo il sorgente della nostra applicazione Windows Form. Inseriamo una splash screen utilizzando il menù Progetto->Aggiungi Nuovo Elemento e selezionando il tipo di elemento “Schermata Iniziale” A questo punto Visual Studio creerà, automaticamente, la schermata iniziale che possiamo personalizzare graficamente come vogliamo. Per poter fare in modo che questa finestra appaia nel momento in cui avviamo l’applicazione, è necessario aprire le proprietà del progetto e impostare la maschera di avvio: In questo modo, all’avvio dell’applicazione, la schermata appare immediatamente e scompare un attimo prima della visualizzazione della finestra dell’applicazione. Possiamo far apparire la schermata iniziale con un ef

VB.NET: Convertire un file DOC in RTF e PDF con office interop

In questo post vorrei proporvi del codice per poter convertire un file .doc in un file .rtf oppure .pdf utilizzando le API di interoperabilità di Office. Creeremo una classe, DocConverter, che esporrà le due funzionalità sopra citate. Cominciamo con il prevedere un attributo privato della classe che rappresenterà l’applicazione Word che utilizzeremo per la conversione. Creeremo l’istanza dell’attributo privato all’interno del costruttore della classe: Public Sub New () If Not CreateWordApp() Then Throw New ApplicationException(" Assembly di interoperabilità con Office non trovato! ") End If End Sub Private _wordApp As Word.ApplicationClass Protected Function CreateWordApp() As Boolean Dim retval = True Try _wordApp = New Word.ApplicationClass() _wordApp.Visible = False Catch ex As System.Exception _wordApp = Nothing retval = False End Try Return retval End Function La conve