[eog] Avoid recompressing JPEGs as PNG when printing
- From: Felix Riemann <friemann src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [eog] Avoid recompressing JPEGs as PNG when printing
- Date: Wed, 11 Apr 2012 19:27:00 +0000 (UTC)
commit 7029dfe154cf8d1ce4df8fd6f3157b344e0ad9b7
Author: Felix Riemann <friemann gnome org>
Date: Wed Apr 11 21:15:39 2012 +0200
Avoid recompressing JPEGs as PNG when printing
Use cairo's feature to simply attach the source file data to
the printing surface. This reduces the file size of the resulting
PDF file pretty much to the source file size.
https://bugzilla.gnome.org/show_bug.cgi?id=394260
src/eog-image.c | 18 +++++++-
src/eog-image.h | 6 ++-
src/eog-print.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 160 insertions(+), 2 deletions(-)
---
diff --git a/src/eog-image.c b/src/eog-image.c
index fd2b2c0..f813c2b 100644
--- a/src/eog-image.c
+++ b/src/eog-image.c
@@ -2510,6 +2510,8 @@ eog_image_get_svg (EogImage *img)
return img->priv->svg;
}
+#endif
+
EogTransform *
eog_image_get_transform (EogImage *img)
@@ -2519,7 +2521,13 @@ eog_image_get_transform (EogImage *img)
return img->priv->trans;
}
-#endif
+EogTransform*
+eog_image_get_autorotate_transform (EogImage *img)
+{
+ g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
+
+ return img->priv->trans_autorotate;
+}
/**
* eog_image_file_changed:
@@ -2565,3 +2573,11 @@ eog_image_is_file_writable (EogImage *img)
return is_writable;
}
+
+gboolean
+eog_image_is_jpeg (EogImage *img)
+{
+ g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
+
+ return ((img->priv->file_type != NULL) && (g_ascii_strcasecmp (img->priv->file_type, EOG_FILE_FORMAT_JPEG) == 0));
+}
diff --git a/src/eog-image.h b/src/eog-image.h
index d886278..abefebe 100644
--- a/src/eog-image.h
+++ b/src/eog-image.h
@@ -210,9 +210,13 @@ gboolean eog_image_start_animation (EogImage *img);
#ifdef HAVE_RSVG
gboolean eog_image_is_svg (EogImage *img);
RsvgHandle *eog_image_get_svg (EogImage *img);
-EogTransform *eog_image_get_transform (EogImage *img);
#endif
+EogTransform *eog_image_get_transform (EogImage *img);
+EogTransform *eog_image_get_autorotate_transform (EogImage *img);
+
+gboolean eog_image_is_jpeg (EogImage *img);
+
void eog_image_file_changed (EogImage *img);
gboolean eog_image_is_file_changed (EogImage *img);
diff --git a/src/eog-print.c b/src/eog-print.c
index a41ca82..f84808a 100644
--- a/src/eog-print.c
+++ b/src/eog-print.c
@@ -45,6 +45,29 @@ typedef struct {
GtkUnit unit;
} EogPrintData;
+/* art_affine_flip modified to work with cairo_matrix_t */
+static void
+_eog_cairo_matrix_flip (cairo_matrix_t *dst, const cairo_matrix_t *src, gboolean horiz, gboolean vert)
+{
+ dst->xx = horiz ? -src->xx : src->xx;
+ dst->yx = horiz ? -src->yx : src->yx;
+ dst->xy = vert ? -src->xy : src->xy;
+ dst->yy = vert ? -src->yy : src->yy;
+ dst->x0 = horiz ? -src->x0 : src->x0;
+ dst->y0 = vert ? -src->y0 : src->y0;
+}
+
+static gboolean
+_cairo_ctx_supports_jpg_metadata (cairo_t *cr)
+{
+ cairo_surface_t *surface = cairo_get_target (cr);
+ cairo_surface_type_t type = cairo_surface_get_type (surface);
+
+ /* Based on cairo-1.10 */
+ return (type == CAIRO_SURFACE_TYPE_PDF || type == CAIRO_SURFACE_TYPE_PS ||
+ type == CAIRO_SURFACE_TYPE_SVG || type == CAIRO_SURFACE_TYPE_WIN32_PRINTING);
+}
+
static void
eog_print_draw_page (GtkPrintOperation *operation,
GtkPrintContext *context,
@@ -105,8 +128,123 @@ eog_print_draw_page (GtkPrintOperation *operation,
RsvgHandle *svg = eog_image_get_svg (data->image);
rsvg_handle_render_cairo (svg, cr);
+ return;
} else
#endif
+ /* JPEGs can be attached to the cairo surface which simply embeds the JPEG file into the
+ * destination PDF skipping (PNG-)recompression. This should reduce PDF sizes enormously. */
+ if (eog_image_is_jpeg (data->image) && _cairo_ctx_supports_jpg_metadata (cr))
+ {
+ GFile *file;
+ char *img_data;
+ gsize data_len;
+ cairo_surface_t *surface = NULL;
+
+ eog_debug_message (DEBUG_PRINTING, "Attaching image to cairo surface");
+
+ file = eog_image_get_file (data->image);
+ if (g_file_load_contents (file, NULL, &img_data, &data_len, NULL, NULL))
+ {
+ EogTransform *tf = eog_image_get_transform (data->image);
+ EogTransform *auto_tf = eog_image_get_autorotate_transform (data->image);
+ cairo_matrix_t mx, mx2;
+
+ if (!tf && auto_tf) {
+ /* If only autorotation data present,
+ * make it the normal rotation. */
+ tf = auto_tf;
+ auto_tf = NULL;
+ }
+
+ /* Care must be taken with height and width values. They are not the original
+ * values but were affected by the transformation. As the surface needs to be
+ * generated using the original dimensions they might need to be flipped. */
+ if (tf) {
+ if (auto_tf) {
+ /* If we have an autorotation apply
+ * it before the others */
+ tf = eog_transform_compose (auto_tf, tf);
+ }
+
+ switch (eog_transform_get_transform_type (tf)) {
+ case EOG_TRANSFORM_ROT_90:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, height, width);
+ cairo_rotate (cr, 90.0 * (G_PI/180.0));
+ cairo_translate (cr, 0.0, -width);
+ break;
+ case EOG_TRANSFORM_ROT_180:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, width, height);
+ cairo_rotate (cr, 180.0 * (G_PI/180.0));
+ cairo_translate (cr, -width, -height);
+ break;
+ case EOG_TRANSFORM_ROT_270:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, height, width);
+ cairo_rotate (cr, 270.0 * (G_PI/180.0));
+ cairo_translate (cr, -height, 0.0);
+ break;
+ case EOG_TRANSFORM_FLIP_HORIZONTAL:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, width, height);
+ cairo_matrix_init_identity (&mx);
+ _eog_cairo_matrix_flip (&mx2, &mx, TRUE, FALSE);
+ cairo_transform (cr, &mx2);
+ cairo_translate (cr, -width, 0.0);
+ break;
+ case EOG_TRANSFORM_FLIP_VERTICAL:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, width, height);
+ cairo_matrix_init_identity (&mx);
+ _eog_cairo_matrix_flip (&mx2, &mx, FALSE, TRUE);
+ cairo_transform (cr, &mx2);
+ cairo_translate (cr, 0.0, -height);
+ break;
+ case EOG_TRANSFORM_TRANSPOSE:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, height, width);
+ cairo_matrix_init_rotate (&mx, 90.0 * (G_PI/180.0));
+ cairo_matrix_init_identity (&mx2);
+ _eog_cairo_matrix_flip (&mx2, &mx2, TRUE, FALSE);
+ cairo_matrix_multiply (&mx2, &mx, &mx2);
+ cairo_transform (cr, &mx2);
+ break;
+ case EOG_TRANSFORM_TRANSVERSE:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, height, width);
+ cairo_matrix_init_rotate (&mx, 90.0 * (G_PI/180.0));
+ cairo_matrix_init_identity (&mx2);
+ _eog_cairo_matrix_flip (&mx2, &mx2, FALSE, TRUE);
+ cairo_matrix_multiply (&mx2, &mx, &mx2);
+ cairo_transform (cr, &mx2);
+ cairo_translate (cr, -height , -width);
+ break;
+ case EOG_TRANSFORM_NONE:
+ default:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, width, height);
+ break;
+ }
+ }
+
+ if (!surface)
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ width, height);
+ cairo_surface_set_mime_data (surface,
+ CAIRO_MIME_TYPE_JPEG,
+ (unsigned char*)img_data, data_len,
+ g_free, img_data);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_surface_destroy (surface);
+ g_object_unref (file);
+ return;
+ }
+ g_object_unref (file);
+
+ }
+
{
GdkPixbuf *pixbuf;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]