Differenze tra le versioni di "Creare una Image direttamente dai dati di un file immagine scaricato da internet senza ricreare il file nella memoria di massa"

Da Gambas-it.org - Wikipedia.
Riga 5: Riga 5:
 
Ricapitolando: l'unica cosa, che abbiamo nella RAM immediatamente dopo lo scarico, è una variabile di tipo ''Stringa'' contenente tutti i dati del file immagine.  La parte difficile è come assegnare ad una ''PictureBox'' i dati del file immagine "''così com'è''" contenuti dalla variabile di tipo ''Stringa'' senza passare preliminarmente per il metodo ''.Load()'' della Classe ''Image''.
 
Ricapitolando: l'unica cosa, che abbiamo nella RAM immediatamente dopo lo scarico, è una variabile di tipo ''Stringa'' contenente tutti i dati del file immagine.  La parte difficile è come assegnare ad una ''PictureBox'' i dati del file immagine "''così com'è''" contenuti dalla variabile di tipo ''Stringa'' senza passare preliminarmente per il metodo ''.Load()'' della Classe ''Image''.
  
Il problema può essere risolto, purché l'immagine da scaricare abbia il canale Alfa e dunque sia di formato a 32-bit - RGBA. Bisognerà, però, utilizzare alcune funzioni esterne di ''gdk_pixbuf'' richiamando nel progetto Gambas la libreria dinamica condivisa "''libgtk-3.so.0.1000.8''".
+
Il problema può essere risolto, purché l'immagine da scaricare abbia il canale Alfa e dunque sia di formato a 32-bit - RGBA. Bisognerà, però, utilizzare alcune funzioni esterne di ''gdk_pixbuf'' richiamando nel progetto Gambas la libreria condivisa: "''libgtk-3.so.0.2404.16'' ".
  
Mostriamo di seguito il codice con un esistente indirizzo web di un'immagine ''png'' da scaricare:
+
Mostriamo di seguito il codice con un esistente indirizzo web di un'immagine ''PNG'' da scaricare:
 
  Private myhttp As New HttpClient As "myhttp"   
 
  Private myhttp As New HttpClient As "myhttp"   
 
   
 
   
 
   
 
   
  Library "libgtk-3:0.1000.8"
+
  Library "libgtk-3:0.2404.16"
 
   
 
   
 
  <FONT Color=gray>' ''GdkPixbufLoader * gdk_pixbuf_loader_new(void)''
 
  <FONT Color=gray>' ''GdkPixbufLoader * gdk_pixbuf_loader_new(void)''
Riga 60: Riga 60:
 
      
 
      
 
  '''End'''
 
  '''End'''
 
 
   
 
   
 
  '''Public''' Sub MyHTTP_Finished()
 
  '''Public''' Sub MyHTTP_Finished()
Riga 66: Riga 65:
 
   Dim s As String
 
   Dim s As String
 
   
 
   
  MyHTTP.Close
+
  MyHTTP.Close
 
    
 
    
 
  <FONT Color=gray>' ''Trasferiamo in una variabile stringa i dati dell'immagine scaricata e salvata in memoria:''</font>
 
  <FONT Color=gray>' ''Trasferiamo in una variabile stringa i dati dell'immagine scaricata e salvata in memoria:''</font>
  s = myhttp.Peek()
+
  s = myhttp.Peek()
  Print "Immagine scaricata !\n\nDimensione: "; Len(s); " byte"
+
  Print "Immagine scaricata !\n\nDimensione: "; Len(s); " byte"
 
    
 
    
  Immagine(s)
+
  Immagine(s)
 
    
 
    
 
  '''End'''
 
  '''End'''
 
 
   
 
   
 
  '''Private''' Procedure Immagine(im As String)
 
  '''Private''' Procedure Immagine(im As String)
Riga 81: Riga 79:
 
   Dim bb, bb2 As Byte[]
 
   Dim bb, bb2 As Byte[]
 
   Dim w, h As Integer
 
   Dim w, h As Integer
   Dim loader, Pixbuf, dati As Pointer
+
   Dim loader, pixbuf, dati As Pointer
 
   Dim c As Byte
 
   Dim c As Byte
 
   Dim bo As Boolean
 
   Dim bo As Boolean
Riga 87: Riga 85:
 
   Dim imago As Image
 
   Dim imago As Image
 
    
 
    
  bb = Byte[].FromString(im)
+
  bb = Byte[].FromString(im)
 
    
 
    
  loader = gdk_pixbuf_loader_new()
