/** * Rotates jpeg image. * * <p> Operates on DCT blocks to avoid doing a full decode. */ static void rotateJpeg( JNIEnv* env, struct jpeg_source_mgr& source, struct jpeg_destination_mgr& destination, RotationType rotation_type) { JpegErrorHandler error_handler{env}; if (setjmp(error_handler.setjmpBuffer)) { return; } // prepare decompress struct struct jpeg_decompress_struct dinfo; initDecompressStruct(dinfo, error_handler, source); // create compress struct struct jpeg_compress_struct cinfo; initCompressStruct(cinfo, dinfo, error_handler, destination); // prepare transform struct jpeg_transform_info xinfo; initTransformInfo(xinfo, dinfo, rotation_type); // transform jvirt_barray_ptr* srccoefs = jpeg_read_coefficients(&dinfo); jpeg_copy_critical_parameters(&dinfo, &cinfo); jvirt_barray_ptr* dstcoefs = jtransform_adjust_parameters(&dinfo, &cinfo, srccoefs, &xinfo); jpeg_write_coefficients(&cinfo, dstcoefs); jcopy_markers_execute(&dinfo, &cinfo, JCOPYOPT_ALL); jtransform_execute_transformation(&dinfo, &cinfo, srccoefs, &xinfo); // tear down jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); jpeg_destroy_decompress(&dinfo); }
void *turn_jpeg_file_threadfunc(void *arg) { struct quick_jpeg_print_info *qinfo = (struct quick_jpeg_print_info *) arg; /* turn like in jpegtran i.e. turn losslessly by turning only the compressed data, and should be much more efficient, and even doing it through a pipe for efficiency - hah, that's cool, isn't it? */ jpeg_transform_info transformoption; jvirt_barray_ptr *src_coef_arrays, *dst_coef_arrays; j_decompress_ptr srcinfo; struct jpeg_compress_struct dstinfo; srcinfo = qinfo->pipesrcinfo; transformoption.transform = JXFORM_ROT_270; transformoption.perfect = FALSE; transformoption.trim = FALSE; transformoption.force_grayscale = FALSE; transformoption.crop = FALSE; dstinfo.err = &(qinfo->jerr); jpeg_create_compress(&dstinfo); jtransform_request_workspace(srcinfo, &transformoption); src_coef_arrays = jpeg_read_coefficients(srcinfo); jpeg_copy_critical_parameters(srcinfo, &dstinfo); dst_coef_arrays = jtransform_adjust_parameters(srcinfo, &dstinfo, src_coef_arrays, &transformoption); jpeg_stdio_dest(&dstinfo, qinfo->pipefile[1]); jpeg_write_coefficients(&dstinfo, dst_coef_arrays); jtransform_execute_transformation(srcinfo, &dstinfo, src_coef_arrays, &transformoption); jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); jpeg_finish_decompress(srcinfo); jpeg_destroy_decompress(srcinfo); fclose(qinfo->pipefile[1]); close(qinfo->threadpipe[1]); return NULL; }
static BOOL JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) { const BOOL onlyReturnCropRect = (dst_io == NULL) || (dst_handle == NULL); const long stream_start = onlyReturnCropRect ? 0 : dst_io->tell_proc(dst_handle); BOOL swappedDim = FALSE; BOOL trimH = FALSE; BOOL trimV = FALSE; // Set up the jpeglib structures jpeg_decompress_struct srcinfo; jpeg_compress_struct dstinfo; jpeg_error_mgr jsrcerr, jdsterr; jvirt_barray_ptr *src_coef_arrays = NULL; jvirt_barray_ptr *dst_coef_arrays = NULL; // Support for copying optional markers from source to destination file JCOPY_OPTION copyoption; // Image transformation options jpeg_transform_info transfoptions; // Initialize structures memset(&srcinfo, 0, sizeof(srcinfo)); memset(&jsrcerr, 0, sizeof(jsrcerr)); memset(&jdsterr, 0, sizeof(jdsterr)); memset(&dstinfo, 0, sizeof(dstinfo)); memset(&transfoptions, 0, sizeof(transfoptions)); // Copy all extra markers from source file copyoption = JCOPYOPT_ALL; // Set up default JPEG parameters transfoptions.force_grayscale = FALSE; transfoptions.crop = FALSE; // Select the transform option switch(operation) { case FIJPEG_OP_FLIP_H: // horizontal flip transfoptions.transform = JXFORM_FLIP_H; trimH = TRUE; break; case FIJPEG_OP_FLIP_V: // vertical flip transfoptions.transform = JXFORM_FLIP_V; trimV = TRUE; break; case FIJPEG_OP_TRANSPOSE: // transpose across UL-to-LR axis transfoptions.transform = JXFORM_TRANSPOSE; swappedDim = TRUE; break; case FIJPEG_OP_TRANSVERSE: // transpose across UR-to-LL axis transfoptions.transform = JXFORM_TRANSVERSE; trimH = TRUE; trimV = TRUE; swappedDim = TRUE; break; case FIJPEG_OP_ROTATE_90: // 90-degree clockwise rotation transfoptions.transform = JXFORM_ROT_90; trimH = TRUE; swappedDim = TRUE; break; case FIJPEG_OP_ROTATE_180: // 180-degree rotation trimH = TRUE; trimV = TRUE; transfoptions.transform = JXFORM_ROT_180; break; case FIJPEG_OP_ROTATE_270: // 270-degree clockwise (or 90 ccw) transfoptions.transform = JXFORM_ROT_270; trimV = TRUE; swappedDim = TRUE; break; default: case FIJPEG_OP_NONE: // no transformation transfoptions.transform = JXFORM_NONE; break; } // (perfect == TRUE) ==> fail if there is non-transformable edge blocks transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE; // Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle. transfoptions.trim = TRUE; try { // Initialize the JPEG decompression object with default error handling srcinfo.err = jpeg_std_error(&jsrcerr); srcinfo.err->error_exit = ls_jpeg_error_exit; srcinfo.err->output_message = ls_jpeg_output_message; jpeg_create_decompress(&srcinfo); // Initialize the JPEG compression object with default error handling dstinfo.err = jpeg_std_error(&jdsterr); dstinfo.err->error_exit = ls_jpeg_error_exit; dstinfo.err->output_message = ls_jpeg_output_message; jpeg_create_compress(&dstinfo); // Specify data source for decompression jpeg_freeimage_src(&srcinfo, src_handle, src_io); // Enable saving of extra markers that we want to copy jcopy_markers_setup(&srcinfo, copyoption); // Read the file header jpeg_read_header(&srcinfo, TRUE); // crop option char crop[64]; const BOOL hasCrop = getCropString(crop, left, top, right, bottom, swappedDim ? srcinfo.image_height : srcinfo.image_width, swappedDim ? srcinfo.image_width : srcinfo.image_height); if(hasCrop) { if(!jtransform_parse_crop_spec(&transfoptions, crop)) { FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop); throw(1); } } // Any space needed by a transform option must be requested before // jpeg_read_coefficients so that memory allocation will be done right // Prepare transformation workspace // Fails right away if perfect flag is TRUE and transformation is not perfect if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) { FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect"); throw(1); } if(left || top) { // compute left and top offsets, it's a bit tricky, taking into account both // transform, which might have trimed the image, // and crop itself, which is adjusted to lie on a iMCU boundary const int fullWidth = swappedDim ? srcinfo.image_height : srcinfo.image_width; const int fullHeight = swappedDim ? srcinfo.image_width : srcinfo.image_height; int transformedFullWidth = fullWidth; int transformedFullHeight = fullHeight; if(trimH && transformedFullWidth/transfoptions.iMCU_sample_width > 0) { transformedFullWidth = (transformedFullWidth/transfoptions.iMCU_sample_width) * transfoptions.iMCU_sample_width; } if(trimV && transformedFullHeight/transfoptions.iMCU_sample_height > 0) { transformedFullHeight = (transformedFullHeight/transfoptions.iMCU_sample_height) * transfoptions.iMCU_sample_height; } const int trimmedWidth = fullWidth - transformedFullWidth; const int trimmedHeight = fullHeight - transformedFullHeight; if(left) { *left = trimmedWidth + transfoptions.x_crop_offset * transfoptions.iMCU_sample_width; } if(top) { *top = trimmedHeight + transfoptions.y_crop_offset * transfoptions.iMCU_sample_height; } } if(right) { *right = (left ? *left : 0) + transfoptions.output_width; } if(bottom) { *bottom = (top ? *top : 0) + transfoptions.output_height; } // if only the crop rect is requested, we are done if(onlyReturnCropRect) { jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return TRUE; } // Read source file as DCT coefficients src_coef_arrays = jpeg_read_coefficients(&srcinfo); // Initialize destination compression parameters from source values jpeg_copy_critical_parameters(&srcinfo, &dstinfo); // Adjust destination parameters if required by transform options; // also find out which set of coefficient arrays will hold the output dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); // Note: we assume that jpeg_read_coefficients consumed all input // until JPEG_REACHED_EOI, and that jpeg_finish_decompress will // only consume more while (! cinfo->inputctl->eoi_reached). // We cannot call jpeg_finish_decompress here since we still need the // virtual arrays allocated from the source object for processing. if(src_handle == dst_handle) { dst_io->seek_proc(dst_handle, stream_start, SEEK_SET); } // Specify data destination for compression jpeg_freeimage_dst(&dstinfo, dst_handle, dst_io); // 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, copyoption); // Execute image transformation, if any jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); // Finish compression and release memory jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); } catch(...) { jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return FALSE; } return TRUE; }
static int _epeg_transform(Epeg_Image *im) { jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; JCOPY_OPTION copyoption; jpeg_transform_info transformoption; memset(&transformoption, 0, sizeof(jpeg_transform_info)); copyoption = JCOPYOPT_NONE; transformoption.crop = FALSE; transformoption.trim = TRUE; transformoption.force_grayscale = FALSE; switch(im->out.transform) { case EPEG_TRANSFORM_NONE: transformoption.transform = JXFORM_NONE; break; case EPEG_TRANSFORM_FLIP_H: transformoption.transform = JXFORM_FLIP_H; break; case EPEG_TRANSFORM_FLIP_V: transformoption.transform = JXFORM_FLIP_V; break; case EPEG_TRANSFORM_TRANSPOSE: transformoption.transform = JXFORM_TRANSPOSE; break; case EPEG_TRANSFORM_TRANSVERSE: transformoption.transform = JXFORM_TRANSVERSE; break; case EPEG_TRANSFORM_ROT_90: transformoption.transform = JXFORM_ROT_90; break; case EPEG_TRANSFORM_ROT_180: transformoption.transform = JXFORM_ROT_180; break; case EPEG_TRANSFORM_ROT_270: transformoption.transform = JXFORM_ROT_270; break; default: return 1; } struct epeg_destination_mgr *dst_mgr = NULL; int ok = 0; if ((im->out.w < 1) || (im->out.h < 1)) { return 1; } if (im->out.f) { return 1; } if (im->out.file) { im->out.f = fopen(im->out.file, "wb"); if (!im->out.f) { im->error = 1; return 1; } } else { im->out.f = NULL; } im->out.jinfo.err = jpeg_std_error(&(im->jerr.pub)); im->jerr.pub.error_exit = _epeg_fatal_error_handler; #ifdef NOWARNINGS im->jerr.pub.emit_message = _emit_message; im->jerr.pub.output_message = _output_message; im->jerr.pub.format_message = _format_message; #endif if (setjmp(im->jerr.setjmp_buffer)) { im->jerr.pub.format_message((j_common_ptr)&(im->out.jinfo), im->error_msg); ok = 1; im->error = 1; goto done; } jpeg_create_compress(&(im->out.jinfo)); if (im->out.f) { jpeg_stdio_dest(&(im->out.jinfo), im->out.f); } else { *(im->out.mem.data) = NULL; *(im->out.mem.size) = 0; /* Setup RAM destination manager */ dst_mgr = calloc(1, sizeof(struct epeg_destination_mgr)); if (!dst_mgr) { return 1; } dst_mgr->dst_mgr.init_destination = _jpeg_init_destination; dst_mgr->dst_mgr.empty_output_buffer = _jpeg_empty_output_buffer; dst_mgr->dst_mgr.term_destination = _jpeg_term_destination; dst_mgr->im = im; dst_mgr->buf = malloc(65536); if (!dst_mgr->buf) { ok = 1; im->error = 1; goto done; } im->out.jinfo.dest = (struct jpeg_destination_mgr *)dst_mgr; } jcopy_markers_setup(&(im->in.jinfo), copyoption); jtransform_request_workspace(&(im->in.jinfo), &transformoption); src_coef_arrays = jpeg_read_coefficients(&(im->in.jinfo)); jpeg_copy_critical_parameters(&(im->in.jinfo), &(im->out.jinfo)); im->out.jinfo.write_JFIF_header = FALSE; // for Exif format dst_coef_arrays = jtransform_adjust_parameters(&(im->in.jinfo), &(im->out.jinfo), src_coef_arrays, &transformoption); jpeg_write_coefficients(&(im->out.jinfo), dst_coef_arrays); jcopy_markers_execute(&(im->in.jinfo), &(im->out.jinfo), copyoption); jtransform_execute_transformation(&(im->in.jinfo), &(im->out.jinfo), src_coef_arrays, &transformoption); jpeg_finish_compress(&(im->out.jinfo)); done: if ((im->in.f) || (im->in.mem.data != NULL)) { jpeg_destroy_decompress(&(im->in.jinfo)); } if ((im->in.f) && (im->in.file)) { fclose(im->in.f); } if (dst_mgr) { if (dst_mgr->buf) { free(dst_mgr->buf); } free(dst_mgr); im->out.jinfo.dest = NULL; } jpeg_destroy_compress(&(im->out.jinfo)); if ((im->out.f) && (im->out.file)) { fclose(im->out.f); } im->in.f = NULL; im->out.f = NULL; return ok; }
int main (int argc, char **argv) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr, jdsterr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; int file_index; FILE * input_file; FILE * output_file; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "jpegtran"; /* in case C library doesn't provide it */ /* 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); /* Now safe to enable signal catcher. * Note: we assume only the decompression object will have virtual arrays. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &srcinfo); #endif /* Scan command line to find file names. * It is convenient to use just one switch-parsing routine, but the switch * values read here are mostly ignored; we will rescan the switches after * opening the input file. Also note that most of the switches affect the * destination JPEG object, so we parse into that and then copy over what * needs to affects the source too. */ file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); jsrcerr.trace_level = jdsterr.trace_level; srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; #ifdef TWO_FILE_COMMANDLINE /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ input_file = read_stdin(); } /* Open the output file. */ if (outfilename != NULL) { if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, outfilename); exit(EXIT_FAILURE); } } else { /* default output file is stdout */ output_file = write_stdout(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &dstinfo, &progress); #endif /* Specify data source for decompression */ jpeg_stdio_src(&srcinfo, input_file); /* Enable saving of extra markers that we want to copy */ jcopy_markers_setup(&srcinfo, copyoption); /* Read file header */ (void) jpeg_read_header(&srcinfo, TRUE); /* Any space needed by a transform option must be requested before * jpeg_read_coefficients so that memory allocation will be done right. */ #if TRANSFORMS_SUPPORTED jtransform_request_workspace(&srcinfo, &transformoption); #endif /* Read source file as DCT coefficients */ src_coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); /* Adjust destination parameters if required by transform options; * also find out which set of coefficient arrays will hold the output. */ #if TRANSFORMS_SUPPORTED dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #else dst_coef_arrays = src_coef_arrays; #endif /* Adjust default compression parameters by re-parsing the options */ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); /* Specify data destination for compression */ jpeg_stdio_dest(&dstinfo, output_file); /* 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, copyoption); /* Execute image transformation, if any */ #if TRANSFORMS_SUPPORTED jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #endif /* Finish compression and release memory */ jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); if (output_file != stdout) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &dstinfo); #endif /* All done. */ exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
static gboolean jpegtran_internal (struct jpeg_decompress_struct *srcinfo, struct jpeg_compress_struct *dstinfo, GthTransform transformation, JCOPY_OPTION option, JpegMcuAction mcu_action, GError **error) { jpeg_transform_info transformoption; jvirt_barray_ptr *src_coef_arrays; jvirt_barray_ptr *dst_coef_arrays; JXFORM_CODE transform; switch (transformation) { case GTH_TRANSFORM_NONE: transform = JXFORM_NONE; break; case GTH_TRANSFORM_FLIP_H: transform = JXFORM_FLIP_H; break; case GTH_TRANSFORM_FLIP_V: transform = JXFORM_FLIP_V; break; case GTH_TRANSFORM_TRANSPOSE: transform = JXFORM_TRANSPOSE; break; case GTH_TRANSFORM_TRANSVERSE: transform = JXFORM_TRANSVERSE; break; case GTH_TRANSFORM_ROTATE_90: transform = JXFORM_ROT_90; break; case GTH_TRANSFORM_ROTATE_180: transform = JXFORM_ROT_180; break; case GTH_TRANSFORM_ROTATE_270: transform = JXFORM_ROT_270; break; } transformoption.transform = transform; transformoption.trim = (mcu_action == JPEG_MCU_ACTION_TRIM); transformoption.force_grayscale = FALSE; /* Enable saving of extra markers that we want to copy */ jcopy_markers_setup (srcinfo, option); /* Read file header */ (void) jpeg_read_header (srcinfo, TRUE); /* Check JPEG Minimal Coding Unit (mcu) */ if ((mcu_action == JPEG_MCU_ACTION_ABORT) && ! jtransform_perfect_transform (srcinfo->image_width, srcinfo->image_height, srcinfo->max_h_samp_factor * DCTSIZE, srcinfo->max_v_samp_factor * DCTSIZE, transform)) { if (error != NULL) g_set_error (error, JPEG_ERROR, JPEG_ERROR_MCU, "MCU Error"); return FALSE; } /* Any space needed by a transform option must be requested before * jpeg_read_coefficients so that memory allocation will be done right. */ jtransform_request_workspace (srcinfo, &transformoption); /* Read source file as DCT coefficients */ src_coef_arrays = jpeg_read_coefficients (srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters (srcinfo, dstinfo); /* Do not output a JFIF marker for EXIF thumbnails. * This is not the optimal way to detect the difference * between a thumbnail and a normal image, but it works * well for gThumb. */ if (option == JCOPYOPT_NONE) dstinfo->write_JFIF_header = FALSE; #if JPEG_LIB_VERSION < 80 /* Adjust the markers to create a standard EXIF file if an EXIF marker * is present in the input. By default, libjpeg creates a JFIF file, * which is incompatible with the EXIF standard. */ jcopy_markers_exif (srcinfo, dstinfo, option); #endif /* Adjust destination parameters if required by transform options; * also find out which set of coefficient arrays will hold the output. */ dst_coef_arrays = jtransform_adjust_parameters (srcinfo, dstinfo, src_coef_arrays, &transformoption); /* 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, option); /* Execute image transformation, if any */ jtransform_execute_transformation (srcinfo, dstinfo, src_coef_arrays, &transformoption); /* Finish compression */ jpeg_finish_compress (dstinfo); jpeg_finish_decompress (srcinfo); return TRUE; }
int main (int argc, char **argv) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr, jdsterr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; int file_index; /* We assume all-in-memory processing and can therefore use only a * single file pointer for sequential input and output operation. */ FILE * fp; unsigned char *inbuffer = NULL; unsigned long insize = 0; unsigned char *outbuffer = NULL; unsigned long outsize = 0; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "jpegtran"; /* in case C library doesn't provide it */ /* 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); dstinfo.use_moz_defaults = TRUE; /* Scan command line to find file names. * It is convenient to use just one switch-parsing routine, but the switch * values read here are mostly ignored; we will rescan the switches after * opening the input file. Also note that most of the switches affect the * destination JPEG object, so we parse into that and then copy over what * needs to affects the source too. */ file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); jsrcerr.trace_level = jdsterr.trace_level; srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; #ifdef TWO_FILE_COMMANDLINE /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ fp = read_stdin(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &dstinfo, &progress); #endif /* Specify data source for decompression */ memsrc = dstinfo.use_moz_defaults; /* needed to revert to original */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) if (memsrc) { size_t nbytes; do { inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE); if (inbuffer == NULL) { fprintf(stderr, "%s: memory allocation failure\n", progname); exit(EXIT_FAILURE); } nbytes = JFREAD(fp, &inbuffer[insize], INPUT_BUF_SIZE); if (nbytes < INPUT_BUF_SIZE && ferror(fp)) { if (file_index < argc) fprintf(stderr, "%s: can't read from %s\n", progname, argv[file_index]); else fprintf(stderr, "%s: can't read from stdin\n", progname); } insize += (unsigned long)nbytes; } while (nbytes == INPUT_BUF_SIZE); jpeg_mem_src(&srcinfo, inbuffer, insize); } else #endif jpeg_stdio_src(&srcinfo, fp); /* Enable saving of extra markers that we want to copy */ jcopy_markers_setup(&srcinfo, copyoption); /* Read file header */ (void) jpeg_read_header(&srcinfo, TRUE); /* Any space needed by a transform option must be requested before * jpeg_read_coefficients so that memory allocation will be done right. */ #if TRANSFORMS_SUPPORTED /* Fail right away if -perfect is given and transformation is not perfect. */ if (!jtransform_request_workspace(&srcinfo, &transformoption)) { fprintf(stderr, "%s: transformation is not perfect\n", progname); exit(EXIT_FAILURE); } #endif /* Read source file as DCT coefficients */ src_coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); /* Adjust destination parameters if required by transform options; * also find out which set of coefficient arrays will hold the output. */ #if TRANSFORMS_SUPPORTED dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #else dst_coef_arrays = src_coef_arrays; #endif /* Close input file, if we opened it. * Note: we assume that jpeg_read_coefficients consumed all input * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will * only consume more while (! cinfo->inputctl->eoi_reached). * We cannot call jpeg_finish_decompress here since we still need the * virtual arrays allocated from the source object for processing. */ if (fp != stdin) fclose(fp); /* Open the output file. */ if (outfilename != NULL) { if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename); exit(EXIT_FAILURE); } } else { /* default output file is stdout */ fp = write_stdout(); } /* Adjust default compression parameters by re-parsing the options */ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); /* Specify data destination for compression */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) if (dstinfo.use_moz_defaults) jpeg_mem_dest(&dstinfo, &outbuffer, &outsize); else #endif 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, copyoption); /* Execute image transformation, if any */ #if TRANSFORMS_SUPPORTED jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #endif /* Finish compression and release memory */ jpeg_finish_compress(&dstinfo); if (dstinfo.use_moz_defaults) { size_t nbytes; unsigned char *buffer = outbuffer; unsigned long size = outsize; if (insize < size) { size = insize; buffer = inbuffer; } nbytes = JFWRITE(fp, buffer, size); if (nbytes < size && ferror(fp)) { if (file_index < argc) fprintf(stderr, "%s: can't write to %s\n", progname, argv[file_index]); else fprintf(stderr, "%s: can't write to stdout\n", progname); } } jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); /* Close output file, if we opened it */ if (fp != stdout) fclose(fp); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &dstinfo); #endif /* All done. */ exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
static gboolean _save_jpeg_as_jpeg (EomImage *image, const char *file, EomImageSaveInfo *source, EomImageSaveInfo *target, GError **error) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct error_handler_data jsrcerr, jdsterr; jpeg_transform_info transformoption; jvirt_barray_ptr *src_coef_arrays; jvirt_barray_ptr *dst_coef_arrays; FILE *output_file; FILE *input_file; EomImagePrivate *priv; gchar *infile_uri; g_return_val_if_fail (EOM_IS_IMAGE (image), FALSE); g_return_val_if_fail (EOM_IMAGE (image)->priv->file != NULL, FALSE); priv = image->priv; init_transform_info (image, &transformoption); /* Initialize the JPEG decompression object with default error * handling. */ jsrcerr.filename = g_file_get_path (priv->file); srcinfo.err = jpeg_std_error (&(jsrcerr.pub)); jsrcerr.pub.error_exit = fatal_error_handler; jsrcerr.pub.output_message = output_message_handler; jsrcerr.error = error; jpeg_create_decompress (&srcinfo); /* Initialize the JPEG compression object with default error * handling. */ jdsterr.filename = (char *) file; dstinfo.err = jpeg_std_error (&(jdsterr.pub)); jdsterr.pub.error_exit = fatal_error_handler; jdsterr.pub.output_message = output_message_handler; jdsterr.error = error; jpeg_create_compress (&dstinfo); dstinfo.err->trace_level = 0; dstinfo.arith_code = FALSE; dstinfo.optimize_coding = FALSE; jsrcerr.pub.trace_level = jdsterr.pub.trace_level; srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; /* Open the output file. */ /* FIXME: Make this a GIO aware input manager */ infile_uri = g_file_get_path (priv->file); input_file = fopen (infile_uri, "rb"); if (input_file == NULL) { g_warning ("Input file not openable: %s\n", infile_uri); g_free (jsrcerr.filename); g_free (infile_uri); return FALSE; } g_free (infile_uri); output_file = fopen (file, "wb"); if (output_file == NULL) { g_warning ("Output file not openable: %s\n", file); fclose (input_file); g_free (jsrcerr.filename); return FALSE; } if (sigsetjmp (jsrcerr.setjmp_buffer, 1)) { fclose (output_file); fclose (input_file); jpeg_destroy_compress (&dstinfo); jpeg_destroy_decompress (&srcinfo); g_free (jsrcerr.filename); return FALSE; } if (sigsetjmp (jdsterr.setjmp_buffer, 1)) { fclose (output_file); fclose (input_file); jpeg_destroy_compress (&dstinfo); jpeg_destroy_decompress (&srcinfo); g_free (jsrcerr.filename); return FALSE; } /* Specify data source for decompression */ jpeg_stdio_src (&srcinfo, input_file); /* Enable saving of extra markers that we want to copy */ jcopy_markers_setup (&srcinfo, JCOPYOPT_DEFAULT); /* Read file header */ (void) jpeg_read_header (&srcinfo, TRUE); /* Any space needed by a transform option must be requested before * jpeg_read_coefficients so that memory allocation will be done right. */ jtransform_request_workspace (&srcinfo, &transformoption); /* Read source file as DCT coefficients */ src_coef_arrays = jpeg_read_coefficients (&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters (&srcinfo, &dstinfo); /* Adjust destination parameters if required by transform options; * also find out which set of coefficient arrays will hold the output. */ dst_coef_arrays = jtransform_adjust_parameters (&srcinfo, &dstinfo, src_coef_arrays, &transformoption); /* Specify data destination for compression */ jpeg_stdio_dest (&dstinfo, output_file); /* Start compressor (note no image data is actually written here) */ jpeg_write_coefficients (&dstinfo, dst_coef_arrays); /* handle EXIF/IPTC data explicitly */ #if HAVE_EXIF /* exif_chunk and exif are mutally exclusvie, this is what we assure here */ g_assert (priv->exif_chunk == NULL); if (priv->exif != NULL) { unsigned char *exif_buf; unsigned int exif_buf_len; exif_data_save_data (priv->exif, &exif_buf, &exif_buf_len); jpeg_write_marker (&dstinfo, JPEG_APP0+1, exif_buf, exif_buf_len); g_free (exif_buf); } #else if (priv->exif_chunk != NULL) { jpeg_write_marker (&dstinfo, JPEG_APP0+1, priv->exif_chunk, priv->exif_chunk_len); } #endif /* FIXME: Consider IPTC data too */ /* Copy to the output file any extra markers that we want to * preserve */ jcopy_markers_execute (&srcinfo, &dstinfo, JCOPYOPT_DEFAULT); /* Execute image transformation, if any */ jtransform_execute_transformation (&srcinfo, &dstinfo, src_coef_arrays, &transformoption); /* Finish compression and release memory */ jpeg_finish_compress (&dstinfo); jpeg_destroy_compress (&dstinfo); (void) jpeg_finish_decompress (&srcinfo); jpeg_destroy_decompress (&srcinfo); g_free (jsrcerr.filename); /* Close files */ fclose (input_file); fclose (output_file); return TRUE; }
int main (int argc, char **argv) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr, jdsterr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; int file_index; FILE * input_file; FILE * output_file; #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "jpegtran"; srcinfo.err = jpeg_std_error(&jsrcerr); jpeg_create_decompress(&srcinfo); dstinfo.err = jpeg_std_error(&jdsterr); jpeg_create_compress(&dstinfo); #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &srcinfo); #endif file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); jsrcerr.trace_level = jdsterr.trace_level; srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; #ifdef TWO_FILE_COMMANDLINE if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { input_file = read_stdin(); } if (outfilename != NULL) { if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, outfilename); exit(EXIT_FAILURE); } } else { output_file = write_stdout(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &dstinfo, &progress); #endif jpeg_stdio_src(&srcinfo, input_file); jcopy_markers_setup(&srcinfo, copyoption); (void) jpeg_read_header(&srcinfo, TRUE); #if TRANSFORMS_SUPPORTED jtransform_request_workspace(&srcinfo, &transformoption); #endif src_coef_arrays = jpeg_read_coefficients(&srcinfo); jpeg_copy_critical_parameters(&srcinfo, &dstinfo); #if TRANSFORMS_SUPPORTED dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #else dst_coef_arrays = src_coef_arrays; #endif file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); jpeg_stdio_dest(&dstinfo, output_file); /* Start compressor (note no image data is actually written here) */ jpeg_write_coefficients(&dstinfo, dst_coef_arrays); jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); #if TRANSFORMS_SUPPORTED jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #endif jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); if (input_file != stdin) fclose(input_file); if (output_file != stdout) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &dstinfo); #endif exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); return 0; }
void JpegContent::applyPendingTransformation() { if (d->mRawData.size() == 0) { qCritical() << "No data loaded\n"; return; } // The following code is inspired by jpegtran.c from the libjpeg // Init JPEG structs struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; // Initialize the JPEG decompression object JPEGErrorManager srcErrorManager; srcinfo.err = &srcErrorManager; jpeg_create_decompress(&srcinfo); if (setjmp(srcErrorManager.jmp_buffer)) { qCritical() << "libjpeg error in src\n"; return; } // Initialize the JPEG compression object JPEGErrorManager dstErrorManager; dstinfo.err = &dstErrorManager; jpeg_create_compress(&dstinfo); if (setjmp(dstErrorManager.jmp_buffer)) { qCritical() << "libjpeg error in dst\n"; return; } // Specify data source for decompression QBuffer buffer(&d->mRawData); buffer.open(QIODevice::ReadOnly); IODeviceJpegSourceManager::setup(&srcinfo, &buffer); // Enable saving of extra markers that we want to copy jcopy_markers_setup(&srcinfo, JCOPYOPT_ALL); (void) jpeg_read_header(&srcinfo, true); // Init transformation jpeg_transform_info transformoption; memset(&transformoption, 0, sizeof(jpeg_transform_info)); transformoption.transform = findJxform(d->mTransformMatrix); jtransform_request_workspace(&srcinfo, &transformoption); /* Read source file as DCT coefficients */ src_coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); /* Adjust destination parameters if required by transform options; * also find out which set of coefficient arrays will hold the output. */ dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); /* Specify data destination for compression */ QByteArray output; output.resize(d->mRawData.size()); d->setupInmemDestination(&dstinfo, &output); /* 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); /* Execute image transformation, if any */ jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); /* Finish compression and release memory */ jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); // Set rawData to our new JPEG d->mRawData = output; }
bool ImageGrayScale::image2GrayScaleJPEG(const QString& src, const QString& dest, QString& err, bool updateFileTimeStamp) { JCOPY_OPTION copyoption = JCOPYOPT_ALL; jpeg_transform_info transformoption; transformoption.transform = JXFORM_NONE; transformoption.force_grayscale = true; transformoption.trim = false; struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr; struct jpeg_error_mgr jdsterr; 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 *input_file; FILE *output_file; input_file = fopen(QFile::encodeName(src), "rb"); if (!input_file) { kError( 51000 ) << "Image2GrayScale: Error in opening input file" << endl; err = i18n("Error in opening input file"); return false; } output_file = fopen(QFile::encodeName(dest), "wb"); if (!output_file) { fclose(input_file); kError( 51000 ) << "Image2GrayScale: Error in opening output file" << endl; err = i18n("Error in opening output file"); return false; } // Open jpeglib stream jpeg_stdio_src(&srcinfo, input_file); // Setup decompression object to save desired markers in memory jcopy_markers_setup(&srcinfo, copyoption); // Decompression startup: read start of JPEG datastream to see what's there (void) jpeg_read_header(&srcinfo, true); // Request any required workspace jtransform_request_workspace(&srcinfo, &transformoption); // Read source file as DCT coefficients src_coef_arrays = jpeg_read_coefficients(&srcinfo); // Initialize destination compression parameters from source values jpeg_copy_critical_parameters(&srcinfo, &dstinfo); // Adjust output image parameters dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); // Specify data destination for compression jpeg_stdio_dest(&dstinfo, output_file); // Do not write a JFIF header if previously the image did not contain it dstinfo.write_JFIF_header = false; // 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 (merging from src file with Qt tmp file) jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); // Execute the actual jpeg transformations jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); // Finish compression and release memory jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); fclose(input_file); fclose(output_file); // And set finaly update the metadata to target file. KExiv2Iface::KExiv2 exiv2Iface; #if KEXIV2_VERSION >= 0x000600 exiv2Iface.setUpdateFileTimeStamp(updateFileTimeStamp); #endif exiv2Iface.load(dest); QImage img(dest); QImage exifThumbnail = img.scaled(160, 120, Qt::KeepAspectRatio); exiv2Iface.setImageProgramId(QString("Kipi-plugins"), QString(kipiplugins_version)); exiv2Iface.setExifThumbnail(exifThumbnail); exiv2Iface.save(dest); return true; }
static BOOL LosslessTransform(const FilenameIO *filenameIO, FREE_IMAGE_JPEG_OPERATION operation, const char *crop, BOOL perfect) { // We assume all-in-memory processing and can therefore use only a // single file pointer for sequential input and output operation FILE *fp = NULL; // check for UNICODE filenames - previous structure filling was done before bool bUseUnicode = filenameIO && filenameIO->wsrc_file && filenameIO->wdst_file; // Set up the jpeglib structures jpeg_decompress_struct srcinfo; jpeg_compress_struct dstinfo; jpeg_error_mgr jsrcerr, jdsterr; jvirt_barray_ptr *src_coef_arrays = NULL; jvirt_barray_ptr *dst_coef_arrays = NULL; // Support for copying optional markers from source to destination file JCOPY_OPTION copyoption; // Image transformation options jpeg_transform_info transfoptions; // Initialize structures memset(&srcinfo, 0, sizeof(srcinfo)); memset(&jsrcerr, 0, sizeof(jsrcerr)); memset(&jdsterr, 0, sizeof(jdsterr)); memset(&dstinfo, 0, sizeof(dstinfo)); memset(&transfoptions, 0, sizeof(transfoptions)); // Copy all extra markers from source file copyoption = JCOPYOPT_ALL; // Set up default JPEG parameters transfoptions.force_grayscale = FALSE; transfoptions.crop = FALSE; // Select the transform option switch(operation) { case FIJPEG_OP_FLIP_H: // horizontal flip transfoptions.transform = JXFORM_FLIP_H; break; case FIJPEG_OP_FLIP_V: // vertical flip transfoptions.transform = JXFORM_FLIP_V; break; case FIJPEG_OP_TRANSPOSE: // transpose across UL-to-LR axis transfoptions.transform = JXFORM_TRANSPOSE; break; case FIJPEG_OP_TRANSVERSE: // transpose across UR-to-LL axis transfoptions.transform = JXFORM_TRANSVERSE; break; case FIJPEG_OP_ROTATE_90: // 90-degree clockwise rotation transfoptions.transform = JXFORM_ROT_90; break; case FIJPEG_OP_ROTATE_180: // 180-degree rotation transfoptions.transform = JXFORM_ROT_180; break; case FIJPEG_OP_ROTATE_270: // 270-degree clockwise (or 90 ccw) transfoptions.transform = JXFORM_ROT_270; break; default: case FIJPEG_OP_NONE: // no transformation transfoptions.transform = JXFORM_NONE; break; } // (perfect == TRUE) ==> fail if there is non-transformable edge blocks transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE; // Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle. transfoptions.trim = TRUE; try { // Initialize the JPEG decompression object with default error handling srcinfo.err = jpeg_std_error(&jsrcerr); srcinfo.err->error_exit = ls_jpeg_error_exit; srcinfo.err->output_message = ls_jpeg_output_message; jpeg_create_decompress(&srcinfo); // Initialize the JPEG compression object with default error handling dstinfo.err = jpeg_std_error(&jdsterr); dstinfo.err->error_exit = ls_jpeg_error_exit; dstinfo.err->output_message = ls_jpeg_output_message; jpeg_create_compress(&dstinfo); // crop option if(crop != NULL) { if(!jtransform_parse_crop_spec(&transfoptions, crop)) { FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop); throw(1); } } // Open the input file if(bUseUnicode) { #ifdef _WIN32 if((fp = _wfopen(filenameIO->wsrc_file, L"rb")) == NULL) { FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open input file for reading"); } #else fp = NULL; #endif // _WIN32 } else { if((fp = fopen(filenameIO->src_file, "rb")) == NULL) { FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for reading", filenameIO->src_file); } } if(fp == NULL) { jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return FALSE; } // Specify data source for decompression jpeg_stdio_src(&srcinfo, fp); // Enable saving of extra markers that we want to copy jcopy_markers_setup(&srcinfo, copyoption); // Read the file header jpeg_read_header(&srcinfo, TRUE); // Any space needed by a transform option must be requested before // jpeg_read_coefficients so that memory allocation will be done right // Prepare transformation workspace // Fails right away if perfect flag is TRUE and transformation is not perfect if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) { FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect"); throw(1); } // Read source file as DCT coefficients src_coef_arrays = jpeg_read_coefficients(&srcinfo); // Initialize destination compression parameters from source values jpeg_copy_critical_parameters(&srcinfo, &dstinfo); // Adjust destination parameters if required by transform options; // also find out which set of coefficient arrays will hold the output dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); // Close the input file. // Note: we assume that jpeg_read_coefficients consumed all input // until JPEG_REACHED_EOI, and that jpeg_finish_decompress will // only consume more while (! cinfo->inputctl->eoi_reached). // We cannot call jpeg_finish_decompress here since we still need the // virtual arrays allocated from the source object for processing. fclose(fp); // Open the output file if(bUseUnicode) { #ifdef _WIN32 if((fp = _wfopen(filenameIO->wdst_file, L"wb")) == NULL) { FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open output file for writing"); } #else fp = NULL; #endif // _WIN32 } else { if((fp = fopen(filenameIO->dst_file, "wb")) == NULL) { FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open %s for writing", filenameIO->dst_file); } } if(fp == NULL) { throw(1); } // 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, copyoption); // Execute image transformation, if any jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); // Finish compression and release memory jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); // Close output file and return fclose(fp); } catch(...) { if(fp) fclose(fp); jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return FALSE; } return TRUE; }