Example #1
0
bool CxImageJPG::Decode(CxFile * hFile)
{

	bool is_exif = false;
#if CXIMAGEJPG_SUPPORT_EXIF
	is_exif = DecodeExif(hFile);
#endif

	CImageIterator iter(this);
	/* 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. <CSC> */
	struct jpg_error_mgr jerr;
	jerr.buffer=info.szLastError;
	/* More stuff */
	JSAMPARRAY buffer;	/* Output row buffer */
	int row_stride;		/* physical row width in output buffer */

	/* 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.
	*/

	/* 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 = ima_jpeg_error_exit;

	/* Establish the setjmp return context for my_error_exit to use. */
#pragma warning(push)
#pragma warning(disable:4611)
	if (setjmp(jerr.setjmp_buffer)) {
#pragma warning(pop)
		/* 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.
		*/
		jpeg_destroy_decompress(&cinfo);
		return 0;
	}
	/* 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);
	CxFileJpg src(hFile);
    cinfo.src = &src;

	/* Step 3: read file parameters with jpeg_read_header() */
	(void) jpeg_read_header(&cinfo, TRUE);

	/* Step 4 <chupeev> handle decoder options*/
	if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_GRAYSCALE) != 0)
		cinfo.out_color_space = JCS_GRAYSCALE;
	if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_QUANTIZE) != 0) {
		cinfo.quantize_colors = TRUE;
		cinfo.desired_number_of_colors = GetJpegQuality();
	}
	if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_DITHER) != 0)
		cinfo.dither_mode = m_nDither;
	if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_ONEPASS) != 0)
		cinfo.two_pass_quantize = FALSE;
	if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_NOSMOOTH) != 0)
		cinfo.do_fancy_upsampling = FALSE;

//<DP>: Load true color images as RGB (no quantize) 
/* Step 4: set parameters for decompression */
/*  if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) {
 *	cinfo.quantize_colors = TRUE;
 *	cinfo.desired_number_of_colors = 128;
 *}
 */ //</DP>

	// Set the scale <ignacio>
	cinfo.scale_denom = GetJpegScale();

	// Borrowed the idea from GIF implementation <ignacio>
	if (info.nEscape == -1) {
		// Return output dimensions only
		jpeg_calc_output_dimensions(&cinfo);
		head.biWidth = cinfo.output_width;
		head.biHeight = cinfo.output_height;
		info.dwType = CXIMAGE_FORMAT_JPG;
		jpeg_destroy_decompress(&cinfo);
		return true;
	}

	/* Step 5: Start decompressor */
	jpeg_start_decompress(&cinfo);

	/* 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.
	*/
	//Create the image using output dimensions <ignacio>
	//Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);
	Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);

	if (!pDib) longjmp(jerr.setjmp_buffer, 1);  //<DP> check if the image has been created

	if (is_exif){
#if CXIMAGEJPG_SUPPORT_EXIF
	if ((m_exifinfo.Xresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0))
		SetXDPI((long)(m_exifinfo.Xresolution/m_exifinfo.ResolutionUnit));
	if ((m_exifinfo.Yresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0))
		SetYDPI((long)(m_exifinfo.Yresolution/m_exifinfo.ResolutionUnit));
#endif
	} else {
		switch (cinfo.density_unit) {
		case 0:	// [andy] fix for aspect ratio...
			if((cinfo.Y_density > 0) && (cinfo.X_density > 0)){
				SetYDPI((long)(GetXDPI()*(float(cinfo.Y_density)/float(cinfo.X_density))));
			}
			break;
		case 2: // [andy] fix: cinfo.X/Y_density is pixels per centimeter
			SetXDPI((long)floor(cinfo.X_density * 2.54 + 0.5));
			SetYDPI((long)floor(cinfo.Y_density * 2.54 + 0.5));
			break;
		default:
			SetXDPI(cinfo.X_density);
			SetYDPI(cinfo.Y_density);
		}
	}

	if (cinfo.out_color_space==JCS_GRAYSCALE){
		SetGrayPalette();
		head.biClrUsed =256;
	} else {
		if (cinfo.quantize_colors){
			SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]);
			head.biClrUsed=cinfo.actual_number_of_colors;
		} else {
			head.biClrUsed=0;
		}
	}

	/* 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 */
	buffer = (*cinfo.mem->alloc_sarray)
		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

	/* 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.
	*/
	iter.Upset();
	while (cinfo.output_scanline < cinfo.output_height) {

		if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding
		
		(void) jpeg_read_scanlines(&cinfo, buffer, 1);
		// info.nProgress = (long)(100*cinfo.output_scanline/cinfo.output_height);
		//<DP> Step 6a: CMYK->RGB */ 
		if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){
			BYTE k,*dst,*src;
			dst=iter.GetRow();
			src=buffer[0];
			for(long x3=0,x4=0; x3<(long)info.dwEffWidth && x4<row_stride; x3+=3, x4+=4){
				k=src[x4+3];
				dst[x3]  =(BYTE)((k * src[x4+2])/255);
				dst[x3+1]=(BYTE)((k * src[x4+1])/255);
				dst[x3+2]=(BYTE)((k * src[x4+0])/255);
			}
		} else {
			/* Assume put_scanline_someplace wants a pointer and sample count. */
			iter.SetRow(buffer[0], row_stride);
		}
			iter.PrevRow();
	}

	/* 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.
	*/

	//<DP> Step 7A: Swap red and blue components
	// not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison>
	if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){
		BYTE* r0=GetBits();
		for(long y=0;y<head.biHeight;y++){
			if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding
			RGBtoBGR(r0,3*head.biWidth);
			r0+=info.dwEffWidth;
		}
	}

	/* Step 8: Release JPEG decompression object */
	/* This is an important step since it will release a good deal of memory. */
	jpeg_destroy_decompress(&cinfo);

	/* 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! */
	return true;
}
Example #2
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;

	/* 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 ((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 */
	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);

	/* Adjust default decompression parameters */
	if (scaleoption != NULL)
	if (sscanf(scaleoption, "%d/%d",
	&srcinfo.scale_num, &srcinfo.scale_denom) < 1)
		usage();

	/* 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 */
	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);
	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 */
}
Example #3
0
int64_t
GetImageMetadata(const char *path, char *name)
{
	ExifData *ed;
	ExifEntry *e = NULL;
	ExifLoader *l;
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	FILE *infile;
	int width=0, height=0, thumb=0;
	char make[32], model[64] = {'\0'};
	char b[1024];
	struct stat file;
	int64_t ret;
	image_s *imsrc;
	metadata_t m;
	uint32_t free_flags = 0xFFFFFFFF;
	memset(&m, '\0', sizeof(metadata_t));

	//DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing %s...\n", path);
	if ( stat(path, &file) != 0 )
		return 0;
	strip_ext(name);
	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size);

	/* MIME hard-coded to JPEG for now, until we add PNG support */
	m.mime = strdup("image/jpeg");

	l = exif_loader_new();
	exif_loader_write_file(l, path);
	ed = exif_loader_get_data(l);
	exif_loader_unref(l);
	if( !ed )
		goto no_exifdata;

	e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL);
	if( e || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED)) )
	{
		m.date = strdup(exif_entry_get_value(e, b, sizeof(b)));
		if( strlen(m.date) > 10 )
		{
			m.date[4] = '-';
			m.date[7] = '-';
			m.date[10] = 'T';
		}
		else {
			free(m.date);
			m.date = NULL;
		}
	}
	else {
		/* One last effort to get the date from XMP */
		image_get_jpeg_date_xmp(path, &m.date);
	}
	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * date: %s\n", m.date);

	e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE);
	if( e )
	{
		strncpyt(make, exif_entry_get_value(e, b, sizeof(b)), sizeof(make));
		e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL);
		if( e )
		{
			strncpyt(model, exif_entry_get_value(e, b, sizeof(b)), sizeof(model));
			if( !strcasestr(model, make) )
				snprintf(model, sizeof(model), "%s %s", make, exif_entry_get_value(e, b, sizeof(b)));
			m.creator = escape_tag(trim(model), 1);
		}
	}
	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * model: %s\n", model);

	e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION);
	if( e )
	{
		switch( exif_get_short(e->data, exif_data_get_byte_order(ed)) )
		{
		case 3:
			m.rotation = 180;
			break;
		case 6:
			m.rotation = 90;
			break;
		case 8:
			m.rotation = 270;
			break;
		default:
			m.rotation = 0;
			break;
		}
	}

	if( ed->size )
	{
		/* We might need to verify that the thumbnail is 160x160 or smaller */
		if( ed->size > 12000 )
		{
			imsrc = image_new_from_jpeg(NULL, 0, ed->data, ed->size, 1, ROTATE_NONE);
			if( imsrc )
			{
 				if( (imsrc->width <= 160) && (imsrc->height <= 160) )
					thumb = 1;
				image_free(imsrc);
			}
		}
		else
			thumb = 1;
	}
	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * thumbnail: %d\n", thumb);

	exif_data_unref(ed);

no_exifdata:
	/* If SOF parsing fails, then fall through to reading the JPEG data with libjpeg to get the resolution */
	if( image_get_jpeg_resolution(path, &width, &height) != 0 || !width || !height )
	{
		infile = fopen(path, "r");
		if( infile )
		{
			cinfo.err = jpeg_std_error(&jerr);
			jerr.error_exit = libjpeg_error_handler;
			jpeg_create_decompress(&cinfo);
			if( setjmp(setjmp_buffer) )
				goto error;
			jpeg_stdio_src(&cinfo, infile);
			jpeg_read_header(&cinfo, TRUE);
			jpeg_start_decompress(&cinfo);
			width = cinfo.output_width;
			height = cinfo.output_height;
			error:
			jpeg_destroy_decompress(&cinfo);
			fclose(infile);
		}
	}
	//DEBUG DPRINTF(E_DEBUG, L_METADATA, " * resolution: %dx%d\n", width, height);

	if( !width || !height )
	{
		free_metadata(&m, free_flags);
		return 0;
	}
	if( width <= 640 && height <= 480 )
		m.dlna_pn = strdup("JPEG_SM");
	else if( width <= 1024 && height <= 768 )
		m.dlna_pn = strdup("JPEG_MED");
	else if( (width <= 4096 && height <= 4096) || !GETFLAG(DLNA_STRICT_MASK) )
		m.dlna_pn = strdup("JPEG_LRG");
	xasprintf(&m.resolution, "%dx%d", width, height);

	ret = sql_exec(db, "INSERT into DETAILS"
	                   " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION,"
	                    " ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
	                   "VALUES"
	                   " (%Q, '%q', %lld, %lld, %Q, %Q, %u, %d, %Q, %Q, %Q);",
	                   path, name, (long long)file.st_size, (long long)file.st_mtime, m.date,
	                   m.resolution, m.rotation, thumb, m.creator, m.dlna_pn, m.mime);
	if( ret != SQLITE_OK )
	{
		DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path);
		ret = 0;
	}
	else
	{
		ret = sqlite3_last_insert_rowid(db);
	}
	free_metadata(&m, free_flags);

	return ret;
}
Example #4
0
////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Takes JPEG data inside of a buffer and decompresses it to
///   another buffer which will store the raw image.
///
///   \param[in] jpeg Pointer to JPEG data.
///   \param[in] jpegSize The size in bytes of the JPEG data.
///   \param[out] image Pointer to buffer which will store the result.  If NULL
///                     or too small new memory will be allocated dynamically.
///                     Decompressed data will be in BGR format.
///   \param[out] width The width of the image decompressed.
///   \param[out] height The height of the image decompressed.
///   \param[out] channels The number of channels in the decompressed image.
///   \param[out] imageBufferSize Optional parameter indicating how big the
///               buffer image points to actually is.
///
///   \return 1 on success, 0 on failure.
///
////////////////////////////////////////////////////////////////////////////////////
int CxUtils::JPEG::DecompressImage(const unsigned char* jpeg,
                                   const unsigned int jpegSize,
                                   unsigned char** image,
                                   unsigned short* width,
                                   unsigned short* height,
                                   unsigned char* channels,
                                   unsigned int* imageBufferSize)
{
    int result = 0;

    *width = *height = *channels = 0;

    // Create an input source for the JPEG source manager.
    struct InputSource inputSource;
    inputSource.mpImage = (unsigned char*)jpeg;
    inputSource.mImageSize = jpegSize;
    inputSource.mNumBytesRead = 0;

    // Create an input source manager for JPEG decompressor.
    jpeg_source_mgr mgr;
    mgr.bytes_in_buffer = 0;
    mgr.next_input_byte = NULL;
    mgr.init_source             = InitSource;
    mgr.fill_input_buffer       = FillInputBuffer;
    mgr.skip_input_data         = SkipInputData;
    mgr.resync_to_restart       = jpeg_resync_to_restart; // Default from library
    mgr.term_source             = TerminateSource;

    // Create a JPEG compression structure.
    struct jpeg_decompress_struct cinfo;

    // Initialize it.
    jpeg_create_decompress(&cinfo);

    // Set the input data for decompression.
    cinfo.client_data = &inputSource;
    // Set the error handler.
    cinfo.err = jpeg_std_error(&inputSource.mErrorManager.mManager);
    inputSource.mErrorManager.mManager.error_exit = ErrorExit;
    // Set jump state on error for decompressor, if failed
    // exit.
    if(setjmp(inputSource.mErrorManager.mSetJumpBuffer))
    {
        jpeg_destroy_decompress(&cinfo);
        return result;
    }
    
    // Assign the source manager to the decompressor.
    cinfo.src = &mgr;

    // Read the JPEG header data.
    jpeg_read_header(&cinfo, TRUE);

#ifdef JCS_EXTENSIONS
    if(cinfo.out_color_space == JCS_RGB)
    {
        cinfo.out_color_space = JCS_EXT_BGR;
    }
    //std::cout << "JPEG_TURBO!\n";
#endif


    // Start decompression.
    jpeg_start_decompress(&cinfo);

    // Do we support the number of color components?
    // We only support grayscale or BGR images.
    if(cinfo.output_components != 1 && cinfo.output_components != 3)
    {
        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);
        return result;
    }

    // Double check the color space that we support.
