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