jpeg_compressor.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <fvutils/compression/jpeg_compressor.h>
00027 #include <fvutils/color/yuvrgb.h>
00028 #include <fvutils/color/rgbyuv.h>
00029
00030 #include <core/exception.h>
00031
00032 #include <cstdio>
00033 #include <cstring>
00034 #include <cstdlib>
00035 #include <setjmp.h>
00036 extern "C" {
00037 #include <jpeglib.h>
00038 #include <jerror.h>
00039 }
00040
00041
00042
00043
00044 typedef struct {
00045 struct jpeg_error_mgr pub;
00046 jmp_buf setjmp_buffer;
00047 } fv_jpeg_error_mgr_t;
00048
00049
00050
00051
00052
00053 typedef struct {
00054 struct jpeg_destination_mgr pub;
00055 JOCTET *buffer;
00056 int bufsize;
00057 int datacount;
00058 } fv_jpeg_memory_destination_mgr_t;
00059
00060
00061
00062
00063
00064
00065 METHODDEF(void)
00066 fv_jpeg_init_destination (j_compress_ptr cinfo)
00067 {
00068 fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00069 dest->pub.next_output_byte = dest->buffer;
00070 dest->pub.free_in_buffer = dest->bufsize;
00071 dest->datacount=0;
00072 }
00073
00074
00075
00076
00077
00078 METHODDEF(boolean)
00079 fv_jpeg_empty_output_buffer (j_compress_ptr cinfo)
00080 {
00081 fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00082 dest->pub.next_output_byte = dest->buffer;
00083 dest->pub.free_in_buffer = dest->bufsize;
00084
00085 return TRUE;
00086 }
00087
00088
00089
00090
00091
00092
00093 METHODDEF(void)
00094 fv_jpeg_term_destination (j_compress_ptr cinfo)
00095 {
00096
00097
00098 fv_jpeg_memory_destination_mgr_t *dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00099 dest->datacount = dest->bufsize - dest->pub.free_in_buffer;
00100 }
00101
00102
00103
00104
00105
00106
00107 GLOBAL(void)
00108 fv_jpeg_memory_destination_setup(j_compress_ptr cinfo, JOCTET *buffer,int bufsize)
00109 {
00110 fv_jpeg_memory_destination_mgr_t *dest;
00111 if ( cinfo->dest == NULL ) {
00112 cinfo->dest = (struct jpeg_destination_mgr *)
00113 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
00114 sizeof(fv_jpeg_memory_destination_mgr_t));
00115
00116 }
00117
00118 dest = (fv_jpeg_memory_destination_mgr_t *) cinfo->dest;
00119 dest->bufsize = bufsize;
00120 dest->buffer = buffer;
00121 dest->pub.init_destination = fv_jpeg_init_destination;
00122 dest->pub.empty_output_buffer = fv_jpeg_empty_output_buffer;
00123 dest->pub.term_destination = fv_jpeg_term_destination;
00124 }
00125
00126 METHODDEF(void)
00127 init_source(j_decompress_ptr cinfo)
00128 {
00129
00130 }
00131
00132 METHODDEF(boolean)
00133 fill_input_buffer(j_decompress_ptr cinfo)
00134 {
00135
00136 return FALSE;
00137 }
00138
00139 METHODDEF(void)
00140 skip_input_data(j_decompress_ptr cinfo, long num_bytes)
00141 {
00142 if ((size_t)num_bytes > cinfo->src->bytes_in_buffer) {
00143 cinfo->src->next_input_byte = NULL;
00144 cinfo->src->bytes_in_buffer = 0;
00145 } else {
00146 cinfo->src->next_input_byte += (size_t) num_bytes;
00147 cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
00148 }
00149 }
00150
00151 METHODDEF(void)
00152 term_source(j_decompress_ptr cinfo)
00153 {
00154
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164 GLOBAL(void)
00165 fv_jpeg_memory_source_setup(j_decompress_ptr cinfo, unsigned char *ptr, size_t size)
00166 {
00167 struct jpeg_source_mgr *src;
00168 src = cinfo->src = (struct jpeg_source_mgr *)
00169 (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo,
00170 JPOOL_PERMANENT,
00171 sizeof(*src));
00172 src->init_source = init_source;
00173 src->fill_input_buffer = fill_input_buffer;
00174 src->skip_input_data = skip_input_data;
00175 src->resync_to_restart = jpeg_resync_to_restart;
00176 src->term_source = term_source;
00177 src->next_input_byte = ptr;
00178 src->bytes_in_buffer = size;
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 JpegImageCompressor::JpegImageCompressor(unsigned int quality, JpegColorspace jcs)
00193 {
00194 this->quality = quality;
00195 jpeg_cs = jcs;
00196 }
00197
00198
00199 JpegImageCompressor::~JpegImageCompressor()
00200 {
00201 }
00202
00203
00204 void
00205 JpegImageCompressor::compress()
00206 {
00207 struct jpeg_compress_struct cinfo;
00208 struct jpeg_error_mgr jerr;
00209 unsigned int row_stride;
00210 unsigned char *row_buffer;
00211
00212
00213 fv_jpeg_memory_destination_mgr_t *dest;
00214
00215
00216 FILE *outfile = NULL;
00217
00218
00219
00220 memset (&cinfo, 0, sizeof(cinfo));
00221 cinfo.err = jpeg_std_error(&jerr);
00222 jpeg_create_compress(&cinfo);
00223
00224
00225 cinfo.image_width = width;
00226 cinfo.image_height = height;
00227 cinfo.input_components = 3;
00228 if ( jpeg_cs == JPEG_CS_RGB ) {
00229 cinfo.in_color_space = JCS_RGB;
00230 } else {
00231 cinfo.in_color_space = JCS_YCbCr;
00232 }
00233
00234 row_stride = cinfo.image_width * cinfo.input_components;
00235
00236 if ( compdest == COMP_DEST_MEM ) {
00237
00238 fv_jpeg_memory_destination_setup(&cinfo, (JOCTET *)jpeg_buffer, jpeg_buffer_size);
00239 } else {
00240 outfile = fopen(filename, "wb");
00241 if (outfile == NULL) {
00242 throw fawkes::Exception("JpegImageCompressor: cannot open %s\n", filename);
00243 }
00244 jpeg_stdio_dest( &cinfo, outfile );
00245 }
00246
00247 jpeg_set_defaults(&cinfo);
00248 jpeg_set_quality (&cinfo, quality, true );
00249 jpeg_start_compress(&cinfo, true);
00250
00251
00252 row_buffer = (unsigned char *)malloc( row_stride );
00253
00254
00255 if ( jpeg_cs == JPEG_CS_RGB ) {
00256 while (cinfo.next_scanline < cinfo.image_height) {
00257 convert_line_yuv422planar_to_rgb( buffer, row_buffer,
00258 cinfo.image_width, cinfo.image_height,
00259 cinfo.next_scanline, 0 );
00260 jpeg_write_scanlines(&cinfo, &row_buffer, 1);
00261 }
00262 } else {
00263 while (cinfo.next_scanline < cinfo.image_height) {
00264 convert_line_yuv422planar_to_yuv444packed( buffer, row_buffer,
00265 cinfo.image_width, cinfo.image_height,
00266 cinfo.next_scanline, 0 );
00267 jpeg_write_scanlines(&cinfo, &row_buffer, 1);
00268 }
00269 }
00270
00271 free(row_buffer);
00272 jpeg_finish_compress(&cinfo);
00273
00274 if ( compdest == COMP_DEST_MEM ) {
00275
00276 dest=(fv_jpeg_memory_destination_mgr_t *)cinfo.dest;
00277 jpeg_bytes = dest->datacount;
00278 } else {
00279 fclose( outfile );
00280 }
00281
00282
00283 jpeg_destroy_compress(&cinfo);
00284
00285 }
00286
00287
00288 void
00289 JpegImageCompressor::set_image_dimensions(unsigned int width, unsigned int height)
00290 {
00291 this->width = width;
00292 this->height = height;
00293 }
00294
00295
00296 void
00297 JpegImageCompressor::set_image_buffer(colorspace_t cspace, unsigned char *buffer)
00298 {
00299 if ( cspace == YUV422_PLANAR ) {
00300 this->buffer = buffer;
00301 }
00302 }
00303
00304
00305 void
00306 JpegImageCompressor::set_compression_destination(ImageCompressor::CompressionDestination cd)
00307 {
00308 compdest = cd;
00309 }
00310
00311
00312 bool
00313 JpegImageCompressor::supports_compression_destination(ImageCompressor::CompressionDestination cd)
00314 {
00315 return true;
00316 }
00317
00318
00319 void
00320 JpegImageCompressor::set_destination_buffer(unsigned char *buf, unsigned int buf_size)
00321 {
00322 jpeg_buffer = buf;
00323 jpeg_buffer_size = buf_size;
00324 }
00325
00326
00327 size_t
00328 JpegImageCompressor::compressed_size()
00329 {
00330 return jpeg_bytes;
00331 }
00332
00333 size_t
00334 JpegImageCompressor::recommended_compressed_buffer_size()
00335 {
00336 return width * height / 5;
00337 }
00338
00339
00340 void
00341 JpegImageCompressor::set_filename(const char *filename)
00342 {
00343 this->filename = filename;
00344 }