#ifdef JCS_EXTENSIONS
    if (cinfo.out_color_space == JCS_RGB || cinfo.out_color_space == JCS_EXT_BGR)
        *channels = (unsigned char)3;
#else
    if (cinfo.out_color_space == JCS_RGB)
        *channels = (unsigned char)3;
#endif
    else if (cinfo.out_color_space == JCS_GRAYSCALE)
        *channels = (unsigned char)1;
    else
    {
        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);
        return result;
    }
    
    // Make a one-row high sample array that will be deleted when
    // done decompressing.  This will be used to store temp data.
    int row_stride = cinfo.output_width * cinfo.output_components;
    JSAMPARRAY buffer = NULL;
    buffer = (*cinfo.mem->alloc_sarray)
             ((j_common_ptr) &cinfo,
             JPOOL_IMAGE,
             row_stride,
             1);

    // Calculate size of output image in bytes.
    unsigned int outputSize;
    outputSize = cinfo.output_components*cinfo.output_width*cinfo.output_height;

    // Allocate memory to store the decompressed image.
    if(*image != NULL)
    {
        // See if we need to re-allocate. 
        if((imageBufferSize != NULL && *imageBufferSize < outputSize) ||
            (outputSize >= (unsigned int)(*width)*(*height)*(*channels)))
        {
            delete[] *image;
            *image = new unsigned char[outputSize + 100];
            if(*imageBufferSize)
            {
                *imageBufferSize = outputSize + 100;
            }
        }
    }
    else
    {
        *image = new unsigned char[outputSize + 100];
    }

    *width = (unsigned short)cinfo.output_width;
    *height = (unsigned short)cinfo.output_height;
    *channels = (unsigned char)cinfo.output_components;
    
    unsigned char* ptr = *image;
    int linesRead = 0;
    // Now decompress each scanline in the image.
    while (cinfo.output_scanline < cinfo.output_height) 
    {
        linesRead += (int)jpeg_read_scanlines(&cinfo, buffer, 1);
        //(void) jpeg_read_scanlines(&cinfo, buffer, 1);
        memcpy(ptr, buffer[0], row_stride);
        ptr += row_stride;
    }
    
    if(linesRead != (int)cinfo.output_height)
    {
        return result;
    }

    (void) jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    
    result = 1;

    return result;
}
Example #5
0
void GenericImage::read_jpg(const char *filename)
{
    unsigned char *p = NULL;
    int w, h, c;

    FILE *fin;

    //fp = fopen(filename, "rb");
    //if(fp == NULL){ fprintf(stderr, "test: fopen() file %s error!\n", filename); exit(0); }
    //else { fprintf(stderr, "test: fopen() file %s ok!\n", filename); fclose(fp); }
    
    if ((fin = fopen(filename, "rb")))
    {
    	//fprintf(stderr, "begin to read in jpg header info.\n");
    	fprintf(stderr, "fopen() file %s ok!\n", filename);
    	
        struct jpeg_decompress_struct cinfo;
        struct jpeg_error_mgr         jerr;

        /* Initialize the JPG decompressor. */

        cinfo.err = jpeg_std_error(&jerr);

        jpeg_create_decompress(&cinfo);
        jpeg_stdio_src(&cinfo, fin);

        /* Grab the JPG header info. */

        jpeg_read_header(&cinfo, TRUE);
        jpeg_start_decompress(&cinfo);

        w = cinfo.output_width;
        h = cinfo.output_height;
        c = cinfo.output_components;

        /* Allocate the pixel buffer and copy pixels there. */

        if ((p = (unsigned char *) malloc ((w) * (h) * (c))))
        {
            int i = h - 1;

            while (cinfo.output_scanline < cinfo.output_height)
            {
                unsigned char *s = p + i * (w) * (c);
                i -= jpeg_read_scanlines(&cinfo, &s, 1);
            }
        }

        /* Finalize the decompression. */

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

        fclose(fin);
  
        //set the generic iimage object
        width = w;
        height = h;
        pixels = p;
        components = c;
        pix_depth = 1;
	    
        print();
        success("file opened\n");
    }
    else
    {
        fail("can't open file\n");
    }
}
Example #6
0
/*
  Function: gdImageCreateFromJpegCtxEx

  See <gdImageCreateFromJpeg>.
*/
BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtxEx(gdIOCtx *infile, int ignore_warning)
{
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	jmpbuf_wrapper jmpbufw;
	/* volatile so we can gdFree them after longjmp */
	volatile JSAMPROW row = 0;
	volatile gdImagePtr im = 0;
	JSAMPROW rowptr[1];
	JDIMENSION i, j;
	int retval;
	JDIMENSION nrows;
	int channels = 3;
	int inverted = 0;

#ifdef JPEG_DEBUG
	gd_error_ex(GD_DEBUG, "gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION);
	gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG library version %d, %d-bit sample values\n", JPEG_LIB_VERSION, BITS_IN_JSAMPLE);
	gd_error_ex(GD_DEBUG, "sizeof: %d\n", sizeof(struct jpeg_decompress_struct));
#endif

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

	jmpbufw.ignore_warning = ignore_warning;

	cinfo.err = jpeg_std_error(&jerr);
	cinfo.client_data = &jmpbufw;

	cinfo.err->emit_message = jpeg_emit_message;

	if(setjmp(jmpbufw.jmpbuf) != 0) {
		/* we're here courtesy of longjmp */
		if(row) {
			gdFree(row);
		}
		if(im) {
			gdImageDestroy(im);
		}
		return 0;
	}

	cinfo.err->error_exit = fatal_jpeg_error;

	jpeg_create_decompress(&cinfo);

	jpeg_gdIOCtx_src(&cinfo, infile);

	/* 2.0.22: save the APP14 marker to check for Adobe Photoshop CMYK
	 * files with inverted components.
	 */
	jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256);

	retval = jpeg_read_header(&cinfo, TRUE);
	if(retval != JPEG_HEADER_OK) {
		gd_error("gd-jpeg: warning: jpeg_read_header returns"
		         " %d, expected %d\n", retval, JPEG_HEADER_OK);
	}

	if(cinfo.image_height > INT_MAX) {
		gd_error("gd-jpeg: warning: JPEG image height (%u) is"
		         " greater than INT_MAX (%d) (and thus greater than"
		         " gd can handle)", cinfo.image_height, INT_MAX);
	}

	if(cinfo.image_width > INT_MAX) {
		gd_error("gd-jpeg: warning: JPEG image width (%u) is"
		         " greater than INT_MAX (%d) (and thus greater than"
		         " gd can handle)\n", cinfo.image_width, INT_MAX);
	}

	im = gdImageCreateTrueColor((int)cinfo.image_width, (int)cinfo.image_height);
	if(im == 0) {
		gd_error("gd-jpeg error: cannot allocate gdImage struct\n");
		goto error;
	}

	/* check if the resolution is specified */
	switch (cinfo.density_unit) {
	case 1:
		im->res_x = cinfo.X_density;
		im->res_y = cinfo.Y_density;
		break;
	case 2:
		im->res_x = DPCM2DPI(cinfo.X_density);
		im->res_y = DPCM2DPI(cinfo.Y_density);
		break;
	}

	/* 2.0.22: very basic support for reading CMYK colorspace files. Nice for
	 * thumbnails but there's no support for fussy adjustment of the
	 * assumed properties of inks and paper.
	 */
	if((cinfo.jpeg_color_space == JCS_CMYK) || (cinfo.jpeg_color_space == JCS_YCCK)) {
		cinfo.out_color_space = JCS_CMYK;
	} else {
		cinfo.out_color_space = JCS_RGB;
	}

	if(jpeg_start_decompress(&cinfo) != TRUE) {
		gd_error("gd-jpeg: warning: jpeg_start_decompress"
		        " reports suspended data source\n");
	}

#ifdef JPEG_DEBUG
	gd_error_ex(GD_DEBUG, "gd-jpeg: JPEG image information:");
	if(cinfo.saw_JFIF_marker) {
		gd_error_ex(GD_DEBUG, " JFIF version %d.%.2d", (int)cinfo.JFIF_major_version, (int)cinfo.JFIF_minor_version);
	} else if(cinfo.saw_Adobe_marker) {
		gd_error_ex(GD_DEBUG, " Adobe format");
	} else {
		gd_error_ex(GD_DEBUG, " UNKNOWN format");
	}

	gd_error_ex(GD_DEBUG, " %ux%u (raw) / %ux%u (scaled) %d-bit", cinfo.image_width,
		    cinfo.image_height, cinfo.output_width,
		    cinfo.output_height, cinfo.data_precision
		);
	gd_error_ex(GD_DEBUG, " %s", (cinfo.progressive_mode ? "progressive" : "baseline"));
	gd_error_ex(GD_DEBUG, " image, %d quantized colors, ", cinfo.actual_number_of_colors);

	switch(cinfo.jpeg_color_space) {
	case JCS_GRAYSCALE:
		gd_error_ex(GD_DEBUG, "grayscale");
		break;

	case JCS_RGB:
		gd_error_ex(GD_DEBUG, "RGB");
		break;

	case JCS_YCbCr:
		gd_error_ex(GD_DEBUG, "YCbCr (a.k.a. YUV)");
		break;

	case JCS_CMYK:
		gd_error_ex(GD_DEBUG, "CMYK");
		break;

	case JCS_YCCK:
		gd_error_ex(GD_DEBUG, "YCbCrK");
		break;

	default:
		gd_error_ex(GD_DEBUG, "UNKNOWN (value: %d)", (int)cinfo.jpeg_color_space);
		break;
	}

	gd_error_ex(GD_DEBUG, " colorspace\n");
	fflush(stdout);
#endif /* JPEG_DEBUG */

	/* REMOVED by TBB 2/12/01. This field of the structure is
	 * documented as private, and sure enough it's gone in the
	 * latest libjpeg, replaced by something else. Unfortunately
	 * there is still no right way to find out if the file was
	 * progressive or not; just declare your intent before you
	 * write one by calling gdImageInterlace(im, 1) yourself.
	 * After all, we're not really supposed to rework JPEGs and
	 * write them out again anyway. Lossy compression, remember? */
#if 0
	gdImageInterlace (im, cinfo.progressive_mode != 0);
#endif
	if(cinfo.out_color_space == JCS_RGB) {
		if(cinfo.output_components != 3) {
			gd_error("gd-jpeg: error: JPEG color quantization"
			         " request resulted in output_components == %d"
			         " (expected 3 for RGB)\n", cinfo.output_components);
			goto error;
		}
		channels = 3;
	} else if(cinfo.out_color_space == JCS_CMYK) {
		jpeg_saved_marker_ptr marker;
		if(cinfo.output_components != 4) {
			gd_error("gd-jpeg: error: JPEG color quantization"
			         " request resulted in output_components == %d"
			         " (expected 4 for CMYK)\n", cinfo.output_components);
			goto error;
		}
		channels = 4;

		marker = cinfo.marker_list;
		while(marker) {
			if(	(marker->marker == (JPEG_APP0 + 14)) &&
			        (marker->data_length >= 12) &&
			        (!strncmp((const char *)marker->data, "Adobe", 5))) {
				inverted = 1;
				break;
			}
			marker = marker->next;
		}
	} else {
		gd_error("gd-jpeg: error: unexpected colorspace\n");
		goto error;
	}
#if BITS_IN_JSAMPLE == 12
	gd_error_ex(GD_ERROR,
		    "gd-jpeg: error: jpeg library was compiled for 12-bit\n"
		    "precision. This is mostly useless, because JPEGs on the web are\n"
		    "8-bit and such versions of the jpeg library won't read or write\n"
		    "them. GD doesn't support these unusual images. Edit your\n"
		    "jmorecfg.h file to specify the correct precision and completely\n"
		    "'make clean' and 'make install' libjpeg again. Sorry.\n");
	goto error;
#endif /* BITS_IN_JSAMPLE == 12 */

	row = gdCalloc(cinfo.output_width *channels, sizeof(JSAMPLE));
	if(row == 0) {
		gd_error("gd-jpeg: error: unable to allocate row for"
		         " JPEG scanline: gdCalloc returns NULL\n");
		goto error;
	}
	rowptr[0] = row;
	if(cinfo.out_color_space == JCS_CMYK) {
		for(i = 0; i < cinfo.output_height; i++) {
			register JSAMPROW currow = row;
			register int *tpix = im->tpixels[i];
			nrows = jpeg_read_scanlines(&cinfo, rowptr, 1);
			if(nrows != 1) {
				gd_error("gd-jpeg: error: jpeg_read_scanlines"
				         " returns %u, expected 1\n", nrows);
				goto error;
			}
			for(j = 0; j < cinfo.output_width; j++, currow += 4, tpix++) {
				*tpix = CMYKToRGB(currow[0], currow[1], currow[2], currow[3], inverted);
			}
		}
	} else {
		for(i = 0; i < cinfo.output_height; i++) {
			register JSAMPROW currow = row;
			register int *tpix = im->tpixels[i];
			nrows = jpeg_read_scanlines(&cinfo, rowptr, 1);
			if(nrows != 1) {
				gd_error("gd-jpeg: error: jpeg_read_scanlines"
				         " returns %u, expected 1\n", nrows);
				goto error;
			}
			for(j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) {
				*tpix = gdTrueColor(currow[0], currow[1], currow[2]);
			}
		}
	}

	if(jpeg_finish_decompress (&cinfo) != TRUE) {
		gd_error("gd-jpeg: warning: jpeg_finish_decompress"
		         " reports suspended data source\n");
	}
	/* TBB 2.0.29: we should do our best to read whatever we can read, and a
	 * warning is a warning. A fatal error on warnings doesn't make sense. */
#if 0
	/* This was originally added by Truxton Fulton */
	if (cinfo.err->num_warnings > 0)
		goto error;
#endif

	jpeg_destroy_decompress(&cinfo);
	gdFree(row);
	return im;

error:
	jpeg_destroy_decompress(&cinfo);

	if(row) {
		gdFree(row);
	}
	if(im) {
		gdImageDestroy(im);
	}

	return 0;
}
Example #7
0
static int
next_dctd(fz_context *ctx, fz_stream *stm, size_t max)
{
	fz_dctd *state = stm->state;
	j_decompress_ptr cinfo = &state->cinfo;
	unsigned char *p = state->buffer;
	unsigned char *ep;

	if (max > sizeof(state->buffer))
		max = sizeof(state->buffer);
	ep = state->buffer + max;

	if (setjmp(state->jb))
	{
		if (cinfo->src)
			state->curr_stm->rp = state->curr_stm->wp - cinfo->src->bytes_in_buffer;
		fz_throw(ctx, FZ_ERROR_GENERIC, "jpeg error: %s", state->msg);
	}

	if (!state->init)
	{
		int c;
		cinfo->client_data = state;
		cinfo->err = &state->errmgr;
		jpeg_std_error(cinfo->err);
		cinfo->err->error_exit = error_exit;

		fz_dct_mem_init(state);

		jpeg_create_decompress(cinfo);
		state->init = 1;

		/* Skip over any stray returns at the start of the stream */
		while ((c = fz_peek_byte(ctx, state->chain)) == '\n' || c == '\r')
			(void)fz_read_byte(ctx, state->chain);

		cinfo->src = &state->srcmgr;
		cinfo->src->init_source = init_source;
		cinfo->src->fill_input_buffer = fill_input_buffer;
		cinfo->src->skip_input_data = skip_input_data;
		cinfo->src->resync_to_restart = jpeg_resync_to_restart;
		cinfo->src->term_source = term_source;

		/* optionally load additional JPEG tables first */
		if (state->jpegtables)
		{
			state->curr_stm = state->jpegtables;
			cinfo->src->next_input_byte = state->curr_stm->rp;
			cinfo->src->bytes_in_buffer = state->curr_stm->wp - state->curr_stm->rp;
			jpeg_read_header(cinfo, 0);
			state->curr_stm->rp = state->curr_stm->wp - state->cinfo.src->bytes_in_buffer;
			state->curr_stm = state->chain;
		}

		cinfo->src->next_input_byte = state->curr_stm->rp;
		cinfo->src->bytes_in_buffer = state->curr_stm->wp - state->curr_stm->rp;

		jpeg_read_header(cinfo, 1);

		/* default value if ColorTransform is not set */
		if (state->color_transform == -1)
		{
			if (state->cinfo.num_components == 3)
				state->color_transform = 1;
			else
				state->color_transform = 0;
		}

		if (cinfo->saw_Adobe_marker)
			state->color_transform = cinfo->Adobe_transform;

		/* Guess the input colorspace, and set output colorspace accordingly */
		switch (cinfo->num_components)
		{
		case 3:
			if (state->color_transform)
				cinfo->jpeg_color_space = JCS_YCbCr;
			else
				cinfo->jpeg_color_space = JCS_RGB;
			break;
		case 4:
			if (state->color_transform)
				cinfo->jpeg_color_space = JCS_YCCK;
			else
				cinfo->jpeg_color_space = JCS_CMYK;
			break;
		}

		cinfo->scale_num = 8/(1<<state->l2factor);
		cinfo->scale_denom = 8;

		jpeg_start_decompress(cinfo);

		state->stride = cinfo->output_width * cinfo->output_components;
		state->scanline = fz_malloc(ctx, state->stride);
		state->rp = state->scanline;
		state->wp = state->scanline;
	}

	while (state->rp < state->wp && p < ep)
		*p++ = *state->rp++;

	while (p < ep)
	{
		if (cinfo->output_scanline == cinfo->output_height)
			break;

		if (p + state->stride <= ep)
		{
			jpeg_read_scanlines(cinfo, &p, 1);
			p += state->stride;
		}
		else
		{
			jpeg_read_scanlines(cinfo, &state->scanline, 1);
			state->rp = state->scanline;
			state->wp = state->scanline + state->stride;
		}

		while (state->rp < state->wp && p < ep)
			*p++ = *state->rp++;
	}
	stm->rp = state->buffer;
	stm->wp = p;
	stm->pos += (p - state->buffer);
	if (p == stm->rp)
		return EOF;

	return *stm->rp++;
}
Example #8
0
BYTE* CJpeg::ReadJPEGFile(LPCSTR lpstrFileName, UINT *uWidth, UINT *uHeight)
{
	*uWidth=0;
	*uHeight=0;

	
	//定义JPEG文件的解压信息
	struct jpeg_decompress_struct cinfo;
	
	//定义JPEG文件的错误信息
	struct my_error_mgr jerr;
	
	//定义缓冲区
	FILE * infile;		
	JSAMPARRAY buffer;	
	int row_stride;		
	char buf[250];

	
    //打开JPEG文件
	if ((infile = fopen(lpstrFileName, "rb")) == NULL) 
	{
		sprintf(buf, "JPEG :\nCan't open %s\n", lpstrFileName);
		m_strJPEGError = buf;
		return NULL;
	}

	
    //为JPEG文件解压对象分配内存并对其初始化

	cinfo.err = jpeg_std_error(&jerr.pub);
	jerr.pub.error_exit = my_error_exit;



	if (setjmp(jerr.setjmp_buffer)) 
	{
		

		jpeg_destroy_decompress(&cinfo);
		fclose(infile);
		return NULL;
	}


	jpeg_create_decompress(&cinfo);


    //设定数据源 
	jpeg_stdio_src(&cinfo, infile);
    //读取JPEG文件参数

	(void) jpeg_read_header(&cinfo, TRUE);

      //开始解压
	(void) jpeg_start_decompress(&cinfo);
	
	BYTE *dataBuf;

	
	dataBuf=(BYTE *)new BYTE[cinfo.output_width * 3 * cinfo.output_height];
	if (dataBuf==NULL) 
	{

		m_strJPEGError = "JpegFile :\nOut of memory";

		jpeg_destroy_decompress(&cinfo);
		
		fclose(infile);

		return NULL;
	}


	*uWidth = cinfo.output_width;
	*uHeight = cinfo.output_height;
	

	row_stride = cinfo.output_width * cinfo.output_components;

	buffer = (*cinfo.mem->alloc_sarray)
		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

	

	//读取扫描线
	while (cinfo.output_scanline < cinfo.output_height) 
	{
	
		(void) jpeg_read_scanlines(&cinfo, buffer, 1);
	
		if (cinfo.out_color_components==3) 
		{
			
			j_putRGBScanline(buffer[0], 
							*uWidth,
							dataBuf,
							cinfo.output_scanline-1);

		} 
		else if (cinfo.out_color_components==1) 
		{

		
			j_putGrayScanlineToRGB(buffer[0], 
								*uWidth,
								dataBuf,
								cinfo.output_scanline-1);

		}

	}


     //完成解压
	(void) jpeg_finish_decompress(&cinfo);

    //释放JPEG解压对象

	jpeg_destroy_decompress(&cinfo);

	
	fclose(infile);

	
	return dataBuf;
}
Example #9
0
uint8_t* ImageDecoder::decodeJPEGImpl(jpeg_source_mgr *src, jpeg_source_mgr *headerTables, uint32_t* width, uint32_t* height, bool* hasAlpha)
{
	struct jpeg_decompress_struct cinfo;
	struct error_mgr err;

	cinfo.err = jpeg_std_error(&err);
	err.error_exit = error_exit;

	if (setjmp(err.jmpBuf)) {
		return NULL;
	}

	jpeg_create_decompress(&cinfo);
	
	if (headerTables)
		cinfo.src = headerTables;
	else
		cinfo.src = src;

	//DefineBits tag may contain "abbreviated datastreams" (as
	//they are called in the libjpeg documentation), i.e. streams
	//with only compression tables and no image data. The first
	//jpeg_read_header accepts table-only streams.
	int headerStatus = jpeg_read_header(&cinfo, FALSE);

	if (headerTables)
	{
		// Must call init_source manually after switching src
		// Check this. Doesn't jpeg_read_header call
		// init_source anyway?
		cinfo.src = src;
		src->init_source(&cinfo);
	}

	//If the first jpeg_read_header got tables-only datastream,
	//a second call is needed to read the real image header.
	if (headerStatus == JPEG_HEADER_TABLES_ONLY) 
		jpeg_read_header(&cinfo, TRUE);

#ifdef JCS_EXTENSIONS
	//JCS_EXT_XRGB is a fast decoder that outputs alpha channel,
	//but is only available on libjpeg-turbo
	cinfo.out_color_space = JCS_EXT_XRGB;
	cinfo.output_components = 4;
#endif
	jpeg_start_decompress(&cinfo);

	*width = cinfo.output_width;
	*height = cinfo.output_height;
	if(cinfo.num_components != 3)
	{
		LOG(LOG_NOT_IMPLEMENTED,"Only RGB JPEG's are supported");
		/* TODO: is this the right thing for aborting? */
		jpeg_abort_decompress(&cinfo);
		jpeg_destroy_decompress(&cinfo);
		return NULL;
	}
	assert(cinfo.output_components == 3 || cinfo.output_components == 4);

	*hasAlpha = (cinfo.output_components == 4);

	int rowstride = cinfo.output_width * cinfo.output_components;
	JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, rowstride, 1);

	uint8_t* outData = new uint8_t[cinfo.output_height * rowstride];

	/* read one scanline at a time */
	int y=0;
	while (cinfo.output_scanline < cinfo.output_height) {
		jpeg_read_scanlines(&cinfo, buffer, 1);
		memcpy(&outData[y*rowstride], buffer[0], rowstride);
		y++;
	}

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

	return outData;
}
Example #10
0
int res_create_surface_jpg(const char* name, gr_surface* pSurface) {
    GGLSurface* surface = NULL;
    int result = 0;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    FILE* fp = fopen(name, "rb");
    if (fp == NULL) {
        char resPath[256];

        snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.jpg", name);
        resPath[sizeof(resPath)-1] = '\0';
        fp = fopen(resPath, "rb");
        if (fp == NULL) {
            result = -1;
            goto exit;
        }
    }

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    /* Specify data source for decompression */
    jpeg_stdio_src(&cinfo, fp);

    /* Read file header, set default decompression parameters */
    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK)
        goto exit;

    /* Start decompressor */
    (void) jpeg_start_decompress(&cinfo);

    size_t width = cinfo.image_width;
    size_t height = cinfo.image_height;
    size_t stride = 4 * width;
    size_t pixelSize = stride * height;

    surface = malloc(sizeof(GGLSurface) + pixelSize);
    if (surface == NULL) {
        result = -8;
        goto exit;
    }

    unsigned char* pData = (unsigned char*) (surface + 1);
    surface->version = sizeof(GGLSurface);
    surface->width = width;
    surface->height = height;
    surface->stride = width; /* Yes, pixels, not bytes */
    surface->data = pData;
    surface->format = GGL_PIXEL_FORMAT_RGBX_8888;

    int y;
    for (y = 0; y < (int) height; ++y) {
        unsigned char* pRow = pData + y * stride;
        jpeg_read_scanlines(&cinfo, &pRow, 1);

        int x;
        for(x = width - 1; x >= 0; x--) {
            int sx = x * 3;
            int dx = x * 4;
            unsigned char r = pRow[sx];
            unsigned char g = pRow[sx + 1];
            unsigned char b = pRow[sx + 2];
            unsigned char a = 0xff;
            pRow[dx    ] = r; // r
            pRow[dx + 1] = g; // g
            pRow[dx + 2] = b; // b
            pRow[dx + 3] = a;
        }
    }
    *pSurface = (gr_surface) surface;

