コード例 #1
0
ファイル: imgscale.c プロジェクト: ender672/liboil
static void prepare_jpeg_decompress(FILE *input,
	struct jpeg_decompress_struct *dinfo, struct jpeg_error_mgr *jerr)
{
	long i;

	dinfo->err = jpeg_std_error(jerr);
	jpeg_create_decompress(dinfo);
	jpeg_stdio_src(dinfo, input);

	/* Save custom headers for the compressor, but ignore APP0 & APP14 so
	 * libjpeg can handle them.
	 */
	jpeg_save_markers(dinfo, JPEG_COM, 0xFFFF);
	for (i=1; i<14; i++) {
		jpeg_save_markers(dinfo, JPEG_APP0+i, 0xFFFF);
	}
	jpeg_save_markers(dinfo, JPEG_APP0+15, 0xFFFF);
	jpeg_read_header(dinfo, TRUE);

	/* For testing purposes, you can run with the environment variable
	 * OILRGBX in order to trigger libjpeg turbo's JCS_RGBX color space.
	 */
#ifdef JCS_EXTENSIONS
	if (getenv("OILRGBX") != NULL && dinfo->out_color_space == JCS_RGB) {
		dinfo->out_color_space = JCS_EXT_RGBX;
		jpeg_calc_output_dimensions(dinfo);
	}
#endif

	jpeg_start_decompress(dinfo);
}
コード例 #2
0
ファイル: jpeg2vips.c プロジェクト: Jondeen/libvips
/* Read the jpeg from file or buffer.
 */
static int
vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
{
	/* Need to read in APP1 (EXIF metadata), APP2 (ICC profile), APP13
	 * (photoshop IPCT).
	 */
	jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 1, 0xffff );
	jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 2, 0xffff );
	jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 13, 0xffff );

	/* Convert!
	 */
	if( header_only ) {
		if( read_jpeg_header( jpeg, out ) )
			return( -1 ); 

		/* Swap width and height if we're going to rotate this image.
		 */
		if( jpeg->autorotate ) { 
			VipsAngle angle = vips_autorot_get_angle( out ); 

			if( angle == VIPS_ANGLE_D90 || 
				angle == VIPS_ANGLE_D270 )
				VIPS_SWAP( int, out->Xsize, out->Ysize );

			/* We won't be returning an orientation tag.
			 */
			(void) vips_image_remove( out, ORIENTATION );
		}
	}
コード例 #3
0
static void save_jpg_markers(struct jpeg_decompress_struct *cinfo)
{
	/* Comment marker */
	jpeg_save_markers(cinfo, JPEG_COM, JPEG_COM_MAX);

	/* APP0 marker = JFIF data */
	jpeg_save_markers(cinfo, JPEG_APP0 + 1, 0xffff);

	/* APP1 marker = Exif data */
	jpeg_save_markers(cinfo, JPEG_APP0 + 1, 0xffff);
}
コード例 #4
0
ファイル: epeg.c プロジェクト: clones/kaa
static Epeg_Image *
_epeg_open_header(Epeg_Image *im)
{
   struct jpeg_source_mgr *src_mgr = NULL;

   im->in.jinfo.err = jpeg_std_error(&(im->jerr.pub));
   im->jerr.pub.error_exit = _epeg_fatal_error_handler;

   if (setjmp(im->jerr.setjmp_buffer))
     {
	error:
	epeg_close(im);
	im = NULL;
	return NULL;
     }

   jpeg_create_decompress(&(im->in.jinfo));
   jpeg_save_markers(&(im->in.jinfo), JPEG_APP0 + 7, 1024);
   jpeg_save_markers(&(im->in.jinfo), JPEG_COM,      65535);
   if (im->in.f != NULL)
     {
	jpeg_stdio_src(&(im->in.jinfo), im->in.f);
     }
   else
     {
	/* Setup RAM source manager. */
	src_mgr = calloc(1, sizeof(struct jpeg_source_mgr));
	if (!src_mgr) goto error;
	src_mgr->init_source = _jpeg_init_source;
	src_mgr->fill_input_buffer = _jpeg_fill_input_buffer;
	src_mgr->skip_input_data = _jpeg_skip_input_data;
	src_mgr->resync_to_restart = jpeg_resync_to_restart;
	src_mgr->term_source = _jpeg_term_source;
	src_mgr->bytes_in_buffer = im->in.mem.size;
	src_mgr->next_input_byte = (JOCTET *) im->in.mem.data;
   	im->in.jinfo.src = (struct jpeg_source_mgr *) src_mgr;
     }

   jpeg_read_header(&(im->in.jinfo), TRUE);
   im->in.w = im->in.jinfo.image_width;
   im->in.h = im->in.jinfo.image_height;
   if (im->in.w < 1) goto error;
   if (im->in.h < 1) goto error;

   im->out.w = im->in.w;
   im->out.h = im->in.h;

   im->color_space = ((im->in.color_space = im->in.jinfo.out_color_space) == JCS_GRAYSCALE) ? EPEG_GRAY8 : EPEG_RGB8;
   if (im->in.color_space == JCS_CMYK) im->color_space = EPEG_CMYK;
   return im;
}
コード例 #5
0
ファイル: transupp.cpp プロジェクト: gamman/MRPT
jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option)
{
#ifdef SAVE_MARKERS_SUPPORTED
  int m;

  /* Save comments except under NONE option */
  if (option != JCOPYOPT_NONE) {
    jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
  }
  /* Save all types of APPn markers iff ALL option */
  if (option == JCOPYOPT_ALL) {
    for (m = 0; m < 16; m++)
      jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
  }
#endif /* SAVE_MARKERS_SUPPORTED */
}
コード例 #6
0
ファイル: jpgicc.c プロジェクト: etlegacy/EasyGen
static
cmsBool OpenInput(const char* FileName)
{
	int m;

	lIsITUFax = FALSE;
	InFile  = fopen(FileName, "rb");
	if (InFile == NULL) {
		FatalError("Cannot open '%s'", FileName);
	}

	// Now we can initialize the JPEG decompression object.
	Decompressor.err                 = jpeg_std_error(&ErrorHandler.pub);
	ErrorHandler.pub.error_exit      = my_error_exit;
	ErrorHandler.pub.output_message  = my_error_exit;

	jpeg_create_decompress(&Decompressor);
	jpeg_stdio_src(&Decompressor, InFile);

	for (m = 0; m < 16; m++)
		jpeg_save_markers(&Decompressor, JPEG_APP0 + m, 0xFFFF);

	// setup_read_icc_profile(&Decompressor);

	fseek(InFile, 0, SEEK_SET);
	jpeg_read_header(&Decompressor, TRUE);

	return TRUE;
}
コード例 #7
0
ファイル: jpegtopnm.c プロジェクト: Eleanor66613/CS131
static void
saveMarkers(struct jpeg_decompress_struct * const cinfoP) {

    unsigned int app_type;
    /* Get all the miscellaneous markers (COM and APPn) saved for our
       later access.
    */
    jpeg_save_markers(cinfoP, JPEG_COM, 65535);
    for (app_type = 0; app_type <= 15; ++app_type) {
        if (app_type == 0 || app_type == 14) {
            /* The jpeg library uses APP0 and APP14 internally (see
               libjpeg.doc), so we don't mess with those.
            */
        } else
            jpeg_save_markers(cinfoP, JPEG_APP0 + app_type, 65535);
    }
}
コード例 #8
0
ファイル: jpeg2vips.c プロジェクト: jieah/libvips
/* Read a JPEG file into a VIPS image.
 */
int
vips__jpeg_read_file( const char *filename, VipsImage *out,
                      gboolean header_only, int shrink, gboolean fail )
{
    ReadJpeg *jpeg;
    int result;

    if( !(jpeg = readjpeg_new( out, shrink, fail )) )
        return( -1 );

    /* Here for longjmp() from vips__new_error_exit() during startup.
     */
    if( setjmp( jpeg->eman.jmp ) ) {
        (void) readjpeg_free( jpeg );

        return( -1 );
    }

    /* Set input to file.
     */
    if( readjpeg_file( jpeg, filename ) ) {
        (void) readjpeg_free( jpeg );

        return( -1 );
    }

    /* Need to read in APP1 (EXIF metadata), APP2 (ICC profile), APP13
     * (photoshop IPCT).
     */
    jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 1, 0xffff );
    jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 2, 0xffff );
    jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 13, 0xffff );

    /* Convert!
     */
    if( header_only )
        result = read_jpeg_header( jpeg, out );
    else
        result = read_jpeg_image( jpeg, out );

    /* Don't call readjpeg_free(), we're probably still live.
     */

    return( result );
}
コード例 #9
0
ファイル: im_jpeg2vips.c プロジェクト: aturcotte/libvips
/**
 * im_bufjpeg2vips:
 * @buf: memory area to load
 * @len: size of memory area
 * @out: image to write
 * @header_only: set to just read the header
 *
 * Read a JPEG-formatted memory block into a VIPS image. It can read most 
 * 8-bit JPEG images, including CMYK and YCbCr.
 *
 * This function is handy for processing JPEG image thumbnails.
 *
 * See also: #VipsFormat, im_jpeg2vips().
 *
 * Returns: 0 on success, -1 on error.
 */
