2010-12-30 16 views
21

Ho trovato questa funzione che libjpeg utilizza per scrivere in un file:Scrive sul buffer di memoria invece del file con libjpeg?

int write_jpeg_file(char *filename) 
{ 
    struct jpeg_compress_struct cinfo; 
    struct jpeg_error_mgr jerr; 

    /* this is a pointer to one row of image data */ 
    JSAMPROW row_pointer[1]; 
    FILE *outfile = fopen(filename, "wb"); 

    if (!outfile) 
    { 
     printf("Error opening output jpeg file %s\n!", filename); 
     return -1; 
    } 
    cinfo.err = jpeg_std_error(&jerr); 
    jpeg_create_compress(&cinfo); 
    jpeg_stdio_dest(&cinfo, outfile); 

    /* Setting the parameters of the output file here */ 
    cinfo.image_width = width; 
    cinfo.image_height = height; 
    cinfo.input_components = bytes_per_pixel; 
    cinfo.in_color_space = color_space; 
    /* default compression parameters, we shouldn't be worried about these */ 
    jpeg_set_defaults(&cinfo); 
    /* Now do the compression .. */ 
    jpeg_start_compress(&cinfo, TRUE); 
    /* like reading a file, this time write one row at a time */ 
    while(cinfo.next_scanline < cinfo.image_height) 
    { 
     row_pointer[0] = &raw_image[ cinfo.next_scanline * cinfo.image_width * cinfo.input_components]; 
     jpeg_write_scanlines(&cinfo, row_pointer, 1); 
    } 
    /* similar to read file, clean up after we're done compressing */ 
    jpeg_finish_compress(&cinfo); 
    jpeg_destroy_compress(&cinfo); 
    fclose(outfile); 
    /* success code is 1! */ 
    return 1; 
} 

vorrei davvero bisogno di scrivere l'immagine JPEG compressa solo per buffer di memoria, senza salvarlo in un file, per risparmiare tempo. Qualcuno potrebbe darmi un esempio su come farlo?

Sono stato a cercare sul Web per un po ', ma la documentazione è molto rara se c'è ne ed alcuni esempi sono anche difficili da trovare.

risposta

15

È possibile definire il proprio gestore di destinazione abbastanza facilmente. Il jpeg_compress_struct contiene un puntatore ad una jpeg_destination_mgr, che contiene un puntatore a un buffer, un conteggio di spazio lasciato nel buffer, e 3 puntatori a funzioni:

init_destination (j_compress_ptr cinfo) 
empty_output_buffer (j_compress_ptr cinfo) 
term_destination (j_compress_ptr cinfo) 

È necessario compilare i puntatori a funzione prima di effettuare la prima chiamata nella libreria jpeg e lasciare che queste funzioni gestiscano il buffer. Se crei un buffer che è più grande del più grande output possibile che ti aspetti, diventa banale; init_destination riempie semplicemente il puntatore del buffer e conta e empty_output_buffer e term_destination non fanno nulla.

Ecco alcuni esempi di codice:

std::vector<JOCTET> my_buffer; 
#define BLOCK_SIZE 16384 

void my_init_destination(j_compress_ptr cinfo) 
{ 
    my_buffer.resize(BLOCK_SIZE); 
    cinfo->dest->next_output_byte = &my_buffer[0]; 
    cinfo->dest->free_in_buffer = my_buffer.size(); 
} 

boolean my_empty_output_buffer(j_compress_ptr cinfo) 
{ 
    size_t oldsize = my_buffer.size(); 
    my_buffer.resize(oldsize + BLOCK_SIZE); 
    cinfo->dest->next_output_byte = &my_buffer[oldsize]; 
    cinfo->dest->free_in_buffer = my_buffer.size() - oldsize; 
    return true; 
} 

void my_term_destination(j_compress_ptr cinfo) 
{ 
    my_buffer.resize(my_buffer.size() - cinfo->dest->free_in_buffer); 
} 

cinfo->dest->init_destination = &my_init_destination; 
cinfo->dest->empty_output_buffer = &my_empty_output_buffer; 
cinfo->dest->term_destination = &my_term_destination; 
+0