+
  loader = gdk_pixbuf_loader_new()
 +
  If loader == 0 Then Error.Raise("Errore !")
 
    
 
    
  gdk_pixbuf_loader_write(loader, bb.data, bb.count, 0)
+
  gdk_pixbuf_loader_write(loader, bb.data, bb.count, 0)
 
    
 
    
  gdk_pixbuf_loader_close(loader, 0)
+
  gdk_pixbuf_loader_close(loader, 0)
 
    
 
    
  pixbuf = gdk_pixbuf_loader_get_pixbuf(loader)
+
  pixbuf = gdk_pixbuf_loader_get_pixbuf(loader)
 +
  If pixbuf == 0 Then Error.Raise("Errore !")
 
    
 
    
  w = gdk_pixbuf_get_width(Pixbuf)
+
  w = gdk_pixbuf_get_width(Pixbuf)
  Print "Larghezza: "; w; " pixel"
+
  Print "Larghezza: "; w; " pixel"
  h = gdk_pixbuf_get_height(Pixbuf)
+
  h = gdk_pixbuf_get_height(Pixbuf)
  Print "Altezza:  "; h; " pixel"
+
  Print "Altezza:  "; h; " pixel"
  c = gdk_pixbuf_get_n_channels(Pixbuf)
+
  c = gdk_pixbuf_get_n_channels(Pixbuf)
  Print "Canali:    "; c
+
  Print "Canali:    "; c
 
    
 
    
 
  <FONT Color=gray>' ''Verifichiamo che l'immagine scaricata abbia il canale Alfa:''</font>
 
  <FONT Color=gray>' ''Verifichiamo che l'immagine scaricata abbia il canale Alfa:''</font>
  bo = gdk_pixbuf_get_has_alpha(Pixbuf)
+
  bo = gdk_pixbuf_get_has_alpha(Pixbuf)
  If bo = False Then Error.Raise("L'immagine scaricata è priva del canale Alfa !")
+
  If bo = False Then Error.Raise("L'immagine scaricata è priva del canale Alfa !")
 
    
 
    
  dati = gdk_pixbuf_get_pixels(Pixbuf)
+
  dati = gdk_pixbuf_get_pixels(Pixbuf)
  If dati = 0 Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dei pixel dell'immagine !")
+
  If dati == 0 Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dei pixel dell'immagine !")
 
    
 
    
 
  <FONT Color=gray>' ''Carichiamo i dati nel vettore "bb[]" per gestire successivamente i dati grezzi dei pixel:''</font>
 
  <FONT Color=gray>' ''Carichiamo i dati nel vettore "bb[]" per gestire successivamente i dati grezzi dei pixel:''</font>
  st = Memory dati For Read
+
  st = Memory dati For Read
 
    
 
    
  With bb = New Byte[w * h * c]
+
  With bb = New Byte[w * h * c]
    .Read(st, 0, .count)
+
    .Read(st, 0, .count)
  End With
+
  End With
 
    
 
    
 
  <FONT Color=gray>' ''Effettua la correzione della disposizione dei dati RGB dei pixel dell'immagine scaricata:''</font>
 
  <FONT Color=gray>' ''Effettua la correzione della disposizione dei dati RGB dei pixel dell'immagine scaricata:''</font>
  bb2 = Corregge(bb)
+
  bb2 = Corregge(bb)
 
    
 
    
  st.Close
+
  st.Close
 
    
 
    
 
  <FONT Color=gray>' ''Viene preparata la variabile di tipo Image per la gestione dei dati del futuro nuovo file immagine:''</font>
 
  <FONT Color=gray>' ''Viene preparata la variabile di tipo Image per la gestione dei dati del futuro nuovo file immagine:''</font>
  With imago = New Image(w, h, 0, 0)
+
  With imago = New Image(w, h, 0, 0)
    st = Memory .Data For Write
+
    st = Memory .Data For Write
  End With
+
  End With
 
    
 
    
 
  <FONT Color=gray>' ''Scrive i dati presenti nel vettore "bb[]" nell'area di memoria puntata dal Puntatore ".Data" della variabile di tipo "Image":''</font>
 
  <FONT Color=gray>' ''Scrive i dati presenti nel vettore "bb[]" nell'area di memoria puntata dal Puntatore ".Data" della variabile di tipo "Image":''</font>
  bb2.Write(st, 0, bb2.Count)
+
  bb2.Write(st, 0, bb2.Count)
 
    
 
    
  st.Close
