Creare file GIF con le funzioni esterne del API di Libplot

Da Gambas-it.org - Wikipedia.

La libreria Libplot fornisce risorse per creare svariati tipi di file di grafica 2-D sia vettoriali che bitmap.

In particolare, anche se questa libreria può produrre ciò che sembrano essere GIF e GIF animate, essa non trasgredisce alcun brevetto che copre l'algoritmo di compressione LZW. La ragione è che invece di codifica LZW, utilizza la codifica run-length encoding (RLE), che non è brevettabile. Per evitare confusione, i file prodotti da questa libreria vengono chiamati: "file pseudo-GIF".

Come già accennato, la libreria Libplot è in grado di generare vari tipi di file, compreso quello GIF, contenenti elementi grafici di base come testo e figure piane (cerchio, ellisse, quadrato, rettangolo, arco, linee, ed altro). Può essere impostata sia la trasparenza che il colore.

In questa pagina si procederà, per quanto possibile, a mostrare gradatamente le capacità principali e le funzioni essenziali e più rilevanti per la realizzazione delle GIF, spiegandone la caratterisica di ciascuna brevemente con una didascalia in commento prima dell'istruzione.


Va precisato che per fruire in Gambas delle risorse della libreria Libprot, va installata e richiamata la libreria dinamica condivisa: "libplot.so.2.2.4"


Creare una semplice GIF con solo sfondo colorato

Il primo esempio mostrerà come realizzate una GIF avente semplicemente lo sfondo di colore unico.

Per la creazione di una GIF essenziale e di base sono sufficienti poche istruzioni. Va subito sottolineato che la funzione della libreria Libprot utile per impostare le caratteristiche fondamentali dell'immagine GIF, è la funzione: pl_setplparam().

Questa funzione può essere omessa qualora si intenda lasciare peruna determinata caratteristica le impostazioni predefinite previste dalla libreria Libprot.

Così, per iniziare, se si vuole creare una semplice GIF con le sole impostazioni predefinite, si otterrà un'immagine di tipo GIF con fondo di colore bianco e delle dimensioni 570x570 pixel.

Library "libplot:2.2.4"

' plPlotterParams * pl_newplparams (void)
' Constructor constructor for the plPlotterParams type.
Private Extern pl_newplparams() As Pointer

' plPlotter * pl_newpl_r (const char *type, FILE *infile, FILE *outfile, FILE *errfile, const plPlotterParams *plotter_params)
' Constructor for the plPlotter type.
Private Extern pl_newpl_r(type As String, infile As Pointer, outfile As Pointer, errfile As Pointer, plotter_params As Pointer) As Pointer

' int pl_openpl_r (plPlotter *plotter)
Private Extern pl_openpl_r(plPlotter As Pointer) As Integer

' int pl_closepl_r (plPlotter *plotter)
Private Extern pl_closepl_r(plPlotter As Pointer) As Integer

' int pl_deletepl_r (plPlotter *plotter)
' Destructor for the plPlotter type.
Private Extern pl_deletepl_r(plPlotter As Pointer) As Integer

' int pl_deleteplparams (plPlotterParams *plotter_params)
' Destructor for the plPlotterParams type.
Private Extern pl_deleteplparams(plotter_params As Pointer) As Integer


Library "libc:6"

' FILE *fopen(const char *filename, const char *mode)
' Opens the filename pointed to by filename using the given mode.
Private Extern fopen(filename As String, mode As String) As Pointer

' int fclose(FILE *stream)
' Closes the stream. All buffers are flushed.
Private Extern fclose(fs As Pointer) As Integer


Public Sub Main()

  Dim fl, param, plotter As Pointer

  fl = fopen("/percorso/del/file.gif", "wb")

' Imposta i parametri (in questo caso sono quelli predefiniti) del disegnatore della GIF:
  param = pl_newplparams()
  If param == 0 Then Error.Raise("Errore !")

' Crea un disegnatore di GIF con i parametri specificati (in questo caso sono quelli predefiniti):
  plotter = pl_newpl_r("gif", 0, fl, 0, param)
  If plotter == 0 Then Error.Raise("Errore !")
   
  pl_openpl_r(plotter)
   