int
im_bufjpeg2vips( void *buf, size_t len, IMAGE *out, gboolean header_only )
{
	struct jpeg_decompress_struct cinfo;
        ErrorManager eman;
	int result;
	gboolean invert_pels;

	/* Make jpeg dcompression object.
 	 */
        cinfo.err = jpeg_std_error( &eman.pub );
	eman.pub.error_exit = new_error_exit;
	eman.pub.output_message = new_output_message;
	eman.fp = NULL;
	if( setjmp( eman.jmp ) ) {
		/* Here for longjmp() from new_error_exit().
		 */
		jpeg_destroy_decompress( &cinfo );

		return( -1 );
	}
        jpeg_create_decompress( &cinfo );

	/* Make input.
	 */
	buf_source( &cinfo, buf, len );

	/* Need to read in APP1 (EXIF metadata) and APP2 (ICC profile).
	 */
	jpeg_save_markers( &cinfo, JPEG_APP0 + 1, 0xffff );
	jpeg_save_markers( &cinfo, JPEG_APP0 + 2, 0xffff );

	/* Convert!
	 */
	result = read_jpeg_header( &cinfo, out, &invert_pels, 1 );
	if( !header_only && !result )
		result = read_jpeg_image( &cinfo, out, invert_pels );

	/* Close and tidy.
	 */
	jpeg_destroy_decompress( &cinfo );

	return( result );
}
コード例 #10
0
static FX_BOOL _JpegLoadInfo(FX_LPCBYTE src_buf, FX_DWORD src_size, int& width, int& height,
                             int& num_components, int& bits_per_components, FX_BOOL& color_transform,
                             FX_LPBYTE* icc_buf_ptr, FX_DWORD* icc_length)
{
    _JpegScanSOI(src_buf, src_size);
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    jerr.error_exit = _error_fatal;
    jerr.emit_message = _error_do_nothing1;
    jerr.output_message = _error_do_nothing;
    jerr.format_message = _error_do_nothing2;
    jerr.reset_error_mgr = _error_do_nothing;
    jerr.trace_level = 0;
    cinfo.err = &jerr;
    jmp_buf mark;
    cinfo.client_data = &mark;
    if (setjmp(mark) == -1) {
        return FALSE;
    }
    jpeg_create_decompress(&cinfo);
    struct jpeg_source_mgr src;
    src.init_source = _src_do_nothing;
    src.term_source = _src_do_nothing;
    src.skip_input_data = _src_skip_data;
    src.fill_input_buffer = _src_fill_buffer;
    src.resync_to_restart = _src_resync;
    src.bytes_in_buffer = src_size;
    src.next_input_byte = src_buf;
    cinfo.src = &src;
    if (setjmp(mark) == -1) {
        jpeg_destroy_decompress(&cinfo);
        return FALSE;
    }
    if(icc_buf_ptr && icc_length) {
        jpeg_save_markers(&cinfo, JPEG_MARKER_ICC, JPEG_MARKER_MAXSIZE);
    }
    int ret = jpeg_read_header(&cinfo, TRUE);
    if (ret != JPEG_HEADER_OK) {
        jpeg_destroy_decompress(&cinfo);
        return FALSE;
    }
    width = cinfo.image_width;
    height = cinfo.image_height;
    num_components = cinfo.num_components;
    color_transform = cinfo.jpeg_color_space == JCS_YCbCr || cinfo.jpeg_color_space == JCS_YCCK;
    bits_per_components = cinfo.data_precision;
    if(icc_buf_ptr != NULL) {
        *icc_buf_ptr = NULL;
    }
    if(icc_length != NULL) {
        *icc_length = 0;
    }
    jpeg_destroy_decompress(&cinfo);
    return TRUE;
}
コード例 #11
0
ファイル: jpeg2vips.c プロジェクト: jieah/libvips
int
vips__jpeg_read_buffer( void *buf, size_t len, VipsImage *out,
                        gboolean header_only, int shrink, int fail )
{
    ReadJpeg *jpeg;
    int result;

    if( !(jpeg = readjpeg_new( out, shrink, fail )) )
        return( -1 );

    if( setjmp( jpeg->eman.jmp ) ) {
        (void) readjpeg_free( jpeg );

        return( -1 );
    }

    /* Set input to buffer.
     */
    readjpeg_buffer( jpeg, buf, len );

    /* Need to read in APP1 (EXIF metadata) and APP2 (ICC profile).
     */
    jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 1, 0xffff );
    jpeg_save_markers( &jpeg->cinfo, JPEG_APP0 + 2, 0xffff );

    /* Convert!
     */
    if( header_only )
        result = read_jpeg_header( jpeg, out );
    else
        result = read_jpeg_image( jpeg, out );

    /* Don't call readjpeg_free(), we're probably still live.
     */

    return( result );
}
コード例 #12
0
void ScImgDataLoader_JPEG::loadEmbeddedProfile(const QString& fn, int /*page*/)
{
	m_embeddedProfile.resize(0);
	m_profileComponents = 0;
	if (!QFile::exists(fn))
		return;
	struct jpeg_decompress_struct cinfo;
	struct my_error_mgr         jerr;
	FILE     *infile;
	cinfo.err = jpeg_std_error (&jerr.pub);
	jerr.pub.error_exit = my_error_exit;
	infile = NULL;
	if (setjmp (jerr.setjmp_buffer))
	{
		jpeg_destroy_decompress (&cinfo);
		if (infile)
			fclose (infile);
		return;
	}
	jpeg_create_decompress (&cinfo);
	if ((infile = fopen (fn.toLocal8Bit(), "rb")) == NULL)
		return;
	jpeg_stdio_src(&cinfo, infile);
	jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
	jpeg_read_header(&cinfo, true);
	//jpeg_start_decompress(&cinfo);
	unsigned int EmbedLen = 0;
	unsigned char* EmbedBuffer;
	if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
	{
		cmsHPROFILE prof = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
		if (prof)
		{
			if (static_cast<int>(cmsGetColorSpace(prof)) == icSigRgbData)
				m_profileComponents = 3;
			if (static_cast<int>(cmsGetColorSpace(prof)) == icSigCmykData)
				m_profileComponents = 4;
			if (static_cast<int>(cmsGetColorSpace(prof)) == icSigGrayData)
				m_profileComponents = 1;
			m_embeddedProfile = QByteArray((const char*) EmbedBuffer, EmbedLen);
		}
		cmsCloseProfile(prof);
		free(EmbedBuffer);
	}
	//(void) jpeg_finish_decompress(&cinfo);
	fclose (infile);
	jpeg_destroy_decompress (&cinfo);
}
コード例 #13
0
void ScImgDataLoader_JPEG::loadEmbeddedProfile(const QString& fn, int /*page*/)
{
	m_embeddedProfile.resize(0);
	m_profileComponents = 0;
	if (!QFile::exists(fn))
		return;
	struct jpeg_decompress_struct cinfo;
	struct my_error_mgr         jerr;
	FILE     *infile;
	cinfo.err = jpeg_std_error (&jerr.pub);
	jerr.pub.error_exit = my_error_exit;
	infile = NULL;
	if (setjmp (jerr.setjmp_buffer))
	{
		jpeg_destroy_decompress (&cinfo);
		if (infile)
			fclose (infile);
		return;
	}
	jpeg_create_decompress (&cinfo);
	if ((infile = fopen (fn.toLocal8Bit(), "rb")) == NULL)
		return;
	jpeg_stdio_src(&cinfo, infile);
	jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
	jpeg_read_header(&cinfo, true);
	unsigned int EmbedLen = 0;
	unsigned char* EmbedBuffer;
	if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
	{
		QByteArray profArray = QByteArray((const char*) EmbedBuffer, EmbedLen);
		ScColorProfile prof  = ScColorMgmtEngine::openProfileFromMem(profArray);
		if (prof)
		{
			if (prof.colorSpace() == ColorSpace_Rgb)
				m_profileComponents = 3;
			if (prof.colorSpace() == ColorSpace_Cmyk)
				m_profileComponents = 4;
			if (prof.colorSpace() == ColorSpace_Gray)
				m_profileComponents = 1;
			m_embeddedProfile = profArray;
		}
		free(EmbedBuffer);
	}
	fclose (infile);
	jpeg_destroy_decompress (&cinfo);
}
コード例 #14
0
    JPEGImageReader(JPEGImageDecoder* decoder)
        : m_decoder(decoder)
        , m_bufferLength(0)
        , m_bytesToSkip(0)
        , m_state(JPEG_HEADER)
        , m_samples(0)
#if USE(QCMSLIB)
        , m_transform(0)
