Updated with upstream update

This commit is contained in:
2023-10-30 15:55:30 -07:00
parent 098531073c
commit 3bbdd873ef
584 changed files with 91827 additions and 70362 deletions

View File

@ -1195,6 +1195,7 @@ pika_undo_type_get_type (void)
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, "PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE", "group-image-vectors-merge" },
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, "PIKA_UNDO_GROUP_IMAGE_QUICK_MASK", "group-image-quick-mask" },
{ PIKA_UNDO_GROUP_IMAGE_GRID, "PIKA_UNDO_GROUP_IMAGE_GRID", "group-image-grid" },
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, "PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP", "group-image-colormap-remap" },
{ PIKA_UNDO_GROUP_GUIDE, "PIKA_UNDO_GROUP_GUIDE", "group-guide" },
{ PIKA_UNDO_GROUP_SAMPLE_POINT, "PIKA_UNDO_GROUP_SAMPLE_POINT", "group-sample-point" },
{ PIKA_UNDO_GROUP_DRAWABLE, "PIKA_UNDO_GROUP_DRAWABLE", "group-drawable" },
@ -1303,6 +1304,7 @@ pika_undo_type_get_type (void)
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, NC_("undo-type", "Merge paths"), NULL },
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, NC_("undo-type", "Quick Mask"), NULL },
{ PIKA_UNDO_GROUP_IMAGE_GRID, NC_("undo-type", "Grid"), NULL },
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, NC_("undo-type", "Colormap remapping"), NULL },
{ PIKA_UNDO_GROUP_GUIDE, NC_("undo-type", "Guide"), NULL },
{ PIKA_UNDO_GROUP_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
{ PIKA_UNDO_GROUP_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL },

View File

@ -548,6 +548,7 @@ typedef enum /*< pdb-skip >*/
PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, /*< desc="Merge paths" >*/
PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, /*< desc="Quick Mask" >*/
PIKA_UNDO_GROUP_IMAGE_GRID, /*< desc="Grid" >*/
PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, /*< desc="Colormap remapping" >*/
PIKA_UNDO_GROUP_GUIDE, /*< desc="Guide" >*/
PIKA_UNDO_GROUP_SAMPLE_POINT, /*< desc="Sample Point" >*/
PIKA_UNDO_GROUP_DRAWABLE, /*< desc="Layer/Channel" >*/

View File

@ -33,8 +33,10 @@
#include "pikacontainer.h"
#include "pikacontext.h"
#include "pikadisplay.h"
#include "pikadrawable.h"
#include "pikaimage.h"
#include "pikaprogress.h"
#include "pikaresource.h"
#include "pikawaitable.h"
#include "about.h"
@ -325,17 +327,17 @@ pika_get_empty_display (Pika *pika)
return NULL;
}
guint32
GBytes *
pika_get_display_window_id (Pika *pika,
PikaDisplay *display)
{
g_return_val_if_fail (PIKA_IS_PIKA (pika), -1);
g_return_val_if_fail (PIKA_IS_DISPLAY (display), -1);
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
if (pika->gui.display_get_window_id)
return pika->gui.display_get_window_id (display);
return -1;
return NULL;
}
PikaDisplay *
@ -407,10 +409,11 @@ gboolean
pika_pdb_dialog_new (Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaContainer *container,
GType contents_type,
GBytes *parent_handle,
const gchar *title,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
...)
{
gboolean retval = FALSE;
@ -418,7 +421,10 @@ pika_pdb_dialog_new (Pika *pika,
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), FALSE);
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE), FALSE);
g_return_val_if_fail (object == NULL ||
g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
g_return_val_if_fail (title != NULL, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE);
@ -426,12 +432,11 @@ pika_pdb_dialog_new (Pika *pika,
{
va_list args;
va_start (args, object_name);
va_start (args, object);
retval = pika->gui.pdb_dialog_new (pika, context, progress,
container, title,
callback_name, object_name,
args);
contents_type, parent_handle, title,
callback_name, object, args);
va_end (args);
}
@ -440,27 +445,28 @@ pika_pdb_dialog_new (Pika *pika,
}
gboolean
pika_pdb_dialog_set (Pika *pika,
PikaContainer *container,
const gchar *callback_name,
const gchar *object_name,
pika_pdb_dialog_set (Pika *pika,
GType contents_type,
const gchar *callback_name,
PikaObject *object,
...)
{
gboolean retval = FALSE;
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE);
g_return_val_if_fail (object_name != NULL, FALSE);
g_return_val_if_fail (object == NULL || g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
if (pika->gui.pdb_dialog_set)
{
va_list args;
va_start (args, object_name);
va_start (args, object);
retval = pika->gui.pdb_dialog_set (pika, container, callback_name,
object_name, args);
retval = pika->gui.pdb_dialog_set (pika, contents_type, callback_name,
object, args);
va_end (args);
}
@ -470,15 +476,16 @@ pika_pdb_dialog_set (Pika *pika,
gboolean
pika_pdb_dialog_close (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name)
{
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE);
if (pika->gui.pdb_dialog_close)
return pika->gui.pdb_dialog_close (pika, container, callback_name);
return pika->gui.pdb_dialog_close (pika, contents_type, callback_name);
return FALSE;
}

View File

@ -58,7 +58,7 @@ struct _PikaGui
PikaObject * (* get_window_strategy) (Pika *pika);
PikaDisplay * (* get_empty_display) (Pika *pika);
guint32 (* display_get_window_id) (PikaDisplay *display);
GBytes * (* display_get_window_id) (PikaDisplay *display);
PikaDisplay * (* display_create) (Pika *pika,
PikaImage *image,
PikaUnit unit,
@ -77,18 +77,19 @@ struct _PikaGui
gboolean (* pdb_dialog_new) (Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaContainer *container,
GType contents_type,
GBytes *parent_handle,
const gchar *title,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
va_list args);
gboolean (* pdb_dialog_set) (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
va_list args);
gboolean (* pdb_dialog_close) (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name);
gboolean (* recent_list_add_file) (Pika *pika,
GFile *file,
@ -126,7 +127,7 @@ PikaDisplay * pika_get_display_by_id (Pika *pika,
gint ID);
gint pika_get_display_id (Pika *pika,
PikaDisplay *display);
guint32 pika_get_display_window_id (Pika *pika,
GBytes * pika_get_display_window_id (Pika *pika,
PikaDisplay *display);
PikaDisplay * pika_create_display (Pika *pika,
PikaImage *image,
@ -175,19 +176,21 @@ GFile * pika_get_icon_theme_dir (Pika *pika);
gboolean pika_pdb_dialog_new (Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaContainer *container,
GType contents_type,
GBytes *parent_handle,
const gchar *title,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
...) G_GNUC_NULL_TERMINATED;
gboolean pika_pdb_dialog_set (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
...) G_GNUC_NULL_TERMINATED;
gboolean pika_pdb_dialog_close (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name);
gboolean pika_recent_list_add_file (Pika *pika,
GFile *file,
const gchar *mime_type);

View File

@ -202,6 +202,7 @@ pika_container_class_init (PikaContainerClass *klass)
klass->search = NULL;
klass->get_unique_names = NULL;
klass->get_child_by_name = NULL;
klass->get_children_by_name = NULL;
klass->get_child_by_index = NULL;
klass->get_child_index = NULL;
@ -885,6 +886,34 @@ pika_container_get_unique_names (PikaContainer *container)
return FALSE;
}
GList *
pika_container_get_children_by_name (PikaContainer *container,
const gchar *name)
{
g_return_val_if_fail (PIKA_IS_CONTAINER (container), NULL);
if (!name)
return NULL;
if (PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name != NULL &&
! pika_container_get_unique_names (container))
{
return PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name (container,
name);
}
else
{
PikaObject *child;
child = PIKA_CONTAINER_GET_CLASS (container)->get_child_by_name (container, name);
if (child != NULL)
return g_list_prepend (NULL, child);
else
return NULL;
}
}
PikaObject *
pika_container_get_child_by_name (PikaContainer *container,
const gchar *name)

View File

@ -79,6 +79,8 @@ struct _PikaContainerClass
gboolean (* get_unique_names) (PikaContainer *container);
PikaObject * (* get_child_by_name) (PikaContainer *container,
const gchar *name);
GList * (* get_children_by_name) (PikaContainer *container,
const gchar *name);
PikaObject * (* get_child_by_index) (PikaContainer *container,
gint index);
gint (* get_child_index) (PikaContainer *container,
@ -121,6 +123,8 @@ PikaObject * pika_container_search (PikaContainer *contain
gboolean pika_container_get_unique_names (PikaContainer *container);
GList * pika_container_get_children_by_name (PikaContainer *container,
const gchar *name);
PikaObject * pika_container_get_child_by_name (PikaContainer *container,
const gchar *name);
PikaObject * pika_container_get_child_by_index (PikaContainer *container,

View File

@ -34,6 +34,7 @@
#include "pika-memsize.h"
#include "pikadata.h"
#include "pikaidtable.h"
#include "pikaimage.h"
#include "pikatag.h"
#include "pikatagged.h"
@ -51,6 +52,7 @@ enum
PROP_0,
PROP_ID,
PROP_FILE,
PROP_IMAGE,
PROP_WRITABLE,
PROP_DELETABLE,
PROP_MIME_TYPE
@ -59,8 +61,10 @@ enum
struct _PikaDataPrivate
{
gint ID;
GFile *file;
gint ID;
GFile *file;
PikaImage *image;
GQuark mime_type;
guint writable : 1;
guint deletable : 1;
@ -172,6 +176,11 @@ pika_data_class_init (PikaDataClass *klass)
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_IMAGE,
g_param_spec_object ("image", NULL, NULL,
PIKA_TYPE_IMAGE,
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_WRITABLE,
g_param_spec_boolean ("writable", NULL, NULL,
FALSE,
@ -268,6 +277,12 @@ pika_data_set_property (GObject *object,
private->deletable);
break;
case PROP_IMAGE:
pika_data_set_image (data,
g_value_get_object (value),
private->writable,
private->deletable);
break;
case PROP_WRITABLE:
private->writable = g_value_get_boolean (value);
break;
@ -307,6 +322,10 @@ pika_data_get_property (GObject *object,
g_value_set_object (value, private->file);
break;
case PROP_IMAGE:
g_value_set_object (value, private->image);
break;
case PROP_WRITABLE:
g_value_set_boolean (value, private->writable);
break;
@ -462,7 +481,7 @@ pika_data_get_identifier (PikaTagged *tagged)
gchar *identifier = NULL;
gchar *collection = NULL;
g_return_val_if_fail (private->internal || private->file != NULL, NULL);
g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
collection = pika_data_get_collection (data);
/* The identifier is guaranteed to be unique because we use 2 directory
@ -503,7 +522,7 @@ pika_data_get_collection (PikaData *data)
PikaDataPrivate *private = PIKA_DATA_GET_PRIVATE (data);
gchar *collection = NULL;
g_return_val_if_fail (private->internal || private->file != NULL, NULL);
g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
if (private->file)
{
@ -551,6 +570,10 @@ pika_data_get_collection (PikaData *data)
g_free (path);
}
else if (private->image)
{
collection = g_strdup_printf ("[image-id-%d]", pika_image_get_id (private->image));
}
else if (private->internal)
{
collection = g_strdup (private->collection);
@ -603,7 +626,7 @@ pika_data_save (PikaData *data,
g_return_val_if_fail (private->writable == TRUE, FALSE);
if (private->internal)
if (private->internal || private->image != NULL)
{
private->dirty = FALSE;
return TRUE;
@ -862,6 +885,8 @@ pika_data_set_file (PikaData *data,
if (private->internal)
return;
g_return_if_fail (private->image == NULL);
g_set_object (&private->file, file);
private->writable = FALSE;
@ -937,6 +962,53 @@ pika_data_get_file (PikaData *data)
return private->file;
}
/**
* pika_data_set_image:
* @data: A #PikaData object
* @image: Image to assign to @data.
* @writable: %TRUE if we want to be able to write to this file.
* @deletable: %TRUE if we want to be able to delete this file.
*
* This function assigns an image to @data. This can only be done if no file has
* been assigned (a non-internal data can be attached either to a file or to an
* image).
**/
void
pika_data_set_image (PikaData *data,
PikaImage *image,
gboolean writable,
gboolean deletable)
{
PikaDataPrivate *private;
g_return_if_fail (PIKA_IS_DATA (data));
g_return_if_fail (PIKA_IS_IMAGE (image));
private = PIKA_DATA_GET_PRIVATE (data);
if (private->internal)
return;
g_return_if_fail (private->file == NULL);
g_set_object (&private->image, image);
private->writable = writable ? TRUE : FALSE;
private->deletable = deletable ? TRUE : FALSE;
}
PikaImage *
pika_data_get_image (PikaData *data)
{
PikaDataPrivate *private;
g_return_val_if_fail (PIKA_IS_DATA (data), NULL);
private = PIKA_DATA_GET_PRIVATE (data);
return private->image;
}
/**
* pika_data_create_filename:
* @data: a #Pikadata object.

View File

@ -102,6 +102,11 @@ void pika_data_set_file (PikaData *data,
gboolean writable,
gboolean deletable);
GFile * pika_data_get_file (PikaData *data);
void pika_data_set_image (PikaData *data,
PikaImage *image,
gboolean writable,
gboolean deletable);
PikaImage * pika_data_get_image (PikaData *data);
void pika_data_create_filename (PikaData *data,
GFile *dest_dir);

View File

@ -403,6 +403,9 @@ pika_data_factory_real_data_save (PikaDataFactory *factory)
PikaData *data = list->data;
GError *error = NULL;
if (pika_data_get_image (data))
continue;
if (! pika_data_get_file (data))
pika_data_create_filename (data, writable_dir);
@ -460,6 +463,7 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
gint copy_len;
gint number;
gchar *new_name;
GError *error = NULL;
ext = strrchr (name, '#');
copy_len = strlen (_("copy"));
@ -479,8 +483,12 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
pika_object_take_name (PIKA_OBJECT (new_data), new_name);
if (! pika_data_factory_data_save_single (factory, new_data, &error))
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
pika_container_add (priv->container, PIKA_OBJECT (new_data));
g_object_unref (new_data);
g_clear_error (&error);
}
return new_data;
@ -674,8 +682,14 @@ pika_data_factory_data_new (PikaDataFactory *factory,
if (data)
{
GError *error = NULL;
if (! pika_data_factory_data_save_single (factory, data, &error))
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
pika_container_add (priv->container, PIKA_OBJECT (data));
g_object_unref (data);
g_clear_error (&error);
return data;
}
@ -750,7 +764,7 @@ pika_data_factory_data_save_single (PikaDataFactory *factory,
g_return_val_if_fail (PIKA_IS_DATA (data), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (! pika_data_is_dirty (data))
if (! pika_data_is_dirty (data) || pika_data_get_image (data))
return TRUE;
if (! pika_data_get_file (data))

View File

@ -31,25 +31,43 @@
#include "core-types.h"
#include "config/pikageglconfig.h"
#include "gegl/pika-babl.h"
#include "gegl/pika-gegl-loops.h"
#include "pika.h"
#include "pikacontainer.h"
#include "pikadatafactory.h"
#include "pikadrawable.h"
#include "pikaimage.h"
#include "pikaimage-colormap.h"
#include "pikaimage-private.h"
#include "pikaimage-undo.h"
#include "pikaimage-undo-push.h"
#include "pikapalette.h"
#include "pika-intl.h"
typedef struct
{
GeglBuffer *buffer;
const Babl *format;
/* Shared by jobs. */
gboolean *found;
GRWLock *lock;
} IndexUsedJobData;
/* local function prototype */
static void pika_image_colormap_set_palette_entry (PikaImage *image,
const PikaRGB *color,
gint index);
static void pika_image_colormap_set_palette_entry (PikaImage *image,
const PikaRGB *color,
gint index);
static void pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
gint index);
/* public functions */
@ -80,7 +98,7 @@ pika_image_colormap_init (PikaImage *image)
pika_palette_set_columns (private->palette, 16);
pika_data_make_internal (PIKA_DATA (private->palette), palette_id);
pika_data_set_image (PIKA_DATA (private->palette), image, TRUE, FALSE);
palettes = pika_data_factory_get_container (image->pika->palette_factory);
@ -319,9 +337,8 @@ pika_image_set_colormap (PikaImage *image,
pika_image_colormap_set_palette_entry (image, &color, i);
}
pika_data_thaw (PIKA_DATA (private->palette));
pika_image_colormap_changed (image, -1);
pika_data_thaw (PIKA_DATA (private->palette));
}
void
@ -347,6 +364,45 @@ pika_image_unset_colormap (PikaImage *image,
pika_image_colormap_changed (image, -1);
}
gboolean
pika_image_colormap_is_index_used (PikaImage *image,
gint color_index)
{
GList *layers;
GList *iter;
GThreadPool *pool;
GRWLock lock;
gboolean found = FALSE;
gint num_processors;
g_rw_lock_init (&lock);
num_processors = PIKA_GEGL_CONFIG (image->pika->config)->num_processors;
layers = pika_image_get_layer_list (image);
pool = g_thread_pool_new_full ((GFunc) pika_image_colormap_thread_is_index_used,
GINT_TO_POINTER (color_index),
(GDestroyNotify) g_free,
num_processors, TRUE, NULL);
for (iter = layers; iter; iter = g_list_next (iter))
{
IndexUsedJobData *job_data;
job_data = g_malloc (sizeof (IndexUsedJobData ));
job_data->buffer = pika_drawable_get_buffer (iter->data);
job_data->format = pika_drawable_get_format_without_alpha (iter->data);
job_data->found = &found;
job_data->lock = &lock;
g_thread_pool_push (pool, job_data, NULL);
}
g_thread_pool_free (pool, FALSE, TRUE);
g_rw_lock_clear (&lock);
g_list_free (layers);
return found;
}
void
pika_image_get_colormap_entry (PikaImage *image,
gint color_index,
@ -420,6 +476,57 @@ pika_image_add_colormap_entry (PikaImage *image,
pika_image_colormap_changed (image, -1);
}
gboolean
pika_image_delete_colormap_entry (PikaImage *image,
gint color_index,
gboolean push_undo)
{
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
if (! pika_image_colormap_is_index_used (image, color_index))
{
PikaImagePrivate *private;
PikaPaletteEntry *entry;
GList *layers;
GList *iter;
if (push_undo)
{
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP,
C_("undo-type", "Delete Colormap entry"));
pika_image_undo_push_image_colormap (image, NULL);
}
private = PIKA_IMAGE_GET_PRIVATE (image);
layers = pika_image_get_layer_list (image);
for (iter = layers; iter; iter = g_list_next (iter))
{
if (push_undo)
pika_image_undo_push_drawable_mod (image, NULL, iter->data, TRUE);
pika_gegl_shift_index (pika_drawable_get_buffer (iter->data), NULL,
pika_drawable_get_format (iter->data),
color_index, -1);
}
entry = pika_palette_get_entry (private->palette, color_index);
pika_palette_delete_entry (private->palette, entry);
g_list_free (layers);
if (push_undo)
pika_image_undo_group_end (image);
pika_image_colormap_changed (image, -1);
return TRUE;
}
return FALSE;
}
/* private functions */
@ -442,3 +549,22 @@ pika_image_colormap_set_palette_entry (PikaImage *image,
pika_palette_set_entry (private->palette, index, name, color);
}
static void
pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
gint index)
{
g_rw_lock_reader_lock (data->lock);
if (*data->found)
{
g_rw_lock_reader_unlock (data->lock);
return;
}
g_rw_lock_reader_unlock (data->lock);
if (pika_gegl_is_index_used (data->buffer, NULL, data->format, index))
{
g_rw_lock_writer_lock (data->lock);
*data->found = TRUE;
g_rw_lock_writer_unlock (data->lock);
}
}

View File

@ -49,6 +49,9 @@ void pika_image_set_colormap (PikaImage *image,
void pika_image_unset_colormap (PikaImage *image,
gboolean push_undo);
gboolean pika_image_colormap_is_index_used (PikaImage *image,
gint color_index);
void pika_image_get_colormap_entry (PikaImage *image,
gint color_index,
PikaRGB *color);
@ -59,6 +62,9 @@ void pika_image_set_colormap_entry (PikaImage *image,
void pika_image_add_colormap_entry (PikaImage *image,
const PikaRGB *color);
gboolean pika_image_delete_colormap_entry (PikaImage *image,
gint color_index,
gboolean push_undo);
#endif /* __PIKA_IMAGE_COLORMAP_H__ */

View File

@ -24,17 +24,22 @@
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <gexiv2/gexiv2.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "core-types.h"
#include "pika.h"
#include "pikaimage.h"
#include "pikaimage-color-profile.h"
#include "pikaimage-metadata.h"
#include "pikaimage-private.h"
#include "pikaimage-rotate.h"
#include "pikaimage-undo.h"
#include "pikaimage-undo-push.h"
#include "pikalayer-new.h"
/* public functions */
@ -186,3 +191,110 @@ pika_image_metadata_update_colorspace (PikaImage *image)
pika_metadata_set_colorspace (metadata, space);
}
}
/**
* pika_image_metadata_load_thumbnail:
* @pika: The #Pika object.
* @file: A #GFile image.
* @full_image_width: the width of the full image (not the thumbnail).
* @full_image_height: the height of the full image (not the thumbnail).
* @error: Return location for error message
*
* Retrieves a thumbnail from metadata in @file if present.
* It does not need to actually load the full image, only the metadata through
* GExiv2, which makes it fast.
*
* Returns: (transfer none) (nullable): a #PikaImage of the @file thumbnail.
*/
PikaImage *
pika_image_metadata_load_thumbnail (Pika *pika,
GFile *file,
gint *full_image_width,
gint *full_image_height,
const Babl **format,
GError **error)
{
PikaMetadata *metadata;
GInputStream *input_stream;
GdkPixbuf *pixbuf;
guint8 *thumbnail_buffer;
gint thumbnail_size;
PikaImage *image = NULL;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
metadata = pika_metadata_load_from_file (file, error);
if (! metadata)
return NULL;
if (! gexiv2_metadata_get_exif_thumbnail (GEXIV2_METADATA (metadata),
&thumbnail_buffer,
&thumbnail_size))
{
g_object_unref (metadata);
return NULL;
}
input_stream = g_memory_input_stream_new_from_data (thumbnail_buffer,
thumbnail_size,
(GDestroyNotify) g_free);
pixbuf = gdk_pixbuf_new_from_stream (input_stream, NULL, error);
g_object_unref (input_stream);
if (pixbuf)
{
PikaLayer *layer;
image = pika_image_new (pika,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
PIKA_RGB, PIKA_PRECISION_U8_NON_LINEAR);
pika_image_undo_disable (image);
/* XXX This is possibly wrong, because an image of a given color space may
* have a thumbnail stored in a different colorspace. This is even more
* true with PIKA which always exports RGB thumbnails (see code in
* pika_image_metadata_save_filter()), even for say grayscale images.
* Nevertheless other software may store thumbnail using the same
* colorspace.
*/
*format = pika_pixbuf_get_format (pixbuf);
layer = pika_layer_new_from_pixbuf (pixbuf, image,
pika_image_get_layer_format (image, FALSE),
/* No need to localize; this image is short-lived. */
"Background",
PIKA_OPACITY_OPAQUE,
pika_image_get_default_new_layer_mode (image));
g_object_unref (pixbuf);
pika_image_add_layer (image, layer, NULL, 0, FALSE);
pika_image_apply_metadata_orientation (image, pika_get_user_context (pika), metadata, NULL);
}
/* This is the unoriented dimensions. Should we switch when there is a 90 or
* 270 degree rotation? We don't actually know if the metadata orientation is
* correct.
*/
*full_image_width = gexiv2_metadata_get_pixel_width (GEXIV2_METADATA (metadata));
*full_image_height = gexiv2_metadata_get_pixel_height (GEXIV2_METADATA (metadata));
if (*full_image_width < 1 || *full_image_height < 1)
{
/* Dimensions stored in metadata might be less accurate, yet it's still
* informational.
*/
*full_image_width = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
*full_image_height = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
}
if (*full_image_width < 1 || *full_image_height < 1)
{
*full_image_width = 0;
*full_image_height = 0;
}
g_object_unref (metadata);
return image;
}

View File

@ -33,5 +33,12 @@ void pika_image_metadata_update_bits_per_sample (PikaImage *image);
void pika_image_metadata_update_resolution (PikaImage *image);
void pika_image_metadata_update_colorspace (PikaImage *image);
PikaImage * pika_image_metadata_load_thumbnail (Pika *pika,
GFile *file,
gint *full_image_width,
gint *full_image_height,
const Babl **format,
GError **error);
#endif /* __PIKA_IMAGE_METADATA_H__ */

View File

@ -282,6 +282,17 @@ pika_image_import_rotation_metadata (PikaImage *image,
}
}
void
pika_image_apply_metadata_orientation (PikaImage *image,
PikaContext *context,
PikaMetadata *metadata,
PikaProgress *progress)
{
pika_image_metadata_rotate (image, context,
gexiv2_metadata_try_get_orientation (GEXIV2_METADATA (metadata), NULL),
progress);
}
/* Private Functions */

View File

@ -23,14 +23,20 @@
#define __PIKA_IMAGE_ROTATE_H__
void pika_image_rotate (PikaImage *image,
PikaContext *context,
PikaRotationType rotate_type,
PikaProgress *progress);
void pika_image_rotate (PikaImage *image,
PikaContext *context,
PikaRotationType rotate_type,
PikaProgress *progress);
void pika_image_import_rotation_metadata (PikaImage *image,
PikaContext *context,
PikaProgress *progress,
gboolean interactive);
void pika_image_apply_metadata_orientation (PikaImage *image,
PikaContext *context,
PikaMetadata *metadata,
PikaProgress *progress);
void pika_image_import_rotation_metadata (PikaImage *image,
PikaContext *context,
PikaProgress *progress,
gboolean interactive);
#endif /* __PIKA_IMAGE_ROTATE_H__ */

View File

@ -625,6 +625,9 @@ pika_image_undo_dirty_from_type (PikaUndoType undo_type)
case PIKA_UNDO_GROUP_IMAGE_CONVERT:
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
case PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP:
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
case PIKA_UNDO_GROUP_IMAGE_LAYERS_MERGE:
return PIKA_DIRTY_IMAGE_STRUCTURE | PIKA_DIRTY_DRAWABLE;

View File

@ -45,6 +45,7 @@
#include "pikacontainer.h"
#include "pikacontext.h"
#include "pikaimage.h"
#include "pikaimage-metadata.h"
#include "pikaimagefile.h"
#include "pikapickable.h"
#include "pikaprogress.h"
@ -486,19 +487,37 @@ pika_imagefile_create_thumbnail (PikaImagefile *imagefile,
if (error && *error)
{
g_printerr ("Info: Thumbnail load procedure failed: %s\n"
" Falling back to file load procedure.\n",
" Falling back to metadata or file load.\n",
(*error)->message);
g_clear_error (error);
}
image = file_open_image (private->pika, context, progress,
private->file,
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
&status, &mime_type, error);
image = pika_image_metadata_load_thumbnail (private->pika, private->file, &width, &height, &format, error);
if (image)
pika_thumbnail_set_info_from_image (private->thumbnail,
mime_type, image);
{
pika_thumbnail_set_info (private->thumbnail,
mime_type, width, height,
format, 0);
}
else
{
if (error && *error)
{
g_printerr ("Info: metadata load failed: %s\n"
" Falling back to file load procedure.\n",
(*error)->message);
g_clear_error (error);
}
image = file_open_image (private->pika, context, progress,
private->file,
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
&status, &mime_type, error);
if (image)
pika_thumbnail_set_info_from_image (private->thumbnail,
mime_type, image);
}
}
if (image)

View File

@ -76,6 +76,8 @@ static PikaObject * pika_list_search (PikaContainer *conta
PikaContainerSearchFunc func,
gpointer user_data);
static gboolean pika_list_get_unique_names (PikaContainer *container);
static GList * pika_list_get_children_by_name (PikaContainer *container,
const gchar *name);
static PikaObject * pika_list_get_child_by_name (PikaContainer *container,
const gchar *name);
static PikaObject * pika_list_get_child_by_index (PikaContainer *container,
@ -101,23 +103,24 @@ pika_list_class_init (PikaListClass *klass)
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
PikaContainerClass *container_class = PIKA_CONTAINER_CLASS (klass);
object_class->finalize = pika_list_finalize;
object_class->set_property = pika_list_set_property;
object_class->get_property = pika_list_get_property;
object_class->finalize = pika_list_finalize;
object_class->set_property = pika_list_set_property;
object_class->get_property = pika_list_get_property;
pika_object_class->get_memsize = pika_list_get_memsize;
pika_object_class->get_memsize = pika_list_get_memsize;
container_class->add = pika_list_add;
container_class->remove = pika_list_remove;
container_class->reorder = pika_list_reorder;
container_class->clear = pika_list_clear;
container_class->have = pika_list_have;
container_class->foreach = pika_list_foreach;
container_class->search = pika_list_search;
container_class->get_unique_names = pika_list_get_unique_names;
container_class->get_child_by_name = pika_list_get_child_by_name;
container_class->get_child_by_index = pika_list_get_child_by_index;
container_class->get_child_index = pika_list_get_child_index;
container_class->add = pika_list_add;
container_class->remove = pika_list_remove;
container_class->reorder = pika_list_reorder;
container_class->clear = pika_list_clear;
container_class->have = pika_list_have;
container_class->foreach = pika_list_foreach;
container_class->search = pika_list_search;
container_class->get_unique_names = pika_list_get_unique_names;
container_class->get_children_by_name = pika_list_get_children_by_name;
container_class->get_child_by_name = pika_list_get_child_by_name;
container_class->get_child_by_index = pika_list_get_child_by_index;
container_class->get_child_index = pika_list_get_child_index;
g_object_class_install_property (object_class, PROP_UNIQUE_NAMES,
g_param_spec_boolean ("unique-names",
@ -369,6 +372,29 @@ pika_list_get_unique_names (PikaContainer *container)
return list->unique_names;
}
static GList *
pika_list_get_children_by_name (PikaContainer *container,
const gchar *name)
{
PikaList *list = PIKA_LIST (container);
GList *children = NULL;
GList *iter;
for (iter = list->queue->head; iter; iter = g_list_next (iter))
{
PikaObject *object = iter->data;
if (! strcmp (pika_object_get_name (object), name))
{
children = g_list_prepend (children, object);
if (list->unique_names)
return children;
}
}
return children;
}
static PikaObject *
pika_list_get_child_by_name (PikaContainer *container,
const gchar *name)

View File

@ -33,6 +33,8 @@
#include "core-types.h"
#include "pika-memsize.h"
#include "pikaimage.h"
#include "pikaimage-undo-push.h"
#include "pikapalette.h"
#include "pikapalette-load.h"
#include "pikapalette-save.h"
@ -44,6 +46,12 @@
#define RGB_EPSILON 1e-6
enum
{
ENTRY_CHANGED,
LAST_SIGNAL
};
/* local function prototypes */
@ -75,6 +83,8 @@ static gchar * pika_palette_get_description (PikaViewable *viewa
static const gchar * pika_palette_get_extension (PikaData *data);
static void pika_palette_copy (PikaData *data,
PikaData *src_data);
static void pika_palette_real_entry_changed (PikaPalette *palette,
gint index);
static void pika_palette_entry_free (PikaPaletteEntry *entry);
static gint64 pika_palette_entry_get_memsize (PikaPaletteEntry *entry,
@ -88,6 +98,7 @@ G_DEFINE_TYPE_WITH_CODE (PikaPalette, pika_palette, PIKA_TYPE_DATA,
#define parent_class pika_palette_parent_class
static guint signals[LAST_SIGNAL] = { 0 };
static void
pika_palette_class_init (PikaPaletteClass *klass)
@ -97,6 +108,14 @@ pika_palette_class_init (PikaPaletteClass *klass)
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
PikaDataClass *data_class = PIKA_DATA_CLASS (klass);
signals[ENTRY_CHANGED] = g_signal_new ("entry-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaPaletteClass, entry_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_INT);
object_class->finalize = pika_palette_finalize;
pika_object_class->get_memsize = pika_palette_get_memsize;
@ -110,6 +129,8 @@ pika_palette_class_init (PikaPaletteClass *klass)
data_class->save = pika_palette_save;
data_class->get_extension = pika_palette_get_extension;
data_class->copy = pika_palette_copy;
klass->entry_changed = pika_palette_real_entry_changed;
}
static void
@ -344,6 +365,16 @@ pika_palette_copy (PikaData *data,
pika_data_thaw (data);
}
static void
pika_palette_real_entry_changed (PikaPalette *palette,
gint index)
{
PikaImage *image = pika_data_get_image (PIKA_DATA (palette));
if (image != NULL)
pika_image_colormap_changed (image, index);
}
static gchar *
pika_palette_get_checksum (PikaTagged *tagged)
{
@ -406,11 +437,17 @@ pika_palette_move_entry (PikaPalette *palette,
if (g_list_find (palette->colors, entry))
{
gint old_position = g_list_index (palette->colors, entry);
palette->colors = g_list_remove (palette->colors,
entry);
palette->colors = g_list_insert (palette->colors,
entry, position);
if (! pika_data_is_frozen (PIKA_DATA (palette)))
for (gint i = MIN (position, old_position); i <= MAX (position, old_position); i++)
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
pika_data_dirty (PIKA_DATA (palette));
}
}
@ -442,6 +479,10 @@ pika_palette_add_entry (PikaPalette *palette,
palette->n_colors += 1;
if (! pika_data_is_frozen (PIKA_DATA (palette)))
for (gint i = position; i < palette->n_colors; i++)
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
pika_data_dirty (PIKA_DATA (palette));
return entry;
@ -456,12 +497,18 @@ pika_palette_delete_entry (PikaPalette *palette,
if (g_list_find (palette->colors, entry))
{
gint old_position = g_list_index (palette->colors, entry);
pika_palette_entry_free (entry);
palette->colors = g_list_remove (palette->colors, entry);
palette->n_colors--;
if (! pika_data_is_frozen (PIKA_DATA (palette)))
for (gint i = old_position; i < palette->n_colors; i++)
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
pika_data_dirty (PIKA_DATA (palette));
}
}
@ -489,6 +536,9 @@ pika_palette_set_entry (PikaPalette *palette,
entry->name = g_strdup (name);
if (! pika_data_is_frozen (PIKA_DATA (palette)))
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
pika_data_dirty (PIKA_DATA (palette));
return TRUE;
@ -497,7 +547,8 @@ pika_palette_set_entry (PikaPalette *palette,
gboolean
pika_palette_set_entry_color (PikaPalette *palette,
gint position,
const PikaRGB *color)
const PikaRGB *color,
gboolean push_undo_if_image)
{
PikaPaletteEntry *entry;
@ -509,8 +560,15 @@ pika_palette_set_entry_color (PikaPalette *palette,
if (! entry)
return FALSE;
if (push_undo_if_image && pika_data_get_image (PIKA_DATA (palette)))
pika_image_undo_push_image_colormap (pika_data_get_image (PIKA_DATA (palette)),
C_("undo-type", "Change Colormap entry"));
entry->color = *color;
if (! pika_data_is_frozen (PIKA_DATA (palette)))
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
pika_data_dirty (PIKA_DATA (palette));
return TRUE;
@ -535,6 +593,9 @@ pika_palette_set_entry_name (PikaPalette *palette,
entry->name = g_strdup (name);
if (! pika_data_is_frozen (PIKA_DATA (palette)))
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
pika_data_dirty (PIKA_DATA (palette));
return TRUE;

View File

@ -56,6 +56,9 @@ struct _PikaPalette
struct _PikaPaletteClass
{
PikaDataClass parent_class;
void (* entry_changed) (PikaPalette *palette,
gint index);
};
@ -85,7 +88,8 @@ gboolean pika_palette_set_entry (PikaPalette *palette,
const PikaRGB *color);
gboolean pika_palette_set_entry_color (PikaPalette *palette,
gint position,
const PikaRGB *color);
const PikaRGB *color,
gboolean push_undo_if_image);
gboolean pika_palette_set_entry_name (PikaPalette *palette,
gint position,
const gchar *name);

View File

@ -217,7 +217,7 @@ pika_palette_mru_add (PikaPaletteMru *mru,
/* Even though they are nearly the same color, let's make them
* exactly equal.
*/
pika_palette_set_entry_color (palette, 0, color);
pika_palette_set_entry_color (palette, 0, color, FALSE);
return;
}

View File

@ -78,7 +78,7 @@ static void pika_pdb_progress_progress_set_value (PikaProgress *progress
gdouble percentage);
static gdouble pika_pdb_progress_progress_get_value (PikaProgress *progress);
static void pika_pdb_progress_progress_pulse (PikaProgress *progress);
static guint32 pika_pdb_progress_progress_get_window_id (PikaProgress *progress);
static GBytes * pika_pdb_progress_progress_get_window_id (PikaProgress *progress);
static GObjectClass *parent_class = NULL;
@ -241,14 +241,13 @@ pika_pdb_progress_set_property (GObject *object,
}
}
static gdouble
pika_pdb_progress_run_callback (PikaPdbProgress *progress,
PikaProgressCommand command,
const gchar *text,
gdouble value)
static void
pika_pdb_progress_run_callback (PikaPdbProgress *progress,
PikaProgressCommand command,
const gchar *text,
gdouble value,
GBytes **handle)
{
gdouble retval = 0;
if (progress->callback_name && ! progress->callback_busy)
{
PikaValueArray *return_vals;
@ -274,17 +273,16 @@ pika_pdb_progress_run_callback (PikaPdbProgress *progress,
g_type_name (G_TYPE_FROM_INSTANCE (progress)));
}
else if (pika_value_array_length (return_vals) >= 2 &&
G_VALUE_HOLDS_DOUBLE (pika_value_array_index (return_vals, 1)))
handle != NULL &&
G_VALUE_HOLDS_BOXED (pika_value_array_index (return_vals, 1)))
{
retval = g_value_get_double (pika_value_array_index (return_vals, 1));
*handle = g_value_dup_boxed (pika_value_array_index (return_vals, 1));
}
pika_value_array_unref (return_vals);
progress->callback_busy = FALSE;
}
return retval;
}
static PikaProgress *
@ -298,7 +296,7 @@ pika_pdb_progress_progress_start (PikaProgress *progress,
{
pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_START,
message, 0.0);
message, 0.0, NULL);
pdb_progress->active = TRUE;
pdb_progress->value = 0.0;
@ -318,7 +316,7 @@ pika_pdb_progress_progress_end (PikaProgress *progress)
{
pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_END,
NULL, 0.0);
NULL, 0.0, NULL);
pdb_progress->active = FALSE;
pdb_progress->value = 0.0;
@ -342,7 +340,7 @@ pika_pdb_progress_progress_set_text (PikaProgress *progress,
if (pdb_progress->active)
pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_SET_TEXT,
message, 0.0);
message, 0.0, NULL);
}
static void
@ -355,7 +353,7 @@ pika_pdb_progress_progress_set_value (PikaProgress *progress,
{
pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_SET_VALUE,
NULL, percentage);
NULL, percentage, NULL);
pdb_progress->value = percentage;
}
}
@ -377,18 +375,19 @@ pika_pdb_progress_progress_pulse (PikaProgress *progress)
if (pdb_progress->active)
pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_PULSE,
NULL, 0.0);
NULL, 0.0, NULL);
}
static guint32
static GBytes *
pika_pdb_progress_progress_get_window_id (PikaProgress *progress)
{
PikaPdbProgress *pdb_progress = PIKA_PDB_PROGRESS (progress);
GBytes *handle = NULL;
return (guint32)
pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_GET_WINDOW,
NULL, 0.0);
pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_GET_WINDOW,
NULL, 0.0, &handle);
return handle;
}
PikaPdbProgress *

View File

@ -209,7 +209,7 @@ pika_progress_pulse (PikaProgress *progress)
progress_iface->pulse (progress);
}
guint32
GBytes *
pika_progress_get_window_id (PikaProgress *progress)
{
PikaProgressInterface *progress_iface;
@ -221,7 +221,7 @@ pika_progress_get_window_id (PikaProgress *progress)
if (progress_iface->get_window_id)
return progress_iface->get_window_id (progress);
return 0;
return NULL;
}
gboolean

View File

@ -48,7 +48,7 @@ struct _PikaProgressInterface
gdouble (* get_value) (PikaProgress *progress);
void (* pulse) (PikaProgress *progress);
guint32 (* get_window_id) (PikaProgress *progress);
GBytes * (* get_window_id) (PikaProgress *progress);
gboolean (* message) (PikaProgress *progress,
Pika *pika,
@ -78,7 +78,7 @@ void pika_progress_set_value (PikaProgress *progress,
gdouble pika_progress_get_value (PikaProgress *progress);
void pika_progress_pulse (PikaProgress *progress);
guint32 pika_progress_get_window_id (PikaProgress *progress);
GBytes * pika_progress_get_window_id (PikaProgress *progress);
gboolean pika_progress_message (PikaProgress *progress,
Pika *pika,

View File

@ -59,7 +59,7 @@ static void pika_sub_progress_set_value (PikaProgress *prog
gdouble percentage);
static gdouble pika_sub_progress_get_value (PikaProgress *progress);
static void pika_sub_progress_pulse (PikaProgress *progress);
static guint32 pika_sub_progress_get_window_id (PikaProgress *progress);
static GBytes * pika_sub_progress_get_window_id (PikaProgress *progress);
static gboolean pika_sub_progress_message (PikaProgress *progress,
Pika *pika,
PikaMessageSeverity severity,
@ -228,7 +228,7 @@ pika_sub_progress_pulse (PikaProgress *progress)
pika_progress_pulse (sub->progress);
}
static guint32
static GBytes *
pika_sub_progress_get_window_id (PikaProgress *progress)
{
PikaSubProgress *sub = PIKA_SUB_PROGRESS (progress);
@ -236,7 +236,7 @@ pika_sub_progress_get_window_id (PikaProgress *progress)
if (sub->progress)
return pika_progress_get_window_id (sub->progress);
return 0;
return NULL;
}
static gboolean