+
  st.Close
 
    
 
    
  With PictureBox1
+
  With PictureBox1
    .W = w
+
    .W = w
    .H = h
+
    .H = h
    .Picture = imago.Picture
+
    .Picture = imago.Picture
  End With
+
  End With
 
    
 
    
 
  '''End'''
 
  '''End'''
 
 
   
 
   
 
  '''Private''' Function Corregge(vett As Byte[]) As Byte[]
 
  '''Private''' Function Corregge(vett As Byte[]) As Byte[]
Riga 147: Riga 146:
 
   Dim bb As Byte[]
 
   Dim bb As Byte[]
 
    
 
    
  bb = New Byte[vett.Count]
+
  bb = New Byte[vett.Count]
 
    
 
    
  For i = 0 To vett.Max Step 4
+
  For i = 0 To vett.Max Step 4
    bb[i + 1] = vett[i + 1]
+
    bb[i + 1] = vett[i + 1]
    bb[i + 2] = vett[i]
+
    bb[i + 2] = vett[i]
    bb[i] = vett[i + 2]
+
    bb[i] = vett[i + 2]
    bb[i + 3] = vett[i + 3]
+
    bb[i + 3] = vett[i + 3]
  Next
+
  Next
 
    
 
    
  Return bb
+
  Return bb
 
    
 
    
 
  '''End'''
 
  '''End'''

Versione delle 20:12, 7 dic 2021

Il problema qui posto è quello di come creare una immagine di tipo Image (da assegnare convertita in una Picture ad una PictureBox) direttamente dai dati di un file immagine scaricato da internet, senza che tale file sia stato salvato in un percorso di una cartella nella memoria di massa, e quindi caricato con l'apposito metodo .Load() della Classe Image.

Per scaricare il file immagine ci serviremo delle risorse della Classe HttpClient, attivando i Componenti Gambas gb.net e gb.net.curl. Però tale Classe consente di scaricare in dati formato Stringa il file immagine "così com'è". Vengono, cioè scaricati i dati del file immagine nel suo formato in quanto tale, e non già i suoi dati immagine grezzi. Ciò significa che se viene scaricato un file immagine compresso non potremo fare altro che salvarlo dapprima in memoria dura e solo successivamente caricarlo in memoria RAM con le apposite risorse della Classe Image.

Ricapitolando: l'unica cosa, che abbiamo nella RAM immediatamente dopo lo scarico, è una variabile di tipo Stringa contenente tutti i dati del file immagine. La parte difficile è come assegnare ad una PictureBox i dati del file immagine "così com'è" contenuti dalla variabile di tipo Stringa senza passare preliminarmente per il metodo .Load() della Classe Image.

Il problema può essere risolto, purché l'immagine da scaricare abbia il canale Alfa e dunque sia di formato a 32-bit - RGBA. Bisognerà, però, utilizzare alcune funzioni esterne di gdk_pixbuf richiamando nel progetto Gambas la libreria condivisa: "libgtk-3.so.0.2404.16 ".

Mostriamo di seguito il codice con un esistente indirizzo web di un'immagine PNG da scaricare:

Private myhttp As New HttpClient As "myhttp"  


Library "libgtk-3:0.2404.16"

' GdkPixbufLoader * gdk_pixbuf_loader_new(void)
' Creates a new pixbuf loader object.
Private Extern gdk_pixbuf_loader_new() As Pointer

' gboolean gdk_pixbuf_loader_write (GdkPixbufLoader *loader, const guchar *buf, gsize count, GError **error)'
' Cause a pixbuf loader to parse the next count bytes of an image.
Private Extern gdk_pixbuf_loader_write(lo As Pointer, buf As Pointer, i As Integer, po As Pointer)

' gboolean gdk_pixbuf_loader_close (GdkPixbufLoader *loader, GError **error)'
' Informs a pixbuf loader that no further writes.
Private Extern gdk_pixbuf_loader_close(lo As Pointer, po As Pointer)

' GdkPixbuf * gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)'
' Queries the GdkPixbuf that a pixbuf loader is currently creating.
Private Extern gdk_pixbuf_loader_get_pixbuf(lo As Pointer) As Pointer

' guchar * gdk_pixbuf_get_pixels (const GdkPixbuf *pixbuf)'
' Queries a pointer to the pixel data of a pixbuf.
Private Extern gdk_pixbuf_get_pixels(GdkPixbuf As Pointer) As Pointer