#endif
    {
        memset(&m_info, 0, sizeof(jpeg_decompress_struct));

        // We set up the normal JPEG error routines, then override error_exit.
        m_info.err = jpeg_std_error(&m_err.pub);
        m_err.pub.error_exit = error_exit;

        // Allocate and initialize JPEG decompression object.
        jpeg_create_decompress(&m_info);

        decoder_source_mgr* src = 0;
        if (!m_info.src) {
            src = (decoder_source_mgr*)fastZeroedMalloc(sizeof(decoder_source_mgr));
            if (!src) {
                m_state = JPEG_ERROR;
                return;
            }
        }

        m_info.src = (jpeg_source_mgr*)src;

        // Set up callback functions.
        src->pub.init_source = init_source;
        src->pub.fill_input_buffer = fill_input_buffer;
        src->pub.skip_input_data = skip_input_data;
        src->pub.resync_to_restart = jpeg_resync_to_restart;
        src->pub.term_source = term_source;
        src->decoder = this;

#if USE(ICCJPEG)
        // Retain ICC color profile markers for color management.
        setup_read_icc_profile(&m_info);
#endif

        // Keep APP1 blocks, for obtaining exif data.
        jpeg_save_markers(&m_info, exifMarker, 0xFFFF);
    }
コード例 #15
0
    JPEGImageReader(JPEGImageDecoder* decoder)
        : m_decoder(decoder)
        , m_bufferLength(0)
        , m_bytesToSkip(0)
        , m_state(JPEG_HEADER)
        , m_samples(0)
    {
        memset(&m_info, 0, sizeof(jpeg_decompress_struct));
 
        // We set up the normal JPEG error routines, then override error_exit.
        m_info.err = jpeg_std_error(&m_err.pub);
        m_err.pub.error_exit = error_exit;

        // Allocate and initialize JPEG decompression object.
        jpeg_create_decompress(&m_info);
  
        decoder_source_mgr* src = 0;
        if (!m_info.src) {
            src = (decoder_source_mgr*)fastCalloc(sizeof(decoder_source_mgr), 1);
            if (!src) {
                m_state = JPEG_ERROR;
                return;
            }
        }

        m_info.src = (jpeg_source_mgr*)src;

        // Set up callback functions.
        src->pub.init_source = init_source;
        src->pub.fill_input_buffer = fill_input_buffer;
        src->pub.skip_input_data = skip_input_data;
        src->pub.resync_to_restart = jpeg_resync_to_restart;
        src->pub.term_source = term_source;
        src->decoder = this;

        // Enable these markers for the ICC color profile.
        // Apparently there are 16 of these markers.  I don't see anywhere in the header with this constant.
        for (unsigned i = 0; i < 0xF; ++i)
            jpeg_save_markers(&m_info, JPEG_APP0 + i, 0xFFFF);
    }
