diff --git a/ChangeLog b/ChangeLog index 1d11294eeb..11f44aeca0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2004-11-13 Sven Neumann + + * app/plug-in/plug-in-proc-def.[ch] + * app/plug-in/plug-in-rc.c + * app/plug-in/plug-ins.[ch]: allow to associate a procedure for + thumbnail loading with any file load procedure. + + * tools/pdbgen/pdb/fileops.pdb: export this functionality to the + PDB as gimp_register_thumbnail_loader(). + + * app/pdb/fileops_cmds.c + * app/pdb/internal_procs.c + * libgimp/gimpfileops_pdb.[ch]: regenerated. + + * app/core/gimpimagefile.c + * app/file/file-open.[ch]: when creating a thumbnail for an image + file, use a thumbnail load procedure if available. + + * plug-ins/common/svg.c: added "file_svg_load_thumb", a procedure + that allows to load a small preview of the SVG image. + 2004-11-13 DindinX * app/actions/layers-actions.c: added back H as a shortcut diff --git a/app/core/gimpimagefile.c b/app/core/gimpimagefile.c index 46dd74f350..4d61dde47b 100644 --- a/app/core/gimpimagefile.c +++ b/app/core/gimpimagefile.c @@ -78,6 +78,15 @@ static gboolean gimp_imagefile_save_thumb (GimpImagefile *imagefile, static gchar * gimp_imagefile_get_description (GimpViewable *viewable, gchar **tooltip); +static void gimp_thumbnail_set_info_from_image (GimpThumbnail *thumbnail, + const gchar *mime_type, + GimpImage *image); +static void gimp_thumbnail_set_info (GimpThumbnail *thumbnail, + const gchar *mime_type, + gint width, + gint height); + + static guint gimp_imagefile_signals[LAST_SIGNAL] = { 0 }; @@ -253,34 +262,46 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile, if (gimp_thumbnail_peek_image (thumbnail) >= GIMP_THUMB_STATE_EXISTS) { - GimpImage *gimage; - GimpPDBStatusType dummy; - gboolean success; - const gchar *mime_type = NULL; - GError *error = NULL; + GimpImage *image; + gboolean success; + gint width = 0; + gint height = 0; + const gchar *mime_type = NULL; + GError *error = NULL; g_object_ref (imagefile); - gimage = file_open_image (imagefile->gimp, context, progress, - thumbnail->image_uri, - thumbnail->image_uri, - NULL, - GIMP_RUN_NONINTERACTIVE, - &dummy, - &mime_type, - NULL); + image = file_open_thumbnail (imagefile->gimp, context, progress, + thumbnail->image_uri, size, + &mime_type, &width, &height); - if (gimage) + if (image) { - if (mime_type) - g_object_set (thumbnail, - "image-mimetype", mime_type, - NULL); + gimp_thumbnail_set_info (imagefile->thumbnail, + mime_type, width, height); + } + else + { + GimpPDBStatusType status; + + image = file_open_image (imagefile->gimp, context, progress, + thumbnail->image_uri, thumbnail->image_uri, + NULL, GIMP_RUN_NONINTERACTIVE, + &status, &mime_type, NULL); + + if (image) + gimp_thumbnail_set_info_from_image (imagefile->thumbnail, + mime_type, image); + } + + if (image) + { success = gimp_imagefile_save_thumb (imagefile, - gimage, size, replace, &error); + image, size, replace, + &error); - g_object_unref (gimage); + g_object_unref (image); } else { @@ -386,13 +407,11 @@ gimp_imagefile_save_thumbnail (GimpImagefile *imagefile, if (size > 0) { - /* peek the thumbnail to make sure that mtime and filesize are set */ - gimp_thumbnail_peek_image (imagefile->thumbnail); + gimp_thumbnail_set_info_from_image (imagefile->thumbnail, NULL, gimage); success = gimp_imagefile_save_thumb (imagefile, gimage, size, FALSE, &error); - if (! success) { g_message (error->message); @@ -719,9 +738,6 @@ gimp_imagefile_save_thumb (GimpImagefile *imagefile, { GimpThumbnail *thumbnail = imagefile->thumbnail; GdkPixbuf *pixbuf; - GimpEnumDesc *enum_desc; - GimpImageType type; - gint num_layers; gint width, height; gboolean success = FALSE; @@ -755,24 +771,6 @@ gimp_imagefile_save_thumb (GimpImagefile *imagefile, if (! pixbuf) return TRUE; - type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (gimp_image_base_type (gimage)); - - if (gimp_image_has_alpha (gimage)) - type = GIMP_IMAGE_TYPE_WITH_ALPHA (type); - - - enum_desc = gimp_enum_get_desc (g_type_class_peek (GIMP_TYPE_IMAGE_TYPE), - type); - - num_layers = gimp_container_num_children (gimage->layers); - - g_object_set (thumbnail, - "image-width", gimage->width, - "image-height", gimage->height, - "image-type", enum_desc->value_desc, - "image-num-layers", num_layers, - NULL); - success = gimp_thumbnail_save_thumb (thumbnail, pixbuf, "The GIMP " GIMP_VERSION, @@ -792,3 +790,48 @@ gimp_imagefile_save_thumb (GimpImagefile *imagefile, return success; } + +static void +gimp_thumbnail_set_info_from_image (GimpThumbnail *thumbnail, + const gchar *mime_type, + GimpImage *image) +{ + GimpEnumDesc *desc; + GimpImageType type; + + /* peek the thumbnail to make sure that mtime and filesize are set */ + gimp_thumbnail_peek_image (thumbnail); + + type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (gimp_image_base_type (image)); + + if (gimp_image_has_alpha (image)) + type = GIMP_IMAGE_TYPE_WITH_ALPHA (type); + + desc = gimp_enum_get_desc (g_type_class_peek (GIMP_TYPE_IMAGE_TYPE), type); + + g_object_set (thumbnail, + "image-mimetype", mime_type, + "image-width", gimp_image_get_width (image), + "image-height", gimp_image_get_height (image), + "image-type", desc->value_desc, + "image-num-layers", gimp_container_num_children (image->layers), + NULL); +} + +static void +gimp_thumbnail_set_info (GimpThumbnail *thumbnail, + const gchar *mime_type, + gint width, + gint height) +{ + /* peek the thumbnail to make sure that mtime and filesize are set */ + gimp_thumbnail_peek_image (thumbnail); + + g_object_set (thumbnail, + "image-mimetype", mime_type, + "image-width", width, + "image-height", height, + "image-type", NULL, + "image-num-layers", NULL, + NULL); +} diff --git a/app/file/file-open.c b/app/file/file-open.c index ecaf27bb80..28b79d7d83 100644 --- a/app/file/file-open.c +++ b/app/file/file-open.c @@ -64,6 +64,9 @@ #include "gimp-intl.h" +static void file_open_sanitize_image (GimpImage *gimage); + + /* public functions */ GimpImage * @@ -81,7 +84,7 @@ file_open_image (Gimp *gimp, const ProcRecord *proc; Argument *args; Argument *return_vals; - gint gimage_id; + gint image_id; gint i; gchar *filename; @@ -89,7 +92,6 @@ file_open_image (Gimp *gimp, g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); g_return_val_if_fail (status != NULL, NULL); - g_return_val_if_fail (mime_type == NULL || *mime_type == NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); *status = GIMP_PDB_EXECUTION_ERROR; @@ -146,31 +148,19 @@ file_open_image (Gimp *gimp, if (filename) g_free (filename); - *status = return_vals[0].value.pdb_int; - gimage_id = return_vals[1].value.pdb_int; + *status = return_vals[0].value.pdb_int; + image_id = return_vals[1].value.pdb_int; procedural_db_destroy_args (return_vals, proc->num_values); g_free (args); if (*status == GIMP_PDB_SUCCESS) { - if (gimage_id != -1) + if (image_id != -1) { - GimpImage *gimage = gimp_image_get_by_ID (gimp, gimage_id); + GimpImage *gimage = gimp_image_get_by_ID (gimp, image_id); - /* clear all undo steps */ - gimp_image_undo_free (gimage); - - /* make sure that undo is enabled */ - while (gimage->undo_freeze_count) - gimp_image_undo_thaw (gimage); - - /* set the image to clean */ - gimp_image_clean_all (gimage); - - gimp_image_invalidate_layer_previews (gimage); - gimp_image_invalidate_channel_previews (gimage); - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); + file_open_sanitize_image (gimage); if (mime_type) *mime_type = file_proc->mime_type; @@ -194,6 +184,88 @@ file_open_image (Gimp *gimp, return NULL; } +/* Attempts to load a thumbnail by using a registered thumbnail loader. */ +GimpImage * +file_open_thumbnail (Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + const gchar *uri, + gint size, + const gchar **mime_type, + gint *image_width, + gint *image_height) +{ + PlugInProcDef *file_proc; + const ProcRecord *proc; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); + g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); + g_return_val_if_fail (mime_type != NULL, NULL); + g_return_val_if_fail (image_width != NULL, NULL); + g_return_val_if_fail (image_height != NULL, NULL); + + *image_width = 0; + *image_height = 0; + + file_proc = file_utils_find_proc (gimp->load_procs, uri); + + if (! file_proc || ! file_proc->thumb_loader) + return NULL; + + proc = procedural_db_lookup (gimp, file_proc->thumb_loader); + + if (proc && proc->num_args >= 2) + { + GimpPDBStatusType status; + Argument *args; + Argument *return_vals; + gchar *filename; + gint image_id; + gint i; + + filename = g_filename_from_uri (uri, NULL, NULL); + + args = g_new0 (Argument, proc->num_args); + + for (i = 0; i < proc->num_args; i++) + args[i].arg_type = proc->args[i].arg_type; + + args[0].value.pdb_pointer = filename ? filename : (gchar *) uri; + args[1].value.pdb_int = size; + + return_vals = procedural_db_execute (gimp, context, progress, + proc->name, args); + + if (filename) + g_free (filename); + + status = return_vals[0].value.pdb_int; + image_id = return_vals[1].value.pdb_int; + *image_width = MAX (0, return_vals[2].value.pdb_int); + *image_height = MAX (0, return_vals[3].value.pdb_int); + + procedural_db_destroy_args (return_vals, proc->num_values); + g_free (args); + + if (status == GIMP_PDB_SUCCESS && image_id != -1) + { + GimpImage *image = gimp_image_get_by_ID (gimp, image_id); + + file_open_sanitize_image (image); + + *mime_type = file_proc->mime_type; + + g_printerr ("opened thumbnail at %d x %d\n", + image->width, image->height); + + return image; + } + } + + return NULL; +} + GimpImage * file_open_with_display (Gimp *gimp, GimpContext *context, @@ -347,3 +419,24 @@ file_open_layer (Gimp *gimp, return new_layer; } + + +/* private functions */ + +static void +file_open_sanitize_image (GimpImage *gimage) +{ + /* clear all undo steps */ + gimp_image_undo_free (gimage); + + /* make sure that undo is enabled */ + while (gimage->undo_freeze_count) + gimp_image_undo_thaw (gimage); + + /* set the image to clean */ + gimp_image_clean_all (gimage); + + gimp_image_invalidate_layer_previews (gimage); + gimp_image_invalidate_channel_previews (gimage); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); +} diff --git a/app/file/file-open.h b/app/file/file-open.h index 5a8cc84e17..e2687f2435 100644 --- a/app/file/file-open.h +++ b/app/file/file-open.h @@ -33,6 +33,14 @@ GimpImage * file_open_image (Gimp *gimp, const gchar **mime_type, GError **error); +GimpImage * file_open_thumbnail (Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + const gchar *uri, + gint size, + const gchar **mime_type, + gint *image_width, + gint *image_height); GimpImage * file_open_with_display (Gimp *gimp, GimpContext *context, GimpProgress *progress, diff --git a/app/pdb/fileops_cmds.c b/app/pdb/fileops_cmds.c index a17cadf432..31855dcfc4 100644 --- a/app/pdb/fileops_cmds.c +++ b/app/pdb/fileops_cmds.c @@ -63,6 +63,7 @@ static ProcRecord register_magic_load_handler_proc; static ProcRecord register_load_handler_proc; static ProcRecord register_save_handler_proc; static ProcRecord register_file_handler_mime_proc; +static ProcRecord register_thumbnail_loader_proc; void register_fileops_procs (Gimp *gimp) @@ -76,6 +77,7 @@ register_fileops_procs (Gimp *gimp) procedural_db_register (gimp, ®ister_load_handler_proc); procedural_db_register (gimp, ®ister_save_handler_proc); procedural_db_register (gimp, ®ister_file_handler_mime_proc); + procedural_db_register (gimp, ®ister_thumbnail_loader_proc); } static Argument * @@ -861,3 +863,62 @@ static ProcRecord register_file_handler_mime_proc = NULL, { { register_file_handler_mime_invoker } } }; + +static Argument * +register_thumbnail_loader_invoker (Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + Argument *args) +{ + gboolean success = TRUE; + gchar *load_proc; + gchar *thumb_proc; + + load_proc = (gchar *) args[0].value.pdb_pointer; + if (load_proc == NULL || !g_utf8_validate (load_proc, -1, NULL)) + success = FALSE; + + thumb_proc = (gchar *) args[1].value.pdb_pointer; + if (thumb_proc == NULL || !g_utf8_validate (thumb_proc, -1, NULL)) + success = FALSE; + + if (success) + { + success = (plug_ins_file_register_thumb_loader (gimp, + load_proc, + thumb_proc) != NULL); + } + + return procedural_db_return_args (®ister_thumbnail_loader_proc, success); +} + +static ProcArg register_thumbnail_loader_inargs[] = +{ + { + GIMP_PDB_STRING, + "load_proc", + "The name of the procedure the thumbnail loader with." + }, + { + GIMP_PDB_STRING, + "thumb_proc", + "The name of the thumbnail load procedure." + } +}; + +static ProcRecord register_thumbnail_loader_proc = +{ + "gimp_register_thumbnail_loader", + "Associates a thumbnail loader with a file load procedure.", + "Some file formats allow for embedded thumbnails, other file formats contain a scalable image or provide the image data in different resolutions. A file plug-in for such a format may register a special procedure that allows GIMP to load a thumbnail preview of the image. This procedure is then associated with the standard load procedure using this function.", + "Sven Neumann", + "Sven Neumann", + "2004", + NULL, + GIMP_INTERNAL, + 2, + register_thumbnail_loader_inargs, + 0, + NULL, + { { register_thumbnail_loader_invoker } } +}; diff --git a/app/pdb/gimppluginprocedure.c b/app/pdb/gimppluginprocedure.c index 9f1e3b2820..3ed851c7bd 100644 --- a/app/pdb/gimppluginprocedure.c +++ b/app/pdb/gimppluginprocedure.c @@ -100,6 +100,8 @@ plug_in_proc_def_free (PlugInProcDef *proc_def) g_slist_foreach (proc_def->magics_list, (GFunc) g_free, NULL); g_slist_free (proc_def->magics_list); + g_free (proc_def->thumb_loader); + g_free (proc_def); } diff --git a/app/pdb/gimppluginprocedure.h b/app/pdb/gimppluginprocedure.h index 65bfdd1173..1511832e84 100644 --- a/app/pdb/gimppluginprocedure.h +++ b/app/pdb/gimppluginprocedure.h @@ -51,6 +51,7 @@ struct _PlugInProcDef GSList *extensions_list; GSList *prefixes_list; GSList *magics_list; + gchar *thumb_loader; }; diff --git a/app/pdb/internal_procs.c b/app/pdb/internal_procs.c index 8c31748807..11534d4eea 100644 --- a/app/pdb/internal_procs.c +++ b/app/pdb/internal_procs.c @@ -74,7 +74,7 @@ void register_transform_tools_procs (Gimp *gimp); void register_undo_procs (Gimp *gimp); void register_unit_procs (Gimp *gimp); -/* 433 procedures registered total */ +/* 434 procedures registered total */ void internal_procs_init (Gimp *gimp, @@ -98,7 +98,7 @@ internal_procs_init (Gimp *gimp, (* status_callback) (NULL, _("Color"), 0.06); register_color_procs (gimp); - (* status_callback) (NULL, _("Context"), 0.095); + (* status_callback) (NULL, _("Context"), 0.094); register_context_procs (gimp); (* status_callback) (NULL, _("Convert"), 0.145); @@ -107,61 +107,61 @@ internal_procs_init (Gimp *gimp, (* status_callback) (NULL, _("Display procedures"), 0.152); register_display_procs (gimp); - (* status_callback) (NULL, _("Drawable procedures"), 0.162); + (* status_callback) (NULL, _("Drawable procedures"), 0.161); register_drawable_procs (gimp); - (* status_callback) (NULL, _("Transformation procedures"), 0.238); + (* status_callback) (NULL, _("Transformation procedures"), 0.237); register_drawable_transform_procs (gimp); - (* status_callback) (NULL, _("Edit procedures"), 0.275); + (* status_callback) (NULL, _("Edit procedures"), 0.274); register_edit_procs (gimp); (* status_callback) (NULL, _("File Operations"), 0.293); register_fileops_procs (gimp); - (* status_callback) (NULL, _("Floating selections"), 0.314); + (* status_callback) (NULL, _("Floating selections"), 0.316); register_floating_sel_procs (gimp); - (* status_callback) (NULL, _("Font UI"), 0.328); + (* status_callback) (NULL, _("Font UI"), 0.329); register_font_select_procs (gimp); - (* status_callback) (NULL, _("Fonts"), 0.335); + (* status_callback) (NULL, _("Fonts"), 0.336); register_fonts_procs (gimp); - (* status_callback) (NULL, _("Gimprc procedures"), 0.339); + (* status_callback) (NULL, _("Gimprc procedures"), 0.341); register_gimprc_procs (gimp); - (* status_callback) (NULL, _("Gradient"), 0.353); + (* status_callback) (NULL, _("Gradient"), 0.355); register_gradient_procs (gimp); - (* status_callback) (NULL, _("Gradient UI"), 0.42); + (* status_callback) (NULL, _("Gradient UI"), 0.422); register_gradient_select_procs (gimp); - (* status_callback) (NULL, _("Gradients"), 0.427); + (* status_callback) (NULL, _("Gradients"), 0.429); register_gradients_procs (gimp); - (* status_callback) (NULL, _("Guide procedures"), 0.439); + (* status_callback) (NULL, _("Guide procedures"), 0.44); register_guides_procs (gimp); - (* status_callback) (NULL, _("Help procedures"), 0.453); + (* status_callback) (NULL, _("Help procedures"), 0.454); register_help_procs (gimp); - (* status_callback) (NULL, _("Image"), 0.455); + (* status_callback) (NULL, _("Image"), 0.456); register_image_procs (gimp); - (* status_callback) (NULL, _("Layer"), 0.603); + (* status_callback) (NULL, _("Layer"), 0.604); register_layer_procs (gimp); - (* status_callback) (NULL, _("Message procedures"), 0.665); + (* status_callback) (NULL, _("Message procedures"), 0.666); register_message_procs (gimp); - (* status_callback) (NULL, _("Miscellaneous"), 0.672); + (* status_callback) (NULL, _("Miscellaneous"), 0.673); register_misc_procs (gimp); (* status_callback) (NULL, _("Paint Tool procedures"), 0.677); register_paint_tools_procs (gimp); - (* status_callback) (NULL, _("Palette"), 0.711); + (* status_callback) (NULL, _("Palette"), 0.712); register_palette_procs (gimp); (* status_callback) (NULL, _("Palette UI"), 0.737); @@ -176,7 +176,7 @@ internal_procs_init (Gimp *gimp, (* status_callback) (NULL, _("Paths"), 0.781); register_paths_procs (gimp); - (* status_callback) (NULL, _("Pattern"), 0.815); + (* status_callback) (NULL, _("Pattern"), 0.816); register_pattern_procs (gimp); (* status_callback) (NULL, _("Pattern UI"), 0.82); @@ -191,13 +191,13 @@ internal_procs_init (Gimp *gimp, (* status_callback) (NULL, _("Procedural database"), 0.848); register_procedural_db_procs (gimp); - (* status_callback) (NULL, _("Progress"), 0.868); + (* status_callback) (NULL, _("Progress"), 0.869); register_progress_procs (gimp); (* status_callback) (NULL, _("Image mask"), 0.88); register_selection_procs (gimp); - (* status_callback) (NULL, _("Selection Tool procedures"), 0.921); + (* status_callback) (NULL, _("Selection Tool procedures"), 0.922); register_selection_tools_procs (gimp); (* status_callback) (NULL, _("Text procedures"), 0.933); diff --git a/app/plug-in/gimppluginmanager.c b/app/plug-in/gimppluginmanager.c index 290d2c68bd..316a908787 100644 --- a/app/plug-in/gimppluginmanager.c +++ b/app/plug-in/gimppluginmanager.c @@ -514,6 +514,39 @@ plug_ins_file_register_mime (Gimp *gimp, return NULL; } +PlugInProcDef * +plug_ins_file_register_thumb_loader (Gimp *gimp, + const gchar *load_proc, + const gchar *thumb_proc) +{ + GSList *list; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + g_return_val_if_fail (load_proc, NULL); + g_return_val_if_fail (thumb_proc, NULL); + + if (gimp->current_plug_in && gimp->current_plug_in->plug_in_def) + list = gimp->current_plug_in->plug_in_def->proc_defs; + else + list = gimp->plug_in_proc_defs; + + for (; list; list = list->next) + { + PlugInProcDef *proc_def = list->data; + + if (strcmp (proc_def->db_info.name, load_proc) == 0) + { + if (proc_def->thumb_loader) + g_free (proc_def->thumb_loader); + proc_def->thumb_loader = g_strdup (thumb_proc); + + return proc_def; + } + } + + return NULL; +} + void plug_ins_def_add_from_rc (Gimp *gimp, PlugInDef *plug_in_def) diff --git a/app/plug-in/gimppluginmanager.h b/app/plug-in/gimppluginmanager.h index e74fcb2f83..f82ec9b541 100644 --- a/app/plug-in/gimppluginmanager.h +++ b/app/plug-in/gimppluginmanager.h @@ -45,6 +45,12 @@ PlugInProcDef * plug_ins_file_register_mime (Gimp *gimp, const gchar *name, const gchar *mime_type); +PlugInProcDef * plug_ins_file_register_thumb_loader + (Gimp *gimp, + const gchar *load_proc, + const gchar *thumb_proc); + + /* Add a plug-in definition. */ void plug_ins_def_add_from_rc (Gimp *gimp, PlugInDef *plug_in_def); diff --git a/app/plug-in/gimppluginprocedure.c b/app/plug-in/gimppluginprocedure.c index 9f1e3b2820..3ed851c7bd 100644 --- a/app/plug-in/gimppluginprocedure.c +++ b/app/plug-in/gimppluginprocedure.c @@ -100,6 +100,8 @@ plug_in_proc_def_free (PlugInProcDef *proc_def) g_slist_foreach (proc_def->magics_list, (GFunc) g_free, NULL); g_slist_free (proc_def->magics_list); + g_free (proc_def->thumb_loader); + g_free (proc_def); } diff --git a/app/plug-in/gimppluginprocedure.h b/app/plug-in/gimppluginprocedure.h index 65bfdd1173..1511832e84 100644 --- a/app/plug-in/gimppluginprocedure.h +++ b/app/plug-in/gimppluginprocedure.h @@ -51,6 +51,7 @@ struct _PlugInProcDef GSList *extensions_list; GSList *prefixes_list; GSList *magics_list; + gchar *thumb_loader; }; diff --git a/app/plug-in/plug-in-proc-def.c b/app/plug-in/plug-in-proc-def.c index 9f1e3b2820..3ed851c7bd 100644 --- a/app/plug-in/plug-in-proc-def.c +++ b/app/plug-in/plug-in-proc-def.c @@ -100,6 +100,8 @@ plug_in_proc_def_free (PlugInProcDef *proc_def) g_slist_foreach (proc_def->magics_list, (GFunc) g_free, NULL); g_slist_free (proc_def->magics_list); + g_free (proc_def->thumb_loader); + g_free (proc_def); } diff --git a/app/plug-in/plug-in-proc-def.h b/app/plug-in/plug-in-proc-def.h index 65bfdd1173..1511832e84 100644 --- a/app/plug-in/plug-in-proc-def.h +++ b/app/plug-in/plug-in-proc-def.h @@ -51,6 +51,7 @@ struct _PlugInProcDef GSList *extensions_list; GSList *prefixes_list; GSList *magics_list; + gchar *thumb_loader; }; diff --git a/app/plug-in/plug-in-rc.c b/app/plug-in/plug-in-rc.c index 48e5f6360c..95ca48d6ba 100644 --- a/app/plug-in/plug-in-rc.c +++ b/app/plug-in/plug-in-rc.c @@ -57,7 +57,7 @@ static GTokenType plug_in_icon_deserialize (GScanner *scanner, PlugInProcDef *proc_def); static GTokenType plug_in_proc_arg_deserialize (GScanner *scanner, ProcArg *arg); -static GTokenType plug_in_mime_type_deserialize (GScanner *scanner, +static GTokenType plug_in_extra_deserialize (GScanner *scanner, PlugInProcDef *proc_def); static GTokenType plug_in_locale_def_deserialize (GScanner *scanner, PlugInDef *plug_in_def); @@ -78,7 +78,8 @@ enum PROC_ARG, MENU_PATH, ICON, - MIME_TYPE + MIME_TYPE, + THUMB_LOADER }; @@ -125,6 +126,8 @@ plug_in_rc_parse (Gimp *gimp, "icon", GINT_TO_POINTER (ICON)); g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, "mime-type", GINT_TO_POINTER (MIME_TYPE)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "thumb-loader", GINT_TO_POINTER (THUMB_LOADER)); token = G_TOKEN_LEFT_PAREN; @@ -357,13 +360,10 @@ plug_in_proc_def_deserialize (GScanner *scanner, return token; } - if (g_scanner_peek_next_token (scanner) == G_TOKEN_LEFT_PAREN) - { - token = plug_in_mime_type_deserialize (scanner, proc_def); + token = plug_in_extra_deserialize (scanner, proc_def); - if (token != G_TOKEN_LEFT_PAREN) - return token; - } + if (token != G_TOKEN_LEFT_PAREN) + return token; if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) return G_TOKEN_RIGHT_PAREN; @@ -490,29 +490,50 @@ plug_in_icon_deserialize (GScanner *scanner, return G_TOKEN_LEFT_PAREN; } + +/* Handle extra info such as mime-type and thumb-loader. */ static GTokenType -plug_in_mime_type_deserialize (GScanner *scanner, - PlugInProcDef *proc_def) +plug_in_extra_deserialize (GScanner *scanner, + PlugInProcDef *proc_def) { - gchar *mime_type; + GTokenType token; + gchar *value; - if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN)) - return G_TOKEN_LEFT_PAREN; + while (g_scanner_peek_next_token (scanner) == G_TOKEN_LEFT_PAREN) + { + token = token = g_scanner_get_next_token (scanner); - if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL) || - GPOINTER_TO_INT (scanner->value.v_symbol) != MIME_TYPE) - return G_TOKEN_SYMBOL; + if (token != G_TOKEN_LEFT_PAREN) + return token; - if (! gimp_scanner_parse_string (scanner, &mime_type)) - return G_TOKEN_STRING; + if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL)) + return G_TOKEN_SYMBOL; - if (proc_def->mime_type) - g_free (proc_def->mime_type); + switch (GPOINTER_TO_INT (scanner->value.v_symbol)) + { + case MIME_TYPE: + if (! gimp_scanner_parse_string (scanner, &value)) + return G_TOKEN_STRING; - proc_def->mime_type = mime_type; + g_free (proc_def->mime_type); + proc_def->mime_type = value; + break; - if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) - return G_TOKEN_RIGHT_PAREN; + case THUMB_LOADER: + if (! gimp_scanner_parse_string (scanner, &value)) + return G_TOKEN_STRING; + + g_free (proc_def->thumb_loader); + proc_def->thumb_loader = value; + break; + + default: + return G_TOKEN_SYMBOL; + } + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + } return G_TOKEN_LEFT_PAREN; } @@ -752,6 +773,13 @@ plug_in_rc_write (GSList *plug_in_defs, gimp_config_writer_close (writer); } + if (proc_def->thumb_loader) + { + gimp_config_writer_open (writer, "thumb-loader"); + gimp_config_writer_string (writer, proc_def->thumb_loader); + gimp_config_writer_close (writer); + } + gimp_config_writer_close (writer); } diff --git a/app/plug-in/plug-ins.c b/app/plug-in/plug-ins.c index 290d2c68bd..316a908787 100644 --- a/app/plug-in/plug-ins.c +++ b/app/plug-in/plug-ins.c @@ -514,6 +514,39 @@ plug_ins_file_register_mime (Gimp *gimp, return NULL; } +PlugInProcDef * +plug_ins_file_register_thumb_loader (Gimp *gimp, + const gchar *load_proc, + const gchar *thumb_proc) +{ + GSList *list; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + g_return_val_if_fail (load_proc, NULL); + g_return_val_if_fail (thumb_proc, NULL); + + if (gimp->current_plug_in && gimp->current_plug_in->plug_in_def) + list = gimp->current_plug_in->plug_in_def->proc_defs; + else + list = gimp->plug_in_proc_defs; + + for (; list; list = list->next) + { + PlugInProcDef *proc_def = list->data; + + if (strcmp (proc_def->db_info.name, load_proc) == 0) + { + if (proc_def->thumb_loader) + g_free (proc_def->thumb_loader); + proc_def->thumb_loader = g_strdup (thumb_proc); + + return proc_def; + } + } + + return NULL; +} + void plug_ins_def_add_from_rc (Gimp *gimp, PlugInDef *plug_in_def) diff --git a/app/plug-in/plug-ins.h b/app/plug-in/plug-ins.h index e74fcb2f83..f82ec9b541 100644 --- a/app/plug-in/plug-ins.h +++ b/app/plug-in/plug-ins.h @@ -45,6 +45,12 @@ PlugInProcDef * plug_ins_file_register_mime (Gimp *gimp, const gchar *name, const gchar *mime_type); +PlugInProcDef * plug_ins_file_register_thumb_loader + (Gimp *gimp, + const gchar *load_proc, + const gchar *thumb_proc); + + /* Add a plug-in definition. */ void plug_ins_def_add_from_rc (Gimp *gimp, PlugInDef *plug_in_def); diff --git a/devel-docs/libgimp/libgimp-sections.txt b/devel-docs/libgimp/libgimp-sections.txt index dfea683784..3b46cece54 100644 --- a/devel-docs/libgimp/libgimp-sections.txt +++ b/devel-docs/libgimp/libgimp-sections.txt @@ -367,6 +367,7 @@ gimp_register_magic_load_handler gimp_register_load_handler gimp_register_save_handler gimp_register_file_handler_mime +gimp_register_thumbnail_loader
diff --git a/devel-docs/libgimp/tmpl/gimpfileops.sgml b/devel-docs/libgimp/tmpl/gimpfileops.sgml index 113339f6b8..1e2ab0f20a 100644 --- a/devel-docs/libgimp/tmpl/gimpfileops.sgml +++ b/devel-docs/libgimp/tmpl/gimpfileops.sgml @@ -92,3 +92,13 @@ File operations (load, save, etc.) @Returns: + + + + + +@load_proc: +@thumb_proc: +@Returns: + + diff --git a/libgimp/gimp.def b/libgimp/gimp.def index a67e95dd4a..808b7dae89 100644 --- a/libgimp/gimp.def +++ b/libgimp/gimp.def @@ -479,6 +479,7 @@ EXPORTS gimp_register_load_handler gimp_register_magic_load_handler gimp_register_save_handler + gimp_register_thumbnail_loader gimp_repeat_mode_get_type gimp_rgn_iterate1 gimp_rgn_iterate2 diff --git a/libgimp/gimpfileops_pdb.c b/libgimp/gimpfileops_pdb.c index 8ab61f8848..bf3b1e99e2 100644 --- a/libgimp/gimpfileops_pdb.c +++ b/libgimp/gimpfileops_pdb.c @@ -290,3 +290,42 @@ gimp_register_file_handler_mime (const gchar *procedure_name, return success; } + +/** + * gimp_register_thumbnail_loader: + * @load_proc: The name of the procedure the thumbnail loader with. + * @thumb_proc: The name of the thumbnail load procedure. + * + * Associates a thumbnail loader with a file load procedure. + * + * Some file formats allow for embedded thumbnails, other file formats + * contain a scalable image or provide the image data in different + * resolutions. A file plug-in for such a format may register a special + * procedure that allows GIMP to load a thumbnail preview of the image. + * This procedure is then associated with the standard load procedure + * using this function. + * + * Returns: TRUE on success. + * + * Since: GIMP 2.2 + */ +gboolean +gimp_register_thumbnail_loader (const gchar *load_proc, + const gchar *thumb_proc) +{ + GimpParam *return_vals; + gint nreturn_vals; + gboolean success = TRUE; + + return_vals = gimp_run_procedure ("gimp_register_thumbnail_loader", + &nreturn_vals, + GIMP_PDB_STRING, load_proc, + GIMP_PDB_STRING, thumb_proc, + GIMP_PDB_END); + + success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS; + + gimp_destroy_params (return_vals, nreturn_vals); + + return success; +} diff --git a/libgimp/gimpfileops_pdb.h b/libgimp/gimpfileops_pdb.h index 96f66883c6..5e52dfad55 100644 --- a/libgimp/gimpfileops_pdb.h +++ b/libgimp/gimpfileops_pdb.h @@ -50,6 +50,8 @@ gboolean gimp_register_save_handler (const gchar *procedure_name, const gchar *prefixes); gboolean gimp_register_file_handler_mime (const gchar *procedure_name, const gchar *mime_type); +gboolean gimp_register_thumbnail_loader (const gchar *load_proc, + const gchar *thumb_proc); G_END_DECLS diff --git a/plug-ins/common/svg.c b/plug-ins/common/svg.c index 1ca8c9edb6..7e9d4df786 100644 --- a/plug-ins/common/svg.c +++ b/plug-ins/common/svg.c @@ -69,14 +69,14 @@ static void run (const gchar *name, gint *nreturn_vals, GimpParam **return_vals); -static gint32 load_image (const gchar *filename); -static GdkPixbuf * load_rsvg_pixbuf (const gchar *filename, - SvgLoadVals *vals, - GError **error); -static gboolean load_rsvg_size (const gchar *filename, - SvgLoadVals *vals, - GError **error); -static gboolean load_dialog (const gchar *filename); +static gint32 load_image (const gchar *filename); +static GdkPixbuf * load_rsvg_pixbuf (const gchar *filename, + SvgLoadVals *vals, + GError **error); +static gboolean load_rsvg_size (const gchar *filename, + SvgLoadVals *vals, + GError **error); +static gboolean load_dialog (const gchar *filename); GimpPlugInInfo PLUG_IN_INFO = @@ -115,6 +115,18 @@ query (void) { GIMP_PDB_IMAGE, "image", "Output image" } }; + static GimpParamDef thumb_args[] = + { + { GIMP_PDB_STRING, "filename", "The name of the file to load" }, + { GIMP_PDB_INT32, "thumb_size", "Preferred thumbnail size" } + }; + static GimpParamDef thumb_return_vals[] = + { + { GIMP_PDB_IMAGE, "image", "Thumbnail image" }, + { GIMP_PDB_INT32, "image_width", "Width of full-sized image" }, + { GIMP_PDB_INT32, "image_height", "Height of full-sized image" } + }; + gimp_install_procedure ("file_svg_load", "Loads files in the SVG file format", "Renders SVG files to raster graphics using librsvg.", @@ -132,6 +144,21 @@ query (void) gimp_register_magic_load_handler ("file_svg_load", "svg", "", "0,string,", + SVG_VERSION, + N_("Scalable SVG image"), + NULL, + GIMP_PLUGIN, + G_N_ELEMENTS (thumb_args), + G_N_ELEMENTS (thumb_return_vals), + thumb_args, thumb_return_vals); + + gimp_register_thumbnail_loader ("file_svg_load", "file_svg_load_thumb"); } static void @@ -192,14 +219,13 @@ run (const gchar *name, if (status == GIMP_PDB_SUCCESS) { - gint32 image_ID = load_image (param[1].data.d_string); + const gchar *filename = param[1].data.d_string; + gint32 image_ID = load_image (filename); if (image_ID != -1) { if (load_vals.import) - gimp_path_import (image_ID, - param[1].data.d_string, - load_vals.merge, TRUE); + gimp_path_import (image_ID, filename, load_vals.merge, TRUE); *nreturn_vals = 2; values[1].type = GIMP_PDB_IMAGE; @@ -213,6 +239,47 @@ run (const gchar *name, gimp_set_data ("file_svg_load", &load_vals, sizeof (load_vals)); } } + else if (strcmp (name, "file_svg_load_thumb") == 0) + { + if (nparams < 2) + { + status = GIMP_PDB_CALLING_ERROR; + } + else + { + const gchar *filename = param[0].data.d_string; + gint width = 0; + gint height = 0; + gint32 image_ID; + + if (load_rsvg_size (filename, &load_vals, NULL)) + { + width = load_vals.width; + height = load_vals.height; + } + + load_vals.resolution = SVG_DEFAULT_RESOLUTION; + load_vals.width = - param[1].data.d_int32; + load_vals.height = - param[1].data.d_int32; + + image_ID = load_image (filename); + + if (image_ID != -1) + { + *nreturn_vals = 4; + values[1].type = GIMP_PDB_IMAGE; + values[1].data.d_image = image_ID; + values[2].type = GIMP_PDB_INT32; + values[2].data.d_int32 = width; + values[3].type = GIMP_PDB_INT32; + values[3].data.d_int32 = height; + } + else + { + status = GIMP_PDB_EXECUTION_ERROR; + } + } + } else { status = GIMP_PDB_CALLING_ERROR; diff --git a/tools/pdbgen/pdb/fileops.pdb b/tools/pdbgen/pdb/fileops.pdb index 7e0509c725..7633e7fe3a 100644 --- a/tools/pdbgen/pdb/fileops.pdb +++ b/tools/pdbgen/pdb/fileops.pdb @@ -528,6 +528,34 @@ CODE ); } +sub register_thumbnail_loader { + $blurb = 'Associates a thumbnail loader with a file load procedure.'; + + $help = <<'HELP'; +Some file formats allow for embedded thumbnails, other file formats contain a scalable image or provide the image data in different resolutions. A file plug-in for such a format may register a special procedure that allows GIMP to load a thumbnail preview of the image. This procedure is then associated with the standard load procedure using this function. +HELP + + $author = $copyright = 'Sven Neumann'; + $date = '2004'; + $since = '2.2'; + + @inargs = ( + { name => 'load_proc', type => 'string', + desc => "The name of the procedure the thumbnail loader with." }, + { name => 'thumb_proc', type => 'string', + desc => "The name of the thumbnail load procedure." } + ); + %invoke = ( + code => <<'CODE' +{ + success = (plug_ins_file_register_thumb_loader (gimp, + load_proc, + thumb_proc) != NULL); +} +CODE + ); +} + @headers = qw( "libgimpbase/gimpbase.h" "libgimpthumb/gimpthumb.h" "core/gimp.h" "core/gimpimagefile.h" @@ -537,8 +565,9 @@ CODE @procs = qw(file_load file_save file_load_thumbnail file_save_thumbnail temp_name register_magic_load_handler register_load_handler - register_save_handler register_file_handler_mime); -%exports = (app => [@procs], lib => [@procs[0,1,4..8]]); + register_save_handler register_file_handler_mime + register_thumbnail_loader); +%exports = (app => [@procs], lib => [@procs[0,1,4..9]]); $desc = 'File Operations';