exit:
    if (fp != NULL)
    {
        if (surface)
        {
            (void) jpeg_finish_decompress(&cinfo);
            if (result < 0)
            {
                free(surface);
            }
        }
        jpeg_destroy_decompress(&cinfo);
        fclose(fp);
    }
    return result;
}
Example #11
0
int read_jpeg_file( char *filename )
{
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;

	JSAMPROW row_pointer[1];

	FILE *infile = fopen( filename, "rb" );
	unsigned long location = 0;
	long long j=0, i = 0;

	if ( !infile )
	{
		printf("Error opening jpeg file %s\n!", filename );
		return -1;
	}

	cinfo.err = jpeg_std_error( &jerr );

	jpeg_create_decompress( &cinfo );

	jpeg_stdio_src( &cinfo, infile );

	jpeg_read_header( &cinfo, TRUE );

	jpeg_start_decompress( &cinfo );

    width=cinfo.image_width;
	height=cinfo.image_height;
	bytes_per_pixel=cinfo.num_components;

	printf("components = %d\n", cinfo.num_components);

	raw_image = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components );
	raw_image2 = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components );

   unsigned char  **img = (unsigned char  **)malloc(height * sizeof(unsigned char  *));
    for (i=0; i<height; i++)
         img[i] = (unsigned char *)malloc(width*bytes_per_pixel * sizeof(unsigned char ));


   unsigned char  **oimg = (unsigned char  **)malloc(height * sizeof(unsigned char  *));
    for (i=0; i<height; i++)
         oimg[i] = (unsigned char *)malloc(width*bytes_per_pixel * sizeof(unsigned char ));

	row_pointer[0] = (unsigned char *)malloc( cinfo.output_width*cinfo.num_components );

	while( cinfo.output_scanline < cinfo.image_height )
	{
		jpeg_read_scanlines( &cinfo, row_pointer, 1 );
		for( i=0; i<cinfo.image_width*cinfo.num_components;i++)
			raw_image[location++] = row_pointer[0][i];
	}

    location=0;
    for(i=0;i<height;i++)
     for(j=0;j<width*bytes_per_pixel;j++)
     {
        img[i][j]=raw_image[location++];
     }

    int count=0;

   for(i=0;i<height;i++)
     for(j=0;j<width*bytes_per_pixel;j++)
     {
        if(i!=height-1&&j!=width*bytes_per_pixel-1)
        {
            oimg[i][j]=abs(img[i][j]*fs[0][0]+img[i][j+1]*fs[0][1]+img[i+1][j]*fs[1][0]+img[i+1][j+1]*fs[1][1])
                      +abs(img[i][j]*ft[0][0]+img[i][j+1]*ft[0][1]+img[i+1][j]*ft[1][0]+img[i+1][j+1]*ft[1][1]);
        }
        else
        {
            if(i!=height-1&&j==width*bytes_per_pixel-1)
            {
                oimg[i][j]=abs(img[i][j]*fs[0][0]+img[i+1][j]*fs[1][0])
                          +abs(img[i][j]*ft[0][0]+img[i+1][j]*ft[1][0]);
            }
            else
            if(i==height-1&&j!=width*bytes_per_pixel-1)
            {
                oimg[i][j]=abs(img[i][j]*fs[0][0]+img[i][j+1]*fs[0][1])
                          +abs(img[i][j]*ft[0][0]+img[i][j+1]*ft[0][1]);
            }
            else
            {
                oimg[i][j]=abs(img[i][j]*fs[0][0])+abs(img[i][j]*ft[0][0]);
            }


        }


     }

    printf("count is %d \n",count);

    location=0;
    for(i=0;i<height;i++)
     for(j=0;j<width*bytes_per_pixel;j++)
     {
        raw_image2[location++]=oimg[i][j];
     }


	jpeg_finish_decompress( &cinfo );
	jpeg_destroy_decompress( &cinfo );
	free( row_pointer[0] );
	fclose( infile );

	return 1;
}
Example #12
0
    TTexture* LoadJPG(const char* FileName, bool Fast = true)
    {
#if __posix__
        // printf("Loading jpg dude %s\n", FileName);

        FILE* file = fopen(FileName, "rb");  //open the file
        struct jpeg_decompress_struct info;  //the jpeg decompress info
        struct jpeg_error_mgr err;           //the error handler

        info.err = jpeg_std_error(&err);     //tell the jpeg decompression handler to send the errors to err
        jpeg_create_decompress(&info);       //sets info to all the default stuff

        //if the jpeg file didnt load exit
        if(!file)
        {
            fprintf(stderr, "Error reading JPEG file %s!!!", FileName);
            return NULL;
        }

        jpeg_stdio_src(&info, file);    //tell the jpeg lib the file we'er reading

        jpeg_read_header(&info, TRUE);   //tell it to start reading it

        //if it wants to be read fast or not
        if(Fast)
        {
            info.do_fancy_upsampling = FALSE;
        }

        jpeg_start_decompress(&info);    //decompress the file

        //set the x and y
        unsigned int w = info.output_width;
        unsigned int l = info.output_height;
        TTexture* Image = new TTexture(FileName,TImgType::JPG, w, l );
        GLuint channels = info.num_components;

        GLuint type = GL_RGB;

        if(channels == 4)
        {
            type = GL_RGBA;
        }

        GLuint bpp = channels * 8;

        GLuint size = w * l * 3;

        //read turn the uncompressed data into something ogl can read
        Image->FData = new unsigned char[size];      //setup data for the data its going to be handling

        unsigned char* p1 = (unsigned char*)    Image->FData;
        unsigned char** p2 = &p1;
        int numlines = 0;

        while(info.output_scanline < info.output_height)
        {
            numlines = jpeg_read_scanlines(&info, p2, 1);
            *p2 += numlines * 3 * info.output_width;
        }

        jpeg_finish_decompress(&info);   //finish decompressing this file

        fclose(file);                    //close the file

        return Image;
#elif WIN32
		ASSERT_NOT_IMPLEMENTED()
		return nullptr;

#endif
    }
