2013-04-24 4 views
2

Я решил использовать libjpeg в качестве основной библиотеки, работающей с файлами jpeg. Я читал файл libjpg.txt. И я был рад, что библиотека позволяет читать и записывать DCT-коэффициенты удобным способом. Поскольку писать собственный декодер займет много времени.Изменение DCT-коэффициентов

Моя работа связана с вложением без потерь. В настоящее время мне нужно прочитать DCT-коэффициенты из файла, а затем изменить некоторые из них и записать измененные коэффициенты в один и тот же файл.

Ну, я нашел jpeg_write_coefficients() функция. И я наивно думал, что могу применить его к декомпрессионному объекту (struct jpeg_decompress_struct). Но это не работает и требует объекта сжатия.

Не могу поверить, что такая мощная библиотека не в состоянии это сделать. Я думаю, что, скорее всего, я что-то упустил. Хотя я старался быть внимательным. Возможно, коэффициенты записи можно сделать более сложным способом. Но я не знаю, как это сделать.

Я буду очень рад, если вы предложите свои идеи.

+0

Посмотрите http://stackoverflow.com/questions/4470107/extracting-dct-coefficients-from-encoded-images-and-video/ – misha

+0

Миша! Спасибо за ответ! Но я не знаю, как применить исходный код к моей проблеме. Я также извлек коэффициенты DCT. Теперь моя задача - просто написать измененные коэффициенты в один и тот же файл jpeg. Но, по-видимому, jpeglib не может это сделать, просто используя вызов функции. Мне не нужно изменять какую-либо информацию, кроме значений quontized dct. – Alexey

ответ

0

Вы действительно должны смотреть на transupp.h и источники для jpegtran, который поставляется с библиотекой. В любом случае, вот мой грязный код с комментариями, собранный частично от jpegtran. Это позволяет вам управлять коэффициентами DCT один за другим.

#include "jpeglib.h"    /* Common decls for cjpeg/djpeg applications */ 
#include "transupp.h"   /* Support routines for jpegtran */ 


struct jpeg_decompress_struct srcinfo; 
struct jpeg_compress_struct dstinfo; 
struct jpeg_error_mgr jsrcerr, jdsterr; 

static jpeg_transform_info transformoption; /* image transformation options */ 
transformoption.transform = JXFORM_NONE; 
transformoption.trim = FALSE; 
transformoption.force_grayscale = FALSE; 

jvirt_barray_ptr * src_coef_arrays; 
jvirt_barray_ptr * dst_coef_arrays; 

/* Initialize the JPEG decompression object with default error handling. */ 
srcinfo.err = jpeg_std_error(&jsrcerr); 
jpeg_create_decompress(&srcinfo); 
/* Initialize the JPEG compression object with default error handling. */ 
dstinfo.err = jpeg_std_error(&jdsterr); 
jpeg_create_compress(&dstinfo); 

FILE *fp; 

if((fp = fopen(filePath], "rb")) == NULL) { 
    //Throw an error 
} else { 
    //Continue 
} 

/* Specify data source for decompression */ 
jpeg_stdio_src(&srcinfo, fp); 

/* Enable saving of extra markers that we want to copy */ 
jcopy_markers_setup(&srcinfo, JCOPYOPT_ALL); 

/* Read file header */ 
(void) jpeg_read_header(&srcinfo, TRUE); 

jtransform_request_workspace(&srcinfo, &transformoption); 
src_coef_arrays = jpeg_read_coefficients(&srcinfo); 
jpeg_copy_critical_parameters(&srcinfo, &dstinfo); 

/* Do your DCT shenanigans here on src_coef_arrays like this (I've moved it into a separate function): */ 

moveDCTAround(&srcinfo, &dstinfo, 0, src_coef_arrays); 

/* ..when done with DCT, do this: */ 
dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); 
fclose(fp); 

//And write everything back 
fp = fopen(filePath, "wb"); 

/* Specify data destination for compression */ 
jpeg_stdio_dest(&dstinfo, fp); 

/* Start compressor (note no image data is actually written here) */ 
jpeg_write_coefficients(&dstinfo, dst_coef_arrays); 

