Decomprimere un file immagine jpeg per ottenerne i dati grezzi mediante le funzioni esterne del API di libjpeg

Da Gambas-it.org - Wikipedia.

Il formato JPEG (Joint Photographic Experts Group) è uno standard di compressione delle immagini, arrivando a ridurre le dimensioni di un file immagine anche sino al 5%.

E' possibile ottenere da un file immagine JPEG i suoi dati in formato grezzo utilizzando alcune funzioni della libreria dinamica condivisa: "libjpeg.so.8.0.2".


Mostriamo di seguito un esempio di decodifica di un file JPEG, nel quale utilizzeremo - al fine di gestire con sicurezza una parte di codice - istruzioni in linguaggio C che saranno poste in un'apposita libreria esterna da noi creata.
Il progamma mostrerà anche alcune informazioni di carattere generale sul file JPEG caricato.

Library "libjpeg:8.0.2"

' struct jpeg_error_mgr * jpeg_std_error(struct jpeg_error_mgr * error_mgr)
' Update the given jpeg_error_mgr object with standard error handling methods.
Private Extern jpeg_std_error(error_mgr As Pointer) As Pointer

' void jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t size)
' Allocate and initialize a JPEG decompression object of type struct jpeg_decompress_struct.
Private Extern jpeg_CreateDecompress(cinfo_ptr As Pointer, version As Integer, size As Integer)

' void jpeg_mem_src(j_decompress_ptr cinfo, unsigned char * inbuffer, unsigned long insize)
' Data source and destination managers: memory buffers.
Private Extern jpeg_mem_src(cinfo_ptr As Pointer, inbuffer As Byte[], insize As Long)

' int jpeg_read_header(j_decompress_ptr cinfo, boolean require_image)
' Read the JPEG datastream until the first SOS marker is encountered.
Private Extern jpeg_read_header(cinfo_ptr As Pointer, require_image As Boolean) As Integer

' boolean jpeg_start_decompress(j_decompress_ptr cinfo)
' Initialize state for a JPEG decompression cycle and allocate working memory.
Private Extern jpeg_start_decompress(cinfo_ptr As Pointer) As Boolean

' boolean jpeg_finish_decompress(j_decompress_ptr cinfo)
' Set the decompression state to completion.
Private Extern jpeg_finish_decompress(cinfo_ptr As Pointer) As Boolean

' void jpeg_destroy_decompress(j_decompress_ptr cinfo)
' Deallocate and release all memory associated with the decompression object.
Private Extern jpeg_destroy_decompress(cinfo_ptr As Pointer)


' unsigned char *  Legge_linee(struct jpeg_decompress_struct * cinfo, int bmp_size, int row_stride)
' Invoca la libreria externa appositamente creata per leggere le righe di pixel del file JPEG.
Private Extern Legge_linee(cinfo_ptr As Pointer, bmp_buf As Pointer, row As Integer) As Pointer In "/tmp/libadhoc"


Public Sub Main()

 Dim percorso, header As String
 Dim mgr, cinfo, bmp As Pointer
 Dim st As Stream
 Dim dim_jpg, dim_bmp As Long
 Dim fl As File
 Dim prog_riga, width, height As Integer
 Dim num_comp, dim_pixel, rc As Integer
 Dim buffer, buf, bb As Byte[]

' Crea la libreria esterna condivisa .so appositamente scritta:
  Creaso()
  
  percorso = "/percorso/del/file/immagine.jpg"
  If Not Exist(percorso) Then Error.Raise("Percorso file immagine inesistente !")
  Print "File immagine JPEG: ", Null; percorso

' Carica i dati jpeg da un file in un buffer di memoria:
  dim_jpg = Stat(percorso).Size
  Print "Dimensione del file: ", Null; dim_jpg; " byte"

  fl = Open percorso For Read

  With buffer = New Byte[dim_jpg]
    .Read(fl, 0, buffer.Max)
  End With

  fl.close()

  mgr = Alloc(168)
  cinfo = Alloc(656)
 
  st = Memory cinfo For Write
  Write #st, jpeg_std_error(mgr) As Pointer

  jpeg_CreateDecompress(cinfo, 80, 656)
 
  jpeg_mem_src(cinfo, buffer, dim_jpg)

  rc = jpeg_read_header(cinfo, True)
  If rc <> 1 Then Error.Raise("Il file non sembra essere un normale JPEG !")
 
' Comincia la decompressione dei dati JPEG:
  jpeg_start_decompress(cinfo)
 
  Seek #st, 48
  Read #st, width
  Print "Larghezza in pixel:  "; width
  Read #st, height
  Print "Altezza in pixel:    "; height
  Read #st, num_comp
  Read #st, dim_pixel
  Print "Byte per pixel:      "; num_comp; " (profondità: "; dim_pixel * 8; " bit)"
  st.Close
  
  dim_bmp = width * height * dim_pixel
  Print "Dimensione bitMap: ", Null; dim_bmp; " byte\n"
 
' La variabile "prog_riga" è il numero totale di byte che serve per memorizzare un'intera linea di scansione (riga):
  prog_riga = width * dim_pixel

' Al termine della decompressione, si va a leggere tutte le linee di scansione del jpeg,
' le quali di norma risultano disposte con l'ordine RGBRGBRGB (ordine che può essere cambiato agendo sul membro "cinfo.out_color_space"):
  bmp = Legge_linee(cinfo, dim_bmp, prog_riga)

  jpeg_finish_decompress(cinfo)
   
  jpeg_destroy_decompress(cinfo)
' ''''''''''''''''''''''''''''''''''''''
  
' Ottenuti i dati grezzi, possiamo utilizzarli, ad esempio creando un file immagine non compresso (in questo caso di formato PNM):
  fl = Open "/tmp/file.ppm" For Create
 
  st = Memory bmp For Read
  bb = New Byte[dim_bmp]
  bb.Read(st)
 
  header = "P6 " & CStr(width) & " " & CStr(height) & " 255\n"
 
  With buf = Byte[].FromString(header)
    .Insert(bb)
    .Write(fl)
  End With
 

' Va in chiusura:
  st.Close
  fl.Close
  Free(cinfo)
  Free(mgr)

End


Private Procedure Creaso()
 
' Imposta il codice sorgente della parte in linguaggio C:
 File.Save("/tmp/libadhoc.c", "#include <stdio.h>\n#include <stdlib.h>\n#include <jpeglib.h>\n\n" &
           "unsigned char * bmp_buffer;\n\n" &
           "unsigned char *  Legge_linee(struct jpeg_decompress_struct * cinfo, int bmp_size, int row_stride) {\n\n" &
           "   bmp_buffer = (unsigned char*) malloc(bmp_size);\n\n" &
           "   while (cinfo->output_scanline < cinfo->output_height) {\n" &
           "     unsigned char *buffer_array[1];\n" &
           "     buffer_array[0] = bmp_buffer + (cinfo->output_scanline) * row_stride;\n" &
           "     jpeg_read_scanlines(cinfo, buffer_array, 1);\n   }\n\n" &
           "   return bmp_buffer;\n\n}")
 
' Crea la libreria esterna condivisa .so appositamente scritta per gestire la parte in linguaggio C:
 Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -shared -fPIC -ljpeg" Wait
 
End



Riferimenti