image_t* image_load_jpg(image_t* x, stream_t* stream)
{
  image_t* im;

  TRACE1 ("loading jpeg file");

  if (!stream) {
    im = NULL;
  } else {
    int load;
    im = image_instantiate_toplevel (x);

    struct jpeg_decompress_struct cinfo;
    myerror_mgr errmgr;

    errmgr.im = im;
    errmgr.image_is_owned_p = (im != x);

    if (setjmp (errmgr.env)) {
	    jpeg_destroy_decompress(&cinfo);

	// coming back from an error
	return NULL;
    }

    /* insert here useless error test */
    /* jpeg object initialisation */
    jpeg_create_decompress (&cinfo);

    /* specify data source */
    jpeg_stream_src (&cinfo, stream);

    /* standard error */
    cinfo.err               = jpeg_std_error (&errmgr.super);
    errmgr.super.error_exit = image_load_jpeg_error_exit;

    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
	    return NULL;
    }

    if (jpeg_start_decompress(&cinfo) < 0) {
	    return NULL;
    }

    if (!cinfo.output_width || !cinfo.output_height) {
	    WARNING1("null size image.");
	    return NULL;
    }

    image_new(im,
	      cinfo.output_width,
	      cinfo.output_height,
	      cinfo.output_width);

    switch (cinfo.output_components) {
    case 1: /* GRAY */
	load = 1;
	break;
    case 3: // RGB
	load = 1;
	break;
    default:
	/* don't know how to load that */
	image_destroy (im);
	if(im != x) {
		image_retire (im);
	}
	im = NULL;

	load = 0;
    }

    if (load) {
	JSAMPARRAY scanline_buf;

	scanline_buf = (*cinfo.mem->alloc_sarray)
		((j_common_ptr) &cinfo, JPOOL_IMAGE,
		 cinfo.output_width *
		 cinfo.output_components,
		 cinfo.rec_outbuf_height);

	while (cinfo.output_scanline < cinfo.output_height) {
	    int n;

	    uint32_t* dest = im->pixels + im->pitch * cinfo.output_scanline;

	    n = jpeg_read_scanlines(&cinfo,
				    scanline_buf,
				    cinfo.rec_outbuf_height);

	    int s;
	    for (s = 0; s < n; s++) {
		    unsigned char* scanline = scanline_buf [s];

		    /* copy to image */
		    int i;
		    for (i = 0; i < im->width; i++) {
			    if(cinfo.output_components == 1) {
				    dest[i] = 0xff000000 |
					    (scanline[i] << 16) |
					    (scanline[i] << 8) |
					    (scanline[i]);
			    } else if(cinfo.output_components == 3) {
#if (BYTE_ORDER == LITTLE_ENDIAN && defined (PIXEL_RGBA8888)) ||	\
	(BYTE_ORDER == BIG_ENDIAN && defined (PIXEL_BGRA8888))
				    dest[i] =
					    0xff000000 |
					    (scanline [3*i + 0] << 16) |
					    (scanline [3*i + 1] << 8) |
					    (scanline [3*i + 2] << 0);
#else
				    /*dest[i] = 0xff000000 | //alpha
					    (scanline [3*i + 2] << 0) |
					    (scanline [3*i + 1] << 8) |
					    (scanline [3*i + 2] << 16);
				    */
				    dest[i] = 0xff000000 | // alpha
					    (scanline [3 * i + 0] << 0) | // r
					    (scanline [3 * i + 1] << 8) | // g
					    (scanline [3 * i + 2] << 16); // b

#endif
			    }
		    }
		    dest += im->pitch;
	    }
	}
    }

    jpeg_finish_decompress(&cinfo);

  }

    return im;
}
std::optional<ImageData2D> JpegImporter::doImage2D(UnsignedInt) {
    /* Initialize structures */
    jpeg_decompress_struct file;
    JSAMPARRAY rows = nullptr;
    unsigned char* data = nullptr;

    /* Fugly error handling stuff */
    /** @todo Get rid of this crap */
    struct ErrorManager {
        jpeg_error_mgr jpegErrorManager;
        std::jmp_buf setjmpBuffer;
    } errorManager;
    file.err = jpeg_std_error(&errorManager.jpegErrorManager);
    errorManager.jpegErrorManager.error_exit = [](j_common_ptr info) {
        info->err->output_message(info);
        std::longjmp(reinterpret_cast<ErrorManager*>(info->err)->setjmpBuffer, 1);
    };
    if(setjmp(errorManager.setjmpBuffer)) {
        Error() << "Trade::JpegImporter::image2D(): error while reading JPEG file";

        jpeg_destroy_decompress(&file);
        delete[] rows;
        delete[] data;
        return std::nullopt;
    }

    /* Open file */
    jpeg_create_decompress(&file);
    jpeg_mem_src(&file, _in.begin(), _in.size());

    /* Read file header, start decompression */
    jpeg_read_header(&file, true);
    jpeg_start_decompress(&file);

    /* Image size and type */
    const Vector2i size(file.output_width, file.output_height);
    static_assert(BITS_IN_JSAMPLE == 8, "Only 8-bit JPEG is supported");
    constexpr const ImageType type = ImageType::UnsignedByte;

    /* Image format */
    ImageFormat format;
    switch(file.out_color_space) {
        case JCS_GRAYSCALE:
            CORRADE_INTERNAL_ASSERT(file.out_color_components == 1);
            #ifdef MAGNUM_TARGET_GLES
            format = Context::current() && Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_rg>() ?
                ImageFormat::Red : ImageFormat::Luminance;
            #else
            format = ImageFormat::Red;
            #endif
            break;
        case JCS_RGB:
            CORRADE_INTERNAL_ASSERT(file.out_color_components == 3);
            format = ImageFormat::RGB;
            break;

        /** @todo RGBA (only in libjpeg-turbo and probably ignored) */

        default:
            Error() << "Trade::JpegImporter::image2D(): unsupported color space" << file.out_color_space;
    }

    /* Initialize data array */
    data = new unsigned char[size.product()*file.out_color_components*BITS_IN_JSAMPLE/8];

    /* Read image row by row */
    rows = new JSAMPROW[size.y()];
    const Int stride = size.x()*file.out_color_components*BITS_IN_JSAMPLE/8;
    for(Int i = 0; i != size.y(); ++i)
        rows[i] = data + (size.y() - i - 1)*stride;
    while(file.output_scanline < file.output_height)
        jpeg_read_scanlines(&file, rows+file.output_scanline, file.output_height-file.output_scanline);
    delete[] rows;
    rows = nullptr;

    /* Cleanup */
    jpeg_finish_decompress(&file);
    jpeg_destroy_decompress(&file);

    return Trade::ImageData2D(format, type, size, data);
}
Example #15
0
LexerTransition<nsJPEGDecoder::State>
nsJPEGDecoder::ReadJPEGData(const char* aData, size_t aLength)
{
  mSegment = reinterpret_cast<const JOCTET*>(aData);
  mSegmentLen = aLength;

  // Return here if there is a fatal error within libjpeg.
  nsresult error_code;
  // This cast to nsresult makes sense because setjmp() returns whatever we
  // passed to longjmp(), which was actually an nsresult.
  if ((error_code = static_cast<nsresult>(setjmp(mErr.setjmp_buffer))) != NS_OK) {
    if (error_code == NS_ERROR_FAILURE) {
      // Error due to corrupt data. Make sure that we don't feed any more data
      // to libjpeg-turbo.
      mState = JPEG_SINK_NON_JPEG_TRAILER;
      MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
             ("} (setjmp returned NS_ERROR_FAILURE)"));
    } else {
      // Error for another reason. (Possibly OOM.)
      mState = JPEG_ERROR;
      MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
             ("} (setjmp returned an error)"));
    }

    return Transition::TerminateFailure();
  }

  MOZ_LOG(sJPEGLog, LogLevel::Debug,
         ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));

  switch (mState) {
    case JPEG_HEADER: {
      LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::Write -- entering JPEG_HEADER"
                " case");

      // Step 3: read file parameters with jpeg_read_header()
      if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
        MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
               ("} (JPEG_SUSPENDED)"));
        return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
      }

      // If we have a sample size specified for -moz-sample-size, use it.
      if (mSampleSize > 0) {
        mInfo.scale_num = 1;
        mInfo.scale_denom = mSampleSize;
      }

      // Used to set up image size so arrays can be allocated
      jpeg_calc_output_dimensions(&mInfo);

      // Post our size to the superclass
      PostSize(mInfo.output_width, mInfo.output_height,
               ReadOrientationFromEXIF());
      if (HasError()) {
        // Setting the size led to an error.
        mState = JPEG_ERROR;
        return Transition::TerminateFailure();
      }

      // If we're doing a metadata decode, we're done.
      if (IsMetadataDecode()) {
        return Transition::TerminateSuccess();
      }

      // We're doing a full decode.
      if (mCMSMode != eCMSMode_Off &&
          (mInProfile = GetICCProfile(mInfo)) != nullptr) {
        uint32_t profileSpace = qcms_profile_get_color_space(mInProfile);
        bool mismatch = false;

#ifdef DEBUG_tor
      fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
#endif
      switch (mInfo.jpeg_color_space) {
        case JCS_GRAYSCALE:
          if (profileSpace == icSigRgbData) {
            mInfo.out_color_space = JCS_RGB;
          } else if (profileSpace != icSigGrayData) {
            mismatch = true;
          }
          break;
        case JCS_RGB:
          if (profileSpace != icSigRgbData) {
            mismatch =  true;
          }
          break;
        case JCS_YCbCr:
          if (profileSpace == icSigRgbData) {
            mInfo.out_color_space = JCS_RGB;
          } else {
            // qcms doesn't support ycbcr
            mismatch = true;
          }
          break;
        case JCS_CMYK:
        case JCS_YCCK:
            // qcms doesn't support cmyk
            mismatch = true;
          break;
        default:
          mState = JPEG_ERROR;
          MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
                 ("} (unknown colorpsace (1))"));
          return Transition::TerminateFailure();
      }

      if (!mismatch) {
        qcms_data_type type;
        switch (mInfo.out_color_space) {
          case JCS_GRAYSCALE:
            type = QCMS_DATA_GRAY_8;
            break;
          case JCS_RGB:
            type = QCMS_DATA_RGB_8;
            break;
          default:
            mState = JPEG_ERROR;
            MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
                   ("} (unknown colorpsace (2))"));
            return Transition::TerminateFailure();
        }
