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 for Dummies: Gli Eventi

Vorrei iniziare con questo post una serie dedicata ad aspetti di VB.NET di base che possono essere utile a coloro che si avvicinano al mondo .NET e che, in genere, non vengono trattati a livello base. La serie di post non ha la pretesa di essere assolutamente esaustivi sugli argomenti che tratterò In questo primo post parleremo degli eventi. Cosa sono e a cosa servono Un evento è la “notifica” dell’accadimento di qualcosa. Quando, ad esempio, premiamo un bottone della finestra di un’applicazione, dietro le quinte, il bottone stesso “notifica” al mondo circostante che qualcuno, in quell’istante, lo ha premuto. Sta, poi, al mondo circostante preoccuparsi di “intercettare” l’evento stesso per gestirlo (tramite un gestore di evento). Attenzione a non confondere la pressione del tasto con la “notifica” della pressione del tasto: l’evento è la “notifica” dell’accadimento, non l’accadimento stesso. Ma a cosa serve tutto ciò? Utilizzare gli eventi è un modo per disaccoppiare ...

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...

Alla scoperta del Kinect: presentazioni e convenevoli

Oggi è arrivato un Kinect nuovo nuovo su cui cominciare a fare sperimentazione ed ho, quindi, deciso di condividere tutto ciò che scopro, le cavolate che faccio e i segreti che scopro con chi mi segue. I post che cercherò di scrivere con frequenza sono post di un neofita che si avvicina all’”Aggeggio” e che quindi sono diretti a chi nulla dell’argomento. Gli esperti troveranno noiosi e banali questi post, ma non si può aver tutto dalla vita. Per cominciare, scartato l’”Aggeggio” ho cominciato a preparare l’ambiente di sviluppo: 1) Visual Studio 2010 Ultimate (che uso normalmente ma che non è necessario in quanto si può sviluppare tranquillamente con la express edition); 2) Kinect SDK, scaricabile all’indirizzo http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/download.aspx 3) DirectX Software Development Kit scaricabile all’indirizzo http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=6812 A questo punto vi basta connettere il Kinect al...