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 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; }
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: default: 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; #if JPEG_LIB_VERSION >= 80 transformoption.perfect = (mcu_action == JPEG_MCU_ACTION_ABORT); transformoption.crop = FALSE; transformoption.crop_width_set = FALSE; transformoption.crop_height_set = FALSE; transformoption.crop_xoffset_set = FALSE; transformoption.crop_yoffset_set = FALSE; #ifdef LIBJPEG_TURBO_VERSION transformoption.slow_hflip = FALSE; #endif #endif /* 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; /* 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; }