' Va in chiusura:
  pl_deleteplparams(param)
  pl_closepl_r(plotter)
  pl_deletepl_r(plotter)
  fclose(fl)

End


Impostare parametri dell'immagine diversi da quelli predefiniti

Per impostare caratteristiche dell'immagine diverse da quelle predefinite, dopo la funzione pl_newplparams() si dovrà fare uso della funzione pl_setplparam().
Detta nuova funzione verrà così dichiarata con Extern:

' int pl_setplparam (plPlotterParams *plotter_params, const char *parameter, void *value)
' A function for setting a single Plotter parameter in a plPlotterParams instance.
Private Extern pl_setplparam(plotter_params As Pointer, parameter As String, value As String) As Integer

Va precisato che la funzione esterna "pl_setplparam()" andrà utilizzata tante volte quanti sono i parametri che si intendono impostare.

Cambiare colore allo sfondo dell'immagine

Se si intende cambiare colore allo sfondo dell'immagine, allora nel secondo argomento della funzione esterna "pl_setplparam()" si inserirà il parametro "BG_COLOR ", e terzo argomento verrà impostato il colore di fondo con il nome oppure con il corrispondente valore numerico.
Quindi avremo:

......

  param = pl_newplparams()

  pl_setplparam(param, "BG_COLOR", "yellow")

......

Impostare le dimensioni dell'immagine

Se si intende impostare una dimensione della GIF diversa da quella predefinita (570x570 pixel), si imposterà nel secondo argomento della funzione esterna "pl_setplparam()" il parametro "BITMAPSIZE ", e nel terzo argomento una stringa contenente i valori desiderati separati da una "x" minuscola (ad esempio: "640x400").
Quindi avremo:

......

  param = pl_newplparams()

  pl_setplparam(param, "BITMAPSIZE", "640x400")

......

Impostare la trasparenza

Può essere impostata la trasparenza sull'intera immagine o su parte di essa. In ogni caso la trasparenza va impostata individuando un colore già impostato in precedenza. Così, rifacendoci all'esempio di sopra, se si intende attribuire la trasparenza allo sfondo della GIF, che in modalità predefinita è bianco, si farà riferimento a tale colore.
Nel secondo argomento della funzione esterna "pl_setplparam()" si inserirà il parametro "TRANSPARENT_COLOR ", e nel terzo argomento una stringa contenente il nome o il valore numerico del colore che occupa la parte che si vuole rendere trasparente.
Quindi avremo:

......

  param = pl_newplparams()

  pl_setplparam(param, "TRANSPARENT_COLOR", "white")

......


Disegnare in una GIF

La libreria Libplot, come già detto, consente di disegnare all'interno dell'immagine semplici elementi grafici: punti, linee, cerchi, archi, rettangoli, etc., mediante specifiche funzioni.

Innanzitutto bisognerà impostare la funzione esterna di controllo "pl_fspace_r()", la quale specifica le posizioni degli angoli in basso a sinistra e in alto a destra di una finestra rettangolare del sistema di coordinate dell'utente che verrà associata al finestra di disegno: la porzione del dispositivo di uscita ove la grafica sarà disegnata. In modalità predefinita questa porzione di disegno è quadrata. La funzione esterna "pl_fspace_r()" va solitamente invocata all'inizio di ogni pagina di grafica, ad esempio, immediatamente dopo la chiamata alla funzione esterna "pl_openpl_r()".

La funzione pl_fspace_r() andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_fspace_r (plPlotter *plotter, double x0, double y0, double x1, double y1)
Private Extern pl_fspace_r(plPlotter As Pointer, x0F As Float, y0F As Float, x1F As Float, y1F As Float) As Integer


Quindi ad esempio avremo:

......

  i = pl_fspace_r(plotter, 1.0, 1.8, 15.0, 10.8)

......

Impostare il colore del punto o della linea che definisce l'elemento del disegno