コード例 #16
0
void
nsJPEGDecoder::InitInternal()
{
  mCMSMode = gfxPlatform::GetCMSMode();
  if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
    mCMSMode = eCMSMode_Off;

  /* We set up the normal JPEG error routines, then override error_exit. */
  mInfo.err = jpeg_std_error(&mErr.pub);
  /*   mInfo.err = jpeg_std_error(&mErr.pub); */
  mErr.pub.error_exit = my_error_exit;
  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp(mErr.setjmp_buffer)) {
    /* If we get here, the JPEG code has signaled an error.
     * We need to clean up the JPEG object, close the input file, and return.
     */
    PostDecoderError(NS_ERROR_FAILURE);
    return;
  }

  /* Step 1: allocate and initialize JPEG decompression object */
  jpeg_create_decompress(&mInfo);
  /* Set the source manager */
  mInfo.src = &mSourceMgr;

  /* Step 2: specify data source (eg, a file) */

  /* Setup callback functions. */
  mSourceMgr.init_source = init_source;
  mSourceMgr.fill_input_buffer = fill_input_buffer;
  mSourceMgr.skip_input_data = skip_input_data;
  mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
  mSourceMgr.term_source = term_source;

  /* Record app markers for ICC data */
  for (uint32_t m = 0; m < 16; m++)
    jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
}
コード例 #17
0
ファイル: jpeg.c プロジェクト: CaptainSifff/darktable
void
setup_read_icc_profile (j_decompress_ptr cinfo)
{
  /* Tell the library to keep any APP2 data it may find */
  jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
}
コード例 #18
0
ファイル: jpeginput.cpp プロジェクト: ElaraFX/oiio
bool
JpgInput::open (const std::string &name, ImageSpec &newspec)
{
    // Check that file exists and can be opened
    m_filename = name;
    m_fd = Filesystem::fopen (name, "rb");
    if (m_fd == NULL) {
        error ("Could not open file \"%s\"", name.c_str());
        return false;
    }

    // Check magic number to assure this is a JPEG file
    uint8_t magic[2] = {0, 0};
    if (fread (magic, sizeof(magic), 1, m_fd) != 1) {
        error ("Empty file \"%s\"", name.c_str());
        close_file ();
        return false;
    }

    rewind (m_fd);
    if (magic[0] != JPEG_MAGIC1 || magic[1] != JPEG_MAGIC2) {
        close_file ();
        error ("\"%s\" is not a JPEG file, magic number doesn't match (was 0x%x%x)",
               name.c_str(), int(magic[0]), int(magic[1]));
        return false;
    }

    // Set up the normal JPEG error routines, then override error_exit and
    // output_message so we intercept all the errors.
    m_cinfo.err = jpeg_std_error ((jpeg_error_mgr *)&m_jerr);
    m_jerr.pub.error_exit = my_error_exit;
    m_jerr.pub.output_message = my_output_message;
    if (setjmp (m_jerr.setjmp_buffer)) {
        // Jump to here if there's a libjpeg internal error
        // Prevent memory leaks, see example.c in jpeg distribution
        jpeg_destroy_decompress (&m_cinfo);
        close_file ();
        return false;
    }

    jpeg_create_decompress (&m_cinfo);          // initialize decompressor
    jpeg_stdio_src (&m_cinfo, m_fd);            // specify the data source

    // Request saving of EXIF and other special tags for later spelunking
    for (int mark = 0;  mark < 16;  ++mark)
        jpeg_save_markers (&m_cinfo, JPEG_APP0+mark, 0xffff);
    jpeg_save_markers (&m_cinfo, JPEG_COM, 0xffff);     // comment marker

    // read the file parameters
    if (jpeg_read_header (&m_cinfo, FALSE) != JPEG_HEADER_OK || m_fatalerr) {
        error ("Bad JPEG header for \"%s\"", filename().c_str());
        return false;
    }

    int nchannels = m_cinfo.num_components;

    if (m_cinfo.jpeg_color_space == JCS_CMYK ||
        m_cinfo.jpeg_color_space == JCS_YCCK) {
        // CMYK jpegs get converted by us to RGB
        m_cinfo.out_color_space = JCS_CMYK;     // pre-convert YCbCrK->CMYK
        nchannels = 3;
        m_cmyk = true;
    }

    if (m_raw)
        m_coeffs = jpeg_read_coefficients (&m_cinfo);
    else
        jpeg_start_decompress (&m_cinfo);       // start working
    if (m_fatalerr)
        return false;
    m_next_scanline = 0;                        // next scanline we'll read

    m_spec = ImageSpec (m_cinfo.output_width, m_cinfo.output_height,
                        nchannels, TypeDesc::UINT8);

    // Assume JPEG is in sRGB unless the Exif or XMP tags say otherwise.
    m_spec.attribute ("oiio:ColorSpace", "sRGB");

    if (m_cinfo.jpeg_color_space == JCS_CMYK)
        m_spec.attribute ("jpeg:ColorSpace", "CMYK");
    else if (m_cinfo.jpeg_color_space == JCS_YCCK)
        m_spec.attribute ("jpeg:ColorSpace", "YCbCrK");

    // If the chroma subsampling is detected and matches something
    // we expect, then set an attribute so that it can be preserved
    // in future operations.
    std::string subsampling = comp_info_to_attr(m_cinfo);
    if (!subsampling.empty())
        m_spec.attribute(JPEG_SUBSAMPLING_ATTR, subsampling);
        
    for (jpeg_saved_marker_ptr m = m_cinfo.marker_list;  m;  m = m->next) {
        if (m->marker == (JPEG_APP0+1) &&
                ! strcmp ((const char *)m->data, "Exif")) {
            // The block starts with "Exif\0\0", so skip 6 bytes to get
            // to the start of the actual Exif data TIFF directory
            decode_exif ((unsigned char *)m->data+6, m->data_length-6, m_spec);
        }
        else if (m->marker == (JPEG_APP0+1) &&
                 ! strcmp ((const char *)m->data, "http://ns.adobe.com/xap/1.0/")) {
#ifndef NDEBUG
            std::cerr << "Found APP1 XMP! length " << m->data_length << "\n";
#endif
            std::string xml ((const char *)m->data, m->data_length);
            decode_xmp (xml, m_spec);
        }
        else if (m->marker == (JPEG_APP0+13) &&
                ! strcmp ((const char *)m->data, "Photoshop 3.0"))
            jpeg_decode_iptc ((unsigned char *)m->data);
        else if (m->marker == JPEG_COM) {
            if (! m_spec.find_attribute ("ImageDescription", TypeDesc::STRING))
                m_spec.attribute ("ImageDescription",
                                  std::string ((const char *)m->data, m->data_length));
        }
    }

    // Handle density/pixelaspect. We need to do this AFTER the exif is
    // decoded, in case it contains useful information.
    float xdensity = m_spec.get_float_attribute ("XResolution");
    float ydensity = m_spec.get_float_attribute ("YResolution");
    if (! xdensity || ! ydensity) {
        xdensity = float(m_cinfo.X_density);
        ydensity = float(m_cinfo.Y_density);
        if (xdensity && ydensity) {
            m_spec.attribute ("XResolution", xdensity);
            m_spec.attribute ("YResolution", ydensity);
        }
    }
    if (xdensity && ydensity) {
        float aspect = ydensity/xdensity;
        if (aspect != 1.0f)
            m_spec.attribute ("PixelAspectRatio", aspect);
        switch (m_cinfo.density_unit) {
        case 0 : m_spec.attribute ("ResolutionUnit", "none"); break;
        case 1 : m_spec.attribute ("ResolutionUnit", "in");   break;
        case 2 : m_spec.attribute ("ResolutionUnit", "cm");   break;
        }
    }

    read_icc_profile(&m_cinfo, m_spec); /// try to read icc profile

    newspec = m_spec;
    return true;
}
コード例 #19
0
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);
		}
		
	}
	
}
コード例 #20
0
unsigned char* simage_jpeg_load(std::istream& fin,
                                int *width_ret,
                                int *height_ret,
                                int *numComponents_ret,
                                unsigned int* exif_orientation)
{
    int width;
    int height;
    unsigned char *currPtr;
    int format;
    /* This struct contains the JPEG decompression parameters and pointers to
     * working space (which is allocated as needed by the JPEG library).
     */
    struct jpeg_decompress_struct cinfo;
    /* We use our private extension JPEG error handler.
     * Note that this struct must live as long as the main JPEG parameter
     * struct, to avoid dangling-pointer problems.
     */
    struct my_error_mgr jerr;
    /* More stuff */
    //FILE * infile;               /* source file */
    JSAMPARRAY rowbuffer;        /* Output row buffer */
    int row_stride;              /* physical row width in output buffer */

    jpegerror = ERR_NO_ERROR;

    /* In this example we want to open the input file before doing anything else,
     * so that the setjmp() error recovery below can assume the file is open.
     * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
     * requires it in order to read binary files.
     */

    /*if ((infile = fopen(filename, "rb")) == NULL)
    {
        jpegerror = ERR_OPEN;
        return NULL;
    }*/

    /* Step 1: allocate and initialize JPEG decompression object */

    /* We set up the normal JPEG error routines, then override error_exit. */
    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;
    jerr.pub.output_message = my_output_message;
    /* Establish the setjmp return context for my_error_exit to use. */
    if (setjmp(jerr.setjmp_buffer))
    {
        /* If we get here, the JPEG code has signaled an error.
         * We need to clean up the JPEG object, close the input file, and return.
         */
        jpegerror = ERR_JPEGLIB;
        jpeg_destroy_decompress(&cinfo);
        //fclose(infile);
        //if (buffer) delete [] buffer;
        return NULL;
    }

    // used to be before setjump above, but have moved to after to avoid compile warnings.
    unsigned char *buffer = NULL;

    /* Now we can initialize the JPEG decompression object. */
    jpeg_create_decompress(&cinfo);

    /* Step 2: specify data source (eg, a file) */

    //jpeg_stdio_src(&cinfo, infile);
    jpeg_istream_src(&cinfo,&fin);



    /* Step 3: read file parameters with jpeg_read_header() */

    jpeg_save_markers (&cinfo, EXIF_JPEG_MARKER, 0xffff);

    (void) jpeg_read_header(&cinfo, TRUE);
    /* We can ignore the return value from jpeg_read_header since
     *   (a) suspension is not possible with the stdio data source, and
     *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
     * See libjpeg.doc for more info.
     */

    /* check for orientation tag */
    *exif_orientation = EXIF_Orientation (&cinfo);
    if (*exif_orientation!=0)
    {
        OSG_INFO<<"We have an EXIF_Orientation "<<exif_orientation<<std::endl;
    }


    /* Step 4: set parameters for decompression */
    /* In this example, we don't need to change any of the defaults set by
     * jpeg_read_header(), so we do nothing here.
     */

    /* Step 5: Start decompressor */
    if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
    {
        format = 1;
        cinfo.out_color_space = JCS_GRAYSCALE;
    }
    else                         /* use rgb */
    {
        format = 3;
        cinfo.out_color_space = JCS_RGB;
    }

    (void) jpeg_start_decompress(&cinfo);
    /* We can ignore the return value since suspension is not possible
     * with the stdio data source.
     */

    /* We may need to do some setup of our own at this point before reading
     * the data.  After jpeg_start_decompress() we have the correct scaled
     * output image dimensions available, as well as the output colormap
     * if we asked for color quantization.
     * In this example, we need to make an output work buffer of the right size.
     */
    /* JSAMPLEs per row in output buffer */
    row_stride = cinfo.output_width * cinfo.output_components;
    /* Make a one-row-high sample array that will go away when done with image */
    rowbuffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
    width = cinfo.output_width;
    height = cinfo.output_height;
    buffer = currPtr = new unsigned char [width*height*cinfo.output_components];

    /* Step 6: while (scan lines remain to be read) */
    /*           jpeg_read_scanlines(...); */

    /* Here we use the library's state variable cinfo.output_scanline as the
     * loop counter, so that we don't have to keep track ourselves.
     */

    /* flip image upside down */
    if (buffer)
    {
        currPtr = buffer + row_stride * (cinfo.output_height-1);

        while (cinfo.output_scanline < cinfo.output_height)
        {
            /* jpeg_read_scanlines expects an array of pointers to scanlines.
             * Here the array is only one element long, but you could ask for
             * more than one scanline at a time if that's more convenient.
             */
            (void) jpeg_read_scanlines(&cinfo, rowbuffer, 1);
            /* Assume put_scanline_someplace wants a pointer and sample count. */
            currPtr = copyScanline(currPtr, rowbuffer[0], row_stride);
        }
    }
    /* Step 7: Finish decompression */

    (void) jpeg_finish_decompress(&cinfo);
    /* We can ignore the return value since suspension is not possible
     * with the stdio data source.
     */

    /* Step 8: Release JPEG decompression object */

    /* This is an important step since it will release a good deal of memory. */
    jpeg_destroy_decompress(&cinfo);

    /* After finish_decompress, we can close the input file.
     * Here we postpone it until after no more JPEG errors are possible,
     * so as to simplify the setjmp error logic above.  (Actually, I don't
     * think that jpeg_destroy can do an error exit, but why assume anything...)
     */
    //fclose(infile);

    /* At this point you may want to check to see whether any corrupt-data
     * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
     */

    /* And we're done! */
    if (buffer)
    {
        *width_ret = width;
        *height_ret = height;
        *numComponents_ret = format;
    }
    else
    {
        jpegerror = ERR_MEM;
    }
    return buffer;
}
コード例 #21
0
ファイル: epeg_main.c プロジェクト: bohwaz/epeg-transform
static Epeg_Image *
_epeg_open_header(Epeg_Image *im) {
    struct jpeg_marker_struct *m;
    struct jpeg_source_mgr *src_mgr = NULL;

    im->in.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)) {
error:
        epeg_close(im);
        im = NULL;
        return NULL;
    }

    jpeg_create_decompress(&(im->in.jinfo));
    jpeg_save_markers(&(im->in.jinfo), JPEG_APP0 + 7, 1024);
    jpeg_save_markers(&(im->in.jinfo), JPEG_COM,      65535);
    if (im->in.f != NULL) {
        jpeg_stdio_src(&(im->in.jinfo), im->in.f);
    } else {
        /* Setup RAM source manager. */
        src_mgr = calloc(1, sizeof(struct jpeg_source_mgr));
        if (!src_mgr) {
            goto error;
        }
        src_mgr->init_source = _jpeg_init_source;
        src_mgr->fill_input_buffer = _jpeg_fill_input_buffer;
        src_mgr->skip_input_data = _jpeg_skip_input_data;
        src_mgr->resync_to_restart = jpeg_resync_to_restart;
        src_mgr->term_source = _jpeg_term_source;
        src_mgr->bytes_in_buffer = im->in.mem.size;
        src_mgr->next_input_byte = (JOCTET *) im->in.mem.data;
        im->in.jinfo.src = (struct jpeg_source_mgr *) src_mgr;
    }

    jpeg_read_header(&(im->in.jinfo), TRUE);
    im->in.w = im->in.jinfo.image_width;
    im->in.h = im->in.jinfo.image_height;
    if (im->in.w < 1) {
        goto error;
    }
    if (im->in.h < 1) {
        goto error;
    }

    im->out.w = im->in.w;
    im->out.h = im->in.h;

    im->color_space = ((im->in.color_space = im->in.jinfo.out_color_space) == JCS_GRAYSCALE) ? EPEG_GRAY8 : EPEG_RGB8;
    if (im->in.color_space == JCS_CMYK) {
        im->color_space = EPEG_CMYK;
    }

    for (m = im->in.jinfo.marker_list; m; m = m->next) {
        if (m->marker == JPEG_COM) {
            if (im->in.comment) {
                free(im->in.comment);
            }
            im->in.comment = malloc(m->data_length + 1);
            if (im->in.comment) {
                memcpy(im->in.comment, m->data, m->data_length);
                im->in.comment[m->data_length] = 0;
            }
        } else if (m->marker == (JPEG_APP0 + 7)) {
            if ((m->data_length > 7) &&
                    (!strncmp((char *)m->data, "Thumb::", 7))) {
                char *p, *p2;

                p = malloc(m->data_length + 1);
                if (p) {
                    memcpy(p, m->data, m->data_length);
                    p[m->data_length] = 0;
                    p2 = strchr(p, '\n');
                    if (p2) {
                        p2[0] = 0;
                        if (!strcmp(p, "Thumb::URI"))

                        {
                            im->in.thumb_info.uri = strdup(p2 + 1);
                        } else if (!strcmp(p, "Thumb::MTime")) {
                            sscanf(p2 + 1, "%llu", &(im->in.thumb_info.mtime));
                        } else if (!strcmp(p, "Thumb::Image::Width")) {
                            im->in.thumb_info.w = atoi(p2 + 1);
                        } else if (!strcmp(p, "Thumb::Image::Height")) {
                            im->in.thumb_info.h = atoi(p2 + 1);
                        } else if (!strcmp(p, "Thumb::Mimetype")) {
                            im->in.thumb_info.mime = strdup(p2 + 1);
                        }
                    }
                    free(p);
                }
            }
        }
    }
    return im;
}
コード例 #22
0
// returns w and h and tw and th and comment as a convenience
static bool verify_jpeg(FILE *f, int32_t *w, int32_t *h,
			int32_t *tw, int32_t *th,
			char **comment, GError **err) {
  struct jpeg_decompress_struct cinfo;
  struct _openslide_jpeg_error_mgr jerr;
  jmp_buf env;
  bool success = false;

  *w = 0;
  *h = 0;
  *tw = 0;
  *th = 0;

  if (comment) {
    *comment = NULL;
  }

  if (setjmp(env) == 0) {
    cinfo.err = _openslide_jpeg_set_error_handler(&jerr, &env);
    jpeg_create_decompress(&cinfo);
    _openslide_jpeg_stdio_src(&cinfo, f);

    int header_result;

    if (comment) {
      // extract comment
      jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
    }

    header_result = jpeg_read_header(&cinfo, TRUE);
    if (header_result != JPEG_HEADER_OK
        && header_result != JPEG_HEADER_TABLES_ONLY) {
      g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA,
                  "Couldn't read JPEG header");
      goto DONE;
    }
    if (cinfo.num_components != 3) {
      g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA,
                  "JPEG color components != 3");
      goto DONE;
    }
    if (cinfo.restart_interval == 0) {
      g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA,
                  "No restart markers");
      goto DONE;
    }

    jpeg_start_decompress(&cinfo);

    if (comment) {
      if (cinfo.marker_list) {
	// copy everything out
	char *com = g_strndup((const gchar *) cinfo.marker_list->data,
			      cinfo.marker_list->data_length);
	// but only really save everything up to the first '\0'
	*comment = g_strdup(com);
	g_free(com);
      }
      jpeg_save_markers(&cinfo, JPEG_COM, 0);  // stop saving
    }

    *w = cinfo.output_width;
    *h = cinfo.output_height;

    if (cinfo.restart_interval > cinfo.MCUs_per_row) {
      g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA,
                  "Restart interval greater than MCUs per row");
      goto DONE;
    }

    *tw = *w / (cinfo.MCUs_per_row / cinfo.restart_interval);
    *th = *h / cinfo.MCU_rows_in_scan;
    int leftover_mcus = cinfo.MCUs_per_row % cinfo.restart_interval;
    if (leftover_mcus != 0) {
      g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA,
                  "Inconsistent restart marker spacing within row");
      goto DONE;
    }


    //  g_debug("w: %d, h: %d, restart_interval: %d\n"
    //	 "mcus_per_row: %d, mcu_rows_in_scan: %d\n"
    //	 "leftover mcus: %d",
    //	 cinfo.output_width, cinfo.output_height,
    //	 cinfo.restart_interval,
    //	 cinfo.MCUs_per_row, cinfo.MCU_rows_in_scan,
    //	 leftover_mcus);
  } else {
    // setjmp has returned again
    g_propagate_error(err, jerr.err);
    goto DONE;
  }

  success = true;

