Пример #1
0
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);

    }
}
Пример #2
0
/**
 * 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);
}
Пример #3
0
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;
}
Пример #4
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;
  /* 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 */
}
Пример #5
0
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;
}
Пример #6
0
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 */
}
Пример #7
0
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);
		}
		
	}
	
}
Пример #9
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;

  /* 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 */
}
Пример #10
0
void JpegContent::applyPendingTransformation()
{
    if (d->mRawData.size() == 0) {
        qCritical() << "No data loaded\n";
        return;
    }

    // The following code is inspired by jpegtran.c from the libjpeg

    // Init JPEG structs
    struct jpeg_decompress_struct srcinfo;
    struct jpeg_compress_struct dstinfo;
    jvirt_barray_ptr * src_coef_arrays;
    jvirt_barray_ptr * dst_coef_arrays;

    // Initialize the JPEG decompression object
    JPEGErrorManager srcErrorManager;
    srcinfo.err = &srcErrorManager;
    jpeg_create_decompress(&srcinfo);
    if (setjmp(srcErrorManager.jmp_buffer)) {
        qCritical() << "libjpeg error in src\n";
        return;
    }

    // Initialize the JPEG compression object
    JPEGErrorManager dstErrorManager;
    dstinfo.err = &dstErrorManager;
    jpeg_create_compress(&dstinfo);
    if (setjmp(dstErrorManager.jmp_buffer)) {
        qCritical() << "libjpeg error in dst\n";
        return;
    }

    // Specify data source for decompression
    QBuffer buffer(&d->mRawData);
    buffer.open(QIODevice::ReadOnly);
    IODeviceJpegSourceManager::setup(&srcinfo, &buffer);

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

    (void) jpeg_read_header(&srcinfo, true);

    // Init transformation
    jpeg_transform_info transformoption;
    memset(&transformoption, 0, sizeof(jpeg_transform_info));
    transformoption.transform = findJxform(d->mTransformMatrix);
    jtransform_request_workspace(&srcinfo, &transformoption);

    /* Read source file as DCT coefficients */
    src_coef_arrays = jpeg_read_coefficients(&srcinfo);

    /* Initialize destination compression parameters from source values */
    jpeg_copy_critical_parameters(&srcinfo, &dstinfo);

    /* Adjust destination parameters if required by transform options;
    * also find out which set of coefficient arrays will hold the output.
    */
    dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
                      src_coef_arrays,
                      &transformoption);

    /* Specify data destination for compression */
    QByteArray output;
    output.resize(d->mRawData.size());
    d->setupInmemDestination(&dstinfo, &output);

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

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

    /* Execute image transformation, if any */
    jtransform_execute_transformation(&srcinfo, &dstinfo,
                                      src_coef_arrays,
                                      &transformoption);

    /* Finish compression and release memory */
    jpeg_finish_compress(&dstinfo);
    jpeg_destroy_compress(&dstinfo);
    (void) jpeg_finish_decompress(&srcinfo);
    jpeg_destroy_decompress(&srcinfo);

    // Set rawData to our new JPEG
    d->mRawData = output;
}
Пример #11
0
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;
}
Пример #12
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;
}
Пример #13
0
// 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;
}
Пример #14
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;
}
Пример #15
0
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;
}
Пример #16
0
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);;
}
Пример #17
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;			
}
Пример #18
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;
}
Пример #19
0
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;
}
Пример #20
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 */
}