[eog] Avoid recompressing JPEGs as PNG when printing



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]