DONE:
  jpeg_destroy_decompress(&cinfo);
  return success;
}
コード例 #23
0
int imFileFormatJPEG::ReadImageInfo(int index)
{
  (void)index;
  this->fix_adobe_cmyk = 0;

  if (setjmp(this->jerr.setjmp_buffer)) 
    return IM_ERR_ACCESS;

  // notify libjpeg to save the COM marker
  jpeg_save_markers(&this->dinfo, JPEG_COM, 0xFFFF);
  jpeg_save_markers(&this->dinfo, JPEG_APP0+1, 0xFFFF);

  /* Step 3: read file parameters with jpeg_read_header() */
  if (jpeg_read_header(&this->dinfo, TRUE) != JPEG_HEADER_OK)
    return IM_ERR_ACCESS;

  this->width = this->dinfo.image_width;
  this->height = this->dinfo.image_height;
  this->file_data_type = IM_BYTE;

  switch(this->dinfo.jpeg_color_space)
  {
  case JCS_GRAYSCALE:
    this->file_color_mode = IM_GRAY;
    break;
  case JCS_RGB:
    this->file_color_mode = IM_RGB;
    break;
  case JCS_YCbCr:
    this->file_color_mode = IM_RGB;
    break;
  case JCS_CMYK:
    this->file_color_mode = IM_CMYK;
    if (this->dinfo.saw_Adobe_marker)
      this->fix_adobe_cmyk = 1;
    break;
  case JCS_YCCK:
    this->file_color_mode = IM_CMYK; 
    this->dinfo.out_color_space = JCS_CMYK;  // this is the only supported conversion in libjpeg
    if (this->dinfo.saw_Adobe_marker)
      this->fix_adobe_cmyk = 1;
    break;
  default: /* JCS_UNKNOWN */
    return IM_ERR_DATA;
  }

  imAttribTable* attrib_table = AttribTable();

  int* auto_ycbcr = (int*)attrib_table->Get("AutoYCbCr");
  if (auto_ycbcr && *auto_ycbcr == 0 &&
      this->dinfo.jpeg_color_space == JCS_YCbCr)
  {
    this->file_color_mode = IM_YCBCR;
    this->dinfo.out_color_space = JCS_YCbCr;
  }

  this->file_color_mode |= IM_TOPDOWN;

  if (imColorModeDepth(this->file_color_mode) > 1)
    this->file_color_mode |= IM_PACKED;

  if (this->dinfo.progressive_mode != 0)
  {
    int progressive = 1;
    attrib_table->Set("Interlaced", IM_INT, 1, &progressive);
  }

  if (this->dinfo.density_unit != 0)
  {
    float xres = (float)this->dinfo.X_density, 
          yres = (float)this->dinfo.Y_density;

    if (this->dinfo.density_unit == 1)
      attrib_table->Set("ResolutionUnit", IM_BYTE, -1, "DPI");
    else
      attrib_table->Set("ResolutionUnit", IM_BYTE, -1, "DPC");

    attrib_table->Set("XResolution", IM_FLOAT, 1, (void*)&xres);
    attrib_table->Set("YResolution", IM_FLOAT, 1, (void*)&yres);
  }

  if (this->dinfo.marker_list)
  {
    jpeg_saved_marker_ptr cur_marker = this->dinfo.marker_list;

    // search for COM marker
    while (cur_marker)
    {
      if (cur_marker->marker == JPEG_COM)
      {
        char* desc = new char [cur_marker->data_length+1];
        memcpy(desc, cur_marker->data, cur_marker->data_length);
        desc[cur_marker->data_length] = 0;
        attrib_table->Set("Description", IM_BYTE, cur_marker->data_length+1, desc);
        delete [] desc;
      }
      
#ifdef USE_EXIF
      if (cur_marker->marker == JPEG_APP0+1)
        iReadExifAttrib(cur_marker->data, cur_marker->data_length, attrib_table);
#endif

      cur_marker = cur_marker->next;
    }
  }

  /* Step 5: Start decompressor */
  if (jpeg_start_decompress(&this->dinfo) == FALSE)
    return IM_ERR_ACCESS;

  return IM_ERR_NONE;
}
コード例 #24
0
ファイル: io-jpeg.c プロジェクト: coapp-packages/gdk-pixbuf
/*
 * context - from image_begin_load
 * buf - new image data
 * size - length of new image data
 *
 * append image data onto inrecrementally built output image
 */