#if 0
        // We don't currently support CMYK profiles. The following
        // code dealt with lcms types. Add something like this
        // back when we gain support for CMYK.

        // Adobe Photoshop writes YCCK/CMYK files with inverted data
        if (mInfo.out_color_space == JCS_CMYK) {
          type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
        }
#endif

        if (gfxPlatform::GetCMSOutputProfile()) {

          // Calculate rendering intent.
          int intent = gfxPlatform::GetRenderingIntent();
          if (intent == -1) {
            intent = qcms_profile_get_rendering_intent(mInProfile);
          }

          // Create the color management transform.
          mTransform = qcms_transform_create(mInProfile,
                                          type,
                                          gfxPlatform::GetCMSOutputProfile(),
                                          QCMS_DATA_RGB_8,
                                          (qcms_intent)intent);
        }
      } else {
#ifdef DEBUG_tor
        fprintf(stderr, "ICM profile colorspace mismatch\n");
#endif
      }
    }

    if (!mTransform) {
      switch (mInfo.jpeg_color_space) {
        case JCS_GRAYSCALE:
        case JCS_RGB:
        case JCS_YCbCr:
          // if we're not color managing we can decode directly to
          // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
          if (mCMSMode != eCMSMode_All) {
              mInfo.out_color_space = MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB;
              mInfo.out_color_components = 4;
          } else {
              mInfo.out_color_space = JCS_RGB;
          }
          break;
        case JCS_CMYK:
        case JCS_YCCK:
          // libjpeg can convert from YCCK to CMYK, but not to RGB
          mInfo.out_color_space = JCS_CMYK;
          break;
        default:
          mState = JPEG_ERROR;
          MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
                 ("} (unknown colorpsace (3))"));
          return Transition::TerminateFailure();
      }
    }

    // Don't allocate a giant and superfluous memory buffer
    // when not doing a progressive decode.
    mInfo.buffered_image = mDecodeStyle == PROGRESSIVE &&
                           jpeg_has_multiple_scans(&mInfo);

    MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
    nsresult rv = AllocateFrame(/* aFrameNum = */ 0, OutputSize(),
                                FullOutputFrame(), SurfaceFormat::B8G8R8A8);
    if (NS_FAILED(rv)) {
      mState = JPEG_ERROR;
      MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
             ("} (could not initialize image frame)"));
      return Transition::TerminateFailure();
    }

    MOZ_ASSERT(mImageData, "Should have a buffer now");

    if (mDownscaler) {
      nsresult rv = mDownscaler->BeginFrame(Size(), Nothing(),
                                            mImageData,
                                            /* aHasAlpha = */ false);
      if (NS_FAILED(rv)) {
        mState = JPEG_ERROR;
        return Transition::TerminateFailure();
      }
    }

    MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
           ("        JPEGDecoderAccounting: nsJPEGDecoder::"
            "Write -- created image frame with %ux%u pixels",
            mInfo.output_width, mInfo.output_height));

    mState = JPEG_START_DECOMPRESS;
    MOZ_FALLTHROUGH; // to start decompressing.
  }

  case JPEG_START_DECOMPRESS: {
    LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::Write -- entering"
                            " JPEG_START_DECOMPRESS case");
    // Step 4: set parameters for decompression

    // FIXME -- Should reset dct_method and dither mode
    // for final pass of progressive JPEG

    mInfo.dct_method =  JDCT_ISLOW;
    mInfo.dither_mode = JDITHER_FS;
    mInfo.do_fancy_upsampling = TRUE;
    mInfo.enable_2pass_quant = FALSE;
    mInfo.do_block_smoothing = TRUE;

    // Step 5: Start decompressor
    if (jpeg_start_decompress(&mInfo) == FALSE) {
      MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
             ("} (I/O suspension after jpeg_start_decompress())"));
      return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
    }

    // If this is a progressive JPEG ...
    mState = mInfo.buffered_image ?
             JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
    MOZ_FALLTHROUGH; // to decompress sequential JPEG.
  }

  case JPEG_DECOMPRESS_SEQUENTIAL: {
    if (mState == JPEG_DECOMPRESS_SEQUENTIAL) {
      LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::Write -- "
                              "JPEG_DECOMPRESS_SEQUENTIAL case");

      bool suspend;
      OutputScanlines(&suspend);

      if (suspend) {
        MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
               ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
        return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
      }

      // If we've completed image output ...
      NS_ASSERTION(mInfo.output_scanline == mInfo.output_height,
                   "We didn't process all of the data!");
      mState = JPEG_DONE;
    }
    MOZ_FALLTHROUGH; // to decompress progressive JPEG.
  }

  case JPEG_DECOMPRESS_PROGRESSIVE: {
    if (mState == JPEG_DECOMPRESS_PROGRESSIVE) {
      LOG_SCOPE((mozilla::LogModule*)sJPEGLog,
                "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");

      int status;
      do {
        status = jpeg_consume_input(&mInfo);
      } while ((status != JPEG_SUSPENDED) &&
               (status != JPEG_REACHED_EOI));

      for (;;) {
        if (mInfo.output_scanline == 0) {
          int scan = mInfo.input_scan_number;

          // if we haven't displayed anything yet (output_scan_number==0)
          // and we have enough data for a complete scan, force output
          // of the last full scan
          if ((mInfo.output_scan_number == 0) &&
              (scan > 1) &&
              (status != JPEG_REACHED_EOI))
            scan--;

          if (!jpeg_start_output(&mInfo, scan)) {
            MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
                   ("} (I/O suspension after jpeg_start_output() -"
                    " PROGRESSIVE)"));
            return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
          }
        }

        if (mInfo.output_scanline == 0xffffff) {
          mInfo.output_scanline = 0;
        }

        bool suspend;
        OutputScanlines(&suspend);

        if (suspend) {
          if (mInfo.output_scanline == 0) {
            // didn't manage to read any lines - flag so we don't call
            // jpeg_start_output() multiple times for the same scan
            mInfo.output_scanline = 0xffffff;
          }
          MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
                 ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
          return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
        }

        if (mInfo.output_scanline == mInfo.output_height) {
          if (!jpeg_finish_output(&mInfo)) {
            MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
                   ("} (I/O suspension after jpeg_finish_output() -"
                    " PROGRESSIVE)"));
            return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
          }

          if (jpeg_input_complete(&mInfo) &&
              (mInfo.input_scan_number == mInfo.output_scan_number))
            break;

          mInfo.output_scanline = 0;
          if (mDownscaler) {
            mDownscaler->ResetForNextProgressivePass();
          }
        }
      }

      mState = JPEG_DONE;
    }
    MOZ_FALLTHROUGH; // to finish decompressing.
  }

  case JPEG_DONE: {
    LOG_SCOPE((mozilla::LogModule*)sJPEGLog, "nsJPEGDecoder::ProcessData -- entering"
                            " JPEG_DONE case");

    // Step 7: Finish decompression

    if (jpeg_finish_decompress(&mInfo) == FALSE) {
      MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
             ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
      return Transition::ContinueUnbuffered(State::JPEG_DATA); // I/O suspension
    }

    // Make sure we don't feed any more data to libjpeg-turbo.
    mState = JPEG_SINK_NON_JPEG_TRAILER;

    // We're done.
    return Transition::TerminateSuccess();
  }
  case JPEG_SINK_NON_JPEG_TRAILER:
    MOZ_LOG(sJPEGLog, LogLevel::Debug,
           ("[this=%p] nsJPEGDecoder::ProcessData -- entering"
            " JPEG_SINK_NON_JPEG_TRAILER case\n", this));

    MOZ_ASSERT_UNREACHABLE("Should stop getting data after entering state "
                           "JPEG_SINK_NON_JPEG_TRAILER");

    return Transition::TerminateSuccess();

  case JPEG_ERROR:
    MOZ_ASSERT_UNREACHABLE("Should stop getting data after entering state "
                           "JPEG_ERROR");

    return Transition::TerminateFailure();
  }

  MOZ_ASSERT_UNREACHABLE("Escaped the JPEG decoder state machine");
  return Transition::TerminateFailure();
}
Example #16
0
bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
        JpegDecoderMgr** decoderMgrOut) {

    // Create a JpegDecoderMgr to own all of the decompress information
    SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));

    // libjpeg errors will be caught and reported here
    if (setjmp(decoderMgr->getJmpBuf())) {
        return decoderMgr->returnFalse("ReadHeader");
    }

    // Initialize the decompress info and the source manager
    decoderMgr->init();

    // Instruct jpeg library to save the markers that we care about.  Since
    // the orientation and color profile will not change, we can skip this
    // step on rewinds.
    if (codecOut) {
        jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
        jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
    }

    // Read the jpeg header
    if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
        return decoderMgr->returnFalse("ReadHeader");
    }

    if (codecOut) {
        // Get the encoded color type
        SkEncodedInfo::Color color;
        if (!decoderMgr->getEncodedColor(&color)) {
            return false;
        }

        // Create image info object and the codec
        SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);

        Origin orientation = get_exif_orientation(decoderMgr->dinfo());
        sk_sp<SkData> iccData = get_icc_profile(decoderMgr->dinfo());
        sk_sp<SkColorSpace> colorSpace = nullptr;
        if (iccData) {
            colorSpace = SkColorSpace::NewICC(iccData->data(), iccData->size());
            if (!colorSpace) {
                SkCodecPrintf("Could not create SkColorSpace from ICC data.\n");
            }
        }
        if (!colorSpace) {
            // Treat unmarked jpegs as sRGB.
            colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
        }

        const int width = decoderMgr->dinfo()->image_width;
        const int height = decoderMgr->dinfo()->image_height;
        *codecOut = new SkJpegCodec(width, height, info, stream, decoderMgr.release(),
                std::move(colorSpace), orientation, std::move(iccData));
    } else {
        SkASSERT(nullptr != decoderMgrOut);
        *decoderMgrOut = decoderMgr.release();
    }
    return true;
}
Example #17
0
//--------------------------------------------------------------------------------
BitmapData* LoadJPEG(const Path& in_file)
{
	struct jpeg_decompress_struct cinfo;
	struct my_error_mgr jerr;
	
	FILE *infile;
	JSAMPARRAY buffer;

	FOPEN(&infile, in_file.GetData(), L("rb"));
								  
	if (infile == nullptr)
	{
		Assert(false);
		return nullptr;
	}

	cinfo.err = jpeg_std_error(&jerr.pub);
	jerr.pub.error_exit = my_error_exit;
	if (setjmp(jerr.setjmp_buffer)) 
	{
		jpeg_destroy_decompress(&cinfo);
		fclose(infile);
		return nullptr;
	}

	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo, infile);
	jpeg_read_header(&cinfo, true);
	jpeg_start_decompress(&cinfo);

	BufferFormat eFormat = BufferFormat::INVALID_FORMAT;
	switch (cinfo.out_color_space)
	{
	case JCS_EXT_ABGR:	eFormat = BufferFormat::RGBA_U32; break;
	case JCS_EXT_BGRA:	eFormat = BufferFormat::ARGB_U32; break;
	case JCS_EXT_RGBA:	eFormat = BufferFormat::ABGR_U32; break;
	case JCS_RGB:		eFormat = BufferFormat::BGR_U24; break;
	case JCS_EXT_BGR:	eFormat = BufferFormat::RGB_U24; break;
	//case JCS_RGB565:	eFormat = BufferFormat::R5G6B5_U16; break;
	case JCS_GRAYSCALE: eFormat = BufferFormat::A_U8; break;
	default:
		Assert(false);
		return nullptr;
	}

	BitmapData* pData = new BitmapData(cinfo.output_width, cinfo.output_height, eFormat);

	buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, pData->GetBufferPitch(), 1);

	while (cinfo.output_scanline < cinfo.output_height) 
	{
		jpeg_read_scanlines(&cinfo, buffer, 1);
		memcpy((u8*)&(pData->GetBuffer()[(cinfo.output_scanline-1) * pData->GetBufferPitch()]), buffer[0], pData->GetBufferPitch());
	}

	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	fclose(infile);

	Assert(jerr.pub.num_warnings == 0);

	return pData;
}
Example #18
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;
    } 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);
   }

   fclose(infile);
   infile=NULL;
     

   if (dest && !noaction) {
     if (file_exists(newname) && !overwrite_mode) {
       warn("target file already exists: %s\n",newname);
       jpeg_abort_decompress(&dinfo);
       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);
     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 = round(abs(oldquality-quality)/2.0);
       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);


   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;
	  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);;
}
Example #19
0
int JpegDecode(char *srcbuf, char *dstbuf)
{
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
#ifdef PROGRESS_REPORT
  struct cdjpeg_progress_mgr progress;
#endif
  int file_index;
  djpeg_dest_ptr dest_mgr = NULL;
  FILE * input_file;
  FILE * output_file;
  JDIMENSION num_scanlines;

  int argc=5;
  char *argv[5];
  char arg0[] = {"0"};
  char arg1[] = {"-bmp"};
  char arg2[] = {"-outfile"};
  char arg3[] = {"1.raw"};
  char arg4[] = {"E:\\WORK\\JPEGSR6\\JPEG-6B\\p3.jpg"};

  argv[0] = arg0;
  argv[1] = arg1;
  argv[2] = arg2;
  argv[3] = arg3;
  argv[4] = arg4;

  /* On Mac, fetch a command line. */
#ifdef USE_CCOMMAND
  argc = ccommand(&argv);
#endif

  progname = argv[0];
  if (progname == NULL || progname[0] == 0)
    progname = "djpeg";		/* in case C library doesn't provide it */

  /* Initialize the JPEG decompression object with default error handling. */
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);
  /* Add some application-specific error messages (from cderror.h) */
  jerr.addon_message_table = cdjpeg_message_table;
  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
  jerr.last_addon_message = JMSG_LASTADDONCODE;

  /* Insert custom marker processor for COM and APP12.
   * APP12 is used by some digital camera makers for textual info,
   * so we provide the ability to display it as text.
   * If you like, additional APPn marker types can be selected for display,
   * but don't try to override APP0 or APP14 this way (see libjpeg.doc).
   */
  jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
  jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);

  /* Now safe to enable signal catcher. */
