Differenze tra le versioni di "Generare un file immagine da una DrawingArea"

Da Gambas-it.org - Wikipedia.
 
(77 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
Per generare un file immagine dal disegno di una ''DrawingArea'', si possono adottare almeno due procedure:
+
Per generare un file immagine dal disegno di una ''DrawingArea'', si possono adottare le seguenti modalità:
 
* utilizzare le sole funzioni di Gambas;
 
* utilizzare le sole funzioni di Gambas;
 +
* utilizzare le funzioni esterne della libreria di ''X11'';
 +
* utilizzare le funzioni esterne delle librerie di ''X11'' e di ''Cairo'';
 
* utilizzare le funzioni esterne delle librerie di ''X11'' e di ''Imlib2''.
 
* utilizzare le funzioni esterne delle librerie di ''X11'' e di ''Imlib2''.
  
  
 
==Utilizzare le sole funzioni di Gambas==
 
==Utilizzare le sole funzioni di Gambas==
L'uso delle sole funzioni fornite dirattemente da Gambas richiede un procedimento più complesso, che può essere così brevemente esplicitato:
+
L'uso delle sole funzioni fornite direttemente da Gambas consente di adottare almeno quattro modalità.
 +
 
 +
===Usando un Oggetto "Image" di appoggio===
 +
La prima modalità è la più semplice fra quelle previste in questa pagina. Consiste nel disegnare in immediata successione la medesima cosa sia nella ''DrawingArea'' che in un distinto Oggetto ''Image'', il quale poi verrà salvato in un file immagine.
 +
 
 +
Mostriamo un semplice esempio pratico:
 +
Private DrawingArea1 As DrawingArea
 +
Private im As Image
 +
 +
 +
Public Sub Form_Open()
 +
 
 +
  With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
 +
    .X = 0
 +
    .Y = 0
 +
    .W = Me.W
 +
    .H = Me.H
 +
    .Background = Color.White
 +
  End With
 +
 
 +
<FONT Color=gray>' ''Crea un'immagine delle medesime fattezze della "DrawingArea":''</font>
 +
  im = New Image(DrawingArea1.W, DrawingArea1.H, DrawingArea1.Background, Image.Standard)
 +
 
 +
End
 +
 
 +
 +
Public Sub DrawingArea1_Draw()  <FONT Color=gray>' ''Nella medesima routine disegna sia sulla "DrawingArea" che nell'Oggetto "Image":''</font>
 +
 
 +
<FONT Color=gray>' ''Disegna sulla "DrawingArea":''</font>
 +
  With Paint
 +
    .Brush = .Color(Color.Orange)
 +
    .Ellipse(100, 100, 100, 100, Rad(0), Rad(360), False)
 +
    .Fill
 +
<FONT Color=gray>' ''Disegna nell'Oggetto "Image":''</font>
 +
    .Begin(im)
 +
    .Brush = .Color(Color.Orange)
 +
    .Ellipse(100, 100, 100, 100, Rad(0), Rad(360), False)
 +
    .Fill
 +
    .End
 +
  End With
 +
 
 +
<FONT Color=gray>' ''Salva il contenuto dell'Oggetto "Image" in un file immagine:''</font>
 +
  im.Save("/tmp/immagine.png", 100)
 +
 
 +
End
 +
 
 +
===Usando la Classe "DesktopWindow" del Componente gb.desktop.x11===
 +
La seconda modalità utilizza la Classe "DesktopWindow"; e pertanto sarà necessario attivare il Componente ''gb.desktop.x11'' .
 +
 
 +
Mostriamo un esempio pratico:
 +
Private DrawingArea1 As DrawingArea
 +
Private Button1 As Button
 +
 +
 +
Public Sub Form_Open()
 +
 
 +
  With Me
 +
    .W = Screen.AvailableWidth * 0.3
 +
    .H = Screen.AvailableHeight * 0.3
 +
    .Center
 +
  End With
 +
  With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
 +
    .X = 0
 +
    .Y = 0
 +
    .W = Me.W
 +
    .H = Me.H * 0.5
 +
  End With
 +
  With Button1 = New Button(Me) As "Button1"
 +
    .W = Me.W * 0.2
 +
    .H = Me.H * 0.3
 +
    .X = (Me.W / 2) - (.W / 2)
 +
    .Y = Me.H * 0.6
 +
  End With
 +
 
 +
End
 +
 +
 +
Public Sub DrawingArea1_Draw()
 +
 
 +
  Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 +
  Dim p As Float[] = [0, 0.34, 0.67, 1]
 +
 
 +
<FONT Color=gray>' ''Disegniamo all'interno della "DrawingArea":''</font>
 +
  With Paint
 +
    .Brush = .LinearGradient(0, 0, DrawingArea1.W, DrawingArea1.H, c, p)
 +
    .Rectangle(0, 0, DrawingArea1.W, DrawingArea1.H)
 +
    .Fill
 +
  .End
 +
  End With
 +
 
 +
End
 +
 +
 +
Public Sub Button1_Click() <FONT Color=gray>' ''Cliccando sul tasto, viene generato il file immagine di quanto mostrato nella "DrawingArea"''</font>
 +
 
 +
  Dim dw As DesktopWindow
 +
  Dim pc As Picture
 +
 
 +
  With dw = New DesktopWindow(DrawingArea1.Handle)
 +
    pc = .GetScreenshot(True)
 +
  End With
 +
   
 +
  pc.Save("/tmp/immagine.png", 100)
 +
 
 +
End
 +
 
 +
===Usando il Metodo ".Screenshot()" della Classe "Desktop" del Componente gb.desktop.x11===
 +
La terza modalità è molto simile alla precedente con la differenza che viene utilizzato il Metodo ".Screenshot()" della Classe "Desktop".
 +
<BR>Anche in questo caso è necessario attivare il Componente ''gb.desktop.x11'' .
 +
 
 +
Mostriamo un esempio pratico:
 +
Private DrawingArea1 As DrawingArea
 +
Private Button1 As Button
 +
 +
 +
Public Sub Form_Open()
 +
 
 +
  With Me
 +
    .W = Screen.AvailableWidth * 0.3
 +
    .H = Screen.AvailableHeight * 0.3
 +
    .Center
 +
  End With
 +
  With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
 +
    .X = 0
 +
    .Y = 0
 +
    .W = Me.W
 +
    .H = Me.H * 0.5
 +
  End With
 +
  With Button1 = New Button(Me) As "Button1"
 +
    .W = Me.W * 0.2
 +
    .H = Me.H * 0.3
 +
    .X = (Me.W / 2) - (.W / 2)
 +
    .Y = Me.H * 0.6
 +
  End With
 +
 
 +
End
 +
 +
 +
Public Sub DrawingArea1_Draw()
 +
 
 +
  Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 +
  Dim p As Float[] = [0, 0.34, 0.67, 1]
 +
 
 +
<FONT Color=gray>' ''Disegnamo all'interno della "DrawingArea":''</font>
 +
  With Paint
 +
    .Brush = .LinearGradient(0, 0, DrawingArea1.W, DrawingArea1.H, c, p)
 +
    .Rectangle(0, 0, DrawingArea1.W, DrawingArea1.H)
 +
    .Fill
 +
    .End
 +
  End With
 +
 
 +
End
 +
 +
 +
Public Sub Button1_Click()
 +
 
 +
  Dim pc As Picture
 +
 
 +
  With pc = Desktop.Screenshot(DrawingArea1.ScreenX, DrawingArea1.ScreenY, DrawingArea1.Width, DrawingArea1.Height)
 +
    .Save("/tmp/immagine.png", 100)
 +
  End With
 +
 
 +
End
 +
 
 +
===Usando la Classe "Printer", nonché la Classe "PdfDocument" del Componente gb.poppler===
 +
La quarta modalità richiede un procedimento più complesso, che può essere così brevemente esplicitato:
 
* disegno e/o scrivo nella DrawingArea;
 
* disegno e/o scrivo nella DrawingArea;
* [[Printer#Stampare_in_un_file_.pdf_o_.ps|creo il file PDF]] mediante la proprietà .OutputFile della Classe Printer;
+
* [[Stampare_in_Gambas#Stampare_in_un_file_PDF|creo il file PDF]] mediante la Proprietà ".OutputFile" della Classe ''Printer'';
* utilizzando il file PDF, [[Codice_essenziale_per_mostrare_un_file_PDF|converto la pagina PDF in una Image]] (è necessario attivare il componente gb.pdf);
+
* utilizzando il file PDF, [[Codice_essenziale_per_mostrare_un_file_PDF_con_le_risorse_del_Componente_gb.poppler|converto la pagina PDF in una Image]] (è necessario attivare il componente gb.poppler); <SUP>&#91;[[#Note|nota 1]]&#93;</sup>
* quindi salvo detta Image con il suo metodo .Save in un file immagine.
+
* quindi salvo detta Image con il suo Metodo ".Save()" in un file immagine.
 
 
  
 
Mostriamo di seguito un esempio:
 
Mostriamo di seguito un esempio:
  '''Public''' Sub DrawingArea1_Draw()
+
  Private DrawingArea1 As DrawingArea
 +
Private Button1 As Button
 +
Private Button2 As Button
 +
Private Printer1 As Printer
 +
 +
Public Sub Form_Open()
 +
 +
  With Me
 +
    .W = Screen.AvailableWidth * 0.5
 +
    .H = Screen.AvailableHeight
 +
    .Center
 +
  End With
 +
  With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
 +
    .X = 0
 +
    .Y = 0
 +
    .W = Me.W * 0.8
 +
    .H = Me.H
 +
    .Background = Color.White
 +
  End With
 +
  With Button1 = New Button(Me) As "Button1"
 +
    .W = Me.W * 0.1
 +
    .H = Me.H * 0.1
 +
    .X = (Me.W / 1.1) - (.W / 2)
 +
    .Y = Me.H * 0.3
 +
    .Text = "1"
 +
  End With
 +
  With Button2 = New Button(Me) As "Button2"
 +
    .W = Me.W * 0.1
 +
    .H = Me.H * 0.1
 +
    .X = (Me.W / 1.1) - (.W / 2)
 +
    .Y = Me.H * 0.6
 +
    .Text = "2"
 +
  End With
 
    
 
    
  With Paint
+
End
    .Brush = Paint.Color(Color.Red)
+
    .MoveTo(200, 200)
+
    .RelLineTo(0, 100)
+
Public Sub DrawingArea1_Draw()
    .Stroke
+
 
    .DrawText("Testo con DrawText", 10, 10, 20, 20)
+
  With Paint
    .End
+
    .Brush = Paint.Color(Color.Red)
  End With
+
    .MoveTo(200, 200)
 +
    .RelLineTo(0, 100)
 +
    .Stroke
 +
    .DrawText("Testo con DrawText", 10, 10, 20, 20)
 +
    .End
 +
  End With
 
      
 
      
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Public''' Sub Button1_Click()
+
  Public Sub Button1_Click()
 
   
 
   
  With Printer1
+
  With Printer1
    .Configure
+
    .Configure
    .Orientation = 0
+
    .Orientation = Printer.Portrait
    .Paper = 2
+
    .Paper = Printer.A4
    .Resolution = Desktop.Resolution
+
    .Resolution = Desktop.Resolution
  <FONT color=gray>' ''Stampa/crea un file .pdf:''</font>
+
  <FONT color=gray>' ''Stampa/crea un file .pdf nella cartella "/tmp":''</font>
    .OutputFile = "''/tmp/mio_file.pdf''"
+
    <FONT color=red>.OutputFile</font> = "/tmp/file.pdf"
    .Print
+
    .Print
  End With
+
  End With
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Public''' Sub Printer1_Draw()
+
  Public Sub Printer1_Draw()
 
   
 
   
 
   DrawingArea1_Draw()
 
   DrawingArea1_Draw()
 
   
 
   
  '''End'''
+
  End
 +
 +
 +
Public Sub Button2_Click()
 +
 +
  Dim pdf As PdfDocument
 +
  Dim im As Image
 +
 
 +
<FONT Color=gray>' ''Apre il file PDF prima generato:''</font>
 +
  pdf = New PdfDocument("/tmp/file.pdf")
 +
   
 +
<FONT Color=gray>' ''Genera una "Image" dalla 1^ pagina del file PDF aperto:''</font>
 +
  im = pdf[0].Render()
 +
 
 +
  im.Save("/tmp/immagine.png", 100)
 +
 +
End
 +
 
 +
===Usando le Classi "MediaPipeline" e "MediaControl" del Componente gb.media===
 +
Questa modalità prevede l'uso delle Classi "MediaPipeline" e "MediaControl" del Componente gb.media.
 +
<BR>In particolare si catturerà quanto mostrato dalla ''DrawingArea'', assegnando il suo numero identificativo alla Proprietà "xid" del plugin "ximagesrc" di GStreamer, e si provvederà a salvare in un file immagine.
 +
 
 +
====Generare un file JPG====
 +
Mostriamo un esempio, nel quale si genererà un file JPG:
 +
Public Sub DrawingArea1_Draw()
 +
 +
  Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 +
  Dim p As Float[] = [0, 0.34, 0.67, 1]
 +
 +
<FONT Color=gray>' ''Disegna all'interno della "DrawingArea":''</font>
 +
  With Paint
 +
    .Brush = .LinearGradient(0, 0, DrawingArea1.W, DrawingArea1.H, c, p)
 +
    .Rectangle(0, 0, DrawingArea1.W, DrawingArea1.H)
 +
    .Fill
 +
  .End
 +
  End With
 +
 +
End
 +
 
   
 
   
 +
Public Sub Button1_Click()
 
   
 
   
'''Public''' Sub Button2_Click()
+
  Dim pl As MediaPipeline
 +
  Dim xis, con, enc, snk As MediaControl
 
   
 
   
   Dim pdf As New PdfDocument
+
   pl = New MediaPipeline
  Dim i As New Image
 
 
   
 
   
 +
  xis = New MediaControl(pl, "ximagesrc")
 +
  xis["xid"] = DrawingArea1.Id
 +
  con = New MediaControl(pl, "videoconvert")
 +
  enc = New MediaControl(pl, "jpegenc")
 +
  snk = New MediaControl(pl, "filesink")
 +
  snk["location"] = "/tmp/immagine.jpg"
 
    
 
    
  With pdf
+
  <FONT Color=gray>' ''Collega fra loro i plugin di "GStreamer":''</font>
    .Open("''/tmp/mio_file.pdf''")
+
  xis.LinkTo(con)
  <FONT color=gray>' ''Se il file pdf è stato caricato correttamente...''</font>
+
  con.LinkTo(enc)
    If .Ready = True Then
+
  enc.LinkTo(snk)
  <FONT color=gray>' ''...allora convertiamo la prima pagina ("indice" delle pagine = 1) in una "Image":''</font>
+
      i = pdf[1].Image
+
  <FONT Color=gray>' ''Effettua la cattura di quanto mostrato dalla "DrawingArea":''</font>
 +
  pl.Play()
 +
 +
  pl.Stop
 +
  pl.Close
 +
 +
End
 +
 
 +
====Generare un file PNG====
 +
Volendo invece generare un file immagine di formato PNG, la seconda sub-routine dell'esempio precedente sarà così impostata:
 +
  Public Sub Button1_Click()
 
   
 
   
<FONT color=gray>' ''Infine salviamo l'Image in un file immagine
+
  Dim pl As MediaPipeline
' ''(è necessario scegliere il tipo di file immagine fra quelli supportati):''</font>
+
  Dim xis, con, enc, snk As MediaControl
      i.Save("''/tmp/mio_file_immagine.xxx''")
 
 
   
 
   
     Else
+
  pl = New MediaPipeline
      Message.Error("&lt;FONT color=darkred>Errore nel caricamento del file PDF !")
+
 +
  xis = New MediaControl(pl, "ximagesrc")
 +
  xis["xid"] = DrawingArea1.Id
 +
  con = New MediaControl(pl, "videoconvert")
 +
  enc = New MediaControl(pl, "pngenc")
 +
  snk = New MediaControl(pl, "filesink")
 +
  snk["location"] = "/tmp/immagine.png"
 +
 
 +
<FONT Color=gray>' ''Collega fra loro i plugin di "GStreamer":''</font>
 +
  xis.LinkTo(con)
 +
  con.LinkTo(enc)
 +
  enc.LinkTo(snk)
 +
 
 +
<FONT Color=gray>' ''Effettua la cattura di quanto mostrato dalla "DrawingArea":''</font>
 +
  pl.Play()
 +
 +
  pl.Stop
 +
  pl.Close
 +
 +
End
 +
 
 +
====Generare un file BMP====
 +
Volendo invece generare un file immagine di formato BMP, la seconda sub-routine dell'esempio precedente sarà così impostata:
 +
  Public Sub Button1_Click()
 +
 +
  Dim pl As MediaPipeline
 +
  Dim xis, con, enc, snk As MediaControl
 +
 +
  pl = New MediaPipeline
 +
 +
  xis = New MediaControl(pl, "ximagesrc")
 +
  xis["xid"] = DrawingArea1.Id
 +
  con = New MediaControl(pl, "videoconvert")
 +
  enc = New MediaControl(pl, "avenc_bmp")
 +
  snk = New MediaControl(pl, "filesink")
 +
  snk["location"] = "/tmp/immagine.bmp"
 +
 
 +
<FONT Color=gray>' ''Collega fra loro i plugin di "GStreamer":''</font>
 +
  xis.LinkTo(con)
 +
  con.LinkTo(enc)
 +
  enc.LinkTo(snk)
 +
 
 +
<FONT Color=gray>' ''Effettua la cattura di quanto mostrato dalla "DrawingArea":''</font>
 +
  pl.Play()
 +
 +
  pl.Stop
 +
  pl.Close
 +
 +
End
 +
 
 +
 
 +
==Uso delle funzioni esterne del API di ''X11''==
 +
L'uso delle risorse della libreria esterna ''X11'', opportunamente combinate con quelle di Gambas, consente un procedimento molto più snello ripetto al precedente. Tale modalità richiede nel codice Gambas la dichiarazione della libreria condivisa: "''libX11.so.6.4.0'' ".
 +
 
 +
Sussistono almeno due modalità.
 +
<BR>Al fine di evitare che la funzione esterna "XGetImage()" ritorni un Puntatore nullo, bisognerà avere massima cura che le dimensioni del ''Form'' siano sufficientemente superiori alle dimensioni della ''DrawingArea'' contenuta.
 +
 
 +
===1<SUP>a</sup> modalità===
 +
La prima modalità prevede l'assegnazione dei dati dei pixel della ''DrawingArea'', contenuti nell'area di memoria puntata dal ''Puntatore'' restituito dalla funzione esterna "XGetImage()" della libreria di X11, direttamente all'area di memoria puntata dalla Proprietà ".Data" di un Oggetto ''Image'' preliminarmente creato.
 +
 
 +
 
 +
Mostriamo un esempio pratico (è necessario porre sul ''Form'' una ''DrawingArea'' e un ''Button''): <SUP>&#091;[[#Note|Nota 2]]&#093;</sup>
 +
Library "libX11:6.4.0"
 +
 +
Public Struct funcs
 +
  create_image As Pointer
 +
  destroy_image As Pointer
 +
  get_pixel As Pointer
 +
  put_pixel As Pointer
 +
  sub_image As Pointer
 +
  add_pixel As Pointer
 +
End Struct
 +
 +
Public Struct XImage
 +
  width As Integer
 +
  height As Integer
 +
  xoffset As Integer
 +
  gformat As Integer
 +
  data As Pointer
 +
  byte_order As Integer
 +
  bitmap_unit As Integer
 +
  bitmap_bit_order As Integer
 +
  bitmap_pad As Integer
 +
  depth As Integer
 +
  bytes_per_line As Integer
 +
  bits_per_pixel As Integer
 +
  red_mask As Long
 +
  green_mask As Long
 +
  blue_mask As Long
 +
  obdata As Pointer
 +
  func As Struct Funcs
 +
End Struct
 +
 +
Private Enum XYBitmap = 0, XYPixmap, ZPixmap
 +
 +
<FONT Color=gray>' ''Display *XOpenDisplay(char *display_name)''
 +
' ''Opens a connection to the X server that controls a display.''</font>
 +
Private Extern XOpenDisplay(display_name As Pointer) As Pointer
 +
 +
<FONT Color=gray>' ''unsigned long XAllPlanes()''
 +
' ''Returns a value with all bits set to 1 suitable for use in a plane argument to a procedure.''</font>
 +
Private Extern XAllPlanes() As Long
 +
 +
<FONT Color=gray>' ''XImage *XGetImage(Display *display, Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)''
 +
' ''Returns a pointer to an XImage structure.''</font>
 +
Private Extern XGetImage(display As Pointer, d As Long, x As Integer, y As Integer, width As Integer, height As Integer, plane_mask As Long, xformat As Integer) As XImage
 +
 
 +
<FONT Color=gray>' ''XCloseDisplay(Display *display)''
 +
' ''Closes the connection to the X server for the display specified in the Display structure and destroys all windows.''</font>
 +
Private Extern XCloseDisplay(display As Pointer)
 +
 +
 +
Public Sub Form_Open()
 +
 +
<FONT Color=gray>' ''Imposta alcune proprietà della "DrawingArea":''</font>
 +
  With DrawingArea1
 +
    .X = 10
 +
    .Y = 10
 +
    .W = 400
 +
    .H = 400
 +
    .Background = Color.White
 +
  End With
 +
 
 +
End
 +
 +
 +
Public Sub DrawingArea1_Draw()
 +
 
 +
  Dim colori As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 +
  Dim p As Float[] = [0, 0.34, 0.67, 1]
 +
 
 +
<FONT Color=gray>' ''Disegnamo all'interno della "DrawingArea":''</font>
 +
  With Paint
 +
    .Brush = .LinearGradient(10, 40, 300, 40, colori, p)
 +
    .Rectangle(10, 40, 300, 40)
 +
     .Fill
 +
<FONT Color=gray>' ''Imposta il colore dei caratteri:''</font>
 +
    .Brush = .Color(Color.Red)
 +
<FONT Color=gray>' ''Imposta il tipo di carattere:''</font>
 +
    .Font.Name = "Arial"
 +
<FONT Color=gray>' ''Imposta la dimensione dei caratteri:''</font>
 +
    .Font.Size = 16
 +
<FONT Color=gray>' ''Scrive sull'Area di Disegno il seguente testo di caratteri nella posizione X, Y all'interno di un quadrilatero virtuale W, H''
 +
' ''con i metodi .RichText  e .Text, ma occorrerà uno ".Stroke" a seguire (però .Stroke tende a dare l'effetto del grassetto):''</font>
 +
    .RichText("Testo con RichText", 200, 20, 16, 100)
 +
    .Text("Testo con Text", 10, 30, 20, 20)
 +
    .Stroke
 +
<FONT Color=gray>' ''...oppure (meglio, perché non dà l'effetto del grassetto) ".fill":''</font>
 +
    .Fill
 +
<FONT Color=gray>' ''Con il metodo .DrawText non è necessario l'uso di ".Stroke", né di ".Fill":''</font>
 +
    .DrawText("Testo con DrawText", 10, 10, 20, 20)
 +
    .End
 +
  End With
 +
 
 +
End
 +
 +
 +
Public Sub Button1_Click()
 +
 +
  Dim dsp As Pointer
 +
  Dim xi As XImage
 +
  Dim im As Image
 +
  Dim st As Stream
 +
  Dim i As Integer
 +
 
 +
  dsp = XOpenDisplay(0)
 +
  If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")
 +
 
 +
<FONT Color=gray>' ''Otteniamo un puntatore alla "Struttura" contenente i dati dell'immagine disegnata nella "DrawingArea":''</font>
 +
  xi = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
 +
  If IsNull(xi) Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
 +
     
 +
<FONT Color=gray>' ''Creiamo un semplice oggetto di tipo "Image":''</font>
 +
  im = New Image(DrawingArea1.W, DrawingArea1.H)
 +
  If IsNull(im) Then Error.Raise("Impossibile creare un oggetto 'Image' !")
 +
 
 +
<FONT Color=gray>' ''Utilizziamo ovviamente i "Memory Stream" per scrivere nell'area di memoria dell'oggetto "Image", destinata ai dati attinenti ai pixel, il cui indirizzo di memoria è ritornato dalla proprietà ".Data" della variabile di tipo "Image":''</font>
 +
  st = Memory im.Data For Write
 +
 
 +
  For i = 0 To im.W * im.H * Len(im.Format)
 +
    Write #st, Byte@(xi.data + i) As Byte
 +
  Next
 +
 
 +
  st.Close
 +
 
 +
<FONT Color=gray>' ''Genera in fine il file immagine:''</font>
 +
  im.Save("<FONT Color=darkgreen>''/percorso/del/file/immagine.xxx''</font>", 100)
 +
 
 +
<FONT Color=gray>' ''Va in chiusura:''</font>
 +
  XCloseDisplay(dsp)
 +
 
 +
End
 +
 
 +
===2<SUP>a</sup> modalità===
 +
La seconda modalità prevede l'assegnazione dei dati dei pixel della ''DrawingArea'' all'area di memoria puntata dal membro "''*data'' " della Struttura "''GB_IMG''" contenuta nel file sorgente "''.../main/lib/image/gb.image.h'' ". <SUP>&#91;[[#Note|nota 3]]&#93;</sup>
 +
 
 +
Mostriamo di seguito un semplice esempio, nel quale disegneremo all'interno di una ''DrawingArea'' una riga colorata con tutta la gamma dei colori dal blu al rosso. Al termine salveremo in un file immagine il disegno presente nella ''DrawingArea''.
 +
Library "libX11:6.4.0"
 +
 +
Public Struct funcs
 +
  create_image As Pointer
 +
  destroy_image As Pointer
 +
  get_pixel As Pointer
 +
  put_pixel As Pointer
 +
  sub_image As Pointer
 +
  add_pixel As Pointer
 +
End Struct
 +
 +
Public Struct XImage
 +
  width As Integer
 +
  height As Integer
 +
  xoffset As Integer
 +
  gformat As Integer
 +
  data As Pointer
 +
  byte_order As Integer
 +
  bitmap_unit As Integer
 +
  bitmap_bit_order As Integer
 +
  bitmap_pad As Integer
 +
  depth As Integer
 +
  bytes_per_line As Integer
 +
  bits_per_pixel As Integer
 +
  red_mask As Long
 +
  green_mask As Long
 +
  blue_mask As Long
 +
  obdata As Pointer
 +
  func As Struct Funcs
 +
End Struct
 +
 +
Private Enum XYBitmap = 0, XYPixmap, ZPixmap
 +
 +
<FONT Color=gray>' ''Display *XOpenDisplay(char *display_name)''
 +
' ''Opens a connection to the X server that controls a display.''</font>
 +
Private Extern XOpenDisplay(display_name As Pointer) As Pointer
 +
 +
<FONT Color=gray>' ''unsigned long XAllPlanes()''
 +
' ''Returns a value with all bits set to 1 suitable for use in a plane argument to a procedure.''</font>
 +
Private Extern XAllPlanes() As Long
 +
 +
<FONT Color=gray>' ''XImage *XGetImage(Display *display, Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)''
 +
' ''Returns a pointer to an XImage structure.''</font>
 +
Private Extern XGetImage(displayP As Pointer, d As Long, x As Integer, y As Integer, width As Integer, height As Integer, plane_mask As Long, xformat As Integer) As XImage
 +
 
 +
<FONT color=gray>' ''XCloseDisplay(Display *display)''
 +
' ''Closes the connection to the X server for the display specified in the Display structure and destroys all windows.''</font>
 +
Private Extern XCloseDisplay(display As Pointer)
 +
 +
 
 +
Public Sub Form_Open()
 +
 
 +
  DrawingArea1.Background = Color.White
 +
 +
End
 +
 +
 +
Public Sub DrawingArea1_Draw()
 +
 
 +
  Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 +
  Dim p As Float[] = [0, 0.34, 0.67, 1]
 
      
 
      
    Endif
+
<FONT Color=gray>' ''Disegnamo all'interno della "DrawingArea":''</font>
 +
  With Paint
 +
    .Brush = .LinearGradient(10, 40, 300, 40, c, p)
 +
    .Rectangle(10, 40, 300, 40)
 +
    .Fill
 +
    .End
 +
  End With
 +
 +
End
 
   
 
   
  End With
 
 
   
 
   
  '''End'''
+
  Public Sub Button1_Click()
 +
 
 +
  Dim dsp, p, p1 As Pointer
 +
  Dim xi As XImage
 +
  Dim bb As Byte[]
 +
  Dim i As Integer
 +
  Dim st As Stream
 +
  Dim im As Image
 +
   
 +
  dsp = XOpenDisplay(0)
 +
  If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")
 +
   
 +
<FONT Color=gray>' ''Otteniamo un puntatore alla "Struttura" contenente i dati dell'immagine disegnata nella "DrawingArea":''</font>
 +
  xi = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
 +
  If IsNull(xi) Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
 +
   
 +
  bb = New Byte[]   
 +
 
 +
  For i = 0 To (DrawingArea1.W * DrawingArea1.H * 4) - 1
 +
    bb.Push(Byte@(xi.data + i))
 +
  Next
 +
   
 +
  im = New Image(DrawingArea1.W, DrawingArea1.H)
 +
   
 +
  p = Object.Address(im)
 +
   
 +
  p1 = Pointer@(p + (SizeOf(gb.Pointer) * 2))  <SUP><FONT Color=gray>'</font> &#091;[[#Note|Nota 4]]&#093;</sup>
 +
   
 +
<FONT Color=gray>' ''Scriviamo i dati immagine grezzi, ottenuti dalla funzione XGetImage(), nell'area di memoria puntata dal membro "*data" della Struttura "GB_IMG" contenuta nel file sorgente ".../main/lib/image/gb.image.h":''</font>
 +
  st = Memory p1 For Write
 +
  bb.Write(st, 0, bb.Count)
 +
  st.Close
 +
 
 +
<FONT Color=gray>' ''Generiamo dunque il file immagine:''</font>
 +
  im.Save("<FONT Color=darkgreen>''/percorso/dove/salvare/il/file/immagine.xxx''</font>")
 +
 
 +
<FONT Color=gray>' ''Va in chiusura:''</font>
 +
  XCloseDisplay(dsp)
 +
 +
End
 +
 
 +
 
 +
==Uso delle funzioni esterne del API di ''X11'' e di ''Cairo''==
 +
L'uso delle risorse delle librerie esterne ''X11'' e ''Cairo'' richiede nel codice Gambas la dichiarazione delle seguenti librerie dinamiche condivise:
 +
* "''libX11.so.6.4.0'' "
 +
* "''libcairo.so.2.11802.2'' "
  
 +
Mostriamo di seguito un semplice esempio, nel quale disegneremo all'interno di una ''DrawingArea'' una riga colorata con tutta la gamma dei colori dal blu al rosso. Al termine salveremo in un file immagine il disegno presente nella ''DrawingArea''.
 +
<BR>Al fine di evitare che la funzione esterna "XGetImage()" ritorni un Puntatore nullo, bisognerà avere massima cura che le dimensioni del ''Form'' siano sufficientemente superiori alle dimensioni della ''DrawingArea'' contenuta.
 +
Library "<FONT color=blue>libX11:6.4.0</font>"
 +
 +
<FONT color=gray>' ''Display *XOpenDisplay(char *display_name)''
 +
' ''Opens a connection to the X server that controls a display.''</font>
 +
Private Extern XOpenDisplay(display_name As Pointer) As Pointer
 +
 +
<FONT color=gray>' ''int XDefaultScreen(display)''
 +
' ''Returns the default screen number.''</font>
 +
Private Extern XDefaultScreen(display As Pointer) As Integer
 +
 +
<FONT color=gray>' ''Visual *XDefaultVisual(display, screen_number)''
 +
' ''Returns the default visual type for the specified screen.''</font>
 +
Private Extern XDefaultVisual(display As Pointer, scr_num As Integer) As Pointer
 +
 
 +
<FONT color=gray>' ''XCloseDisplay(Display *display)''
 +
' ''Closes the connection to the X server for the display specified in the Display structure and destroys all windows.''</font>
 +
Private Extern XCloseDisplay(display As Pointer)
 +
 +
 +
Library "<FONT color=red>libcairo:2.11802.2</font>"
 +
 +
<FONT Color=gray>' ''cairo_surface_t * cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int width, int height)''
 +
' ''Creates an Xlib surface that draws to the given drawable.''</font>
 +
Private Extern cairo_xlib_surface_create(dpy As Pointer, drawable As Long, visual As Pointer, width As Integer, height As Integer) As Pointer
 +
 +
<FONT Color=gray>' ''cairo_status_t cairo_surface_write_to_png(cairo_surface_t *surface, const char *filename)''
 +
' ''Writes the contents of surface to a new file filename as a PNG image.''</font>
 +
Private Extern cairo_surface_write_to_png(cairo_surface As Pointer, filename As String) As Integer
 +
 +
<FONT Color=gray>' ''void cairo_surface_destroy(cairo_surface_t *surface)''
 +
' ''Decreases the reference count on surface by one.''</font>
 +
Private Extern cairo_surface_destroy(cairo_surface As Pointer)
 +
 +
 +
Public Sub Form_Open()
 +
 +
  DrawingArea1.Background = Color.White
 +
 +
End
 +
 +
 +
Public Sub DrawingArea1_Draw()
 +
 +
  Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 +
  Dim p As Float[] = [0, 0.34, 0.67, 1]
 +
   
 +
<FONT Color=gray>' ''Disegnamo all'interno della "DrawingArea":''</font>
 +
  With Paint
 +
    .Brush = .LinearGradient(10, 40, 300, 40, c, p)
 +
    .Rectangle(10, 40, 300, 40)
 +
    .Fill
 +
    .End
 +
  End With
 +
 +
End
 +
 +
 +
Public Sub Button1_Click()
 +
 +
  Dim dsp, vis, surface As Pointer
 +
  Dim scr, err As Integer
 +
 +
  dsp = XOpenDisplay(0)
 +
  If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")
 +
 +
  scr = XDefaultScreen(dsp)
 +
  vis = XDefaultVisual(dsp, scr)
 +
  If vis == 0 Then Error.Raise("Errore !")
 +
 +
<FONT Color=gray>' ''Ottiene la superficie grafica della "DrawingArea":''</font>
 +
  surface = cairo_xlib_surface_create(dsp, DrawingArea1.Handle, vis, DrawingArea1.W, DrawingArea1.H)
 +
  If surface == 0 Then Error.Raise("Errore !")
 +
 +
<FONT Color=gray>' ''Si salva il disegno della superficie grafica della "DrawingArea" in un file immagine .png:''</font>
 +
  err = cairo_surface_write_to_png(surface, "/tmp/immagine.png")
 +
  If err > 0 Then Error.Raise("Errore nella creazione del file immagine .png !")
 +
 +
<FONT Color=gray>' ''Va in chiusura:''</font>
 +
  cairo_surface_destroy(surface)
 +
  XCloseDisplay(dsp)
 +
 +
End
  
  
 
==Uso delle funzioni esterne del API di ''X11'' e di ''ImLib2''==
 
==Uso delle funzioni esterne del API di ''X11'' e di ''ImLib2''==
L'uso delle risorse delle librerie esterne ''X11'' e ''ImLib2'' consente un procedimento molto più snello ripetto al precedente. Tale modalità richiede nel codice Gambas la dichiarazione delle seguenti librerie dinamiche condivise:
+
L'uso delle risorse delle librerie esterne ''X11'' e ''ImLib2'' richiede nel codice Gambas la dichiarazione delle seguenti librerie dinamiche condivise:
* "''libX11.so.6.3.0''"
+
* "''libX11.so.6.4.0'' "
* "''libImlib2.so.1.4.6''"
+
* "''libImlib2.so.1.12.3'' "
  
 
+
Mostriamo di seguito un semplice esempio, nel quale disegneremo all'interno di una ''DrawingArea'' una riga colorata con tutta la gamma dei colori dal blu al rosso. Al termine salveremo in un file immagine il disegno presente nella ''DrawingArea''.
Mostriamo di seguito un semplice esempio, nel quale disegneremo all'interno di una ''DrawingArea'' una riga colorata con tutta la gamma dei colori dal blu al rosso. Al termine salveremo in un file immagine il disegno presente nella ''DrawingArea'':
+
<BR>Al fine di evitare che la funzione esterna "XGetImage()" ritorni un Puntatore nullo, bisognerà avere massima cura che le dimensioni del ''Form'' siano sufficientemente superiori alle dimensioni della ''DrawingArea'' contenuta.
  Library "libX11:6.3.0"
+
  Library "<FONT color=blue>libX11:6.4.0</font>"
 +
 +
Public Struct funcs
 +
  create_image As Pointer
 +
  destroy_image As Pointer
 +
  get_pixel As Pointer
 +
  put_pixel As Pointer
 +
  sub_image As Pointer
 +
  add_pixel As Pointer
 +
End Struct
 +
 +
Public Struct XImage
 +
  width As Integer
 +
  height As Integer
 +
  xoffset As Integer
 +
  gformat As Integer
 +
  data As Pointer
 +
  byte_order As Integer
 +
  bitmap_unit As Integer
 +
  bitmap_bit_order As Integer
 +
  bitmap_pad As Integer
 +
  depth As Integer
 +
  bytes_per_line As Integer
 +
  bits_per_pixel As Integer
 +
  red_mask As Long
 +
  green_mask As Long
 +
  blue_mask As Long
 +
  obdata As Pointer
 +
  func As Struct Funcs
 +
End Struct
 
   
 
   
 
  Private Enum XYBitmap = 0, XYPixmap, ZPixmap
 
  Private Enum XYBitmap = 0, XYPixmap, ZPixmap
Riga 90: Riga 769:
 
  <FONT Color=gray>' ''Display *XOpenDisplay(char *display_name)''
 
  <FONT Color=gray>' ''Display *XOpenDisplay(char *display_name)''
 
  ' ''Opens a connection to the X server that controls a display.''</font>
 
  ' ''Opens a connection to the X server that controls a display.''</font>
  Private Extern XOpenDisplay(display$ As String) As Pointer
+
  Private Extern XOpenDisplay(display_name As Pointer) As Pointer
 
   
 
   
 
  <FONT Color=gray>' ''unsigned long XAllPlanes()''
 
  <FONT Color=gray>' ''unsigned long XAllPlanes()''
Riga 98: Riga 777:
 
  <FONT Color=gray>' ''XImage *XGetImage(Display *display, Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)''
 
  <FONT Color=gray>' ''XImage *XGetImage(Display *display, Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)''
 
  ' ''Returns a pointer to an XImage structure.''</font>
 
  ' ''Returns a pointer to an XImage structure.''</font>
  Private Extern XGetImage(displayP As Pointer, d As Long, xI As Integer, yI As Integer, wid As Integer, hei As Integer, plane_mask As Long, formatI As Integer) As Pointer
+
  Private Extern XGetImage(display As Pointer, d As Long, x As Integer, y As Integer, width As Integer, height As Integer, plane_mask As Long, xformat As Integer) As XImage
 
    
 
    
 
  <FONT color=gray>' ''XCloseDisplay(Display *display)''
 
  <FONT color=gray>' ''XCloseDisplay(Display *display)''
 
  ' ''Closes the connection to the X server for the display specified in the Display structure and destroys all windows.''</font>
 
  ' ''Closes the connection to the X server for the display specified in the Display structure and destroys all windows.''</font>
  Private Extern XCloseDisplay(displayP As Pointer)
+
  Private Extern XCloseDisplay(display As Pointer)
 
   
 
   
 
   
 
   
  Library "libImlib2:1.4.6"
+
  Library "<FONT Color=red>libImlib2:1.12.3</font>"
 
   
 
   
 
  <FONT Color=gray>' ''Imlib_Image imlib_create_image_using_data(int width, int height, DATA32 * data)''
 
  <FONT Color=gray>' ''Imlib_Image imlib_create_image_using_data(int width, int height, DATA32 * data)''
Riga 113: Riga 792:
 
  <FONT Color=gray>' ''void imlib_context_set_image(Imlib_Image image)''
 
  <FONT Color=gray>' ''void imlib_context_set_image(Imlib_Image image)''
 
  ' ''Sets the current image Imlib2 will be using with its function calls.''</font>
 
  ' ''Sets the current image Imlib2 will be using with its function calls.''</font>
  Private Extern imlib_context_set_image(Imlib_Image As Pointer)
+
  Private Extern imlib_context_set_image(Iimage As Pointer)
 
   
 
   
 
  <FONT Color=gray>' ''void imlib_image_set_has_alpha(char has_alpha)''
 
  <FONT Color=gray>' ''void imlib_image_set_has_alpha(char has_alpha)''
Riga 123: Riga 802:
 
  Private Extern imlib_save_image(filename As String)
 
  Private Extern imlib_save_image(filename As String)
 
   
 
   
 +
<FONT Color=gray>' ''void imlib_free_image(void)''
 +
' ''Frees the image that is set as the current image in Imlib2's context.''</font>
 +
Private Extern imlib_free_image()
 +
 +
 +
Public Sub Form_Open()
 
   
 
   
'''Public''' Sub Form_Open()
 
 
 
 
   DrawingArea1.Background = Color.White
 
   DrawingArea1.Background = Color.White
 
   
 
   
  '''End'''
+
  End
 +
 
   
 
   
 +
Public Sub DrawingArea1_Draw()
 
   
 
   
'''Public''' Sub DrawingArea1_Draw()
 
 
 
 
   Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 
   Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 
   Dim p As Float[] = [0, 0.34, 0.67, 1]
 
   Dim p As Float[] = [0, 0.34, 0.67, 1]
 
      
 
      
 
  <FONT Color=gray>' ''Disegnamo all'interno della "DrawingArea":''</font>
 
  <FONT Color=gray>' ''Disegnamo all'interno della "DrawingArea":''</font>
  With Paint
+
  With Paint
    .Begin(DrawingArea1)
+
    .Brush = .LinearGradient(10, 40, 300, 40, c, p)
    .Brush = .LinearGradient(10, 40, 300, 40, c, p)
+
    .Rectangle(10, 40, 300, 40)
    .Rectangle(10, 40, 300, 40)
+
    .Fill
    .Fill
+
    .End
    .End
+
  End With
  End With
 
 
   
 
   
  '''End'''
+
  End
 
   
 
   
 
   
 
   
  '''Public''' Sub Button1_Click()
+
  Public Sub Button1_Click()
 
   
 
   
   Dim dsp, XImage, immago As Pointer
+
   Dim dsp, imago As Pointer
   Dim st as Stream
+
   Dim xi As XImage
 +
   
 +
  dsp = XOpenDisplay(0)
 +
  If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")
 
    
 
    
  dsp = XOpenDisplay(Null)
 
   
 
 
  <FONT Color=gray>' ''Otteniamo un puntatore alla "Struttura" contenente i dati dell'immagine disegnata nella "DrawingArea":''</font>
 
  <FONT Color=gray>' ''Otteniamo un puntatore alla "Struttura" contenente i dati dell'immagine disegnata nella "DrawingArea":''</font>
  XImage = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
+
  xi = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
+
  If IsNull(xi) Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
<FONT Color=gray>' ''Otteniamo l'indirizzo di memoria dei dati grezzi dell'immagine puntati dalla Struttura "XImage":''</font>
+
     
  st = Memory XImage For Read
 
  Seek #st, 16
 
  Read #st, immago
 
  st.Close
 
 
 
  <FONT Color=gray>' ''Viene creata l'immagine dai dati grezzi passando il "Puntatore" ai dati grezzi dell'immagine:''</font>
 
  <FONT Color=gray>' ''Viene creata l'immagine dai dati grezzi passando il "Puntatore" ai dati grezzi dell'immagine:''</font>
  immago = imlib_create_image_using_data(DrawingArea1.W, DrawingArea1.H, immago)
+
  imago = imlib_create_image_using_data(DrawingArea1.W, DrawingArea1.H, xi.data)
+
  If imago == 0 Then Error.Raise("Impossibile creare l'immagine dai dati grezzi acquisiti !")
  imlib_context_set_image(immago)
+
   
 +
  imlib_context_set_image(imago)
 
      
 
      
  <FONT Color=gray>' ''L'immagine creata viene salvata nel nuovo file immagine, indicando il suo percorso comprensivo dell'estenzione del formato immagine desiderato:''</font>
+
  <FONT Color=gray>' ''L'immagine creata viene salvata in un file immagine.''
  imlib_save_image("''/percorso/del/file/immagine/creato''")
+
' ''Al nome del file immagine, da creare, <U>va esplicitata l'estensione del formato immagine desiderato</u>:''</font>
 +
  imlib_save_image("<FONT Color=darkgreen>''/percorso/dove/salvare/il/file/immagine.xxx''</font>")
 
    
 
    
 
  <FONT Color=gray>' ''Va in chiusura:''</font>
 
  <FONT Color=gray>' ''Va in chiusura:''</font>
  XCloseDisplay(dsp)
+
  imlib_free_image()
 +
  XCloseDisplay(dsp)
 
   
 
   
  '''End'''
+
  End
 +
 
 +
 
 +
 
 +
=Note=
 +
[1] Vedere anche questa pagina della Wiki: [[Convertire una pagina di un file PDF in una immagine con le risorse del Componente gb.poppler]]
 +
 
 +
[2] Vedere anche questa pagina della Wiki: [[Passare direttamente ad un oggetto Image i dati grezzi dei pixel di una DrawingArea mediante le risorse del API di X11]]
 +
 
 +
[3] Spieghiamo brevemente perché sia necessario spostarsi al byte, di indice pari al valore restituito da ''SizeOf(gb.Pointer)'', dell'area di memoria puntata dal Puntatore ''XImage''.
 +
<BR>Bisogna innanzitutto tenere in considerazione la omonima Struttura XImage restituita dalla funzione "XGetImage()", che può essere presa in visione qui:
 +
<BR>http://tronche.com/gui/x/xlib/graphics/images.html#XImage
 +
<BR>Ebbene, il quinto membro di detta Struttura
 +
char *data;<FONT Color=transparent>............</font><FONT Color=gray>''/* pointer to image data */''</font>
 +
è una variabile Puntatore di tipo ''char'', che contiene l'indirizzo dell'area di memoria ove sono stipati i dati dell'immagine mostrata dalla DrawingArea.
 +
<BR>Va precisato che, come evidente, nell'esempio in Gambas noi operiamo semplicemente sull'area di memoria riservata dalla predetta funzione "XGetImage()" e puntata dall'apposita variabile XImage. Insomma, non abbiamo passato una variabile di tipo Struttura (come in realtà è previsto nella libreria esterna di X11), ma semplicemente un Puntatore all'area di memoria riservata coerentemente corrispondente a quella della omonima Struttura prevista dalla funzione "XGetImage()".
 +
<BR>Perché dobbiamo spostarci al byte di indice uguale al doppio dei byte di memoria, occupati da una variabile di tipo Puntatore, per leggere il valore di quell'indirizzo di memoria ?
 +
<BR>La risposta è nei quattro membri precedenti, i quali sono tutti di tipo Intero, e pertanto occupano ciascuno un numero di byte di memoria pari a ''SizeOf(gb.Integer)'' e complessivamente: ''SizeOf(gb.Integer)'' + ''SizeOf(gb.Integer)'' = ''SizeOf(gb.Pointer)''.
 +
<BR>Il valore del Puntatore (ossia l'indirizzo di memoria dei dati grezzi dell'immagine puntati dalla omonima Struttura "XImage" della libreria esterna di X11), che a noi interessa, si trova a cominciare dal byte di indice = ''SizeOf(gb.Pointer)''. Il valore dell'indirizzo di memoria verrà da noi salvato nel tipo di variabile a ciò deputato, ossia il Puntatore, e così passato alla successiva funzione "imlib_create_image_using_data()", come da essa richiesto.
  
 +
[4] Al riguardo vedasi anche la pagina della Wiki: [[Gestire un oggetto Image agendo direttamente sulle risorse dei sorgenti Gambas]]
  
  

Versione attuale delle 10:18, 19 nov 2024

Per generare un file immagine dal disegno di una DrawingArea, si possono adottare le seguenti modalità:

  • utilizzare le sole funzioni di Gambas;
  • utilizzare le funzioni esterne della libreria di X11;
  • utilizzare le funzioni esterne delle librerie di X11 e di Cairo;
  • utilizzare le funzioni esterne delle librerie di X11 e di Imlib2.


Utilizzare le sole funzioni di Gambas

L'uso delle sole funzioni fornite direttemente da Gambas consente di adottare almeno quattro modalità.

Usando un Oggetto "Image" di appoggio

La prima modalità è la più semplice fra quelle previste in questa pagina. Consiste nel disegnare in immediata successione la medesima cosa sia nella DrawingArea che in un distinto Oggetto Image, il quale poi verrà salvato in un file immagine.

Mostriamo un semplice esempio pratico:

Private DrawingArea1 As DrawingArea
Private im As Image


Public Sub Form_Open()
 
 With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
   .X = 0
   .Y = 0
   .W = Me.W
   .H = Me.H
   .Background = Color.White
 End With
 
' Crea un'immagine delle medesime fattezze della "DrawingArea":
 im = New Image(DrawingArea1.W, DrawingArea1.H, DrawingArea1.Background, Image.Standard)
 
End
 

Public Sub DrawingArea1_Draw()   ' Nella medesima routine disegna sia sulla "DrawingArea" che nell'Oggetto "Image":
 
' Disegna sulla "DrawingArea":
 With Paint
   .Brush = .Color(Color.Orange)
   .Ellipse(100, 100, 100, 100, Rad(0), Rad(360), False)
   .Fill
' Disegna nell'Oggetto "Image":
   .Begin(im)
   .Brush = .Color(Color.Orange)
   .Ellipse(100, 100, 100, 100, Rad(0), Rad(360), False)
   .Fill
   .End
 End With
 
' Salva il contenuto dell'Oggetto "Image" in un file immagine:
 im.Save("/tmp/immagine.png", 100)
  
End

Usando la Classe "DesktopWindow" del Componente gb.desktop.x11

La seconda modalità utilizza la Classe "DesktopWindow"; e pertanto sarà necessario attivare il Componente gb.desktop.x11 .

Mostriamo un esempio pratico:

Private DrawingArea1 As DrawingArea
Private Button1 As Button


Public Sub Form_Open()
 
 With Me
   .W = Screen.AvailableWidth * 0.3
   .H = Screen.AvailableHeight * 0.3
   .Center
 End With
 With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
   .X = 0
   .Y = 0
   .W = Me.W
   .H = Me.H * 0.5
 End With
 With Button1 = New Button(Me) As "Button1"
   .W = Me.W * 0.2
   .H = Me.H * 0.3
   .X = (Me.W / 2) - (.W / 2)
   .Y = Me.H * 0.6
 End With
  
End


Public Sub DrawingArea1_Draw()
 
 Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 Dim p As Float[] = [0, 0.34, 0.67, 1]
 
' Disegniamo all'interno della "DrawingArea":
 With Paint
   .Brush = .LinearGradient(0, 0, DrawingArea1.W, DrawingArea1.H, c, p)
   .Rectangle(0, 0, DrawingArea1.W, DrawingArea1.H)
   .Fill
  .End
 End With
  
End


Public Sub Button1_Click() ' Cliccando sul tasto, viene generato il file immagine di quanto mostrato nella "DrawingArea"
 
 Dim dw As DesktopWindow
 Dim pc As Picture
 
 With dw = New DesktopWindow(DrawingArea1.Handle)
   pc = .GetScreenshot(True)
 End With
   
 pc.Save("/tmp/immagine.png", 100)
  
End

Usando il Metodo ".Screenshot()" della Classe "Desktop" del Componente gb.desktop.x11

La terza modalità è molto simile alla precedente con la differenza che viene utilizzato il Metodo ".Screenshot()" della Classe "Desktop".
Anche in questo caso è necessario attivare il Componente gb.desktop.x11 .

Mostriamo un esempio pratico:

Private DrawingArea1 As DrawingArea
Private Button1 As Button


Public Sub Form_Open()
 
 With Me
   .W = Screen.AvailableWidth * 0.3
   .H = Screen.AvailableHeight * 0.3
   .Center
 End With
 With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
   .X = 0
   .Y = 0
   .W = Me.W
   .H = Me.H * 0.5
 End With
 With Button1 = New Button(Me) As "Button1"
   .W = Me.W * 0.2
   .H = Me.H * 0.3
   .X = (Me.W / 2) - (.W / 2)
   .Y = Me.H * 0.6
 End With
  
End


Public Sub DrawingArea1_Draw()
 
 Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 Dim p As Float[] = [0, 0.34, 0.67, 1]
  
' Disegnamo all'interno della "DrawingArea":
 With Paint
   .Brush = .LinearGradient(0, 0, DrawingArea1.W, DrawingArea1.H, c, p)
   .Rectangle(0, 0, DrawingArea1.W, DrawingArea1.H)
   .Fill
   .End
 End With
  
End


Public Sub Button1_Click()
 
 Dim pc As Picture
 
 With pc = Desktop.Screenshot(DrawingArea1.ScreenX, DrawingArea1.ScreenY, DrawingArea1.Width, DrawingArea1.Height)
   .Save("/tmp/immagine.png", 100)
 End With
 
End

Usando la Classe "Printer", nonché la Classe "PdfDocument" del Componente gb.poppler

La quarta modalità richiede un procedimento più complesso, che può essere così brevemente esplicitato:

  • disegno e/o scrivo nella DrawingArea;
  • creo il file PDF mediante la Proprietà ".OutputFile" della Classe Printer;
  • utilizzando il file PDF, converto la pagina PDF in una Image (è necessario attivare il componente gb.poppler); [nota 1]
  • quindi salvo detta Image con il suo Metodo ".Save()" in un file immagine.

Mostriamo di seguito un esempio:

Private DrawingArea1 As DrawingArea
Private Button1 As Button
Private Button2 As Button
Private Printer1 As Printer

Public Sub Form_Open()

 With Me
   .W = Screen.AvailableWidth * 0.5
   .H = Screen.AvailableHeight
   .Center
 End With
 With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
   .X = 0
   .Y = 0
   .W = Me.W * 0.8
   .H = Me.H
   .Background = Color.White
 End With
 With Button1 = New Button(Me) As "Button1"
   .W = Me.W * 0.1
   .H = Me.H * 0.1
   .X = (Me.W / 1.1) - (.W / 2)
   .Y = Me.H * 0.3
   .Text = "1"
 End With
 With Button2 = New Button(Me) As "Button2"
   .W = Me.W * 0.1
   .H = Me.H * 0.1
   .X = (Me.W / 1.1) - (.W / 2)
   .Y = Me.H * 0.6
   .Text = "2"
 End With
 
End


Public Sub DrawingArea1_Draw()
 
 With Paint
   .Brush = Paint.Color(Color.Red)
   .MoveTo(200, 200)
   .RelLineTo(0, 100)
   .Stroke
   .DrawText("Testo con DrawText", 10, 10, 20, 20)
   .End
 End With
    
End


Public Sub Button1_Click()

 With Printer1
   .Configure
   .Orientation = Printer.Portrait
   .Paper = Printer.A4
   .Resolution = Desktop.Resolution
' Stampa/crea un file .pdf nella cartella "/tmp":
   .OutputFile = "/tmp/file.pdf"
   .Print
 End With

End


Public Sub Printer1_Draw()

  DrawingArea1_Draw()

End


Public Sub Button2_Click()

 Dim pdf As PdfDocument
 Dim im As Image
  
' Apre il file PDF prima generato:
 pdf = New PdfDocument("/tmp/file.pdf")
   
' Genera una "Image" dalla 1^ pagina del file PDF aperto:
 im = pdf[0].Render()
 
 im.Save("/tmp/immagine.png", 100)

End

Usando le Classi "MediaPipeline" e "MediaControl" del Componente gb.media

Questa modalità prevede l'uso delle Classi "MediaPipeline" e "MediaControl" del Componente gb.media.
In particolare si catturerà quanto mostrato dalla DrawingArea, assegnando il suo numero identificativo alla Proprietà "xid" del plugin "ximagesrc" di GStreamer, e si provvederà a salvare in un file immagine.

Generare un file JPG

Mostriamo un esempio, nel quale si genererà un file JPG:

Public Sub DrawingArea1_Draw()

 Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 Dim p As Float[] = [0, 0.34, 0.67, 1]

' Disegna all'interno della "DrawingArea":
 With Paint
   .Brush = .LinearGradient(0, 0, DrawingArea1.W, DrawingArea1.H, c, p)
   .Rectangle(0, 0, DrawingArea1.W, DrawingArea1.H)
   .Fill
  .End
 End With

End


Public Sub Button1_Click()

 Dim pl As MediaPipeline
 Dim xis, con, enc, snk As MediaControl

 pl = New MediaPipeline 

 xis = New MediaControl(pl, "ximagesrc")
 xis["xid"] = DrawingArea1.Id
 con = New MediaControl(pl, "videoconvert")
 enc = New MediaControl(pl, "jpegenc")
 snk = New MediaControl(pl, "filesink")
 snk["location"] = "/tmp/immagine.jpg"
  
' Collega fra loro i plugin di "GStreamer":
 xis.LinkTo(con)
 con.LinkTo(enc)
 enc.LinkTo(snk)

' Effettua la cattura di quanto mostrato dalla "DrawingArea":
 pl.Play()

 pl.Stop
 pl.Close

End

Generare un file PNG

Volendo invece generare un file immagine di formato PNG, la seconda sub-routine dell'esempio precedente sarà così impostata:

 Public Sub Button1_Click()

 Dim pl As MediaPipeline
 Dim xis, con, enc, snk As MediaControl

 pl = New MediaPipeline 

 xis = New MediaControl(pl, "ximagesrc")
 xis["xid"] = DrawingArea1.Id
 con = New MediaControl(pl, "videoconvert")
 enc = New MediaControl(pl, "pngenc")
 snk = New MediaControl(pl, "filesink")
 snk["location"] = "/tmp/immagine.png"
  
' Collega fra loro i plugin di "GStreamer":
 xis.LinkTo(con)
 con.LinkTo(enc)
 enc.LinkTo(snk)
 
' Effettua la cattura di quanto mostrato dalla "DrawingArea":
 pl.Play()

 pl.Stop
 pl.Close

End

Generare un file BMP

Volendo invece generare un file immagine di formato BMP, la seconda sub-routine dell'esempio precedente sarà così impostata:

 Public Sub Button1_Click()

 Dim pl As MediaPipeline
 Dim xis, con, enc, snk As MediaControl

 pl = New MediaPipeline 

 xis = New MediaControl(pl, "ximagesrc")
 xis["xid"] = DrawingArea1.Id
 con = New MediaControl(pl, "videoconvert")
 enc = New MediaControl(pl, "avenc_bmp")
 snk = New MediaControl(pl, "filesink")
 snk["location"] = "/tmp/immagine.bmp"
  
' Collega fra loro i plugin di "GStreamer":
 xis.LinkTo(con)
 con.LinkTo(enc)
 enc.LinkTo(snk)
 
' Effettua la cattura di quanto mostrato dalla "DrawingArea":
 pl.Play()

 pl.Stop
 pl.Close

End


Uso delle funzioni esterne del API di X11

L'uso delle risorse della libreria esterna X11, opportunamente combinate con quelle di Gambas, consente un procedimento molto più snello ripetto al precedente. Tale modalità richiede nel codice Gambas la dichiarazione della libreria condivisa: "libX11.so.6.4.0 ".

Sussistono almeno due modalità.
Al fine di evitare che la funzione esterna "XGetImage()" ritorni un Puntatore nullo, bisognerà avere massima cura che le dimensioni del Form siano sufficientemente superiori alle dimensioni della DrawingArea contenuta.

1a modalità

La prima modalità prevede l'assegnazione dei dati dei pixel della DrawingArea, contenuti nell'area di memoria puntata dal Puntatore restituito dalla funzione esterna "XGetImage()" della libreria di X11, direttamente all'area di memoria puntata dalla Proprietà ".Data" di un Oggetto Image preliminarmente creato.


Mostriamo un esempio pratico (è necessario porre sul Form una DrawingArea e un Button): [Nota 2]

Library "libX11:6.4.0"

Public Struct funcs
  create_image As Pointer
  destroy_image As Pointer
  get_pixel As Pointer
  put_pixel As Pointer
  sub_image As Pointer
  add_pixel As Pointer
End Struct

Public Struct XImage
  width As Integer
  height As Integer
  xoffset As Integer
  gformat As Integer
  data As Pointer
  byte_order As Integer
  bitmap_unit As Integer
  bitmap_bit_order As Integer
  bitmap_pad As Integer
  depth As Integer
  bytes_per_line As Integer
  bits_per_pixel As Integer
  red_mask As Long
  green_mask As Long
  blue_mask As Long
  obdata As Pointer
  func As Struct Funcs
End Struct

Private Enum XYBitmap = 0, XYPixmap, ZPixmap

' Display *XOpenDisplay(char *display_name)
' Opens a connection to the X server that controls a display.
Private Extern XOpenDisplay(display_name As Pointer) As Pointer

' unsigned long XAllPlanes()
' Returns a value with all bits set to 1 suitable for use in a plane argument to a procedure.
Private Extern XAllPlanes() As Long

' XImage *XGetImage(Display *display, Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)
' Returns a pointer to an XImage structure.
Private Extern XGetImage(display As Pointer, d As Long, x As Integer, y As Integer, width As Integer, height As Integer, plane_mask As Long, xformat As Integer) As XImage
 
' XCloseDisplay(Display *display)
' Closes the connection to the X server for the display specified in the Display structure and destroys all windows.
Private Extern XCloseDisplay(display As Pointer)


Public Sub Form_Open()

' Imposta alcune proprietà della "DrawingArea":
 With DrawingArea1
   .X = 10
   .Y = 10
   .W = 400
   .H = 400
   .Background = Color.White
 End With
 
End


Public Sub DrawingArea1_Draw()
 
 Dim colori As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 Dim p As Float[] = [0, 0.34, 0.67, 1]
  
' Disegnamo all'interno della "DrawingArea":
  With Paint
    .Brush = .LinearGradient(10, 40, 300, 40, colori, p)
    .Rectangle(10, 40, 300, 40)
    .Fill
' Imposta il colore dei caratteri:
    .Brush = .Color(Color.Red) 
' Imposta il tipo di carattere:
   .Font.Name = "Arial" 
' Imposta la dimensione dei caratteri:
   .Font.Size = 16
' Scrive sull'Area di Disegno il seguente testo di caratteri nella posizione X, Y all'interno di un quadrilatero virtuale W, H
' con i metodi .RichText  e .Text, ma occorrerà uno ".Stroke" a seguire (però .Stroke tende a dare l'effetto del grassetto):
   .RichText("Testo con RichText", 200, 20, 16, 100)
   .Text("Testo con Text", 10, 30, 20, 20)
   .Stroke
' ...oppure (meglio, perché non dà l'effetto del grassetto) ".fill":
   .Fill
' Con il metodo .DrawText non è necessario l'uso di ".Stroke", né di ".Fill":
   .DrawText("Testo con DrawText", 10, 10, 20, 20)
   .End
 End With
  
End


Public Sub Button1_Click()

 Dim dsp As Pointer
 Dim xi As XImage
 Dim im As Image
 Dim st As Stream
 Dim i As Integer
  
 dsp = XOpenDisplay(0)
 If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")
  
' Otteniamo un puntatore alla "Struttura" contenente i dati dell'immagine disegnata nella "DrawingArea":
 xi = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
 If IsNull(xi) Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
     
' Creiamo un semplice oggetto di tipo "Image":
 im = New Image(DrawingArea1.W, DrawingArea1.H)
 If IsNull(im) Then Error.Raise("Impossibile creare un oggetto 'Image' !")
  
' Utilizziamo ovviamente i "Memory Stream" per scrivere nell'area di memoria dell'oggetto "Image", destinata ai dati attinenti ai pixel, il cui indirizzo di memoria è ritornato dalla proprietà ".Data" della variabile di tipo "Image":
 st = Memory im.Data For Write
  
 For i = 0 To im.W * im.H * Len(im.Format)
   Write #st, Byte@(xi.data + i) As Byte
 Next
  
 st.Close
 
' Genera in fine il file immagine:
 im.Save("/percorso/del/file/immagine.xxx", 100)
  
' Va in chiusura:
 XCloseDisplay(dsp)
  
End

2a modalità

La seconda modalità prevede l'assegnazione dei dati dei pixel della DrawingArea all'area di memoria puntata dal membro "*data " della Struttura "GB_IMG" contenuta nel file sorgente ".../main/lib/image/gb.image.h ". [nota 3]

Mostriamo di seguito un semplice esempio, nel quale disegneremo all'interno di una DrawingArea una riga colorata con tutta la gamma dei colori dal blu al rosso. Al termine salveremo in un file immagine il disegno presente nella DrawingArea.

Library "libX11:6.4.0"

Public Struct funcs
  create_image As Pointer
  destroy_image As Pointer
  get_pixel As Pointer
  put_pixel As Pointer
  sub_image As Pointer
  add_pixel As Pointer
End Struct

Public Struct XImage
  width As Integer
  height As Integer
  xoffset As Integer
  gformat As Integer
  data As Pointer
  byte_order As Integer
  bitmap_unit As Integer
  bitmap_bit_order As Integer
  bitmap_pad As Integer
  depth As Integer
  bytes_per_line As Integer
  bits_per_pixel As Integer
  red_mask As Long
  green_mask As Long
  blue_mask As Long
  obdata As Pointer
  func As Struct Funcs
End Struct

Private Enum XYBitmap = 0, XYPixmap, ZPixmap

' Display *XOpenDisplay(char *display_name)
' Opens a connection to the X server that controls a display.
Private Extern XOpenDisplay(display_name As Pointer) As Pointer

' unsigned long XAllPlanes()
' Returns a value with all bits set to 1 suitable for use in a plane argument to a procedure.
Private Extern XAllPlanes() As Long

' XImage *XGetImage(Display *display, Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)
' Returns a pointer to an XImage structure.
Private Extern XGetImage(displayP As Pointer, d As Long, x As Integer, y As Integer, width As Integer, height As Integer, plane_mask As Long, xformat As Integer) As XImage
 
' XCloseDisplay(Display *display)
' Closes the connection to the X server for the display specified in the Display structure and destroys all windows.
Private Extern XCloseDisplay(display As Pointer)

 
Public Sub Form_Open()
  
 DrawingArea1.Background = Color.White

End


Public Sub DrawingArea1_Draw()
  
 Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 Dim p As Float[] = [0, 0.34, 0.67, 1]
   
' Disegnamo all'interno della "DrawingArea":
 With Paint
   .Brush = .LinearGradient(10, 40, 300, 40, c, p)
   .Rectangle(10, 40, 300, 40)
   .Fill
   .End
 End With

End


Public Sub Button1_Click()
 
 Dim dsp, p, p1 As Pointer
 Dim xi As XImage
 Dim bb As Byte[]
 Dim i As Integer
 Dim st As Stream
 Dim im As Image
   
 dsp = XOpenDisplay(0)
 If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")
   
' Otteniamo un puntatore alla "Struttura" contenente i dati dell'immagine disegnata nella "DrawingArea":
 xi = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
 If IsNull(xi) Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
    
 bb = New Byte[]    
  
 For i = 0 To (DrawingArea1.W * DrawingArea1.H * 4) - 1
   bb.Push(Byte@(xi.data + i))
 Next
   
 im = New Image(DrawingArea1.W, DrawingArea1.H)
   
 p = Object.Address(im)
   
 p1 = Pointer@(p + (SizeOf(gb.Pointer) * 2))  ' [Nota 4]
   
' Scriviamo i dati immagine grezzi, ottenuti dalla funzione XGetImage(), nell'area di memoria puntata dal membro "*data" della Struttura "GB_IMG" contenuta nel file sorgente ".../main/lib/image/gb.image.h":
 st = Memory p1 For Write
 bb.Write(st, 0, bb.Count)
 st.Close
  
' Generiamo dunque il file immagine:
 im.Save("/percorso/dove/salvare/il/file/immagine.xxx")
 
' Va in chiusura:
 XCloseDisplay(dsp)

End


Uso delle funzioni esterne del API di X11 e di Cairo

L'uso delle risorse delle librerie esterne X11 e Cairo richiede nel codice Gambas la dichiarazione delle seguenti librerie dinamiche condivise:

  • "libX11.so.6.4.0 "
  • "libcairo.so.2.11802.2 "

Mostriamo di seguito un semplice esempio, nel quale disegneremo all'interno di una DrawingArea una riga colorata con tutta la gamma dei colori dal blu al rosso. Al termine salveremo in un file immagine il disegno presente nella DrawingArea.
Al fine di evitare che la funzione esterna "XGetImage()" ritorni un Puntatore nullo, bisognerà avere massima cura che le dimensioni del Form siano sufficientemente superiori alle dimensioni della DrawingArea contenuta.

Library "libX11:6.4.0"

' Display *XOpenDisplay(char *display_name)
' Opens a connection to the X server that controls a display.
Private Extern XOpenDisplay(display_name As Pointer) As Pointer

' int XDefaultScreen(display)
' Returns the default screen number.
Private Extern XDefaultScreen(display As Pointer) As Integer

' Visual *XDefaultVisual(display, screen_number)
' Returns the default visual type for the specified screen.
Private Extern XDefaultVisual(display As Pointer, scr_num As Integer) As Pointer
 
' XCloseDisplay(Display *display)
' Closes the connection to the X server for the display specified in the Display structure and destroys all windows.
Private Extern XCloseDisplay(display As Pointer)


Library "libcairo:2.11802.2"

' cairo_surface_t * cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int width, int height)
' Creates an Xlib surface that draws to the given drawable.
Private Extern cairo_xlib_surface_create(dpy As Pointer, drawable As Long, visual As Pointer, width As Integer, height As Integer) As Pointer

' cairo_status_t cairo_surface_write_to_png(cairo_surface_t *surface, const char *filename)
' Writes the contents of surface to a new file filename as a PNG image.
Private Extern cairo_surface_write_to_png(cairo_surface As Pointer, filename As String) As Integer

' void cairo_surface_destroy(cairo_surface_t *surface)
' Decreases the reference count on surface by one.
Private Extern cairo_surface_destroy(cairo_surface As Pointer)


Public Sub Form_Open()

 DrawingArea1.Background = Color.White

End


Public Sub DrawingArea1_Draw()

 Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 Dim p As Float[] = [0, 0.34, 0.67, 1]
   
' Disegnamo all'interno della "DrawingArea":
 With Paint
   .Brush = .LinearGradient(10, 40, 300, 40, c, p)
   .Rectangle(10, 40, 300, 40)
   .Fill
   .End
 End With

End


Public Sub Button1_Click()

 Dim dsp, vis, surface As Pointer
 Dim scr, err As Integer

 dsp = XOpenDisplay(0)
 If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")

 scr = XDefaultScreen(dsp)
 vis = XDefaultVisual(dsp, scr)
 If vis == 0 Then Error.Raise("Errore !")

' Ottiene la superficie grafica della "DrawingArea":
 surface = cairo_xlib_surface_create(dsp, DrawingArea1.Handle, vis, DrawingArea1.W, DrawingArea1.H)
 If surface == 0 Then Error.Raise("Errore !")

' Si salva il disegno della superficie grafica della "DrawingArea" in un file immagine .png:
 err = cairo_surface_write_to_png(surface, "/tmp/immagine.png")
 If err > 0 Then Error.Raise("Errore nella creazione del file immagine .png !")

' Va in chiusura:
 cairo_surface_destroy(surface)
 XCloseDisplay(dsp)

End


Uso delle funzioni esterne del API di X11 e di ImLib2

L'uso delle risorse delle librerie esterne X11 e ImLib2 richiede nel codice Gambas la dichiarazione delle seguenti librerie dinamiche condivise:

  • "libX11.so.6.4.0 "
  • "libImlib2.so.1.12.3 "

Mostriamo di seguito un semplice esempio, nel quale disegneremo all'interno di una DrawingArea una riga colorata con tutta la gamma dei colori dal blu al rosso. Al termine salveremo in un file immagine il disegno presente nella DrawingArea.
Al fine di evitare che la funzione esterna "XGetImage()" ritorni un Puntatore nullo, bisognerà avere massima cura che le dimensioni del Form siano sufficientemente superiori alle dimensioni della DrawingArea contenuta.

Library "libX11:6.4.0"

Public Struct funcs
  create_image As Pointer
  destroy_image As Pointer
  get_pixel As Pointer
  put_pixel As Pointer
  sub_image As Pointer
  add_pixel As Pointer
End Struct

Public Struct XImage
  width As Integer
  height As Integer
  xoffset As Integer
  gformat As Integer
  data As Pointer
  byte_order As Integer
  bitmap_unit As Integer
  bitmap_bit_order As Integer
  bitmap_pad As Integer
  depth As Integer
  bytes_per_line As Integer
  bits_per_pixel As Integer
  red_mask As Long
  green_mask As Long
  blue_mask As Long
  obdata As Pointer
  func As Struct Funcs
End Struct

Private Enum XYBitmap = 0, XYPixmap, ZPixmap

' Display *XOpenDisplay(char *display_name)
' Opens a connection to the X server that controls a display.
Private Extern XOpenDisplay(display_name As Pointer) As Pointer

' unsigned long XAllPlanes()
' Returns a value with all bits set to 1 suitable for use in a plane argument to a procedure.
Private Extern XAllPlanes() As Long

' XImage *XGetImage(Display *display, Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)
' Returns a pointer to an XImage structure.
Private Extern XGetImage(display As Pointer, d As Long, x As Integer, y As Integer, width As Integer, height As Integer, plane_mask As Long, xformat As Integer) As XImage
 
' XCloseDisplay(Display *display)
' Closes the connection to the X server for the display specified in the Display structure and destroys all windows.
Private Extern XCloseDisplay(display As Pointer)


Library "libImlib2:1.12.3"

' Imlib_Image imlib_create_image_using_data(int width, int height, DATA32 * data)
' Creates an image from the image data - in the format of a DATA32 (32 bits) per pixel in a linear array - specified with the width and the height specified.
Private Extern imlib_create_image_using_data(width As Integer, height As Integer, data As Pointer) As Pointer

' void imlib_context_set_image(Imlib_Image image)
' Sets the current image Imlib2 will be using with its function calls.
Private Extern imlib_context_set_image(Iimage As Pointer)

' void imlib_image_set_has_alpha(char has_alpha)
' Sets the alpha flag for the current image.
Private Extern imlib_image_set_has_alpha(has_alpha As Boolean)

' void imlib_save_image(const char *filename)
' Saves the current image in the format specified by the current image's format settings to the filename.
Private Extern imlib_save_image(filename As String)

' void imlib_free_image(void)
' Frees the image that is set as the current image in Imlib2's context.
Private Extern imlib_free_image()


Public Sub Form_Open()

 DrawingArea1.Background = Color.White

End


Public Sub DrawingArea1_Draw()

 Dim c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
 Dim p As Float[] = [0, 0.34, 0.67, 1]
   
' Disegnamo all'interno della "DrawingArea":
 With Paint
   .Brush = .LinearGradient(10, 40, 300, 40, c, p)
   .Rectangle(10, 40, 300, 40)
   .Fill
   .End
 End With

End


Public Sub Button1_Click()

 Dim dsp, imago As Pointer
 Dim xi As XImage
   
 dsp = XOpenDisplay(0)
 If dsp == 0 Then Error.Raise("Impossibile aprire una connessione al server X !")
 
' Otteniamo un puntatore alla "Struttura" contenente i dati dell'immagine disegnata nella "DrawingArea":
 xi = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
 If IsNull(xi) Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
     
' Viene creata l'immagine dai dati grezzi passando il "Puntatore" ai dati grezzi dell'immagine:
 imago = imlib_create_image_using_data(DrawingArea1.W, DrawingArea1.H, xi.data)
 If imago == 0 Then Error.Raise("Impossibile creare l'immagine dai dati grezzi acquisiti !")
   
 imlib_context_set_image(imago)
   
' L'immagine creata viene salvata in un file immagine.
' Al nome del file immagine, da creare, va esplicitata l'estensione del formato immagine desiderato:
 imlib_save_image("/percorso/dove/salvare/il/file/immagine.xxx")
 
' Va in chiusura:
 imlib_free_image()
 XCloseDisplay(dsp)

End


Note

[1] Vedere anche questa pagina della Wiki: Convertire una pagina di un file PDF in una immagine con le risorse del Componente gb.poppler

[2] Vedere anche questa pagina della Wiki: Passare direttamente ad un oggetto Image i dati grezzi dei pixel di una DrawingArea mediante le risorse del API di X11

[3] Spieghiamo brevemente perché sia necessario spostarsi al byte, di indice pari al valore restituito da SizeOf(gb.Pointer), dell'area di memoria puntata dal Puntatore XImage.
Bisogna innanzitutto tenere in considerazione la omonima Struttura XImage restituita dalla funzione "XGetImage()", che può essere presa in visione qui:
http://tronche.com/gui/x/xlib/graphics/images.html#XImage
Ebbene, il quinto membro di detta Struttura

char *data;............/* pointer to image data */

è una variabile Puntatore di tipo char, che contiene l'indirizzo dell'area di memoria ove sono stipati i dati dell'immagine mostrata dalla DrawingArea.
Va precisato che, come evidente, nell'esempio in Gambas noi operiamo semplicemente sull'area di memoria riservata dalla predetta funzione "XGetImage()" e puntata dall'apposita variabile XImage. Insomma, non abbiamo passato una variabile di tipo Struttura (come in realtà è previsto nella libreria esterna di X11), ma semplicemente un Puntatore all'area di memoria riservata coerentemente corrispondente a quella della omonima Struttura prevista dalla funzione "XGetImage()".
Perché dobbiamo spostarci al byte di indice uguale al doppio dei byte di memoria, occupati da una variabile di tipo Puntatore, per leggere il valore di quell'indirizzo di memoria ?
La risposta è nei quattro membri precedenti, i quali sono tutti di tipo Intero, e pertanto occupano ciascuno un numero di byte di memoria pari a SizeOf(gb.Integer) e complessivamente: SizeOf(gb.Integer) + SizeOf(gb.Integer) = SizeOf(gb.Pointer).
Il valore del Puntatore (ossia l'indirizzo di memoria dei dati grezzi dell'immagine puntati dalla omonima Struttura "XImage" della libreria esterna di X11), che a noi interessa, si trova a cominciare dal byte di indice = SizeOf(gb.Pointer). Il valore dell'indirizzo di memoria verrà da noi salvato nel tipo di variabile a ciò deputato, ossia il Puntatore, e così passato alla successiva funzione "imlib_create_image_using_data()", come da essa richiesto.

[4] Al riguardo vedasi anche la pagina della Wiki: Gestire un oggetto Image agendo direttamente sulle risorse dei sorgenti Gambas


Riferimenti