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 3 lug 2024 alle 13:47 di Vuott (Discussione | contributi)
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 condivisa: "libjpeg.so.8.3.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.3.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: "; 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(Sizeof(gb.Byte), 168) cinfo = Alloc(Sizeof(gb.Byte), 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: "; 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