예제 #1
0
파일: jpegtran.c 프로젝트: novas0x2a/gthumb
gboolean
jpegtran (void           *in_buffer,
          gsize           in_buffer_size,
          void          **out_buffer,
          gsize          *out_buffer_size,
          GthTransform    transformation,
          JpegMcuAction   mcu_action,
          GError        **error)
{
    struct jpeg_decompress_struct  srcinfo;
    struct jpeg_compress_struct    dstinfo;
    struct error_handler_data      jsrcerr, jdsterr;
    gboolean                       success;

    *out_buffer = NULL;
    *out_buffer_size = 0;

    /* Initialize the JPEG decompression object with default error
     * handling. */
    srcinfo.err = jpeg_std_error (&(jsrcerr.pub));
    jsrcerr.pub.error_exit = fatal_error_handler;
    jsrcerr.pub.output_message = output_message_handler;
    jsrcerr.error = error;

    jpeg_create_decompress (&srcinfo);

    /* Initialize the JPEG compression object with default error
     * handling. */
    dstinfo.err = jpeg_std_error (&(jdsterr.pub));
    jdsterr.pub.error_exit = fatal_error_handler;
    jdsterr.pub.output_message = output_message_handler;
    jdsterr.error = error;

    jpeg_create_compress (&dstinfo);

    dstinfo.err->trace_level = 0;
    dstinfo.arith_code = FALSE;
    dstinfo.optimize_coding = FALSE;

    jsrcerr.pub.trace_level = jdsterr.pub.trace_level;
    srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;

    /* Decompression error handler */
    if (sigsetjmp (jsrcerr.setjmp_buffer, 1)) {
        jpeg_destroy_compress (&dstinfo);
        jpeg_destroy_decompress (&srcinfo);
        return FALSE;
    }

    /* Compression error handler */
    if (sigsetjmp (jdsterr.setjmp_buffer, 1)) {
        jpeg_destroy_compress (&dstinfo);
        jpeg_destroy_decompress (&srcinfo);
        return FALSE;
    }

    /* Specify data source for decompression */
    _jpeg_memory_src (&srcinfo, in_buffer, in_buffer_size);

    /* Specify data destination for compression */
    _jpeg_memory_dest (&dstinfo, out_buffer, out_buffer_size);

    /* Apply transformation */
    success = jpegtran_internal (&srcinfo, &dstinfo, transformation, JCOPYOPT_ALL, mcu_action, error);

    /* Release memory */
    jpeg_destroy_compress (&dstinfo);
    jpeg_destroy_decompress (&srcinfo);

    if (success) {
        gth_hook_invoke ("jpegtran-after", out_buffer, out_buffer_size, &transformation);
    }
    else {
        g_free (*out_buffer);
        *out_buffer_size = 0;
    }

    return success;
}
예제 #2
0
static gboolean
_cairo_surface_write_as_jpeg (cairo_surface_t  *image,
			      char            **buffer,
			      gsize            *buffer_size,
			      char            **keys,
			      char            **values,
			      GError          **error)
{
	struct jpeg_compress_struct cinfo;
	struct error_handler_data jerr;
	guchar            *buf = NULL;
	guchar            *pixels = NULL;
	volatile int       quality = 85; /* default; must be between 0 and 100 */
	volatile int       smoothing = 0;
	volatile gboolean  optimize = FALSE;
#ifdef HAVE_PROGRESSIVE_JPEG
	volatile gboolean  progressive = FALSE;
#endif
	int                w, h = 0;
	int                rowstride = 0;

	if (keys && *keys) {
		char **kiter = keys;
		char **viter = values;

		while (*kiter) {
			if (strcmp (*kiter, "quality") == 0) {
				char *endptr = NULL;
				quality = strtol (*viter, &endptr, 10);

				if (endptr == *viter) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG quality must be a value between 0 and 100; value '%s' could not be parsed.",
						     *viter);

					return FALSE;
				}

				if (quality < 0 || quality > 100) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG quality must be a value between 0 and 100; value '%d' is not allowed.",
						     quality);

					return FALSE;
				}
			}
			else if (strcmp (*kiter, "smooth") == 0) {
				char *endptr = NULL;
				smoothing = strtol (*viter, &endptr, 10);

				if (endptr == *viter) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG smoothing must be a value between 0 and 100; value '%s' could not be parsed.",
						     *viter);

					return FALSE;
				}

				if (smoothing < 0 || smoothing > 100) {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG smoothing must be a value between 0 and 100; value '%d' is not allowed.",
						     smoothing);

					return FALSE;
				}
			}
			else if (strcmp (*kiter, "optimize") == 0) {
				if (strcmp (*viter, "yes") == 0)
					optimize = TRUE;
				else if (strcmp (*viter, "no") == 0)
					optimize = FALSE;
				else {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG optimize option must be 'yes' or 'no', value is: %s", *viter);

					return FALSE;
				}
			}