#ifdef NEED_SIGNAL_CATCHER
  enable_signal_catcher((j_common_ptr) &cinfo);
#endif

  /* Scan command line to find file names. */
  /* It is convenient to use just one switch-parsing routine, but the switch
   * values read here are ignored; we will rescan the switches after opening
   * the input file.
   * (Exception: tracing level set here controls verbosity for COM markers
   * found during jpeg_read_header...)
   */

  file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);

#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 */

#if 0
  /* 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();
  }
#endif
  input_file = (FILE *)0xFF;
  output_file = (FILE *)0xFF;

#ifdef PROGRESS_REPORT
  start_progress_monitor((j_common_ptr) &cinfo, &progress);
#endif

  /* Specify data source for decompression */
  jpeg_stdio_src(&cinfo, input_file);

  cinfo.src_buffer = (UINT8 *)srcbuf;
  cinfo.src_position = 0;
  cinfo.dst_buffer = (UINT8 *)dstbuf;
  cinfo.dst_position = 0;


  /* Read file header, set default decompression parameters */
  (void) jpeg_read_header(&cinfo, TRUE);

  /* Adjust default decompression parameters by re-parsing the options */
  file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);

  /* Initialize the output module now to let it override any crucial
   * option settings (for instance, GIF wants to force color quantization).
   */
  switch (requested_fmt) {
#ifdef BMP_SUPPORTED
  case FMT_BMP:
    dest_mgr = jinit_write_bmp(&cinfo, FALSE);
    break;
  case FMT_OS2:
    dest_mgr = jinit_write_bmp(&cinfo, TRUE);
    break;
#endif
#ifdef GIF_SUPPORTED
  case FMT_GIF:
    dest_mgr = jinit_write_gif(&cinfo);
    break;
#endif
#ifdef PPM_SUPPORTED
  case FMT_PPM:
    dest_mgr = jinit_write_ppm(&cinfo);
    break;
#endif
#ifdef RLE_SUPPORTED
  case FMT_RLE:
    dest_mgr = jinit_write_rle(&cinfo);
    break;
#endif
#ifdef TARGA_SUPPORTED
  case FMT_TARGA:
    dest_mgr = jinit_write_targa(&cinfo);
    break;
#endif
  default:
    ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
    break;
  }
  dest_mgr->output_file = output_file;

  /* Start decompressor */
  (void) jpeg_start_decompress(&cinfo);

  /* Write output file header */
  (*dest_mgr->start_output) (&cinfo, dest_mgr);

  /* Process data */
  while (cinfo.output_scanline < cinfo.output_height) {
    num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
					dest_mgr->buffer_height);
    (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
  }

#ifdef PROGRESS_REPORT
  /* Hack: count final pass as done in case finish_output does an extra pass.
   * The library won't have updated completed_passes.
   */
  progress.pub.completed_passes = progress.pub.total_passes;
