Passare direttamente ad un oggetto Image i dati grezzi dei pixel di una DrawingArea mediante le risorse del API di X11

Da Gambas-it.org - Wikipedia.
Versione del 16 dic 2016 alle 18:33 di Vuott (Discussione | contributi) (Creata pagina con "Per passare ad un oggetto ''Image'' i dati grezzi dei pixel del disegno presente in una ''DrawingArea'', senza creare preliminarmente in ausilio un file immagine, si potranno...")

(diff) ← Versione meno recente | Versione attuale (diff) | Versione più recente → (diff)

Per passare ad un oggetto Image i dati grezzi dei pixel del disegno presente in una DrawingArea, senza creare preliminarmente in ausilio un file immagine, si potranno utilizzare le risorse del API della libreria di X11.

In particolare si avranno almeno due modalità.


Passare i dati all'indirizzo dell'area di memoria restituito dalla proprietà .Data dell'oggetto Image

La prima modaltà prevede il passaggio dei dati dei pixel all'indirizzo dell'area di memoria restituito dalla proprietà .Data dell'oggetto Image.

Si tratta di creare un ogetto di tipo Image, avente le medesime dimensioni della DrawingArea, e di passare direttamente all'area di memoria puntata dalla proprietà .Data di detta variabile di tipo Image i dati grezzi dei pixel ottenuti dalla DrawingArea e contenuti nell'area di memoria riservata, puntata dal Puntatore restituito dalla funzione XGetImage( ) della libreria di X11. Tutti i dati precedenti relativi ai pixel, comunque contenuti dalla variabile Image, saranno sostituiti dai nuovi dati dei pixel afferenti al disegno presente nella DrawingArea.

E' necessario richiamare in Gambas la librria dinamica condivisa: "libX11.so.6.3.0"


Mostriamo un esempio pratico (è necessario porre sul Form una DrawingArea, un Button ed una PictureBox):

Library "libX11:6.3.0"

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 String) 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, xI As Integer, yI As Integer, wid As Integer, hei As Integer, plane_mask As Long, formatI 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)


Public Sub Form_Open()

' Imposta alcune proprietà della "DrawingArea":
 With DrawingArea1
   .X = 10
   .Y = 10
   .W = 400
   .H = 300
   .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, XImage, dati_imm As Pointer
 Dim im As Image
 Dim st As Stream
 Dim i As Integer
  
  dsp = XOpenDisplay(Null)
  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":
  XImage = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
  If XImage = 0 Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
  
' Otteniamo l'indirizzo di memoria dei dati grezzi dell'immagine puntati dalla Struttura "XImage":
  dati_imm = Pointer@(XImage + 16)
  
' 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@(dati_imm + i) As Byte
  Next
  
  st.Close
 
' Come verifica finale mostriamo in una "PictureBox" i dati contenuti nella variabile di tipo "Image",
' dopo averla convertita opportunamente in una variabile di tipo "Picture":
  PictureBox1.Picture = im.Picture
  
' Va in chiusura:
  XCloseDisplay(dsp)
  
End


Passare i dati all'area di memoria puntata dal membro "*data" della Struttura "GB_IMG" dichiarata nel file sorgente gb.image.h

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 1]


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.
Funziona solo su sistemi a 64-bit.

Library "libX11:6.3.0"

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$ As String) 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, xI As Integer, yI As Integer, wid As Integer, hei As Integer, plane_mask As Long, formatI 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(displayP 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, XImage, imago, p, p1 As Pointer
 Dim bb As Byte[]
 Dim i As Integer
 Dim st As Stream
 Dim im As Image
   
  dsp = XOpenDisplay(Null)
  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":
  XImage = XGetImage(dsp, DrawingArea1.Handle, 0, 0, DrawingArea1.W, DrawingArea1.H, XAllPlanes(), ZPixmap)
  If XImage = 0 Then Error.Raise("Impossibile ottenere un 'Puntatore' ai dati dell'immagine della DrawingArea !")
 
' Otteniamo l'indirizzo di memoria dei dati grezzi dell'immagine puntati dalla Struttura "XImage":
  imago = Pointer@(XImage + 16)
    
  bb = New Byte[]    
  
  For i = 0 To (DrawingArea1.W * DrawingArea1.H * 4) - 1
    bb.Push(Byte@(imago + i))
  Next
   
  im = New Image(DrawingArea1.W, DrawingArea1.H)
   
  p = Object.Address(im)
   
  p1 = Pointer@(p + 16)
   
' 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
  
' Come verifica finale mostriamo in una "PictureBox" i dati contenuti nella variabile di tipo "Image",
' dopo averla convertita opportunamente in una variabile di tipo "Picture":
  PictureBox1.Picture = im.Picture
 
  
' Va in chiusura:
  XCloseDisplay(dsp)

End



Note

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