#ifdef HAVE_PROGRESSIVE_JPEG
			else if (strcmp (*kiter, "progressive") == 0) {
				if (strcmp (*viter, "yes") == 0)
					progressive = TRUE;
				else if (strcmp (*viter, "no") == 0)
					progressive = FALSE;
				else {
					g_set_error (error,
						     GDK_PIXBUF_ERROR,
						     GDK_PIXBUF_ERROR_BAD_OPTION,
						     "JPEG progressive option must be 'yes' or 'no', value is: %s", *viter);

					return FALSE;
				}
			}
#endif
			else {
				g_warning ("Bad option name '%s' passed to JPEG saver", *kiter);
				return FALSE;
			}

			++kiter;
			++viter;
		}
	}

	rowstride = cairo_image_surface_get_stride (image);
	w = cairo_image_surface_get_width (image);
	h = cairo_image_surface_get_height (image);
	pixels = _cairo_image_surface_flush_and_get_data (image);
	g_return_val_if_fail (pixels != NULL, FALSE);

	/* allocate a small buffer to convert image data */

	buf = g_try_malloc (w * 3 * sizeof (guchar));
	if (! buf) {
		g_set_error (error,
			     GDK_PIXBUF_ERROR,
			     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
			     "Couldn't allocate memory for loading JPEG file");
		return FALSE;
	}

	/* set up error handling */

	cinfo.err = jpeg_std_error (&(jerr.pub));
	jerr.pub.error_exit = fatal_error_handler;
	jerr.pub.output_message = output_message_handler;
	jerr.error = error;
	if (sigsetjmp (jerr.setjmp_buffer, 1)) {
		jpeg_destroy_compress (&cinfo);
		g_free (buf);
		return FALSE;
	}

	/* setup compress params */

	jpeg_create_compress (&cinfo);
	_jpeg_memory_dest (&cinfo, (void **)buffer, buffer_size);

	cinfo.image_width      = w;
	cinfo.image_height     = h;
	cinfo.input_components = 3;
	cinfo.in_color_space   = JCS_RGB;

	/* set up jepg compression parameters */

	jpeg_set_defaults (&cinfo);
	jpeg_set_quality (&cinfo, quality, TRUE);
	cinfo.smoothing_factor = smoothing;
	cinfo.optimize_coding = optimize;

#ifdef HAVE_PROGRESSIVE_JPEG
	if (progressive)
		jpeg_simple_progression (&cinfo);
#endif /* HAVE_PROGRESSIVE_JPEG */

	jpeg_start_compress (&cinfo, TRUE);

	/* go one scanline at a time... and save */
	while (cinfo.next_scanline < cinfo.image_height) {
		JSAMPROW *jbuf;

		/* convert scanline from RGBA to RGB packed */

		_cairo_copy_line_as_rgba_big_endian (buf, pixels, w, FALSE);

		/* write scanline */
		jbuf = (JSAMPROW *)(&buf);
		jpeg_write_scanlines (&cinfo, jbuf, 1);

		pixels += rowstride;
	}

	/* finish off */

	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);
	g_free (buf);

	return TRUE;
}