diff options
author | Felix Riemann <[email protected]> | 2017-04-22 14:11:23 +0200 |
---|---|---|
committer | raveit65 <[email protected]> | 2017-04-23 12:12:21 +0200 |
commit | 57c530e27bb13687d674fb7abba03d414ab814fb (patch) | |
tree | a63dc28bd58176f5a834f02b6559d5ab6786ebca | |
parent | 21685bf89ab10cc5cd51f9d2963c63d11632a182 (diff) | |
download | eom-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.c | 17 | ||||
-rw-r--r-- | src/eom-image.h | 6 | ||||
-rw-r--r-- | src/eom-print.c | 138 |
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; |