summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Riemann <[email protected]>2017-04-22 14:11:23 +0200
committerraveit65 <[email protected]>2017-04-23 12:12:21 +0200
commit57c530e27bb13687d674fb7abba03d414ab814fb (patch)
treea63dc28bd58176f5a834f02b6559d5ab6786ebca
parent21685bf89ab10cc5cd51f9d2963c63d11632a182 (diff)
downloadeom-57c530e27bb13687d674fb7abba03d414ab814fb.tar.bz2
eom-57c530e27bb13687d674fb7abba03d414ab814fb.tar.xz
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 taken from: https://git.gnome.org/browse/eog/commit/?id=7029dfe
-rw-r--r--src/eom-image.c17
-rw-r--r--src/eom-image.h6
-rw-r--r--src/eom-print.c138
3 files changed, 160 insertions, 1 deletions
diff --git a/src/eom-image.c b/src/eom-image.c
index 8fb9311..1627f2a 100644
--- a/src/eom-image.c
+++ b/src/eom-image.c
@@ -2350,6 +2350,14 @@ eom_image_get_transform (EomImage *img)
return img->priv->trans;
}
+EomTransform*
+eom_image_get_autorotate_transform (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), NULL);
+
+ return img->priv->trans_autorotate;
+}
+
/**
* eom_image_file_changed:
* @img: a #EomImage
@@ -2373,3 +2381,12 @@ eom_image_is_file_changed (EomImage *img)
return img->priv->file_is_changed;
}
+
+gboolean
+eom_image_is_jpeg (EomImage *img)
+{
+ g_return_val_if_fail (EOM_IS_IMAGE (img), FALSE);
+
+ return ((img->priv->file_type != NULL) && (g_ascii_strcasecmp (img->priv->file_type, EOM_FILE_FORMAT_JPEG) == 0));
+}
+
diff --git a/src/eom-image.h b/src/eom-image.h
index 3e503db..74abdc5 100644
--- a/src/eom-image.h
+++ b/src/eom-image.h
@@ -211,9 +211,13 @@ gboolean eom_image_start_animation (EomImage *img);
#ifdef HAVE_RSVG
gboolean eom_image_is_svg (EomImage *img);
RsvgHandle *eom_image_get_svg (EomImage *img);
-EomTransform *eom_image_get_transform (EomImage *img);
#endif
+EomTransform *eom_image_get_transform (EomImage *img);
+EomTransform *eom_image_get_autorotate_transform (EomImage *img);
+
+gboolean eom_image_is_jpeg (EomImage *img);
+
void eom_image_file_changed (EomImage *img);
gboolean eom_image_is_file_changed (EomImage *img);
diff --git a/src/eom-print.c b/src/eom-print.c
index f0329ec..54db68e 100644
--- a/src/eom-print.c
+++ b/src/eom-print.c
@@ -45,6 +45,29 @@ typedef struct {
GtkUnit unit;
} EomPrintData;
+/* art_affine_flip modified to work with cairo_matrix_t */
+static void
+_eom_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
eom_print_draw_page (GtkPrintOperation *operation,
GtkPrintContext *context,
@@ -105,8 +128,123 @@ eom_print_draw_page (GtkPrintOperation *operation,
RsvgHandle *svg = eom_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 (eom_image_is_jpeg (data->image) && _cairo_ctx_supports_jpg_metadata (cr))
+ {
+ GFile *file;
+ char *img_data;
+ gsize data_len;
+ cairo_surface_t *surface = NULL;
+
+ eom_debug_message (DEBUG_PRINTING, "Attaching image to cairo surface");
+
+ file = eom_image_get_file (data->image);
+ if (g_file_load_contents (file, NULL, &img_data, &data_len, NULL, NULL))
+ {
+ EomTransform *tf = eom_image_get_transform (data->image);
+ EomTransform *auto_tf = eom_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 = eom_transform_compose (auto_tf, tf);
+ }
+
+ switch (eom_transform_get_transform_type (tf)) {
+ case EOM_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 EOM_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 EOM_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 EOM_TRANSFORM_FLIP_HORIZONTAL:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, width, height);
+ cairo_matrix_init_identity (&mx);
+ _eom_cairo_matrix_flip (&mx2, &mx, TRUE, FALSE);
+ cairo_transform (cr, &mx2);
+ cairo_translate (cr, -width, 0.0);
+ break;
+ case EOM_TRANSFORM_FLIP_VERTICAL:
+ surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, width, height);
+ cairo_matrix_init_identity (&mx);
+ _eom_cairo_matrix_flip (&mx2, &mx, FALSE, TRUE);
+ cairo_transform (cr, &mx2);
+ cairo_translate (cr, 0.0, -height);
+ break;
+ case EOM_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);
+ _eom_cairo_matrix_flip (&mx2, &mx2, TRUE, FALSE);
+ cairo_matrix_multiply (&mx2, &mx, &mx2);
+ cairo_transform (cr, &mx2);
+ break;
+ case EOM_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);
+ _eom_cairo_matrix_flip (&mx2, &mx2, FALSE, TRUE);
+ cairo_matrix_multiply (&mx2, &mx, &mx2);
+ cairo_transform (cr, &mx2);
+ cairo_translate (cr, -height , -width);
+ break;
+ case EOM_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;