Se si intende dare un colore diverso da quello predefinito (nero) ad un eventuale punto o alla linea che definisce un elemento del disegno (una linea, la circonferenza di un cerchio, e così via), è necessario utilizzare - prima di scrivere le specifiche funzioni di disegno - la funzione esterna "pl_pencolorname_r()". Nel secondo suo argomento verrà definito il nome o il valore numerico del colore desiderato.
In Gambas questa funzione andrà dichiarata con l'istruzione Extern come segue:

' int pl_pencolorname_r (plPlotter *plotter, const char *name)
Private Extern pl_pencolorname_r(plPlotter As Pointer, name As String) As Integer

Quindi ad esempio avremo:

......

  i = pl_pencolorname_r(plotter, "#FF00FF")

......

Disegnare un punto

Per disegnare un punto si utilizza la funzione esterna "pl_fpoint_r()", che andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_fpoint_r (plPlotter *plotter, double x, double y)
Private Extern pl_fpoint_r(plPlotter As Pointer, xF As Float, yF As Float) As Integer

Quindi ad esempio avremo:

......

  i = pl_fpoint_r(plotter, 10.5, 20.7)

......

Disegnare una linea

Per disegnare unalinea si utilizza la funzione esterna "pl_fline_r()", che andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_fline_r (plPlotter *plotter, double x0, double y0, double x1, double y1)
Private Extern pl_fline_r(plPlotter As Pointer, x0F As Float, y0F As Float, x1F As Float, y1F As Float) As Integer

Quindi ad esempio avremo:

......

  i = pl_fline_r(plotter, 5.5, 12.7, 10.9, 14.6)

......

Questa funzione contiene due valori (x0,y0) che determinano le coordinate di inizio della linea e due valori (x1,y1) che determinano le coordinate di fine della linea.

Disegnare un quadrato o un rettangolo

Per disegnare un quadrato o un rettangolo si utilizza la funzione esterna "pl_fbox_r()", che andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_fbox_r (plPlotter *plotter, double x0, double y0, double x1, double y1)
Private Extern pl_fbox_r(plPlotter As Pointer, x0F As Float, y0F As Float, x1F As Float, y1F As Float) As Integer

laddove x0 e y0 sono le coordinate dell'angolo in basso a sinistra, e x1 e y1 sono le coordinate dell'angolo in alto a destra. Quindi ad esempio avremo:

......

  i = pl_fbox_r(plotter, 5.5, 12.7, 10.9, 14.6)

......


Un'altra modalità per creare un quadrilatero rettangolo prevede l'uso della funzione esterna "pl_fline_r()" preceduta dalla funzione esterna "pl_flineWidth_r()" con un adeguato valore posto nel secondo argomento di quest'ultima funzione.
La funzione esterna "pl_flineWidth_r()" andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_flinewidth_r (plPlotter *plotter, double size)
Private Extern pl_flineWidth_r(plPlotter As Pointer, size As Integer) As Integer

Quindi ad esempio avremo:

......

  i = pl_flinewidth_r(plotter, 30)
  
  i = pl_fline_r(plotter, 5.5, 12.7, 10.9, 14.6)

......

Disegnare un cerchio

Per disegnare un cerchio si utilizza la funzione esterna "pl_fcircle_r()", che andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_fcircle_r (double xc, double yc, double r)
Private Extern pl_fcircle_r(plPlotter As Pointer, xcF As Float, ycF As Float, r As Float) As Integer

laddove xc e yc sono le coordinate del centro del cerchio, mentre r rappresenta il raggio.
Quindi ad esempio avremo:

......

  i = pl_fcircle_r(plotter, 5.5, 12.7, 4.6)

......

Disegnare un'ellisse

Per disegnare un'ellisse si utilizza la funzione esterna "pl_fellipse_r()", che andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int fellipse (double xc, double yc, double rx, double ry, double angle)
Private Extern pl_fellipse_r(plPlotter As Pointer, xcF As Float, ycF As Float, rxF As Float, ryF As Float, angle As Float) As Integer

laddove xc e yc sono le coordinate del centro dell'ellisse, rx e ry sono le lunghezze dei suoi semiassi, e angle rappresenta l'inclinazione del primo semiasse in senso antiorario dall'asse x del sistema di coordinate utente.
Quindi ad esempio avremo:

......

  i = pl_fellipse_r(plotter, 10.5, 12.7, 4.6, 6.0, 90)

......

Riempire l'area di una figura piana

Per riempire con un colore l'area di una figura piana disegnata, si utilizza la funzione esterna "pl_filltype_r()", che andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_filltype_r (plPlotter *plotter, int level)
Private Extern pl_filltype_r(plPlotter As Pointer, level As Integer) As Integer

laddove se secondo argomento è uguale a 1, allora l'area di ogni figura piana creata dopo questa funzione viene riempita con il colore che deve essere impostato con la funzione esterna "pl_fillcolorname_r()".
Quest'ultima funzione per il colore andrà dichiarata in Gambas con l'istruzione Extern come segue:

' int pl_fillcolorname_r (plPlotter *plotter, const char *name)
Private Extern pl_fillcolorname_r(plPlotter As Pointer, name As String) As String

laddove nel secondo argomento verrà scritto il nome del colore oppure il valore numerico corrispondente.
Quindi ad esempio avremo:

......

  i = pl_filltype_r(plotter, 1)

  i = pl_fillcolorname_r(plotter, "yellow")

......

Disegnare un testo

Per disegnare un testo in modo essenziale, ci si servirà di almeno quattro funzioni esterne:

  • "pl_ftextangle_r()", per attribuire eventualmente un'inclinazione all'intero rigo di testo;
  • "pl_ffontsize_r()", per assegnare la dimensione dei caratteri;
  • "pl_fmove_r()", per stabilire il punto ove far iniziare il disegno del testo all'interno dell'area di disegno;
  • "pl_alabel_r()", per scrivere il testo.


Tali funzioni in Gambas verranno così dichiarate con Extern:

' double pl_ftextangle_r (plPlotter *plotter, double angle)
Private Extern pl_ftextangle_r(plPlotter As Pointer, angle As Float) As Float

' double pl_ffontsize_r (plPlotter *plotter, double size)
Private Extern pl_ffontsize_r(plPlotter As Pointer, size As Float) As Float

' int pl_fmove_r (plPlotter *plotter, double x, double y)
Private Extern pl_fmove_r(plPlotter As Pointer, xF As Float, yF As Float) As Integer

' int pl_alabel_r (plPlotter *plotter, int x_justify, int y_justify, const char *s)
Private Extern pl_alabel_r(plPlotter As Pointer, x_justify As Integer, y_justify As Integer, s As String) As Integer


Quindi ad esempio avremo:

......

pl_ftextangle_r (plotter, 0);
pl_ffontsize_r (plotter, 0.8); 
pl_fmove_r (plotter, 10.0, 18.0);
pl_alabel_r (plotter, 0,0, "Testo qualsiasi");

......


Altre funzioni

La libreria dispone di altre funzioni utili per il disegno, in ordine alle quali rinviamo ai siti specifici segnalati in fondo nel paragrafo Riferimenti.


Esempio pratico

Di seguito viene mostrato un esempio pratico di utilizzo di molte delle funzioni sopra esposte. In particolare si creerà un'immagine di tipo GIF, avente dimensioni 400x300, fondo giallo, una riga, un quadrato riempito di colore verde ed un'ellisse priva di colore di riempimento diverso dal colore di sfondo dell'immagine. I tre elementi grafici sono disegnati con tratto di colore rosso.

Library "libplot:2.2.4"

' plPlotterParams * pl_newplparams (void)
' Constructor constructor for the plPlotterParams type.
Private Extern pl_newplparams() As Pointer

' int pl_setplparam (plPlotterParams *plotter_params, const char *parameter, void *value)
' A function for setting a single Plotter parameter in a plPlotterParams instance.
Private Extern pl_setplparam(plotter_params As Pointer, parameter As String, value As String) As Integer