' int gdk_pixbuf_get_width (const GdkPixbuf *pixbuf)'
' Queries the width of a pixbuf.
Private Extern gdk_pixbuf_get_width(GdkPixbuf As Pointer) As Integer

' int gdk_pixbuf_get_height (const GdkPixbuf *pixbuf)'
' Queries the height of a pixbuf.
Private Extern gdk_pixbuf_get_height(GdkPixbuf As Pointer) As Integer

' int gdk_pixbuf_get_n_channels (const GdkPixbuf *pixbuf)'
' Queries the number of channels of a pixbuf.
Private Extern gdk_pixbuf_get_n_channels(GdkPixbuf As Pointer) As Integer

' gboolean gdk_pixbuf_get_has_alpha (const GdkPixbuf *pixbuf)'
' Queries whether a pixbuf has an alpha channel (opacity information).
Private Extern gdk_pixbuf_get_has_alpha(GdkPixbuf As Pointer) As Boolean


Public Sub Button1_Click()
 
' Invia la richiesta al server per scaricare il file immagine:
  myhttp.URL = "http://f.tqn.com/y/painting/1/W/4/k/2/RGB_color_wheel_36.jpg.png"
  myhttp.Timeout = 15

' Lasciando il secondo parametro vuoto, i dati dell'immagine vengono salvati soltanto in memoria:
  myhttp.Get()
    
End

Public Sub MyHTTP_Finished()

 Dim s As String

 MyHTTP.Close
 
' Trasferiamo in una variabile stringa i dati dell'immagine scaricata e salvata in memoria:
 s = myhttp.Peek()
 Print "Immagine scaricata !\n\nDimensione: "; Len(s); " byte"
 
 Immagine(s)
  
End

Private Procedure Immagine(im As String)
 
 Dim bb, bb2 As Byte[]
 Dim w, h As Integer
 Dim loader, pixbuf, dati As Pointer
 Dim c As Byte
 Dim bo As Boolean
 Dim st As Stream
 Dim imago As Image
  
 bb = Byte[].FromString(im)
 
 loader = gdk_pixbuf_loader_new()
 If loader == 0 Then Error.Raise("Errore !")
 
 gdk_pixbuf_loader_write(loader, bb.data, bb.count, 0)
 
 gdk_pixbuf_loader_close(loader, 0)
 
 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader)
 If pixbuf == 0 Then Error.Raise("Errore !")
 
 w = gdk_pixbuf_get_width(Pixbuf)
 Print "Larghezza: "; w; " pixel"
 h = gdk_pixbuf_get_height(Pixbuf)
 Print "Altezza:   "; h; " pixel"
 c = gdk_pixbuf_get_n_channels(Pixbuf)
 Print "Canali:    "; c
  
' Verifichiamo che l'immagine scaricata abbia il canale Alfa:
 bo = gdk_pixbuf_get_has_alpha(Pixbuf)
 If bo = False Then Error.Raise("L'immagine scaricata è priva del canale Alfa !")
  
 dati = gdk_pixbuf_get_pixels(Pixbuf)
 If dati == 0 Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dei pixel dell'immagine !")
  
' Carichiamo i dati nel vettore "bb[]" per gestire successivamente i dati grezzi dei pixel:
 st = Memory dati For Read
  
 With bb = New Byte[w * h * c]
   .Read(st, 0, .count)
 End With
 
' Effettua la correzione della disposizione dei dati RGB dei pixel dell'immagine scaricata:
 bb2 = Corregge(bb)
  
 st.Close
 
' Viene preparata la variabile di tipo Image per la gestione dei dati del futuro nuovo file immagine:
 With imago = New Image(w, h, 0, 0)
   st = Memory .Data For Write
 End With
 
' Scrive i dati presenti nel vettore "bb[]" nell'area di memoria puntata dal Puntatore ".Data" della variabile di tipo "Image":
 bb2.Write(st, 0, bb2.Count)
 
 st.Close
 
 With PictureBox1
   .W = w
   .H = h
   .Picture = imago.Picture
 End With
 
End

Private Function Corregge(vett As Byte[]) As Byte[]
 
 Dim i As Integer
 Dim bb As Byte[]
 
 bb = New Byte[vett.Count]
  
 For i = 0 To vett.Max Step 4
   bb[i + 1] = vett[i + 1]
   bb[i + 2] = vett[i]
   bb[i] = vett[i + 2]
   bb[i + 3] = vett[i + 3]
 Next
  
 Return bb
  
End