示例#1
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);
}
示例#2
0
/**
 * Resizes jpeg.
 *
 * <p> During the resize, the image is decoded line by line and encoded again.
 */
static void resizeJpeg(
    JNIEnv* env,
    struct jpeg_source_mgr& source,
    struct jpeg_destination_mgr& destination,
    const ScaleFactor& scale_factor,
    int quality) {
  THROW_AND_RETURN_IF(quality < 1, "quality should not be lower than 1");
  THROW_AND_RETURN_IF(quality > 100, "quality should not be greater than 100");
  THROW_AND_RETURN_IF(
      8 % scale_factor.getDenominator() > 0,
      "wrong scale denominator");
  THROW_AND_RETURN_IF(
      scale_factor.getNumerator() < 1,
      "scale numerator cannot be lower than 1");
  THROW_AND_RETURN_IF(
      scale_factor.getNumerator() > 16,
      "scale numerator cannot be greater than 16");

  JpegErrorHandler error_handler{env};
  if (setjmp(error_handler.setjmpBuffer)) {
    return;
  }

  // prepare decompress struct
  struct jpeg_decompress_struct dinfo;
  initDecompressStruct(dinfo, error_handler, source);
  dinfo.scale_num = scale_factor.getNumerator();
  dinfo.scale_denom = scale_factor.getDenominator();
  dinfo.out_color_space = JCS_RGB;
  (void) jpeg_start_decompress(&dinfo);

  // create compress struct
  struct jpeg_compress_struct cinfo;
  initCompressStruct(cinfo, dinfo, error_handler, destination);
  jpeg_set_quality(&cinfo, quality, false);
  jpeg_start_compress(&cinfo, true);

  jcopy_markers_execute(&dinfo, &cinfo, JCOPYOPT_ALL);
  size_t row_stride = dinfo.output_width * dinfo.output_components;
  JSAMPARRAY buffer = (*dinfo.mem->alloc_sarray)
    ((j_common_ptr) &dinfo, JPOOL_IMAGE, row_stride, 1);
  while (dinfo.output_scanline < dinfo.output_height) {
    jpeg_read_scanlines(&dinfo, buffer, 1);
    (void) jpeg_write_scanlines(&cinfo, buffer, 1);
  }

  // tear down
  jpeg_finish_compress(&cinfo);
  jpeg_destroy_decompress(&dinfo);
  jpeg_destroy_compress(&cinfo);
}
示例#3
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;
}
示例#4
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;
}
示例#5
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 */
}
示例#6
0
文件: jpgicc.c 项目: etlegacy/EasyGen
static
int TransformImage(char *cDefInpProf, char *cOutProf)
{
       cmsHPROFILE hIn, hOut, hProof;
       cmsHTRANSFORM xform;
       cmsUInt32Number wInput, wOutput;
       int OutputColorSpace;
       cmsUInt32Number dwFlags = 0;
       cmsUInt32Number EmbedLen;
       cmsUInt8Number* EmbedBuffer;


       cmsSetAdaptationState(ObserverAdaptationState);

       if (BlackPointCompensation) {

            dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
       }


       switch (PrecalcMode) {

       case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break;
       case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
       case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
       default:;
       }


       if (GamutCheck) {
            dwFlags |= cmsFLAGS_GAMUTCHECK;
            cmsSetAlarmCodes(Alarm);
       }

       // Take input color space
       wInput = GetInputPixelType();

        if (lIsDeviceLink) {

            hIn = cmsOpenProfileFromFile(cDefInpProf, "r");
            hOut = NULL;
            hProof = NULL;
       }
        else {

        if (!IgnoreEmbedded && read_icc_profile(&Decompressor, &EmbedBuffer, &EmbedLen))
        {
              hIn = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);

               if (Verbose) {

                  fprintf(stdout, " (Embedded profile found)\n");
				  PrintProfileInformation(hIn);
                  fflush(stdout);
              }

               if (hIn != NULL && SaveEmbedded != NULL)
                          SaveMemoryBlock(EmbedBuffer, EmbedLen, SaveEmbedded);

              free(EmbedBuffer);
        }
        else
        {
            // Default for ITU/Fax
            if (cDefInpProf == NULL && T_COLORSPACE(wInput) == PT_Lab)
                cDefInpProf = "*Lab";

            if (cDefInpProf != NULL && cmsstrcasecmp(cDefInpProf, "*lab") == 0)
                hIn = CreateITU2PCS_ICC();
            else
                hIn = OpenStockProfile(0, cDefInpProf);
       }

        if (cOutProf != NULL && cmsstrcasecmp(cOutProf, "*lab") == 0)
            hOut = CreatePCS2ITU_ICC();
        else
        hOut = OpenStockProfile(0, cOutProf);

       hProof = NULL;
       if (cProofing != NULL) {

           hProof = OpenStockProfile(0, cProofing);
           if (hProof == NULL) {
            FatalError("Proofing profile couldn't be read.");
           }
           dwFlags |= cmsFLAGS_SOFTPROOFING;
          }
       }

        if (!hIn)
            FatalError("Input profile couldn't be read.");
        if (!hOut)
            FatalError("Output profile couldn't be read.");

       // Assure both, input profile and input JPEG are on same colorspace
       if (cmsGetColorSpace(hIn) != _cmsICCcolorSpace(T_COLORSPACE(wInput)))
              FatalError("Input profile is not operating in proper color space");


       // Output colorspace is given by output profile

        if (lIsDeviceLink) {
            OutputColorSpace = GetDevicelinkColorSpace(hIn);
        }
        else {
            OutputColorSpace = GetProfileColorSpace(hOut);
        }

       jpeg_copy_critical_parameters(&Decompressor, &Compressor);

       WriteOutputFields(OutputColorSpace);

       wOutput      = ComputeOutputFormatDescriptor(wInput, OutputColorSpace);


       xform = cmsCreateProofingTransform(hIn, wInput,
                                          hOut, wOutput,
                                          hProof, Intent,
                                          ProofingIntent, dwFlags);
	   if (xform == NULL)
                 FatalError("Cannot transform by using the profiles");

       DoTransform(xform, OutputColorSpace);


       jcopy_markers_execute(&Decompressor, &Compressor);

       cmsDeleteTransform(xform);
       cmsCloseProfile(hIn);
       cmsCloseProfile(hOut);
       if (hProof) cmsCloseProfile(hProof);

       return 1;
}
示例#7
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;
}
示例#8
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 */
}
示例#9
0
static
int TransformImage(char *cDefInpProf, char *cOutProf)
{
       cmsHPROFILE hIn, hOut, hProof;
       cmsHTRANSFORM xform;
       DWORD wInput, wOutput;
       int OutputColorSpace;
       DWORD dwFlags = 0; 
       DWORD EmbedLen;
       LPBYTE EmbedBuffer;


       if (BlackPointCompensation) {

            dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;            
       }

       switch (PrecalcMode) {
           
       case 0: dwFlags |= cmsFLAGS_NOTPRECALC; break;
       case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
       case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
       default:;
       }
        

       if (GamutCheck)
            dwFlags |= cmsFLAGS_GAMUTCHECK;
        

        if (lIsDeviceLink) {

            hIn = cmsOpenProfileFromFile(cDefInpProf, "r");
            hOut = NULL;
            hProof = NULL;
       }
        else {

        if (!IgnoreEmbedded && read_icc_profile(&Decompressor, &EmbedBuffer, &EmbedLen))
        {
              hIn = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);

               if (Verbose) {

                  fprintf(stdout, " (Embedded profile found)\n");
                  fprintf(stdout, "Product name: %s\n", cmsTakeProductName(hIn));
                  fprintf(stdout, "Description : %s\n", cmsTakeProductDesc(hIn));                          
                  fflush(stdout);
              }

               if (hIn != NULL && SaveEmbedded != NULL)
                          SaveMemoryBlock(EmbedBuffer, EmbedLen, SaveEmbedded);

              free(EmbedBuffer);
        }
        else
        {
                hIn = OpenStockProfile(cDefInpProf);
       }

        hOut = OpenStockProfile(cOutProf);


       hProof = NULL;
       if (cProofing != NULL) {

           hProof = OpenStockProfile(cProofing);
       }
        }

       // Take input color space

       wInput = GetInputPixelType();

       // Assure both, input profile and input JPEG are on same colorspace

       
       if (cmsGetColorSpace(hIn) != _cmsICCcolorSpace(T_COLORSPACE(wInput)))
              FatalError("Input profile is not operating in proper color space");
       

       // Output colorspace is given by output profile

        if (lIsDeviceLink) {
            OutputColorSpace = T_COLORSPACE(wInput);
        }
        else {
            OutputColorSpace = GetProfileColorSpace(hOut);
        }

       jpeg_copy_critical_parameters(&Decompressor, &Compressor);
       
       WriteOutputFields(OutputColorSpace);               
       
       wOutput      = ComputeOutputFormatDescriptor(wInput, OutputColorSpace);
       
       xform = cmsCreateProofingTransform(hIn, wInput, 
                                          hOut, wOutput, 
                                          hProof, Intent, 
                                          ProofingIntent, dwFlags);

       // Handle tile by tile or strip by strip strtok

       DoTransform(xform);

       
       jcopy_markers_execute(&Decompressor, &Compressor);
       
       cmsDeleteTransform(xform);
       cmsCloseProfile(hIn);
       cmsCloseProfile(hOut);
       if (hProof) cmsCloseProfile(hProof);
       
       return 1;
}
示例#10
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;
}
示例#11
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;			
}
示例#12
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;
}
示例#13
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;
}
示例#14
0
static YOPTIMIZE_SPEED int
decompress_jpeg(struct jpeg_decompress_struct *cinfo,
                struct jpeg_compress_struct *cinfoout, JCOPY_OPTION copyoption,
                Vbitmap *vbitmap, YmagineFormatOptions *options)
{
  int scanlines;
  int nlines;
  int totallines;
  int j;
  int scalenum = -1;
  JSAMPARRAY buffer;
  Vrect srcrect;
  Vrect destrect;
  size_t row_stride;
  Transformer *transformer;
  PixelShader *shader = NULL;
  int iwidth, iheight;
  float sharpen = 0.0f;

  if (vbitmap == NULL && cinfoout == NULL) {
    /* No output specified */
    return 0;
  }
  if (options == NULL) {
    /* Options argument is mandatory */
    return 0;
  }

  iwidth = cinfo->image_width;
  iheight = cinfo->image_height;

  if (YmaginePrepareTransform(vbitmap, options,
                              iwidth, iheight,
                              &srcrect, &destrect) != YMAGINE_OK) {
    return 0;
  }

  shader = options->pixelshader;
  sharpen = options->sharpen;

  /* Define if image can be pre-subsampled by a ratio n/8 (n=1..7) */
  scalenum = GetScaleNum(destrect.width, destrect.height,
                         srcrect.width, srcrect.height,
                         options->scalemode);
  if (scalenum > 0 && scalenum < 8) {
    cinfo->scale_num = scalenum;
    cinfo->scale_denom = 8;
  }

  /* Compute actual output dimension for image returned by decoder */
  jpeg_calc_output_dimensions(cinfo);

#if YMAGINE_DEBUG_JPEG
  ALOGD("src=%dx%d@%d,%d dst=%dx%d@%d,%d",
        srcrect.width, srcrect.height, srcrect.x, srcrect.y,
        destrect.width, destrect.height, destrect.x, destrect.y);

  ALOGD("size: %dx%d req: %dx%d %s -> scale: %d/%d output: %dx%d components: %d",
        iwidth, iheight,
        destrect.width, destrect.height,
        Ymagine_scaleModeStr(options->scalemode),
        cinfo->scale_num, cinfo->scale_denom,
        cinfo->output_width, cinfo->output_height,
        cinfo->output_components);
#endif

  /* Scale the crop region to reflect scaling ratio applied by JPEG decoder */
  if (cinfo->image_width != cinfo->output_width) {
    srcrect.x = (srcrect.x * cinfo->output_width) / cinfo->image_width;
    srcrect.width = (srcrect.width * cinfo->output_width) / cinfo->image_width;
  }
  if (cinfo->image_height != cinfo->output_height) {
    srcrect.y = (srcrect.y * cinfo->output_height) / cinfo->image_height;
    srcrect.height = (srcrect.height * cinfo->output_height) / cinfo->image_height;
  }

  /* Number of scan lines to handle per pass. Making it larger actually doesn't help much */
  row_stride = cinfo->output_width * cinfo->output_components;
  scanlines = (32 * 1024) / row_stride;
  if (scanlines < 1) {
    scanlines = 1;
  }
  if (scanlines > cinfo->output_height) {
    scanlines = cinfo->output_height;
  }

#if YMAGINE_DEBUG_JPEG
  ALOGD("BITMAP @(%d,%d) %dx%d bpp=%d -> @(%dx%d) %dx%d (%d lines)",
        srcrect.x, srcrect.y, srcrect.width, srcrect.height, JpegPixelSize(cinfo->out_color_space),
        destrect.x, destrect.y, destrect.width, destrect.height,
        scanlines);
#endif

  /* Resize encoder */
  if (cinfoout != NULL) {
    cinfoout->image_width = destrect.width;
    cinfoout->image_height = destrect.height;
    jpeg_start_compress(cinfoout, TRUE);
    if (copyoption != JCOPYOPT_NONE) {
      /* Copy to the output file any extra markers that we want to preserve */
      jcopy_markers_execute(cinfo, cinfoout, copyoption);
    }
  }

  /* Resize target bitmap */
  if (vbitmap != NULL) {
    if (options->resizable) {
      destrect.x = 0;
      destrect.y = 0;
      if (VbitmapResize(vbitmap, destrect.width, destrect.height) != YMAGINE_OK) {
        return 0;
      }
    }
    if (VbitmapType(vbitmap) == VBITMAP_NONE) {
      /* Decode bounds only, return positive number (number of lines) on success */
      return VbitmapHeight(vbitmap);
    }
  }

  if (!jpeg_start_decompress(cinfo)) {
    if (cinfoout != NULL) {
      jpeg_abort_compress(cinfoout);
    }
    return 0;
  }
  
  buffer = (JSAMPARRAY) (*cinfo->mem->alloc_sarray)((j_common_ptr) cinfo, JPOOL_IMAGE,
                                                    row_stride, scanlines);
  if (buffer == NULL) {
    if (cinfoout != NULL) {
      jpeg_abort_compress(cinfoout);
    }
    jpeg_abort_decompress(cinfo);
    return 0;
  }
  
  totallines = 0;
  
  transformer = TransformerCreate();
  if (transformer != NULL) {
    TransformerSetScale(transformer,
                        cinfo->output_width, cinfo->output_height,
                        destrect.width, destrect.height);
    TransformerSetRegion(transformer,
                         srcrect.x, srcrect.y, srcrect.width, srcrect.height);

    if (vbitmap != NULL) {
      TransformerSetMode(transformer, JpegPixelMode(cinfo->out_color_space), VbitmapColormode(vbitmap));
      TransformerSetBitmap(transformer, vbitmap, destrect.x, destrect.y);
    } else {
      TransformerSetMode(transformer, JpegPixelMode(cinfo->out_color_space),
                         JpegPixelMode(cinfoout->in_color_space));
      TransformerSetWriter(transformer, JpegWriter, cinfoout);
    }
    TransformerSetShader(transformer, shader);
    TransformerSetSharpen(transformer, sharpen);
  }

  while (transformer != NULL && cinfo->output_scanline < cinfo->output_height) {
    nlines = jpeg_read_scanlines(cinfo, buffer, scanlines);
    if (nlines <= 0) {
      /* Decoding error */
      ALOGD("decoding error (nlines=%d)", nlines);
      break;
    }

    for (j = 0; j < nlines; j++) {
      if (TransformerPush(transformer, (const char*) buffer[j]) != YMAGINE_OK) {
        TransformerRelease(transformer);
        transformer = NULL;
        break;
      }
      totallines++;
    }
  }

  /* Clean up */
  if (transformer != NULL) {
    TransformerRelease(transformer);
  }
  if (cinfo->output_scanline > 0 && cinfo->output_scanline == cinfo->output_height) {
    /* Do normal cleanup if whole image has been read and decoded */
    jpeg_finish_decompress(cinfo);
    if (cinfoout != NULL) {
      jpeg_finish_compress(cinfoout);
    }
  }
  else {
    /* else early abort */
    jpeg_abort_decompress(cinfo);
    if (cinfoout != NULL) {
      jpeg_abort_compress(cinfoout);
    }
    totallines = 0;
  }
  
  return totallines;
}
示例#15
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;
}