static gboolean
gdk_pixbuf__jpeg_image_load_increment (gpointer data,
                                       const guchar *buf, guint size,
                                       GError **error)
{
	JpegProgContext *context = (JpegProgContext *)data;
	struct           jpeg_decompress_struct *cinfo;
	my_src_ptr       src;
	guint            num_left, num_copy;
	guint            last_num_left, last_bytes_left;
	guint            spinguard;
	gboolean         first;
	const guchar    *bufhd;
	gint             width, height;
        int              is_otag;
	char             otag_str[5];

	g_return_val_if_fail (context != NULL, FALSE);
	g_return_val_if_fail (buf != NULL, FALSE);

	src = (my_src_ptr) context->cinfo.src;

	cinfo = &context->cinfo;

        context->jerr.error = error;
        
	/* check for fatal error */
	if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
		return FALSE;
	}

	/* skip over data if requested, handle unsigned int sizes cleanly */
	/* only can happen if we've already called jpeg_get_header once   */
	if (context->src_initialized && src->skip_next) {
		if (src->skip_next > size) {
			src->skip_next -= size;
			return TRUE;
		} else {
			num_left = size - src->skip_next;
			bufhd = buf + src->skip_next;
			src->skip_next = 0;
		}
	} else {
		num_left = size;
		bufhd = buf;
	}

	if (num_left == 0)
		return TRUE;

	last_num_left = num_left;
	last_bytes_left = 0;
	spinguard = 0;
	first = TRUE;
	while (TRUE) {

		/* handle any data from caller we haven't processed yet */
		if (num_left > 0) {
			if(src->pub.bytes_in_buffer && 
			   src->pub.next_input_byte != src->buffer)
				memmove(src->buffer, src->pub.next_input_byte,
					src->pub.bytes_in_buffer);


			num_copy = MIN (JPEG_PROG_BUF_SIZE - src->pub.bytes_in_buffer,
					num_left);

			memcpy(src->buffer + src->pub.bytes_in_buffer, bufhd,num_copy);
			src->pub.next_input_byte = src->buffer;
			src->pub.bytes_in_buffer += num_copy;
			bufhd += num_copy;
			num_left -= num_copy;
		}

                /* did anything change from last pass, if not return */
                if (first) {
                        last_bytes_left = src->pub.bytes_in_buffer;
                        first = FALSE;
                } else if (src->pub.bytes_in_buffer == last_bytes_left
			   && num_left == last_num_left) {
                        spinguard++;
		} else {
                        last_bytes_left = src->pub.bytes_in_buffer;
			last_num_left = num_left;
		}

		/* should not go through twice and not pull bytes out of buf */
		if (spinguard > 2)
			return TRUE;

		/* try to load jpeg header */
		if (!context->got_header) {
			int rc;
		
			jpeg_save_markers (cinfo, EXIF_JPEG_MARKER, 0xffff);
			rc = jpeg_read_header (cinfo, TRUE);
			context->src_initialized = TRUE;
			
			if (rc == JPEG_SUSPENDED)
				continue;
			
			context->got_header = TRUE;

			/* check for orientation tag */
			is_otag = get_orientation (cinfo);
		
			width = cinfo->image_width;
			height = cinfo->image_height;
			if (context->size_func) {
				(* context->size_func) (&width, &height, context->user_data);
				if (width == 0 || height == 0) {
					g_set_error_literal (error,
                                                             GDK_PIXBUF_ERROR,
                                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                                             _("Transformed JPEG has zero width or height."));
					return FALSE;
				}
			}
			
			cinfo->scale_num = 1;
			for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
				jpeg_calc_output_dimensions (cinfo);
				if (cinfo->output_width < width || cinfo->output_height < height) {
					cinfo->scale_denom /= 2;
					break;
				}
			}
			jpeg_calc_output_dimensions (cinfo);
			
			context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
							  cinfo->output_components == 4 ? TRUE : FALSE,
							  8, 
							  cinfo->output_width,
							  cinfo->output_height);

			if (context->pixbuf == NULL) {
                                g_set_error_literal (error,
                                                     GDK_PIXBUF_ERROR,
                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                                     _("Couldn't allocate memory for loading JPEG file"));
                                return FALSE;
			}
		
		        /* if orientation tag was found set an option to remember its value */
		        if (is_otag) {
                		g_snprintf (otag_str, sizeof (otag_str), "%d", is_otag);
		                gdk_pixbuf_set_option (context->pixbuf, "orientation", otag_str);
		        }

			/* Use pixbuf buffer to store decompressed data */
			context->dptr = context->pixbuf->pixels;
			
			/* Notify the client that we are ready to go */
			if (context->prepared_func)
				(* context->prepared_func) (context->pixbuf,
							    NULL,
							    context->user_data);
			
		} else if (!context->did_prescan) {
			int rc;			
			
			/* start decompression */
			cinfo->buffered_image = cinfo->progressive_mode;
			rc = jpeg_start_decompress (cinfo);
			cinfo->do_fancy_upsampling = FALSE;
			cinfo->do_block_smoothing = FALSE;

			if (rc == JPEG_SUSPENDED)
				continue;

			context->did_prescan = TRUE;
		} else if (!cinfo->buffered_image) {
                        /* we're decompressing unbuffered so
                         * simply get scanline by scanline from jpeg lib
                         */
                        if (! gdk_pixbuf__jpeg_image_load_lines (context,
                                                                 error))
                                return FALSE;

			if (cinfo->output_scanline >= cinfo->output_height)
				return TRUE;
		} else {
                        /* we're decompressing buffered (progressive)
                         * so feed jpeg lib scanlines
                         */

			/* keep going until we've done all passes */
			while (!jpeg_input_complete (cinfo)) {
				if (!context->in_output) {
					if (jpeg_start_output (cinfo, cinfo->input_scan_number)) {
						context->in_output = TRUE;
						context->dptr = context->pixbuf->pixels;
					}
					else
						break;
				}

                                /* get scanlines from jpeg lib */
                                if (! gdk_pixbuf__jpeg_image_load_lines (context,
                                                                         error))
                                        return FALSE;

				if (cinfo->output_scanline >= cinfo->output_height &&
				    jpeg_finish_output (cinfo))
					context->in_output = FALSE;
				else
					break;
			}
			if (jpeg_input_complete (cinfo))
				/* did entire image */
				return TRUE;
			else
				continue;
		}
	}
}
コード例 #25
0
ファイル: io-jpeg.c プロジェクト: coapp-packages/gdk-pixbuf
/* Shared library entry point */
static GdkPixbuf *
gdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
{
	gint   i;
	int     is_otag;
	char   otag_str[5];
	GdkPixbuf * volatile pixbuf = NULL;
	guchar *dptr;
	guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height, 
                           * from the header file: 
                           * " Usually rec_outbuf_height will be 1 or 2, 
                           * at most 4."
			   */
	guchar **lptr;
	struct jpeg_decompress_struct cinfo;
	struct error_handler_data jerr;
	stdio_src_ptr src;

	/* setup error handler */
	cinfo.err = jpeg_std_error (&jerr.pub);
	jerr.pub.error_exit = fatal_error_handler;
        jerr.pub.output_message = output_message_handler;
        jerr.error = error;
        
	if (sigsetjmp (jerr.setjmp_buffer, 1)) {
		/* Whoops there was a jpeg error */
		if (pixbuf)
			g_object_unref (pixbuf);

		jpeg_destroy_decompress (&cinfo);

		/* error should have been set by fatal_error_handler () */
		return NULL;
	}

	/* load header, setup */
	jpeg_create_decompress (&cinfo);

	cinfo.src = (struct jpeg_source_mgr *)
	  (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
				  sizeof (stdio_source_mgr));
	src = (stdio_src_ptr) cinfo.src;
	src->buffer = (JOCTET *)
	  (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
				      JPEG_PROG_BUF_SIZE * sizeof (JOCTET));

	src->pub.init_source = stdio_init_source;
	src->pub.fill_input_buffer = stdio_fill_input_buffer;
	src->pub.skip_input_data = stdio_skip_input_data;
	src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
	src->pub.term_source = stdio_term_source;
	src->infile = f;
	src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
	src->pub.next_input_byte = NULL; /* until buffer loaded */

	jpeg_save_markers (&cinfo, EXIF_JPEG_MARKER, 0xffff);
	jpeg_read_header (&cinfo, TRUE);

	/* check for orientation tag */
	is_otag = get_orientation (&cinfo);
	
	jpeg_start_decompress (&cinfo);
	cinfo.do_fancy_upsampling = FALSE;
	cinfo.do_block_smoothing = FALSE;

	pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
				 cinfo.out_color_components == 4 ? TRUE : FALSE, 
				 8, cinfo.output_width, cinfo.output_height);
	      
	if (!pixbuf) {
		jpeg_destroy_decompress (&cinfo);

                /* broken check for *error == NULL for robustness against
                 * crappy JPEG library
                 */
                if (error && *error == NULL) {
                        g_set_error_literal (error,
                                             GDK_PIXBUF_ERROR,
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                             _("Insufficient memory to load image, try exiting some applications to free memory"));
                }
                
		return NULL;
	}

	/* if orientation tag was found set an option to remember its value */
	if (is_otag) {
		g_snprintf (otag_str, sizeof (otag_str), "%d", is_otag);
		gdk_pixbuf_set_option (pixbuf, "orientation", otag_str);
	}


	dptr = pixbuf->pixels;

	/* decompress all the lines, a few at a time */
	while (cinfo.output_scanline < cinfo.output_height) {
		lptr = lines;
		for (i = 0; i < cinfo.rec_outbuf_height; i++) {
			*lptr++ = dptr;
			dptr += pixbuf->rowstride;
		}

		jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height);

		switch (cinfo.out_color_space) {
		    case JCS_GRAYSCALE:
		      explode_gray_into_buf (&cinfo, lines);
		      break;
		    case JCS_RGB:
		      /* do nothing */
		      break;
		    case JCS_CMYK:
		      convert_cmyk_to_rgb (&cinfo, lines);
		      break;
		    default:
		      g_object_unref (pixbuf);
		      if (error && *error == NULL) {
                        g_set_error (error,
                                     GDK_PIXBUF_ERROR,
				     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
				     _("Unsupported JPEG color space (%s)"),
				     colorspace_name (cinfo.out_color_space)); 
		      }
                
		      jpeg_destroy_decompress (&cinfo);
		      return NULL;
		}
	}

	jpeg_finish_decompress (&cinfo);
	jpeg_destroy_decompress (&cinfo);

	return pixbuf;
}
コード例 #26
0
ファイル: jpegdec.c プロジェクト: 5Ecur1ty/libsdl-image
static void SaveMetadataMarkers(j_decompress_ptr dinfo) {
  const unsigned int max_marker_length = 0xffff;
  jpeg_save_markers(dinfo, JPEG_APP1, max_marker_length);  // Exif/XMP
  jpeg_save_markers(dinfo, JPEG_APP2, max_marker_length);  // ICC profile
}
コード例 #27
0
ファイル: jpeginfo.c プロジェクト: finyael/WebcamDownload
int main(int argc, char **argv) 
{
  JSAMPARRAY buf = malloc(sizeof(JSAMPROW)*BUF_LINES);
  jpeg_saved_marker_ptr exif_marker, cmarker;
  MD5_CTX *MD5 = malloc(sizeof(MD5_CTX));
  volatile int i;
  int c,j,lines_read, err_count;
  char ch;
  char namebuf[1024];
  long fs;
  char *md5buf,digest[16],digest_text[33];
  
  global_total_errors=0;
  if (rcsid); /* to keep compiler from not complaining about rcsid */
 
  cinfo.err = jpeg_std_error(&jerr.pub);
  jpeg_create_decompress(&cinfo);
  jerr.pub.error_exit=my_error_exit;
  jerr.pub.output_message=my_output_message;

  if (!buf || !MD5) no_memory();
  if (argc<2) {
    if (quiet_mode < 2) fprintf(stderr,"jpeginfo: file arguments missing\n"
			     "Try 'jpeginfo "
			     "--help"
			     "' for more information.\n");
    exit(1);
  }
 
  /* parse command line parameters */
  while(1) {
    opt_index=0;
    if ( (c=getopt_long(argc,argv,"livVdcChqm:f:5",
			long_options,&opt_index))  == -1) 
      break;
    switch (c) {
    case 'm':
        if (!strcasecmp(optarg,"all")) del_mode=0;
        else if (!strcasecmp(optarg,"erronly")) del_mode=1;
	else if (!quiet_mode) 
	  fprintf(stderr,"Unknown parameter for -m, --mode.\n");
      break;
    case 'f':
        if (!strcmp(optarg,"-")) listfile=stdin;
	else if ((listfile=fopen(optarg,"r"))==NULL) {
	  fprintf(stderr,"Cannot open file '%s'.\n",optarg);
	  exit(2);
	}
	input_from_file=1;
	break;
    case 'v':
      verbose_mode=1;
      break;
    case 'V':
      fprintf(stderr,"jpeginfo v" VERSION "  " HOST_TYPE 
	      "\nCopyright (c) Timo Kokkonen, 1995-2002.\n"); 
      exit(0);
    case 'd':
      delete_mode=1;
      break;
    case 'c':
      check_mode=1;
      break;
    case 'h':
      p_usage();
      break;
    case 'q':
      quiet_mode++;
      break;
    case 'l':
      list_mode=1;
      break;
    case 'i':
      longinfo_mode=1;
      break;
    case '5':
      md5_mode=1;
      break;
    case 'C':
      com_mode=1;
      break;
    case '?':
      break;

    default:
      if (!quiet_mode) 
	fprintf(stderr,"jpeginfo: error parsing parameters.\n");
    }
  }

  if (delete_mode && verbose_mode && !quiet_mode) 
    fprintf(stderr,"jpeginfo: delete mode enabled (%s)\n",
	    !del_mode?"normal":"errors only"); 

  i=1;  
  do {
   if (input_from_file) {
     if (!fgetstr(namebuf,sizeof(namebuf),listfile)) break;
     current=namebuf;
   } 
   else current=argv[i];
 
   if (current[0]==0) continue;
   if (current[0]=='-' && !input_from_file) continue;
 
   if (setjmp(jerr.setjmp_buffer)) {
      jpeg_abort_decompress(&cinfo);
      fclose(infile);
      if (list_mode && quiet_mode < 2) printf(" %s",current);
      if (quiet_mode < 2) printf(" [ERROR]\n");
      if (delete_mode) delete_file(current,verbose_mode,quiet_mode);
      continue;
   }

   if ((infile=fopen(current,"r"))==NULL) {
     if (!quiet_mode) fprintf(stderr, "jpeginfo: can't open '%s'\n", current);
     continue;
   }
   if (is_dir(infile)) {
     fclose(infile);
     if (verbose_mode) printf("directory: %s  skipped\n",current); 
     continue;
   }

   fs=filesize(infile);

   if (md5_mode) {
     md5buf=malloc(fs);
     if (!md5buf) no_memory();
     fread(md5buf,1,fs,infile);
     rewind(infile);
     
     MD5Init(MD5);
     MD5Update(MD5,md5buf,fs);
     MD5Final(digest,MD5);
     md2str(digest,digest_text);

     free(md5buf);
   }

   if (!list_mode && quiet_mode < 2) printf("%s ",current);

   global_error_counter=0;
   err_count=jerr.pub.num_warnings;
   if (com_mode) jpeg_save_markers(&cinfo, JPEG_COM, 0xffff);
   jpeg_save_markers(&cinfo, EXIF_JPEG_MARKER, 0xffff);
   jpeg_stdio_src(&cinfo, infile);
   jpeg_read_header(&cinfo, TRUE); 

   /* check for Exif marker */
   exif_marker=NULL;
   cmarker=cinfo.marker_list;
   while (cmarker) {
     if (cmarker->marker == EXIF_JPEG_MARKER) {
       if (!memcmp(cmarker->data,EXIF_IDENT_STRING,6)) exif_marker=cmarker;
     }
     cmarker=cmarker->next;
   }   

   if (quiet_mode < 2) {
     printf("%4d x %-4d %2dbit ",(int)cinfo.image_width,
            (int)cinfo.image_height,(int)cinfo.num_components*8);

     if (exif_marker) printf("Exif  ");
     else if (cinfo.saw_JFIF_marker) printf("JFIF  ");
     else if (cinfo.saw_Adobe_marker) printf("Adobe ");
     else printf("n/a   "); 

     if (longinfo_mode) {
       printf("%s %s",(cinfo.progressive_mode?"Progressive":"Normal"),
	      (cinfo.arith_code?"Arithmetic":"Huffman") );

       if (cinfo.density_unit==1||cinfo.density_unit==2) 
	 printf(",%ddp%c",MIN(cinfo.X_density,cinfo.Y_density),
		(cinfo.density_unit==1?'i':'c') );
     
       if (cinfo.CCIR601_sampling) printf(",CCIR601");
       printf(" %7ld ",fs);

     } else printf("%c %7ld ",(cinfo.progressive_mode?'P':'N'),fs);

     if (md5_mode) printf("%s ",digest_text);
     if (list_mode) printf("%s ",current);

     if (com_mode) {
       cmarker=cinfo.marker_list;
       while (cmarker) {
	 if (cmarker->marker == JPEG_COM) {
	   printf("\"");
	   for (j=0;j<cmarker->data_length;j++) {
	     ch = cmarker->data[j];
	     if (ch < 32 || iscntrl(ch)) continue;
	     printf("%c",cmarker->data[j]);
	   }
	   printf("\" ");
	 }
	 cmarker=cmarker->next;
       }
     }
   }

   if (check_mode) {
     cinfo.out_color_space=JCS_GRAYSCALE; /* to speed up the process... */
     cinfo.scale_denom = 8;
     jpeg_start_decompress(&cinfo);
 
     for (j=0;j<BUF_LINES;j++) {
        buf[j]=malloc(sizeof(JSAMPLE)*cinfo.output_width*
                                      cinfo.out_color_components);
        if (!buf[j]) no_memory();
     }

     while (cinfo.output_scanline < cinfo.output_height) {
       lines_read = jpeg_read_scanlines(&cinfo, buf,BUF_LINES);
     }

     jpeg_finish_decompress(&cinfo);
     for(j=0;j<BUF_LINES;j++) free(buf[j]);

     if (!global_error_counter) {
       if (quiet_mode < 2) printf(" [OK]\n");
     }
     else {
       if (quiet_mode < 2) printf(" [WARNING]\n");
       if (delete_mode && !del_mode) 
	 delete_file(current,verbose_mode,quiet_mode);
     }
   }
   else { /* !check_mode */
     if (quiet_mode < 2) printf("\n"); 
     jpeg_abort_decompress(&cinfo);
   }

   fclose(infile);
  
  } while (++i<argc || input_from_file);

  jpeg_destroy_decompress(&cinfo);
  free(buf);
  free(MD5);

  return (global_total_errors>0?1:0); /* return 1 if any errors found file(s)
					 we checked */
}
コード例 #28
0
static int load_jpeg_sub(RefImage *image, Value r, int info_only)
{
    int channels;
    int inverted = FALSE;
    int rowbytes;
    uint8_t *data;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    memset(&cinfo, 0, sizeof(cinfo));
    memset(&jerr, 0, sizeof(jerr));

    cinfo.err = jpeg_std_error(&jerr);
    jerr.error_exit = fatal_jpeg_error;
    jerr.output_message = throw_jpeg_error;
    jpeg_create_decompress(&cinfo);
    jpeg_init_source(&cinfo, r);

    jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256);

    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
        if (fg->error == VALUE_NULL) {
            fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format");
        }
        goto ERROR_END;
    }
    if (cinfo.image_width > MAX_IMAGE_SIZE || cinfo.image_height > MAX_IMAGE_SIZE) {
        fs->throw_errorf(mod_image, "ImageError", "Image size too large (max:%d)", MAX_IMAGE_SIZE);
        goto ERROR_END;
    }

    image->width = cinfo.image_width;
    image->height = cinfo.image_height;

    if (!jpeg_start_decompress(&cinfo)) {
        if (fg->error == VALUE_NULL) {
            fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format (jpeg_start_decompress failed)");
        }
        goto ERROR_END;
    }
    if (image->width != cinfo.output_width || image->height != cinfo.output_height) {
        fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format");
        goto ERROR_END;
    }

    switch (cinfo.jpeg_color_space) {
    case JCS_CMYK:
    case JCS_YCCK:
        cinfo.out_color_space = JCS_CMYK;
        break;
    case JCS_GRAYSCALE:
        cinfo.out_color_space = JCS_GRAYSCALE;
        break;
    default:
        cinfo.out_color_space = JCS_RGB;
        break;
    }

    if (cinfo.out_color_space == JCS_RGB) {
        if (cinfo.output_components != 3) {
            fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format (output_components %d, expected 3)", cinfo.output_components);
            goto ERROR_END;
        }
        image->bands = BAND_RGB;
        channels = 3;
    } else if (cinfo.out_color_space == JCS_CMYK) {
        jpeg_saved_marker_ptr marker;
        if (cinfo.output_components != 4) {
            fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format (output_components %d, expected 4)", cinfo.output_components);
            goto ERROR_END;
        }
        for (marker = cinfo.marker_list; marker != NULL; marker = marker->next) {
            if (marker->marker == (JPEG_APP0 + 14) && marker->data_length >= 12 && strncmp((const char*)marker->data, "Adobe", 5) == 0) {
                inverted = TRUE;
                break;
            }
        }
        image->bands = BAND_RGB;
        channels = 3;
    } else if (cinfo.out_color_space == JCS_GRAYSCALE) {
        if (cinfo.output_components != 1) {
            fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format (output_components %d, expected 1)", cinfo.output_components);
            goto ERROR_END;
        }
        image->bands = BAND_L;
        channels = 1;
    } else {
        fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format (Not suppoeter color_space)");
        goto ERROR_END;
    }

    rowbytes = image->width * channels;
    image->pitch = rowbytes;

    if (!info_only) {
        if (rowbytes * image->height > fs->max_alloc) {
            fs->throw_error_select(THROW_MAX_ALLOC_OVER__INT, fs->max_alloc);
            goto ERROR_END;
        }
        data = malloc(rowbytes * image->height);

        if (cinfo.out_color_space == JCS_RGB || cinfo.out_color_space == JCS_GRAYSCALE) {
            JSAMPROW rows[1];
            int i;

            for (i = 0; i < image->height; i++) {
                rows[0] = data + rowbytes * i;
                if (jpeg_read_scanlines(&cinfo, rows, 1) != 1) {
                    if (fg->error == VALUE_NULL) {
                        fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format (jpeg_read_scanlines failed)");
                    }
                    goto ERROR_END;
                }
            }
        } else if (cinfo.out_color_space == JCS_CMYK) {
            JSAMPROW rows[1];
            int i;
            uint8_t *cmyk = malloc(image->width * 4);
            rows[0] = cmyk;

            for (i = 0; i < image->height; i++) {
                // CMYK CMYK ...
                if (jpeg_read_scanlines(&cinfo, rows, 1) != 1) {
                    if (fg->error == VALUE_NULL) {
                        fs->throw_errorf(mod_image, "ImageError", "Invalid JPEG format (jpeg_read_scanlines failed)");
                    }
                    goto ERROR_END;
                }
                CMYK_to_RGB(data + rowbytes * i, cmyk, image->width, inverted);
            }
            free(cmyk);
        }
        image->data = data;
    }
    jpeg_destroy_decompress(&cinfo);

    return TRUE;