' plPlotter * pl_newpl_r (const char *type, FILE *infile, FILE *outfile, FILE *errfile, const plPlotterParams *plotter_params)
' Constructor for the plPlotter type.
Private Extern pl_newpl_r(type As String, infile As Pointer, outfile As Pointer, errfile As Pointer, plotter_params As Pointer) As Pointer

' int pl_openpl_r (plPlotter *plotter)
Private Extern pl_openpl_r(plPlotter As Pointer) As Integer

' int pl_fspace_r (plPlotter *plotter, double x0, double y0, double x1, double y1)
Private Extern pl_fspace_r(plPlotter As Pointer, x0F As Float, y0F As Float, x1F As Float, y1F As Float) As Integer

' int pl_pencolorname_r (plPlotter *plotter, const char *name)
Private Extern pl_pencolorname_r(plPlotter As Pointer, name As String) As Integer

' int pl_fline_r (plPlotter *plotter, double x0, double y0, double x1, double y1)
Private Extern pl_fline_r(plPlotter As Pointer, x0F As Float, y0F As Float, x1F As Float, y1F As Float) As Integer

' int pl_filltype_r (plPlotter *plotter, int level)
Private Extern pl_filltype_r(plPlotter As Pointer, level As Integer) As Integer

' int pl_fillcolorname_r (plPlotter *plotter, const char *name)
Private Extern pl_fillcolorname_r(plPlotter As Pointer, name As String) As String

' int pl_fbox_r (plPlotter *plotter, double x0, double y0, double x1, double y1)
Private Extern pl_fbox_r(plPlotter As Pointer, x0F As Float, y0F As Float, x1F As Float, y1F As Float) As Integer

' int fellipse (double xc, double yc, double rx, double ry, double angle)
Private Extern pl_fellipse_r(plPlotter As Pointer, xcF As Float, ycF As Float, rxF As Float, ryF As Float, angle As Float) As Integer

' int pl_closepl_r (plPlotter *plotter)
Private Extern pl_closepl_r(plPlotter As Pointer) As Integer

' int pl_deletepl_r (plPlotter *plotter)
' Destructor for the plPlotter type.
Private Extern pl_deletepl_r(plPlotter As Pointer) As Integer

' int pl_deleteplparams (plPlotterParams *plotter_params)
' Destructor for the plPlotterParams type.
Private Extern pl_deleteplparams(plotter_params As Pointer) As Integer


Library "libc:6"

' FILE *fopen(const char *filename, const char *mode)
' Opens the filename pointed to by filename using the given mode.
Private Extern fopen(filename As String, mode As String) As Pointer

' int fclose(FILE *stream)
' Closes the stream. All buffers are flushed.
Private Extern fclose(fs As Pointer) As Integer


Public Sub Main()

  Dim fl, param, plotter As Pointer

  fl = fopen("/percorso/del/file.gif", "wb")

' Imposta i parametri (in questo caso sono quelli predefiniti) del disegnatore della GIF:
  param = pl_newplparams()
  If param == 0 Then Error.Raise("Errore !")

  pl_setplparam(param, "BG_COLOR", "yellow")
 
  pl_setplparam(param, "BITMAPSIZE", "400x300")

' Crea un disegnatore di GIF con i parametri specificati (in questo caso sono quelli predefiniti):
  plotter = pl_newpl_r("gif", 0, fl, 0, param)
  If plotter == 0 Then Error.Raise("Errore !")

  pl_openpl_r(plotter)

  pl_fspace_r(plotter, 0.0, 0.0, 15.0, 10.8)
 
  pl_pencolorname_r(plotter, "#FF0000")
 
  pl_fline_r(plotter, 1.5, 1.7, 4.9, 4.6)
 
  pl_filltype_r(plotter, 1)
  pl_fillcolorname_r(plotter, "green")
  pl_fbox_r(plotter, 2.5, 6.7, 6.7, 10.6)
 
  pl_filltype_r(plotter, 0)
  pl_fellipse_r(plotter, 10.0, 5.0, 1.6, 3.0, 90)
   

' Va in chiusura:
  pl_deleteplparams(param)
  pl_closepl_r(plotter)
  pl_deletepl_r(plotter)
  fclose(fl)

End


Riferimenti