Immagino che questi puntatori di funzione siano ciò che influenza 'jpeg_stdio_dest'? –

+0

@Ben Voigt, guardando il sorgente di 'jpeg_stdio_dest' è esattamente quello che fa. Alloca una struttura e la imposta in 'cinfo-> dest', quindi imposta i puntatori.Sto pensando che il mio codice di esempio potrebbe essere un po 'incompleto dal momento che non crea una struttura 'jpeg_destination_mgr', ma lo esaminerò più avanti. –

+0

Oh, certo. Puoi [memorizzare i tuoi dati ('std :: vector') immediatamente dopo i puntatori di funzione e non hanno bisogno di variabili globali] (http://blogs.msdn.com/b/oldnewthing/archive/2010/12/20/ 10107027.aspx). –

0

Tutto quello che devi fare è passare un oggetto-FILE-like a jpeg_stdio_dest().

9

C'è una funzione predefinita jpeg_mem_src definito jdatasrc.c. Esempio di utilizzo più semplice:

unsigned char *mem = NULL; 
unsigned long mem_size = 0; 
struct jpeg_compress_struct cinfo; 
struct jpeg_error_mgr jerr; 
cinfo.err = jpeg_std_error(&jerr); 
jpeg_create_compress(&cinfo); 
jpeg_mem_dest(&cinfo, &mem, &mem_size); 

// do compression 

// use mem buffer 

Non dimenticare di deallocare il buffer.

+0

Non nel mio' jdatasrc.c' (libjpeg-6b). –

+2

L'ultima versione stabile di libjpeg è 9, è possibile scaricarla qui http://www.ijg.org/files/jpegsr9.zip e contiene jpeg_mem_src. – dmitriykovalev

+0

Chiama gratis o cancella nel buffer mem? Ho chiamato delete [] e valgrind mi ha dato un avviso di eliminazione non corrispondente. Usato gratis() e l'avviso è scomparso. – shehzan

3

Ho provato la soluzione di Marco e sulla mia piattaforma dà sempre errore falut SEGMENTAZIONE quando si esegue

cinfo->dest->term_destination = &my_term_destination; 

E mi sono girato verso i codici sorgente jpeglib (jdatadst.c) e ho trovato questo:

jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize) 

appena sotto il metodo jpeg_stdio_dest(), e l'ho provato semplicemente inserendo l'indirizzo del buffer (char *) e l'indirizzo della dimensione del buffer (int). Il gestore di destinazione assegna automaticamente la memoria per il buffer e il programma deve liberare la memoria dopo l'uso.

Viene eseguito correttamente sulla mia piattaforma, Beaglebone Black con la versione preinstallata di Angstrom Linux. La mia versione di libjpeg è 8d.

1
unsigned char ***image_ptr  
unsigned char* ptr; 
unsigned char** image_buf; 

for(int i=0;i<h;i++){ 
image_buf[i] = new unsigned char[w*o]; 
} 

ptr = image_buf[0]; 

    while (info.output_scanline < info.image_height) { 

    jpeg_read_scanlines(&info,&ptr,1); 

    ptr = image_buf[c]; 

    c++; 


    } 

    *image_ptr = image_buf; 

Questo è tutto ciò che serve leggere.

JSAMPROW row_pointer; 

     while (info.next_scanline < info.image_height) { 

     row_pointer = &image_buf[info.next_scanline][0]; 

      (void) jpeg_write_scanlines(&info, &row_pointer, 1); 



           } 

E questo è tutto ciò che serve per scrivere.

+8

** Avviso ** - per favore non usare oscenità nei tuoi messaggi. L'ho rimosso per te. Nota che altri utenti potrebbero aver contrassegnato il tuo messaggio come "maleducato o abusivo" che porta a possibili perdite o sospensioni. Per favore leggi [Be Nice] (http://superuser.com/help/be-nice): "Evita termini volgari e qualsiasi cosa sessualmente allusiva" – DavidPostill