libgimp, libgimpbase: new gimp_load_procedure_new2() for run() function using…

… a GimpProcedureConfig for arguments.

This also factorizes the code to load metadata. By default, a GimpLoadProcedure
will try and load metadata from a file (if Exiv2 knows the format). The run()
function will be allowed to edit the GimpMetadata object but also the load flags
before it is actually attached to the image, allowing plug-ins to have custom
metadata handling code when needed.
This commit is contained in:
Jehan 2023-08-05 18:58:57 +02:00
parent 2d33f1fb39
commit af644b1950
6 changed files with 179 additions and 6 deletions

View file

@ -619,6 +619,7 @@ EXPORTS
gimp_load_procedure_get_thumbnail_loader
gimp_load_procedure_get_type
gimp_load_procedure_new
gimp_load_procedure_new2
gimp_load_procedure_set_handles_raw
gimp_load_procedure_set_thumbnail_loader
gimp_main

View file

@ -121,7 +121,6 @@ gimp_image_metadata_load_finish (GimpImage *image,
GimpMetadataLoadFlags flags)
{
g_return_if_fail (GIMP_IS_IMAGE (image));
g_return_if_fail (mime_type != NULL);
g_return_if_fail (GEXIV2_IS_METADATA (metadata));
if (flags & GIMP_METADATA_LOAD_COMMENT)

View file

@ -25,6 +25,8 @@
#include "gimploadprocedure.h"
#include "gimppdb_pdb.h"
#include "libgimp-intl.h"
/**
* GimpLoadProcedure:
@ -53,6 +55,7 @@
struct _GimpLoadProcedurePrivate
{
GimpRunLoadFunc run_func;
GimpRunLoadFunc2 run_func2;
gpointer run_data;
GDestroyNotify run_data_destroy;
@ -193,11 +196,102 @@ gimp_load_procedure_run (GimpProcedure *procedure,
gimp_value_array_append (remaining, value);
}
return_values = load_proc->priv->run_func (procedure,
run_mode,
file,
remaining,
load_proc->priv->run_data);
if (load_proc->priv->run_func2)
{
GimpProcedureConfig *config;
GimpImage *image = NULL;
GimpMetadata *metadata = NULL;
gchar *mimetype = NULL;
GimpMetadataLoadFlags flags = GIMP_METADATA_LOAD_ALL;
GimpPDBStatusType status = GIMP_PDB_EXECUTION_ERROR;
config = gimp_procedure_create_config (procedure);
mimetype = (gchar *) gimp_file_procedure_get_mime_types (GIMP_FILE_PROCEDURE (procedure));
if (mimetype != NULL)
{
char *delim;
mimetype = g_strdup (mimetype);
mimetype = g_strstrip (mimetype);
delim = strstr (mimetype, ",");
if (delim)
*delim = '\0';
/* Though docs only writes about the list being comma-separated, our
* code apparently also split by spaces.
*/
delim = strstr (mimetype, " ");
if (delim)
*delim = '\0';
delim = strstr (mimetype, "\t");
if (delim)
*delim = '\0';
metadata = gimp_metadata_load_from_file (file, NULL);
g_free (mimetype);
}
else
{
flags = GIMP_METADATA_LOAD_NONE;
}
if (metadata == NULL)
metadata = gimp_metadata_new ();
return_values = load_proc->priv->run_func2 (procedure,
run_mode,
file,
metadata, &flags,
config,
load_proc->priv->run_data);
if (return_values != NULL &&
gimp_value_array_length (return_values) > 0 &&
G_VALUE_HOLDS_ENUM (gimp_value_array_index (return_values, 0)))
status = GIMP_VALUES_GET_ENUM (return_values, 0);
gimp_procedure_config_end_run (config, status);
if (status == GIMP_PDB_SUCCESS)
{
if (gimp_value_array_length (return_values) < 2 ||
! GIMP_VALUE_HOLDS_IMAGE (gimp_value_array_index (return_values, 1)))
{
GError *error = NULL;
status = GIMP_PDB_EXECUTION_ERROR;
g_set_error (&error, GIMP_PLUG_IN_ERROR, 0,
_("This file loading plug-in returned SUCCESS as a status without an image. "
"This is a bug in the plug-in code. Contact the plug-in developer."));
gimp_value_array_unref (return_values);
return_values = gimp_procedure_new_return_values (procedure, status, error);
}
else
{
image = GIMP_VALUES_GET_IMAGE (return_values, 1);
}
}
if (image != NULL && metadata != NULL && flags != GIMP_METADATA_LOAD_NONE)
gimp_image_metadata_load_finish (image, NULL, metadata, flags);
/* This is debug printing to help plug-in developers figure out best
* practices.
*/
if (G_OBJECT (config)->ref_count > 1)
g_printerr ("%s: ERROR: the GimpSaveProcedureConfig object was refed "
"by plug-in, it MUST NOT do that!\n", G_STRFUNC);
g_object_unref (config);
}
else
{
return_values = load_proc->priv->run_func (procedure,
run_mode,
file,
remaining,
load_proc->priv->run_data);
}
gimp_value_array_unref (remaining);
@ -275,6 +369,53 @@ gimp_load_procedure_new (GimpPlugIn *plug_in,
return GIMP_PROCEDURE (procedure);
}
/**
* gimp_load_procedure_new2:
* @plug_in: a #GimpPlugIn.
* @name: the new procedure's name.
* @proc_type: the new procedure's #GimpPDBProcType.
* @run_func: the run function for the new procedure.
* @run_data: user data passed to @run_func.
* @run_data_destroy: (nullable): free function for @run_data, or %NULL.
*
* Creates a new load procedure named @name which will call @run_func
* when invoked.
*
* See gimp_procedure_new() for information about @proc_type.
*
* Returns: (transfer full): a new #GimpProcedure.
*
* Since: 3.0
**/
GimpProcedure *
gimp_load_procedure_new2 (GimpPlugIn *plug_in,
const gchar *name,
GimpPDBProcType proc_type,
GimpRunLoadFunc2 run_func,
gpointer run_data,
GDestroyNotify run_data_destroy)
{
GimpLoadProcedure *procedure;
g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL);
g_return_val_if_fail (gimp_is_canonical_identifier (name), NULL);
g_return_val_if_fail (proc_type != GIMP_PDB_PROC_TYPE_INTERNAL, NULL);
g_return_val_if_fail (proc_type != GIMP_PDB_PROC_TYPE_EXTENSION, NULL);
g_return_val_if_fail (run_func != NULL, NULL);
procedure = g_object_new (GIMP_TYPE_LOAD_PROCEDURE,
"plug-in", plug_in,
"name", name,
"procedure-type", proc_type,
NULL);
procedure->priv->run_func2 = run_func;
procedure->priv->run_data = run_data;
procedure->priv->run_data_destroy = run_data_destroy;
return GIMP_PROCEDURE (procedure);
}
/**
* gimp_load_procedure_set_handles_raw:
* @procedure: A load procedure object.

View file

@ -50,6 +50,29 @@ typedef GimpValueArray * (* GimpRunLoadFunc) (GimpProcedure *procedure,
const GimpValueArray *args,
gpointer run_data);
/**
* GimpRunLoadFunc2:
* @procedure: the #GimpProcedure that runs.
* @run_mode: the #GimpRunMode.
* @file: the #GFile to load from.
* @config: the @procedure's remaining arguments.
* @run_data: (closure): the run_data given in gimp_load_procedure_new().
*
* The load function is run during the lifetime of the GIMP session,
* each time a plug-in load procedure is called.
*
* Returns: (transfer full): the @procedure's return values.
*
* Since: 3.0
**/
typedef GimpValueArray * (* GimpRunLoadFunc2) (GimpProcedure *procedure,
GimpRunMode run_mode,
GFile *file,
GimpMetadata *metadata,
GimpMetadataLoadFlags *flags,
GimpProcedureConfig *config,
gpointer run_data);
#define GIMP_TYPE_LOAD_PROCEDURE (gimp_load_procedure_get_type ())
#define GIMP_LOAD_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LOAD_PROCEDURE, GimpLoadProcedure))
@ -84,6 +107,12 @@ GimpProcedure * gimp_load_procedure_new (GimpPlugIn *plu
GimpRunLoadFunc run_func,
gpointer run_data,
GDestroyNotify run_data_destroy);
GimpProcedure * gimp_load_procedure_new2 (GimpPlugIn *plug_in,
const gchar *name,
GimpPDBProcType proc_type,
GimpRunLoadFunc2 run_func,
gpointer run_data,
GDestroyNotify run_data_destroy);
void gimp_load_procedure_set_handles_raw (GimpLoadProcedure *procedure,
gboolean handles_raw);

View file

@ -34,6 +34,7 @@ G_BEGIN_DECLS
/**
* GimpMetadataLoadFlags:
* @GIMP_METADATA_LOAD_NONE: Do not load the metadata
* @GIMP_METADATA_LOAD_COMMENT: Load the comment
* @GIMP_METADATA_LOAD_RESOLUTION: Load the resolution
* @GIMP_METADATA_LOAD_ORIENTATION: Load the orientation (rotation)
@ -44,6 +45,7 @@ G_BEGIN_DECLS
**/
typedef enum
{
GIMP_METADATA_LOAD_NONE = 0,
GIMP_METADATA_LOAD_COMMENT = 1 << 0,
GIMP_METADATA_LOAD_RESOLUTION = 1 << 1,
GIMP_METADATA_LOAD_ORIENTATION = 1 << 2,

View file

@ -6,6 +6,7 @@ libgimp/gimpbrushselectbutton.c
libgimp/gimpexport.c
libgimp/gimpimagemetadata.c
libgimp/gimpimagemetadata-save.c
libgimp/gimploadprocedure.c
libgimp/gimpparamspecs-desc.c
libgimp/gimppatternselectbutton.c
libgimp/gimppdb.c