2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2005-07-16 06:54:59 +08:00
|
|
|
*
|
2010-08-28 00:43:00 +08:00
|
|
|
* file-pdf-load.c - PDF file loader
|
2005-07-18 18:16:45 +08:00
|
|
|
*
|
2005-07-16 06:54:59 +08:00
|
|
|
* Copyright (C) 2005 Nathan Summers
|
|
|
|
*
|
2011-04-21 16:27:13 +08:00
|
|
|
* Some code in render_page_to_surface() borrowed from
|
|
|
|
* poppler.git/glib/poppler-page.cc.
|
2011-04-20 21:25:44 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2005-07-16 06:54:59 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2005-07-16 06:54:59 +08:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2005-07-16 06:54:59 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include <libgimp/gimpui.h>
|
|
|
|
|
2008-05-24 04:38:52 +08:00
|
|
|
#undef GTK_DISABLE_SINGLE_INCLUDES
|
2005-07-16 06:54:59 +08:00
|
|
|
#include <poppler.h>
|
2008-05-24 04:38:52 +08:00
|
|
|
#define GTK_DISABLE_SINGLE_INCLUDES
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
|
2005-07-19 00:52:03 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
#define LOAD_PROC "file-pdf-load"
|
|
|
|
#define LOAD_THUMB_PROC "file-pdf-load-thumb"
|
|
|
|
#define PLUG_IN_BINARY "file-pdf-load"
|
|
|
|
#define PLUG_IN_ROLE "gimp-file-pdf-load"
|
|
|
|
|
|
|
|
#define THUMBNAIL_SIZE 128
|
|
|
|
|
|
|
|
#define GIMP_PLUGIN_PDF_LOAD_ERROR gimp_plugin_pdf_load_error_quark ()
|
|
|
|
static GQuark
|
|
|
|
gimp_plugin_pdf_load_error_quark (void)
|
|
|
|
{
|
|
|
|
return g_quark_from_static_string ("gimp-plugin-pdf-load-error-quark");
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gint n_pages;
|
|
|
|
gint *pages;
|
|
|
|
} PdfSelectedPages;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _Pdf Pdf;
|
|
|
|
typedef struct _PdfClass PdfClass;
|
|
|
|
|
|
|
|
struct _Pdf
|
|
|
|
{
|
|
|
|
GimpPlugIn parent_instance;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _PdfClass
|
|
|
|
{
|
|
|
|
GimpPlugInClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#define PDF_TYPE (pdf_get_type ())
|
2023-10-19 00:29:37 +08:00
|
|
|
#define PDF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PDF_TYPE, Pdf))
|
2019-08-20 08:32:15 +08:00
|
|
|
|
|
|
|
GType pdf_get_type (void) G_GNUC_CONST;
|
|
|
|
|
2023-08-06 06:48:31 +08:00
|
|
|
static GList * pdf_query_procedures (GimpPlugIn *plug_in);
|
|
|
|
static GimpProcedure * pdf_create_procedure (GimpPlugIn *plug_in,
|
|
|
|
const gchar *name);
|
|
|
|
|
2024-05-01 02:55:42 +08:00
|
|
|
static gboolean pdf_extract (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
GimpVectorLoadData *extracted_dimensions,
|
|
|
|
gpointer *data_for_run,
|
|
|
|
GDestroyNotify *data_for_run_destroy,
|
|
|
|
gpointer extract_data,
|
|
|
|
GError **error);
|
2023-08-06 06:48:31 +08:00
|
|
|
static GimpValueArray * pdf_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
2024-04-24 05:22:41 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
2024-04-26 07:07:59 +08:00
|
|
|
GimpVectorLoadData extracted_data,
|
2023-08-06 06:48:31 +08:00
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
2024-04-26 07:07:59 +08:00
|
|
|
gpointer data_from_extract,
|
2023-08-06 06:48:31 +08:00
|
|
|
gpointer run_data);
|
|
|
|
static GimpValueArray * pdf_load_thumb (GimpProcedure *procedure,
|
|
|
|
GFile *file,
|
|
|
|
gint size,
|
2023-08-11 08:01:05 +08:00
|
|
|
GimpProcedureConfig *config,
|
2023-08-06 06:48:31 +08:00
|
|
|
gpointer run_data);
|
|
|
|
|
|
|
|
static GimpImage * load_image (PopplerDocument *doc,
|
|
|
|
GFile *file,
|
2024-06-09 09:18:21 +08:00
|
|
|
GimpVectorLoadData extracted_data,
|
2023-08-06 06:48:31 +08:00
|
|
|
GimpRunMode run_mode,
|
2019-08-20 08:32:15 +08:00
|
|
|
GimpPageSelectorTarget target,
|
2024-04-24 05:22:41 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
2023-08-06 06:48:31 +08:00
|
|
|
gdouble resolution,
|
|
|
|
gboolean antialias,
|
|
|
|
gboolean white_background,
|
|
|
|
gboolean reverse_order,
|
|
|
|
PdfSelectedPages *pages);
|
|
|
|
|
|
|
|
static GimpPDBStatusType load_dialog (PopplerDocument *doc,
|
|
|
|
PdfSelectedPages *pages,
|
2024-06-09 00:37:38 +08:00
|
|
|
GimpVectorLoadData extracted_data,
|
2023-08-06 06:48:31 +08:00
|
|
|
GimpProcedure *procedure,
|
|
|
|
GimpProcedureConfig *config);
|
|
|
|
|
|
|
|
static PopplerDocument * open_document (GFile *file,
|
|
|
|
const gchar *PDF_password,
|
|
|
|
GimpRunMode run_mode,
|
2024-05-01 02:55:42 +08:00
|
|
|
gdouble *width,
|
|
|
|
gdouble *height,
|
2023-08-06 06:48:31 +08:00
|
|
|
GError **error);
|
|
|
|
|
|
|
|
static cairo_surface_t * get_thumb_surface (PopplerDocument *doc,
|
|
|
|
gint page,
|
|
|
|
gint preferred_size,
|
|
|
|
gboolean white_background);
|
|
|
|
|
|
|
|
static GdkPixbuf * get_thumb_pixbuf (PopplerDocument *doc,
|
|
|
|
gint page,
|
|
|
|
gint preferred_size,
|
|
|
|
gboolean white_background);
|
|
|
|
|
|
|
|
static GimpLayer * layer_from_surface (GimpImage *image,
|
|
|
|
const gchar *layer_name,
|
|
|
|
gint position,
|
|
|
|
cairo_surface_t *surface,
|
|
|
|
gdouble progress_start,
|
|
|
|
gdouble progress_scale);
|
2019-08-20 08:32:15 +08:00
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (Pdf, pdf, GIMP_TYPE_PLUG_IN)
|
|
|
|
|
|
|
|
GIMP_MAIN (PDF_TYPE)
|
2022-05-26 06:59:36 +08:00
|
|
|
DEFINE_STD_SET_I18N
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
2019-08-20 08:32:15 +08:00
|
|
|
pdf_class_init (PdfClass *klass)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2019-08-20 08:32:15 +08:00
|
|
|
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
|
|
|
|
|
|
|
|
plug_in_class->query_procedures = pdf_query_procedures;
|
|
|
|
plug_in_class->create_procedure = pdf_create_procedure;
|
2022-05-26 06:59:36 +08:00
|
|
|
plug_in_class->set_i18n = STD_SET_I18N;
|
2005-07-16 06:54:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-08-20 08:32:15 +08:00
|
|
|
pdf_init (Pdf *pdf)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static GList *
|
|
|
|
pdf_query_procedures (GimpPlugIn *plug_in)
|
|
|
|
{
|
|
|
|
GList *list = NULL;
|
|
|
|
|
|
|
|
list = g_list_append (list, g_strdup (LOAD_THUMB_PROC));
|
2019-09-11 01:36:54 +08:00
|
|
|
list = g_list_append (list, g_strdup (LOAD_PROC));
|
2019-08-20 08:32:15 +08:00
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpProcedure *
|
|
|
|
pdf_create_procedure (GimpPlugIn *plug_in,
|
|
|
|
const gchar *name)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2019-08-20 08:32:15 +08:00
|
|
|
GimpProcedure *procedure = NULL;
|
|
|
|
|
|
|
|
if (! strcmp (name, LOAD_PROC))
|
|
|
|
{
|
2024-04-24 05:22:41 +08:00
|
|
|
procedure = gimp_vector_load_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
2024-05-01 02:55:42 +08:00
|
|
|
pdf_extract, NULL, NULL,
|
2024-04-24 05:22:41 +08:00
|
|
|
pdf_load, NULL, NULL);
|
2019-08-20 08:32:15 +08:00
|
|
|
|
2022-07-05 04:50:53 +08:00
|
|
|
gimp_procedure_set_menu_label (procedure, _("Portable Document Format"));
|
2019-08-20 08:32:15 +08:00
|
|
|
|
|
|
|
gimp_procedure_set_documentation (procedure,
|
|
|
|
"Load file in PDF format",
|
|
|
|
"Loads files in Adobe's Portable "
|
|
|
|
"Document Format. PDF is designed to "
|
|
|
|
"be easily processed by a variety "
|
|
|
|
"of different platforms, and is a "
|
|
|
|
"distant cousin of PostScript.",
|
|
|
|
name);
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Nathan Summers, Lionel N.",
|
|
|
|
"Nathan Summers, Lionel N.",
|
|
|
|
"2005, 2017");
|
|
|
|
|
2024-04-24 05:22:41 +08:00
|
|
|
gimp_file_procedure_set_format_name (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
_("PDF"));
|
2019-08-20 08:32:15 +08:00
|
|
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"application/pdf");
|
|
|
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"pdf");
|
|
|
|
gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"0, string,%PDF-");
|
|
|
|
|
|
|
|
gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
|
|
|
|
LOAD_THUMB_PROC);
|
|
|
|
|
2024-06-13 00:53:12 +08:00
|
|
|
gimp_procedure_add_string_argument (procedure, "password",
|
|
|
|
_("PDF password"),
|
|
|
|
_("The password to decrypt the encrypted PDF file"),
|
|
|
|
NULL,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_boolean_argument (procedure, "reverse-order",
|
|
|
|
_("Load in re_verse order"),
|
|
|
|
_("Load PDF pages in reverse order"),
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
/* FIXME: this should be a gimp_procedure_add_enum_argument () of type
|
2023-04-22 06:10:12 +08:00
|
|
|
* GIMP_TYPE_PAGE_SELECTOR_TARGET but it won't work right now (see FIXME
|
|
|
|
* comment in libgimp/gimpgpparams-body.c:116).
|
|
|
|
|
2024-06-13 00:53:12 +08:00
|
|
|
gimp_procedure_add_enum_argument (procedure, "target",
|
|
|
|
_("Open pages as"),
|
|
|
|
_("Number of pages to load (0 for all)"),
|
|
|
|
GIMP_TYPE_PAGE_SELECTOR_TARGET,
|
|
|
|
GIMP_PAGE_SELECTOR_TARGET_LAYERS,
|
|
|
|
G_PARAM_READWRITE);
|
2023-04-22 06:10:12 +08:00
|
|
|
|
|
|
|
*/
|
2024-06-13 00:53:12 +08:00
|
|
|
gimp_procedure_add_int_aux_argument (procedure, "target",
|
|
|
|
_("Open pages as"),
|
|
|
|
_("Number of pages to load (0 for all)"),
|
|
|
|
GIMP_PAGE_SELECTOR_TARGET_LAYERS, GIMP_PAGE_SELECTOR_TARGET_IMAGES,
|
|
|
|
GIMP_PAGE_SELECTOR_TARGET_LAYERS,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_int_argument (procedure, "n-pages",
|
|
|
|
_("N pages"),
|
|
|
|
_("Number of pages to load (0 for all)"),
|
|
|
|
0, G_MAXINT, 0,
|
|
|
|
G_PARAM_READWRITE);
|
2019-08-20 08:32:15 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
/* FIXME: shouldn't the whole selector be considered as one argument
|
|
|
|
* containing properties "target", "n-pages" and "pages" as a single
|
|
|
|
* object?
|
|
|
|
* Or actually should we store pages at all? While it makes sense to store
|
|
|
|
* some settings generally, not sure that the list of page makes sense
|
|
|
|
* from one PDF document loaded to another (different) one.
|
|
|
|
*/
|
2024-06-13 00:53:12 +08:00
|
|
|
gimp_procedure_add_int32_array_argument (procedure, "pages",
|
|
|
|
_("Pages"),
|
|
|
|
_("The pages to load in the expected order"),
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_boolean_argument (procedure, "antialias",
|
|
|
|
_("Use _Anti-aliasing"),
|
|
|
|
_("Render texts with anti-aliasing"),
|
|
|
|
TRUE,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_boolean_argument (procedure, "white-background",
|
|
|
|
_("_Fill transparent areas with white"),
|
|
|
|
_("Render all pages as opaque by filling the background in white"),
|
|
|
|
TRUE,
|
|
|
|
G_PARAM_READWRITE);
|
2019-08-20 08:32:15 +08:00
|
|
|
}
|
|
|
|
else if (! strcmp (name, LOAD_THUMB_PROC))
|
|
|
|
{
|
2019-08-30 18:52:28 +08:00
|
|
|
procedure = gimp_thumbnail_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
2019-08-20 08:32:15 +08:00
|
|
|
pdf_load_thumb, NULL, NULL);
|
|
|
|
|
|
|
|
gimp_procedure_set_documentation (procedure,
|
|
|
|
"Loads a preview from a PDF file.",
|
|
|
|
"Loads a small preview of the first "
|
|
|
|
"page of the PDF format file. Uses "
|
|
|
|
"the embedded thumbnail if present.",
|
|
|
|
name);
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Nathan Summers",
|
|
|
|
"Nathan Summers",
|
|
|
|
"2005");
|
|
|
|
}
|
|
|
|
|
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
|
2024-05-01 02:55:42 +08:00
|
|
|
static gboolean
|
|
|
|
pdf_extract (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
GimpVectorLoadData *extracted_dimensions,
|
|
|
|
gpointer *data_for_run,
|
|
|
|
GDestroyNotify *data_for_run_destroy,
|
|
|
|
gpointer extract_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
PopplerDocument *doc = NULL;
|
|
|
|
gchar *password = NULL;
|
|
|
|
gdouble width = 0.0;
|
|
|
|
gdouble height = 0.0;
|
|
|
|
|
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
|
|
gimp_ui_init (PLUG_IN_BINARY);
|
|
|
|
|
|
|
|
g_object_get (config, "password", &password, NULL);
|
|
|
|
doc = open_document (file, password, run_mode,
|
|
|
|
&width, &height, error);
|
|
|
|
g_free (password);
|
|
|
|
if (doc == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
extracted_dimensions->width = width;
|
|
|
|
extracted_dimensions->height = height;
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
extracted_dimensions->width_unit = gimp_unit_point ();
|
|
|
|
extracted_dimensions->height_unit = gimp_unit_point ();
|
2024-05-01 02:55:42 +08:00
|
|
|
extracted_dimensions->exact_width = TRUE;
|
|
|
|
extracted_dimensions->exact_height = TRUE;
|
|
|
|
extracted_dimensions->correct_ratio = TRUE;
|
|
|
|
|
|
|
|
*data_for_run = doc;
|
|
|
|
*data_for_run_destroy = g_object_unref;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
static GimpValueArray *
|
2023-08-06 06:48:31 +08:00
|
|
|
pdf_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
2024-04-24 05:22:41 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
2024-04-26 07:07:59 +08:00
|
|
|
GimpVectorLoadData extracted_data,
|
2023-08-06 06:48:31 +08:00
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
2024-04-26 07:07:59 +08:00
|
|
|
gpointer data_from_extract,
|
2023-08-06 06:48:31 +08:00
|
|
|
gpointer run_data)
|
2019-08-20 08:32:15 +08:00
|
|
|
{
|
2023-04-22 06:10:12 +08:00
|
|
|
GimpValueArray *return_vals;
|
|
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
|
|
|
GimpImage *image = NULL;
|
2024-05-01 02:55:42 +08:00
|
|
|
PopplerDocument *doc = POPPLER_DOCUMENT (data_from_extract);
|
2023-04-22 06:10:12 +08:00
|
|
|
PdfSelectedPages pages = { 0, NULL };
|
|
|
|
GError *error = NULL;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-07-22 20:56:04 +08:00
|
|
|
gegl_init (NULL, NULL);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-08-06 06:48:31 +08:00
|
|
|
if (doc == NULL)
|
|
|
|
{
|
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
|
|
}
|
|
|
|
else if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
|
|
{
|
2024-06-09 00:37:38 +08:00
|
|
|
status = load_dialog (doc, &pages, extracted_data, procedure, config);
|
2023-08-06 06:48:31 +08:00
|
|
|
}
|
|
|
|
else if (run_mode == GIMP_RUN_NONINTERACTIVE)
|
|
|
|
{
|
|
|
|
PopplerPage *test_page = poppler_document_get_page (doc, 0);
|
2023-04-22 06:10:12 +08:00
|
|
|
|
2023-08-06 06:48:31 +08:00
|
|
|
if (test_page)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
gint doc_n_pages;
|
|
|
|
|
|
|
|
g_object_get (config, "n-pages", &pages.n_pages, NULL);
|
|
|
|
doc_n_pages = poppler_document_get_n_pages (doc);
|
|
|
|
/* The number of imported pages may be bigger than
|
|
|
|
* the number of pages from the original document.
|
|
|
|
* Indeed it is possible to duplicate some pages
|
|
|
|
* by setting the same number several times in the
|
|
|
|
* "pages" argument.
|
|
|
|
* Not ceiling this value is *not* an error.
|
|
|
|
*/
|
|
|
|
if (pages.n_pages <= 0)
|
2023-04-22 06:10:12 +08:00
|
|
|
{
|
2023-08-06 06:48:31 +08:00
|
|
|
pages.n_pages = doc_n_pages;
|
|
|
|
pages.pages = g_new (gint, pages.n_pages);
|
|
|
|
for (i = 0; i < pages.n_pages; i++)
|
|
|
|
pages.pages[i] = i;
|
2023-04-22 06:10:12 +08:00
|
|
|
}
|
2023-08-06 06:48:31 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const gint32 *p;
|
2023-04-22 06:10:12 +08:00
|
|
|
|
2023-08-06 06:48:31 +08:00
|
|
|
g_object_get (config, "pages", &p, NULL);
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2023-08-06 06:48:31 +08:00
|
|
|
pages.pages = g_new (gint, pages.n_pages);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-08-06 06:48:31 +08:00
|
|
|
for (i = 0; i < pages.n_pages; i++)
|
2017-09-11 03:55:41 +08:00
|
|
|
{
|
2023-08-06 06:48:31 +08:00
|
|
|
if (p[i] >= doc_n_pages)
|
2017-09-25 09:22:50 +08:00
|
|
|
{
|
2023-08-06 06:48:31 +08:00
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
|
|
g_set_error (&error, GIMP_PLUGIN_PDF_LOAD_ERROR, 0,
|
|
|
|
/* TRANSLATORS: first argument is file name,
|
|
|
|
* second is out-of-range page number,
|
|
|
|
* third is number of pages.
|
|
|
|
* Specify order as in English if needed.
|
|
|
|
*/
|
|
|
|
ngettext ("PDF document '%1$s' has %3$d page. Page %2$d is out of range.",
|
|
|
|
"PDF document '%1$s' has %3$d pages. Page %2$d is out of range.",
|
|
|
|
doc_n_pages),
|
|
|
|
gimp_file_get_utf8_name (file),
|
|
|
|
p[i],
|
|
|
|
doc_n_pages);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pages.pages[i] = p[i];
|
2017-09-25 09:22:50 +08:00
|
|
|
}
|
2007-10-07 05:34:12 +08:00
|
|
|
}
|
2005-07-21 03:39:46 +08:00
|
|
|
}
|
2023-08-06 06:48:31 +08:00
|
|
|
|
|
|
|
g_object_unref (test_page);
|
2005-07-21 03:39:46 +08:00
|
|
|
}
|
2019-08-20 08:32:15 +08:00
|
|
|
}
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
|
|
{
|
2023-04-22 06:10:12 +08:00
|
|
|
GimpPageSelectorTarget target;
|
|
|
|
gboolean reverse_order;
|
|
|
|
gdouble resolution;
|
|
|
|
gboolean antialias;
|
|
|
|
gboolean white_background;
|
|
|
|
|
|
|
|
g_object_get (config,
|
|
|
|
"target", &target,
|
|
|
|
"reverse-order", &reverse_order,
|
2024-04-24 05:22:41 +08:00
|
|
|
"width", &width,
|
|
|
|
"height", &height,
|
|
|
|
"pixel-density", &resolution,
|
2023-04-22 06:10:12 +08:00
|
|
|
"antialias", &antialias,
|
|
|
|
"white-background", &white_background,
|
|
|
|
NULL);
|
2019-08-23 05:22:48 +08:00
|
|
|
image = load_image (doc,
|
2024-06-09 09:18:21 +08:00
|
|
|
file, extracted_data,
|
2019-08-23 05:22:48 +08:00
|
|
|
run_mode,
|
2023-04-22 06:10:12 +08:00
|
|
|
target,
|
2024-04-24 05:22:41 +08:00
|
|
|
width, height,
|
2023-04-22 06:10:12 +08:00
|
|
|
resolution,
|
|
|
|
antialias,
|
|
|
|
white_background,
|
|
|
|
reverse_order,
|
2019-08-23 05:22:48 +08:00
|
|
|
&pages);
|
2023-04-22 06:10:12 +08:00
|
|
|
|
|
|
|
if (image == NULL)
|
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
2019-08-20 08:32:15 +08:00
|
|
|
}
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
g_free (pages.pages);
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
return_vals = gimp_procedure_new_return_values (procedure, status, error);
|
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
|
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
2008-11-11 07:15:40 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
return return_vals;
|
|
|
|
}
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
static GimpValueArray *
|
2023-08-11 08:01:05 +08:00
|
|
|
pdf_load_thumb (GimpProcedure *procedure,
|
|
|
|
GFile *file,
|
|
|
|
gint size,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data)
|
2019-08-20 08:32:15 +08:00
|
|
|
{
|
|
|
|
GimpValueArray *return_vals;
|
|
|
|
gdouble width = 0;
|
|
|
|
gdouble height = 0;
|
|
|
|
gdouble scale;
|
2019-08-23 05:22:48 +08:00
|
|
|
GimpImage *image = NULL;
|
2019-08-20 08:32:15 +08:00
|
|
|
gint num_pages = 0;
|
|
|
|
PopplerDocument *doc = NULL;
|
|
|
|
cairo_surface_t *surface = NULL;
|
|
|
|
GError *error = NULL;
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
gegl_init (NULL, NULL);
|
2007-04-27 18:12:12 +08:00
|
|
|
|
2024-05-01 02:55:42 +08:00
|
|
|
doc = open_document (file, NULL, GIMP_RUN_NONINTERACTIVE,
|
|
|
|
NULL, NULL, &error);
|
2019-07-22 18:07:04 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
if (doc)
|
|
|
|
{
|
|
|
|
PopplerPage *page = poppler_document_get_page (doc, 0);
|
2007-04-27 18:12:12 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
if (page)
|
|
|
|
{
|
|
|
|
poppler_page_get_size (page, &width, &height);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
g_object_unref (page);
|
|
|
|
}
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
num_pages = poppler_document_get_n_pages (doc);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
surface = get_thumb_surface (doc, 0, size, TRUE);
|
2007-04-27 18:12:12 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
g_object_unref (doc);
|
2005-07-16 06:54:59 +08:00
|
|
|
}
|
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
if (surface)
|
2008-08-18 05:39:44 +08:00
|
|
|
{
|
2019-08-20 08:32:15 +08:00
|
|
|
image = gimp_image_new (cairo_image_surface_get_width (surface),
|
|
|
|
cairo_image_surface_get_height (surface),
|
|
|
|
GIMP_RGB);
|
|
|
|
|
|
|
|
gimp_image_undo_disable (image);
|
|
|
|
|
|
|
|
layer_from_surface (image, "thumbnail", 0, surface, 0.0, 1.0);
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
|
|
|
|
gimp_image_undo_enable (image);
|
|
|
|
gimp_image_clean_all (image);
|
2008-08-18 05:39:44 +08:00
|
|
|
}
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
/* Thumbnail resolution: 100.0. */
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
scale = 100.0 / gimp_unit_get_factor (gimp_unit_point ());
|
2019-08-20 08:32:15 +08:00
|
|
|
|
|
|
|
width *= scale;
|
|
|
|
height *= scale;
|
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
if (! image)
|
2019-08-20 08:32:15 +08:00
|
|
|
return gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_EXECUTION_ERROR,
|
|
|
|
error);
|
|
|
|
|
|
|
|
return_vals = gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_SUCCESS,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
|
|
|
GIMP_VALUES_SET_INT (return_vals, 2, width);
|
|
|
|
GIMP_VALUES_SET_INT (return_vals, 3, height);
|
|
|
|
GIMP_VALUES_SET_ENUM (return_vals, 4, GIMP_RGB_IMAGE);
|
|
|
|
GIMP_VALUES_SET_INT (return_vals, 5, num_pages);
|
2019-07-22 20:56:04 +08:00
|
|
|
|
2019-08-20 08:32:15 +08:00
|
|
|
return return_vals;
|
2005-07-16 06:54:59 +08:00
|
|
|
}
|
|
|
|
|
2019-09-12 03:48:34 +08:00
|
|
|
static PopplerDocument *
|
|
|
|
open_document (GFile *file,
|
2017-09-11 03:55:41 +08:00
|
|
|
const gchar *PDF_password,
|
|
|
|
GimpRunMode run_mode,
|
2024-05-01 02:55:42 +08:00
|
|
|
gdouble *width,
|
|
|
|
gdouble *height,
|
2017-09-11 03:55:41 +08:00
|
|
|
GError **load_error)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
|
|
|
PopplerDocument *doc;
|
2008-08-18 05:39:44 +08:00
|
|
|
GError *error = NULL;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-01-03 05:51:31 +08:00
|
|
|
doc = poppler_document_new_from_gfile (file, PDF_password, NULL, &error);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2017-09-11 02:34:45 +08:00
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
2017-08-31 23:45:01 +08:00
|
|
|
{
|
2017-09-11 03:55:41 +08:00
|
|
|
GtkWidget *label;
|
|
|
|
|
2017-09-11 02:34:45 +08:00
|
|
|
label = gtk_label_new (_("PDF is password protected, please input the password:"));
|
2017-09-11 04:53:47 +08:00
|
|
|
while (error &&
|
|
|
|
error->domain == POPPLER_ERROR &&
|
|
|
|
error->code == POPPLER_ERROR_ENCRYPTED)
|
2017-08-31 23:45:01 +08:00
|
|
|
{
|
2017-09-11 02:34:45 +08:00
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *dialog;
|
|
|
|
GtkWidget *entry;
|
|
|
|
gint run;
|
|
|
|
|
|
|
|
dialog = gimp_dialog_new (_("Encrypted PDF"), PLUG_IN_ROLE,
|
|
|
|
NULL, 0,
|
|
|
|
NULL, NULL,
|
|
|
|
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
|
|
_("_OK"), GTK_RESPONSE_OK,
|
|
|
|
NULL);
|
|
|
|
gimp_window_set_transient (GTK_WINDOW (dialog));
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
|
|
|
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
|
|
|
|
vbox, TRUE, TRUE, 0);
|
|
|
|
entry = gtk_entry_new ();
|
|
|
|
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
|
|
|
|
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
|
|
|
|
gtk_container_add (GTK_CONTAINER (vbox), label);
|
|
|
|
gtk_container_add (GTK_CONTAINER (vbox), entry);
|
|
|
|
|
|
|
|
gtk_widget_show_all (dialog);
|
|
|
|
|
|
|
|
run = gimp_dialog_run (GIMP_DIALOG (dialog));
|
|
|
|
if (run == GTK_RESPONSE_OK)
|
|
|
|
{
|
|
|
|
g_clear_error (&error);
|
2019-01-03 05:51:31 +08:00
|
|
|
doc = poppler_document_new_from_gfile (file,
|
|
|
|
gtk_entry_get_text (GTK_ENTRY (entry)),
|
|
|
|
NULL, &error);
|
2017-09-11 02:34:45 +08:00
|
|
|
}
|
|
|
|
label = gtk_label_new (_("Wrong password! Please input the right one:"));
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
if (run == GTK_RESPONSE_CANCEL || run == GTK_RESPONSE_DELETE_EVENT)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2017-08-31 23:45:01 +08:00
|
|
|
}
|
2019-09-12 03:48:34 +08:00
|
|
|
|
2017-09-11 02:34:45 +08:00
|
|
|
gtk_widget_destroy (label);
|
2017-08-31 23:45:01 +08:00
|
|
|
}
|
|
|
|
|
2010-05-16 17:00:53 +08:00
|
|
|
/* We can't g_mapped_file_unref(mapped_file) as apparently doc has
|
|
|
|
* references to data in there. No big deal, this is just a
|
|
|
|
* short-lived plug-in.
|
|
|
|
*/
|
2008-08-18 05:39:44 +08:00
|
|
|
if (! doc)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2008-08-18 05:39:44 +08:00
|
|
|
g_set_error (load_error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
2010-05-16 17:00:53 +08:00
|
|
|
_("Could not load '%s': %s"),
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_file_get_utf8_name (file),
|
2008-08-18 05:39:44 +08:00
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
2005-07-16 06:54:59 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-05-01 02:55:42 +08:00
|
|
|
if (width && height)
|
|
|
|
{
|
|
|
|
gint n_pages;
|
|
|
|
|
|
|
|
n_pages = poppler_document_get_n_pages (doc);
|
|
|
|
for (gint i = 0; i < n_pages; i++)
|
|
|
|
{
|
|
|
|
PopplerPage *page;
|
|
|
|
|
|
|
|
page = poppler_document_get_page (doc, i);
|
|
|
|
poppler_page_get_size (page, width, height);
|
|
|
|
g_object_unref (page);
|
|
|
|
|
|
|
|
/* Only check the first page for the whole document size. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
return doc;
|
|
|
|
}
|
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
static GimpLayer *
|
|
|
|
layer_from_surface (GimpImage *image,
|
2011-04-21 10:18:25 +08:00
|
|
|
const gchar *layer_name,
|
|
|
|
gint position,
|
|
|
|
cairo_surface_t *surface,
|
|
|
|
gdouble progress_start,
|
|
|
|
gdouble progress_scale)
|
|
|
|
{
|
2019-08-23 05:22:48 +08:00
|
|
|
GimpLayer *layer;
|
2011-04-21 10:18:25 +08:00
|
|
|
|
2019-07-22 18:33:27 +08:00
|
|
|
layer = gimp_layer_new_from_surface (image, layer_name, surface,
|
|
|
|
progress_start,
|
|
|
|
progress_start + progress_scale);
|
2019-08-23 05:22:48 +08:00
|
|
|
gimp_image_insert_layer (image, layer, NULL, position);
|
2011-04-21 10:18:25 +08:00
|
|
|
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static cairo_surface_t *
|
|
|
|
render_page_to_surface (PopplerPage *page,
|
|
|
|
int width,
|
|
|
|
int height,
|
2012-02-02 22:04:07 +08:00
|
|
|
double scale,
|
2023-04-22 06:10:12 +08:00
|
|
|
gboolean antialias,
|
|
|
|
gboolean white_background)
|
2011-04-20 21:25:44 +08:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2012-02-02 22:04:07 +08:00
|
|
|
if (! antialias)
|
|
|
|
{
|
2012-02-03 00:26:30 +08:00
|
|
|
cairo_font_options_t *options = cairo_font_options_create ();
|
2012-02-02 22:04:07 +08:00
|
|
|
|
|
|
|
cairo_get_font_options (cr, options);
|
|
|
|
cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_NONE);
|
|
|
|
cairo_set_font_options (cr, options);
|
|
|
|
cairo_font_options_destroy (options);
|
2012-02-03 00:26:30 +08:00
|
|
|
|
|
|
|
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
|
2012-02-02 22:04:07 +08:00
|
|
|
}
|
|
|
|
|
2011-04-20 21:25:44 +08:00
|
|
|
poppler_page_render (page, cr);
|
|
|
|
cairo_restore (cr);
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
if (white_background)
|
|
|
|
{
|
|
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
|
|
|
|
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
|
|
|
|
cairo_paint (cr);
|
|
|
|
}
|
|
|
|
|
2011-04-20 21:25:44 +08:00
|
|
|
cairo_destroy (cr);
|
2011-04-21 10:18:25 +08:00
|
|
|
|
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
/* This is currently unused, but we'll have it here in case the military
|
|
|
|
wants it. */
|
|
|
|
|
|
|
|
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));
|
2011-04-20 21:25:44 +08:00
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
|
|
|
|
return pixbuf;
|
|
|
|
}
|
|
|
|
|
2011-04-21 10:18:25 +08:00
|
|
|
#endif
|
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
static GimpImage *
|
2005-08-23 07:05:12 +08:00
|
|
|
load_image (PopplerDocument *doc,
|
2019-09-12 03:48:34 +08:00
|
|
|
GFile *file,
|
2024-06-09 09:18:21 +08:00
|
|
|
GimpVectorLoadData extracted_data,
|
2005-08-23 07:05:12 +08:00
|
|
|
GimpRunMode run_mode,
|
|
|
|
GimpPageSelectorTarget target,
|
2024-04-24 05:22:41 +08:00
|
|
|
gint doc_width,
|
|
|
|
gint doc_height,
|
2021-01-19 00:19:21 +08:00
|
|
|
gdouble resolution,
|
2012-02-02 22:04:07 +08:00
|
|
|
gboolean antialias,
|
2023-04-22 06:10:12 +08:00
|
|
|
gboolean white_background,
|
2021-01-09 00:44:36 +08:00
|
|
|
gboolean reverse_order,
|
2005-08-23 07:05:12 +08:00
|
|
|
PdfSelectedPages *pages)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2019-08-23 05:22:48 +08:00
|
|
|
GimpImage *image = NULL;
|
|
|
|
GimpImage **images = NULL;
|
|
|
|
gint i;
|
|
|
|
gdouble scale;
|
|
|
|
gdouble doc_progress = 0;
|
2021-01-09 00:44:36 +08:00
|
|
|
gint base_index = 0;
|
|
|
|
gint sign = 1;
|
|
|
|
|
|
|
|
if (reverse_order && pages->n_pages > 0)
|
|
|
|
{
|
|
|
|
base_index = pages->n_pages - 1;
|
|
|
|
sign = -1;
|
|
|
|
}
|
2005-08-23 07:05:12 +08:00
|
|
|
|
|
|
|
if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
2019-08-23 05:22:48 +08:00
|
|
|
images = g_new0 (GimpImage *, pages->n_pages);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2005-09-30 16:16:10 +08:00
|
|
|
gimp_progress_init_printf (_("Opening '%s'"),
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_file_get_utf8_name (file));
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2024-06-09 09:18:21 +08:00
|
|
|
scale = (gdouble) doc_width / extracted_data.width;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
/* read the file */
|
|
|
|
|
|
|
|
for (i = 0; i < pages->n_pages; i++)
|
2005-07-18 18:16:45 +08:00
|
|
|
{
|
2005-08-15 18:30:39 +08:00
|
|
|
PopplerPage *page;
|
|
|
|
gchar *page_label;
|
|
|
|
gdouble page_width;
|
|
|
|
gdouble page_height;
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2011-04-21 10:18:25 +08:00
|
|
|
cairo_surface_t *surface;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
2021-01-09 00:44:36 +08:00
|
|
|
gint page_index;
|
2005-08-15 18:30:39 +08:00
|
|
|
|
2021-01-09 00:44:36 +08:00
|
|
|
page_index = base_index + sign * i;
|
|
|
|
|
|
|
|
page = poppler_document_get_page (doc, pages->pages[page_index]);
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
poppler_page_get_size (page, &page_width, &page_height);
|
2024-04-24 05:22:41 +08:00
|
|
|
width = (gint) ceil (page_width * scale);
|
|
|
|
height = (gint) ceil (page_height * scale);
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2005-08-23 07:05:12 +08:00
|
|
|
g_object_get (G_OBJECT (page), "label", &page_label, NULL);
|
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
if (! image)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2024-04-24 05:22:41 +08:00
|
|
|
image = gimp_image_new (doc_width, doc_height, GIMP_RGB);
|
2019-08-23 05:22:48 +08:00
|
|
|
gimp_image_undo_disable (image);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
gimp_image_set_resolution (image, resolution, resolution);
|
2005-07-16 06:54:59 +08:00
|
|
|
}
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
surface = render_page_to_surface (page, width, height, scale,
|
|
|
|
antialias, white_background);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2020-04-09 02:08:00 +08:00
|
|
|
layer_from_surface (image, page_label, 0, surface,
|
2011-04-21 10:18:25 +08:00
|
|
|
doc_progress, 1.0 / pages->n_pages);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
g_free (page_label);
|
2011-04-21 10:18:25 +08:00
|
|
|
cairo_surface_destroy (surface);
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
doc_progress = (double) (i + 1) / pages->n_pages;
|
|
|
|
gimp_progress_update (doc_progress);
|
2005-08-23 07:05:12 +08:00
|
|
|
|
|
|
|
if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
|
|
|
{
|
2019-08-23 05:22:48 +08:00
|
|
|
images[i] = image;
|
2005-08-23 07:05:12 +08:00
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
gimp_image_undo_enable (image);
|
|
|
|
gimp_image_clean_all (image);
|
2005-08-23 07:05:12 +08:00
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
image = 0;
|
2005-08-23 07:05:12 +08:00
|
|
|
}
|
2011-04-11 01:05:08 +08:00
|
|
|
}
|
|
|
|
gimp_progress_update (1.0);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
if (image)
|
2005-08-23 07:05:12 +08:00
|
|
|
{
|
2019-08-23 05:22:48 +08:00
|
|
|
gimp_image_undo_enable (image);
|
|
|
|
gimp_image_clean_all (image);
|
2005-08-23 07:05:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
2005-08-15 18:30:39 +08:00
|
|
|
{
|
2005-08-23 07:05:12 +08:00
|
|
|
if (run_mode != GIMP_RUN_NONINTERACTIVE)
|
|
|
|
{
|
|
|
|
/* Display images in reverse order. The last will be
|
|
|
|
* displayed by GIMP itself
|
|
|
|
*/
|
|
|
|
for (i = pages->n_pages - 1; i > 0; i--)
|
|
|
|
gimp_display_new (images[i]);
|
|
|
|
}
|
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
image = images[0];
|
2005-08-23 07:05:12 +08:00
|
|
|
|
|
|
|
g_free (images);
|
2005-08-15 18:30:39 +08:00
|
|
|
}
|
|
|
|
|
2019-08-23 05:22:48 +08:00
|
|
|
return image;
|
2005-07-16 06:54:59 +08:00
|
|
|
}
|
|
|
|
|
2011-04-21 10:18:25 +08:00
|
|
|
static cairo_surface_t *
|
|
|
|
get_thumb_surface (PopplerDocument *doc,
|
|
|
|
gint page_num,
|
2023-04-22 06:10:12 +08:00
|
|
|
gint preferred_size,
|
|
|
|
gboolean white_background)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2023-04-22 06:10:12 +08:00
|
|
|
PopplerPage *page;
|
2011-04-21 10:18:25 +08:00
|
|
|
cairo_surface_t *surface;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
page = poppler_document_get_page (doc, page_num);
|
|
|
|
|
|
|
|
if (! page)
|
|
|
|
return NULL;
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2011-04-21 10:18:25 +08:00
|
|
|
surface = poppler_page_get_thumbnail (page);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2011-04-21 10:18:25 +08:00
|
|
|
if (! surface)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2007-04-27 18:12:12 +08:00
|
|
|
gdouble width;
|
|
|
|
gdouble height;
|
|
|
|
gdouble scale;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
poppler_page_get_size (page, &width, &height);
|
|
|
|
|
2007-04-27 18:12:12 +08:00
|
|
|
scale = (gdouble) preferred_size / MAX (width, height);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
width *= scale;
|
|
|
|
height *= scale;
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
surface = render_page_to_surface (page, width, height, scale, TRUE, white_background);
|
2005-07-16 06:54:59 +08:00
|
|
|
}
|
|
|
|
|
2005-07-16 07:48:09 +08:00
|
|
|
g_object_unref (page);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2011-04-21 10:18:25 +08:00
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkPixbuf *
|
|
|
|
get_thumb_pixbuf (PopplerDocument *doc,
|
|
|
|
gint page_num,
|
2023-04-22 06:10:12 +08:00
|
|
|
gint preferred_size,
|
|
|
|
gboolean white_background)
|
2011-04-21 10:18:25 +08:00
|
|
|
{
|
|
|
|
cairo_surface_t *surface;
|
2023-04-22 06:10:12 +08:00
|
|
|
GdkPixbuf *pixbuf;
|
2011-04-21 10:18:25 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
surface = get_thumb_surface (doc, page_num, preferred_size, white_background);
|
|
|
|
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
|
|
|
|
cairo_image_surface_get_width (surface),
|
|
|
|
cairo_image_surface_get_height (surface));
|
2011-04-21 10:18:25 +08:00
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
return pixbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
PopplerDocument *document;
|
|
|
|
GimpPageSelector *selector;
|
2023-04-22 06:10:12 +08:00
|
|
|
gboolean white_background;
|
|
|
|
|
|
|
|
GMutex mutex;
|
|
|
|
GCond render_thumb;
|
2023-04-22 07:09:38 +08:00
|
|
|
gboolean stop_thumbnailing;
|
|
|
|
gboolean render_thumbnails;
|
2005-07-16 06:54:59 +08:00
|
|
|
} ThreadData;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GimpPageSelector *selector;
|
|
|
|
gint page_no;
|
|
|
|
GdkPixbuf *pixbuf;
|
|
|
|
} IdleData;
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
idle_set_thumbnail (gpointer data)
|
|
|
|
{
|
|
|
|
IdleData *idle_data = data;
|
|
|
|
|
|
|
|
gimp_page_selector_set_page_thumbnail (idle_data->selector,
|
|
|
|
idle_data->page_no,
|
|
|
|
idle_data->pixbuf);
|
|
|
|
g_object_unref (idle_data->pixbuf);
|
|
|
|
g_free (idle_data);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gpointer
|
|
|
|
thumbnail_thread (gpointer data)
|
|
|
|
{
|
2023-04-22 06:10:12 +08:00
|
|
|
ThreadData *thread_data = data;
|
|
|
|
gboolean first_loop = TRUE;
|
|
|
|
gint n_pages;
|
|
|
|
gint i;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
|
|
|
n_pages = poppler_document_get_n_pages (thread_data->document);
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
while (TRUE)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2023-04-22 06:10:12 +08:00
|
|
|
gboolean white_background;
|
|
|
|
gboolean stop_thumbnailing;
|
2023-04-22 07:09:38 +08:00
|
|
|
gboolean render_thumbnails;
|
2023-04-22 06:10:12 +08:00
|
|
|
|
|
|
|
g_mutex_lock (&thread_data->mutex);
|
2023-04-22 07:09:38 +08:00
|
|
|
if (first_loop)
|
|
|
|
first_loop = FALSE;
|
|
|
|
else
|
2023-04-22 06:10:12 +08:00
|
|
|
g_cond_wait (&thread_data->render_thumb, &thread_data->mutex);
|
2023-04-22 07:09:38 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
stop_thumbnailing = thread_data->stop_thumbnailing;
|
|
|
|
g_mutex_unlock (&thread_data->mutex);
|
|
|
|
|
|
|
|
if (stop_thumbnailing)
|
|
|
|
break;
|
|
|
|
|
2023-04-22 07:09:38 +08:00
|
|
|
g_mutex_lock (&thread_data->mutex);
|
|
|
|
render_thumbnails = thread_data->render_thumbnails;
|
|
|
|
white_background = thread_data->white_background;
|
|
|
|
thread_data->render_thumbnails = FALSE;
|
|
|
|
g_mutex_unlock (&thread_data->mutex);
|
|
|
|
|
|
|
|
/* This handles "spurious wakeup", i.e. cases when g_cond_wait() returned
|
|
|
|
* even though there was no call asking us to re-render the thumbnails.
|
|
|
|
* See docs of g_cond_wait().
|
|
|
|
*/
|
|
|
|
if (! render_thumbnails)
|
|
|
|
continue;
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
for (i = 0; i < n_pages; i++)
|
|
|
|
{
|
|
|
|
IdleData *idle_data = g_new0 (IdleData, 1);
|
|
|
|
gboolean white_background2;
|
|
|
|
|
|
|
|
idle_data->selector = thread_data->selector;
|
|
|
|
idle_data->page_no = i;
|
|
|
|
|
|
|
|
/* FIXME get preferred size from somewhere? */
|
|
|
|
idle_data->pixbuf = get_thumb_pixbuf (thread_data->document, i,
|
|
|
|
THUMBNAIL_SIZE,
|
|
|
|
white_background);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
g_idle_add (idle_set_thumbnail, idle_data);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
g_mutex_lock (&thread_data->mutex);
|
|
|
|
white_background2 = thread_data->white_background;
|
|
|
|
stop_thumbnailing = thread_data->stop_thumbnailing;
|
|
|
|
g_mutex_unlock (&thread_data->mutex);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
if (stop_thumbnailing || white_background2 != white_background)
|
|
|
|
break;
|
|
|
|
}
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
if (stop_thumbnailing)
|
2005-07-16 06:54:59 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
static void
|
|
|
|
white_background_toggled (GtkToggleButton *widget,
|
|
|
|
ThreadData *thread_data)
|
|
|
|
{
|
|
|
|
g_mutex_lock (&thread_data->mutex);
|
2023-04-22 07:09:38 +08:00
|
|
|
thread_data->white_background = gtk_toggle_button_get_active (widget);
|
|
|
|
thread_data->render_thumbnails = TRUE;
|
2023-04-22 06:10:12 +08:00
|
|
|
g_cond_signal (&thread_data->render_thumb);
|
|
|
|
g_mutex_unlock (&thread_data->mutex);
|
|
|
|
}
|
|
|
|
|
2011-12-07 20:53:26 +08:00
|
|
|
static GimpPDBStatusType
|
2023-04-22 06:10:12 +08:00
|
|
|
load_dialog (PopplerDocument *doc,
|
|
|
|
PdfSelectedPages *pages,
|
2024-06-09 00:37:38 +08:00
|
|
|
GimpVectorLoadData extracted_data,
|
2023-04-22 06:10:12 +08:00
|
|
|
GimpProcedure *procedure,
|
|
|
|
GimpProcedureConfig *config)
|
2005-07-16 06:54:59 +08:00
|
|
|
{
|
2005-07-18 18:16:45 +08:00
|
|
|
GtkWidget *dialog;
|
|
|
|
GtkWidget *vbox;
|
2006-03-17 23:43:15 +08:00
|
|
|
GtkWidget *title;
|
2005-07-18 18:16:45 +08:00
|
|
|
GtkWidget *selector;
|
2023-04-22 06:10:12 +08:00
|
|
|
GtkWidget *white_bg;
|
2005-07-16 07:48:09 +08:00
|
|
|
|
2005-07-18 18:16:45 +08:00
|
|
|
ThreadData thread_data;
|
|
|
|
GThread *thread;
|
|
|
|
|
|
|
|
gint i;
|
|
|
|
gint n_pages;
|
|
|
|
|
|
|
|
gboolean run;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
GimpPageSelectorTarget target;
|
|
|
|
gboolean white_background;
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2024-04-24 05:22:41 +08:00
|
|
|
n_pages = poppler_document_get_n_pages (doc);
|
|
|
|
|
|
|
|
dialog = gimp_vector_load_procedure_dialog_new (GIMP_VECTOR_LOAD_PROCEDURE (procedure),
|
|
|
|
GIMP_PROCEDURE_CONFIG (config),
|
2024-06-09 00:37:38 +08:00
|
|
|
&extracted_data, NULL);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
g_object_get (config,
|
|
|
|
"target", &target,
|
|
|
|
"white-background", &white_background,
|
|
|
|
NULL);
|
2007-05-15 15:12:15 +08:00
|
|
|
|
2011-09-30 18:17:53 +08:00
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
2005-07-16 06:54:59 +08:00
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
|
2011-03-04 17:44:58 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
|
|
|
|
vbox, TRUE, TRUE, 0);
|
2005-07-16 06:54:59 +08:00
|
|
|
gtk_widget_show (vbox);
|
|
|
|
|
2005-07-16 07:48:09 +08:00
|
|
|
/* Title */
|
2006-03-17 23:43:15 +08:00
|
|
|
title = gimp_prop_label_new (G_OBJECT (doc), "title");
|
2010-03-28 18:34:38 +08:00
|
|
|
gtk_label_set_ellipsize (GTK_LABEL (title), PANGO_ELLIPSIZE_END);
|
2006-03-17 23:43:15 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), title, FALSE, FALSE, 0);
|
2005-07-16 07:48:09 +08:00
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
/* Page Selector */
|
|
|
|
selector = gimp_page_selector_new ();
|
2007-05-02 22:30:17 +08:00
|
|
|
gtk_widget_set_size_request (selector, 380, 360);
|
2005-07-16 06:54:59 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), selector, TRUE, TRUE, 0);
|
2007-05-02 22:30:17 +08:00
|
|
|
gtk_widget_show (selector);
|
|
|
|
|
2011-12-07 20:27:28 +08:00
|
|
|
if (n_pages <= 0)
|
2011-12-08 02:09:31 +08:00
|
|
|
{
|
|
|
|
g_message (_("Error getting number of pages from the given PDF file."));
|
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
|
|
|
}
|
2011-12-07 20:27:28 +08:00
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
gimp_page_selector_set_n_pages (GIMP_PAGE_SELECTOR (selector), n_pages);
|
2007-05-02 22:30:17 +08:00
|
|
|
gimp_page_selector_set_target (GIMP_PAGE_SELECTOR (selector),
|
2023-04-22 06:10:12 +08:00
|
|
|
target);
|
2005-07-16 07:48:09 +08:00
|
|
|
|
2005-07-18 18:16:45 +08:00
|
|
|
for (i = 0; i < n_pages; i++)
|
2005-07-16 07:48:09 +08:00
|
|
|
{
|
2023-04-22 06:10:12 +08:00
|
|
|
PopplerPage *page;
|
|
|
|
gchar *label;
|
2005-07-16 07:48:09 +08:00
|
|
|
|
|
|
|
page = poppler_document_get_page (doc, i);
|
|
|
|
g_object_get (G_OBJECT (page), "label", &label, NULL);
|
|
|
|
|
|
|
|
gimp_page_selector_set_page_label (GIMP_PAGE_SELECTOR (selector), i,
|
|
|
|
label);
|
|
|
|
|
|
|
|
g_object_unref (page);
|
|
|
|
g_free (label);
|
|
|
|
}
|
2017-09-25 05:54:49 +08:00
|
|
|
/* Since selecting none will be equivalent to selecting all, this is
|
|
|
|
* only useful as a feedback for the default behavior of selecting all
|
|
|
|
* pages. */
|
2017-09-25 07:53:59 +08:00
|
|
|
gimp_page_selector_select_all (GIMP_PAGE_SELECTOR (selector));
|
2005-07-16 07:48:09 +08:00
|
|
|
|
2005-10-28 22:57:32 +08:00
|
|
|
g_signal_connect_swapped (selector, "activate",
|
|
|
|
G_CALLBACK (gtk_window_activate_default),
|
|
|
|
dialog);
|
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
thread_data.document = doc;
|
|
|
|
thread_data.selector = GIMP_PAGE_SELECTOR (selector);
|
2023-04-22 07:09:38 +08:00
|
|
|
thread_data.render_thumbnails = TRUE;
|
2005-07-16 06:54:59 +08:00
|
|
|
thread_data.stop_thumbnailing = FALSE;
|
2023-04-22 06:10:12 +08:00
|
|
|
thread_data.white_background = white_background;
|
|
|
|
g_mutex_init (&thread_data.mutex);
|
|
|
|
g_cond_init (&thread_data.render_thumb);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2012-11-21 08:47:11 +08:00
|
|
|
thread = g_thread_new ("thumbnailer", thumbnail_thread, &thread_data);
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"reverse-order",
|
|
|
|
NULL);
|
2021-01-09 00:44:36 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
white_bg = gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"white-background", G_TYPE_NONE);
|
|
|
|
g_signal_connect (white_bg, "toggled",
|
|
|
|
G_CALLBACK (white_background_toggled), &thread_data);
|
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"antialias",
|
|
|
|
"white-background",
|
|
|
|
NULL);
|
2012-02-02 22:04:07 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
|
2005-07-16 06:54:59 +08:00
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
target = gimp_page_selector_get_target (GIMP_PAGE_SELECTOR (selector));
|
|
|
|
g_object_set (config,
|
|
|
|
"target", target,
|
|
|
|
NULL);
|
2005-08-23 07:05:12 +08:00
|
|
|
|
2005-07-18 18:16:45 +08:00
|
|
|
pages->pages =
|
2005-07-16 06:54:59 +08:00
|
|
|
gimp_page_selector_get_selected_pages (GIMP_PAGE_SELECTOR (selector),
|
|
|
|
&pages->n_pages);
|
|
|
|
|
|
|
|
/* select all if none selected */
|
|
|
|
if (pages->n_pages == 0)
|
|
|
|
{
|
|
|
|
gimp_page_selector_select_all (GIMP_PAGE_SELECTOR (selector));
|
|
|
|
|
2005-07-18 18:16:45 +08:00
|
|
|
pages->pages =
|
2005-07-16 06:54:59 +08:00
|
|
|
gimp_page_selector_get_selected_pages (GIMP_PAGE_SELECTOR (selector),
|
|
|
|
&pages->n_pages);
|
|
|
|
}
|
2005-07-18 18:16:45 +08:00
|
|
|
|
2005-07-16 06:54:59 +08:00
|
|
|
/* cleanup */
|
2023-04-22 06:10:12 +08:00
|
|
|
g_mutex_lock (&thread_data.mutex);
|
2005-07-16 06:54:59 +08:00
|
|
|
thread_data.stop_thumbnailing = TRUE;
|
2023-04-22 06:10:12 +08:00
|
|
|
g_cond_signal (&thread_data.render_thumb);
|
|
|
|
g_mutex_unlock (&thread_data.mutex);
|
2005-07-16 06:54:59 +08:00
|
|
|
g_thread_join (thread);
|
|
|
|
|
2023-04-22 06:10:12 +08:00
|
|
|
g_mutex_clear (&thread_data.mutex);
|
|
|
|
g_cond_clear (&thread_data.render_thumb);
|
|
|
|
|
|
|
|
/* XXX Unsure why, I get some CRITICALs when destroying the dialog, unless I
|
|
|
|
* unselect all first.
|
|
|
|
*/
|
|
|
|
gimp_page_selector_unselect_all (GIMP_PAGE_SELECTOR (selector));
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
|
2011-12-07 20:53:26 +08:00
|
|
|
return run ? GIMP_PDB_SUCCESS : GIMP_PDB_CANCEL;
|
2005-07-16 06:54:59 +08:00
|
|
|
}
|