static void write_DCT(const char *outputname, JBLOCKARRAY *coef_buffers, j_compress_ptr outputinfo) { { printf("writing to new picture\n"); j_common_ptr common = (j_common_ptr) outputinfo; /* Output the new DCT coeffs to a JPEG file */ for (int compnum=0; compnum<num_components; compnum++) { for (JDIMENSION rownum=0; rownum<height_in_blocks[compnum]; rownum++) { row_ptrs[compnum] = outputinfo->mem->access_virt_barray(common, coef_arrays[compnum], rownum, (JDIMENSION) 1, TRUE); memcpy(row_ptrs[compnum][0][0], coef_buffers[compnum][rownum][0], block_row_size[compnum]); } } /* Write to the output file */ jpeg_write_coefficients(outputinfo, coef_arrays); /* Finish compression and release memory */ jpeg_finish_compress(outputinfo); jpeg_destroy_compress(outputinfo); /* All done. */ printf("New DCT coefficients successfully written to %s\n\n", outputname); exit(jerr.num_warnings ? EXIT_FAILURE : EXIT_SUCCESS); } }
/** * 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; }
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 inputinfo; struct jpeg_compress_struct outputinfo; struct jpeg_error_mgr jerr; jvirt_barray_ptr *coef_arrays; JDIMENSION i, compnum, rownum, blocknum; JBLOCKARRAY coef_buffers[MAX_COMPONENTS]; JBLOCKARRAY row_ptrs[MAX_COMPONENTS]; FILE * input_file; FILE * output_file; /* Handle arguments */ if (argc != 3) usage(); char *inputname; inputname = argv[1]; char *outputname; outputname = argv[2]; /* Open the input and output files */ if ((input_file = fopen(inputname, READ_BINARY)) == NULL) { fprintf(stderr, "Can't open %s\n", inputname); exit(EXIT_FAILURE); } if ((output_file = fopen(outputname, WRITE_BINARY)) == NULL) { fprintf(stderr, "Can't open %s\n", outputname); exit(EXIT_FAILURE); } /* Initialize the JPEG compression and decompression objects with default error handling. */ inputinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&inputinfo); outputinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&outputinfo); /* Specify data source for decompression and recompression */ jpeg_stdio_src(&inputinfo, input_file); jpeg_stdio_dest(&outputinfo, output_file); /* Read file header */ (void) jpeg_read_header(&inputinfo, TRUE); /* Allocate memory for reading out DCT coeffs */ for (compnum=0; compnum<inputinfo.num_components; compnum++) coef_buffers[compnum] = ((&inputinfo)->mem->alloc_barray) ((j_common_ptr) &inputinfo, JPOOL_IMAGE, inputinfo.comp_info[compnum].width_in_blocks, inputinfo.comp_info[compnum].height_in_blocks); /* Read input file as DCT coeffs */ coef_arrays = jpeg_read_coefficients(&inputinfo); /* Copy compression parameters from the input file to the output file */ jpeg_copy_critical_parameters(&inputinfo, &outputinfo); /* Copy DCT coeffs to a new array */ int num_components = inputinfo.num_components; size_t block_row_size[num_components]; int width_in_blocks[num_components]; int height_in_blocks[num_components]; for (compnum=0; compnum<num_components; compnum++) { height_in_blocks[compnum] = inputinfo.comp_info[compnum].height_in_blocks; width_in_blocks[compnum] = inputinfo.comp_info[compnum].width_in_blocks; block_row_size[compnum] = (size_t) SIZEOF(JCOEF)*DCTSIZE2*width_in_blocks[compnum]; for (rownum=0; rownum<height_in_blocks[compnum]; rownum++) { row_ptrs[compnum] = ((&inputinfo)->mem->access_virt_barray) ((j_common_ptr) &inputinfo, coef_arrays[compnum], rownum, (JDIMENSION) 1, FALSE); for (blocknum=0; blocknum<width_in_blocks[compnum]; blocknum++) { for (i=0; i<DCTSIZE2; i++) { coef_buffers[compnum][rownum][blocknum][i] = row_ptrs[compnum][0][blocknum][i]; } } } } /* Print out or modify DCT coefficients */ for (compnum=0; compnum<num_components; compnum++) { for (rownum=0; rownum<height_in_blocks[compnum]; rownum++) { for (blocknum=0; blocknum<width_in_blocks[compnum]; blocknum++) { printf("\n\nComponent: %i, Row:%i, Column: %i\n", compnum, rownum, blocknum); for (i=0; i<DCTSIZE2; i++) { coef_buffers[compnum][rownum][blocknum][i] = - coef_buffers[compnum][rownum][blocknum][i]; printf("%i,", coef_buffers[compnum][rownum][blocknum][i]); } } } } printf("\n\n"); /* Output the new DCT coeffs to a JPEG file */ for (compnum=0; compnum<num_components; compnum++) { for (rownum=0; rownum<height_in_blocks[compnum]; rownum++) { row_ptrs[compnum] = ((&outputinfo)->mem->access_virt_barray) ((j_common_ptr) &outputinfo, coef_arrays[compnum], rownum, (JDIMENSION) 1, TRUE); memcpy(row_ptrs[compnum][0][0], coef_buffers[compnum][rownum][0], block_row_size[compnum]); } } /* Write to the output file */ jpeg_write_coefficients(&outputinfo, coef_arrays); /* Finish compression and release memory */ jpeg_finish_compress(&outputinfo); jpeg_destroy_compress(&outputinfo); jpeg_finish_decompress(&inputinfo); jpeg_destroy_decompress(&inputinfo); /* Close files */ fclose(input_file); fclose(output_file); /* All done. */ printf("New DCT coefficients successfully written to %s\n\n", outputname); exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
size_t Jpeg::Leanify(size_t size_leanified /*= 0*/) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr, jdsterr; srcinfo.err = jpeg_std_error(&jsrcerr); jsrcerr.error_exit = mozjpeg_error_handler; if (setjmp(setjmp_buffer)) { jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return Format::Leanify(size_leanified); } jpeg_create_decompress(&srcinfo); dstinfo.err = jpeg_std_error(&jdsterr); jdsterr.error_exit = mozjpeg_error_handler; jpeg_create_compress(&dstinfo); if (is_verbose) { dstinfo.err->trace_level++; } if (is_fast) { jpeg_c_set_int_param(&dstinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST); } /* Specify data source for decompression */ jpeg_mem_src(&srcinfo, fp_, size_); // Always save exif to show warning if orientation might change. jpeg_save_markers(&srcinfo, JPEG_APP0 + 1, 0xFFFF); if (keep_icc_profile_ || keep_all_metadata_) { jpeg_save_markers(&srcinfo, JPEG_APP0 + 2, 0xFFFF); } if (keep_all_metadata_) { // Save the rest APPn markers. for (int i = 3; i < 16; i++) jpeg_save_markers(&srcinfo, JPEG_APP0 + i, 0xFFFF); // Save comments. jpeg_save_markers(&srcinfo, JPEG_COM, 0xFFFF); } (void)jpeg_read_header(&srcinfo, true); /* Read source file as DCT coefficients */ auto coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); // use arithmetic coding if input file is arithmetic coded if (srcinfo.arith_code) { dstinfo.arith_code = true; dstinfo.optimize_coding = false; } else { dstinfo.optimize_coding = true; } uint8_t* outbuffer = nullptr; unsigned long outsize = 0; /* Specify data destination for compression */ jpeg_mem_dest(&dstinfo, &outbuffer, &outsize); /* Start compressor (note no image data is actually written here) */ jpeg_write_coefficients(&dstinfo, coef_arrays); for (auto marker = srcinfo.marker_list; marker; marker = marker->next) { if (marker->marker == JPEG_APP0 + 1 && !keep_exif_ && !keep_all_metadata_) { // Tag number: 0x0112, data format: unsigned short(3), number of components: 1 const uint8_t kExifOrientation[] = { 0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00 }; const uint8_t kExifOrientationMotorola[] = { 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01 }; uint8_t* start = marker->data; uint8_t* end = start + marker->data_length; if (std::search(start, end, kExifOrientation, std::end(kExifOrientation)) != end || std::search(start, end, kExifOrientationMotorola, std::end(kExifOrientationMotorola)) != end) { std::cout << "Warning: The Exif being removed contains orientation data, result image might have wrong " "orientation, use --keep-exif to keep Exif." << std::endl; } continue; } jpeg_write_marker(&dstinfo, marker->marker, marker->data, marker->data_length); } /* Finish compression and release memory */ jpeg_finish_compress(&dstinfo); (void)jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); fp_ -= size_leanified; // use mozjpeg result if it's smaller than original if (outsize < size_) { memcpy(fp_, outbuffer, outsize); size_ = outsize; } else { memmove(fp_, fp_ + size_leanified, size_); } jpeg_destroy_compress(&dstinfo); return size_; }
void Jpegoptim(sLONG_PTR *pResult, PackagePtr pParams) { C_LONGINT Param2_Options; C_LONGINT Param3_Quality; int quality = -1; int save_exif = 0; int save_iptc = 0; int save_com = 0; int save_icc = 0; int save_xmp = 0; struct jpeg_decompress_struct dinfo; struct jpeg_compress_struct cinfo; struct my_error_mgr jcerr, jderr; Param2_Options.fromParamAtIndex(pParams, 2); unsigned int o = Param2_Options.getIntValue(); if(o) { save_exif = !(o & JPEG_STRIP_EXIF); save_iptc = !(o & JPEG_STRIP_IPTC); save_com = !(o & JPEG_STRIP_COM ); save_icc = !(o & JPEG_STRIP_ICC ); save_xmp = !(o & JPEG_STRIP_XMP ); } Param3_Quality.fromParamAtIndex(pParams, 3); unsigned int q = Param3_Quality.getIntValue(); if ((q >= 1) && (q <= 101)) { quality = (q-1); } jvirt_barray_ptr *coef_arrays = NULL; JSAMPARRAY buf = NULL; /* get jpeg data */ std::vector<unsigned char>pictureData; std::string type(".jpeg"); if(getPictureDataForType(pParams, 1, pictureData, type)) { /* initialize decompression object */ dinfo.err = jpeg_std_error(&jderr.pub); jpeg_create_decompress(&dinfo); jderr.pub.error_exit=my_error_exit; jderr.pub.output_message=my_output_message; jderr.jump_set = 0; /* initialize compression object */ cinfo.err = jpeg_std_error(&jcerr.pub); jpeg_create_compress(&cinfo); jcerr.pub.error_exit=my_error_exit; jcerr.pub.output_message=my_output_message; jcerr.jump_set = 0; if (setjmp(jderr.setjmp_buffer)) { /* error handler for decompress */ jpeg_abort_decompress(&dinfo); jderr.jump_set=0; } else { jderr.jump_set=1; } /* prepare to decompress */ jpeg_save_markers(&dinfo, JPEG_COM, 0xffff); for (int j=0;j<=15;j++) jpeg_save_markers(&dinfo, JPEG_APP0+j, 0xffff); jpeg_mem_src(&dinfo, &pictureData[0], pictureData.size()); jpeg_read_header(&dinfo, TRUE); jpeg_start_decompress(&dinfo); if(quality == -1) { coef_arrays = jpeg_read_coefficients(&dinfo); }else { buf = (JSAMPARRAY)malloc(sizeof(JSAMPROW)*dinfo.output_height); for (int j=0;j<dinfo.output_height;j++) { buf[j]=(JSAMPROW)malloc(sizeof(JSAMPLE)*dinfo.output_width*dinfo.out_color_components); } while (dinfo.output_scanline < dinfo.output_height) { PA_YieldAbsolute(); jpeg_read_scanlines(&dinfo,&buf[dinfo.output_scanline], dinfo.output_height-dinfo.output_scanline); } } if (setjmp(jcerr.setjmp_buffer)) { /* error handler for compress failures */ jpeg_abort_compress(&cinfo); jpeg_abort_decompress(&dinfo); jcerr.jump_set=0; } else { jcerr.jump_set=1; } size_t outbuffersize = pictureData.size() + 32768; unsigned char *outbuffer = (unsigned char *)malloc(outbuffersize); if(outbuffer) { jpeg_memory_dest(&cinfo, &outbuffer, &outbuffersize, 65536); if(quality == -1) { jpeg_copy_critical_parameters(&dinfo, &cinfo); jpeg_simple_progression(&cinfo); cinfo.optimize_coding = TRUE; }else { cinfo.in_color_space=dinfo.out_color_space; cinfo.input_components=dinfo.output_components; cinfo.image_width=dinfo.image_width; cinfo.image_height=dinfo.image_height; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,quality,TRUE); jpeg_simple_progression(&cinfo); cinfo.optimize_coding = TRUE; jpeg_start_compress(&cinfo,TRUE); } write_markers(&dinfo,&cinfo, save_exif, save_iptc, save_com, save_icc, save_xmp); if(quality == -1) { jpeg_write_coefficients(&cinfo, coef_arrays); }else { while (cinfo.next_scanline < cinfo.image_height) { PA_YieldAbsolute(); jpeg_write_scanlines(&cinfo,&buf[cinfo.next_scanline], dinfo.output_height); } } jpeg_finish_decompress(&dinfo); if(quality != -1) { jpeg_finish_compress(&cinfo); FREE_LINE_BUF(buf,dinfo.output_height); } jpeg_destroy_decompress(&dinfo); jpeg_destroy_compress(&cinfo); PA_Picture picture = PA_CreatePicture((void *)outbuffer, outbuffersize); *(PA_Picture*) pResult = picture; free(outbuffer); } } }
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 */ }
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; }
int jpeg_compress_8u_rgb_IPP (const uint8_t * src, int width, int height, int stride, uint8_t * dest, int * destsize, int quality) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; struct jpeg_destination_mgr jdest; int out_size = *destsize; cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); jdest.next_output_byte = dest; jdest.free_in_buffer = out_size; jdest.init_destination = init_destination; jdest.empty_output_buffer = empty_output_buffer; jdest.term_destination = term_destination; cinfo.dest = &jdest; cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jvirt_barray_ptr barptr[3]; for (c = 0; c < cinfo.num_components; c++) { jpeg_component_info * comp = cinfo.cur_comp_info[c]; barptr[c] = cinfo.mem->request_virt_barray (&cinfo, JPOOL_IMAGE, FALSE, cinfo->width_in_blocks, cinfo->height_in_blocks, cinfo->height_in_blocks); } jpeg_write_coefficients (&cinfo, barptr); for (c = 0; c < cinfo.num_components; c++) { jpeg_component_info * comp = cinfo.cur_comp_info[c]; uint8_t * plane; int pstride; int h_samp = max_h_samp / comp->h_samp_factor; int v_samp = max_v_samp / comp->v_samp_factor; if (h_samp == 2 && v_samp == 2) { if (!tmp_plane) tmp_plane = ippiMalloc_8u_C1 (comp->width_in_blocks*8, comp->height_in_blocks*8, &tmp_stride); plane = tmp_plane; pstride = tmp_stride; } else if (h_samp == 1 && v_samp == 1) { plane = full_plane[c]; pstride = full_stride; } for (i = 0; i < comp->height_in_blocks; i++) { JBLOCKARRAY bar = cinfo.mem->access_virt_barray ( (j_common_ptr) &cinfo, dct_planes[c], i, 1, TRUE); JBLOCKROW row = bar[0]; uint8_t * srow = plane + 8*i*pstride; for (j = 0; j < comp->width_in_blocks; j++) { JBLOCK * blk = row + j; ippiDCTQuantFwd8x8LS_JPEG_8u16s_C1R (srow + j*8, pstride, *blk, cinfo.quant_tbl_ptrs[comp->quant_tbl_no]->quantval); } } if (h_samp == 2 && v_samp == 2) { IppiSize srcroi = { 8*comp->width_in_blocks, 8*comp->height_in_blocks }; IppiSize dstroi = { 8*comp->width_in_blocks + 2, 8*comp->height_in_blocks + 2 }; ippiCopyReplicateBorder_8u_C1IR (tmp_plane + tmp_stride + 8, tmp_stride, srcroi, dstroi, 1, 1); dstroi.width = width; dstroi.height = height; ippiSampleUpH2V2_JPEG_8u_C1R (tmp_plane + tmp_stride + 8, tmp_stride, srcroi, full_plane[c], full_stride, dstroi); } } #if 0 jpeg_start_compress (&cinfo, TRUE); while (cinfo.next_scanline < height) { JSAMPROW row = (JSAMPROW)(src + cinfo.next_scanline * stride); jpeg_write_scanlines (&cinfo, &row, 1); } #endif jpeg_finish_compress (&cinfo); *destsize = out_size - jdest.free_in_buffer; jpeg_destroy_compress (&cinfo); return 0; }
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; }
// Take a buffer containing a jpeg and return an optimized jpeg int optimizeJPEG(unsigned char *inputbuffer, unsigned long inputsize, unsigned char **outputbuffer, unsigned long *outputsize, int quality) { jvirt_barray_ptr *coef_arrays = NULL; JSAMPARRAY buf = NULL; struct jpeg_decompress_struct dinfo; struct jpeg_compress_struct cinfo; int j; int all_normal = 1; int all_progressive = 0; if (quality > 100) quality = 100; /* initialize decompression object */ dinfo.err = jpeg_std_error(&jderr.pub); jpeg_create_decompress(&dinfo); jderr.pub.error_exit=my_error_exit; jderr.pub.output_message=my_output_message; /* initialize compression object */ cinfo.err = jpeg_std_error(&jcerr.pub); jpeg_create_compress(&cinfo); jcerr.pub.error_exit=my_error_exit; jcerr.pub.output_message=my_output_message; /* setup error handling for decompress */ if (setjmp(jderr.setjmp_buffer)) { jpeg_abort_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); jpeg_abort_compress(&cinfo); jpeg_destroy_compress(&cinfo); if (buf) { for (j=0;j<dinfo.output_height;j++) free(buf[j]); free(buf); buf=NULL; } outputsize = 0; outputbuffer = NULL; return 2; } /* prepare to decompress */ jpeg_mem_src(&dinfo, inputbuffer, inputsize); if (jpeg_read_header(&dinfo, TRUE) != JPEG_HEADER_OK) { return 2; } jpeg_mem_dest(&cinfo, outputbuffer, outputsize); printf("Proc: Image is %d by %d with %d components target quality:%d\n", dinfo.output_width, dinfo.output_height, dinfo.output_components, quality); if (quality>-1 ) { jpeg_start_decompress(&dinfo); buf = malloc(sizeof(JSAMPROW)*dinfo.output_height); if (!buf) { return 2; } for (j=0;j<dinfo.output_height;j++) { buf[j]=malloc(sizeof(JSAMPLE)*dinfo.output_width* dinfo.out_color_components); if (!buf[j]) return 2; } while (dinfo.output_scanline < dinfo.output_height) { jpeg_read_scanlines(&dinfo,&buf[dinfo.output_scanline], dinfo.output_height-dinfo.output_scanline); } } else { coef_arrays = jpeg_read_coefficients(&dinfo); } if (setjmp(jcerr.setjmp_buffer)) { jpeg_abort_compress(&cinfo); jpeg_abort_decompress(&dinfo); printf(" [Compress ERROR]\n"); if (buf) { for (j=0;j<dinfo.output_height;j++) free(buf[j]); free(buf); buf=NULL; } outputsize = 0; return 2; } if (quality>-1) { cinfo.in_color_space=dinfo.out_color_space; cinfo.input_components=dinfo.output_components; cinfo.image_width=dinfo.image_width; cinfo.image_height=dinfo.image_height; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,quality,TRUE); if ( (dinfo.progressive_mode || all_progressive) && !all_normal ) jpeg_simple_progression(&cinfo); cinfo.optimize_coding = TRUE; j=0; jpeg_start_compress(&cinfo,TRUE); /* write image */ while (cinfo.next_scanline < cinfo.image_height) { jpeg_write_scanlines(&cinfo,&buf[cinfo.next_scanline], dinfo.output_height); } } else { jpeg_copy_critical_parameters(&dinfo, &cinfo); cinfo.optimize_coding = TRUE; jpeg_write_coefficients(&cinfo, coef_arrays); } jpeg_finish_compress(&cinfo); jpeg_finish_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); jpeg_destroy_compress(&cinfo); return 0; }
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: 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 dinfo; struct jpeg_compress_struct cinfo; struct my_error_mgr jcerr,jderr; JSAMPARRAY buf = NULL; jvirt_barray_ptr *coef_arrays = NULL; char marker_str[256]; char tmpfilename[MAXPATHLEN],tmpdir[MAXPATHLEN]; char newname[MAXPATHLEN], dest_path[MAXPATHLEN]; volatile int i; int c,j, tmpfd, searchcount, searchdone; int opt_index = 0; long insize = 0, outsize = 0, lastsize = 0; int oldquality; double ratio; struct stat file_stat; jpeg_saved_marker_ptr cmarker; unsigned char *outbuffer = NULL; size_t outbuffersize; char *outfname = NULL; FILE *infile = NULL, *outfile = NULL; int marker_in_count, marker_in_size; int compress_err_count = 0; int decompress_err_count = 0; long average_count = 0; double average_rate = 0.0, total_save = 0.0; if (rcsid) ; /* so compiler won't complain about "unused" rcsid string */ umask(077); signal(SIGINT,own_signal_handler); signal(SIGTERM,own_signal_handler); /* initialize decompression object */ dinfo.err = jpeg_std_error(&jderr.pub); jpeg_create_decompress(&dinfo); jderr.pub.error_exit=my_error_exit; jderr.pub.output_message=my_output_message; jderr.jump_set = 0; /* initialize compression object */ cinfo.err = jpeg_std_error(&jcerr.pub); jpeg_create_compress(&cinfo); jcerr.pub.error_exit=my_error_exit; jcerr.pub.output_message=my_output_message; jcerr.jump_set = 0; if (argc<2) { if (!quiet_mode) fprintf(stderr,PROGRAMNAME ": file arguments missing\n" "Try '" PROGRAMNAME " --help' for more information.\n"); exit(1); } /* parse command line parameters */ while(1) { opt_index=0; if ((c=getopt_long(argc,argv,"d:hm:nstqvfVpPoT:S:b",long_options,&opt_index)) == -1) break; switch (c) { case 'm': { int tmpvar; if (sscanf(optarg,"%d",&tmpvar) == 1) { quality=tmpvar; if (quality < 0) quality=0; if (quality > 100) quality=100; } else fatal("invalid argument for -m, --max"); } break; case 'd': if (realpath(optarg,dest_path)==NULL || !is_directory(dest_path)) { fatal("invalid argument for option -d, --dest"); } strncat(dest_path,DIR_SEPARATOR_S,sizeof(dest_path)-strlen(dest_path)-1); if (verbose_mode) fprintf(stderr,"Destination directory: %s\n",dest_path); dest=1; break; case 'v': verbose_mode++; break; case 'h': print_usage(); exit(0); break; case 'q': quiet_mode=1; break; case 't': totals_mode=1; break; case 'n': noaction=1; break; case 'f': force=1; break; case 'b': csv=1; quiet_mode=1; break; case '?': break; case 'V': print_version(); exit(0); break; case 'o': overwrite_mode=1; break; case 'p': preserve_mode=1; break; case 'P': preserve_perms=1; break; case 's': save_exif=0; save_iptc=0; save_com=0; save_icc=0; save_xmp=0; break; case 'T': { int tmpvar; if (sscanf(optarg,"%d",&tmpvar) == 1) { threshold=tmpvar; if (threshold < 0) threshold=0; if (threshold > 100) threshold=100; } else fatal("invalid argument for -T, --threshold"); } break; case 'S': { unsigned int tmpvar; if (sscanf(optarg,"%u",&tmpvar) == 1) { if (tmpvar > 0 && tmpvar < 100 && optarg[strlen(optarg)-1] == '%' ) { target_size=-tmpvar; } else { target_size=tmpvar; } quality=100; } else fatal("invalid argument for -S, --size"); } break; } } /* check for '-' option indicating input is from stdin... */ i=1; while (argv[i]) { if (argv[i][0]=='-' && argv[i][1]==0) stdin_mode=1; i++; } if (stdin_mode) { stdout_mode=1; force=1; } if (stdout_mode) { logs_to_stdout=0; } if (all_normal && all_progressive) fatal("cannot specify both --all-normal and --all-progressive"); if (verbose_mode) { if (quality>=0 && target_size==0) fprintf(stderr,"Image quality limit set to: %d\n",quality); if (threshold>=0) fprintf(stderr,"Compression threshold (%%) set to: %d\n",threshold); if (all_normal) fprintf(stderr,"All output files will be non-progressive\n"); if (all_progressive) fprintf(stderr,"All output files will be progressive\n"); if (target_size > 0) fprintf(stderr,"Target size for output files set to: %u Kbytes.\n", target_size); if (target_size < 0) fprintf(stderr,"Target size for output files set to: %u%%\n", -target_size); } /* loop to process the input files */ i=1; do { if (stdin_mode) { infile=stdin; set_filemode_binary(infile); } else { if (!argv[i][0]) continue; if (argv[i][0]=='-') continue; if (strlen(argv[i]) >= MAXPATHLEN) { warn("skipping too long filename: %s",argv[i]); continue; } if (!noaction) { /* generate tmp dir & new filename */ if (dest) { STRNCPY(tmpdir,dest_path,sizeof(tmpdir)); STRNCPY(newname,dest_path,sizeof(newname)); if (!splitname(argv[i],tmpfilename,sizeof(tmpfilename))) fatal("splitname() failed for: %s",argv[i]); strncat(newname,tmpfilename,sizeof(newname)-strlen(newname)-1); } else { if (!splitdir(argv[i],tmpdir,sizeof(tmpdir))) fatal("splitdir() failed for: %s",argv[i]); STRNCPY(newname,argv[i],sizeof(newname)); } } retry_point: if (!is_file(argv[i],&file_stat)) { if (is_directory(argv[i])) warn("skipping directory: %s",argv[i]); else warn("skipping special file: %s",argv[i]); continue; } if ((infile=fopen(argv[i],"rb"))==NULL) { warn("cannot open file: %s", argv[i]); continue; } } if (setjmp(jderr.setjmp_buffer)) { /* error handler for decompress */ jpeg_abort_decompress(&dinfo); fclose(infile); if (buf) FREE_LINE_BUF(buf,dinfo.output_height); if (!quiet_mode || csv) fprintf(LOG_FH,csv ? ",,,,,error\n" : " [ERROR]\n"); decompress_err_count++; jderr.jump_set=0; continue; } else { jderr.jump_set=1; } if (!retry && (!quiet_mode || csv)) { fprintf(LOG_FH,csv ? "%s," : "%s ",(stdin_mode?"stdin":argv[i])); fflush(LOG_FH); } /* prepare to decompress */ global_error_counter=0; jpeg_save_markers(&dinfo, JPEG_COM, 0xffff); for (j=0;j<=15;j++) jpeg_save_markers(&dinfo, JPEG_APP0+j, 0xffff); jpeg_stdio_src(&dinfo, infile); jpeg_read_header(&dinfo, TRUE); /* check for Exif/IPTC/ICC/XMP markers */ marker_str[0]=0; marker_in_count=0; marker_in_size=0; cmarker=dinfo.marker_list; while (cmarker) { marker_in_count++; marker_in_size+=cmarker->data_length; if (cmarker->marker == EXIF_JPEG_MARKER && !memcmp(cmarker->data,EXIF_IDENT_STRING,EXIF_IDENT_STRING_SIZE)) strncat(marker_str,"Exif ",sizeof(marker_str)-strlen(marker_str)-1); if (cmarker->marker == IPTC_JPEG_MARKER) strncat(marker_str,"IPTC ",sizeof(marker_str)-strlen(marker_str)-1); if (cmarker->marker == ICC_JPEG_MARKER && !memcmp(cmarker->data,ICC_IDENT_STRING,ICC_IDENT_STRING_SIZE)) strncat(marker_str,"ICC ",sizeof(marker_str)-strlen(marker_str)-1); if (cmarker->marker == XMP_JPEG_MARKER && !memcmp(cmarker->data,XMP_IDENT_STRING,XMP_IDENT_STRING_SIZE)) strncat(marker_str,"XMP ",sizeof(marker_str)-strlen(marker_str)-1); cmarker=cmarker->next; } if (verbose_mode > 1) fprintf(LOG_FH,"%d markers found in input file (total size %d bytes)\n", marker_in_count,marker_in_size); if (!retry && (!quiet_mode || csv)) { fprintf(LOG_FH,csv ? "%dx%d,%dbit,%c," : "%dx%d %dbit %c ",(int)dinfo.image_width, (int)dinfo.image_height,(int)dinfo.num_components*8, (dinfo.progressive_mode?'P':'N')); if (!csv) { fprintf(LOG_FH,"%s",marker_str); if (dinfo.saw_Adobe_marker) fprintf(LOG_FH,"Adobe "); if (dinfo.saw_JFIF_marker) fprintf(LOG_FH,"JFIF "); } fflush(LOG_FH); } if ((insize=file_size(infile)) < 0) fatal("failed to stat() input file"); /* decompress the file */ if (quality>=0 && !retry) { jpeg_start_decompress(&dinfo); /* allocate line buffer to store the decompressed image */ buf = malloc(sizeof(JSAMPROW)*dinfo.output_height); if (!buf) fatal("not enough memory"); for (j=0;j<dinfo.output_height;j++) { buf[j]=malloc(sizeof(JSAMPLE)*dinfo.output_width* dinfo.out_color_components); if (!buf[j]) fatal("not enough memory"); } while (dinfo.output_scanline < dinfo.output_height) { jpeg_read_scanlines(&dinfo,&buf[dinfo.output_scanline], dinfo.output_height-dinfo.output_scanline); } } else { coef_arrays = jpeg_read_coefficients(&dinfo); } if (!retry && !quiet_mode) { if (global_error_counter==0) fprintf(LOG_FH," [OK] "); else fprintf(LOG_FH," [WARNING] "); fflush(LOG_FH); } if (dest && !noaction) { if (file_exists(newname) && !overwrite_mode) { warn("target file already exists: %s\n",newname); jpeg_abort_decompress(&dinfo); fclose(infile); if (buf) FREE_LINE_BUF(buf,dinfo.output_height); continue; } } if (setjmp(jcerr.setjmp_buffer)) { /* error handler for compress failures */ jpeg_abort_compress(&cinfo); jpeg_abort_decompress(&dinfo); fclose(infile); if (!quiet_mode) fprintf(LOG_FH," [Compress ERROR]\n"); if (buf) FREE_LINE_BUF(buf,dinfo.output_height); compress_err_count++; jcerr.jump_set=0; continue; } else { jcerr.jump_set=1; } lastsize = 0; searchcount = 0; searchdone = 0; oldquality = 200; binary_search_loop: /* allocate memory buffer that should be large enough to store the output JPEG... */ if (outbuffer) free(outbuffer); outbuffersize=insize + 32768; outbuffer=malloc(outbuffersize); if (!outbuffer) fatal("not enough memory"); /* setup custom "destination manager" for libjpeg to write to our buffer */ jpeg_memory_dest(&cinfo, &outbuffer, &outbuffersize, 65536); if (quality>=0 && !retry) { /* lossy "optimization" ... */ cinfo.in_color_space=dinfo.out_color_space; cinfo.input_components=dinfo.output_components; cinfo.image_width=dinfo.image_width; cinfo.image_height=dinfo.image_height; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,quality,TRUE); if ( (dinfo.progressive_mode || all_progressive) && !all_normal ) jpeg_simple_progression(&cinfo); cinfo.optimize_coding = TRUE; j=0; jpeg_start_compress(&cinfo,TRUE); /* write markers */ write_markers(&dinfo,&cinfo); /* write image */ while (cinfo.next_scanline < cinfo.image_height) { jpeg_write_scanlines(&cinfo,&buf[cinfo.next_scanline], dinfo.output_height); } } else { /* lossless "optimization" ... */ jpeg_copy_critical_parameters(&dinfo, &cinfo); if ( (dinfo.progressive_mode || all_progressive) && !all_normal ) jpeg_simple_progression(&cinfo); cinfo.optimize_coding = TRUE; /* write image */ jpeg_write_coefficients(&cinfo, coef_arrays); /* write markers */ write_markers(&dinfo,&cinfo); } jpeg_finish_compress(&cinfo); outsize=outbuffersize; if (target_size != 0 && !retry) { /* perform (binary) search to try to reach target file size... */ long osize = outsize/1024; long isize = insize/1024; long tsize = target_size; if (tsize < 0) { tsize=((-target_size)*insize/100)/1024; if (tsize < 1) tsize=1; } if (osize == tsize || searchdone || searchcount >= 8 || tsize > isize) { if (searchdone < 42 && lastsize > 0) { if (abs(osize-tsize) > abs(lastsize-tsize)) { if (verbose_mode) fprintf(LOG_FH,"(revert to %d)",oldquality); searchdone=42; quality=oldquality; goto binary_search_loop; } } if (verbose_mode) fprintf(LOG_FH," "); } else { int newquality; int dif = floor((abs(oldquality-quality)/2.0)+0.5); if (osize > tsize) { newquality=quality-dif; if (dif < 1) { newquality--; searchdone=1; } if (newquality < 0) { newquality=0; searchdone=2; } } else { newquality=quality+dif; if (dif < 1) { newquality++; searchdone=3; } if (newquality > 100) { newquality=100; searchdone=4; } } oldquality=quality; quality=newquality; if (verbose_mode) fprintf(LOG_FH,"(try %d)",quality); lastsize=osize; searchcount++; goto binary_search_loop; } } if (buf) FREE_LINE_BUF(buf,dinfo.output_height); jpeg_finish_decompress(&dinfo); fclose(infile); if (quality>=0 && outsize>=insize && !retry && !stdin_mode) { if (verbose_mode) fprintf(LOG_FH,"(retry w/lossless) "); retry=1; goto retry_point; } retry=0; ratio=(insize-outsize)*100.0/insize; if (!quiet_mode || csv) fprintf(LOG_FH,csv ? "%ld,%ld,%0.2f," : "%ld --> %ld bytes (%0.2f%%), ",insize,outsize,ratio); average_count++; average_rate+=(ratio<0 ? 0.0 : ratio); if ((outsize < insize && ratio >= threshold) || force) { total_save+=(insize-outsize)/1024.0; if (!quiet_mode || csv) fprintf(LOG_FH,csv ? "optimized\n" : "optimized.\n"); if (noaction) continue; if (stdout_mode) { outfname=NULL; set_filemode_binary(stdout); if (fwrite(outbuffer,outbuffersize,1,stdout) != 1) fatal("write failed to stdout"); } else { if (preserve_perms && !dest) { /* make backup of the original file */ snprintf(tmpfilename,sizeof(tmpfilename),"%s.jpegoptim.bak",newname); if (verbose_mode > 1 && !quiet_mode) fprintf(LOG_FH,"creating backup of original image as: %s\n",tmpfilename); if (file_exists(tmpfilename)) fatal("backup file already exists: %s",tmpfilename); if (copy_file(newname,tmpfilename)) fatal("failed to create backup of original file"); if ((outfile=fopen(newname,"wb"))==NULL) fatal("error opening output file: %s", newname); outfname=newname; } else { #ifdef HAVE_MKSTEMPS /* rely on mkstemps() to create us temporary file safely... */ snprintf(tmpfilename,sizeof(tmpfilename), "%sjpegoptim-%d-%d.XXXXXX.tmp", tmpdir, (int)getuid(), (int)getpid()); if ((tmpfd = mkstemps(tmpfilename,4)) < 0) fatal("error creating temp file: mkstemps() failed"); if ((outfile=fdopen(tmpfd,"wb"))==NULL) #else /* if platform is missing mkstemps(), try to create at least somewhat "safe" temp file... */ snprintf(tmpfilename,sizeof(tmpfilename), "%sjpegoptim-%d-%d.%d.tmp", tmpdir, (int)getuid(), (int)getpid(),time(NULL)); tmpfd=0; if ((outfile=fopen(tmpfilename,"wb"))==NULL) #endif fatal("error opening temporary file: %s",tmpfilename); outfname=tmpfilename; } if (verbose_mode > 1 && !quiet_mode) fprintf(LOG_FH,"writing %lu bytes to file: %s\n", (long unsigned int)outbuffersize, outfname); if (fwrite(outbuffer,outbuffersize,1,outfile) != 1) fatal("write failed to file: %s", outfname); fclose(outfile); } if (outfname) { if (preserve_mode) { /* preserve file modification time */ struct utimbuf time_save; time_save.actime=file_stat.st_atime; time_save.modtime=file_stat.st_mtime; if (utime(outfname,&time_save) != 0) warn("failed to reset output file time/date"); } if (preserve_perms && !dest) { /* original file was already replaced, remove backup... */ if (delete_file(tmpfilename)) warn("failed to remove backup file: %s",tmpfilename); } else { /* make temp file to be the original file... */ /* preserve file mode */ if (chmod(outfname,(file_stat.st_mode & 0777)) != 0) warn("failed to set output file mode"); /* preserve file group (and owner if run by root) */ if (chown(outfname, (geteuid()==0 ? file_stat.st_uid : -1), file_stat.st_gid) != 0) warn("failed to reset output file group/owner"); if (verbose_mode > 1 && !quiet_mode) fprintf(LOG_FH,"renaming: %s to %s\n",outfname,newname); if (rename_file(outfname,newname)) fatal("cannot rename temp file"); } } } else { if (!quiet_mode || csv) fprintf(LOG_FH,csv ? "skipped\n" : "skipped.\n"); } } while (++i<argc && !stdin_mode); if (totals_mode && !quiet_mode) fprintf(LOG_FH,"Average ""compression"" (%ld files): %0.2f%% (%0.0fk)\n", average_count, average_rate/average_count, total_save); jpeg_destroy_decompress(&dinfo); jpeg_destroy_compress(&cinfo); return (decompress_err_count > 0 || compress_err_count > 0 ? 1 : 0);; }
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; }
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) { char tmpfilename[MAXPATHLEN],tmpdir[MAXPATHLEN]; char newname[MAXPATHLEN], dest_path[MAXPATHLEN]; volatile int i; int c,j, err_count; int opt_index = 0; long insize,outsize; double ratio; struct utimbuf time_save; jpeg_saved_marker_ptr cmarker; if (rcsid); /* so compiler won't complain about "unused" rcsid string */ signal(SIGINT,own_signal_handler); signal(SIGTERM,own_signal_handler); /* initialize decompression object */ dinfo.err = jpeg_std_error(&jderr.pub); jpeg_create_decompress(&dinfo); jderr.pub.error_exit=my_error_exit; jderr.pub.output_message=my_output_message; /* initialize compression object */ cinfo.err = jpeg_std_error(&jcerr.pub); jpeg_create_compress(&cinfo); jcerr.pub.error_exit=my_error_exit; jcerr.pub.output_message=my_output_message; if (argc<2) { if (!quiet_mode) fprintf(stderr,"jpegoptim: file arguments missing\n" "Try 'jpegoptim --help' for more information.\n"); exit(1); } /* parse command line parameters */ while(1) { opt_index=0; if ((c=getopt_long(argc,argv,"d:hm:ntqvfVpoT:",long_options,&opt_index)) == -1) break; switch (c) { case 'm': { int tmpvar; if (sscanf(optarg,"%d",&tmpvar) == 1) { quality=tmpvar; if (quality < 0) quality=0; if (quality > 100) quality=100; } else fatal("invalid argument for -m, --max"); } break; case 'd': if (realpath(optarg,dest_path)==NULL || !is_directory(dest_path)) { fatal("invalid argument for option -d, --dest"); } if (verbose_mode) fprintf(stderr,"Destination directory: %s\n",dest_path); dest=1; break; case 'v': verbose_mode++; break; case 'h': p_usage(); break; case 'q': quiet_mode=1; break; case 't': totals_mode=1; break; case 'n': noaction=1; break; case 'f': force=1; break; case '?': break; case 'V': printf("jpegoptim v%s %s\n",VERSIO,HOST_TYPE); printf("Copyright (c) Timo Kokkonen, 1996-2011.\n"); exit(0); break; case 'o': overwrite_mode=1; break; case 'p': preserve_mode=1; break; case 's': save_exif=0; save_iptc=0; save_com=0; save_icc=0; break; case 'c': save_com=0; break; case 'e': save_exif=0; break; case 'i': save_iptc=0; break; case 'P': save_icc=0; break; case 'T': { int tmpvar; if (sscanf(optarg,"%d",&tmpvar) == 1) { threshold=tmpvar; if (threshold < 0) threshold=0; if (threshold > 100) threshold=100; } else fatal("invalid argument for -T, --threshold"); } break; default: if (!quiet_mode) fprintf(stderr,"jpegoptim: error parsing parameters.\n"); } } if (verbose_mode && (quality>=0)) fprintf(stderr,"Image quality limit set to: %d\n",quality); if (verbose_mode && (threshold>=0)) fprintf(stderr,"Compression treshold (%%) set to: %d\n",threshold); /* loop to process the input files */ i=1; do { if (!argv[i][0]) continue; if (argv[i][0]=='-') continue; if (!noaction) { /* generate temp (& new) filename */ if (dest) { strncpy(tmpdir,dest_path,sizeof(tmpdir)); strncpy(newname,dest_path,sizeof(newname)); if (tmpdir[strlen(tmpdir)-1] != '/') { strncat(tmpdir,"/",sizeof(tmpdir)-strlen(tmpdir)); strncat(newname,"/",sizeof(newname)-strlen(newname)); } strncat(newname,(char*)basename(argv[i]), sizeof(newname)-strlen(newname)); } else { if (!splitdir(argv[i],tmpdir,sizeof(tmpdir))) fatal("splitdir() failed!"); strncpy(newname,argv[i],sizeof(newname)); } snprintf(tmpfilename,sizeof(tmpfilename), "%sjpegoptim-%d-%d.tmp", tmpdir, (int)getuid(), (int)getpid()); } retry_point: if ((infile=fopen(argv[i],"r"))==NULL) { if (!quiet_mode) fprintf(stderr, "jpegoptim: can't open %s\n", argv[i]); continue; } if (is_dir(infile,&time_save.actime,&time_save.modtime)) { fclose(infile); if (verbose_mode) printf("directory: %s skipped\n",argv[i]); continue; } /* setup error handling for decompress */ if (setjmp(jderr.setjmp_buffer)) { jpeg_abort_decompress(&dinfo); fclose(infile); if (buf) { for (j=0;j<dinfo.output_height;j++) free(buf[j]); free(buf); buf=NULL; } printf(" [ERROR]\n"); continue; } if (!retry) { printf("%s ",argv[i]); fflush(stdout); } /* prepare to decompress */ global_error_counter=0; err_count=jderr.pub.num_warnings; if (save_com) jpeg_save_markers(&dinfo, JPEG_COM, 0xffff); if (save_iptc) jpeg_save_markers(&dinfo, IPTC_JPEG_MARKER, 0xffff); if (save_exif) jpeg_save_markers(&dinfo, EXIF_JPEG_MARKER, 0xffff); if (save_icc) jpeg_save_markers(&dinfo, ICC_JPEG_MARKER, 0xffff); jpeg_stdio_src(&dinfo, infile); jpeg_read_header(&dinfo, TRUE); /* check for Exif/IPTC markers */ exif_marker=NULL; iptc_marker=NULL; icc_marker=NULL; cmarker=dinfo.marker_list; while (cmarker) { if (cmarker->marker == EXIF_JPEG_MARKER) { if (!memcmp(cmarker->data,EXIF_IDENT_STRING,EXIF_IDENT_STRING_SIZE)) exif_marker=cmarker; } if (cmarker->marker == IPTC_JPEG_MARKER) { iptc_marker=cmarker; } if (cmarker->marker == ICC_JPEG_MARKER) { if (!memcmp(cmarker->data,ICC_IDENT_STRING,ICC_IDENT_STRING_SIZE)) icc_marker=cmarker; } cmarker=cmarker->next; } if (!retry) { printf("%dx%d %dbit ",(int)dinfo.image_width, (int)dinfo.image_height,(int)dinfo.num_components*8); if (exif_marker) printf("Exif "); if (iptc_marker) printf("IPTC "); if (icc_marker) printf("ICC "); if (dinfo.saw_Adobe_marker) printf("Adobe "); if (dinfo.saw_JFIF_marker) printf("JFIF "); fflush(stdout); } insize=file_size(infile); /* decompress the file */ if (quality>=0 && !retry) { jpeg_start_decompress(&dinfo); buf = malloc(sizeof(JSAMPROW)*dinfo.output_height); if (!buf) fatal("not enough memory"); for (j=0;j<dinfo.output_height;j++) { buf[j]=malloc(sizeof(JSAMPLE)*dinfo.output_width* dinfo.out_color_components); if (!buf[j]) fatal("not enough memory"); } while (dinfo.output_scanline < dinfo.output_height) { jpeg_read_scanlines(&dinfo,&buf[dinfo.output_scanline], dinfo.output_height-dinfo.output_scanline); } } else { coef_arrays = jpeg_read_coefficients(&dinfo); } if (!retry) { if (!global_error_counter) printf(" [OK] "); else printf(" [WARNING] "); fflush(stdout); } if (dest && !noaction) { if (file_exists(newname) && !overwrite_mode) { fprintf(stderr,"target file already exists!\n"); jpeg_abort_decompress(&dinfo); fclose(infile); if (buf) { for (j=0;j<dinfo.output_height;j++) free(buf[j]); free(buf); buf=NULL; } continue; } } if (noaction) { outfname=NULL; if ((outfile=tmpfile())==NULL) fatal("error opening temp file"); } else { outfname=tmpfilename; if ((outfile=fopen(outfname,"w"))==NULL) fatal("error opening target file"); } if (setjmp(jcerr.setjmp_buffer)) { jpeg_abort_compress(&cinfo); jpeg_abort_decompress(&dinfo); fclose(outfile); if (infile) fclose(infile); printf(" [Compress ERROR]\n"); if (buf) { for (j=0;j<dinfo.output_height;j++) free(buf[j]); free(buf); buf=NULL; } if (file_exists(outfname)) delete_file(outfname); outfname=NULL; continue; } jpeg_stdio_dest(&cinfo, outfile); if (quality>=0 && !retry) { /* lossy "optimization" ... */ cinfo.in_color_space=dinfo.out_color_space; cinfo.input_components=dinfo.output_components; cinfo.image_width=dinfo.image_width; cinfo.image_height=dinfo.image_height; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,quality,TRUE); cinfo.optimize_coding = TRUE; j=0; jpeg_start_compress(&cinfo,TRUE); /* write markers */ write_markers(&dinfo,&cinfo); while (cinfo.next_scanline < cinfo.image_height) { jpeg_write_scanlines(&cinfo,&buf[cinfo.next_scanline], dinfo.output_height); } for (j=0;j<dinfo.output_height;j++) free(buf[j]); free(buf); buf=NULL; } else { /* lossless "optimization" ... */ jpeg_copy_critical_parameters(&dinfo, &cinfo); cinfo.optimize_coding = TRUE; jpeg_write_coefficients(&cinfo, coef_arrays); /* write markers */ write_markers(&dinfo,&cinfo); } jpeg_finish_compress(&cinfo); jpeg_finish_decompress(&dinfo); fclose(infile); outsize=file_size(outfile); fclose(outfile); if (preserve_mode && !noaction) { if (utime(outfname,&time_save) != 0) { fprintf(stderr,"jpegoptim: failed to reset output file time/date\n"); } } if (quality>=0 && outsize>=insize && !retry) { if (verbose_mode) printf("(retry w/lossless) "); retry=1; goto retry_point; } retry=0; ratio=(insize-outsize)*100.0/insize; printf("%ld --> %ld bytes (%0.2f%%), ",insize,outsize,ratio); average_count++; average_rate+=(ratio<0 ? 0.0 : ratio); if ((outsize < insize && ratio >= threshold) || force) { total_save+=(insize-outsize)/1024.0; printf("optimized.\n"); if (noaction) continue; if (verbose_mode > 1 && !quiet_mode) fprintf(stderr,"renaming: %s to %s\n",outfname,newname); if (rename(outfname,newname)) fatal("cannot rename temp file"); } else { printf("skipped.\n"); if (!noaction) delete_file(outfname); } } while (++i<argc); if (totals_mode&&!quiet_mode) printf("Average ""compression"" (%ld files): %0.2f%% (%0.0fk)\n", average_count, average_rate/average_count, total_save); jpeg_destroy_decompress(&dinfo); jpeg_destroy_compress(&cinfo); return 0; }
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; }
int startup (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 * 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 ignored; we will rescan the switches after opening * the input file. */ 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); /* Read file header */ (void) jpeg_read_header(&srcinfo, TRUE); /* Read source file as DCT coefficients */ coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); /* 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 */ jpeg_write_coefficients(&dstinfo, coef_arrays); /* ought to copy source comments here... */ /* 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 */ }