#endif

  /* Finish decompression and release memory.
   * I must do it in this order because output module has allocated memory
   * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
   */
  (*dest_mgr->finish_output) (&cinfo, dest_mgr);
  (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

#if 0
  /* Close files, if we opened them */
  if (input_file != stdin)
    fclose(input_file);
  if (output_file != stdout)
    fclose(output_file);
#endif

#ifdef PROGRESS_REPORT
  end_progress_monitor((j_common_ptr) &cinfo);
#endif

#if 0
  /* All done. */
  exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
#endif
  return 0;			/* suppress no-return-value warnings */
}
Example #20
0
bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
{
    wxCHECK_MSG( image, false, "NULL image pointer" );

    struct jpeg_decompress_struct cinfo;
    wx_error_mgr jerr;
    unsigned char *ptr;

    // save this before calling Destroy()
    const unsigned maxWidth = image->GetOptionInt(wxIMAGE_OPTION_MAX_WIDTH),
                   maxHeight = image->GetOptionInt(wxIMAGE_OPTION_MAX_HEIGHT);
    image->Destroy();

    cinfo.err = jpeg_std_error( &jerr );
    jerr.error_exit = wx_error_exit;

    if (!verbose)
        cinfo.err->output_message = wx_ignore_message;

    /* Establish the setjmp return context for wx_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.
       */
      if (verbose)
      {
        wxLogError(_("JPEG: Couldn't load - file is probably corrupted."));
      }
      (cinfo.src->term_source)(&cinfo);
      jpeg_destroy_decompress(&cinfo);
      if (image->IsOk()) image->Destroy();
      return false;
    }

    jpeg_create_decompress( &cinfo );
    wx_jpeg_io_src( &cinfo, stream );
    jpeg_read_header( &cinfo, TRUE );

    int bytesPerPixel;
    if ((cinfo.out_color_space == JCS_CMYK) || (cinfo.out_color_space == JCS_YCCK))
    {
        cinfo.out_color_space = JCS_CMYK;
        bytesPerPixel = 4;
    }
    else // all the rest is treated as RGB
    {
        cinfo.out_color_space = JCS_RGB;
        bytesPerPixel = 3;
    }

    // scale the picture to fit in the specified max size if necessary
    if ( maxWidth > 0 || maxHeight > 0 )
    {
        unsigned& scale = cinfo.scale_denom;
        while ( (maxWidth && (cinfo.image_width / scale > maxWidth)) ||
                    (maxHeight && (cinfo.image_height / scale > maxHeight)) )
        {
            scale *= 2;
        }
    }

    jpeg_start_decompress( &cinfo );

    image->Create( cinfo.output_width, cinfo.output_height );
    if (!image->IsOk()) {
        jpeg_finish_decompress( &cinfo );
        jpeg_destroy_decompress( &cinfo );
        return false;
    }
    image->SetMask( false );
    ptr = image->GetData();

    unsigned stride = cinfo.output_width * bytesPerPixel;
    JSAMPARRAY tempbuf = (*cinfo.mem->alloc_sarray)
                            ((j_common_ptr) &cinfo, JPOOL_IMAGE, stride, 1 );

    while ( cinfo.output_scanline < cinfo.output_height )
    {
        jpeg_read_scanlines( &cinfo, tempbuf, 1 );
        if (cinfo.out_color_space == JCS_RGB)
        {
            memcpy( ptr, tempbuf[0], stride );
            ptr += stride;
        }
        else // CMYK
        {
            const unsigned char* inptr = (const unsigned char*) tempbuf[0];
            for (size_t i = 0; i < cinfo.output_width; i++)
            {
                wx_cmyk_to_rgb(ptr, inptr);
                ptr += 3;
                inptr += 4;
            }
        }
    }

    // set up resolution if available: it's part of optional JFIF APP0 chunk
    if ( cinfo.saw_JFIF_marker )
    {
        image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, cinfo.X_density);
        image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, cinfo.Y_density);

        // we use the same values for this option as libjpeg so we don't need
        // any conversion here
        image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, cinfo.density_unit);
    }

    jpeg_finish_decompress( &cinfo );
    jpeg_destroy_decompress( &cinfo );
    return true;
}
Example #21
0
imgdata loadJpeg( const char* filename){
    unsigned char a,r,g,b;
    int img_width, img_height;

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    FILE *file;
    JSAMPARRAY pJpegBuffer;
    int row_stride;

    std::string image_name(filename);
    file = fopen(image_name.c_str(), "rb");
    if( file == NULL){
        std::string msg("Error opening ");
        throw std::runtime_error(msg + image_name);
    }
    printf("Loading in files %s\n", image_name.c_str());

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, TRUE);
    jpeg_start_decompress(&cinfo);
    img_width  = cinfo.image_width;
    img_height = cinfo.image_height;
    printf("img_width %d img_height %d\n", img_width, img_height);

    unsigned char *img_data = new unsigned char [4 * img_height * img_width];
    unsigned char *pTest = img_data;
    if(!img_data){
        std::string msg("NO MEM FOR JPEG CONVERT!\n");
        throw std::runtime_error(msg);
    }

    row_stride = img_width * cinfo.output_components;
    pJpegBuffer = (*cinfo.mem->alloc_sarray)
      ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

    while( cinfo.output_scanline < cinfo.output_height){
        jpeg_read_scanlines(&cinfo, pJpegBuffer, 1);
        for( int x=0; x<img_width; x++){
            a = 0;
            r = pJpegBuffer[0][cinfo.output_components*x];
            if( cinfo.output_components > 2){
                g = pJpegBuffer[0][cinfo.output_components*x+1];
                b = pJpegBuffer[0][cinfo.output_components*x+2];
            }else{
                g = r;
                b = r;
            }
            //printf( "r %c g %c b %c\n", r,g,b);
            *(img_data++) = r;
            *(img_data++) = g;
            *(img_data++) = b;
            *(img_data++) = a;
        }
    }
    fclose(file);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    imgdata retval;
    retval.height = img_height;
    retval.width = img_width;
    retval.data = pTest;

    return retval;
}
Example #22
0
int main(int argc, char *argv[]) {
  const char *jpg_path;
  const char *yuv_path;
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE *jpg_fd;
  int luma_width;
  int luma_height;
  int chroma_width;
  int chroma_height;
  int frame_width;
  int yuv_size;
  JSAMPLE *jpg_buffer;
  JSAMPROW yrow_pointer[16];
  JSAMPROW cbrow_pointer[8];
  JSAMPROW crrow_pointer[8];
  JSAMPROW *plane_pointer[3];
  unsigned char *yuv_buffer;
  int x;
  int y;
  FILE *yuv_fd;

  if (argc != 3) {
    fprintf(stderr, "Required arguments:\n");
    fprintf(stderr, "1. Path to JPG input file\n");
    fprintf(stderr, "2. Path to YUV output file\n");
    return 1;
  }

  /* Will check these for validity when opening via 'fopen'. */
  jpg_path = argv[1];
  yuv_path = argv[2];

  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);

  jpg_fd = fopen(jpg_path, "rb");
  if (!jpg_fd) {
    fprintf(stderr, "Invalid path to JPEG file!\n");
    return 1;
  }

  jpeg_stdio_src(&cinfo, jpg_fd);

  jpeg_read_header(&cinfo, TRUE);

  cinfo.raw_data_out = TRUE;
  cinfo.do_fancy_upsampling = FALSE;

  jpeg_start_decompress(&cinfo);

  luma_width = cinfo.output_width;
  luma_height = cinfo.output_height;

  chroma_width = (luma_width + 1) >> 1;
  chroma_height = (luma_height + 1) >> 1;

  yuv_size = luma_width*luma_height + 2*chroma_width*chroma_height;
  yuv_buffer = malloc(yuv_size);
  if (!yuv_buffer) {
    fclose(jpg_fd);
    fprintf(stderr, "Memory allocation failure!\n");
    return 1;
  }

  frame_width = (cinfo.output_width + (16 - 1)) & ~(16 - 1);

  jpg_buffer = malloc(frame_width*16 + 2*(frame_width/2)*8);
  if (!jpg_buffer) {
    fclose(jpg_fd);
    free(yuv_buffer);
    fprintf(stderr, "Memory allocation failure!\n");
    return 1;
  }

  plane_pointer[0] = yrow_pointer;
  plane_pointer[1] = cbrow_pointer;
  plane_pointer[2] = crrow_pointer;

  for (y = 0; y < 16; y++) {
    yrow_pointer[y] = &jpg_buffer[frame_width*y];
  }
  for (y = 0; y < 8; y++) {
    cbrow_pointer[y] = &jpg_buffer[frame_width*16 + (frame_width/2)*y];
    crrow_pointer[y] = &jpg_buffer[frame_width*16 + (frame_width/2)*(8 + y)];
  }

  while (cinfo.output_scanline < cinfo.output_height) {
    int luma_scanline;
    int chroma_scanline;

    luma_scanline = cinfo.output_scanline;
    chroma_scanline = (luma_scanline + 1) >> 1;

    jpeg_read_raw_data(&cinfo, plane_pointer, 16);

    for (y = 0; y < 16 && luma_scanline + y < luma_height; y++) {
      for (x = 0; x < luma_width; x++) {
        yuv_buffer[luma_width*(luma_scanline + y) + x] = yrow_pointer[y][x];
      }
    }
    for (y = 0; y < 8 && chroma_scanline + y < chroma_height; y++) {
      for (x = 0; x < chroma_width; x++) {
        yuv_buffer[luma_width*luma_height +
         chroma_width*(chroma_scanline + y) + x] = cbrow_pointer[y][x];
        yuv_buffer[luma_width*luma_height + chroma_width*chroma_height +
         chroma_width*(chroma_scanline + y) + x] = crrow_pointer[y][x];
      }
    }
  }

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

  fclose(jpg_fd);
  free(jpg_buffer);

  yuv_fd = fopen(yuv_path, "wb");
  if (!yuv_fd) {
    fprintf(stderr, "Invalid path to YUV file!");
    free(yuv_buffer);
    return 1;
  }
  if (fwrite(yuv_buffer, yuv_size, 1, yuv_fd) != 1) {
    fprintf(stderr, "Error writing yuv file\n");
  }

  fclose(yuv_fd);
  free(yuv_buffer);

  return 0;
}
Example #23
0
void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *height)
{
  /* 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 = {NULL};
  /* 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.
   */
  /* This struct represents a JPEG error handler.  It is declared separately
   * because applications often want to supply a specialized error handler
   * (see the second half of this file for an example).  But here we just
   * take the easy way out and use the standard error handler, which will
   * print a message on stderr and call exit() if compression fails.
   * Note that this struct must live as long as the main JPEG parameter
   * struct, to avoid dangling-pointer problems.
   */
  struct jpeg_error_mgr jerr;
  /* More stuff */
  JSAMPARRAY buffer;		/* Output row buffer */
  unsigned int row_stride;	/* physical row width in output buffer */
  unsigned int pixelcount, memcount;
  unsigned int sindex, dindex;
  byte *out;
  int len;
	union {
		byte *b;
		void *v;
	} fbuffer;
  byte  *buf;

  /* 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.
   */

  len = ri->FS_ReadFile ( ( char * ) filename, &fbuffer.v);
  if (!fbuffer.b || len < 0)
	return;

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

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error(&jerr);
  cinfo.err->error_exit = R_JPGErrorExit;
  cinfo.err->output_message = R_JPGOutputMessage;

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

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

  jpeg_mem_src(&cinfo, fbuffer.b, len);

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

 ( 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.
   */

  /* Step 4: set parameters for decompression */

  /*
   * Make sure it always converts images to RGB color space. This will
   * automatically convert 8-bit greyscale images to RGB as well.
   */
  cinfo.out_color_space = JCS_RGB;

  /* Step 5: Start decompressor */

 ( 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 */

  pixelcount = cinfo.output_width * cinfo.output_height;

  if(!cinfo.output_width || !cinfo.output_height
      || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height
      || pixelcount > 0x1FFFFFFF || cinfo.output_components != 3
    )
  {
    // Free the memory to make sure we don't leak memory
    ri->FS_FreeFile (fbuffer.v);
    jpeg_destroy_decompress(&cinfo);
  
    ri->Error(ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d", filename,
		    cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components);
  }

  memcount = pixelcount * 4;
  row_stride = cinfo.output_width * cinfo.output_components;

  out = ri->Malloc(memcount);

  *width = cinfo.output_width;
  *height = cinfo.output_height;

  /* 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.
   */
  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.
     */
	buf = ((out+(row_stride*cinfo.output_scanline)));
	buffer = &buf;
   ( void ) jpeg_read_scanlines(&cinfo, buffer, 1);
  }
  
  buf = out;

  // Expand from RGB to RGBA
  sindex = pixelcount * cinfo.output_components;
  dindex = memcount;

  do
  {	
    buf[--dindex] = 255;
    buf[--dindex] = buf[--sindex];
    buf[--dindex] = buf[--sindex];
    buf[--dindex] = buf[--sindex];
  } while(sindex);

  *pic = out;

  /* Step 7: Finish decompression */

  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...)
   */
  ri->FS_FreeFile (fbuffer.v);

  /* 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! */
}
Example #24
0
int LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) {
  /* 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.
   */
  /* This struct represents a JPEG error handler.  It is declared separately
   * because applications often want to supply a specialized error handler
   * (see the second half of this file for an example).  But here we just
   * take the easy way out and use the standard error handler, which will
   * print a message on stderr and call exit() if compression fails.
   * Note that this struct must live as long as the main JPEG parameter
   * struct, to avoid dangling-pointer problems.
   */
  struct jpeg_error_mgr jerr;
  /* More stuff */
  fileHandle_t infile;		/* source file */
  JSAMPARRAY buffer;		/* Output row buffer */
  int row_stride;		/* physical row width in output buffer */
  unsigned char *out;

  /* 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.
   */

  FS_FOpenFileRead( filename, &infile, qfalse );
  if (infile == 0) {
    return 0;
  }

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

  /* We have to set up the error handler first, in case the initialization
   * step fails.  (Unlikely, but it could happen if you are out of memory.)
   * This routine fills in the contents of struct jerr, and returns jerr's
   * address which we place into the link field in cinfo.
   */
  cinfo.err = jpeg_std_error(&jerr);

  /* 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);

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

  (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.
   */

  /* 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 */

  (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;

  out = Z_Malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components);

  *pic = out;
  *width = cinfo.output_width;
  *height = cinfo.output_height;

  /* 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.
   */
  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.
     */
	buffer = (JSAMPARRAY)out+(row_stride*cinfo.output_scanline);
    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
  }

  /* 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...)
   */
  FS_FCloseFile(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! */
  return 1;
}
Example #25
0
static gint32
load_image (char *filename)
{
  GPixelRgn pixel_rgn;
  TileDrawable *drawable;
  gint32 image_ID;
  gint32 layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE *infile;
  guchar *buf;
  guchar **rowbuf;
  char *name;
  int image_type;
  int layer_type;
  int tile_height;
  int scanlines;
  int i, start, end;
  int m;
  int depth = 8;

  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if ((infile = fopen (filename, "rb")) == NULL)
    {
      g_warning ("can't open \"%s\"\n", filename);
      gimp_quit ();
    }

  if( strrchr(filename,'.') &&
      strcmp( strrchr(filename, '.'), ".jp4") == 0 )
    depth = 16;

  name = malloc (strlen (filename) + 12);
  sprintf (name, "%s %s:", _("Loading"), filename);
  gimp_progress_init (name);
  free (name);

  image_ID = -1;
  /* 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.
       */
      jpeg_destroy_decompress (&cinfo);
      if (infile)
	fclose (infile);
      if (image_ID != -1)
	gimp_image_delete (image_ID);
      gimp_quit ();
    }
  /* 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);

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

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

  (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.
   */

  /* 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.
   */
  prepareColour( &cinfo );

  /* Step 5: Start decompressor */

  jpeg_start_decompress (&cinfo);

  /* 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.
   */
  /* temporary buffer */
  tile_height = gimp_tile_height ();
  buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components);
  rowbuf = g_new (guchar*, tile_height);

  for (i = 0; i < tile_height; i++)
    rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i;

  /* Create a new image of the proper size and associate the filename with it.
   */
  if(depth == 8)
  {
    switch (cinfo.output_components)
    {
    case 1:
      image_type = GRAY;
      layer_type = GRAY_IMAGE;
      break;
    case 3:
      image_type = RGB;
      layer_type = RGB_IMAGE;
      break;
    case 4:
      image_type = RGB;
      layer_type = RGBA_IMAGE;
      break;
    default:
      gimp_quit ();
    }
  } else {
    switch (cinfo.output_components)
    {
    case 1:
      image_type = U16_GRAY;
      layer_type = U16_GRAY_IMAGE;
      break;
    case 3:
      image_type = U16_RGB;
      layer_type = U16_RGB_IMAGE;
      break;
    case 4:
      image_type = U16_RGB;
      layer_type = U16_RGBA_IMAGE;
      break;
    default:
      gimp_quit ();
    }
  }

  image_ID = gimp_image_new (cinfo.output_width / (depth/8), cinfo.output_height,
                             image_type);
  gimp_image_set_filename (image_ID, filename);

  layer_ID = gimp_layer_new (image_ID, _("Background"),
			     cinfo.output_width / (depth/8),
			     cinfo.output_height,
			     layer_type, 100, NORMAL_MODE);
  gimp_image_add_layer (image_ID, layer_ID, 0);

  drawable = gimp_drawable_get (layer_ID);
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);

  /* 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.
   */
  while (cinfo.output_scanline < cinfo.output_height)
    {
      start = cinfo.output_scanline;
      end = cinfo.output_scanline + tile_height;
      end = MIN (end,CAST(int) cinfo.output_height);
      scanlines = end - start;

      for (i = 0; i < scanlines; i++)
	jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1);

      /*
      for (i = start; i < end; i++)
	gimp_pixel_rgn_set_row (&pixel_rgn, tilerow[i - start], 0, i, drawable->width);
	*/

      if(cinfo.out_color_space == JCS_CMYK)
        for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i)
          buf[i] = 255 - buf[i];

      if(depth == 16 && 0)
        for(i = 0; i < scanlines*drawable->width*cinfo.output_components; ++i)
        {
          unsigned char c = buf[2*i];
          buf[2*i] = buf[2*i+1];
          buf[2*i+1] = c;
        }

      gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, start, drawable->width, scanlines);

      gimp_progress_update ((double) cinfo.output_scanline / (double) cinfo.output_height);
    }

  // Step 6a: read icc profile
  {
    LPBYTE Buffer = NULL;
    size_t Len = 0;
    cmsHPROFILE hProfile=NULL;

    if (read_icc_profile(&cinfo, &Buffer, &Len))
    {
      printf ("%s:%d %s() embedded profile found\n",__FILE__,__LINE__,__func__);
    } else if (read_icc_profile2(&cinfo, &Buffer, &Len)) {
      printf ("%s:%d %s() default profile selected\n",__FILE__,__LINE__,__func__);
    }

    if(Buffer && Len)
    {
      hProfile = cmsOpenProfileFromMem(Buffer, Len);
      if (hProfile) {
        gimp_image_set_icc_profile_by_mem (image_ID, Len, Buffer, ICC_IMAGE_PROFILE);
        cmsCloseProfile (hProfile);
        free(Buffer);
        printf ("%s:%d %s() set profile\n",__FILE__,__LINE__,__func__);
      }
    }
  }

  /* Step 7: Finish decompression */

  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);

  /* free up the temporary buffers */
  g_free (rowbuf);
  g_free (buf);

  /* 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.num_warnings is nonzero).
   */

  /* Tell the GIMP to display the image.
   */
  gimp_drawable_flush (drawable);

  return image_ID;
}
Example #26
0
/* Shared library entry point */
GdkPixbuf *
gdk_pixbuf__jpeg_image_load (FILE *f)
{
	gint i;
	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;

	if (sigsetjmp (jerr.setjmp_buffer, 1)) {
		/* Whoops there was a jpeg error */
		if (pixbuf)
			gdk_pixbuf_unref (pixbuf);

		jpeg_destroy_decompress (&cinfo);
		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_read_header (&cinfo, TRUE);
	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);
		return NULL;
	}

	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:
		      gdk_pixbuf_unref (pixbuf);
		      jpeg_destroy_decompress (&cinfo);
		      return NULL;
		}
	}

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

	return pixbuf;
}
Example #27
0
bool ImageJpgFile::JpegLoader::InitOk()
{
  // For now we don't support alpha-map images
  // The libjpeg docs are unclear on this subject, it seems that alpha
  // mapped images could be supported by libjpeg (it supports a random
  // number of abstract color channels) but I (A.Z.) just don't have
  // alpha-mapped JPEG images and can't test it.
  Format &= ~CS_IMGFMT_ALPHA;

  /* ==== 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;
  if (setjmp (jerr.setjmp_buffer))
  {
    char errmsg [256];
    if (cinfo.err->msg_code != JERR_NO_SOI)
    {
      cinfo.err->format_message ((jpeg_common_struct *)&cinfo, errmsg);
      Report (object_reg, CS_REPORTER_SEVERITY_WARNING,
	"%s\n", errmsg);
    }
    if (decompCreated) jpeg_destroy_decompress (&cinfo);
    decompCreated = false;
    return false;
  }

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

  /* ==== Step 2: specify data source (memory buffer, in this case) */
  jpeg_memory_src (&cinfo, dataSource->GetData(), (int)dataSource->GetSize());

  /* ==== Step 3: read file parameters with jpeg_read_header() */
  (void) jpeg_read_header(&cinfo, TRUE);

  bool isGrayScale = cinfo.jpeg_color_space == JCS_GRAYSCALE;
  /* ==== Step 4: set parameters for decompression */
  // We want max quality, doesnt matter too much it can be a bit slow
  if (isGrayScale)
    dataType = rdtIndexed;
  else
    dataType = rdtR8G8B8;
  // We almost always want RGB output (no grayscale, yuv etc)
  if (cinfo.jpeg_color_space != JCS_GRAYSCALE)
    cinfo.out_color_space = JCS_RGB;

  // Recalculate output image dimensions
  jpeg_calc_output_dimensions (&cinfo);

  /* ==== Step 5: Start decompressor */

  jpeg_start_decompress (&cinfo);
  /* 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.
   */
  Width = cinfo.output_width;
  Height = cinfo.output_height;

  if ((Format & CS_IMGFMT_MASK) == CS_IMGFMT_ANY)
    Format = (Format & ~CS_IMGFMT_MASK) |
      (isGrayScale ? CS_IMGFMT_PALETTED8 : CS_IMGFMT_TRUECOLOR);

  return true;
}
Example #28
0
/*
 * context - from image_begin_load
 * buf - new image data
 * size - length of new image data
 *
 * append image data onto inrecrementally built output image
 */