ERROR_END:
    jpeg_destroy_decompress(&cinfo);
    return FALSE;
}
コード例 #29
0
ファイル: xpsjpeg.c プロジェクト: computersforpeace/ghostpdl
int
xps_decode_jpeg(xps_context_t *ctx, byte *rbuf, int rlen, xps_image_t *image)
{
    jpeg_decompress_data jddp;
    stream_DCT_state state;
    stream_cursor_read rp;
    stream_cursor_write wp;
    int code;
    int wlen;
    byte *wbuf;
    jpeg_saved_marker_ptr curr_marker;

    s_init_state((stream_state*)&state, &s_DCTD_template, ctx->memory);
    state.report_error = xps_report_error;

    s_DCTD_template.set_defaults((stream_state*)&state);

    state.jpeg_memory = ctx->memory;
    state.data.decompress = &jddp;

    jddp.templat = s_DCTD_template;
    jddp.memory = ctx->memory;
    jddp.scanline_buffer = NULL;

    if ((code = gs_jpeg_create_decompress(&state)) < 0)
        return gs_throw(-1, "cannot gs_jpeg_create_decompress");

    s_DCTD_template.init((stream_state*)&state);

    rp.ptr = rbuf - 1;
    rp.limit = rbuf + rlen - 1;

    /* read the header only by not having a write buffer */
    wp.ptr = 0;
    wp.limit = 0;

    /* Set up to save the ICC marker APP2.
     * According to the spec we should be getting APP1 APP2 and APP13.
     * Library gets APP0 and APP14. */
    jpeg_save_markers(&(jddp.dinfo), 0xe2, 0xFFFF);

    code = s_DCTD_template.process((stream_state*)&state, &rp, &wp, true);
    if (code != 1)
        return gs_throw(-1, "premature EOF or error in jpeg");

    /* Check if we had an ICC profile */
    curr_marker = jddp.dinfo.marker_list;
    while (curr_marker != NULL)
    {
        if (curr_marker->marker == 0xe2)
        {
            /* Found ICC profile. Create a buffer and copy over now.
             * Strip JPEG APP2 14 byte header */
            image->profilesize = curr_marker->data_length - 14;
            image->profile = xps_alloc(ctx, image->profilesize);
            if (image->profile)
            {
                /* If we can't create it, just ignore */
                memcpy(image->profile, &(curr_marker->data[14]), image->profilesize);
            }
            break;
        }
        curr_marker = curr_marker->next;
    }

    image->width = jddp.dinfo.output_width;
    image->height = jddp.dinfo.output_height;
    image->comps = jddp.dinfo.output_components;
    image->bits = 8;
    image->stride = image->width * image->comps;

    if (image->comps == 1)
        image->colorspace = ctx->gray;
    if (image->comps == 3)
        image->colorspace = ctx->srgb;
    if (image->comps == 4)
        image->colorspace = ctx->cmyk;

    if (jddp.dinfo.density_unit == 1)
    {
        image->xres = jddp.dinfo.X_density;
        image->yres = jddp.dinfo.Y_density;
    }
    else if (jddp.dinfo.density_unit == 2)
    {
        image->xres = (int)(jddp.dinfo.X_density * 2.54 + 0.5);
        image->yres = (int)(jddp.dinfo.Y_density * 2.54 + 0.5);
    }
    else
    {
        image->xres = 96;
        image->yres = 96;
    }

    wlen = image->stride * image->height;
    wbuf = xps_alloc(ctx, wlen);
    if (!wbuf)
        return gs_throw1(gs_error_VMerror, "out of memory allocating samples: %d", wlen);

    image->samples = wbuf;

    wp.ptr = wbuf - 1;
    wp.limit = wbuf + wlen - 1;

    code = s_DCTD_template.process((stream_state*)&state, &rp, &wp, true);
    if (code != EOFC)
        return gs_throw1(-1, "error in jpeg (code = %d)", code);

    gs_jpeg_destroy(&state);

    return gs_okay;
}
コード例 #30
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);;
}