From 69f69eed816b89be9a01a48a1f0643d1fd496118 Mon Sep 17 00:00:00 2001 From: Nils Philippsen Date: Fri, 6 May 2011 11:58:44 +0200 Subject: [PATCH] patch: poppler-0.17 Squashed commit of the following: commit 529d940222dfc352d41fbf72de29134421aa4002 Author: Nils Philippsen Date: Fri May 6 11:50:30 2011 +0200 use code based on pixbufs instead of cairo surfaces this is done to avoid adding to libgimp, thanks to Mukund Sivaraman for hints how to do this commit f8671d8767d4cdab830dc06310e96c63a88ec0fd Author: Mukund Sivaraman Date: Thu Apr 21 13:57:13 2011 +0530 file-pdf-load: Update attribution, removing bogus copyright (cherry picked from commit e999122e0b20b6ccd6bde3ce039bb64068fc0019) commit 89a78f2590d298dac2f42e6d9a3016fc5d672c70 Author: Nils Philippsen Date: Thu Apr 21 13:52:18 2011 +0200 file-pdf-load: Use better API + cleanups * fixes issues with poppler 0.17 completely * uses new libgimp API to pass surfaces instead of pixbufs * uses GTK+ 3 API to convert surfaces to pixbufs where available (backported from commit 7bdadd80ba479d6ff904e276d805e16f6b940ee2) commit 4e92302c4a14a961f112587a0ad86696c88da2f8 Author: Nils Philippsen Date: Thu Apr 21 13:38:08 2011 +0200 file-pdf-load: Don't use deprecated API (bug #646947) (cherry picked from commit 9b3e1c91fd2eac69da6947ec9c7fbf10096ba237) Conflicts: plug-ins/common/file-pdf.c --- plug-ins/common/file-pdf.c | 323 ++++++++++++++++++++++++++++++++++++++------ 1 files changed, 283 insertions(+), 40 deletions(-) diff --git a/plug-ins/common/file-pdf.c b/plug-ins/common/file-pdf.c index a43b459..43c2b7d 100644 --- a/plug-ins/common/file-pdf.c +++ b/plug-ins/common/file-pdf.c @@ -4,6 +4,9 @@ * * Copyright (C) 2005 Nathan Summers * + * Some code in render_page_to_surface() borrowed from + * poppler.git/glib/poppler-page.cc. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -80,16 +83,20 @@ static gboolean load_dialog (PopplerDocument *doc, static PopplerDocument * open_document (const gchar *filename, GError **error); -static GdkPixbuf * get_thumbnail (PopplerDocument *doc, +static cairo_surface_t * get_thumb_surface (PopplerDocument *doc, + gint page, + gint preferred_size); + +static GdkPixbuf * get_thumb_pixbuf (PopplerDocument *doc, gint page, gint preferred_size); static gint32 layer_from_pixbuf (gint32 image, - const gchar *layer_name, - gint position, - GdkPixbuf *buf, - gdouble progress_start, - gdouble progress_scale); + const gchar *layer_name, + gint position, + GdkPixbuf *pixbuf, + gdouble progress_start, + gdouble progress_scale); /** ** the following was formerly part of @@ -433,11 +440,12 @@ run (const gchar *name, } else { - gdouble width = 0; - gdouble height = 0; - gdouble scale; - gint32 image = -1; - GdkPixbuf *pixbuf = NULL; + gdouble width = 0; + gdouble height = 0; + gdouble scale; + gint32 image = -1; + gint num_pages = 0; + GdkPixbuf *pixbuf = NULL; /* Possibly retrieve last settings */ gimp_get_data (LOAD_PROC, &loadvals); @@ -455,7 +463,10 @@ run (const gchar *name, g_object_unref (page); } - pixbuf = get_thumbnail (doc, 0, param[1].data.d_int32); + num_pages = poppler_document_get_n_pages (doc); + + pixbuf = get_thumb_pixbuf (doc, 0, param[1].data.d_int32); + g_object_unref (doc); } @@ -548,6 +559,187 @@ open_document (const gchar *filename, return doc; } +/* FIXME: Remove this someday when we depend fully on GTK+ >= 3 */ + +#if (!GTK_CHECK_VERSION (3, 0, 0)) + +static cairo_format_t +gdk_cairo_format_for_content (cairo_content_t content) +{ + switch (content) + { + case CAIRO_CONTENT_COLOR: + return CAIRO_FORMAT_RGB24; + case CAIRO_CONTENT_ALPHA: + return CAIRO_FORMAT_A8; + case CAIRO_CONTENT_COLOR_ALPHA: + default: + return CAIRO_FORMAT_ARGB32; + } +} + +static cairo_surface_t * +gdk_cairo_surface_coerce_to_image (cairo_surface_t *surface, + cairo_content_t content, + int src_x, + int src_y, + int width, + int height) +{ + cairo_surface_t *copy; + cairo_t *cr; + + copy = cairo_image_surface_create (gdk_cairo_format_for_content (content), + width, + height); + + cr = cairo_create (copy); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, -src_x, -src_y); + cairo_paint (cr); + cairo_destroy (cr); + + return copy; +} + +static void +convert_alpha (guchar *dest_data, + int dest_stride, + guchar *src_data, + int src_stride, + int src_x, + int src_y, + int width, + int height) +{ + int x, y; + + src_data += src_stride * src_y + src_x * 4; + + for (y = 0; y < height; y++) { + guint32 *src = (guint32 *) src_data; + + for (x = 0; x < width; x++) { + guint alpha = src[x] >> 24; + + if (alpha == 0) + { + dest_data[x * 4 + 0] = 0; + dest_data[x * 4 + 1] = 0; + dest_data[x * 4 + 2] = 0; + } + else + { + dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; + dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha; + dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; + } + dest_data[x * 4 + 3] = alpha; + } + + src_data += src_stride; + dest_data += dest_stride; + } +} + +static void +convert_no_alpha (guchar *dest_data, + int dest_stride, + guchar *src_data, + int src_stride, + int src_x, + int src_y, + int width, + int height) +{ + int x, y; + + src_data += src_stride * src_y + src_x * 4; + + for (y = 0; y < height; y++) { + guint32 *src = (guint32 *) src_data; + + for (x = 0; x < width; x++) { + dest_data[x * 3 + 0] = src[x] >> 16; + dest_data[x * 3 + 1] = src[x] >> 8; + dest_data[x * 3 + 2] = src[x]; + } + + src_data += src_stride; + dest_data += dest_stride; + } +} + +/** + * gdk_pixbuf_get_from_surface: + * @surface: surface to copy from + * @src_x: Source X coordinate within @surface + * @src_y: Source Y coordinate within @surface + * @width: Width in pixels of region to get + * @height: Height in pixels of region to get + * + * Transfers image data from a #cairo_surface_t and converts it to an RGB(A) + * representation inside a #GdkPixbuf. This allows you to efficiently read + * individual pixels from cairo surfaces. For #GdkWindows, use + * gdk_pixbuf_get_from_window() instead. + * + * This function will create an RGB pixbuf with 8 bits per channel. + * The pixbuf will contain an alpha channel if the @surface contains one. + * + * Return value: (transfer full): A newly-created pixbuf with a reference + * count of 1, or %NULL on error + */ +static GdkPixbuf * +gdk_pixbuf_get_from_surface (cairo_surface_t *surface, + gint src_x, + gint src_y, + gint width, + gint height) +{ + cairo_content_t content; + GdkPixbuf *dest; + + /* General sanity checks */ + g_return_val_if_fail (surface != NULL, NULL); + g_return_val_if_fail (width > 0 && height > 0, NULL); + + content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR; + dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + !!(content & CAIRO_CONTENT_ALPHA), + 8, + width, height); + + surface = gdk_cairo_surface_coerce_to_image (surface, content, + src_x, src_y, + width, height); + cairo_surface_flush (surface); + if (cairo_surface_status (surface) || dest == NULL) + { + cairo_surface_destroy (surface); + return NULL; + } + + if (gdk_pixbuf_get_has_alpha (dest)) + convert_alpha (gdk_pixbuf_get_pixels (dest), + gdk_pixbuf_get_rowstride (dest), + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface), + 0, 0, + width, height); + else + convert_no_alpha (gdk_pixbuf_get_pixels (dest), + gdk_pixbuf_get_rowstride (dest), + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface), + 0, 0, + width, height); + + cairo_surface_destroy (surface); + return dest; +} + +#endif + static gint32 layer_from_pixbuf (gint32 image, const gchar *layer_name, @@ -566,6 +758,54 @@ layer_from_pixbuf (gint32 image, return layer; } +static cairo_surface_t * +render_page_to_surface (PopplerPage *page, + int width, + int height, + double scale) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + + cairo_save (cr); + cairo_translate (cr, 0.0, 0.0); + + if (scale != 1.0) + cairo_scale (cr, scale, scale); + + poppler_page_render (page, cr); + cairo_restore (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_destroy (cr); + + return surface; +} + +static GdkPixbuf * +render_page_to_pixbuf (PopplerPage *page, + int width, + int height, + double scale) +{ + GdkPixbuf *pixbuf; + cairo_surface_t *surface; + + surface = render_page_to_surface (page, width, height, scale); + pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + cairo_surface_destroy (surface); + + return pixbuf; +} + static gint32 load_image (PopplerDocument *doc, const gchar *filename, @@ -597,7 +837,7 @@ load_image (PopplerDocument *doc, gdouble page_width; gdouble page_height; - GdkPixbuf *buf; + GdkPixbuf *pixbuf; gint width; gint height; @@ -627,15 +867,13 @@ load_image (PopplerDocument *doc, gimp_image_set_resolution (image_ID, resolution, resolution); } - buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); - - poppler_page_render_to_pixbuf (page, 0, 0, width, height, scale, 0, buf); + pixbuf = render_page_to_pixbuf (page, width, height, scale); - layer_from_pixbuf (image_ID, page_label, i, buf, + layer_from_pixbuf (image_ID, page_label, i, pixbuf, doc_progress, 1.0 / pages->n_pages); g_free (page_label); - g_object_unref (buf); + g_object_unref(pixbuf); doc_progress = (double) (i + 1) / pages->n_pages; gimp_progress_update (doc_progress); @@ -676,30 +914,22 @@ load_image (PopplerDocument *doc, return image_ID; } -static GdkPixbuf * -get_thumbnail (PopplerDocument *doc, - gint page_num, - gint preferred_size) +static cairo_surface_t * +get_thumb_surface (PopplerDocument *doc, + gint page_num, + gint preferred_size) { PopplerPage *page; - GdkPixbuf *pixbuf; + cairo_surface_t *surface; page = poppler_document_get_page (doc, page_num); if (! page) return NULL; - /* XXX: Remove conditional when we depend on poppler 0.8.0, but also - * add configure check to make sure POPPLER_WITH_GDK is enabled! - */ -#ifdef POPPLER_WITH_GDK - pixbuf = poppler_page_get_thumbnail_pixbuf (page); -#else - pixbuf = poppler_page_get_thumbnail (page); -#endif - + surface = poppler_page_get_thumbnail (page); - if (! pixbuf) + if (! surface) { gdouble width; gdouble height; @@ -712,15 +942,28 @@ get_thumbnail (PopplerDocument *doc, width *= scale; height *= scale; - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, - width, height); - - poppler_page_render_to_pixbuf (page, - 0, 0, width, height, scale, 0, pixbuf); + surface = render_page_to_surface (page, width, height, scale); } g_object_unref (page); + return surface; +} + +static GdkPixbuf * +get_thumb_pixbuf (PopplerDocument *doc, + gint page_num, + gint preferred_size) +{ + cairo_surface_t *surface; + GdkPixbuf *pixbuf; + + surface = get_thumb_surface (doc, page_num, preferred_size); + pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + cairo_surface_destroy (surface); + return pixbuf; } @@ -769,8 +1012,8 @@ thumbnail_thread (gpointer data) idle_data->page_no = i; /* FIXME get preferred size from somewhere? */ - idle_data->pixbuf = get_thumbnail (thread_data->document, i, - THUMBNAIL_SIZE); + idle_data->pixbuf = get_thumb_pixbuf (thread_data->document, i, + THUMBNAIL_SIZE); g_idle_add (idle_set_thumbnail, idle_data); -- 1.7.5