/* Copy to the output file any extra markers that we want to preserve */ 
jcopy_markers_execute(&srcinfo, &dstinfo, JCOPYOPT_ALL); 

jpeg_finish_compress(&dstinfo); 
jpeg_destroy_compress(&dstinfo); 
(void) jpeg_finish_decompress(&srcinfo); 
jpeg_destroy_decompress(&srcinfo); 

fclose(fp); 

И сама функция:

void moveDCTAround (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays) 
{ 
    size_t block_row_size; 
    JBLOCKARRAY coef_buffers[MAX_COMPONENTS]; 
    JBLOCKARRAY row_ptrs[MAX_COMPONENTS]; 

    //Allocate DCT array buffers 
    for (JDIMENSION compnum=0; compnum<srcinfo->num_components; compnum++) 
    { 
     coef_buffers[compnum] = (dstinfo->mem->alloc_barray)((j_common_ptr) dstinfo, JPOOL_IMAGE, srcinfo->comp_info[compnum].width_in_blocks, 
     srcinfo->comp_info[compnum].height_in_blocks); 
    } 

    //For each component, 
    for (JDIMENSION compnum=0; compnum<srcinfo->num_components; compnum++) 
    { 
     block_row_size = (size_t) sizeof(JCOEF)*DCTSIZE2*srcinfo->comp_info[compnum].width_in_blocks; 
     //...iterate over rows, 
     for (JDIMENSION rownum=0; rownum<srcinfo->comp_info[compnum].height_in_blocks; rownum++) 
     { 
      row_ptrs[compnum] = ((dstinfo)->mem->access_virt_barray)((j_common_ptr) &dstinfo, src_coef_arrays[compnum], rownum, (JDIMENSION) 1, FALSE); 
      //...and for each block in a row, 
      for (JDIMENSION blocknum=0; blocknum<srcinfo->comp_info[compnum].width_in_blocks; blocknum++) 
       //...iterate over DCT coefficients 
       for (JDIMENSION i=0; i<DCTSIZE2; i++) 
       { 
         //Manipulate your DCT coefficients here. For instance, the code here inverts the image. 
         coef_buffers[compnum][rownum][blocknum][i] = -row_ptrs[compnum][0][blocknum][i]; 
       } 
     } 
    } 

    //Save the changes 
    //For each component, 
    for (JDIMENSION compnum=0; compnum<srcinfo->num_components; compnum++) 
    { 
     block_row_size = (size_t) sizeof(JCOEF)*DCTSIZE2 * srcinfo->comp_info[compnum].width_in_blocks; 
     //...iterate over rows 
     for (JDIMENSION rownum=0; rownum < srcinfo->comp_info[compnum].height_in_blocks; rownum++) 
     { 
      //Copy the whole rows 
      row_ptrs[compnum] = (dstinfo->mem->access_virt_barray)((j_common_ptr) dstinfo, src_coef_arrays[compnum], rownum, (JDIMENSION) 1, TRUE); 
      memcpy(row_ptrs[compnum][0][0], coef_buffers[compnum][rownum][0], block_row_size); 
     } 
    } 
2

Вы можете и^jpeg_write_coefficients писать ваш измененный DCT.

Следующая информация доступна в libjpeg.txt

To write the contents of a JPEG file as DCT coefficients, you must provide 
the DCT coefficients stored in virtual block arrays. You can either pass 
block arrays read from an input JPEG file by jpeg_read_coefficients(), or 
allocate virtual arrays from the JPEG compression object and fill them 
yourself. In either case, jpeg_write_coefficients() is substituted for 
jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is 
    * Create compression object 
    * Set all compression parameters as necessary 
    * Request virtual arrays if needed 
    * jpeg_write_coefficients() 
    * jpeg_finish_compress() 
    * Destroy or re-use compression object 
jpeg_write_coefficients() is passed a pointer to an array of virtual block 
array descriptors; the number of arrays is equal to cinfo.num_components. 

The virtual arrays need only have been requested, not realized, before 
jpeg_write_coefficients() is called. A side-effect of 
jpeg_write_coefficients() is to realize any virtual arrays that have been 
requested from the compression object's memory manager. Thus, when obtaining 
the virtual arrays from the compression object, you should fill the arrays 
after calling jpeg_write_coefficients(). The data is actually written out 
when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes 
the file header. 

When writing raw DCT coefficients, it is crucial that the JPEG quantization 
tables and sampling factors match the way the data was encoded, or the 
resulting file will be invalid. For transcoding from an existing JPEG file, 
we recommend using jpeg_copy_critical_parameters(). This routine initializes 
all the compression parameters to default values (like jpeg_set_defaults()), 
then copies the critical information from a source decompression object. 
The decompression object should have just been used to read the entire 
JPEG input file --- that is, it should be awaiting jpeg_finish_decompress(). 

jpeg_write_coefficients() marks all tables stored in the compression object 
as needing to be written to the output file (thus, it acts like 
jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid 
emitting abbreviated JPEG files by accident. If you really want to emit an 
abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables' 
individual sent_table flags, between calling jpeg_write_coefficients() and 
jpeg_finish_compress(). 

Так, чтобы изменить один DCT, вы можете использовать следующий простой код: Чтобы получить доступ к любому DCT коэфф, вам необходимо изменить четыре индекса, сй, Ьй , by, bi. В моем коде, я использовал blockptr_one[bi]++; увеличить один DCT Коэфф

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

int write_jpeg_file(std::string outname,jpeg_decompress_struct in_cinfo, jvirt_barray_ptr *coeffs_array){ 

    struct jpeg_compress_struct cinfo; 
    struct jpeg_error_mgr jerr; 
    FILE * infile; 

    if ((infile = fopen(outname.c_str(), "wb")) == NULL) { 
     fprintf(stderr, "can't open %s\n", outname.c_str()); 
     return 0; 
    } 

    cinfo.err = jpeg_std_error(&jerr); 
    jpeg_create_compress(&cinfo); 
    jpeg_stdio_dest(&cinfo, infile); 

    j_compress_ptr cinfo_ptr = &cinfo; 
    jpeg_copy_critical_parameters((j_decompress_ptr)&in_cinfo,cinfo_ptr); 
    jpeg_write_coefficients(cinfo_ptr, coeffs_array); 

    jpeg_finish_compress(&cinfo); 
    jpeg_destroy_compress(&cinfo); 
    fclose(infile); 

    return 1; 
} 

int read_jpeg_file(std::string filename, std::string outname) 
{ 
    struct jpeg_decompress_struct cinfo; 
    struct jpeg_error_mgr jerr; 
    FILE * infile; 

    if ((infile = fopen(filename.c_str(), "rb")) == NULL) { 
     fprintf(stderr, "can't open %s\n", filename.c_str()); 
     return 0; 
    } 

    cinfo.err = jpeg_std_error(&jerr); 
    jpeg_create_decompress(&cinfo); 
    jpeg_stdio_src(&cinfo, infile); 
    (void) jpeg_read_header(&cinfo, TRUE); 


    jvirt_barray_ptr *coeffs_array = jpeg_read_coefficients(&cinfo); 

    //change one dct: 
    int ci = 0; // between 0 and number of image component 
    int by = 0; // between 0 and compptr_one->height_in_blocks 
    int bx = 0; // between 0 and compptr_one->width_in_blocks 
    int bi = 0; // between 0 and 64 (8x8) 
    JBLOCKARRAY buffer_one; 
    JCOEFPTR blockptr_one; 
    jpeg_component_info* compptr_one; 
    compptr_one = cinfo.comp_info + ci; 
    buffer_one = (cinfo.mem->access_virt_barray)((j_common_ptr)&cinfo, coeffs_array[ci], by, (JDIMENSION)1, FALSE); 
    blockptr_one = buffer_one[0][bx]; 
    blockptr_one[bi]++; 

    write_jpeg_file(outname, cinfo, coeffs_array); 

    jpeg_finish_decompress(&cinfo); 
    jpeg_destroy_decompress(&cinfo); 
    fclose(infile); 

    return 1; 


} 

int main() 
{ 
    std::string infilename = "you_image.jpg", outfilename = "out_image.jpg"; 

    /* Try opening a jpeg*/ 
    if(read_jpeg_file(infilename, outfilename) > 0) 
    { 
     std::cout << "It's Okay..." << std::endl; 
    } 
    else return -1; 
    return 0; 
}