gboolean
gdk_pixbuf__jpeg_image_load_increment (gpointer data, guchar *buf, guint size)
{
	JpegProgContext *context = (JpegProgContext *)data;
	struct jpeg_decompress_struct *cinfo;
	my_src_ptr  src;
	guint       num_left, num_copy;
	guint       last_bytes_left;
	guint       spinguard;
	gboolean    first;
	const guchar *bufhd;

	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;

	/* 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_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;
		} else {
		/* 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)
				spinguard++;
			else
				last_bytes_left = src->pub.bytes_in_buffer;
		}

		/* 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;

			rc = jpeg_read_header (cinfo, TRUE);
			context->src_initialized = TRUE;

			if (rc == JPEG_SUSPENDED)
				continue;

			context->got_header = TRUE;

		} else if (!context->did_prescan) {
			int rc;
                        
			/* start decompression */
			cinfo->buffered_image = TRUE;
			rc = jpeg_start_decompress (cinfo);
			cinfo->do_fancy_upsampling = FALSE;
			cinfo->do_block_smoothing = FALSE;

			context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 
							 cinfo->output_components == 4 ? TRUE : FALSE,
							 8, 
							 cinfo->image_width,
							 cinfo->image_height);

			if (context->pixbuf == NULL) {
				return FALSE;
			}

			/* Use pixbuf buffer to store decompressed data */
			context->dptr = context->pixbuf->pixels;

			/* Notify the client that we are ready to go */
			(* context->prepared_func) (context->pixbuf,
						    context->user_data);

			if (rc == JPEG_SUSPENDED)
				continue;

			context->did_prescan = TRUE;
		} else {
			/* we're decompressing so feed jpeg lib scanlines */
			guchar *lines[4];
			guchar **lptr;
			guchar *rowptr;
			gint   nlines, i;

			/* 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;
				}
				/* keep going until we've done all scanlines */
				while (cinfo->output_scanline < cinfo->output_height) {
					lptr = lines;
					rowptr = context->dptr;
					for (i=0; i < cinfo->rec_outbuf_height; i++) {
						*lptr++ = rowptr;
						rowptr += context->pixbuf->rowstride;
					}
					
					nlines = jpeg_read_scanlines (cinfo, lines,
								      cinfo->rec_outbuf_height);
					if (nlines == 0)
						break;

					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:
						    return FALSE;
					}

					context->dptr += nlines * context->pixbuf->rowstride;
					
				        /* send updated signal */
					(* context->updated_func) (context->pixbuf,
								   0, 
								   cinfo->output_scanline-1,
								   cinfo->image_width, 
								   nlines,
								   context->user_data);
				}
				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;
		}
	}

	return TRUE;
}
Example #29
0
void* JPEG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
{
  JPEG* jpeg = NULL;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  unsigned char* buffer = NULL;
  size_t stride;
  unsigned char* line_buffer_array[3];
  int read_lines;

  jpeg = (JPEG*) malloc(sizeof(JPEG));
  if (jpeg == NULL) {
    WTF_OM;
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }

  // Init
  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = my_error_exit;
  if (setjmp(jerr.setjmp_buffer)) {
    LOGE(EMSG("%s"), emsg);
    free(jpeg);
    free(buffer);
    jpeg_destroy_decompress(&cinfo);
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }
  jpeg_create_decompress(&cinfo);
  jpeg_custom_src(&cinfo, &custom_read, patch_head_input_stream);
  jpeg_read_header(&cinfo, TRUE);

  // Start decompress
  cinfo.out_color_space = JCS_EXT_RGBA;
  jpeg_start_decompress(&cinfo);

  stride = cinfo.output_components * cinfo.output_width;
  buffer = malloc(stride * cinfo.output_height);
  if (buffer == NULL) {
    free(jpeg);
    jpeg_destroy_decompress(&cinfo);
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }

  // Copy buffer
  line_buffer_array[0] = buffer;
  line_buffer_array[1] = line_buffer_array[0] + stride;
  line_buffer_array[2] = line_buffer_array[1] + stride;
  while (cinfo.output_scanline < cinfo.output_height) {
    read_lines = jpeg_read_scanlines(&cinfo, line_buffer_array, 3);
    line_buffer_array[0] += stride * read_lines;
    line_buffer_array[1] = line_buffer_array[0] + stride;
    line_buffer_array[2] = line_buffer_array[1] + stride;
  }

  // Finish decompress
  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  // Close stream
  close_patch_head_input_stream(get_env(), patch_head_input_stream);
  destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);

  // Fill jpeg
  jpeg->width = cinfo.output_width;
  jpeg->height = cinfo.output_height;
  jpeg->buffer = buffer;

  return jpeg;
}
bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
                                  SkBitmap::Config prefConfig, Mode mode) {
#ifdef TIME_DECODE
    AutoTimeMillis atm("JPEG Decode");
#endif

    SkAutoMalloc  srcStorage;
    JPEGAutoClean autoClean;

    jpeg_decompress_struct  cinfo;
    sk_error_mgr            sk_err;
    sk_source_mgr           sk_stream(stream);

    cinfo.err = jpeg_std_error(&sk_err);
    sk_err.error_exit = sk_error_exit;

    // All objects need to be instantiated before this setjmp call so that
    // they will be cleaned up properly if an error occurs.
    if (setjmp(sk_err.fJmpBuf)) {
        return false;
    }

    jpeg_create_decompress(&cinfo);
    autoClean.set(&cinfo);

    //jpeg_stdio_src(&cinfo, file);
    cinfo.src = &sk_stream;

    jpeg_read_header(&cinfo, true);

    /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
        can) much faster that we, just use their num/denom api to approximate
        the size.
    */
    int sampleSize = this->getSampleSize();

    cinfo.dct_method = JDCT_IFAST;
    cinfo.scale_num = 1;
    cinfo.scale_denom = sampleSize;

    /*  image_width and image_height are the original dimensions, available
        after jpeg_read_header(). To see the scaled dimensions, we have to call
        jpeg_start_decompress(), and then read output_width and output_height.
    */
    jpeg_start_decompress(&cinfo);

    /*  If we need to better match the request, we might examine the image and
        output dimensions, and determine if the downsampling jpeg provided is
        not sufficient. If so, we can recompute a modified sampleSize value to
        make up the difference.
        
        To skip this additional scaling, just set sampleSize = 1; below.
    */
    sampleSize = sampleSize * cinfo.output_width / cinfo.image_width;

    // check for supported formats
    bool isRGB; // as opposed to gray8
    if (3 == cinfo.num_components && JCS_RGB == cinfo.out_color_space) {
        isRGB = true;
    } else if (1 == cinfo.num_components &&
               JCS_GRAYSCALE == cinfo.out_color_space) {
        isRGB = false;  // could use Index8 config if we want...
    } else {
        SkDEBUGF(("SkJPEGImageDecoder: unsupported jpeg colorspace %d with %d components\n",
                    cinfo.jpeg_color_space, cinfo.num_components));
        return false;
    }
    
    SkBitmap::Config config = prefConfig;
    // if no user preference, see what the device recommends
    if (config == SkBitmap::kNo_Config)
        config = SkImageDecoder::GetDeviceConfig();

    // only these make sense for jpegs
    if (config != SkBitmap::kARGB_8888_Config &&
            config != SkBitmap::kARGB_4444_Config &&
            config != SkBitmap::kRGB_565_Config) {
        config = SkBitmap::kARGB_8888_Config;
    }

    // should we allow the Chooser (if present) to pick a config for us???
    if (!this->chooseFromOneChoice(config, cinfo.output_width,
                                   cinfo.output_height)) {
        return false;
    }

    SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height,
                                  sampleSize);
    
    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
    // jpegs are always opauqe (i.e. have no per-pixel alpha)
    bm->setIsOpaque(true);

    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
        return true;
    }
    if (!this->allocPixelRef(bm, NULL)) {
        return false;
    }

    SkAutoLockPixels alp(*bm);
    
    if (!sampler.begin(bm,
                      isRGB ? SkScaledBitmapSampler::kRGB :
                              SkScaledBitmapSampler::kGray,
                      this->getDitherImage())) {
        return false;
    }

    uint8_t* srcRow = (uint8_t*)srcStorage.alloc(cinfo.output_width * 3);

    skip_src_rows(&cinfo, srcRow, sampler.srcY0());
    for (int y = 0;; y++) {
        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
        int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
        SkASSERT(row_count == 1);
        
        sampler.next(srcRow);
        if (bm->height() - 1 == y) {
            break;
        }
        skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1);
    }

    // ??? If I don't do this, I get an error from finish_decompress
    skip_src_rows(&cinfo, srcRow, cinfo.output_height - cinfo.output_scanline);
        
    jpeg_finish_decompress(&cinfo);

    return true;
}