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

Da Gambas-it.org - Wikipedia.
Versione del 19 mag 2015 alle 06:35 di Vuott (Discussione | contributi) (Creata pagina con '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%. ...')

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

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 esterna (nella sua attuale versione): 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.

Tale liberia ad hoc sarà così scritta:

#include <stdio.h>
#include <stdlib.h>
#include <jpeglib.h>


unsigned char * bmp_buffer;


unsigned char *  Legge_linee(struct jpeg_decompress_struct * cinfo, int bmp_size, int row_stride) {

  bmp_buffer = (unsigned char*) malloc(bmp_size);

  while (cinfo->output_scanline < cinfo->output_height) {

    unsigned char *buffer_array[1];

    buffer_array[0] = bmp_buffer + (cinfo->output_scanline) * row_stride;

    jpeg_read_scanlines(cinfo, buffer_array, 1);

}

 return bmp_buffer;
 
}

Nel nostro esempio tale sorgente della libreria esterna verrà salvato con il nome libadhoc.c nella cartella Dati del progamma principale scritto in Gambas.


Il progamma principale scritto in Gambas, che mostrerà anche alcune informazioni di carattere generale sul file JPEG caricato, potrà avere il seguente tenore:

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)


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, dim_pixel, rc As Integer
 Dim buffer, buf, bb As Byte[]


' Creiamo la libreria esterna condivisa .so da noi scritta:
  Shell "gcc -o /tmp/libadhoc.so " & Application.Path &/ "libadhoc.c -shared -fPIC -ljpeg" Wait


  percorso = "/percorso/del/file/immagine.jpg"
  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: ", Null; width
  Read #st, height
  Print "Altezza in pixel: ", Null; height
  Seek #st, 56
  Read #st, dim_pixel
  Print "Byte per pixel: ", Null; pixel_size; "  (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



Riferimenti