Disegnare e salvare un'immagine di tipo GIF con le funzioni del API di GifLib

Da Gambas-it.org - Wikipedia.

Come si sa, salvare un'immagine in un file di formato .GIF (Graphics Interchange Format), in Gambas non è attualmente possibile. Gambas possiede, sì, risorse per caricare file immagine di tipo .gif, ma non per salvarle.

Un aiuto, però, per la generazione di file immagine di tipo GIF può giungerci dalle risorse della libreria GIFLIB, scritta da Eric Steven Raymond, la quale consente di caricare, gestire, manipolare, creare ex novo e salvare file immagine in fomato GIF.

Per poter utilizzare al meglio le risorse della libreria GifLib con Gambas, suggeriamo di utilizzare la relativa libreria dinamica condivisa nella seguente versione: libgif.so.7.0.0


Mostriamo un semplice esempio, nel quale si creerà e disegnerà un'immagine GIF con fondo bianco e con righe verticali a cinque colori diversi. Successivamente l'imagine sarà salvata in un file di tipo .gif. La risoluzione dell'immagine sarà a 24bit; cosa questa che significa che per determinare il colore di ciascun pixel saranno necessari 3 byte.
L'impostazione dei colori utilizzati - massimo 256 colori - nel disegno avviene all'interno della "mappa dei colori", che può essere pensata come una sorta di lista. Il primo colore impostato si riferirà al fondo dell'immagine, gli altri eventualmente impostati si riferiranno al disegno, ossia a ciò chevisivmente si sovrppone al fondo dell'immagine. La colorazione dei singoli pixel per effettuare il disegno avviene impostando i dati all'interno di una matrice di tipo Puntatore. Le dimensioni di tale matrice rappresenteranno l'una il numero di righe presenti nell'immagine, determinandone quindi l'altezza, l'altra il numero di pixel contenuti in ciascuna riga.
Per attribuire il colore ad un pixel bisognerà scrivere in un elemento della seconda dimensione della predetta matrice di tipo Puntatore. Ovviamente, al fine di non ottenere un'immagine con un disegno ditorto, non desiderato, bisognerà essere attenti alla sua trama, facendo corrispodere la sequenza dei pixel durante la generazione delle varie linee che compongono l'imagine.
Il codice del seguente esempio non consente di creare immagini GIF di dimensioni superiori a 255x255 pixel !

Library "libgif:7.0.0"

Private Enum GIF_ERROR = 0, GIF_OK

' GifFileType * EGifOpenFileName(const char *FileName, const bool TestExistence, int *Error)
' Open a new GIF file for write, specified by name.
Private Extern EGifOpenFileName(FileName As String, TestExistence As Boolean, ErrorP As Pointer) As Pointer
 
' ColorMapObject * GifMakeMapObject (int ColorCount, const GifColorType * ColorMap)
' Allocate a color map of given size.
Private Extern GifMakeMapObject(ColorCount As Integer, ColorMap As Pointer) As Pointer

' int EGifPutScreenDesc(GifFileType *GifFile, const int Width, const int Height, const int ColorRes, const int BackGround, const ColorMapObject *ColorMap)
' This routine should be called immediately following the GIF file opening.
Private Extern EGifPutScreenDesc(GifFileType As Pointer, wI As Integer, hI As Integer, ColorRes As Integer, BackGround As Integer, ColorMap As Pointer) As Integer

' int EGifPutImageDesc(GifFileType *GifFile, const int Left, const int Top, const int Width, const int Height, const bool Interlace, const ColorMapObject *ColorMap)
' This routine should be called before any attempt to dump an image - any call to any of the pixel dump routines.
Private Extern EGifPutImageDesc(GifFileType As Pointer, LeftI As Integer, Top As Integer, wI As Integer, hI As Integer, Interlace As Boolean, ColorMap As Pointer) As Integer

' int EGifPutLine(GifFileType * GifFile, GifPixelType *Line, int LineLen)
' Put one full scanned line (Line) of length LineLen into GIF file.
Private Extern EGifPutLine(GifFileType As Pointer, gpt As Pointer, LineLen As Integer) As Integer

' int DGifCloseFile(GifFileType *GifFile, int *ErrorCode)
' Close the GIF file.
Private Extern DGifCloseFile(GifFileType As Pointer, ErrorP As Pointer) As Integer


Public Sub Main()

 Dim fileGIF, MappaColori, p As Pointer
 Dim buffer As Pointer[]
 Dim Width, Height As Integer
 Dim b, c, n As Byte
 Dim st, rgb As Stream
' Imposta la mappa dei colori:
 Dim colori As Byte[] = [255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0]

' Vengono impostate le dimensioni in pixel dell'immagine "gif":
  Width = 255
  Height = 255

  buffer = New Pointer[Height, Width]

' Alloca il buffer per le linee che formano l'immagine, nel quale si porranno i dati per i colori di ciascun pixel:
  For c = 0 To Height - 1
    For b = 0 To Width - 1
      buffer[c, b] = Alloc(Width)
    Next
  Next

' Apre, creandolo, il nuovo file .gif in uscita:
  fileGIF = EGifOpenFileName("/percorso/del/file.gif", 0, 0)
  If IsNull(fileGIF) Then Error.Raise("Impossibile creare il file GIF !")

  MappaColori = GifMakeMapObject(256, 0)
  If IsNull(MappaColori) Then Error.Raise("Impossibile allocare memoria !")

' Scrive nella mappa dei colori impostando il colore di sfondo dell'immagine e poi gli altri colori utilizzabili per il disegno:
  st = Memory MappaColori For Read
  Seek #st, 16
  Read #st, p
  rgb = Memory p For Write
    colori.Write(rgb, 0, colori.Count)

  If EGifPutScreenDesc(fileGIF, Width, Height, 8, 0, MappaColori) = GIF_ERROR Then Error.Raise("Errore alla funzione 'EGifPutScreenDesc()' !")

  If EGifPutImageDesc(fileGIF, 0, 0, Width, Height, False, 0) = GIF_ERROR Then Error.Raise("Errore alla funzione 'EGifPutImageDesc()' !")
 
  For c = 0 To Height - 1
    For b = 0 To Width - 1
      st = Memory buffer[c, b] For Write
      Inc n
      Write #st, n As Byte
' Fa corrispodere la sequenza dei pixel durante la generazione delle varie linee che compongono l'imagine:
      If n = 5 Then n = 0
      st.Close
      If EGifPutLine(fileGIF, buffer[c, b], 1) = GIF_ERROR Then Error.Raise("Errore alla funzione 'EGifPutLine()' !")
    Next
  Next


' Va in chiusura:
  If EGifCloseFile(fileGIF, 0) = GIF_ERROR Then Error.Raise("Errore nella chiusura del file GIF !")
  For c = 0 To Height - 1
    For b = 0 To Width - 1
      Free(buffer[c, b])
    Next
  Next
       
End



Riferimenti