Update upstream
This commit is contained in:
parent
84ea557696
commit
d472f6348d
|
@ -184,19 +184,31 @@ static const PikaEnumActionEntry edit_paste_actions[] =
|
||||||
PIKA_HELP_EDIT_PASTE_IN_PLACE },
|
PIKA_HELP_EDIT_PASTE_IN_PLACE },
|
||||||
|
|
||||||
{ "edit-paste-into", PIKA_ICON_EDIT_PASTE_INTO,
|
{ "edit-paste-into", PIKA_ICON_EDIT_PASTE_INTO,
|
||||||
NC_("edit-action", "Paste _Into Selection"), NULL, { NULL },
|
NC_("edit-action", "Paste as Floating Data _Into Selection"), NULL, { NULL },
|
||||||
NC_("edit-action",
|
NC_("edit-action",
|
||||||
"Paste the content of the clipboard into the current selection"),
|
"Paste the content of the clipboard into the current selection"),
|
||||||
PIKA_PASTE_TYPE_FLOATING_INTO, FALSE,
|
PIKA_PASTE_TYPE_FLOATING_INTO, FALSE,
|
||||||
PIKA_HELP_EDIT_PASTE_INTO },
|
PIKA_HELP_EDIT_PASTE_INTO },
|
||||||
|
|
||||||
{ "edit-paste-into-in-place", PIKA_ICON_EDIT_PASTE_INTO,
|
{ "edit-paste-into-in-place", PIKA_ICON_EDIT_PASTE_INTO,
|
||||||
NC_("edit-action", "Paste Int_o Selection In Place"), NULL, { NULL },
|
NC_("edit-action", "Paste as Floating Data Int_o Selection In Place"), NULL, { NULL },
|
||||||
NC_("edit-action",
|
NC_("edit-action",
|
||||||
"Paste the content of the clipboard into the current selection "
|
"Paste the content of the clipboard into the current selection "
|
||||||
"at its original position"),
|
"at its original position"),
|
||||||
PIKA_PASTE_TYPE_FLOATING_INTO_IN_PLACE, FALSE,
|
PIKA_PASTE_TYPE_FLOATING_INTO_IN_PLACE, FALSE,
|
||||||
PIKA_HELP_EDIT_PASTE_INTO_IN_PLACE }
|
PIKA_HELP_EDIT_PASTE_INTO_IN_PLACE },
|
||||||
|
|
||||||
|
{ "edit-paste-float", PIKA_ICON_EDIT_PASTE,
|
||||||
|
NC_("edit-action", "Paste as _Floating Data"), NULL, { NULL },
|
||||||
|
NC_("edit-action", "Paste the content of the clipboard as Floating Data"),
|
||||||
|
PIKA_PASTE_TYPE_FLOATING, FALSE,
|
||||||
|
PIKA_HELP_EDIT_PASTE },
|
||||||
|
|
||||||
|
{ "edit-paste-float-in-place", PIKA_ICON_EDIT_PASTE,
|
||||||
|
NC_("edit-action", "Paste as Floa_ting Data In Place"), NULL, { NULL },
|
||||||
|
NC_("edit-action", "Paste the content of the clipboard as Floating Data at its original position"),
|
||||||
|
PIKA_PASTE_TYPE_FLOATING_IN_PLACE, FALSE,
|
||||||
|
PIKA_HELP_EDIT_PASTE }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const PikaEnumActionEntry edit_fill_actions[] =
|
static const PikaEnumActionEntry edit_fill_actions[] =
|
||||||
|
|
|
@ -972,7 +972,7 @@ layers_actions_update (PikaActionGroup *group,
|
||||||
SET_SENSITIVE ("layers-new", image);
|
SET_SENSITIVE ("layers-new", image);
|
||||||
SET_SENSITIVE ("layers-new-last-values", image);
|
SET_SENSITIVE ("layers-new-last-values", image);
|
||||||
SET_SENSITIVE ("layers-new-from-visible", image);
|
SET_SENSITIVE ("layers-new-from-visible", image);
|
||||||
SET_SENSITIVE ("layers-new-group", image && !indexed);
|
SET_SENSITIVE ("layers-new-group", image && !indexed && !fs);
|
||||||
SET_SENSITIVE ("layers-duplicate", n_selected_layers > 0 && !fs && !ac);
|
SET_SENSITIVE ("layers-duplicate", n_selected_layers > 0 && !fs && !ac);
|
||||||
SET_SENSITIVE ("layers-delete", n_selected_layers > 0 && !ac);
|
SET_SENSITIVE ("layers-delete", n_selected_layers > 0 && !ac);
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,16 @@ static const PikaActionEntry select_actions[] =
|
||||||
select_invert_cmd_callback,
|
select_invert_cmd_callback,
|
||||||
PIKA_HELP_SELECTION_INVERT },
|
PIKA_HELP_SELECTION_INVERT },
|
||||||
|
|
||||||
{ "select-float", PIKA_ICON_LAYER_FLOATING_SELECTION,
|
{ "select-cut-float", PIKA_ICON_LAYER_FLOATING_SELECTION,
|
||||||
NC_("select-action", "_Float"), NULL, { "<primary><shift>L", NULL },
|
NC_("select-action", "Cu_t and Float"), NULL, { "<primary><shift>L", NULL },
|
||||||
NC_("select-action", "Create a floating selection"),
|
NC_("select-action", "Cut the selection directly into a floating selection"),
|
||||||
select_float_cmd_callback,
|
select_cut_float_cmd_callback,
|
||||||
|
PIKA_HELP_SELECTION_FLOAT },
|
||||||
|
|
||||||
|
{ "select-copy-float", PIKA_ICON_LAYER_FLOATING_SELECTION,
|
||||||
|
NC_("select-action", "_Copy and Float"), NULL, { NULL },
|
||||||
|
NC_("select-action", "Copy the selection directly into a floating selection"),
|
||||||
|
select_copy_float_cmd_callback,
|
||||||
PIKA_HELP_SELECTION_FLOAT },
|
PIKA_HELP_SELECTION_FLOAT },
|
||||||
|
|
||||||
{ "select-feather", NULL,
|
{ "select-feather", NULL,
|
||||||
|
@ -186,9 +192,13 @@ select_actions_update (PikaActionGroup *group,
|
||||||
SET_SENSITIVE ("select-all", image && ! sel_all);
|
SET_SENSITIVE ("select-all", image && ! sel_all);
|
||||||
SET_SENSITIVE ("select-none", image && sel);
|
SET_SENSITIVE ("select-none", image && sel);
|
||||||
SET_SENSITIVE ("select-invert", image);
|
SET_SENSITIVE ("select-invert", image);
|
||||||
SET_SENSITIVE ("select-float", g_list_length (drawables) == 1 && sel &&
|
|
||||||
! pika_item_is_content_locked (drawables->data, NULL) &&
|
SET_SENSITIVE ("select-cut-float", g_list_length (drawables) == 1 && sel &&
|
||||||
! pika_viewable_get_children (drawables->data));
|
! pika_item_is_content_locked (drawables->data, NULL) &&
|
||||||
|
! pika_viewable_get_children (drawables->data));
|
||||||
|
SET_SENSITIVE ("select-copy-float", g_list_length (drawables) == 1 && sel &&
|
||||||
|
! pika_item_is_content_locked (drawables->data, NULL) &&
|
||||||
|
! pika_viewable_get_children (drawables->data));
|
||||||
|
|
||||||
SET_SENSITIVE ("select-feather", image && sel);
|
SET_SENSITIVE ("select-feather", image && sel);
|
||||||
SET_SENSITIVE ("select-sharpen", image && sel);
|
SET_SENSITIVE ("select-sharpen", image && sel);
|
||||||
|
|
|
@ -71,6 +71,10 @@ static void select_shrink_callback (GtkWidget *widget,
|
||||||
gdouble size,
|
gdouble size,
|
||||||
PikaUnit unit,
|
PikaUnit unit,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
static void select_float (PikaAction *action,
|
||||||
|
GVariant *value,
|
||||||
|
gboolean cut,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
|
||||||
/* public functions */
|
/* public functions */
|
||||||
|
@ -112,33 +116,19 @@ select_invert_cmd_callback (PikaAction *action,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
select_float_cmd_callback (PikaAction *action,
|
select_cut_float_cmd_callback (PikaAction *action,
|
||||||
GVariant *value,
|
GVariant *value,
|
||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
PikaImage *image;
|
select_float (action, value, TRUE, data);
|
||||||
GtkWidget *widget;
|
}
|
||||||
GList *drawables;
|
|
||||||
GError *error = NULL;
|
|
||||||
return_if_no_image (image, data);
|
|
||||||
return_if_no_widget (widget, data);
|
|
||||||
|
|
||||||
drawables = pika_image_get_selected_drawables (image);
|
void
|
||||||
if (pika_selection_float (PIKA_SELECTION (pika_image_get_mask (image)),
|
select_copy_float_cmd_callback (PikaAction *action,
|
||||||
drawables,
|
GVariant *value,
|
||||||
action_data_get_context (data),
|
gpointer data)
|
||||||
TRUE, 0, 0, &error))
|
{
|
||||||
{
|
select_float (action, value, FALSE, data);
|
||||||
pika_image_flush (image);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pika_message_literal (image->pika,
|
|
||||||
G_OBJECT (widget), PIKA_MESSAGE_WARNING,
|
|
||||||
error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
}
|
|
||||||
g_list_free (drawables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -696,3 +686,34 @@ select_shrink_callback (GtkWidget *widget,
|
||||||
TRUE);
|
TRUE);
|
||||||
pika_image_flush (image);
|
pika_image_flush (image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
select_float (PikaAction *action,
|
||||||
|
GVariant *value,
|
||||||
|
gboolean cut,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
PikaImage *image;
|
||||||
|
GtkWidget *widget;
|
||||||
|
GList *drawables;
|
||||||
|
GError *error = NULL;
|
||||||
|
return_if_no_image (image, data);
|
||||||
|
return_if_no_widget (widget, data);
|
||||||
|
|
||||||
|
drawables = pika_image_get_selected_drawables (image);
|
||||||
|
if (pika_selection_float (PIKA_SELECTION (pika_image_get_mask (image)),
|
||||||
|
drawables,
|
||||||
|
action_data_get_context (data),
|
||||||
|
cut, 0, 0, &error))
|
||||||
|
{
|
||||||
|
pika_image_flush (image);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pika_message_literal (image->pika,
|
||||||
|
G_OBJECT (widget), PIKA_MESSAGE_WARNING,
|
||||||
|
error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
}
|
||||||
|
g_list_free (drawables);
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,10 @@ void select_none_cmd_callback (PikaAction *action,
|
||||||
void select_invert_cmd_callback (PikaAction *action,
|
void select_invert_cmd_callback (PikaAction *action,
|
||||||
GVariant *value,
|
GVariant *value,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
void select_float_cmd_callback (PikaAction *action,
|
void select_cut_float_cmd_callback (PikaAction *action,
|
||||||
|
GVariant *value,
|
||||||
|
gpointer data);
|
||||||
|
void select_copy_float_cmd_callback (PikaAction *action,
|
||||||
GVariant *value,
|
GVariant *value,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
void select_feather_cmd_callback (PikaAction *action,
|
void select_feather_cmd_callback (PikaAction *action,
|
||||||
|
|
|
@ -98,6 +98,7 @@ enum
|
||||||
PROP_GLOBAL_PALETTE,
|
PROP_GLOBAL_PALETTE,
|
||||||
PROP_GLOBAL_GRADIENT,
|
PROP_GLOBAL_GRADIENT,
|
||||||
PROP_GLOBAL_FONT,
|
PROP_GLOBAL_FONT,
|
||||||
|
PROP_GLOBAL_EXPAND,
|
||||||
PROP_DEFAULT_IMAGE,
|
PROP_DEFAULT_IMAGE,
|
||||||
PROP_DEFAULT_GRID,
|
PROP_DEFAULT_GRID,
|
||||||
PROP_UNDO_LEVELS,
|
PROP_UNDO_LEVELS,
|
||||||
|
@ -540,6 +541,13 @@ pika_core_config_class_init (PikaCoreConfigClass *klass)
|
||||||
TRUE,
|
TRUE,
|
||||||
PIKA_PARAM_STATIC_STRINGS);
|
PIKA_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_GLOBAL_EXPAND,
|
||||||
|
"global-expand",
|
||||||
|
"Global expand",
|
||||||
|
GLOBAL_EXPAND_BLURB,
|
||||||
|
TRUE,
|
||||||
|
PIKA_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
PIKA_CONFIG_PROP_OBJECT (object_class, PROP_DEFAULT_IMAGE,
|
PIKA_CONFIG_PROP_OBJECT (object_class, PROP_DEFAULT_IMAGE,
|
||||||
"default-image",
|
"default-image",
|
||||||
"Default image",
|
"Default image",
|
||||||
|
@ -1061,6 +1069,9 @@ pika_core_config_set_property (GObject *object,
|
||||||
case PROP_GLOBAL_FONT:
|
case PROP_GLOBAL_FONT:
|
||||||
core_config->global_font = g_value_get_boolean (value);
|
core_config->global_font = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_GLOBAL_EXPAND:
|
||||||
|
core_config->global_expand = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
case PROP_DEFAULT_IMAGE:
|
case PROP_DEFAULT_IMAGE:
|
||||||
if (g_value_get_object (value))
|
if (g_value_get_object (value))
|
||||||
pika_config_sync (g_value_get_object (value) ,
|
pika_config_sync (g_value_get_object (value) ,
|
||||||
|
@ -1337,6 +1348,9 @@ pika_core_config_get_property (GObject *object,
|
||||||
case PROP_GLOBAL_FONT:
|
case PROP_GLOBAL_FONT:
|
||||||
g_value_set_boolean (value, core_config->global_font);
|
g_value_set_boolean (value, core_config->global_font);
|
||||||
break;
|
break;
|
||||||
|
case PROP_GLOBAL_EXPAND:
|
||||||
|
g_value_set_boolean (value, core_config->global_expand);
|
||||||
|
break;
|
||||||
case PROP_DEFAULT_IMAGE:
|
case PROP_DEFAULT_IMAGE:
|
||||||
g_value_set_object (value, core_config->default_image);
|
g_value_set_object (value, core_config->default_image);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -82,6 +82,7 @@ struct _PikaCoreConfig
|
||||||
gboolean global_palette;
|
gboolean global_palette;
|
||||||
gboolean global_gradient;
|
gboolean global_gradient;
|
||||||
gboolean global_font;
|
gboolean global_font;
|
||||||
|
gboolean global_expand;
|
||||||
PikaTemplate *default_image;
|
PikaTemplate *default_image;
|
||||||
PikaGrid *default_grid;
|
PikaGrid *default_grid;
|
||||||
gint levels_of_undo;
|
gint levels_of_undo;
|
||||||
|
|
|
@ -181,6 +181,9 @@ _("When enabled, the selected pattern will be used for all tools.")
|
||||||
#define GLOBAL_PALETTE_BLURB \
|
#define GLOBAL_PALETTE_BLURB \
|
||||||
"When enabled, the selected palette will be used for all tools."
|
"When enabled, the selected palette will be used for all tools."
|
||||||
|
|
||||||
|
#define GLOBAL_EXPAND_BLURB \
|
||||||
|
"When enabled, the selected auto expand layer settings will be used for all tools."
|
||||||
|
|
||||||
#define GRADIENT_PATH_BLURB \
|
#define GRADIENT_PATH_BLURB \
|
||||||
"Sets the gradient search path."
|
"Sets the gradient search path."
|
||||||
|
|
||||||
|
|
|
@ -715,6 +715,7 @@ typedef enum /*< pdb-skip, skip >*/
|
||||||
PIKA_CONTEXT_PROP_BUFFER = 18,
|
PIKA_CONTEXT_PROP_BUFFER = 18,
|
||||||
PIKA_CONTEXT_PROP_IMAGEFILE = 19,
|
PIKA_CONTEXT_PROP_IMAGEFILE = 19,
|
||||||
PIKA_CONTEXT_PROP_TEMPLATE = 20,
|
PIKA_CONTEXT_PROP_TEMPLATE = 20,
|
||||||
|
PIKA_CONTEXT_PROP_EXPAND = 21,
|
||||||
|
|
||||||
PIKA_CONTEXT_PROP_LAST = PIKA_CONTEXT_PROP_TEMPLATE
|
PIKA_CONTEXT_PROP_LAST = PIKA_CONTEXT_PROP_TEMPLATE
|
||||||
} PikaContextPropType;
|
} PikaContextPropType;
|
||||||
|
@ -741,6 +742,7 @@ typedef enum /*< pdb-skip, skip >*/
|
||||||
PIKA_CONTEXT_PROP_MASK_BUFFER = 1 << 18,
|
PIKA_CONTEXT_PROP_MASK_BUFFER = 1 << 18,
|
||||||
PIKA_CONTEXT_PROP_MASK_IMAGEFILE = 1 << 19,
|
PIKA_CONTEXT_PROP_MASK_IMAGEFILE = 1 << 19,
|
||||||
PIKA_CONTEXT_PROP_MASK_TEMPLATE = 1 << 20,
|
PIKA_CONTEXT_PROP_MASK_TEMPLATE = 1 << 20,
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND = 1 << 21,
|
||||||
|
|
||||||
/* aliases */
|
/* aliases */
|
||||||
PIKA_CONTEXT_PROP_MASK_PAINT = (PIKA_CONTEXT_PROP_MASK_FOREGROUND |
|
PIKA_CONTEXT_PROP_MASK_PAINT = (PIKA_CONTEXT_PROP_MASK_FOREGROUND |
|
||||||
|
@ -750,7 +752,8 @@ typedef enum /*< pdb-skip, skip >*/
|
||||||
PIKA_CONTEXT_PROP_MASK_BRUSH |
|
PIKA_CONTEXT_PROP_MASK_BRUSH |
|
||||||
PIKA_CONTEXT_PROP_MASK_DYNAMICS |
|
PIKA_CONTEXT_PROP_MASK_DYNAMICS |
|
||||||
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
PIKA_CONTEXT_PROP_MASK_GRADIENT),
|
PIKA_CONTEXT_PROP_MASK_GRADIENT |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND),
|
||||||
|
|
||||||
PIKA_CONTEXT_PROP_MASK_ALL = (PIKA_CONTEXT_PROP_MASK_IMAGE |
|
PIKA_CONTEXT_PROP_MASK_ALL = (PIKA_CONTEXT_PROP_MASK_IMAGE |
|
||||||
PIKA_CONTEXT_PROP_MASK_DISPLAY |
|
PIKA_CONTEXT_PROP_MASK_DISPLAY |
|
||||||
|
|
|
@ -557,6 +557,9 @@ user_update_menurc_over20 (const GMatchInfo *matched_value,
|
||||||
else if (g_strcmp0 (action_match, "view-rotate-reset") == 0 &&
|
else if (g_strcmp0 (action_match, "view-rotate-reset") == 0 &&
|
||||||
install->old_major == 2)
|
install->old_major == 2)
|
||||||
new_action_name = g_strdup ("view-reset");
|
new_action_name = g_strdup ("view-reset");
|
||||||
|
/* select-float became select-cut-float in 3.0 (select-copy-float added). */
|
||||||
|
else if (g_strcmp0 (action_match, "select-float") == 0)
|
||||||
|
new_action_name = g_strdup ("select-cut-float");
|
||||||
|
|
||||||
if (new_action_name == NULL)
|
if (new_action_name == NULL)
|
||||||
new_action_name = g_strdup (action_match);
|
new_action_name = g_strdup (action_match);
|
||||||
|
|
|
@ -286,7 +286,8 @@ pika_brush_get_new_preview (PikaViewable *viewable,
|
||||||
guchar *mask;
|
guchar *mask;
|
||||||
guchar *buf;
|
guchar *buf;
|
||||||
gint x, y;
|
gint x, y;
|
||||||
gboolean scaled = FALSE;
|
gboolean free_mask = FALSE;
|
||||||
|
gdouble scale = 1.0;
|
||||||
|
|
||||||
mask_width = pika_temp_buf_get_width (mask_buf);
|
mask_width = pika_temp_buf_get_width (mask_buf);
|
||||||
mask_height = pika_temp_buf_get_height (mask_buf);
|
mask_height = pika_temp_buf_get_height (mask_buf);
|
||||||
|
@ -295,45 +296,47 @@ pika_brush_get_new_preview (PikaViewable *viewable,
|
||||||
{
|
{
|
||||||
gdouble ratio_x = (gdouble) width / (gdouble) mask_width;
|
gdouble ratio_x = (gdouble) width / (gdouble) mask_width;
|
||||||
gdouble ratio_y = (gdouble) height / (gdouble) mask_height;
|
gdouble ratio_y = (gdouble) height / (gdouble) mask_height;
|
||||||
gdouble scale = MIN (ratio_x, ratio_y);
|
|
||||||
|
|
||||||
if (scale != 1.0)
|
scale = MIN (ratio_x, ratio_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIKA_IS_BRUSH_GENERATED (brush) || scale != 1.0)
|
||||||
|
{
|
||||||
|
pika_brush_begin_use (brush);
|
||||||
|
|
||||||
|
if (PIKA_IS_BRUSH_GENERATED (brush))
|
||||||
{
|
{
|
||||||
pika_brush_begin_use (brush);
|
PikaBrushGenerated *gen_brush = PIKA_BRUSH_GENERATED (brush);
|
||||||
|
|
||||||
if (PIKA_IS_BRUSH_GENERATED (brush))
|
mask_buf = pika_brush_transform_mask (brush, scale,
|
||||||
{
|
(pika_brush_generated_get_aspect_ratio (gen_brush) - 1.0) * 20.0 / 19.0,
|
||||||
PikaBrushGenerated *gen_brush = PIKA_BRUSH_GENERATED (brush);
|
pika_brush_generated_get_angle (gen_brush) / -360.0,
|
||||||
|
FALSE,
|
||||||
|
pika_brush_generated_get_hardness (gen_brush));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mask_buf = pika_brush_transform_mask (brush, scale, 0.0, 0.0, FALSE, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
mask_buf = pika_brush_transform_mask (brush, scale,
|
if (! mask_buf)
|
||||||
(pika_brush_generated_get_aspect_ratio (gen_brush) - 1.0) * 20.0 / 19.0,
|
{
|
||||||
pika_brush_generated_get_angle (gen_brush) / 360.0,
|
mask_buf = pika_temp_buf_new (1, 1, babl_format ("Y u8"));
|
||||||
FALSE,
|
pika_temp_buf_data_clear ((PikaTempBuf *) mask_buf);
|
||||||
pika_brush_generated_get_hardness (gen_brush));
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
mask_buf = pika_brush_transform_mask (brush, scale,
|
pika_temp_buf_ref ((PikaTempBuf *) mask_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixmap_buf)
|
||||||
|
pixmap_buf = pika_brush_transform_pixmap (brush, scale,
|
||||||
0.0, 0.0, FALSE, 1.0);
|
0.0, 0.0, FALSE, 1.0);
|
||||||
|
|
||||||
if (! mask_buf)
|
mask_width = pika_temp_buf_get_width (mask_buf);
|
||||||
{
|
mask_height = pika_temp_buf_get_height (mask_buf);
|
||||||
mask_buf = pika_temp_buf_new (1, 1, babl_format ("Y u8"));
|
|
||||||
pika_temp_buf_data_clear ((PikaTempBuf *) mask_buf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pika_temp_buf_ref ((PikaTempBuf *) mask_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pixmap_buf)
|
free_mask = TRUE;
|
||||||
pixmap_buf = pika_brush_transform_pixmap (brush, scale,
|
|
||||||
0.0, 0.0, FALSE, 1.0);
|
|
||||||
|
|
||||||
mask_width = pika_temp_buf_get_width (mask_buf);
|
|
||||||
mask_height = pika_temp_buf_get_height (mask_buf);
|
|
||||||
|
|
||||||
scaled = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return_buf = pika_temp_buf_new (mask_width, mask_height,
|
return_buf = pika_temp_buf_new (mask_width, mask_height,
|
||||||
|
@ -381,7 +384,7 @@ pika_brush_get_new_preview (PikaViewable *viewable,
|
||||||
|
|
||||||
pika_temp_buf_unlock (mask_buf, mask_data);
|
pika_temp_buf_unlock (mask_buf, mask_data);
|
||||||
|
|
||||||
if (scaled)
|
if (free_mask)
|
||||||
{
|
{
|
||||||
pika_temp_buf_unref ((PikaTempBuf *) mask_buf);
|
pika_temp_buf_unref ((PikaTempBuf *) mask_buf);
|
||||||
|
|
||||||
|
|
|
@ -747,7 +747,7 @@ pika_channel_resize (PikaItem *item,
|
||||||
gint offset_x,
|
gint offset_x,
|
||||||
gint offset_y)
|
gint offset_y)
|
||||||
{
|
{
|
||||||
PIKA_ITEM_CLASS (parent_class)->resize (item, context, PIKA_FILL_TRANSPARENT,
|
PIKA_ITEM_CLASS (parent_class)->resize (item, context, fill_type,
|
||||||
new_width, new_height,
|
new_width, new_height,
|
||||||
offset_x, offset_y);
|
offset_x, offset_y);
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@ struct _PikaDrawablePrivate
|
||||||
GeglBuffer *paint_buffer;
|
GeglBuffer *paint_buffer;
|
||||||
cairo_region_t *paint_copy_region;
|
cairo_region_t *paint_copy_region;
|
||||||
cairo_region_t *paint_update_region;
|
cairo_region_t *paint_update_region;
|
||||||
|
|
||||||
|
gboolean push_resize_undo;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __PIKA_DRAWABLE_PRIVATE_H__ */
|
#endif /* __PIKA_DRAWABLE_PRIVATE_H__ */
|
||||||
|
|
|
@ -632,7 +632,10 @@ pika_drawable_resize (PikaItem *item,
|
||||||
copy_y - new_offset_y, 0, 0));
|
copy_y - new_offset_y, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
pika_drawable_set_buffer_full (drawable, pika_item_is_attached (item), NULL,
|
pika_drawable_set_buffer_full (drawable,
|
||||||
|
pika_item_is_attached (item) &&
|
||||||
|
drawable->private->push_resize_undo,
|
||||||
|
NULL,
|
||||||
new_buffer,
|
new_buffer,
|
||||||
GEGL_RECTANGLE (new_offset_x, new_offset_y,
|
GEGL_RECTANGLE (new_offset_x, new_offset_y,
|
||||||
0, 0),
|
0, 0),
|
||||||
|
@ -910,6 +913,10 @@ pika_drawable_real_set_buffer (PikaDrawable *drawable,
|
||||||
}
|
}
|
||||||
|
|
||||||
g_set_object (&drawable->private->buffer, buffer);
|
g_set_object (&drawable->private->buffer, buffer);
|
||||||
|
|
||||||
|
if (pika_drawable_is_painting (drawable))
|
||||||
|
g_set_object (&drawable->private->paint_buffer, buffer);
|
||||||
|
|
||||||
g_clear_object (&drawable->private->format_profile);
|
g_clear_object (&drawable->private->format_profile);
|
||||||
|
|
||||||
if (drawable->private->buffer_source_node)
|
if (drawable->private->buffer_source_node)
|
||||||
|
@ -1076,6 +1083,8 @@ pika_drawable_new (GType type,
|
||||||
pika_drawable_set_buffer (drawable, FALSE, NULL, buffer);
|
pika_drawable_set_buffer (drawable, FALSE, NULL, buffer);
|
||||||
g_object_unref (buffer);
|
g_object_unref (buffer);
|
||||||
|
|
||||||
|
pika_drawable_enable_resize_undo (drawable);
|
||||||
|
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1676,6 +1685,22 @@ pika_drawable_push_undo (PikaDrawable *drawable,
|
||||||
x, y, width, height);
|
x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pika_drawable_disable_resize_undo (PikaDrawable *drawable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (PIKA_IS_DRAWABLE (drawable));
|
||||||
|
|
||||||
|
drawable->private->push_resize_undo = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pika_drawable_enable_resize_undo (PikaDrawable *drawable)
|
||||||
|
{
|
||||||
|
g_return_if_fail (PIKA_IS_DRAWABLE (drawable));
|
||||||
|
|
||||||
|
drawable->private->push_resize_undo = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
const Babl *
|
const Babl *
|
||||||
pika_drawable_get_space (PikaDrawable *drawable)
|
pika_drawable_get_space (PikaDrawable *drawable)
|
||||||
{
|
{
|
||||||
|
|
|
@ -209,6 +209,9 @@ void pika_drawable_push_undo (PikaDrawable *drawable,
|
||||||
gint width,
|
gint width,
|
||||||
gint height);
|
gint height);
|
||||||
|
|
||||||
|
void pika_drawable_disable_resize_undo (PikaDrawable *drawable);
|
||||||
|
void pika_drawable_enable_resize_undo (PikaDrawable *drawable);
|
||||||
|
|
||||||
const Babl * pika_drawable_get_space (PikaDrawable *drawable);
|
const Babl * pika_drawable_get_space (PikaDrawable *drawable);
|
||||||
const Babl * pika_drawable_get_format (PikaDrawable *drawable);
|
const Babl * pika_drawable_get_format (PikaDrawable *drawable);
|
||||||
const Babl * pika_drawable_get_format_with_alpha(PikaDrawable *drawable);
|
const Babl * pika_drawable_get_format_with_alpha(PikaDrawable *drawable);
|
||||||
|
|
|
@ -1083,9 +1083,6 @@ pika_palette_load_ase (PikaContext *context,
|
||||||
}
|
}
|
||||||
g_free (palette_name);
|
g_free (palette_name);
|
||||||
|
|
||||||
/* Header blocks are considered a "color" so we offset the count here */
|
|
||||||
num_cols -= 1;
|
|
||||||
|
|
||||||
for (i = 0; i < num_cols; i++)
|
for (i = 0; i < num_cols; i++)
|
||||||
{
|
{
|
||||||
gchar color_space[4];
|
gchar color_space[4];
|
||||||
|
@ -1108,6 +1105,23 @@ pika_palette_load_ase (PikaContext *context,
|
||||||
}
|
}
|
||||||
skip_first = FALSE;
|
skip_first = FALSE;
|
||||||
|
|
||||||
|
/* Skip group marker padding */
|
||||||
|
group = GINT16_FROM_BE (group);
|
||||||
|
if (group < 0)
|
||||||
|
{
|
||||||
|
gchar marker[4];
|
||||||
|
|
||||||
|
if (! g_input_stream_read_all (input, &marker, sizeof (marker),
|
||||||
|
&bytes_read, NULL, error))
|
||||||
|
{
|
||||||
|
g_printerr ("Invalid ASE group marker: %s.",
|
||||||
|
pika_file_get_utf8_name (file));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
num_cols--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
color_name = pika_palette_load_ase_block_name (input, file_size, error);
|
color_name = pika_palette_load_ase_block_name (input, file_size, error);
|
||||||
if (! color_name)
|
if (! color_name)
|
||||||
break;
|
break;
|
||||||
|
@ -1148,7 +1162,7 @@ pika_palette_load_ase (PikaContext *context,
|
||||||
|
|
||||||
for (gint j = 0; j < components; j++)
|
for (gint j = 0; j < components; j++)
|
||||||
{
|
{
|
||||||
gint tmp;
|
gint32 tmp;
|
||||||
|
|
||||||
if (! g_input_stream_read_all (input, &tmp, sizeof (tmp),
|
if (! g_input_stream_read_all (input, &tmp, sizeof (tmp),
|
||||||
&bytes_read, NULL, error))
|
&bytes_read, NULL, error))
|
||||||
|
@ -1162,7 +1176,7 @@ pika_palette_load_ase (PikaContext *context,
|
||||||
|
|
||||||
/* Convert 4 bytes to a 32bit float value */
|
/* Convert 4 bytes to a 32bit float value */
|
||||||
tmp = GINT32_FROM_BE (tmp);
|
tmp = GINT32_FROM_BE (tmp);
|
||||||
pixels[j] = *(gfloat *) &tmp;
|
memcpy (&pixels[j], &tmp, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! valid_color)
|
if (! valid_color)
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
#include "config/pikacoreconfig.h"
|
#include "config/pikacoreconfig.h"
|
||||||
|
|
||||||
|
#include "widgets/pikawidgets-utils.h"
|
||||||
|
|
||||||
#include "about.h"
|
#include "about.h"
|
||||||
#include "git-version.h"
|
#include "git-version.h"
|
||||||
|
|
||||||
|
@ -45,22 +47,34 @@
|
||||||
#include "pika-intl.h"
|
#include "pika-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* The first authors are the creators and maintainers, don't shuffle
|
||||||
|
* them
|
||||||
|
*/
|
||||||
|
#define START_INDEX (G_N_ELEMENTS (creators) - 1 /*NULL*/ + \
|
||||||
|
G_N_ELEMENTS (maintainers) - 1 /*NULL*/)
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
GtkWidget *dialog;
|
GtkWidget *dialog;
|
||||||
|
|
||||||
|
Pika *pika;
|
||||||
|
|
||||||
GtkWidget *update_frame;
|
GtkWidget *update_frame;
|
||||||
PikaCoreConfig *config;
|
PikaCoreConfig *config;
|
||||||
|
|
||||||
GtkWidget *anim_area;
|
GtkWidget *anim_area;
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
|
|
||||||
guint timer;
|
gint n_authors;
|
||||||
|
gint shuffle[G_N_ELEMENTS (authors) - 1]; /* NULL terminated */
|
||||||
|
|
||||||
gint index;
|
guint timer;
|
||||||
gint animstep;
|
|
||||||
gint state;
|
gint index;
|
||||||
gboolean visible;
|
gint animstep;
|
||||||
|
gint state;
|
||||||
|
gboolean visible;
|
||||||
} PikaAboutDialog;
|
} PikaAboutDialog;
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +107,8 @@ static void about_dialog_download_clicked
|
||||||
const gchar *link);
|
const gchar *link);
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
about_dialog_create (PikaCoreConfig *config)
|
about_dialog_create (Pika *pika,
|
||||||
|
PikaCoreConfig *config)
|
||||||
{
|
{
|
||||||
static PikaAboutDialog dialog;
|
static PikaAboutDialog dialog;
|
||||||
|
|
||||||
|
@ -106,6 +121,8 @@ about_dialog_create (PikaCoreConfig *config)
|
||||||
gchar *copyright;
|
gchar *copyright;
|
||||||
gchar *version;
|
gchar *version;
|
||||||
|
|
||||||
|
dialog.pika = pika;
|
||||||
|
dialog.n_authors = G_N_ELEMENTS (authors) - 1;
|
||||||
dialog.config = config;
|
dialog.config = config;
|
||||||
|
|
||||||
pixbuf = about_dialog_load_logo ();
|
pixbuf = about_dialog_load_logo ();
|
||||||
|
@ -134,6 +151,9 @@ about_dialog_create (PikaCoreConfig *config)
|
||||||
"logo", pixbuf,
|
"logo", pixbuf,
|
||||||
"website", "https://heckin.technology/AlderconeStudio/PIKApp/",
|
"website", "https://heckin.technology/AlderconeStudio/PIKApp/",
|
||||||
"website-label", _("Visit the PIKA website"),
|
"website-label", _("Visit the PIKA website"),
|
||||||
|
"authors", authors,
|
||||||
|
"artists", artists,
|
||||||
|
"documenters", documenters,
|
||||||
/* Translators: insert your names here,
|
/* Translators: insert your names here,
|
||||||
separated by newline */
|
separated by newline */
|
||||||
"translator-credits", _("translator-credits"),
|
"translator-credits", _("translator-credits"),
|
||||||
|
@ -196,6 +216,10 @@ about_dialog_map (GtkWidget *widget,
|
||||||
|
|
||||||
dialog->timer = g_timeout_add (800, about_dialog_timer, dialog);
|
dialog->timer = g_timeout_add (800, about_dialog_timer, dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
pika_window_set_title_bar_theme (dialog->pika, widget, FALSE);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -466,6 +490,27 @@ about_dialog_add_update (PikaAboutDialog *dialog,
|
||||||
static void
|
static void
|
||||||
about_dialog_reshuffle (PikaAboutDialog *dialog)
|
about_dialog_reshuffle (PikaAboutDialog *dialog)
|
||||||
{
|
{
|
||||||
|
GRand *gr = g_rand_new ();
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; i < dialog->n_authors; i++)
|
||||||
|
dialog->shuffle[i] = i;
|
||||||
|
|
||||||
|
for (i = START_INDEX; i < dialog->n_authors; i++)
|
||||||
|
{
|
||||||
|
gint j = g_rand_int_range (gr, START_INDEX, dialog->n_authors);
|
||||||
|
|
||||||
|
if (i != j)
|
||||||
|
{
|
||||||
|
gint t;
|
||||||
|
|
||||||
|
t = dialog->shuffle[j];
|
||||||
|
dialog->shuffle[j] = dialog->shuffle[i];
|
||||||
|
dialog->shuffle[i] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_rand_free (gr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -642,11 +687,17 @@ about_dialog_timer (gpointer data)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
text = insert_spacers (_("PIKA is brought to you by Aldercone Studio"));
|
text = insert_spacers (_("PIKA is brought to you by"));
|
||||||
|
dialog->state += 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return FALSE;
|
if (! (dialog->index < dialog->n_authors))
|
||||||
|
dialog->index = 0;
|
||||||
|
|
||||||
|
text = insert_spacers (authors[dialog->shuffle[dialog->index]]);
|
||||||
|
dialog->index += 1;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_return_val_if_reached (TRUE);
|
g_return_val_if_reached (TRUE);
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
#define __ABOUT_DIALOG_H__
|
#define __ABOUT_DIALOG_H__
|
||||||
|
|
||||||
|
|
||||||
GtkWidget * about_dialog_create (PikaCoreConfig *config);
|
GtkWidget * about_dialog_create (Pika *pika,
|
||||||
|
PikaCoreConfig *config);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __ABOUT_DIALOG_H__ */
|
#endif /* __ABOUT_DIALOG_H__ */
|
||||||
|
|
|
@ -221,7 +221,7 @@ dialogs_about_get (PikaDialogFactory *factory,
|
||||||
PikaUIManager *ui_manager,
|
PikaUIManager *ui_manager,
|
||||||
gint view_size)
|
gint view_size)
|
||||||
{
|
{
|
||||||
return about_dialog_create (context->pika);
|
return about_dialog_create (context->pika, context->pika->edit_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
|
|
|
@ -1856,6 +1856,9 @@ prefs_dialog_new (Pika *pika,
|
||||||
prefs_check_button_add_with_icon (object, "global-gradient",
|
prefs_check_button_add_with_icon (object, "global-gradient",
|
||||||
_("_Gradient"), PIKA_ICON_GRADIENT,
|
_("_Gradient"), PIKA_ICON_GRADIENT,
|
||||||
GTK_BOX (vbox2), size_group);
|
GTK_BOX (vbox2), size_group);
|
||||||
|
prefs_check_button_add_with_icon (object, "global-expand",
|
||||||
|
_("E_xpand Layers"), PIKA_ICON_TOOL_SCALE,
|
||||||
|
GTK_BOX (vbox2), size_group);
|
||||||
|
|
||||||
/* Move Tool */
|
/* Move Tool */
|
||||||
vbox2 = prefs_frame_new (_("Move Tool"),
|
vbox2 = prefs_frame_new (_("Move Tool"),
|
||||||
|
|
|
@ -46,6 +46,11 @@ static void pika_display_bounds_changed_handler (PikaImage *image,
|
||||||
gint old_x,
|
gint old_x,
|
||||||
gint old_y,
|
gint old_y,
|
||||||
PikaDisplay *display);
|
PikaDisplay *display);
|
||||||
|
static void pika_display_flush_handler (PikaImage *image,
|
||||||
|
gboolean invalidate_preview,
|
||||||
|
PikaDisplay *display);
|
||||||
|
static gboolean
|
||||||
|
pika_display_flush_handler_idle (gpointer user_data);
|
||||||
|
|
||||||
|
|
||||||
/* public functions */
|
/* public functions */
|
||||||
|
@ -122,3 +127,23 @@ pika_display_bounds_changed_handler (PikaImage *image,
|
||||||
{
|
{
|
||||||
pika_display_update_bounding_box (display);
|
pika_display_update_bounding_box (display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pika_display_flush_handler (PikaImage *image,
|
||||||
|
gboolean invalidate_preview,
|
||||||
|
PikaDisplay *display)
|
||||||
|
{
|
||||||
|
g_idle_add_full (G_PRIORITY_LOW,
|
||||||
|
(GSourceFunc) pika_display_flush_handler_idle,
|
||||||
|
g_object_ref (display), g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pika_display_flush_handler_idle (gpointer user_data)
|
||||||
|
{
|
||||||
|
PikaDisplay *display = user_data;
|
||||||
|
|
||||||
|
pika_display_flush (display);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
|
@ -26,13 +26,19 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <cairo.h>
|
||||||
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
#include <gegl.h>
|
#include <gegl.h>
|
||||||
#include <gegl-plugin.h>
|
#include <gegl-plugin.h>
|
||||||
|
|
||||||
|
#include "libpikacolor/pikacolor.h"
|
||||||
|
|
||||||
#include "pika-gegl-types.h"
|
#include "pika-gegl-types.h"
|
||||||
|
|
||||||
|
#include "core/pikapattern.h"
|
||||||
#include "core/pikaprogress.h"
|
#include "core/pikaprogress.h"
|
||||||
|
|
||||||
|
#include "pika-babl.h"
|
||||||
#include "pika-gegl-loops.h"
|
#include "pika-gegl-loops.h"
|
||||||
#include "pika-gegl-utils.h"
|
#include "pika-gegl-utils.h"
|
||||||
|
|
||||||
|
@ -337,6 +343,100 @@ pika_gegl_buffer_dup (GeglBuffer *buffer)
|
||||||
return new_buffer;
|
return new_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GeglBuffer *
|
||||||
|
pika_gegl_buffer_resize (GeglBuffer *buffer,
|
||||||
|
gint new_width,
|
||||||
|
gint new_height,
|
||||||
|
gint offset_x,
|
||||||
|
gint offset_y,
|
||||||
|
PikaRGB *color,
|
||||||
|
PikaPattern *pattern,
|
||||||
|
gint pattern_offset_x,
|
||||||
|
gint pattern_offset_y)
|
||||||
|
{
|
||||||
|
GeglBuffer *new_buffer;
|
||||||
|
gboolean intersect;
|
||||||
|
GeglRectangle copy_rect;
|
||||||
|
const GeglRectangle *extent;
|
||||||
|
const Babl *format;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
|
||||||
|
|
||||||
|
extent = gegl_buffer_get_extent (buffer);
|
||||||
|
format = gegl_buffer_get_format (buffer);
|
||||||
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, new_width, new_height),
|
||||||
|
format);
|
||||||
|
|
||||||
|
intersect = gegl_rectangle_intersect (©_rect,
|
||||||
|
GEGL_RECTANGLE (0, 0, extent->width,
|
||||||
|
extent->height),
|
||||||
|
GEGL_RECTANGLE (offset_x, offset_y,
|
||||||
|
new_width, new_height));
|
||||||
|
|
||||||
|
if (! intersect ||
|
||||||
|
copy_rect.width != new_width ||
|
||||||
|
copy_rect.height != new_height)
|
||||||
|
{
|
||||||
|
/* Clear the new buffer if needed and color/pattern is given */
|
||||||
|
if (pattern)
|
||||||
|
{
|
||||||
|
GeglBuffer *src_buffer;
|
||||||
|
GeglBuffer *dest_buffer;
|
||||||
|
PikaColorProfile *src_profile;
|
||||||
|
PikaColorProfile *dest_profile;
|
||||||
|
|
||||||
|
src_buffer = pika_pattern_create_buffer (pattern);
|
||||||
|
|
||||||
|
src_profile = pika_babl_format_get_color_profile (
|
||||||
|
gegl_buffer_get_format (src_buffer));
|
||||||
|
dest_profile = pika_babl_format_get_color_profile (
|
||||||
|
gegl_buffer_get_format (new_buffer));
|
||||||
|
|
||||||
|
if (pika_color_transform_can_gegl_copy (src_profile, dest_profile))
|
||||||
|
{
|
||||||
|
dest_buffer = g_object_ref (src_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer),
|
||||||
|
gegl_buffer_get_format (new_buffer));
|
||||||
|
|
||||||
|
pika_gegl_convert_color_profile (src_buffer, NULL, src_profile,
|
||||||
|
dest_buffer, NULL, dest_profile,
|
||||||
|
PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL,
|
||||||
|
TRUE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (src_profile);
|
||||||
|
g_object_unref (dest_profile);
|
||||||
|
|
||||||
|
gegl_buffer_set_pattern (new_buffer, NULL, dest_buffer,
|
||||||
|
pattern_offset_x, pattern_offset_y);
|
||||||
|
|
||||||
|
g_object_unref (src_buffer);
|
||||||
|
g_object_unref (dest_buffer);
|
||||||
|
}
|
||||||
|
else if (color)
|
||||||
|
{
|
||||||
|
GeglColor *gegl_color;
|
||||||
|
|
||||||
|
gegl_color = pika_gegl_color_new (color, gegl_buffer_get_format (buffer));
|
||||||
|
gegl_buffer_set_color (new_buffer, NULL, gegl_color);
|
||||||
|
g_object_unref (gegl_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intersect && copy_rect.width && copy_rect.height)
|
||||||
|
{
|
||||||
|
/* Copy the pixels in the intersection */
|
||||||
|
pika_gegl_buffer_copy (buffer, ©_rect, GEGL_ABYSS_NONE, new_buffer,
|
||||||
|
GEGL_RECTANGLE (copy_rect.x - offset_x,
|
||||||
|
copy_rect.y - offset_y, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
pika_gegl_buffer_set_extent (GeglBuffer *buffer,
|
pika_gegl_buffer_set_extent (GeglBuffer *buffer,
|
||||||
const GeglRectangle *extent)
|
const GeglRectangle *extent)
|
||||||
|
|
|
@ -59,6 +59,15 @@ gboolean pika_gegl_param_spec_has_key (GParamSpec *pspe
|
||||||
const gchar *value);
|
const gchar *value);
|
||||||
|
|
||||||
GeglBuffer * pika_gegl_buffer_dup (GeglBuffer *buffer);
|
GeglBuffer * pika_gegl_buffer_dup (GeglBuffer *buffer);
|
||||||
|
GeglBuffer * pika_gegl_buffer_resize (GeglBuffer *buffer,
|
||||||
|
gint new_width,
|
||||||
|
gint new_height,
|
||||||
|
gint offset_x,
|
||||||
|
gint offset_y,
|
||||||
|
PikaRGB *color,
|
||||||
|
PikaPattern *pattern,
|
||||||
|
gint pattern_offset_x,
|
||||||
|
gint pattern_offset_y);
|
||||||
|
|
||||||
gboolean pika_gegl_buffer_set_extent (GeglBuffer *buffer,
|
gboolean pika_gegl_buffer_set_extent (GeglBuffer *buffer,
|
||||||
const GeglRectangle *extent);
|
const GeglRectangle *extent);
|
||||||
|
|
|
@ -85,5 +85,12 @@ typedef enum /*< skip, pdb-skip >*/
|
||||||
PIKA_PAINT_STATE_FINISH /* Cleanup and/or reset PaintFunc operation */
|
PIKA_PAINT_STATE_FINISH /* Cleanup and/or reset PaintFunc operation */
|
||||||
} PikaPaintState;
|
} PikaPaintState;
|
||||||
|
|
||||||
|
/* State of lock blinking */
|
||||||
|
typedef enum /*< skip, pdb-skip >*/
|
||||||
|
{
|
||||||
|
PIKA_PAINT_LOCK_NOT_BLINKED,
|
||||||
|
PIKA_PAINT_LOCK_BLINK_PENDING,
|
||||||
|
PIKA_PAINT_LOCK_BLINKED,
|
||||||
|
} PikaPaintLockBlinkState;
|
||||||
|
|
||||||
#endif /* __PAINT_ENUMS_H__ */
|
#endif /* __PAINT_ENUMS_H__ */
|
||||||
|
|
|
@ -819,6 +819,8 @@ pika_brush_core_get_paint_buffer (PikaPaintCore *paint_core,
|
||||||
gint x1, y1, x2, y2;
|
gint x1, y1, x2, y2;
|
||||||
gint drawable_width, drawable_height;
|
gint drawable_width, drawable_height;
|
||||||
gint brush_width, brush_height;
|
gint brush_width, brush_height;
|
||||||
|
gint offset_change_x, offset_change_y;
|
||||||
|
PikaCoords new_coords;
|
||||||
|
|
||||||
pika_brush_transform_size (core->brush,
|
pika_brush_transform_size (core->brush,
|
||||||
core->scale, core->aspect_ratio,
|
core->scale, core->aspect_ratio,
|
||||||
|
@ -835,11 +837,31 @@ pika_brush_core_get_paint_buffer (PikaPaintCore *paint_core,
|
||||||
x = (gint) floor (coords->x) - (brush_width / 2);
|
x = (gint) floor (coords->x) - (brush_width / 2);
|
||||||
y = (gint) floor (coords->y) - (brush_height / 2);
|
y = (gint) floor (coords->y) - (brush_height / 2);
|
||||||
|
|
||||||
|
x1 = x - 1;
|
||||||
|
y1 = y - 1;
|
||||||
|
x2 = x + brush_width + 1;
|
||||||
|
y2 = y + brush_height + 1;
|
||||||
|
|
||||||
|
pika_paint_core_expand_drawable (paint_core, drawable, paint_options,
|
||||||
|
x1, x2, y1, y2,
|
||||||
|
&offset_change_x, &offset_change_y);
|
||||||
|
|
||||||
|
if (offset_change_x || offset_change_y)
|
||||||
|
{
|
||||||
|
x += offset_change_x;
|
||||||
|
y += offset_change_y;
|
||||||
|
|
||||||
|
new_coords = *coords;
|
||||||
|
new_coords.x = coords->x + offset_change_x;
|
||||||
|
new_coords.y = coords->y + offset_change_y;
|
||||||
|
pika_symmetry_set_origin (paint_core->sym, drawable, &new_coords);
|
||||||
|
}
|
||||||
|
|
||||||
drawable_width = pika_item_get_width (PIKA_ITEM (drawable));
|
drawable_width = pika_item_get_width (PIKA_ITEM (drawable));
|
||||||
drawable_height = pika_item_get_height (PIKA_ITEM (drawable));
|
drawable_height = pika_item_get_height (PIKA_ITEM (drawable));
|
||||||
|
|
||||||
x1 = CLAMP (x - 1, 0, drawable_width);
|
x1 = CLAMP (x - 1, 0, drawable_width);
|
||||||
y1 = CLAMP (y - 1, 0, drawable_height);
|
y1 = CLAMP (y - 1, 0, drawable_height);
|
||||||
x2 = CLAMP (x + brush_width + 1, 0, drawable_width);
|
x2 = CLAMP (x + brush_width + 1, 0, drawable_width);
|
||||||
y2 = CLAMP (y + brush_height + 1, 0, drawable_height);
|
y2 = CLAMP (y + brush_height + 1, 0, drawable_height);
|
||||||
|
|
||||||
|
|
|
@ -470,6 +470,21 @@ pika_blob_duplicate (PikaBlob *b)
|
||||||
return g_memdup2 (b, sizeof (PikaBlob) + sizeof (PikaBlobSpan) * (b->height - 1));
|
return g_memdup2 (b, sizeof (PikaBlob) + sizeof (PikaBlobSpan) * (b->height - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pika_blob_move (PikaBlob *b,
|
||||||
|
gint x,
|
||||||
|
gint y)
|
||||||
|
{
|
||||||
|
gint i = 0;
|
||||||
|
|
||||||
|
b->y += y;
|
||||||
|
for (i = 0; i < b->height; i++)
|
||||||
|
{
|
||||||
|
b->data[i].left += x;
|
||||||
|
b->data[i].right += x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
void
|
void
|
||||||
pika_blob_dump (PikaBlob *b)
|
pika_blob_dump (PikaBlob *b)
|
||||||
|
|
|
@ -86,6 +86,9 @@ void pika_blob_bounds (PikaBlob *b,
|
||||||
PikaBlob * pika_blob_convex_union (PikaBlob *b1,
|
PikaBlob * pika_blob_convex_union (PikaBlob *b1,
|
||||||
PikaBlob *b2);
|
PikaBlob *b2);
|
||||||
PikaBlob * pika_blob_duplicate (PikaBlob *b);
|
PikaBlob * pika_blob_duplicate (PikaBlob *b);
|
||||||
|
void pika_blob_move (PikaBlob *b,
|
||||||
|
gint x,
|
||||||
|
gint y);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __PIKA_INK_BLOB_H__ */
|
#endif /* __PIKA_INK_BLOB_H__ */
|
||||||
|
|
|
@ -242,17 +242,49 @@ pika_ink_get_paint_buffer (PikaPaintCore *paint_core,
|
||||||
gint *paint_width,
|
gint *paint_width,
|
||||||
gint *paint_height)
|
gint *paint_height)
|
||||||
{
|
{
|
||||||
PikaInk *ink = PIKA_INK (paint_core);
|
PikaInk *ink = PIKA_INK (paint_core);
|
||||||
gint x, y;
|
gint x, y;
|
||||||
gint width, height;
|
gint width, height;
|
||||||
gint dwidth, dheight;
|
gint dwidth, dheight;
|
||||||
gint x1, y1, x2, y2;
|
gint x1, y1, x2, y2;
|
||||||
|
gint offset_change_x, offset_change_y;
|
||||||
|
PikaCoords new_coords;
|
||||||
|
GList *iter;
|
||||||
|
|
||||||
pika_blob_bounds (ink->cur_blob, &x, &y, &width, &height);
|
pika_blob_bounds (ink->cur_blob, &x, &y, &width, &height);
|
||||||
|
|
||||||
|
x1 = x / SUBSAMPLE - 1;
|
||||||
|
y1 = y / SUBSAMPLE - 1;
|
||||||
|
x2 = (x + width) / SUBSAMPLE + 2;
|
||||||
|
y2 = (y + height) / SUBSAMPLE + 2;
|
||||||
|
|
||||||
|
pika_paint_core_expand_drawable (paint_core, drawable, paint_options,
|
||||||
|
x1, x2, y1, y2,
|
||||||
|
&offset_change_x, &offset_change_y);
|
||||||
|
|
||||||
dwidth = pika_item_get_width (PIKA_ITEM (drawable));
|
dwidth = pika_item_get_width (PIKA_ITEM (drawable));
|
||||||
dheight = pika_item_get_height (PIKA_ITEM (drawable));
|
dheight = pika_item_get_height (PIKA_ITEM (drawable));
|
||||||
|
|
||||||
|
if (offset_change_x || offset_change_y)
|
||||||
|
{
|
||||||
|
x += SUBSAMPLE * offset_change_x;
|
||||||
|
y += SUBSAMPLE * offset_change_y;
|
||||||
|
|
||||||
|
new_coords = *coords;
|
||||||
|
new_coords.x = coords->x + offset_change_x;
|
||||||
|
new_coords.y = coords->y + offset_change_y;
|
||||||
|
pika_symmetry_set_origin (paint_core->sym, drawable, &new_coords);
|
||||||
|
|
||||||
|
for (iter = ink->blobs_to_render; iter; iter = g_list_next (iter))
|
||||||
|
pika_blob_move (iter->data,
|
||||||
|
SUBSAMPLE * offset_change_x,
|
||||||
|
SUBSAMPLE * offset_change_y);
|
||||||
|
for (iter = ink->last_blobs; iter; iter = g_list_next (iter))
|
||||||
|
pika_blob_move (iter->data,
|
||||||
|
SUBSAMPLE * offset_change_x,
|
||||||
|
SUBSAMPLE * offset_change_y);
|
||||||
|
}
|
||||||
|
|
||||||
x1 = CLAMP (x / SUBSAMPLE - 1, 0, dwidth);
|
x1 = CLAMP (x / SUBSAMPLE - 1, 0, dwidth);
|
||||||
y1 = CLAMP (y / SUBSAMPLE - 1, 0, dheight);
|
y1 = CLAMP (y / SUBSAMPLE - 1, 0, dheight);
|
||||||
x2 = CLAMP ((x + width) / SUBSAMPLE + 2, 0, dwidth);
|
x2 = CLAMP ((x + width) / SUBSAMPLE + 2, 0, dwidth);
|
||||||
|
@ -319,7 +351,6 @@ pika_ink_motion (PikaPaintCore *paint_core,
|
||||||
PikaInk *ink = PIKA_INK (paint_core);
|
PikaInk *ink = PIKA_INK (paint_core);
|
||||||
PikaInkOptions *options = PIKA_INK_OPTIONS (paint_options);
|
PikaInkOptions *options = PIKA_INK_OPTIONS (paint_options);
|
||||||
PikaContext *context = PIKA_CONTEXT (paint_options);
|
PikaContext *context = PIKA_CONTEXT (paint_options);
|
||||||
GList *blob_unions = NULL;
|
|
||||||
GList *blobs_to_render = NULL;
|
GList *blobs_to_render = NULL;
|
||||||
GeglBuffer *paint_buffer;
|
GeglBuffer *paint_buffer;
|
||||||
gint paint_buffer_x;
|
gint paint_buffer_x;
|
||||||
|
@ -338,6 +369,7 @@ pika_ink_motion (PikaPaintCore *paint_core,
|
||||||
coords.x -= off_x;
|
coords.x -= off_x;
|
||||||
coords.y -= off_y;
|
coords.y -= off_y;
|
||||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
pika_symmetry_set_origin (sym, drawable, &coords);
|
||||||
|
paint_core->sym = sym;
|
||||||
|
|
||||||
n_strokes = pika_symmetry_get_size (sym);
|
n_strokes = pika_symmetry_get_size (sym);
|
||||||
|
|
||||||
|
@ -377,7 +409,8 @@ pika_ink_motion (PikaPaintCore *paint_core,
|
||||||
last_blob);
|
last_blob);
|
||||||
ink->start_blobs = g_list_prepend (ink->start_blobs,
|
ink->start_blobs = g_list_prepend (ink->start_blobs,
|
||||||
pika_blob_duplicate (last_blob));
|
pika_blob_duplicate (last_blob));
|
||||||
blobs_to_render = g_list_prepend (blobs_to_render, last_blob);
|
blobs_to_render = g_list_prepend (blobs_to_render,
|
||||||
|
pika_blob_duplicate (last_blob));
|
||||||
}
|
}
|
||||||
ink->start_blobs = g_list_reverse (ink->start_blobs);
|
ink->start_blobs = g_list_reverse (ink->start_blobs);
|
||||||
ink->last_blobs = g_list_reverse (ink->last_blobs);
|
ink->last_blobs = g_list_reverse (ink->last_blobs);
|
||||||
|
@ -411,7 +444,6 @@ pika_ink_motion (PikaPaintCore *paint_core,
|
||||||
g_list_nth (ink->last_blobs, i)->data = blob;
|
g_list_nth (ink->last_blobs, i)->data = blob;
|
||||||
|
|
||||||
blobs_to_render = g_list_prepend (blobs_to_render, blob_union);
|
blobs_to_render = g_list_prepend (blobs_to_render, blob_union);
|
||||||
blob_unions = g_list_prepend (blob_unions, blob_union);
|
|
||||||
}
|
}
|
||||||
blobs_to_render = g_list_reverse (blobs_to_render);
|
blobs_to_render = g_list_reverse (blobs_to_render);
|
||||||
}
|
}
|
||||||
|
@ -422,6 +454,7 @@ pika_ink_motion (PikaPaintCore *paint_core,
|
||||||
pika_pickable_srgb_to_image_color (PIKA_PICKABLE (drawable),
|
pika_pickable_srgb_to_image_color (PIKA_PICKABLE (drawable),
|
||||||
&foreground, &foreground);
|
&foreground, &foreground);
|
||||||
color = pika_gegl_color_new (&foreground, pika_drawable_get_space (drawable));
|
color = pika_gegl_color_new (&foreground, pika_drawable_get_space (drawable));
|
||||||
|
ink->blobs_to_render = blobs_to_render;
|
||||||
|
|
||||||
for (i = 0; i < n_strokes; i++)
|
for (i = 0; i < n_strokes; i++)
|
||||||
{
|
{
|
||||||
|
@ -467,8 +500,7 @@ pika_ink_motion (PikaPaintCore *paint_core,
|
||||||
|
|
||||||
g_object_unref (color);
|
g_object_unref (color);
|
||||||
|
|
||||||
g_list_free_full (blob_unions, g_free);
|
g_list_free_full (blobs_to_render, g_free);
|
||||||
g_list_free (blobs_to_render);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PikaBlob *
|
static PikaBlob *
|
||||||
|
|
|
@ -41,10 +41,11 @@ struct _PikaInk
|
||||||
{
|
{
|
||||||
PikaPaintCore parent_instance;
|
PikaPaintCore parent_instance;
|
||||||
|
|
||||||
GList *start_blobs; /* starting blobs per stroke (for undo) */
|
GList *start_blobs; /* starting blobs per stroke (for undo) */
|
||||||
|
|
||||||
PikaBlob *cur_blob; /* current blob */
|
PikaBlob *cur_blob; /* current blob */
|
||||||
GList *last_blobs; /* blobs for last stroke positions */
|
GList *last_blobs; /* blobs for last stroke positions */
|
||||||
|
GList *blobs_to_render;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _PikaInkClass
|
struct _PikaInkClass
|
||||||
|
|
|
@ -259,7 +259,7 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
|
||||||
{
|
{
|
||||||
PikaMybrushCore *mybrush = PIKA_MYBRUSH_CORE (paint_core);
|
PikaMybrushCore *mybrush = PIKA_MYBRUSH_CORE (paint_core);
|
||||||
MyPaintRectangle rect;
|
MyPaintRectangle rect;
|
||||||
PikaCoords coords;
|
PikaCoords origin;
|
||||||
GList *iter;
|
GList *iter;
|
||||||
gdouble dt = 0.0;
|
gdouble dt = 0.0;
|
||||||
gint off_x, off_y;
|
gint off_x, off_y;
|
||||||
|
@ -269,10 +269,10 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
|
||||||
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
|
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
|
||||||
n_strokes = pika_symmetry_get_size (sym);
|
n_strokes = pika_symmetry_get_size (sym);
|
||||||
|
|
||||||
coords = *(pika_symmetry_get_origin (sym));
|
origin = *(pika_symmetry_get_origin (sym));
|
||||||
coords.x -= off_x;
|
origin.x -= off_x;
|
||||||
coords.y -= off_y;
|
origin.y -= off_y;
|
||||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
pika_symmetry_set_origin (sym, drawable, &origin);
|
||||||
|
|
||||||
/* The number of strokes may change during a motion, depending on
|
/* The number of strokes may change during a motion, depending on
|
||||||
* the type of symmetry. When that happens, reset the brushes.
|
* the type of symmetry. When that happens, reset the brushes.
|
||||||
|
@ -291,9 +291,8 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
|
||||||
iter;
|
iter;
|
||||||
iter = g_list_next (iter), i++)
|
iter = g_list_next (iter), i++)
|
||||||
{
|
{
|
||||||
MyPaintBrush *brush = iter->data;
|
MyPaintBrush *brush = iter->data;
|
||||||
|
PikaCoords coords = *(pika_symmetry_get_coords (sym, i));
|
||||||
coords = *(pika_symmetry_get_coords (sym, i));
|
|
||||||
|
|
||||||
mypaint_brush_stroke_to (brush,
|
mypaint_brush_stroke_to (brush,
|
||||||
(MyPaintSurface *) mybrush->private->surface,
|
(MyPaintSurface *) mybrush->private->surface,
|
||||||
|
@ -326,6 +325,42 @@ pika_mybrush_core_motion (PikaPaintCore *paint_core,
|
||||||
MyPaintBrush *brush = iter->data;
|
MyPaintBrush *brush = iter->data;
|
||||||
PikaCoords coords = *(pika_symmetry_get_coords (sym, i));
|
PikaCoords coords = *(pika_symmetry_get_coords (sym, i));
|
||||||
gdouble pressure = coords.pressure;
|
gdouble pressure = coords.pressure;
|
||||||
|
gboolean expanded;
|
||||||
|
gfloat radius = 100;
|
||||||
|
gint x1, x2, y1, y2;
|
||||||
|
gint offset_change_x, offset_change_y;
|
||||||
|
gint off_x_surf, off_y_surf;
|
||||||
|
gint off_x, off_y;
|
||||||
|
|
||||||
|
x1 = coords.x - radius;
|
||||||
|
y1 = coords.y - radius;
|
||||||
|
x2 = coords.x + radius;
|
||||||
|
y2 = coords.y + radius;
|
||||||
|
|
||||||
|
expanded = pika_paint_core_expand_drawable (paint_core, drawable, paint_options,
|
||||||
|
x1, x2, y1, y2,
|
||||||
|
&offset_change_x, &offset_change_y);
|
||||||
|
|
||||||
|
pika_item_get_offset (PIKA_ITEM (drawable), &off_x, &off_y);
|
||||||
|
if (expanded)
|
||||||
|
pika_mypaint_surface_set_buffer (mybrush->private->surface, pika_drawable_get_buffer (drawable),
|
||||||
|
off_x, off_y);
|
||||||
|
|
||||||
|
pika_mypaint_surface_get_offset (mybrush->private->surface, &off_x_surf, &off_y_surf);
|
||||||
|
coords.x -= off_x_surf;
|
||||||
|
coords.y -= off_y_surf;
|
||||||
|
|
||||||
|
if (offset_change_x || offset_change_y)
|
||||||
|
{
|
||||||
|
pika_mypaint_surface_set_offset (mybrush->private->surface,
|
||||||
|
off_x_surf + offset_change_x,
|
||||||
|
off_y_surf + offset_change_y);
|
||||||
|
|
||||||
|
origin = *(pika_symmetry_get_origin (sym));
|
||||||
|
origin.x += offset_change_x;
|
||||||
|
origin.y += offset_change_y;
|
||||||
|
pika_symmetry_set_origin (sym, drawable, &origin);
|
||||||
|
}
|
||||||
|
|
||||||
mypaint_brush_stroke_to (brush,
|
mypaint_brush_stroke_to (brush,
|
||||||
(MyPaintSurface *) mybrush->private->surface,
|
(MyPaintSurface *) mybrush->private->surface,
|
||||||
|
|
|
@ -38,13 +38,15 @@
|
||||||
|
|
||||||
struct _PikaMybrushSurface
|
struct _PikaMybrushSurface
|
||||||
{
|
{
|
||||||
MyPaintSurface surface;
|
MyPaintSurface surface;
|
||||||
GeglBuffer *buffer;
|
GeglBuffer *buffer;
|
||||||
GeglBuffer *paint_mask;
|
GeglBuffer *paint_mask;
|
||||||
gint paint_mask_x;
|
gint paint_mask_x;
|
||||||
gint paint_mask_y;
|
gint paint_mask_y;
|
||||||
GeglRectangle dirty;
|
gint off_x;
|
||||||
PikaComponentMask component_mask;
|
gint off_y;
|
||||||
|
GeglRectangle dirty;
|
||||||
|
PikaComponentMask component_mask;
|
||||||
PikaMybrushOptions *options;
|
PikaMybrushOptions *options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -382,6 +384,8 @@ pika_mypaint_surface_draw_dab (MyPaintSurface *base_surface,
|
||||||
colorize = opaque * colorize;
|
colorize = opaque * colorize;
|
||||||
|
|
||||||
/* FIXME: This should use the real matrix values to trim aspect_ratio dabs */
|
/* FIXME: This should use the real matrix values to trim aspect_ratio dabs */
|
||||||
|
x += surface->off_x;
|
||||||
|
y += surface->off_y;
|
||||||
dabRect = calculate_dab_roi (x, y, radius);
|
dabRect = calculate_dab_roi (x, y, radius);
|
||||||
gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer));
|
gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer));
|
||||||
|
|
||||||
|
@ -561,5 +565,40 @@ pika_mypaint_surface_new (GeglBuffer *buffer,
|
||||||
surface->paint_mask_y = paint_mask_y;
|
surface->paint_mask_y = paint_mask_y;
|
||||||
surface->dirty = *GEGL_RECTANGLE (0, 0, 0, 0);
|
surface->dirty = *GEGL_RECTANGLE (0, 0, 0, 0);
|
||||||
|
|
||||||
|
surface->off_x = 0;
|
||||||
|
surface->off_y = 0;
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pika_mypaint_surface_set_buffer (PikaMybrushSurface *surface,
|
||||||
|
GeglBuffer *buffer,
|
||||||
|
gint paint_mask_x,
|
||||||
|
gint paint_mask_y)
|
||||||
|
{
|
||||||
|
g_object_unref (surface->buffer);
|
||||||
|
|
||||||
|
surface->buffer = g_object_ref (buffer);
|
||||||
|
|
||||||
|
surface->paint_mask_x = paint_mask_x;
|
||||||
|
surface->paint_mask_y = paint_mask_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pika_mypaint_surface_set_offset (PikaMybrushSurface *surface,
|
||||||
|
gint off_x,
|
||||||
|
gint off_y)
|
||||||
|
{
|
||||||
|
surface->off_x = off_x;
|
||||||
|
surface->off_y = off_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pika_mypaint_surface_get_offset (PikaMybrushSurface *surface,
|
||||||
|
gint *off_x,
|
||||||
|
gint *off_y)
|
||||||
|
{
|
||||||
|
*off_x = surface->off_x;
|
||||||
|
*off_y = surface->off_y;
|
||||||
|
}
|
||||||
|
|
|
@ -33,5 +33,18 @@ pika_mypaint_surface_new (GeglBuffer *buffer,
|
||||||
gint paint_mask_y,
|
gint paint_mask_y,
|
||||||
PikaMybrushOptions *options);
|
PikaMybrushOptions *options);
|
||||||
|
|
||||||
|
void
|
||||||
|
pika_mypaint_surface_set_buffer (PikaMybrushSurface *surface,
|
||||||
|
GeglBuffer *buffer,
|
||||||
|
gint paint_mask_x,
|
||||||
|
gint paint_mask_y);
|
||||||
|
void
|
||||||
|
pika_mypaint_surface_set_offset (PikaMybrushSurface *surface,
|
||||||
|
gint off_x,
|
||||||
|
gint off_y);
|
||||||
|
void
|
||||||
|
pika_mypaint_surface_get_offset (PikaMybrushSurface *surface,
|
||||||
|
gint *off_x,
|
||||||
|
gint *off_y);
|
||||||
|
|
||||||
#endif /* __PIKA_MYBRUSH_SURFACE_H__ */
|
#endif /* __PIKA_MYBRUSH_SURFACE_H__ */
|
||||||
|
|
|
@ -193,7 +193,8 @@ pika_paintbrush_real_get_paint_params (PikaPaintbrush *paintbrush,
|
||||||
|
|
||||||
*paint_mode = pika_context_get_paint_mode (context);
|
*paint_mode = pika_context_get_paint_mode (context);
|
||||||
|
|
||||||
if (pika_paint_options_get_gradient_color (paint_options, image,
|
if (pika_paint_options_are_dynamics_enabled (paint_options) &&
|
||||||
|
pika_paint_options_get_gradient_color (paint_options, image,
|
||||||
grad_point,
|
grad_point,
|
||||||
paint_core->pixel_dist,
|
paint_core->pixel_dist,
|
||||||
paint_color))
|
paint_color))
|
||||||
|
@ -252,6 +253,7 @@ _pika_paintbrush_motion (PikaPaintCore *paint_core,
|
||||||
coords.x -= off_x;
|
coords.x -= off_x;
|
||||||
coords.y -= off_y;
|
coords.y -= off_y;
|
||||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
pika_symmetry_set_origin (sym, drawable, &coords);
|
||||||
|
paint_core->sym = sym;
|
||||||
|
|
||||||
/* Some settings are based on the original stroke. */
|
/* Some settings are based on the original stroke. */
|
||||||
opacity *= pika_dynamics_get_linear_value (dynamics,
|
opacity *= pika_dynamics_get_linear_value (dynamics,
|
||||||
|
@ -313,6 +315,8 @@ _pika_paintbrush_motion (PikaPaintCore *paint_core,
|
||||||
&paint_buffer_y,
|
&paint_buffer_y,
|
||||||
&paint_width,
|
&paint_width,
|
||||||
&paint_height);
|
&paint_height);
|
||||||
|
coords = *(pika_symmetry_get_coords (sym, i));
|
||||||
|
|
||||||
if (! paint_buffer)
|
if (! paint_buffer)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,12 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <cairo.h>
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
#include <gegl.h>
|
#include <gegl.h>
|
||||||
|
|
||||||
#include "libpikabase/pikabase.h"
|
#include "libpikabase/pikabase.h"
|
||||||
|
#include "libpikacolor/pikacolor.h"
|
||||||
#include "libpikamath/pikamath.h"
|
#include "libpikamath/pikamath.h"
|
||||||
|
|
||||||
#include "paint-types.h"
|
#include "paint-types.h"
|
||||||
|
@ -47,6 +49,9 @@
|
||||||
#include "core/pikaimage-guides.h"
|
#include "core/pikaimage-guides.h"
|
||||||
#include "core/pikaimage-symmetry.h"
|
#include "core/pikaimage-symmetry.h"
|
||||||
#include "core/pikaimage-undo.h"
|
#include "core/pikaimage-undo.h"
|
||||||
|
#include "core/pikaimage-undo-push.h"
|
||||||
|
#include "core/pikalayer.h"
|
||||||
|
#include "core/pikalayermask.h"
|
||||||
#include "core/pikapickable.h"
|
#include "core/pikapickable.h"
|
||||||
#include "core/pikaprojection.h"
|
#include "core/pikaprojection.h"
|
||||||
#include "core/pikasymmetry.h"
|
#include "core/pikasymmetry.h"
|
||||||
|
@ -158,7 +163,10 @@ static void
|
||||||
pika_paint_core_init (PikaPaintCore *core)
|
pika_paint_core_init (PikaPaintCore *core)
|
||||||
{
|
{
|
||||||
core->ID = global_core_ID++;
|
core->ID = global_core_ID++;
|
||||||
core->undo_buffers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
core->undo_buffers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
|
NULL, g_object_unref);
|
||||||
|
core->original_bounds = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
|
NULL, g_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -170,6 +178,7 @@ pika_paint_core_finalize (GObject *object)
|
||||||
|
|
||||||
g_clear_pointer (&core->undo_desc, g_free);
|
g_clear_pointer (&core->undo_desc, g_free);
|
||||||
g_hash_table_unref (core->undo_buffers);
|
g_hash_table_unref (core->undo_buffers);
|
||||||
|
g_hash_table_unref (core->original_bounds);
|
||||||
if (core->applicators)
|
if (core->applicators)
|
||||||
g_hash_table_unref (core->applicators);
|
g_hash_table_unref (core->applicators);
|
||||||
|
|
||||||
|
@ -357,10 +366,11 @@ pika_paint_core_start (PikaPaintCore *core,
|
||||||
const PikaCoords *coords,
|
const PikaCoords *coords,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
PikaImage *image;
|
PikaImage *image;
|
||||||
PikaChannel *mask;
|
PikaChannel *mask;
|
||||||
gint max_width = 0;
|
gint max_width = 0;
|
||||||
gint max_height = 0;
|
gint max_height = 0;
|
||||||
|
GeglRectangle *rect;
|
||||||
|
|
||||||
g_return_val_if_fail (PIKA_IS_PAINT_CORE (core), FALSE);
|
g_return_val_if_fail (PIKA_IS_PAINT_CORE (core), FALSE);
|
||||||
g_return_val_if_fail (g_list_length (drawables) > 0, FALSE);
|
g_return_val_if_fail (g_list_length (drawables) > 0, FALSE);
|
||||||
|
@ -418,8 +428,16 @@ pika_paint_core_start (PikaPaintCore *core,
|
||||||
for (GList *iter = drawables; iter; iter = iter->next)
|
for (GList *iter = drawables; iter; iter = iter->next)
|
||||||
{
|
{
|
||||||
/* Allocate the undo structures */
|
/* Allocate the undo structures */
|
||||||
|
rect = g_new (GeglRectangle, 1);
|
||||||
|
rect->width = pika_item_get_width (PIKA_ITEM (iter->data));
|
||||||
|
rect->height = pika_item_get_height (PIKA_ITEM (iter->data));
|
||||||
|
pika_item_get_offset (PIKA_ITEM (iter->data), &rect->x, &rect->y);
|
||||||
|
|
||||||
|
g_hash_table_insert (core->original_bounds, iter->data,
|
||||||
|
rect);
|
||||||
g_hash_table_insert (core->undo_buffers, iter->data,
|
g_hash_table_insert (core->undo_buffers, iter->data,
|
||||||
pika_gegl_buffer_dup (pika_drawable_get_buffer (iter->data)));
|
pika_gegl_buffer_dup (pika_drawable_get_buffer (iter->data)));
|
||||||
|
|
||||||
max_width = MAX (max_width, pika_item_get_width (iter->data));
|
max_width = MAX (max_width, pika_item_get_width (iter->data));
|
||||||
max_height = MAX (max_height, pika_item_get_height (iter->data));
|
max_height = MAX (max_height, pika_item_get_height (iter->data));
|
||||||
}
|
}
|
||||||
|
@ -484,6 +502,9 @@ pika_paint_core_start (PikaPaintCore *core,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* initialize the lock_blink_state */
|
||||||
|
core->lock_blink_state = PIKA_PAINT_LOCK_NOT_BLINKED;
|
||||||
|
|
||||||
/* Freeze the drawable preview so that it isn't constantly updated. */
|
/* Freeze the drawable preview so that it isn't constantly updated. */
|
||||||
for (GList *iter = drawables; iter; iter = iter->next)
|
for (GList *iter = drawables; iter; iter = iter->next)
|
||||||
pika_viewable_preview_freeze (PIKA_VIEWABLE (iter->data));
|
pika_viewable_preview_freeze (PIKA_VIEWABLE (iter->data));
|
||||||
|
@ -532,7 +553,9 @@ pika_paint_core_finish (PikaPaintCore *core,
|
||||||
{
|
{
|
||||||
GeglBuffer *undo_buffer;
|
GeglBuffer *undo_buffer;
|
||||||
GeglBuffer *buffer;
|
GeglBuffer *buffer;
|
||||||
|
GeglBuffer *drawable_buffer;
|
||||||
GeglRectangle rect;
|
GeglRectangle rect;
|
||||||
|
GeglRectangle old_rect;
|
||||||
|
|
||||||
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
|
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
|
||||||
NULL, (gpointer*) &undo_buffer))
|
NULL, (gpointer*) &undo_buffer))
|
||||||
|
@ -542,16 +565,6 @@ pika_paint_core_finish (PikaPaintCore *core,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pika_rectangle_intersect (core->x1, core->y1,
|
|
||||||
core->x2 - core->x1, core->y2 - core->y1,
|
|
||||||
0, 0,
|
|
||||||
pika_item_get_width (PIKA_ITEM (iter->data)),
|
|
||||||
pika_item_get_height (PIKA_ITEM (iter->data)),
|
|
||||||
&rect.x, &rect.y, &rect.width, &rect.height);
|
|
||||||
|
|
||||||
gegl_rectangle_align_to_buffer (&rect, &rect, undo_buffer,
|
|
||||||
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
|
||||||
|
|
||||||
if (! undo_group_started)
|
if (! undo_group_started)
|
||||||
{
|
{
|
||||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_PAINT,
|
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_PAINT,
|
||||||
|
@ -559,19 +572,115 @@ pika_paint_core_finish (PikaPaintCore *core,
|
||||||
undo_group_started = TRUE;
|
undo_group_started = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PIKA_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
|
/* get new and old bounds of drawable */
|
||||||
|
old_rect = *(GeglRectangle*) g_hash_table_lookup (core->original_bounds, iter->data);
|
||||||
|
|
||||||
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
|
pika_item_get_offset (PIKA_ITEM (iter->data), &rect.x, &rect.y);
|
||||||
pika_drawable_get_format (iter->data));
|
rect.width = pika_item_get_width (PIKA_ITEM (iter->data));
|
||||||
|
rect.height = pika_item_get_height (PIKA_ITEM (iter->data));
|
||||||
|
|
||||||
pika_gegl_buffer_copy (undo_buffer,
|
/* Making copy of entire buffer consumes more memory, so do that only when buffer has resized */
|
||||||
&rect,
|
if (rect.x == old_rect.x &&
|
||||||
GEGL_ABYSS_NONE,
|
rect.y == old_rect.y &&
|
||||||
buffer,
|
rect.width == old_rect.width &&
|
||||||
GEGL_RECTANGLE (0, 0, 0, 0));
|
rect.height == old_rect.height)
|
||||||
|
{
|
||||||
|
pika_rectangle_intersect (core->x1, core->y1, core->x2 - core->x1,
|
||||||
|
core->y2 - core->y1, 0, 0,
|
||||||
|
pika_item_get_width (PIKA_ITEM (iter->data)),
|
||||||
|
pika_item_get_height (PIKA_ITEM (iter->data)),
|
||||||
|
&rect.x, &rect.y, &rect.width, &rect.height);
|
||||||
|
|
||||||
pika_drawable_push_undo (iter->data, NULL,
|
gegl_rectangle_align_to_buffer (&rect, &rect, undo_buffer,
|
||||||
buffer, rect.x, rect.y, rect.width, rect.height);
|
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
||||||
|
|
||||||
|
PIKA_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
|
||||||
|
|
||||||
|
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
|
||||||
|
pika_drawable_get_format (iter->data));
|
||||||
|
|
||||||
|
pika_gegl_buffer_copy (undo_buffer,
|
||||||
|
&rect,
|
||||||
|
GEGL_ABYSS_NONE,
|
||||||
|
buffer,
|
||||||
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||||
|
|
||||||
|
pika_drawable_push_undo (iter->data, NULL,
|
||||||
|
buffer, rect.x, rect.y, rect.width, rect.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* drawable is expanded only if drawable is layer or layer mask*/
|
||||||
|
g_return_if_fail (PIKA_IS_LAYER (iter->data) || PIKA_IS_LAYER_MASK (iter->data));
|
||||||
|
|
||||||
|
/* create a copy of original buffer from undo data */
|
||||||
|
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
pika_drawable_get_format (iter->data));
|
||||||
|
|
||||||
|
pika_gegl_buffer_copy (undo_buffer,
|
||||||
|
GEGL_RECTANGLE (old_rect.x - rect.x,
|
||||||
|
old_rect.y - rect.y,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
GEGL_ABYSS_NONE,
|
||||||
|
buffer,
|
||||||
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||||
|
|
||||||
|
/* make a backup copy of drawable to restore */
|
||||||
|
drawable_buffer = g_object_ref (pika_drawable_get_buffer (PIKA_DRAWABLE (iter->data)));
|
||||||
|
|
||||||
|
if (PIKA_IS_LAYER_MASK (drawables->data) || PIKA_LAYER (drawables->data)->mask)
|
||||||
|
{
|
||||||
|
GeglBuffer *other_new;
|
||||||
|
GeglBuffer *other_old;
|
||||||
|
PikaDrawable *other_drawable;
|
||||||
|
|
||||||
|
if (PIKA_IS_LAYER_MASK (drawables->data))
|
||||||
|
other_drawable = PIKA_DRAWABLE ((PIKA_LAYER_MASK (drawables->data))->layer);
|
||||||
|
else
|
||||||
|
other_drawable = PIKA_DRAWABLE (PIKA_LAYER (drawables->data)->mask);
|
||||||
|
|
||||||
|
/* create a copy of original buffer by taking the required area */
|
||||||
|
other_old = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
pika_drawable_get_format (other_drawable));
|
||||||
|
|
||||||
|
pika_gegl_buffer_copy (pika_drawable_get_buffer (other_drawable),
|
||||||
|
GEGL_RECTANGLE (old_rect.x - rect.x,
|
||||||
|
old_rect.y - rect.y,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
GEGL_ABYSS_NONE,
|
||||||
|
other_old,
|
||||||
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||||
|
|
||||||
|
/* make a backup copy of drawable to restore */
|
||||||
|
other_new = g_object_ref (pika_drawable_get_buffer (other_drawable));
|
||||||
|
|
||||||
|
pika_drawable_set_buffer_full (other_drawable, FALSE, NULL,
|
||||||
|
other_old, &old_rect,
|
||||||
|
FALSE);
|
||||||
|
pika_drawable_set_buffer_full (other_drawable, TRUE, NULL,
|
||||||
|
other_new, &rect,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
g_object_unref (other_new);
|
||||||
|
g_object_unref (other_old);
|
||||||
|
}
|
||||||
|
/* Restore drawable to state before painting started */
|
||||||
|
pika_drawable_set_buffer_full (iter->data, FALSE, NULL,
|
||||||
|
buffer, &old_rect,
|
||||||
|
FALSE);
|
||||||
|
/* Change the drawable again but push undo this time */
|
||||||
|
pika_drawable_set_buffer_full (iter->data, TRUE, NULL,
|
||||||
|
drawable_buffer, &rect,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
g_object_unref (drawable_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
g_object_unref (buffer);
|
g_object_unref (buffer);
|
||||||
g_object_unref (undo_buffer);
|
g_object_unref (undo_buffer);
|
||||||
|
@ -614,7 +723,8 @@ pika_paint_core_cancel (PikaPaintCore *core,
|
||||||
&x, &y, &width, &height))
|
&x, &y, &width, &height))
|
||||||
{
|
{
|
||||||
GeglBuffer *undo_buffer;
|
GeglBuffer *undo_buffer;
|
||||||
GeglRectangle rect;
|
GeglRectangle new_rect;
|
||||||
|
GeglRectangle old_rect;
|
||||||
|
|
||||||
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
|
if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
|
||||||
NULL, (gpointer*) &undo_buffer))
|
NULL, (gpointer*) &undo_buffer))
|
||||||
|
@ -624,21 +734,108 @@ pika_paint_core_cancel (PikaPaintCore *core,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
gegl_rectangle_align_to_buffer (&rect,
|
old_rect = *(GeglRectangle*) g_hash_table_lookup (core->original_bounds, iter->data);
|
||||||
GEGL_RECTANGLE (x, y, width, height),
|
|
||||||
pika_drawable_get_buffer (iter->data),
|
pika_item_get_offset (PIKA_ITEM (iter->data), &new_rect.x, &new_rect.y);
|
||||||
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
new_rect.width = pika_item_get_width (PIKA_ITEM (iter->data));
|
||||||
|
new_rect.height = pika_item_get_height (PIKA_ITEM (iter->data));
|
||||||
|
|
||||||
|
if (new_rect.x == old_rect.x &&
|
||||||
|
new_rect.y == old_rect.y &&
|
||||||
|
new_rect.width == old_rect.width &&
|
||||||
|
new_rect.height == old_rect.height)
|
||||||
|
{
|
||||||
|
GeglRectangle rect;
|
||||||
|
|
||||||
|
gegl_rectangle_align_to_buffer (&rect,
|
||||||
|
GEGL_RECTANGLE (x, y, width, height),
|
||||||
|
pika_drawable_get_buffer (iter->data),
|
||||||
|
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
||||||
|
|
||||||
|
pika_gegl_buffer_copy (undo_buffer,
|
||||||
|
&rect,
|
||||||
|
GEGL_ABYSS_NONE,
|
||||||
|
pika_drawable_get_buffer (iter->data),
|
||||||
|
&rect);
|
||||||
|
|
||||||
|
pika_drawable_update (iter->data, x, y, width, height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GeglBuffer *buffer;
|
||||||
|
GeglRectangle bbox;
|
||||||
|
|
||||||
|
/* drawable is expanded only if drawable is layer or layer mask,
|
||||||
|
* so drawable cannot be anything else */
|
||||||
|
g_return_if_fail (PIKA_IS_LAYER (iter->data) || PIKA_IS_LAYER_MASK (iter->data));
|
||||||
|
|
||||||
|
/* When canceling painting with drawable expansion, ensure that
|
||||||
|
* the drawable display outside the reverted size is not shown. We
|
||||||
|
* cannot use pika_drawable_update() because it won't work while
|
||||||
|
* painting. Directly emit the "update" signal.
|
||||||
|
* */
|
||||||
|
bbox = pika_drawable_get_bounding_box (iter->data);
|
||||||
|
g_signal_emit_by_name (iter->data, "update", bbox.x, bbox.y, bbox.width, bbox.height);
|
||||||
|
|
||||||
|
/* create a copy of original buffer from undo data */
|
||||||
|
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
pika_drawable_get_format (iter->data));
|
||||||
|
|
||||||
|
pika_gegl_buffer_copy (undo_buffer,
|
||||||
|
GEGL_RECTANGLE (old_rect.x - new_rect.x,
|
||||||
|
old_rect.y - new_rect.y,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
GEGL_ABYSS_NONE,
|
||||||
|
buffer,
|
||||||
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||||
|
|
||||||
|
if (PIKA_IS_LAYER_MASK (drawables->data) || PIKA_LAYER (drawables->data)->mask)
|
||||||
|
{
|
||||||
|
GeglBuffer *other_old;
|
||||||
|
PikaDrawable *other_drawable;
|
||||||
|
|
||||||
|
if (PIKA_IS_LAYER_MASK (drawables->data))
|
||||||
|
other_drawable = PIKA_DRAWABLE ((PIKA_LAYER_MASK (drawables->data))->layer);
|
||||||
|
else
|
||||||
|
other_drawable = PIKA_DRAWABLE (PIKA_LAYER (drawables->data)->mask);
|
||||||
|
|
||||||
|
/* create a copy of original buffer by taking the required area */
|
||||||
|
other_old = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
pika_drawable_get_format (other_drawable));
|
||||||
|
|
||||||
|
pika_gegl_buffer_copy (pika_drawable_get_buffer (other_drawable),
|
||||||
|
GEGL_RECTANGLE (old_rect.x - new_rect.x,
|
||||||
|
old_rect.y - new_rect.y,
|
||||||
|
old_rect.width,
|
||||||
|
old_rect.height),
|
||||||
|
GEGL_ABYSS_NONE,
|
||||||
|
other_old,
|
||||||
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
||||||
|
|
||||||
|
pika_drawable_set_buffer_full (other_drawable, FALSE, NULL,
|
||||||
|
other_old, &old_rect,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
g_object_unref (other_old);
|
||||||
|
}
|
||||||
|
/* Restore drawable to state before painting started */
|
||||||
|
pika_drawable_set_buffer_full (iter->data, FALSE, NULL,
|
||||||
|
buffer, &old_rect,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
pika_drawable_update (iter->data, 0, 0, -1, -1);
|
||||||
|
|
||||||
|
g_object_unref (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
pika_gegl_buffer_copy (undo_buffer,
|
|
||||||
&rect,
|
|
||||||
GEGL_ABYSS_NONE,
|
|
||||||
pika_drawable_get_buffer (iter->data),
|
|
||||||
&rect);
|
|
||||||
g_object_unref (undo_buffer);
|
g_object_unref (undo_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pika_drawable_update (iter->data, x, y, width, height);
|
|
||||||
|
|
||||||
pika_viewable_preview_thaw (PIKA_VIEWABLE (iter->data));
|
pika_viewable_preview_thaw (PIKA_VIEWABLE (iter->data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,6 +848,7 @@ pika_paint_core_cleanup (PikaPaintCore *core)
|
||||||
g_return_if_fail (PIKA_IS_PAINT_CORE (core));
|
g_return_if_fail (PIKA_IS_PAINT_CORE (core));
|
||||||
|
|
||||||
g_hash_table_remove_all (core->undo_buffers);
|
g_hash_table_remove_all (core->undo_buffers);
|
||||||
|
g_hash_table_remove_all (core->original_bounds);
|
||||||
|
|
||||||
g_clear_object (&core->saved_proj_buffer);
|
g_clear_object (&core->saved_proj_buffer);
|
||||||
g_clear_object (&core->canvas_buffer);
|
g_clear_object (&core->canvas_buffer);
|
||||||
|
@ -692,6 +890,227 @@ pika_paint_core_get_show_all (PikaPaintCore *core)
|
||||||
return core->show_all;
|
return core->show_all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
pika_paint_core_expand_drawable (PikaPaintCore *core,
|
||||||
|
PikaDrawable *drawable,
|
||||||
|
PikaPaintOptions *options,
|
||||||
|
gint x1,
|
||||||
|
gint x2,
|
||||||
|
gint y1,
|
||||||
|
gint y2,
|
||||||
|
gint *new_off_x,
|
||||||
|
gint *new_off_y)
|
||||||
|
{
|
||||||
|
gint drawable_width, drawable_height;
|
||||||
|
gint drawable_offset_x, drawable_offset_y;
|
||||||
|
gint image_width, image_height;
|
||||||
|
gint new_width, new_height;
|
||||||
|
gint expand_amount;
|
||||||
|
gboolean show_all;
|
||||||
|
gboolean outside_image;
|
||||||
|
PikaImage *image = pika_item_get_image (PIKA_ITEM (drawable));
|
||||||
|
PikaLayer *layer;
|
||||||
|
|
||||||
|
drawable_width = pika_item_get_width (PIKA_ITEM (drawable));
|
||||||
|
drawable_height = pika_item_get_height (PIKA_ITEM (drawable));
|
||||||
|
pika_item_get_offset (PIKA_ITEM (drawable), &drawable_offset_x, &drawable_offset_y);
|
||||||
|
|
||||||
|
new_width = drawable_width;
|
||||||
|
new_height = drawable_height;
|
||||||
|
*new_off_x = 0;
|
||||||
|
*new_off_y = 0;
|
||||||
|
|
||||||
|
image_width = pika_image_get_width (image);
|
||||||
|
image_height = pika_image_get_height (image);
|
||||||
|
|
||||||
|
expand_amount = options->expand_amount;
|
||||||
|
show_all = pika_paint_core_get_show_all (core);
|
||||||
|
outside_image = x2 < -drawable_offset_x || x1 > image_width - drawable_offset_x ||
|
||||||
|
y2 < -drawable_offset_y || y1 > image_height - drawable_offset_y;
|
||||||
|
|
||||||
|
/* Don't expand if drawable is anything other
|
||||||
|
* than layer or layer mask */
|
||||||
|
if (PIKA_IS_LAYER_MASK (drawable))
|
||||||
|
layer = (PIKA_LAYER_MASK (drawable))->layer;
|
||||||
|
else if (PIKA_IS_LAYER (drawable))
|
||||||
|
layer = PIKA_LAYER (drawable);
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!pika_paint_core_get_show_all (core) && outside_image)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!options->expand_use)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (x1 < 0)
|
||||||
|
{
|
||||||
|
if (show_all)
|
||||||
|
{
|
||||||
|
new_width += expand_amount - x1;
|
||||||
|
*new_off_x += expand_amount - x1;
|
||||||
|
}
|
||||||
|
else if (drawable_offset_x > 0)
|
||||||
|
{
|
||||||
|
new_width += expand_amount - x1;
|
||||||
|
*new_off_x += expand_amount - x1;
|
||||||
|
if (*new_off_x > drawable_offset_x)
|
||||||
|
{
|
||||||
|
new_width -= *new_off_x - drawable_offset_x;
|
||||||
|
*new_off_x = drawable_offset_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y1 < 0)
|
||||||
|
{
|
||||||
|
if (show_all)
|
||||||
|
{
|
||||||
|
new_height += expand_amount - y1;
|
||||||
|
*new_off_y += expand_amount - y1;
|
||||||
|
}
|
||||||
|
else if (drawable_offset_y > 0)
|
||||||
|
{
|
||||||
|
new_height += expand_amount - y1;
|
||||||
|
*new_off_y += expand_amount - y1;
|
||||||
|
if (*new_off_y > drawable_offset_y)
|
||||||
|
{
|
||||||
|
new_height -= *new_off_y - drawable_offset_y;
|
||||||
|
*new_off_y = drawable_offset_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x2 > drawable_width)
|
||||||
|
{
|
||||||
|
if (show_all)
|
||||||
|
{
|
||||||
|
new_width += x2 - drawable_width + expand_amount;
|
||||||
|
}
|
||||||
|
else if (drawable_width + drawable_offset_x < image_width)
|
||||||
|
{
|
||||||
|
new_width += x2 - drawable_width + expand_amount;
|
||||||
|
if (new_width + drawable_offset_x - *new_off_x > image_width)
|
||||||
|
new_width = image_width + *new_off_x - drawable_offset_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y2 > drawable_height)
|
||||||
|
{
|
||||||
|
if (show_all)
|
||||||
|
{
|
||||||
|
new_height += y2 - drawable_height + expand_amount;
|
||||||
|
}
|
||||||
|
else if (drawable_height + drawable_offset_y < image_height)
|
||||||
|
{
|
||||||
|
new_height += y2 - drawable_height + expand_amount;
|
||||||
|
if (new_height + drawable_offset_y - *new_off_y > image_height)
|
||||||
|
new_height = image_height + *new_off_y - drawable_offset_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_width != drawable_width || *new_off_x ||
|
||||||
|
new_height != drawable_height || *new_off_y)
|
||||||
|
{
|
||||||
|
PikaRGB color;
|
||||||
|
PikaPattern *pattern;
|
||||||
|
PikaContext *context = PIKA_CONTEXT (options);
|
||||||
|
PikaFillType fill_type = options->expand_fill_type;
|
||||||
|
gboolean context_has_image;
|
||||||
|
PikaFillType mask_fill_type;
|
||||||
|
GeglBuffer *undo_buffer;
|
||||||
|
GeglBuffer *new_buffer;
|
||||||
|
|
||||||
|
if (pika_item_get_lock_position (PIKA_ITEM (layer)))
|
||||||
|
{
|
||||||
|
if (core->lock_blink_state == PIKA_PAINT_LOCK_NOT_BLINKED)
|
||||||
|
core->lock_blink_state = PIKA_PAINT_LOCK_BLINK_PENDING;
|
||||||
|
|
||||||
|
/* Since we are not expanding, set new offset to zero */
|
||||||
|
*new_off_x = 0;
|
||||||
|
*new_off_y = 0;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask_fill_type = options->expand_mask_fill_type == PIKA_ADD_MASK_BLACK ?
|
||||||
|
PIKA_FILL_TRANSPARENT :
|
||||||
|
PIKA_FILL_WHITE;
|
||||||
|
|
||||||
|
/* The image field of context is null but
|
||||||
|
* is required for Filling with Middle Gray */
|
||||||
|
context_has_image = context->image != NULL;
|
||||||
|
if (!context_has_image)
|
||||||
|
context->image = image;
|
||||||
|
|
||||||
|
/* ensure that every expansion is pushed to undo stack */
|
||||||
|
if (core->x2 == core->x1)
|
||||||
|
core->x2++;
|
||||||
|
if (core->y2 == core->y1)
|
||||||
|
core->y2++;
|
||||||
|
|
||||||
|
g_object_freeze_notify (G_OBJECT (layer));
|
||||||
|
|
||||||
|
pika_drawable_disable_resize_undo (PIKA_DRAWABLE (layer));
|
||||||
|
PIKA_LAYER_GET_CLASS (layer)->resize (layer, context, fill_type,
|
||||||
|
new_width, new_height,
|
||||||
|
*new_off_x, *new_off_y);
|
||||||
|
pika_drawable_enable_resize_undo (PIKA_DRAWABLE (layer));
|
||||||
|
|
||||||
|
if (layer->mask)
|
||||||
|
{
|
||||||
|
g_object_freeze_notify (G_OBJECT (layer->mask));
|
||||||
|
|
||||||
|
pika_drawable_disable_resize_undo (PIKA_DRAWABLE (layer->mask));
|
||||||
|
PIKA_ITEM_GET_CLASS (layer->mask)->resize (PIKA_ITEM (layer->mask), context,
|
||||||
|
mask_fill_type, new_width, new_height,
|
||||||
|
*new_off_x, *new_off_y);
|
||||||
|
pika_drawable_enable_resize_undo (PIKA_DRAWABLE (layer->mask));
|
||||||
|
|
||||||
|
g_object_thaw_notify (G_OBJECT (layer->mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_thaw_notify (G_OBJECT (layer));
|
||||||
|
|
||||||
|
pika_image_flush (image);
|
||||||
|
|
||||||
|
if (PIKA_IS_LAYER_MASK (drawable))
|
||||||
|
{
|
||||||
|
fill_type = mask_fill_type;
|
||||||
|
}
|
||||||
|
else if (fill_type == PIKA_FILL_TRANSPARENT &&
|
||||||
|
! pika_drawable_has_alpha (drawable))
|
||||||
|
{
|
||||||
|
fill_type = PIKA_FILL_BACKGROUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_buffer = pika_gegl_buffer_resize (core->canvas_buffer, new_width, new_height,
|
||||||
|
-(*new_off_x), -(*new_off_y), NULL, NULL, 0, 0);
|
||||||
|
g_object_unref (core->canvas_buffer);
|
||||||
|
core->canvas_buffer = new_buffer;
|
||||||
|
|
||||||
|
pika_get_fill_params (context, fill_type, &color, &pattern, NULL);
|
||||||
|
pika_pickable_srgb_to_image_color (PIKA_PICKABLE (drawable),
|
||||||
|
&color, &color);
|
||||||
|
if (! pika_drawable_has_alpha (drawable))
|
||||||
|
pika_rgb_set_alpha (&color, 1.0);
|
||||||
|
|
||||||
|
undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
|
||||||
|
g_object_ref (undo_buffer);
|
||||||
|
|
||||||
|
new_buffer = pika_gegl_buffer_resize (undo_buffer, new_width, new_height,
|
||||||
|
-(*new_off_x), -(*new_off_y), &color,
|
||||||
|
pattern, 0, 0);
|
||||||
|
g_hash_table_insert (core->undo_buffers, drawable, new_buffer);
|
||||||
|
g_object_unref (undo_buffer);
|
||||||
|
|
||||||
|
/* Restore context to its original state */
|
||||||
|
if (!context_has_image)
|
||||||
|
context->image = NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pika_paint_core_set_current_coords (PikaPaintCore *core,
|
pika_paint_core_set_current_coords (PikaPaintCore *core,
|
||||||
const PikaCoords *coords)
|
const PikaCoords *coords)
|
||||||
|
|
|
@ -69,12 +69,17 @@ struct _PikaPaintCore
|
||||||
GeglBuffer *paint_buffer; /* the buffer to paint pixels to */
|
GeglBuffer *paint_buffer; /* the buffer to paint pixels to */
|
||||||
gint paint_buffer_x;
|
gint paint_buffer_x;
|
||||||
gint paint_buffer_y;
|
gint paint_buffer_y;
|
||||||
|
GHashTable *original_bounds; /* the original bounds of drawables */
|
||||||
|
|
||||||
GeglBuffer *mask_buffer; /* the target drawable's mask */
|
GeglBuffer *mask_buffer; /* the target drawable's mask */
|
||||||
|
|
||||||
GHashTable *applicators;
|
GHashTable *applicators;
|
||||||
|
|
||||||
GArray *stroke_buffer;
|
GArray *stroke_buffer;
|
||||||
|
|
||||||
|
PikaSymmetry *sym;
|
||||||
|
PikaPaintLockBlinkState
|
||||||
|
lock_blink_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _PikaPaintCoreClass
|
struct _PikaPaintCoreClass
|
||||||
|
@ -156,6 +161,16 @@ void pika_paint_core_set_show_all (PikaPaintCore *core,
|
||||||
gboolean show_all);
|
gboolean show_all);
|
||||||
gboolean pika_paint_core_get_show_all (PikaPaintCore *core);
|
gboolean pika_paint_core_get_show_all (PikaPaintCore *core);
|
||||||
|
|
||||||
|
gboolean pika_paint_core_expand_drawable (PikaPaintCore *paint_core,
|
||||||
|
PikaDrawable *drawable,
|
||||||
|
PikaPaintOptions *paint_options,
|
||||||
|
gint x1,
|
||||||
|
gint x2,
|
||||||
|
gint y1,
|
||||||
|
gint y2,
|
||||||
|
gint *x,
|
||||||
|
gint *y);
|
||||||
|
|
||||||
void pika_paint_core_set_current_coords (PikaPaintCore *core,
|
void pika_paint_core_set_current_coords (PikaPaintCore *core,
|
||||||
const PikaCoords *coords);
|
const PikaCoords *coords);
|
||||||
void pika_paint_core_get_current_coords (PikaPaintCore *core,
|
void pika_paint_core_get_current_coords (PikaPaintCore *core,
|
||||||
|
|
|
@ -83,6 +83,11 @@
|
||||||
#define DEFAULT_SMOOTHING_QUALITY 20
|
#define DEFAULT_SMOOTHING_QUALITY 20
|
||||||
#define DEFAULT_SMOOTHING_FACTOR 50
|
#define DEFAULT_SMOOTHING_FACTOR 50
|
||||||
|
|
||||||
|
#define DEFAULT_EXPAND_USE FALSE
|
||||||
|
#define DEFAULT_EXPAND_AMOUNT 100.0
|
||||||
|
#define DEFAULT_EXPAND_FILL_TYPE PIKA_FILL_TRANSPARENT
|
||||||
|
#define DEFAULT_EXPAND_MASK_FILL_TYPE PIKA_ADD_MASK_WHITE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
@ -134,7 +139,12 @@ enum
|
||||||
|
|
||||||
PROP_USE_SMOOTHING,
|
PROP_USE_SMOOTHING,
|
||||||
PROP_SMOOTHING_QUALITY,
|
PROP_SMOOTHING_QUALITY,
|
||||||
PROP_SMOOTHING_FACTOR
|
PROP_SMOOTHING_FACTOR,
|
||||||
|
|
||||||
|
PROP_EXPAND_USE,
|
||||||
|
PROP_EXPAND_AMOUNT,
|
||||||
|
PROP_EXPAND_FILL_TYPE,
|
||||||
|
PROP_EXPAND_MASK_FILL_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,6 +318,36 @@ pika_paint_options_class_init (PikaPaintOptionsClass *klass)
|
||||||
DEFAULT_USE_JITTER,
|
DEFAULT_USE_JITTER,
|
||||||
PIKA_PARAM_STATIC_STRINGS);
|
PIKA_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_EXPAND_USE,
|
||||||
|
"expand-use",
|
||||||
|
_("Expand Layers"),
|
||||||
|
_("Expand active layer as you paint"),
|
||||||
|
DEFAULT_EXPAND_USE,
|
||||||
|
PIKA_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
PIKA_CONFIG_PROP_DOUBLE (object_class, PROP_EXPAND_AMOUNT,
|
||||||
|
"expand-amount",
|
||||||
|
_("Amount"),
|
||||||
|
_("Amount of expansion"),
|
||||||
|
1.0, 1000.0, DEFAULT_EXPAND_AMOUNT,
|
||||||
|
PIKA_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
PIKA_CONFIG_PROP_ENUM (object_class, PROP_EXPAND_FILL_TYPE,
|
||||||
|
"expand-fill-type",
|
||||||
|
_("Fill With"),
|
||||||
|
_("Fill layer with"),
|
||||||
|
PIKA_TYPE_FILL_TYPE,
|
||||||
|
DEFAULT_EXPAND_FILL_TYPE,
|
||||||
|
PIKA_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
PIKA_CONFIG_PROP_ENUM (object_class, PROP_EXPAND_MASK_FILL_TYPE,
|
||||||
|
"expand-mask-fill-type",
|
||||||
|
_("Fill Mask With"),
|
||||||
|
_("Fill layer mask with"),
|
||||||
|
PIKA_TYPE_ADD_MASK_TYPE,
|
||||||
|
DEFAULT_EXPAND_MASK_FILL_TYPE,
|
||||||
|
PIKA_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_DYNAMICS_ENABLED,
|
PIKA_CONFIG_PROP_BOOLEAN (object_class, PROP_DYNAMICS_ENABLED,
|
||||||
"dynamics-enabled",
|
"dynamics-enabled",
|
||||||
_("Enable dynamics"),
|
_("Enable dynamics"),
|
||||||
|
@ -642,6 +682,19 @@ pika_paint_options_set_property (GObject *object,
|
||||||
smoothing_options->smoothing_factor = g_value_get_double (value);
|
smoothing_options->smoothing_factor = g_value_get_double (value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_EXPAND_USE:
|
||||||
|
options->expand_use = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
|
case PROP_EXPAND_AMOUNT:
|
||||||
|
options->expand_amount = g_value_get_double (value);
|
||||||
|
break;
|
||||||
|
case PROP_EXPAND_FILL_TYPE:
|
||||||
|
options->expand_fill_type = g_value_get_enum (value);
|
||||||
|
break;
|
||||||
|
case PROP_EXPAND_MASK_FILL_TYPE:
|
||||||
|
options->expand_mask_fill_type = g_value_get_enum (value);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -788,6 +841,19 @@ pika_paint_options_get_property (GObject *object,
|
||||||
g_value_set_double (value, smoothing_options->smoothing_factor);
|
g_value_set_double (value, smoothing_options->smoothing_factor);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_EXPAND_USE:
|
||||||
|
g_value_set_boolean (value, options->expand_use);
|
||||||
|
break;
|
||||||
|
case PROP_EXPAND_AMOUNT:
|
||||||
|
g_value_set_double (value, options->expand_amount);
|
||||||
|
break;
|
||||||
|
case PROP_EXPAND_FILL_TYPE:
|
||||||
|
g_value_set_enum (value, options->expand_fill_type);
|
||||||
|
break;
|
||||||
|
case PROP_EXPAND_MASK_FILL_TYPE:
|
||||||
|
g_value_set_enum (value, options->expand_mask_fill_type);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -1221,9 +1287,18 @@ static const gchar *gradient_props[] =
|
||||||
"gradient-repeat"
|
"gradient-repeat"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const gchar *expand_props[] =
|
||||||
|
{
|
||||||
|
"expand-use",
|
||||||
|
"expand-amount",
|
||||||
|
"expand-fill-type",
|
||||||
|
"expand-mask-fill-type",
|
||||||
|
};
|
||||||
|
|
||||||
static const gint max_n_props = (G_N_ELEMENTS (brush_props) +
|
static const gint max_n_props = (G_N_ELEMENTS (brush_props) +
|
||||||
G_N_ELEMENTS (dynamics_props) +
|
G_N_ELEMENTS (dynamics_props) +
|
||||||
G_N_ELEMENTS (gradient_props));
|
G_N_ELEMENTS (gradient_props) +
|
||||||
|
G_N_ELEMENTS (expand_props));
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
pika_paint_options_is_prop (const gchar *prop_name,
|
pika_paint_options_is_prop (const gchar *prop_name,
|
||||||
|
@ -1254,6 +1329,13 @@ pika_paint_options_is_prop (const gchar *prop_name,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prop_mask & PIKA_CONTEXT_PROP_MASK_EXPAND)
|
||||||
|
{
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (expand_props); i++)
|
||||||
|
if (! strcmp (prop_name, expand_props[i]))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1288,6 +1370,12 @@ pika_paint_options_copy_props (PikaPaintOptions *src,
|
||||||
names[n_props++] = gradient_props[i];
|
names[n_props++] = gradient_props[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prop_mask & PIKA_CONTEXT_PROP_MASK_EXPAND)
|
||||||
|
{
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (expand_props); i++)
|
||||||
|
names[n_props++] = expand_props[i];
|
||||||
|
}
|
||||||
|
|
||||||
if (n_props > 0)
|
if (n_props > 0)
|
||||||
{
|
{
|
||||||
g_object_getv (G_OBJECT (src), n_props, names, values);
|
g_object_getv (G_OBJECT (src), n_props, names, values);
|
||||||
|
|
|
@ -109,6 +109,11 @@ struct _PikaPaintOptions
|
||||||
|
|
||||||
gboolean hard;
|
gboolean hard;
|
||||||
|
|
||||||
|
gboolean expand_use;
|
||||||
|
gdouble expand_amount;
|
||||||
|
PikaFillType expand_fill_type;
|
||||||
|
PikaAddMaskType expand_mask_fill_type;
|
||||||
|
|
||||||
PikaJitterOptions *jitter_options;
|
PikaJitterOptions *jitter_options;
|
||||||
|
|
||||||
gboolean dynamics_enabled;
|
gboolean dynamics_enabled;
|
||||||
|
|
|
@ -406,6 +406,7 @@ pika_smudge_motion (PikaPaintCore *paint_core,
|
||||||
coords.x -= off_x;
|
coords.x -= off_x;
|
||||||
coords.y -= off_y;
|
coords.y -= off_y;
|
||||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
pika_symmetry_set_origin (sym, drawable, &coords);
|
||||||
|
paint_core->sym = sym;
|
||||||
|
|
||||||
opacity = pika_dynamics_get_linear_value (dynamics,
|
opacity = pika_dynamics_get_linear_value (dynamics,
|
||||||
PIKA_DYNAMICS_OUTPUT_OPACITY,
|
PIKA_DYNAMICS_OUTPUT_OPACITY,
|
||||||
|
|
|
@ -347,6 +347,7 @@ pika_source_core_motion (PikaSourceCore *source_core,
|
||||||
coords.x -= off_x;
|
coords.x -= off_x;
|
||||||
coords.y -= off_y;
|
coords.y -= off_y;
|
||||||
pika_symmetry_set_origin (sym, drawable, &coords);
|
pika_symmetry_set_origin (sym, drawable, &coords);
|
||||||
|
paint_core->sym = sym;
|
||||||
|
|
||||||
/* Some settings are based on the original stroke. */
|
/* Some settings are based on the original stroke. */
|
||||||
opacity = pika_dynamics_get_linear_value (dynamics,
|
opacity = pika_dynamics_get_linear_value (dynamics,
|
||||||
|
|
|
@ -5101,7 +5101,7 @@ register_image_procs (PikaPDB *pdb)
|
||||||
"pika-image-get-imported-file");
|
"pika-image-get-imported-file");
|
||||||
pika_procedure_set_static_help (procedure,
|
pika_procedure_set_static_help (procedure,
|
||||||
"Returns the imported file for the specified image.",
|
"Returns the imported file for the specified image.",
|
||||||
"This procedure returns the file associated with the specified image if the image was imported from a non-native Pika format. If the image was not imported, or has since been saved in the native Gimp format, this procedure returns %NULL.",
|
"This procedure returns the file associated with the specified image if the image was imported from a non-native Pika format. If the image was not imported, or has since been saved in the native Pika format, this procedure returns %NULL.",
|
||||||
NULL);
|
NULL);
|
||||||
pika_procedure_set_static_attribution (procedure,
|
pika_procedure_set_static_attribution (procedure,
|
||||||
"Eric Grivel <pika@lumenssolutions.com>",
|
"Eric Grivel <pika@lumenssolutions.com>",
|
||||||
|
|
|
@ -1297,7 +1297,10 @@ vectors_export_to_file_invoker (PikaProcedure *procedure,
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
GList *vectors_list = g_list_prepend (NULL, vectors);
|
GList *vectors_list = NULL;
|
||||||
|
|
||||||
|
if (vectors != NULL)
|
||||||
|
vectors_list = g_list_prepend (vectors_list, vectors);
|
||||||
|
|
||||||
success = pika_vectors_export_file (image, vectors_list, file, error);
|
success = pika_vectors_export_file (image, vectors_list, file, error);
|
||||||
|
|
||||||
|
@ -1327,7 +1330,10 @@ vectors_export_to_string_invoker (PikaProcedure *procedure,
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
GList *vectors_list = g_list_prepend (NULL, vectors);
|
GList *vectors_list = NULL;
|
||||||
|
|
||||||
|
if (vectors != NULL)
|
||||||
|
vectors_list = g_list_prepend (vectors_list, vectors);
|
||||||
|
|
||||||
string = pika_vectors_export_string (image, vectors_list);
|
string = pika_vectors_export_string (image, vectors_list);
|
||||||
g_list_free (vectors_list);
|
g_list_free (vectors_list);
|
||||||
|
@ -2440,7 +2446,7 @@ register_vectors_procs (PikaPDB *pdb)
|
||||||
"pika-vectors-export-to-file");
|
"pika-vectors-export-to-file");
|
||||||
pika_procedure_set_static_help (procedure,
|
pika_procedure_set_static_help (procedure,
|
||||||
"save a path as an SVG file.",
|
"save a path as an SVG file.",
|
||||||
"This procedure creates an SVG file to save a Vectors object, that is, a path. The resulting file can be edited using a vector graphics application, or later reloaded into PIKA. If you pass 0 as the 'vectors' argument, then all paths in the image will be exported.",
|
"This procedure creates an SVG file to save a Vectors object, that is, a path. The resulting file can be edited using a vector graphics application, or later reloaded into PIKA. Pass %NULL as the 'vectors' argument to export all paths in the image.",
|
||||||
NULL);
|
NULL);
|
||||||
pika_procedure_set_static_attribution (procedure,
|
pika_procedure_set_static_attribution (procedure,
|
||||||
"Bill Skaggs <weskaggs@primate.ucdavis.edu>",
|
"Bill Skaggs <weskaggs@primate.ucdavis.edu>",
|
||||||
|
@ -2461,7 +2467,7 @@ register_vectors_procs (PikaPDB *pdb)
|
||||||
pika_procedure_add_argument (procedure,
|
pika_procedure_add_argument (procedure,
|
||||||
pika_param_spec_vectors ("vectors",
|
pika_param_spec_vectors ("vectors",
|
||||||
"vectors",
|
"vectors",
|
||||||
"The vectors object to be saved, or 0 for all in the image",
|
"The vectors object to export, or %NULL for all in the image",
|
||||||
FALSE,
|
FALSE,
|
||||||
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
|
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
|
||||||
pika_pdb_register_procedure (pdb, procedure);
|
pika_pdb_register_procedure (pdb, procedure);
|
||||||
|
@ -2475,7 +2481,7 @@ register_vectors_procs (PikaPDB *pdb)
|
||||||
"pika-vectors-export-to-string");
|
"pika-vectors-export-to-string");
|
||||||
pika_procedure_set_static_help (procedure,
|
pika_procedure_set_static_help (procedure,
|
||||||
"Save a path as an SVG string.",
|
"Save a path as an SVG string.",
|
||||||
"This procedure works like 'pika-vectors-export-to-file' but creates a string rather than a file. The contents are a NUL-terminated string that holds a complete XML document. If you pass 0 as the 'vectors' argument, then all paths in the image will be exported.",
|
"This procedure works like 'pika-vectors-export-to-file' but creates a string rather than a file. The string is NULL-terminated and holds a complete XML document. Pass %NULL as the 'vectors' argument to export all paths in the image.",
|
||||||
NULL);
|
NULL);
|
||||||
pika_procedure_set_static_attribution (procedure,
|
pika_procedure_set_static_attribution (procedure,
|
||||||
"Bill Skaggs <weskaggs@primate.ucdavis.edu>",
|
"Bill Skaggs <weskaggs@primate.ucdavis.edu>",
|
||||||
|
@ -2490,7 +2496,7 @@ register_vectors_procs (PikaPDB *pdb)
|
||||||
pika_procedure_add_argument (procedure,
|
pika_procedure_add_argument (procedure,
|
||||||
pika_param_spec_vectors ("vectors",
|
pika_param_spec_vectors ("vectors",
|
||||||
"vectors",
|
"vectors",
|
||||||
"The vectors object to save, or 0 for all in the image",
|
"The vectors object to export, or %NULL for all in the image",
|
||||||
FALSE,
|
FALSE,
|
||||||
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
|
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
|
||||||
pika_procedure_add_return_value (procedure,
|
pika_procedure_add_return_value (procedure,
|
||||||
|
|
|
@ -450,7 +450,7 @@ pika_update_about_dialog (PikaCoreConfig *config,
|
||||||
if (config->last_known_release != NULL)
|
if (config->last_known_release != NULL)
|
||||||
{
|
{
|
||||||
#ifndef PIKA_CONSOLE_COMPILATION
|
#ifndef PIKA_CONSOLE_COMPILATION
|
||||||
gtk_widget_show (about_dialog_create (pika));
|
gtk_widget_show (about_dialog_create (pika, config));
|
||||||
#else
|
#else
|
||||||
g_printerr (_("A new version of PIKA (%s) was released.\n"
|
g_printerr (_("A new version of PIKA (%s) was released.\n"
|
||||||
"It is recommended to update."),
|
"It is recommended to update."),
|
||||||
|
|
|
@ -170,6 +170,9 @@ pika_tool_options_manager_init (Pika *pika)
|
||||||
g_signal_connect (pika->config, "notify::global-font",
|
g_signal_connect (pika->config, "notify::global-font",
|
||||||
G_CALLBACK (tool_options_manager_global_notify),
|
G_CALLBACK (tool_options_manager_global_notify),
|
||||||
manager);
|
manager);
|
||||||
|
g_signal_connect (pika->config, "notify::global-expand",
|
||||||
|
G_CALLBACK (tool_options_manager_global_notify),
|
||||||
|
manager);
|
||||||
|
|
||||||
g_signal_connect (user_context, "tool-changed",
|
g_signal_connect (user_context, "tool-changed",
|
||||||
G_CALLBACK (tool_options_manager_tool_changed),
|
G_CALLBACK (tool_options_manager_tool_changed),
|
||||||
|
@ -254,6 +257,8 @@ tool_options_manager_get_global_props (PikaCoreConfig *config)
|
||||||
global_props |= PIKA_CONTEXT_PROP_MASK_GRADIENT;
|
global_props |= PIKA_CONTEXT_PROP_MASK_GRADIENT;
|
||||||
if (config->global_font)
|
if (config->global_font)
|
||||||
global_props |= PIKA_CONTEXT_PROP_MASK_FONT;
|
global_props |= PIKA_CONTEXT_PROP_MASK_FONT;
|
||||||
|
if (config->global_expand)
|
||||||
|
global_props |= PIKA_CONTEXT_PROP_MASK_EXPAND;
|
||||||
|
|
||||||
return global_props;
|
return global_props;
|
||||||
}
|
}
|
||||||
|
@ -358,6 +363,12 @@ tool_options_manager_paint_options_notify (PikaPaintOptions *src,
|
||||||
prop_mask |= PIKA_CONTEXT_PROP_MASK_GRADIENT;
|
prop_mask |= PIKA_CONTEXT_PROP_MASK_GRADIENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((active || config->global_expand) &&
|
||||||
|
tool_info->context_props & PIKA_CONTEXT_PROP_MASK_EXPAND)
|
||||||
|
{
|
||||||
|
prop_mask |= PIKA_CONTEXT_PROP_MASK_EXPAND;
|
||||||
|
}
|
||||||
|
|
||||||
if (pika_paint_options_is_prop (pspec->name, prop_mask))
|
if (pika_paint_options_is_prop (pspec->name, prop_mask))
|
||||||
{
|
{
|
||||||
GValue value = G_VALUE_INIT;
|
GValue value = G_VALUE_INIT;
|
||||||
|
|
|
@ -66,6 +66,8 @@ pika_airbrush_tool_register (PikaToolRegisterCallback callback,
|
||||||
PIKA_TYPE_AIRBRUSH_OPTIONS,
|
PIKA_TYPE_AIRBRUSH_OPTIONS,
|
||||||
pika_airbrush_options_gui,
|
pika_airbrush_options_gui,
|
||||||
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
PIKA_CONTEXT_PROP_MASK_GRADIENT,
|
PIKA_CONTEXT_PROP_MASK_GRADIENT,
|
||||||
"pika-airbrush-tool",
|
"pika-airbrush-tool",
|
||||||
_("Airbrush"),
|
_("Airbrush"),
|
||||||
|
|
|
@ -61,6 +61,7 @@ pika_clone_tool_register (PikaToolRegisterCallback callback,
|
||||||
PIKA_TYPE_CLONE_OPTIONS,
|
PIKA_TYPE_CLONE_OPTIONS,
|
||||||
pika_clone_options_gui,
|
pika_clone_options_gui,
|
||||||
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND |
|
||||||
PIKA_CONTEXT_PROP_MASK_PATTERN,
|
PIKA_CONTEXT_PROP_MASK_PATTERN,
|
||||||
"pika-clone-tool",
|
"pika-clone-tool",
|
||||||
_("Clone"),
|
_("Clone"),
|
||||||
|
|
|
@ -73,7 +73,9 @@ pika_convolve_tool_register (PikaToolRegisterCallback callback,
|
||||||
(* callback) (PIKA_TYPE_CONVOLVE_TOOL,
|
(* callback) (PIKA_TYPE_CONVOLVE_TOOL,
|
||||||
PIKA_TYPE_CONVOLVE_OPTIONS,
|
PIKA_TYPE_CONVOLVE_OPTIONS,
|
||||||
pika_convolve_options_gui,
|
pika_convolve_options_gui,
|
||||||
PIKA_PAINT_OPTIONS_CONTEXT_MASK,
|
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND,
|
||||||
"pika-convolve-tool",
|
"pika-convolve-tool",
|
||||||
_("Blur / Sharpen"),
|
_("Blur / Sharpen"),
|
||||||
_("Blur / Sharpen Tool: Selective blurring or unblurring using a brush"),
|
_("Blur / Sharpen Tool: Selective blurring or unblurring using a brush"),
|
||||||
|
|
|
@ -52,7 +52,9 @@ pika_heal_tool_register (PikaToolRegisterCallback callback,
|
||||||
(* callback) (PIKA_TYPE_HEAL_TOOL,
|
(* callback) (PIKA_TYPE_HEAL_TOOL,
|
||||||
PIKA_TYPE_SOURCE_OPTIONS,
|
PIKA_TYPE_SOURCE_OPTIONS,
|
||||||
pika_heal_options_gui,
|
pika_heal_options_gui,
|
||||||
PIKA_PAINT_OPTIONS_CONTEXT_MASK,
|
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND,
|
||||||
"pika-heal-tool",
|
"pika-heal-tool",
|
||||||
_("Healing"),
|
_("Healing"),
|
||||||
_("Healing Tool: Heal image irregularities"),
|
_("Healing Tool: Heal image irregularities"),
|
||||||
|
|
|
@ -50,6 +50,7 @@ pika_ink_options_gui (PikaToolOptions *tool_options)
|
||||||
GtkWidget *frame;
|
GtkWidget *frame;
|
||||||
GtkWidget *vbox2;
|
GtkWidget *vbox2;
|
||||||
GtkWidget *scale;
|
GtkWidget *scale;
|
||||||
|
GtkWidget *combo_box;
|
||||||
GtkWidget *blob_box;
|
GtkWidget *blob_box;
|
||||||
GtkWidget *hbox;
|
GtkWidget *hbox;
|
||||||
GtkWidget *editor;
|
GtkWidget *editor;
|
||||||
|
@ -133,6 +134,28 @@ pika_ink_options_gui (PikaToolOptions *tool_options)
|
||||||
gtk_container_add (GTK_CONTAINER (frame), editor);
|
gtk_container_add (GTK_CONTAINER (frame), editor);
|
||||||
gtk_widget_show (editor);
|
gtk_widget_show (editor);
|
||||||
|
|
||||||
|
/* Expand layer options */
|
||||||
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||||||
|
|
||||||
|
scale = pika_prop_spin_scale_new (config, "expand-amount",
|
||||||
|
1, 10, 2);
|
||||||
|
pika_spin_scale_set_constrain_drag (PIKA_SPIN_SCALE (scale), TRUE);
|
||||||
|
pika_spin_scale_set_scale_limits (PIKA_SPIN_SCALE (scale), 1.0, 1000.0);
|
||||||
|
pika_spin_scale_set_gamma (PIKA_SPIN_SCALE (scale), 1.0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
combo_box = pika_prop_enum_combo_box_new (config, "expand-fill-type", 0, 0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox2), combo_box, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
frame = pika_prop_enum_radio_frame_new (config, "expand-mask-fill-type",
|
||||||
|
"Fill Layer Mask With", 0, 1);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
frame = pika_prop_expanding_frame_new (config, "expand-use", NULL,
|
||||||
|
vbox2, NULL);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (frame);
|
||||||
|
|
||||||
pika_config_connect (config, G_OBJECT (editor), "blob-type");
|
pika_config_connect (config, G_OBJECT (editor), "blob-type");
|
||||||
pika_config_connect (config, G_OBJECT (editor), "blob-aspect");
|
pika_config_connect (config, G_OBJECT (editor), "blob-aspect");
|
||||||
pika_config_connect (config, G_OBJECT (editor), "blob-angle");
|
pika_config_connect (config, G_OBJECT (editor), "blob-angle");
|
||||||
|
|
|
@ -68,7 +68,9 @@ pika_ink_tool_register (PikaToolRegisterCallback callback,
|
||||||
PIKA_CONTEXT_PROP_MASK_FOREGROUND |
|
PIKA_CONTEXT_PROP_MASK_FOREGROUND |
|
||||||
PIKA_CONTEXT_PROP_MASK_BACKGROUND |
|
PIKA_CONTEXT_PROP_MASK_BACKGROUND |
|
||||||
PIKA_CONTEXT_PROP_MASK_OPACITY |
|
PIKA_CONTEXT_PROP_MASK_OPACITY |
|
||||||
PIKA_CONTEXT_PROP_MASK_PAINT_MODE,
|
PIKA_CONTEXT_PROP_MASK_PAINT_MODE |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND,
|
||||||
"pika-ink-tool",
|
"pika-ink-tool",
|
||||||
_("Ink"),
|
_("Ink"),
|
||||||
_("Ink Tool: Calligraphy-style painting"),
|
_("Ink Tool: Calligraphy-style painting"),
|
||||||
|
|
|
@ -50,8 +50,11 @@ pika_mybrush_options_gui (PikaToolOptions *tool_options)
|
||||||
{
|
{
|
||||||
GObject *config = G_OBJECT (tool_options);
|
GObject *config = G_OBJECT (tool_options);
|
||||||
GtkWidget *vbox = pika_paint_options_gui (tool_options);
|
GtkWidget *vbox = pika_paint_options_gui (tool_options);
|
||||||
|
GtkWidget *vbox2;
|
||||||
GtkWidget *button;
|
GtkWidget *button;
|
||||||
GtkWidget *scale;
|
GtkWidget *scale;
|
||||||
|
GtkWidget *combo_box;
|
||||||
|
GtkWidget *frame;
|
||||||
|
|
||||||
/* the brush */
|
/* the brush */
|
||||||
button = pika_prop_mybrush_box_new (NULL, PIKA_CONTEXT (tool_options),
|
button = pika_prop_mybrush_box_new (NULL, PIKA_CONTEXT (tool_options),
|
||||||
|
@ -82,5 +85,28 @@ pika_mybrush_options_gui (PikaToolOptions *tool_options)
|
||||||
0.1, 1.0, 2);
|
0.1, 1.0, 2);
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
/* Expand layer options */
|
||||||
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||||||
|
|
||||||
|
scale = pika_prop_spin_scale_new (config, "expand-amount",
|
||||||
|
1, 10, 2);
|
||||||
|
pika_spin_scale_set_constrain_drag (PIKA_SPIN_SCALE (scale), TRUE);
|
||||||
|
pika_spin_scale_set_scale_limits (PIKA_SPIN_SCALE (scale), 1.0, 1000.0);
|
||||||
|
pika_spin_scale_set_gamma (PIKA_SPIN_SCALE (scale), 1.0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
combo_box = pika_prop_enum_combo_box_new (config, "expand-fill-type", 0, 0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox2), combo_box, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
frame = pika_prop_enum_radio_frame_new (config, "expand-mask-fill-type",
|
||||||
|
"Fill Layer Mask With", 0, 1);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
frame = pika_prop_expanding_frame_new (config, "expand-use", NULL,
|
||||||
|
vbox2, NULL);
|
||||||
|
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (frame);
|
||||||
|
|
||||||
return vbox;
|
return vbox;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,9 @@ pika_mybrush_tool_register (PikaToolRegisterCallback callback,
|
||||||
PIKA_CONTEXT_PROP_MASK_BACKGROUND |
|
PIKA_CONTEXT_PROP_MASK_BACKGROUND |
|
||||||
PIKA_CONTEXT_PROP_MASK_OPACITY |
|
PIKA_CONTEXT_PROP_MASK_OPACITY |
|
||||||
PIKA_CONTEXT_PROP_MASK_PAINT_MODE |
|
PIKA_CONTEXT_PROP_MASK_PAINT_MODE |
|
||||||
PIKA_CONTEXT_PROP_MASK_MYBRUSH,
|
PIKA_CONTEXT_PROP_MASK_MYBRUSH |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND,
|
||||||
"pika-mypaint-brush-tool",
|
"pika-mypaint-brush-tool",
|
||||||
_("MyPaint Brush"),
|
_("MyPaint Brush"),
|
||||||
_("MyPaint Brush Tool: Use MyPaint brushes in PIKA"),
|
_("MyPaint Brush Tool: Use MyPaint brushes in PIKA"),
|
||||||
|
|
|
@ -56,7 +56,9 @@ pika_paintbrush_tool_register (PikaToolRegisterCallback callback,
|
||||||
PIKA_TYPE_PAINT_OPTIONS,
|
PIKA_TYPE_PAINT_OPTIONS,
|
||||||
pika_paint_options_gui,
|
pika_paint_options_gui,
|
||||||
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
||||||
PIKA_CONTEXT_PROP_MASK_GRADIENT,
|
PIKA_CONTEXT_PROP_MASK_EXPAND |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_GRADIENT |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN,
|
||||||
"pika-paintbrush-tool",
|
"pika-paintbrush-tool",
|
||||||
_("Paintbrush"),
|
_("Paintbrush"),
|
||||||
_("Paintbrush Tool: Paint smooth strokes using a brush"),
|
_("Paintbrush Tool: Paint smooth strokes using a brush"),
|
||||||
|
|
|
@ -77,6 +77,8 @@ static GtkWidget * jitter_options_gui (PikaPaintOptions *paint_options,
|
||||||
GType tool_type);
|
GType tool_type);
|
||||||
static GtkWidget * smoothing_options_gui (PikaPaintOptions *paint_options,
|
static GtkWidget * smoothing_options_gui (PikaPaintOptions *paint_options,
|
||||||
GType tool_type);
|
GType tool_type);
|
||||||
|
static GtkWidget * expand_options_gui (PikaPaintOptions *paint_options,
|
||||||
|
GType tool_type);
|
||||||
|
|
||||||
static GtkWidget * pika_paint_options_gui_scale_with_buttons
|
static GtkWidget * pika_paint_options_gui_scale_with_buttons
|
||||||
(GObject *config,
|
(GObject *config,
|
||||||
|
@ -274,6 +276,22 @@ pika_paint_options_gui (PikaToolOptions *tool_options)
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* the "expand layers" options */
|
||||||
|
if (tool_type == PIKA_TYPE_PAINTBRUSH_TOOL ||
|
||||||
|
tool_type == PIKA_TYPE_PENCIL_TOOL ||
|
||||||
|
tool_type == PIKA_TYPE_AIRBRUSH_TOOL ||
|
||||||
|
tool_type == PIKA_TYPE_CLONE_TOOL ||
|
||||||
|
tool_type == PIKA_TYPE_HEAL_TOOL ||
|
||||||
|
tool_type == PIKA_TYPE_CONVOLVE_TOOL ||
|
||||||
|
tool_type == PIKA_TYPE_SMUDGE_TOOL)
|
||||||
|
{
|
||||||
|
GtkWidget *frame;
|
||||||
|
|
||||||
|
frame = expand_options_gui (options, tool_type);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (frame);
|
||||||
|
}
|
||||||
|
|
||||||
return vbox;
|
return vbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,6 +507,39 @@ pika_paint_options_gui_reset_force (GtkWidget *button,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GtkWidget *
|
||||||
|
expand_options_gui (PikaPaintOptions *paint_options,
|
||||||
|
GType tool_type)
|
||||||
|
{
|
||||||
|
GObject *config = G_OBJECT (paint_options);
|
||||||
|
GtkWidget *frame;
|
||||||
|
GtkWidget *scale;
|
||||||
|
GtkWidget *combo_box;
|
||||||
|
GtkWidget *vbox;
|
||||||
|
|
||||||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||||||
|
|
||||||
|
scale = pika_prop_spin_scale_new (config, "expand-amount",
|
||||||
|
1, 10, 2);
|
||||||
|
pika_spin_scale_set_constrain_drag (PIKA_SPIN_SCALE (scale), TRUE);
|
||||||
|
|
||||||
|
pika_spin_scale_set_scale_limits (PIKA_SPIN_SCALE (scale), 1.0, 1000.0);
|
||||||
|
pika_spin_scale_set_gamma (PIKA_SPIN_SCALE (scale), 1.0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
combo_box = pika_prop_enum_combo_box_new (config, "expand-fill-type", 0, 0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
frame = pika_prop_enum_radio_frame_new (config, "expand-mask-fill-type",
|
||||||
|
"Fill Layer Mask With", 0, 1);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
frame = pika_prop_expanding_frame_new (config, "expand-use", NULL,
|
||||||
|
vbox, NULL);
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
static GtkWidget *
|
static GtkWidget *
|
||||||
pika_paint_options_gui_scale_with_buttons (GObject *config,
|
pika_paint_options_gui_scale_with_buttons (GObject *config,
|
||||||
gchar *prop_name,
|
gchar *prop_name,
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "core/pikadrawable.h"
|
#include "core/pikadrawable.h"
|
||||||
#include "core/pikaimage.h"
|
#include "core/pikaimage.h"
|
||||||
|
#include "core/pikalayer.h"
|
||||||
|
#include "core/pikalayermask.h"
|
||||||
#include "core/pikaprojection.h"
|
#include "core/pikaprojection.h"
|
||||||
|
|
||||||
#include "paint/pikapaintcore.h"
|
#include "paint/pikapaintcore.h"
|
||||||
|
@ -41,6 +43,7 @@
|
||||||
|
|
||||||
#include "pikapainttool.h"
|
#include "pikapainttool.h"
|
||||||
#include "pikapainttool-paint.h"
|
#include "pikapainttool-paint.h"
|
||||||
|
#include "pikatools-utils.h"
|
||||||
|
|
||||||
|
|
||||||
#define DISPLAY_UPDATE_INTERVAL 10000 /* microseconds */
|
#define DISPLAY_UPDATE_INTERVAL 10000 /* microseconds */
|
||||||
|
@ -218,6 +221,27 @@ pika_paint_tool_paint_interpolate (PikaPaintTool *paint_tool,
|
||||||
pika_paint_core_interpolate (core, data->drawables, paint_options,
|
pika_paint_core_interpolate (core, data->drawables, paint_options,
|
||||||
&data->coords, data->time);
|
&data->coords, data->time);
|
||||||
|
|
||||||
|
/* Blink the lock box if required */
|
||||||
|
if (core->lock_blink_state == PIKA_PAINT_LOCK_BLINK_PENDING)
|
||||||
|
{
|
||||||
|
GList *iter;
|
||||||
|
PikaLayer *layer;
|
||||||
|
|
||||||
|
/* Blink the lock only once per stroke */
|
||||||
|
core->lock_blink_state = PIKA_PAINT_LOCK_BLINKED;
|
||||||
|
|
||||||
|
for (iter = data->drawables; iter; iter = g_list_next (iter))
|
||||||
|
{
|
||||||
|
layer = PIKA_IS_LAYER_MASK (iter->data) ?
|
||||||
|
PIKA_LAYER_MASK (iter->data)->layer :
|
||||||
|
PIKA_LAYER (iter->data);
|
||||||
|
|
||||||
|
if (pika_item_get_lock_position (PIKA_ITEM (layer)))
|
||||||
|
pika_tools_blink_lock_box (PIKA_CONTEXT (paint_options)->pika,
|
||||||
|
PIKA_ITEM (layer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_list_free (data->drawables);
|
g_list_free (data->drawables);
|
||||||
g_slice_free (InterpolateData, data);
|
g_slice_free (InterpolateData, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ pika_pencil_tool_register (PikaToolRegisterCallback callback,
|
||||||
PIKA_TYPE_PENCIL_OPTIONS,
|
PIKA_TYPE_PENCIL_OPTIONS,
|
||||||
pika_paint_options_gui,
|
pika_paint_options_gui,
|
||||||
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
PIKA_CONTEXT_PROP_MASK_GRADIENT,
|
PIKA_CONTEXT_PROP_MASK_GRADIENT,
|
||||||
"pika-pencil-tool",
|
"pika-pencil-tool",
|
||||||
_("Pencil"),
|
_("Pencil"),
|
||||||
|
|
|
@ -54,6 +54,8 @@ pika_smudge_tool_register (PikaToolRegisterCallback callback,
|
||||||
PIKA_TYPE_SMUDGE_OPTIONS,
|
PIKA_TYPE_SMUDGE_OPTIONS,
|
||||||
pika_smudge_options_gui,
|
pika_smudge_options_gui,
|
||||||
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
PIKA_PAINT_OPTIONS_CONTEXT_MASK |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_EXPAND |
|
||||||
|
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||||
PIKA_CONTEXT_PROP_MASK_GRADIENT,
|
PIKA_CONTEXT_PROP_MASK_GRADIENT,
|
||||||
"pika-smudge-tool",
|
"pika-smudge-tool",
|
||||||
_("Smudge"),
|
_("Smudge"),
|
||||||
|
|
|
@ -51,19 +51,26 @@ static gchar * pika_vectors_export_path_data (PikaVectors *vectors);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pika_vectors_export_file:
|
* pika_vectors_export_file:
|
||||||
* @image: the #PikaImage from which to export vectors
|
* @image: the #PikaImage from which to export
|
||||||
* @vectors: a #GList of #PikaVectors objects or %NULL to export all vectors in @image
|
* @path_list: a #GList of #PikaVectors objects or %NULL to export all paths in @image
|
||||||
* @file: the file to write
|
* @file: the file to write
|
||||||
* @error: return location for errors
|
* @error: return location for errors
|
||||||
*
|
*
|
||||||
* Exports one or more vectors to a SVG file.
|
* Exports one or more vectors aka path to an SVG file aka XML doc.
|
||||||
|
*
|
||||||
|
* When @path_list is %NULL aka empty list, exports all paths in image.
|
||||||
|
*
|
||||||
|
* When @path_list is empty and image has no paths,
|
||||||
|
* this still writes a non-empty file containing an XML doc.
|
||||||
|
*
|
||||||
|
* Will overwrite any existing file.
|
||||||
*
|
*
|
||||||
* Returns: %TRUE on success,
|
* Returns: %TRUE on success,
|
||||||
* %FALSE if there was an error writing the file
|
* %FALSE when there was an error writing the file
|
||||||
**/
|
**/
|
||||||
gboolean
|
gboolean
|
||||||
pika_vectors_export_file (PikaImage *image,
|
pika_vectors_export_file (PikaImage *image,
|
||||||
GList *vectors,
|
GList *path_list,
|
||||||
GFile *file,
|
GFile *file,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
|
@ -81,7 +88,7 @@ pika_vectors_export_file (PikaImage *image,
|
||||||
if (! output)
|
if (! output)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
string = pika_vectors_export (image, vectors);
|
string = pika_vectors_export (image, path_list);
|
||||||
|
|
||||||
if (! g_output_stream_write_all (output, string->str, string->len,
|
if (! g_output_stream_write_all (output, string->str, string->len,
|
||||||
NULL, NULL, &my_error))
|
NULL, NULL, &my_error))
|
||||||
|
@ -111,20 +118,25 @@ pika_vectors_export_file (PikaImage *image,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pika_vectors_export_string:
|
* pika_vectors_export_string:
|
||||||
* @image: the #PikaImage from which to export vectors
|
* @image: the #PikaImage from which to export
|
||||||
* @vectors: a #PikaVectors object or %NULL to export all vectors in @image
|
* @path_list: a #GList of #PikaVectors objects, or %NULL to export all paths in @image
|
||||||
*
|
*
|
||||||
* Exports one or more vectors to a SVG string.
|
* Exports one or more vectors aka path to a SVG string.
|
||||||
*
|
*
|
||||||
* Returns: a %NUL-terminated string that holds a complete XML document
|
* When @path_list is %NULL aka empty list, exports all paths in image.
|
||||||
|
*
|
||||||
|
* When @path_list is empty and image has no paths,
|
||||||
|
* this still returns a string for an empty XML doc.
|
||||||
|
*
|
||||||
|
* Returns: a NULL-terminated string that holds a complete XML document
|
||||||
**/
|
**/
|
||||||
gchar *
|
gchar *
|
||||||
pika_vectors_export_string (PikaImage *image,
|
pika_vectors_export_string (PikaImage *image,
|
||||||
GList *vectors)
|
GList *path_list)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
|
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
|
||||||
|
|
||||||
return g_string_free (pika_vectors_export (image, vectors), FALSE);
|
return g_string_free (pika_vectors_export (image, path_list), FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GString *
|
static GString *
|
||||||
|
|
|
@ -104,6 +104,8 @@ static void pika_action_proxy_button_activate (GtkButton *button,
|
||||||
|
|
||||||
static void pika_action_update_proxy_sensitive (PikaAction *action,
|
static void pika_action_update_proxy_sensitive (PikaAction *action,
|
||||||
GtkWidget *proxy);
|
GtkWidget *proxy);
|
||||||
|
static void pika_action_update_proxy_visible (PikaAction *action,
|
||||||
|
GtkWidget *proxy);
|
||||||
static void pika_action_update_proxy_tooltip (PikaAction *action,
|
static void pika_action_update_proxy_tooltip (PikaAction *action,
|
||||||
GtkWidget *proxy);
|
GtkWidget *proxy);
|
||||||
|
|
||||||
|
@ -446,9 +448,20 @@ void
|
||||||
pika_action_set_visible (PikaAction *action,
|
pika_action_set_visible (PikaAction *action,
|
||||||
gboolean visible)
|
gboolean visible)
|
||||||
{
|
{
|
||||||
g_object_set (action,
|
PikaActionPrivate *priv = GET_PRIVATE (action);
|
||||||
"visible", visible,
|
|
||||||
NULL);
|
/* Only notify when the state actually changed. This is important for
|
||||||
|
* handlers such as visibility of menu items in PikaMenuModel which
|
||||||
|
* will assume that the action visibility changed. Otherwise we might
|
||||||
|
* remove items by mistake.
|
||||||
|
*/
|
||||||
|
if (priv->visible != visible)
|
||||||
|
{
|
||||||
|
priv->visible = visible;
|
||||||
|
|
||||||
|
pika_action_update_proxy_visible (action, NULL);
|
||||||
|
g_object_notify (G_OBJECT (action), "visible");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
@ -929,16 +942,8 @@ pika_action_set_property (GObject *object,
|
||||||
NULL);
|
NULL);
|
||||||
break;
|
break;
|
||||||
case PIKA_ACTION_PROP_VISIBLE:
|
case PIKA_ACTION_PROP_VISIBLE:
|
||||||
if (priv->visible != g_value_get_boolean (value))
|
pika_action_set_visible (PIKA_ACTION (object),
|
||||||
{
|
g_value_get_boolean (value));
|
||||||
priv->visible = g_value_get_boolean (value);
|
|
||||||
/* Only notify when the state actually changed. This is important for
|
|
||||||
* handlers such as visibility of menu items in PikaMenuModel which
|
|
||||||
* will assume that the action visibility changed. Otherwise we might
|
|
||||||
* remove items by mistake.
|
|
||||||
*/
|
|
||||||
g_object_notify (object, "visible");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PIKA_ACTION_PROP_LABEL:
|
case PIKA_ACTION_PROP_LABEL:
|
||||||
|
@ -1391,6 +1396,24 @@ pika_action_update_proxy_sensitive (PikaAction *action,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pika_action_update_proxy_visible (PikaAction *action,
|
||||||
|
GtkWidget *proxy)
|
||||||
|
{
|
||||||
|
PikaActionPrivate *priv = GET_PRIVATE (action);
|
||||||
|
gboolean visible = pika_action_is_visible (action);
|
||||||
|
|
||||||
|
if (proxy)
|
||||||
|
{
|
||||||
|
gtk_widget_set_visible (proxy, visible);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (GList *list = priv->proxies; list; list = list->next)
|
||||||
|
gtk_widget_set_visible (list->data, visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pika_action_update_proxy_tooltip (PikaAction *action,
|
pika_action_update_proxy_tooltip (PikaAction *action,
|
||||||
GtkWidget *proxy)
|
GtkWidget *proxy)
|
||||||
|
|
|
@ -102,10 +102,6 @@ static void pika_container_tree_view_set_view_size (PikaContainerVi
|
||||||
|
|
||||||
static void pika_container_tree_view_real_edit_name (PikaContainerTreeView *tree_view);
|
static void pika_container_tree_view_real_edit_name (PikaContainerTreeView *tree_view);
|
||||||
|
|
||||||
static void pika_container_tree_view_selection_label_notify (GtkLabel *label,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
PikaItemTreeView *view);
|
|
||||||
|
|
||||||
static gboolean pika_container_tree_view_edit_focus_out (GtkWidget *widget,
|
static gboolean pika_container_tree_view_edit_focus_out (GtkWidget *widget,
|
||||||
GdkEvent *event,
|
GdkEvent *event,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
@ -296,12 +292,6 @@ pika_container_tree_view_constructed (GObject *object)
|
||||||
gtk_label_set_selectable (GTK_LABEL (tree_view->priv->multi_selection_label), TRUE);
|
gtk_label_set_selectable (GTK_LABEL (tree_view->priv->multi_selection_label), TRUE);
|
||||||
gtk_tree_view_column_set_widget (tree_view->main_column,
|
gtk_tree_view_column_set_widget (tree_view->main_column,
|
||||||
tree_view->priv->multi_selection_label);
|
tree_view->priv->multi_selection_label);
|
||||||
g_signal_connect (tree_view->priv->multi_selection_label, "notify::label",
|
|
||||||
G_CALLBACK (pika_container_tree_view_selection_label_notify),
|
|
||||||
tree_view);
|
|
||||||
g_signal_connect (tree_view->priv->multi_selection_label, "notify::selection-bound",
|
|
||||||
G_CALLBACK (pika_container_tree_view_selection_label_notify),
|
|
||||||
tree_view);
|
|
||||||
gtk_widget_show (tree_view->priv->multi_selection_label);
|
gtk_widget_show (tree_view->priv->multi_selection_label);
|
||||||
gtk_tree_view_insert_column (tree_view->view, tree_view->main_column, 0);
|
gtk_tree_view_insert_column (tree_view->view, tree_view->main_column, 0);
|
||||||
|
|
||||||
|
@ -1204,20 +1194,6 @@ pika_container_tree_view_real_edit_name (PikaContainerTreeView *tree_view)
|
||||||
|
|
||||||
/* callbacks */
|
/* callbacks */
|
||||||
|
|
||||||
static void
|
|
||||||
pika_container_tree_view_selection_label_notify (GtkLabel *label,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
PikaItemTreeView *view)
|
|
||||||
{
|
|
||||||
/* This is a weird trick to make the label follow the color scheme of
|
|
||||||
* selected items in whatever theme is selected. It seems we cannot
|
|
||||||
* link to the color of another widget whose theme we don't control.
|
|
||||||
* Faking selection is the only way I found, though it is quite ugly
|
|
||||||
* semantically.
|
|
||||||
*/
|
|
||||||
gtk_label_select_region (label, 0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
pika_container_tree_view_edit_focus_out (GtkWidget *widget,
|
pika_container_tree_view_edit_focus_out (GtkWidget *widget,
|
||||||
GdkEvent *event,
|
GdkEvent *event,
|
||||||
|
@ -1354,10 +1330,12 @@ pika_container_tree_view_button (GtkWidget *widget,
|
||||||
GdkEventButton *bevent,
|
GdkEventButton *bevent,
|
||||||
PikaContainerTreeView *tree_view)
|
PikaContainerTreeView *tree_view)
|
||||||
{
|
{
|
||||||
PikaContainerView *container_view = PIKA_CONTAINER_VIEW (tree_view);
|
PikaContainerView *container_view = PIKA_CONTAINER_VIEW (tree_view);
|
||||||
GtkTreeViewColumn *column;
|
GtkTreeViewColumn *column;
|
||||||
GtkTreePath *path;
|
GtkTreePath *path;
|
||||||
gboolean handled = TRUE;
|
gboolean handled = TRUE;
|
||||||
|
GtkCellRenderer *toggled_cell = NULL;
|
||||||
|
PikaCellRendererViewable *clicked_cell = NULL;
|
||||||
|
|
||||||
tree_view->priv->dnd_renderer = NULL;
|
tree_view->priv->dnd_renderer = NULL;
|
||||||
|
|
||||||
|
@ -1366,8 +1344,6 @@ pika_container_tree_view_button (GtkWidget *widget,
|
||||||
&path, &column, NULL, NULL))
|
&path, &column, NULL, NULL))
|
||||||
{
|
{
|
||||||
PikaViewRenderer *renderer;
|
PikaViewRenderer *renderer;
|
||||||
GtkCellRenderer *toggled_cell = NULL;
|
|
||||||
PikaCellRendererViewable *clicked_cell = NULL;
|
|
||||||
GtkCellRenderer *edit_cell = NULL;
|
GtkCellRenderer *edit_cell = NULL;
|
||||||
GdkRectangle column_area;
|
GdkRectangle column_area;
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
|
@ -1389,15 +1365,21 @@ pika_container_tree_view_button (GtkWidget *widget,
|
||||||
multisel_mode = FALSE;
|
multisel_mode = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to grab focus after a button click, in order to make keyboard
|
/* We need to grab focus at button click, in order to make keyboard
|
||||||
* navigation possible. For multi-selection though, actual selection will
|
* navigation possible; yet the timing matters:
|
||||||
* happen in pika_container_tree_view_selection_changed() but the widget
|
* 1. For multi-selection, actual selection will happen in
|
||||||
* must already be focused or the handler won't run.
|
* pika_container_tree_view_selection_changed() but the widget
|
||||||
* Whereas for single selection, grab must happen after we changed the
|
* must already be focused or the handler won't run. So we grab first.
|
||||||
* selection (which will happen in this function) otherwise we end up
|
* 2. For toggled and clicked cells, we must also grab first (see code
|
||||||
* first scrolling to the current selection. So we have a separate
|
* below), and absolutely not in the end, because some toggle cells may
|
||||||
* gtk_widget_grab_focus() at the end of the function.
|
* trigger a popup (and the grab on the source widget would close the
|
||||||
* See also commit 3e101922 and MR !1128.
|
* popup).
|
||||||
|
* 3. Finally for single selection, grab must happen after we changed
|
||||||
|
* the selection (which will happen in this function) otherwise we
|
||||||
|
* end up first scrolling to the current selection.
|
||||||
|
* This is why we have a few separate calls to gtk_widget_grab_focus()
|
||||||
|
* in this function.
|
||||||
|
* See also commit 3e101922, MR !1128 and #10281.
|
||||||
*/
|
*/
|
||||||
if (multisel_mode && bevent->type == GDK_BUTTON_PRESS && ! gtk_widget_has_focus (widget))
|
if (multisel_mode && bevent->type == GDK_BUTTON_PRESS && ! gtk_widget_has_focus (widget))
|
||||||
gtk_widget_grab_focus (widget);
|
gtk_widget_grab_focus (widget);
|
||||||
|
@ -1524,6 +1506,10 @@ pika_container_tree_view_button (GtkWidget *widget,
|
||||||
column, &column_area,
|
column, &column_area,
|
||||||
bevent->x, bevent->y);
|
bevent->x, bevent->y);
|
||||||
|
|
||||||
|
if ((toggled_cell || clicked_cell) &&
|
||||||
|
bevent->type == GDK_BUTTON_PRESS && ! gtk_widget_has_focus (widget))
|
||||||
|
gtk_widget_grab_focus (widget);
|
||||||
|
|
||||||
if (! toggled_cell && ! clicked_cell)
|
if (! toggled_cell && ! clicked_cell)
|
||||||
{
|
{
|
||||||
edit_cell =
|
edit_cell =
|
||||||
|
@ -1720,7 +1706,8 @@ pika_container_tree_view_button (GtkWidget *widget,
|
||||||
handled = TRUE;
|
handled = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handled && bevent->type == GDK_BUTTON_PRESS && ! gtk_widget_has_focus (widget))
|
if (handled && bevent->type == GDK_BUTTON_PRESS && ! gtk_widget_has_focus (widget) &&
|
||||||
|
! toggled_cell && ! clicked_cell)
|
||||||
gtk_widget_grab_focus (widget);
|
gtk_widget_grab_focus (widget);
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
|
|
|
@ -46,6 +46,9 @@ static void pika_image_editor_real_set_image (PikaImageEditor *editor,
|
||||||
static void pika_image_editor_image_flush (PikaImage *image,
|
static void pika_image_editor_image_flush (PikaImage *image,
|
||||||
gboolean invalidate_preview,
|
gboolean invalidate_preview,
|
||||||
PikaImageEditor *editor);
|
PikaImageEditor *editor);
|
||||||
|
static gboolean
|
||||||
|
pika_image_editor_image_flush_idle
|
||||||
|
(gpointer user_data);
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_CODE (PikaImageEditor, pika_image_editor, PIKA_TYPE_EDITOR,
|
G_DEFINE_TYPE_WITH_CODE (PikaImageEditor, pika_image_editor, PIKA_TYPE_EDITOR,
|
||||||
|
@ -177,7 +180,19 @@ pika_image_editor_image_flush (PikaImage *image,
|
||||||
gboolean invalidate_preview,
|
gboolean invalidate_preview,
|
||||||
PikaImageEditor *editor)
|
PikaImageEditor *editor)
|
||||||
{
|
{
|
||||||
|
g_idle_add_full (G_PRIORITY_LOW,
|
||||||
|
(GSourceFunc) pika_image_editor_image_flush_idle,
|
||||||
|
g_object_ref (editor), g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pika_image_editor_image_flush_idle (gpointer user_data)
|
||||||
|
{
|
||||||
|
PikaImageEditor *editor = user_data;
|
||||||
|
|
||||||
if (pika_editor_get_ui_manager (PIKA_EDITOR (editor)))
|
if (pika_editor_get_ui_manager (PIKA_EDITOR (editor)))
|
||||||
pika_ui_manager_update (pika_editor_get_ui_manager (PIKA_EDITOR (editor)),
|
pika_ui_manager_update (pika_editor_get_ui_manager (PIKA_EDITOR (editor)),
|
||||||
pika_editor_get_popup_data (PIKA_EDITOR (editor)));
|
pika_editor_get_popup_data (PIKA_EDITOR (editor)));
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1224,6 +1224,8 @@ pika_layer_tree_view_floating_selection_changed (PikaImage *image,
|
||||||
g_list_free (all_layers);
|
g_list_free (all_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gtk_widget_set_sensitive (layer_view->priv->link_button, ! floating_sel);
|
||||||
|
|
||||||
pika_layer_tree_view_update_highlight (layer_view);
|
pika_layer_tree_view_update_highlight (layer_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,13 +86,13 @@
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/Exiv2/exiv2/releases/download/v0.28.0/exiv2-0.28.0-Source.tar.gz",
|
"url": "https://github.com/Exiv2/exiv2/archive/refs/tags/v0.28.1.tar.gz",
|
||||||
"sha256": "89af3b5ef7277753ef7a7b5374ae017c6b9e304db3b688f1948e73e103491f3d",
|
"sha256": "3078651f995cb6313b1041f07f4dd1bf0e9e4d394d6e2adc6e92ad0b621291fa",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 769,
|
"project-id": 769,
|
||||||
"stable-only": true,
|
"stable-only": true,
|
||||||
"url-template": "https://github.com/Exiv2/exiv2/releases/download/v$version/exiv2-$version-Source.tar.gz"
|
"url-template": "https://github.com/Exiv2/exiv2/archive/refs/tags/v$version.tar.gz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name" : "openexr",
|
"name": "openexr",
|
||||||
"config-opts": [
|
"config-opts": [
|
||||||
"-DBUILD_SHARED_LIBS=ON",
|
"-DBUILD_SHARED_LIBS=ON",
|
||||||
"-DOPENEXR_INSTALL_EXAMPLES=OFF",
|
"-DOPENEXR_INSTALL_EXAMPLES=OFF",
|
||||||
|
@ -201,7 +201,8 @@
|
||||||
"-DOpenJPEG_DIR=/usr/lib64/openjpeg-2.3",
|
"-DOpenJPEG_DIR=/usr/lib64/openjpeg-2.3",
|
||||||
"-DENABLE_BOOST=OFF",
|
"-DENABLE_BOOST=OFF",
|
||||||
"-DWITH_NSS3:BOOL=OFF",
|
"-DWITH_NSS3:BOOL=OFF",
|
||||||
"-DENABLE_QT5:BOOL=OFF"
|
"-DENABLE_QT5:BOOL=OFF",
|
||||||
|
"-DENABLE_QT6:BOOL=OFF"
|
||||||
],
|
],
|
||||||
"cleanup": [
|
"cleanup": [
|
||||||
"/bin",
|
"/bin",
|
||||||
|
@ -212,8 +213,8 @@
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://poppler.freedesktop.org/poppler-23.08.0.tar.xz",
|
"url": "https://poppler.freedesktop.org/poppler-23.11.0.tar.xz",
|
||||||
"sha256": "4a4bf7fc903b9f1a2ab7d04b7c5d8220db9bc6261cc73fdb9a826dc272f49aa8",
|
"sha256": "f99cca6799cb9cb6c92fc1e0eb78547b611cb733750ab7cb047cb0e6c246539c",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 3686,
|
"project-id": 3686,
|
||||||
|
@ -314,8 +315,8 @@
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10012/ghostscript-10.01.2.tar.gz",
|
"url": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10021/ghostscript-10.02.1.tar.gz",
|
||||||
"sha512": "11887850d440b8bbd8b83b8b58df8c743cf94be8fdbcfbda1a5fce55ce7c6a963d94b41a4ebcf1ba48f64f8af01e76dec789e2711212b1f7a32f98c42d75e0ff",
|
"sha512": "24eeff047a24085413283ee42539a2feea4d3de81077664861399055a9d30349a0ef0950746bb0b0ee2237b4b9ee215340204ab0e33347b53dc2acee85fcfc19",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"//": "Bypass broken url-template with anitya checker - See https://github.com/flathub/flatpak-external-data-checker/issues/360",
|
"//": "Bypass broken url-template with anitya checker - See https://github.com/flathub/flatpak-external-data-checker/issues/360",
|
||||||
"type": "json",
|
"type": "json",
|
||||||
|
@ -365,8 +366,8 @@
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/json-c/json-c.git",
|
"url": "https://github.com/json-c/json-c.git",
|
||||||
"tag": "json-c-0.16-20220414",
|
"tag": "json-c-0.17-20230812",
|
||||||
"commit": "2f2ddc1f2dbca56c874e8f9c31b5b963202d80e7",
|
"commit": "b4c371fa0cbc4dcbaccc359ce9e957a22988fb34",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"tag-pattern": "^json-c-([\\d.]+)-[\\d]+$"
|
"tag-pattern": "^json-c-([\\d.]+)-[\\d]+$"
|
||||||
|
@ -469,8 +470,8 @@
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/xianyi/OpenBLAS/archive/v0.3.23.tar.gz",
|
"url": "https://github.com/xianyi/OpenBLAS/archive/v0.3.24.tar.gz",
|
||||||
"sha256": "5d9491d07168a5d00116cdc068a40022c3455bf9293c7cb86a65b1054d7e5114",
|
"sha256": "ceadc5065da97bd92404cac7254da66cc6eb192679cf1002098688978d4d5132",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 2540,
|
"project-id": 2540,
|
||||||
|
@ -616,8 +617,8 @@
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/strukturag/libheif/releases/download/v1.16.2/libheif-1.16.2.tar.gz",
|
"url": "https://github.com/strukturag/libheif/releases/download/v1.17.3/libheif-1.17.3.tar.gz",
|
||||||
"sha256": "7f97e4205c0bd9f9b8560536c8bd2e841d1c9a6d610401eb3eb87ed9cdfe78ea",
|
"sha256": "8d5b6292e7931324f81f871f250ecbb9f874aa3c66b4f6f35ceb0bf3163b53ea",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 64439,
|
"project-id": 64439,
|
||||||
|
|
|
@ -57,7 +57,6 @@ download_lang Galician.isl
|
||||||
download_lang Georgian.isl
|
download_lang Georgian.isl
|
||||||
download_lang Greek.isl
|
download_lang Greek.isl
|
||||||
download_lang Indonesian.isl
|
download_lang Indonesian.isl
|
||||||
download_lang Korean.isl
|
|
||||||
download_lang Latvian.isl
|
download_lang Latvian.isl
|
||||||
download_lang Lithuanian.isl
|
download_lang Lithuanian.isl
|
||||||
download_lang Malaysian.isl
|
download_lang Malaysian.isl
|
||||||
|
@ -67,9 +66,9 @@ download_lang Swedish.isl
|
||||||
download_lang Vietnamese.isl
|
download_lang Vietnamese.isl
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
# Hungarian is not in a release yet, but was moved from Unofficial
|
# Any language not in a release yet, but moved from Unofficial, should be added here
|
||||||
cd "${ISCCDIR}/Languages/"
|
cd "${ISCCDIR}/Languages/"
|
||||||
download_lang_official Hungarian.isl
|
download_lang_official Korean.isl
|
||||||
cd -
|
cd -
|
||||||
|
|
||||||
# Copy generated language files into the source directory.
|
# Copy generated language files into the source directory.
|
||||||
|
|
|
@ -157,6 +157,9 @@ cp -fr ${MSYS_PREFIX}/share/xml/iso-codes/iso_639.xml ${PIKA_DISTRIB}/share/xml/
|
||||||
# Adwaita can be used as the base icon set.
|
# Adwaita can be used as the base icon set.
|
||||||
cp -fr ${MSYS_PREFIX}/share/icons/Adwaita ${PIKA_DISTRIB}/share/icons/
|
cp -fr ${MSYS_PREFIX}/share/icons/Adwaita ${PIKA_DISTRIB}/share/icons/
|
||||||
|
|
||||||
|
# Gdbus is needed to avoid warnings in CMD.
|
||||||
|
cp -fr ${MSYS_PREFIX}/bin/gdbus.exe ${PIKA_DISTRIB}/bin
|
||||||
|
|
||||||
# XXX Why are these for exactly?
|
# XXX Why are these for exactly?
|
||||||
cp -fr ${MSYS_PREFIX}/bin/gspawn*.exe ${PIKA_DISTRIB}/bin/
|
cp -fr ${MSYS_PREFIX}/bin/gspawn*.exe ${PIKA_DISTRIB}/bin/
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ exr
|
||||||
gif
|
gif
|
||||||
heif
|
heif
|
||||||
heic
|
heic
|
||||||
|
hej2
|
||||||
icns
|
icns
|
||||||
jp2
|
jp2
|
||||||
j2k
|
j2k
|
||||||
|
|
|
@ -216,7 +216,7 @@ Name: "it"; MessagesFile: "compiler:Languages\Italian.isl,lang\it.setup.isl"
|
||||||
Name: "ja"; MessagesFile: "compiler:Languages\Japanese.isl,lang\ja.setup.isl"
|
Name: "ja"; MessagesFile: "compiler:Languages\Japanese.isl,lang\ja.setup.isl"
|
||||||
Name: "ka"; MessagesFile: "compiler:Languages\Unofficial\Georgian.isl,lang\ka.setup.isl"
|
Name: "ka"; MessagesFile: "compiler:Languages\Unofficial\Georgian.isl,lang\ka.setup.isl"
|
||||||
Name: "kab"; MessagesFile: "compiler:Default.isl,lang\kab.isl,lang\kab.setup.isl"
|
Name: "kab"; MessagesFile: "compiler:Default.isl,lang\kab.isl,lang\kab.setup.isl"
|
||||||
Name: "ko"; MessagesFile: "compiler:Languages\Unofficial\Korean.isl,lang\ko.setup.isl"
|
Name: "ko"; MessagesFile: "compiler:Languages\Korean.isl,lang\ko.setup.isl"
|
||||||
Name: "lt"; MessagesFile: "compiler:Languages\Unofficial\Lithuanian.isl,lang\lt.setup.isl"
|
Name: "lt"; MessagesFile: "compiler:Languages\Unofficial\Lithuanian.isl,lang\lt.setup.isl"
|
||||||
Name: "lv"; MessagesFile: "compiler:Languages\Unofficial\Latvian.isl,lang\lv.setup.isl"
|
Name: "lv"; MessagesFile: "compiler:Languages\Unofficial\Latvian.isl,lang\lv.setup.isl"
|
||||||
Name: "mr"; MessagesFile: "compiler:Languages\Unofficial\Marathi.islu,lang\mr.setup.isl"
|
Name: "mr"; MessagesFile: "compiler:Languages\Unofficial\Marathi.islu,lang\mr.setup.isl"
|
||||||
|
|
|
@ -407,6 +407,32 @@
|
||||||
</description>
|
</description>
|
||||||
</release>
|
</release>
|
||||||
|
|
||||||
|
<release version="2.10.36" date="2023-11-05">
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
This new version of PIKA comes with many fixes, including
|
||||||
|
vulnerability corrections. It is highly recommended to update. It
|
||||||
|
also provides a few interesting changes, such as:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Adobe ACB and ASE palette support
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
New gradient: FG to Transparent (Hardedge)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Some text tool algorithm enhancement when replacing formatted text
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Better theming of item locks (when hovering them or setting them active)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Improvements in handling a few specific metadata
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="2.10.34" date="2023-02-21">
|
<release version="2.10.34" date="2023-02-21">
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include <libpika/pikafont_pdb.h>
|
#include <libpika/pikafont_pdb.h>
|
||||||
#include <libpika/pikafonts_pdb.h>
|
#include <libpika/pikafonts_pdb.h>
|
||||||
#include <libpika/pikafontselect_pdb.h>
|
#include <libpika/pikafontselect_pdb.h>
|
||||||
|
#include <libpika/pikapikarc_pdb.h>
|
||||||
#include <libpika/pikagradient_pdb.h>
|
#include <libpika/pikagradient_pdb.h>
|
||||||
#include <libpika/pikagradients_pdb.h>
|
#include <libpika/pikagradients_pdb.h>
|
||||||
#include <libpika/pikagradientselect_pdb.h>
|
#include <libpika/pikagradientselect_pdb.h>
|
||||||
|
@ -71,7 +72,6 @@
|
||||||
#include <libpika/pikapattern_pdb.h>
|
#include <libpika/pikapattern_pdb.h>
|
||||||
#include <libpika/pikapatterns_pdb.h>
|
#include <libpika/pikapatterns_pdb.h>
|
||||||
#include <libpika/pikapatternselect_pdb.h>
|
#include <libpika/pikapatternselect_pdb.h>
|
||||||
#include <libpika/pikapikarc_pdb.h>
|
|
||||||
#include <libpika/pikaprogress_pdb.h>
|
#include <libpika/pikaprogress_pdb.h>
|
||||||
#include <libpika/pikaresource_pdb.h>
|
#include <libpika/pikaresource_pdb.h>
|
||||||
#include <libpika/pikaselection_pdb.h>
|
#include <libpika/pikaselection_pdb.h>
|
||||||
|
|
|
@ -1191,14 +1191,14 @@ pika_vectors_import_from_string (PikaImage *image,
|
||||||
* pika_vectors_export_to_file:
|
* pika_vectors_export_to_file:
|
||||||
* @image: The image.
|
* @image: The image.
|
||||||
* @file: The SVG file to create.
|
* @file: The SVG file to create.
|
||||||
* @vectors: The vectors object to be saved, or 0 for all in the image.
|
* @vectors: The vectors object to export, or %NULL for all in the image.
|
||||||
*
|
*
|
||||||
* save a path as an SVG file.
|
* save a path as an SVG file.
|
||||||
*
|
*
|
||||||
* This procedure creates an SVG file to save a Vectors object, that
|
* This procedure creates an SVG file to save a Vectors object, that
|
||||||
* is, a path. The resulting file can be edited using a vector graphics
|
* is, a path. The resulting file can be edited using a vector graphics
|
||||||
* application, or later reloaded into PIKA. If you pass 0 as the
|
* application, or later reloaded into PIKA. Pass %NULL as the
|
||||||
* 'vectors' argument, then all paths in the image will be exported.
|
* 'vectors' argument to export all paths in the image.
|
||||||
*
|
*
|
||||||
* Returns: TRUE on success.
|
* Returns: TRUE on success.
|
||||||
*
|
*
|
||||||
|
@ -1234,14 +1234,14 @@ pika_vectors_export_to_file (PikaImage *image,
|
||||||
/**
|
/**
|
||||||
* pika_vectors_export_to_string:
|
* pika_vectors_export_to_string:
|
||||||
* @image: The image.
|
* @image: The image.
|
||||||
* @vectors: The vectors object to save, or 0 for all in the image.
|
* @vectors: The vectors object to export, or %NULL for all in the image.
|
||||||
*
|
*
|
||||||
* Save a path as an SVG string.
|
* Save a path as an SVG string.
|
||||||
*
|
*
|
||||||
* This procedure works like pika_vectors_export_to_file() but creates
|
* This procedure works like pika_vectors_export_to_file() but creates
|
||||||
* a string rather than a file. The contents are a NUL-terminated
|
* a string rather than a file. The string is NULL-terminated and holds
|
||||||
* string that holds a complete XML document. If you pass 0 as the
|
* a complete XML document. Pass %NULL as the 'vectors' argument to
|
||||||
* 'vectors' argument, then all paths in the image will be exported.
|
* export all paths in the image.
|
||||||
*
|
*
|
||||||
* Returns: (transfer full):
|
* Returns: (transfer full):
|
||||||
* A string whose contents are a complete SVG document.
|
* A string whose contents are a complete SVG document.
|
||||||
|
|
|
@ -351,6 +351,7 @@ pika_config_param_spec_duplicate (GParamSpec *pspec)
|
||||||
* with type names instead.
|
* with type names instead.
|
||||||
*/
|
*/
|
||||||
g_strcmp0 (type_name, "PikaImage") == 0 ||
|
g_strcmp0 (type_name, "PikaImage") == 0 ||
|
||||||
|
g_strcmp0 (type_name, "PikaDisplay") == 0 ||
|
||||||
g_strcmp0 (type_name, "PikaDrawable") == 0 ||
|
g_strcmp0 (type_name, "PikaDrawable") == 0 ||
|
||||||
g_strcmp0 (type_name, "PikaLayer") == 0 ||
|
g_strcmp0 (type_name, "PikaLayer") == 0 ||
|
||||||
g_strcmp0 (type_name, "PikaTextLayer") == 0 ||
|
g_strcmp0 (type_name, "PikaTextLayer") == 0 ||
|
||||||
|
|
|
@ -96,7 +96,9 @@ static void pika_dialog_close (GtkDialog *dialog);
|
||||||
static void pika_dialog_response (GtkDialog *dialog,
|
static void pika_dialog_response (GtkDialog *dialog,
|
||||||
gint response_id);
|
gint response_id);
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
static void pika_dialog_set_title_bar_theme (GtkWidget *dialog);
|
static void pika_dialog_set_title_bar_theme (GtkWidget *dialog);
|
||||||
|
#endif
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (PikaDialog, pika_dialog, GTK_TYPE_DIALOG)
|
G_DEFINE_TYPE_WITH_PRIVATE (PikaDialog, pika_dialog, GTK_TYPE_DIALOG)
|
||||||
|
|
||||||
|
@ -770,10 +772,10 @@ pika_dialogs_show_help_button (gboolean show)
|
||||||
show_help_button = show ? TRUE : FALSE;
|
show_help_button = show ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
void
|
void
|
||||||
pika_dialog_set_title_bar_theme (GtkWidget *dialog)
|
pika_dialog_set_title_bar_theme (GtkWidget *dialog)
|
||||||
{
|
{
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
gboolean use_dark_mode = FALSE;
|
gboolean use_dark_mode = FALSE;
|
||||||
GdkWindow *window = NULL;
|
GdkWindow *window = NULL;
|
||||||
|
@ -810,5 +812,5 @@ pika_dialog_set_title_bar_theme (GtkWidget *dialog)
|
||||||
gdk_window_hide (window);
|
gdk_window_hide (window);
|
||||||
gdk_window_show (window);
|
gdk_window_show (window);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -90,10 +90,16 @@
|
||||||
<item><attribute name="action">app.edit-paste-in-place</attribute></item>
|
<item><attribute name="action">app.edit-paste-in-place</attribute></item>
|
||||||
<submenu>
|
<submenu>
|
||||||
<attribute name="label" translatable="yes" context="edit-action">Paste _as</attribute>
|
<attribute name="label" translatable="yes" context="edit-action">Paste _as</attribute>
|
||||||
<item><attribute name="action">app.edit-paste-merged</attribute></item>
|
<section>
|
||||||
<item><attribute name="action">app.edit-paste-merged-in-place</attribute></item>
|
<item><attribute name="action">app.edit-paste-merged</attribute></item>
|
||||||
<item><attribute name="action">app.edit-paste-into</attribute></item>
|
<item><attribute name="action">app.edit-paste-merged-in-place</attribute></item>
|
||||||
<item><attribute name="action">app.edit-paste-into-in-place</attribute></item>
|
</section>
|
||||||
|
<section>
|
||||||
|
<item><attribute name="action">app.edit-paste-float</attribute></item>
|
||||||
|
<item><attribute name="action">app.edit-paste-float-in-place</attribute></item>
|
||||||
|
<item><attribute name="action">app.edit-paste-into</attribute></item>
|
||||||
|
<item><attribute name="action">app.edit-paste-into-in-place</attribute></item>
|
||||||
|
</section>
|
||||||
<item><attribute name="action">app.edit-paste-as-new-image</attribute><attribute name="label-variant">long</attribute></item>
|
<item><attribute name="action">app.edit-paste-as-new-image</attribute><attribute name="label-variant">long</attribute></item>
|
||||||
</submenu>
|
</submenu>
|
||||||
<submenu>
|
<submenu>
|
||||||
|
@ -143,7 +149,11 @@
|
||||||
<item><attribute name="action">app.select-all</attribute></item>
|
<item><attribute name="action">app.select-all</attribute></item>
|
||||||
<item><attribute name="action">app.select-none</attribute></item>
|
<item><attribute name="action">app.select-none</attribute></item>
|
||||||
<item><attribute name="action">app.select-invert</attribute></item>
|
<item><attribute name="action">app.select-invert</attribute></item>
|
||||||
<item><attribute name="action">app.select-float</attribute></item>
|
<submenu>
|
||||||
|
<attribute name="label" translatable="yes" context="view-action">_Float</attribute>
|
||||||
|
<item><attribute name="action">app.select-cut-float</attribute></item>
|
||||||
|
<item><attribute name="action">app.select-copy-float</attribute></item>
|
||||||
|
</submenu>
|
||||||
<item><attribute name="action">app.tools-by-color-select-short</attribute></item>
|
<item><attribute name="action">app.tools-by-color-select-short</attribute></item>
|
||||||
<item><attribute name="action">app.vectors-selection-from-vectors</attribute></item>
|
<item><attribute name="action">app.vectors-selection-from-vectors</attribute></item>
|
||||||
<item><attribute name="action">app.dialogs-selection-editor</attribute></item>
|
<item><attribute name="action">app.dialogs-selection-editor</attribute></item>
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
<item><attribute name="action">app.select-none</attribute></item>
|
<item><attribute name="action">app.select-none</attribute></item>
|
||||||
<item><attribute name="action">app.select-invert</attribute></item>
|
<item><attribute name="action">app.select-invert</attribute></item>
|
||||||
<item><attribute name="action">app.vectors-selection-from-vectors</attribute></item>
|
<item><attribute name="action">app.vectors-selection-from-vectors</attribute></item>
|
||||||
<item><attribute name="action">app.select-float</attribute></item>
|
<section>
|
||||||
|
<item><attribute name="action">app.select-cut-float</attribute></item>
|
||||||
|
<item><attribute name="action">app.select-copy-float</attribute></item>
|
||||||
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<item><attribute name="action">app.select-feather</attribute></item>
|
<item><attribute name="action">app.select-feather</attribute></item>
|
||||||
<item><attribute name="action">app.select-sharpen</attribute></item>
|
<item><attribute name="action">app.select-sharpen</attribute></item>
|
||||||
|
|
|
@ -1255,8 +1255,8 @@ sub vectors_export_to_file {
|
||||||
$help = <<'HELP';
|
$help = <<'HELP';
|
||||||
This procedure creates an SVG file to save a Vectors object, that is,
|
This procedure creates an SVG file to save a Vectors object, that is,
|
||||||
a path. The resulting file can be edited using a vector graphics
|
a path. The resulting file can be edited using a vector graphics
|
||||||
application, or later reloaded into PIKA. If you pass 0 as the 'vectors'
|
application, or later reloaded into PIKA. Pass %NULL as the 'vectors'
|
||||||
argument, then all paths in the image will be exported.
|
argument to export all paths in the image.
|
||||||
HELP
|
HELP
|
||||||
|
|
||||||
&bill_pdb_misc('2007', '2.6');
|
&bill_pdb_misc('2007', '2.6');
|
||||||
|
@ -1267,14 +1267,17 @@ HELP
|
||||||
{ name => 'file', type => 'file',
|
{ name => 'file', type => 'file',
|
||||||
desc => 'The SVG file to create.' },
|
desc => 'The SVG file to create.' },
|
||||||
{ name => 'vectors', type => 'vectors', no_validate => 1,
|
{ name => 'vectors', type => 'vectors', no_validate => 1,
|
||||||
desc => 'The vectors object to be saved, or 0 for all in the image' }
|
desc => 'The vectors object to export, or %NULL for all in the image' }
|
||||||
);
|
);
|
||||||
|
|
||||||
%invoke = (
|
%invoke = (
|
||||||
headers => [ qw("vectors/pikavectors-export.h") ],
|
headers => [ qw("vectors/pikavectors-export.h") ],
|
||||||
code => <<'CODE'
|
code => <<'CODE'
|
||||||
{
|
{
|
||||||
GList *vectors_list = g_list_prepend (NULL, vectors);
|
GList *vectors_list = NULL;
|
||||||
|
|
||||||
|
if (vectors != NULL)
|
||||||
|
vectors_list = g_list_prepend (vectors_list, vectors);
|
||||||
|
|
||||||
success = pika_vectors_export_file (image, vectors_list, file, error);
|
success = pika_vectors_export_file (image, vectors_list, file, error);
|
||||||
|
|
||||||
|
@ -1289,9 +1292,9 @@ sub vectors_export_to_string {
|
||||||
|
|
||||||
$help = <<'HELP';
|
$help = <<'HELP';
|
||||||
This procedure works like pika_vectors_export_to_file() but creates a string
|
This procedure works like pika_vectors_export_to_file() but creates a string
|
||||||
rather than a file. The contents are a NUL-terminated string that holds a
|
rather than a file. The string is NULL-terminated and holds a
|
||||||
complete XML document. If you pass 0 as the 'vectors' argument, then all
|
complete XML document. Pass %NULL as the 'vectors' argument to export
|
||||||
paths in the image will be exported.
|
all paths in the image.
|
||||||
HELP
|
HELP
|
||||||
|
|
||||||
&bill_pdb_misc('2007', '2.6');
|
&bill_pdb_misc('2007', '2.6');
|
||||||
|
@ -1300,7 +1303,7 @@ HELP
|
||||||
{ name => 'image', type => 'image',
|
{ name => 'image', type => 'image',
|
||||||
desc => 'The image' },
|
desc => 'The image' },
|
||||||
{ name => 'vectors', type => 'vectors', no_validate => 1,
|
{ name => 'vectors', type => 'vectors', no_validate => 1,
|
||||||
desc => 'The vectors object to save, or 0 for all in the image' }
|
desc => 'The vectors object to export, or %NULL for all in the image' }
|
||||||
);
|
);
|
||||||
|
|
||||||
@outargs = (
|
@outargs = (
|
||||||
|
@ -1312,7 +1315,10 @@ HELP
|
||||||
headers => [ qw("vectors/pikavectors-export.h") ],
|
headers => [ qw("vectors/pikavectors-export.h") ],
|
||||||
code => <<'CODE'
|
code => <<'CODE'
|
||||||
{
|
{
|
||||||
GList *vectors_list = g_list_prepend (NULL, vectors);
|
GList *vectors_list = NULL;
|
||||||
|
|
||||||
|
if (vectors != NULL)
|
||||||
|
vectors_list = g_list_prepend (vectors_list, vectors);
|
||||||
|
|
||||||
string = pika_vectors_export_string (image, vectors_list);
|
string = pika_vectors_export_string (image, vectors_list);
|
||||||
g_list_free (vectors_list);
|
g_list_free (vectors_list);
|
||||||
|
|
|
@ -352,7 +352,8 @@ static struct
|
||||||
gint delayTime;
|
gint delayTime;
|
||||||
gint inputFlag;
|
gint inputFlag;
|
||||||
gint disposal;
|
gint disposal;
|
||||||
} Gif89 = { -1, -1, -1, 0 };
|
gint num_loops;
|
||||||
|
} Gif89 = { -1, -1, -1, 0, -1 };
|
||||||
|
|
||||||
static void read_error (const gchar *error_type,
|
static void read_error (const gchar *error_type,
|
||||||
PikaImage *image,
|
PikaImage *image,
|
||||||
|
@ -399,9 +400,10 @@ load_image (GFile *file,
|
||||||
gint grayScale;
|
gint grayScale;
|
||||||
gboolean useGlobalColormap;
|
gboolean useGlobalColormap;
|
||||||
gint bitPixel;
|
gint bitPixel;
|
||||||
gint imageCount = 0;
|
gint imageCount = 0;
|
||||||
PikaImage *image = NULL;
|
PikaImage *image = NULL;
|
||||||
gboolean status;
|
gboolean status;
|
||||||
|
gboolean saved_parasite = FALSE;
|
||||||
|
|
||||||
pika_progress_init_printf (_("Opening '%s'"),
|
pika_progress_init_printf (_("Opening '%s'"),
|
||||||
pika_file_get_utf8_name (file));
|
pika_file_get_utf8_name (file));
|
||||||
|
@ -590,6 +592,25 @@ load_image (GFile *file,
|
||||||
/* If we are loading a thumbnail, we stop after the first frame. */
|
/* If we are loading a thumbnail, we stop after the first frame. */
|
||||||
if (thumbnail)
|
if (thumbnail)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* If there is more than one frame, we add a parasite so that
|
||||||
|
* we know to export as an animation on overwrite */
|
||||||
|
if (Gif89.num_loops > -1 && ! saved_parasite)
|
||||||
|
{
|
||||||
|
PikaParasite *parasite;
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
str = g_strdup_printf ("%d", Gif89.num_loops);
|
||||||
|
parasite = pika_parasite_new ("gif/animated",
|
||||||
|
PIKA_PARASITE_PERSISTENT,
|
||||||
|
strlen (str) + 1,
|
||||||
|
(gpointer) str);
|
||||||
|
g_free (str);
|
||||||
|
|
||||||
|
pika_image_attach_parasite (image, parasite);
|
||||||
|
pika_parasite_free (parasite);
|
||||||
|
saved_parasite = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose (fd);
|
fclose (fd);
|
||||||
|
@ -690,6 +711,15 @@ DoExtension (FILE *fd,
|
||||||
#ifdef GIFDEBUG
|
#ifdef GIFDEBUG
|
||||||
str = "Application Extension";
|
str = "Application Extension";
|
||||||
#endif
|
#endif
|
||||||
|
/* Animation block */
|
||||||
|
if (GetDataBlock (fd, (guchar *) buf))
|
||||||
|
{
|
||||||
|
if (strncmp ((const gchar *) buf, "NETSCAPE2.0", 8) == 0)
|
||||||
|
{
|
||||||
|
if (GetDataBlock (fd, (guchar *) buf))
|
||||||
|
Gif89.num_loops = (buf[0] << 8) | buf[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0xfe: /* Comment Extension */
|
case 0xfe: /* Comment Extension */
|
||||||
#ifdef GIFDEBUG
|
#ifdef GIFDEBUG
|
||||||
|
|
|
@ -268,6 +268,7 @@ gif_save (PikaProcedure *procedure,
|
||||||
PikaExportReturn export = PIKA_EXPORT_CANCEL;
|
PikaExportReturn export = PIKA_EXPORT_CANCEL;
|
||||||
PikaImage *orig_image;
|
PikaImage *orig_image;
|
||||||
PikaImage *sanitized_image = NULL;
|
PikaImage *sanitized_image = NULL;
|
||||||
|
PikaParasite *parasite = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
gegl_init (NULL, NULL);
|
gegl_init (NULL, NULL);
|
||||||
|
@ -288,6 +289,34 @@ gif_save (PikaProcedure *procedure,
|
||||||
*/
|
*/
|
||||||
sanitized_image = image;
|
sanitized_image = image;
|
||||||
|
|
||||||
|
/* If imported as an animation, set the animation configurations
|
||||||
|
* when overwriting the file */
|
||||||
|
parasite = pika_image_get_parasite (image, "gif/animated");
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
gint num_loops;
|
||||||
|
gchar *parasite_data;
|
||||||
|
guint32 parasite_size;
|
||||||
|
|
||||||
|
parasite_data = (gchar *) pika_parasite_get_data (parasite, ¶site_size);
|
||||||
|
parasite_data = g_strndup (parasite_data, parasite_size);
|
||||||
|
|
||||||
|
if (sscanf (parasite_data, "%i", &num_loops) == 1)
|
||||||
|
{
|
||||||
|
gboolean loop = (num_loops == 0);
|
||||||
|
|
||||||
|
g_object_set (config,
|
||||||
|
"as-animation", TRUE,
|
||||||
|
"loop", loop,
|
||||||
|
"number-of-repeats", num_loops,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
pika_image_detach_parasite (image, "gif/animated");
|
||||||
|
g_free (parasite);
|
||||||
|
g_free (parasite_data);
|
||||||
|
}
|
||||||
|
|
||||||
if (run_mode == PIKA_RUN_INTERACTIVE)
|
if (run_mode == PIKA_RUN_INTERACTIVE)
|
||||||
{
|
{
|
||||||
if (! save_dialog (image, procedure, G_OBJECT (config)))
|
if (! save_dialog (image, procedure, G_OBJECT (config)))
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#define LOAD_PROC "file-heif-load"
|
#define LOAD_PROC "file-heif-load"
|
||||||
#define LOAD_PROC_AV1 "file-heif-av1-load"
|
#define LOAD_PROC_AV1 "file-heif-av1-load"
|
||||||
|
#define LOAD_PROC_HEJ2 "file-heif-hej2-load"
|
||||||
#define SAVE_PROC "file-heif-save"
|
#define SAVE_PROC "file-heif-save"
|
||||||
#define SAVE_PROC_AV1 "file-heif-av1-save"
|
#define SAVE_PROC_AV1 "file-heif-av1-save"
|
||||||
#define PLUG_IN_BINARY "file-heif"
|
#define PLUG_IN_BINARY "file-heif"
|
||||||
|
@ -103,6 +104,8 @@ static PikaValueArray * heif_av1_save (PikaProcedure *pro
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PikaImage * load_image (GFile *file,
|
static PikaImage * load_image (GFile *file,
|
||||||
|
PikaMetadata *metadata,
|
||||||
|
PikaMetadataLoadFlags *flags,
|
||||||
gboolean interactive,
|
gboolean interactive,
|
||||||
PikaPDBStatusType *status,
|
PikaPDBStatusType *status,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -172,6 +175,13 @@ heif_init_procedures (PikaPlugIn *plug_in)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LIBHEIF_HAVE_VERSION(1,17,0)
|
||||||
|
if (heif_have_decoder_for_format (heif_compression_JPEG2000))
|
||||||
|
{
|
||||||
|
list = g_list_append (list, g_strdup (LOAD_PROC_HEJ2));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LIBHEIF_HAVE_VERSION(1,13,0)
|
#if LIBHEIF_HAVE_VERSION(1,13,0)
|
||||||
heif_deinit ();
|
heif_deinit ();
|
||||||
#endif
|
#endif
|
||||||
|
@ -412,6 +422,33 @@ heif_create_procedure (PikaPlugIn *plug_in,
|
||||||
pika_export_xmp (),
|
pika_export_xmp (),
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if LIBHEIF_HAVE_VERSION(1,17,0)
|
||||||
|
else if (! strcmp (name, LOAD_PROC_HEJ2))
|
||||||
|
{
|
||||||
|
procedure = pika_load_procedure_new (plug_in, name, PIKA_PDB_PROC_TYPE_PLUGIN,
|
||||||
|
heif_load, NULL, NULL);
|
||||||
|
|
||||||
|
pika_procedure_set_menu_label (procedure, _("JPEG 2000 encapsulated in HEIF"));
|
||||||
|
|
||||||
|
pika_procedure_set_documentation (procedure,
|
||||||
|
_("Loads HEJ2 images"),
|
||||||
|
_("Load JPEG 2000 image encapsulated in HEIF (HEJ2)"),
|
||||||
|
name);
|
||||||
|
pika_procedure_set_attribution (procedure,
|
||||||
|
"Daniel Novomesky <dnovomesky@gmail.com>",
|
||||||
|
"Daniel Novomesky <dnovomesky@gmail.com>",
|
||||||
|
"2023");
|
||||||
|
|
||||||
|
pika_file_procedure_set_handles_remote (PIKA_FILE_PROCEDURE (procedure), TRUE);
|
||||||
|
pika_file_procedure_set_mime_types (PIKA_FILE_PROCEDURE (procedure),
|
||||||
|
"image/hej2k");
|
||||||
|
pika_file_procedure_set_extensions (PIKA_FILE_PROCEDURE (procedure),
|
||||||
|
"hej2");
|
||||||
|
|
||||||
|
pika_file_procedure_set_magics (PIKA_FILE_PROCEDURE (procedure),
|
||||||
|
"4,string,ftypj2ki");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return procedure;
|
return procedure;
|
||||||
}
|
}
|
||||||
|
@ -442,7 +479,7 @@ heif_load (PikaProcedure *procedure,
|
||||||
heif_init (NULL);
|
heif_init (NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
image = load_image (file, interactive, &status, &error);
|
image = load_image (file, metadata, flags, interactive, &status, &error);
|
||||||
|
|
||||||
#if LIBHEIF_HAVE_VERSION(1,13,0)
|
#if LIBHEIF_HAVE_VERSION(1,13,0)
|
||||||
heif_deinit ();
|
heif_deinit ();
|
||||||
|
@ -836,10 +873,12 @@ nclx_to_pika_profile (const struct heif_color_profile_nclx *nclx)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PikaImage *
|
PikaImage *
|
||||||
load_image (GFile *file,
|
load_image (GFile *file,
|
||||||
gboolean interactive,
|
PikaMetadata *metadata,
|
||||||
PikaPDBStatusType *status,
|
PikaMetadataLoadFlags *flags,
|
||||||
GError **error)
|
gboolean interactive,
|
||||||
|
PikaPDBStatusType *status,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
GInputStream *input;
|
GInputStream *input;
|
||||||
goffset file_size;
|
goffset file_size;
|
||||||
|
@ -1267,117 +1306,111 @@ load_image (GFile *file,
|
||||||
|
|
||||||
g_object_unref (buffer);
|
g_object_unref (buffer);
|
||||||
|
|
||||||
{
|
if (metadata)
|
||||||
size_t exif_data_size = 0;
|
{
|
||||||
uint8_t *exif_data = NULL;
|
size_t exif_data_size = 0;
|
||||||
size_t xmp_data_size = 0;
|
uint8_t *exif_data = NULL;
|
||||||
uint8_t *xmp_data = NULL;
|
size_t xmp_data_size = 0;
|
||||||
gint n_metadata;
|
uint8_t *xmp_data = NULL;
|
||||||
heif_item_id metadata_id;
|
gint n_metadata;
|
||||||
|
heif_item_id metadata_id;
|
||||||
|
|
||||||
n_metadata =
|
n_metadata = heif_image_handle_get_list_of_metadata_block_IDs (handle, "Exif",
|
||||||
heif_image_handle_get_list_of_metadata_block_IDs (handle,
|
&metadata_id, 1);
|
||||||
"Exif",
|
if (n_metadata > 0)
|
||||||
&metadata_id, 1);
|
{
|
||||||
if (n_metadata > 0)
|
exif_data_size = heif_image_handle_get_metadata_size (handle, metadata_id);
|
||||||
{
|
|
||||||
exif_data_size = heif_image_handle_get_metadata_size (handle,
|
|
||||||
metadata_id);
|
|
||||||
exif_data = g_alloca (exif_data_size);
|
|
||||||
|
|
||||||
err = heif_image_handle_get_metadata (handle, metadata_id, exif_data);
|
exif_data = g_alloca (exif_data_size);
|
||||||
if (err.code != 0)
|
|
||||||
{
|
|
||||||
exif_data = NULL;
|
|
||||||
exif_data_size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n_metadata =
|
err = heif_image_handle_get_metadata (handle, metadata_id, exif_data);
|
||||||
heif_image_handle_get_list_of_metadata_block_IDs (handle,
|
if (err.code != 0)
|
||||||
"mime",
|
{
|
||||||
&metadata_id, 1);
|
exif_data = NULL;
|
||||||
if (n_metadata > 0)
|
exif_data_size = 0;
|
||||||
{
|
}
|
||||||
if (g_strcmp0 (
|
}
|
||||||
heif_image_handle_get_metadata_content_type (handle, metadata_id),
|
|
||||||
"application/rdf+xml") == 0)
|
|
||||||
{
|
|
||||||
xmp_data_size = heif_image_handle_get_metadata_size (handle,
|
|
||||||
metadata_id);
|
|
||||||
xmp_data = g_alloca (xmp_data_size);
|
|
||||||
|
|
||||||
err = heif_image_handle_get_metadata (handle, metadata_id, xmp_data);
|
n_metadata = heif_image_handle_get_list_of_metadata_block_IDs (handle, "mime",
|
||||||
if (err.code != 0)
|
&metadata_id, 1);
|
||||||
{
|
if (n_metadata > 0)
|
||||||
xmp_data = NULL;
|
{
|
||||||
xmp_data_size = 0;
|
if (g_strcmp0 (heif_image_handle_get_metadata_content_type (handle, metadata_id), "application/rdf+xml")
|
||||||
}
|
== 0)
|
||||||
}
|
{
|
||||||
}
|
xmp_data_size = heif_image_handle_get_metadata_size (handle, metadata_id);
|
||||||
|
|
||||||
if (exif_data || xmp_data)
|
xmp_data = g_alloca (xmp_data_size);
|
||||||
{
|
|
||||||
PikaMetadata *metadata = pika_metadata_new ();
|
|
||||||
PikaMetadataLoadFlags flags = PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION;
|
|
||||||
|
|
||||||
if (exif_data)
|
err = heif_image_handle_get_metadata (handle, metadata_id, xmp_data);
|
||||||
{
|
if (err.code != 0)
|
||||||
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
{
|
||||||
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
xmp_data = NULL;
|
||||||
GExiv2Metadata *exif_metadata = GEXIV2_METADATA (metadata);
|
xmp_data_size = 0;
|
||||||
const guint8 *tiffheader = exif_data;
|
}
|
||||||
glong new_exif_size = exif_data_size;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
if (exif_data || xmp_data)
|
||||||
{
|
{
|
||||||
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
gexiv2_metadata_clear (GEXIV2_METADATA (metadata));
|
||||||
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
|
||||||
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
new_exif_size--;
|
|
||||||
tiffheader++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_exif_size > 4) /* TIFF header + some data found*/
|
if (exif_data)
|
||||||
{
|
{
|
||||||
if (! gexiv2_metadata_open_buf (exif_metadata, tiffheader, new_exif_size, error))
|
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
||||||
{
|
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
||||||
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
GExiv2Metadata *exif_metadata = GEXIV2_METADATA (metadata);
|
||||||
g_clear_error (error);
|
const guint8 *tiffheader = exif_data;
|
||||||
}
|
glong new_exif_size = exif_data_size;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xmp_data)
|
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
||||||
{
|
{
|
||||||
if (!pika_metadata_set_from_xmp (metadata, xmp_data, xmp_data_size, error))
|
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
||||||
{
|
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
||||||
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
{
|
||||||
g_clear_error (error);
|
break;
|
||||||
}
|
}
|
||||||
}
|
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
||||||
|
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
new_exif_size--;
|
||||||
|
tiffheader++;
|
||||||
|
}
|
||||||
|
|
||||||
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
if (new_exif_size > 4) /* TIFF header + some data found*/
|
||||||
GEXIV2_ORIENTATION_NORMAL, NULL);
|
{
|
||||||
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata),
|
if (! gexiv2_metadata_open_buf (exif_metadata, tiffheader, new_exif_size, error))
|
||||||
width, NULL);
|
{
|
||||||
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||||
height, NULL);
|
g_clear_error (error);
|
||||||
pika_image_metadata_load_finish (image, "image/heif",
|
}
|
||||||
metadata, flags);
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
|
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmp_data)
|
||||||
|
{
|
||||||
|
if (! pika_metadata_set_from_xmp (metadata, xmp_data, xmp_data_size, error))
|
||||||
|
{
|
||||||
|
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||||
|
g_clear_error (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
||||||
|
GEXIV2_ORIENTATION_NORMAL, NULL);
|
||||||
|
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata), width, NULL);
|
||||||
|
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
||||||
|
height, NULL);
|
||||||
|
|
||||||
|
*flags = PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION;
|
||||||
|
}
|
||||||
|
|
||||||
if (profile)
|
if (profile)
|
||||||
g_object_unref (profile);
|
g_object_unref (profile);
|
||||||
|
|
|
@ -230,10 +230,10 @@ load_image (GFile *file,
|
||||||
{
|
{
|
||||||
ILBM_Image *true_image = iff_image[i];
|
ILBM_Image *true_image = iff_image[i];
|
||||||
/* Struct representing bitmap header properties */
|
/* Struct representing bitmap header properties */
|
||||||
ILBM_BitMapHeader *bitMapHeader = true_image->bitMapHeader;
|
ILBM_BitMapHeader *bitMapHeader;
|
||||||
/* Struct containing the color palette */
|
/* Struct containing the color palette */
|
||||||
ILBM_ColorMap *colorMap = true_image->colorMap;
|
ILBM_ColorMap *colorMap;
|
||||||
ILBM_Viewport *camg = true_image->viewport;
|
ILBM_Viewport *camg;
|
||||||
IFF_UByte *bitplanes;
|
IFF_UByte *bitplanes;
|
||||||
PikaImageType image_type;
|
PikaImageType image_type;
|
||||||
guchar pika_cmap[768]; /* Max index is (2^nplanes) - 1 */
|
guchar pika_cmap[768]; /* Max index is (2^nplanes) - 1 */
|
||||||
|
@ -244,29 +244,38 @@ load_image (GFile *file,
|
||||||
gint row_length;
|
gint row_length;
|
||||||
gint pixel_size = 1;
|
gint pixel_size = 1;
|
||||||
gint y_height = 0;
|
gint y_height = 0;
|
||||||
|
gint aspect_x = 0;
|
||||||
|
gint aspect_y = 0;
|
||||||
gboolean ehb_mode = FALSE;
|
gboolean ehb_mode = FALSE;
|
||||||
gboolean ham_mode = FALSE;
|
gboolean ham_mode = FALSE;
|
||||||
|
|
||||||
if (! true_image || ! bitMapHeader)
|
if (! true_image)
|
||||||
{
|
{
|
||||||
g_message (_("Invalid or missing ILBM image"));
|
g_message (_("Invalid or missing ILBM image"));
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
if (! true_image->body)
|
|
||||||
{
|
colorMap = true_image->colorMap;
|
||||||
g_message (_("ILBM contains no image data - likely a palette file"));
|
camg = true_image->viewport;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert ACBM files to ILBM format */
|
/* Convert ACBM files to ILBM format */
|
||||||
if (ILBM_imageIsACBM (true_image))
|
if (ILBM_imageIsACBM (true_image))
|
||||||
ILBM_convertACBMToILBM (true_image);
|
ILBM_convertACBMToILBM (true_image);
|
||||||
|
|
||||||
|
bitMapHeader = true_image->bitMapHeader;
|
||||||
|
if (! bitMapHeader || ! true_image->body)
|
||||||
|
{
|
||||||
|
g_message (_("ILBM contains no image data - likely a palette file"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
width = bitMapHeader->w;
|
width = bitMapHeader->w;
|
||||||
height = bitMapHeader->h;
|
height = bitMapHeader->h;
|
||||||
nPlanes = bitMapHeader->nPlanes;
|
nPlanes = bitMapHeader->nPlanes;
|
||||||
row_length = (width + 15) / 16;
|
row_length = (width + 15) / 16;
|
||||||
pixel_size = nPlanes / 8;
|
pixel_size = nPlanes / 8;
|
||||||
|
aspect_x = bitMapHeader->xAspect;
|
||||||
|
aspect_y = bitMapHeader->yAspect;
|
||||||
|
|
||||||
/* Check for ILBM variants in CMAG chunk */
|
/* Check for ILBM variants in CMAG chunk */
|
||||||
if (camg)
|
if (camg)
|
||||||
|
@ -329,8 +338,9 @@ load_image (GFile *file,
|
||||||
|
|
||||||
ILBM_unpackByteRun (true_image);
|
ILBM_unpackByteRun (true_image);
|
||||||
|
|
||||||
image = pika_image_new (width, height,
|
if (! image)
|
||||||
pixel_size == 1 ? PIKA_INDEXED : PIKA_RGB);
|
image = pika_image_new (width, height,
|
||||||
|
pixel_size == 1 ? PIKA_INDEXED : PIKA_RGB);
|
||||||
|
|
||||||
layer = pika_layer_new (image, _("Background"), width, height,
|
layer = pika_layer_new (image, _("Background"), width, height,
|
||||||
image_type, 100,
|
image_type, 100,
|
||||||
|
@ -341,6 +351,24 @@ load_image (GFile *file,
|
||||||
|
|
||||||
bitplanes = true_image->body->chunkData;
|
bitplanes = true_image->body->chunkData;
|
||||||
|
|
||||||
|
/* Setting resolution for non-square pixel aspect ratios */
|
||||||
|
if (aspect_x != aspect_y && aspect_x > 0 && aspect_y > 0)
|
||||||
|
{
|
||||||
|
gdouble image_xres;
|
||||||
|
gdouble image_yres;
|
||||||
|
gfloat ratio = (gfloat) aspect_x / aspect_y;
|
||||||
|
|
||||||
|
g_message (_("Non-square pixels. Image might look squashed if "
|
||||||
|
"Dot for Dot mode is enabled."));
|
||||||
|
|
||||||
|
pika_image_get_resolution (image, &image_xres, &image_yres);
|
||||||
|
if (ratio < 1)
|
||||||
|
image_xres = image_yres * (1 / ratio);
|
||||||
|
else
|
||||||
|
image_yres = image_xres * ratio;
|
||||||
|
pika_image_set_resolution (image, image_xres, image_yres);
|
||||||
|
}
|
||||||
|
|
||||||
/* Loading rows */
|
/* Loading rows */
|
||||||
for (gint j = 0; j < height; j++)
|
for (gint j = 0; j < height; j++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -396,9 +396,11 @@ create_cmyk_layer (PikaImage *image,
|
||||||
}
|
}
|
||||||
|
|
||||||
static PikaImage *
|
static PikaImage *
|
||||||
load_image (GFile *file,
|
load_image (GFile *file,
|
||||||
PikaRunMode runmode,
|
PikaRunMode runmode,
|
||||||
GError **error)
|
PikaMetadata *metadata,
|
||||||
|
PikaMetadataLoadFlags *flags,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
FILE *inputFile = g_fopen (g_file_peek_path (file), "rb");
|
FILE *inputFile = g_fopen (g_file_peek_path (file), "rb");
|
||||||
|
|
||||||
|
@ -430,6 +432,7 @@ load_image (GFile *file,
|
||||||
const Babl *type;
|
const Babl *type;
|
||||||
PikaPrecision precision_linear;
|
PikaPrecision precision_linear;
|
||||||
PikaPrecision precision_non_linear;
|
PikaPrecision precision_non_linear;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
if (!inputFile)
|
if (!inputFile)
|
||||||
{
|
{
|
||||||
|
@ -637,7 +640,7 @@ load_image (GFile *file,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for extra channels */
|
/* Check for extra channels */
|
||||||
for (gint32 i = 0; i < basicinfo.num_extra_channels; i++)
|
for (i = 0; i < basicinfo.num_extra_channels; i++)
|
||||||
{
|
{
|
||||||
JxlExtraChannelInfo extra;
|
JxlExtraChannelInfo extra;
|
||||||
|
|
||||||
|
@ -936,205 +939,208 @@ load_image (GFile *file,
|
||||||
g_object_unref (profile);
|
g_object_unref (profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (basicinfo.have_container)
|
if (metadata)
|
||||||
{
|
{
|
||||||
JxlDecoderReleaseInput (decoder);
|
if (basicinfo.have_container)
|
||||||
JxlDecoderRewind (decoder);
|
{
|
||||||
|
JxlDecoderReleaseInput (decoder);
|
||||||
|
JxlDecoderRewind (decoder);
|
||||||
|
|
||||||
if (JxlDecoderSetInput (decoder, memory, inputFileSize) != JXL_DEC_SUCCESS)
|
if (JxlDecoderSetInput (decoder, memory, inputFileSize) != JXL_DEC_SUCCESS)
|
||||||
{
|
|
||||||
g_printerr ("%s: JxlDecoderSetInput failed after JxlDecoderRewind\n", G_STRFUNC);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JxlDecoderCloseInput (decoder);
|
|
||||||
if (JxlDecoderSubscribeEvents (decoder, JXL_DEC_BOX) != JXL_DEC_SUCCESS)
|
|
||||||
{
|
{
|
||||||
g_printerr ("%s: JxlDecoderSubscribeEvents for JXL_DEC_BOX failed\n", G_STRFUNC);
|
g_printerr ("%s: JxlDecoderSetInput failed after JxlDecoderRewind\n", G_STRFUNC);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gboolean search_exif = TRUE;
|
JxlDecoderCloseInput (decoder);
|
||||||
gboolean search_xmp = TRUE;
|
if (JxlDecoderSubscribeEvents (decoder, JXL_DEC_BOX) != JXL_DEC_SUCCESS)
|
||||||
gboolean success_exif = FALSE;
|
|
||||||
gboolean success_xmp = FALSE;
|
|
||||||
JxlBoxType box_type = { 0, 0, 0, 0 };
|
|
||||||
GByteArray *exif_box = NULL;
|
|
||||||
GByteArray *xml_box = NULL;
|
|
||||||
size_t exif_remains = 0;
|
|
||||||
size_t xml_remains = 0;
|
|
||||||
|
|
||||||
while (search_exif || search_xmp)
|
|
||||||
{
|
{
|
||||||
status = JxlDecoderProcessInput (decoder);
|
g_printerr ("%s: JxlDecoderSubscribeEvents for JXL_DEC_BOX failed\n", G_STRFUNC);
|
||||||
switch (status)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gboolean search_exif = TRUE;
|
||||||
|
gboolean search_xmp = TRUE;
|
||||||
|
gboolean success_exif = FALSE;
|
||||||
|
gboolean success_xmp = FALSE;
|
||||||
|
JxlBoxType box_type = { 0, 0, 0, 0 };
|
||||||
|
GByteArray *exif_box = NULL;
|
||||||
|
GByteArray *xml_box = NULL;
|
||||||
|
size_t exif_remains = 0;
|
||||||
|
size_t xml_remains = 0;
|
||||||
|
|
||||||
|
while (search_exif || search_xmp)
|
||||||
{
|
{
|
||||||
case JXL_DEC_SUCCESS:
|
status = JxlDecoderProcessInput (decoder);
|
||||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
switch (status)
|
||||||
{
|
|
||||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
|
||||||
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
|
||||||
success_exif = TRUE;
|
|
||||||
}
|
|
||||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
|
||||||
{
|
|
||||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
|
||||||
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
|
||||||
success_xmp = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
search_exif = FALSE;
|
|
||||||
search_xmp = FALSE;
|
|
||||||
break;
|
|
||||||
case JXL_DEC_ERROR:
|
|
||||||
search_exif = FALSE;
|
|
||||||
search_xmp = FALSE;
|
|
||||||
g_printerr ("%s: Metadata decoding error\n", G_STRFUNC);
|
|
||||||
break;
|
|
||||||
case JXL_DEC_NEED_MORE_INPUT:
|
|
||||||
search_exif = FALSE;
|
|
||||||
search_xmp = FALSE;
|
|
||||||
g_printerr ("%s: JXL metadata are probably incomplete\n", G_STRFUNC);
|
|
||||||
break;
|
|
||||||
case JXL_DEC_BOX:
|
|
||||||
JxlDecoderSetDecompressBoxes (decoder, JXL_TRUE);
|
|
||||||
|
|
||||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif && exif_box)
|
|
||||||
{
|
|
||||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
|
||||||
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
|
||||||
|
|
||||||
search_exif = FALSE;
|
|
||||||
success_exif = TRUE;
|
|
||||||
}
|
|
||||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp && xml_box)
|
|
||||||
{
|
|
||||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
|
||||||
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
|
||||||
|
|
||||||
search_xmp = FALSE;
|
|
||||||
success_xmp = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JxlDecoderGetBoxType (decoder, box_type, JXL_TRUE) == JXL_DEC_SUCCESS)
|
|
||||||
{
|
{
|
||||||
|
case JXL_DEC_SUCCESS:
|
||||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||||
{
|
{
|
||||||
exif_box = g_byte_array_sized_new (4096);
|
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||||
g_byte_array_set_size (exif_box, 4096);
|
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
||||||
|
success_exif = TRUE;
|
||||||
JxlDecoderSetBoxBuffer (decoder, exif_box->data, exif_box->len);
|
|
||||||
}
|
}
|
||||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||||
{
|
{
|
||||||
xml_box = g_byte_array_sized_new (4096);
|
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||||
g_byte_array_set_size (xml_box, 4096);
|
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
||||||
|
success_xmp = TRUE;
|
||||||
JxlDecoderSetBoxBuffer (decoder, xml_box->data, xml_box->len);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
search_exif = FALSE;
|
search_exif = FALSE;
|
||||||
search_xmp = FALSE;
|
search_xmp = FALSE;
|
||||||
g_printerr ("%s: Error in JxlDecoderGetBoxType\n", G_STRFUNC);
|
break;
|
||||||
}
|
case JXL_DEC_ERROR:
|
||||||
break;
|
|
||||||
case JXL_DEC_BOX_NEED_MORE_OUTPUT:
|
|
||||||
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
|
||||||
{
|
|
||||||
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
|
||||||
g_byte_array_set_size (exif_box, exif_box->len + 4096);
|
|
||||||
JxlDecoderSetBoxBuffer (decoder, exif_box->data + exif_box->len - (4096 + exif_remains), 4096 + exif_remains);
|
|
||||||
}
|
|
||||||
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
|
||||||
{
|
|
||||||
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
|
||||||
g_byte_array_set_size (xml_box, xml_box->len + 4096);
|
|
||||||
JxlDecoderSetBoxBuffer (decoder, xml_box->data + xml_box->len - (4096 + xml_remains), 4096 + xml_remains);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
search_exif = FALSE;
|
search_exif = FALSE;
|
||||||
search_xmp = FALSE;
|
search_xmp = FALSE;
|
||||||
|
g_printerr ("%s: Metadata decoding error\n", G_STRFUNC);
|
||||||
|
break;
|
||||||
|
case JXL_DEC_NEED_MORE_INPUT:
|
||||||
|
search_exif = FALSE;
|
||||||
|
search_xmp = FALSE;
|
||||||
|
g_printerr ("%s: JXL metadata are probably incomplete\n", G_STRFUNC);
|
||||||
|
break;
|
||||||
|
case JXL_DEC_BOX:
|
||||||
|
JxlDecoderSetDecompressBoxes (decoder, JXL_TRUE);
|
||||||
|
|
||||||
|
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif && exif_box)
|
||||||
|
{
|
||||||
|
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||||
|
g_byte_array_set_size (exif_box, exif_box->len - exif_remains);
|
||||||
|
|
||||||
|
search_exif = FALSE;
|
||||||
|
success_exif = TRUE;
|
||||||
|
}
|
||||||
|
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp && xml_box)
|
||||||
|
{
|
||||||
|
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||||
|
g_byte_array_set_size (xml_box, xml_box->len - xml_remains);
|
||||||
|
|
||||||
|
search_xmp = FALSE;
|
||||||
|
success_xmp = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JxlDecoderGetBoxType (decoder, box_type, JXL_TRUE) == JXL_DEC_SUCCESS)
|
||||||
|
{
|
||||||
|
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||||
|
{
|
||||||
|
exif_box = g_byte_array_sized_new (4096);
|
||||||
|
g_byte_array_set_size (exif_box, 4096);
|
||||||
|
|
||||||
|
JxlDecoderSetBoxBuffer (decoder, exif_box->data, exif_box->len);
|
||||||
|
}
|
||||||
|
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||||
|
{
|
||||||
|
xml_box = g_byte_array_sized_new (4096);
|
||||||
|
g_byte_array_set_size (xml_box, 4096);
|
||||||
|
|
||||||
|
JxlDecoderSetBoxBuffer (decoder, xml_box->data, xml_box->len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
search_exif = FALSE;
|
||||||
|
search_xmp = FALSE;
|
||||||
|
g_printerr ("%s: Error in JxlDecoderGetBoxType\n", G_STRFUNC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JXL_DEC_BOX_NEED_MORE_OUTPUT:
|
||||||
|
if (box_type[0] == 'E' && box_type[1] == 'x' && box_type[2] == 'i' && box_type[3] == 'f' && search_exif)
|
||||||
|
{
|
||||||
|
exif_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||||
|
g_byte_array_set_size (exif_box, exif_box->len + 4096);
|
||||||
|
JxlDecoderSetBoxBuffer (decoder, exif_box->data + exif_box->len - (4096 + exif_remains), 4096 + exif_remains);
|
||||||
|
}
|
||||||
|
else if (box_type[0] == 'x' && box_type[1] == 'm' && box_type[2] == 'l' && box_type[3] == ' ' && search_xmp)
|
||||||
|
{
|
||||||
|
xml_remains = JxlDecoderReleaseBoxBuffer (decoder);
|
||||||
|
g_byte_array_set_size (xml_box, xml_box->len + 4096);
|
||||||
|
JxlDecoderSetBoxBuffer (decoder, xml_box->data + xml_box->len - (4096 + xml_remains), 4096 + xml_remains);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
search_exif = FALSE;
|
||||||
|
search_xmp = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (success_exif || success_xmp)
|
if (success_exif || success_xmp)
|
||||||
{
|
|
||||||
PikaMetadata *metadata = pika_metadata_new ();
|
|
||||||
|
|
||||||
if (success_exif && exif_box)
|
|
||||||
{
|
{
|
||||||
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
gexiv2_metadata_clear (GEXIV2_METADATA (metadata));
|
||||||
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
|
||||||
const guint8 *tiffheader = exif_box->data;
|
|
||||||
glong new_exif_size = exif_box->len;
|
|
||||||
|
|
||||||
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
if (success_exif && exif_box)
|
||||||
{
|
{
|
||||||
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
const guint8 tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
|
||||||
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
const guint8 tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
|
||||||
|
const guint8 *tiffheader = exif_box->data;
|
||||||
|
glong new_exif_size = exif_box->len;
|
||||||
|
|
||||||
|
while (new_exif_size >= 4) /*Searching for TIFF Header*/
|
||||||
{
|
{
|
||||||
break;
|
if (tiffheader[0] == tiffHeaderBE[0] && tiffheader[1] == tiffHeaderBE[1] &&
|
||||||
|
tiffheader[2] == tiffHeaderBE[2] && tiffheader[3] == tiffHeaderBE[3])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
||||||
|
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
new_exif_size--;
|
||||||
|
tiffheader++;
|
||||||
}
|
}
|
||||||
if (tiffheader[0] == tiffHeaderLE[0] && tiffheader[1] == tiffHeaderLE[1] &&
|
|
||||||
tiffheader[2] == tiffHeaderLE[2] && tiffheader[3] == tiffHeaderLE[3])
|
if (new_exif_size > 4) /* TIFF header + some data found*/
|
||||||
{
|
{
|
||||||
break;
|
if (! gexiv2_metadata_open_buf (GEXIV2_METADATA (metadata), tiffheader, new_exif_size, error))
|
||||||
|
{
|
||||||
|
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||||
|
g_clear_error (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
||||||
}
|
}
|
||||||
new_exif_size--;
|
|
||||||
tiffheader++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_exif_size > 4) /* TIFF header + some data found*/
|
if (success_xmp && xml_box)
|
||||||
{
|
{
|
||||||
if (! gexiv2_metadata_open_buf (GEXIV2_METADATA (metadata), tiffheader, new_exif_size, error))
|
if (! pika_metadata_set_from_xmp (metadata, xml_box->data, xml_box->len, error))
|
||||||
{
|
{
|
||||||
g_printerr ("%s: Failed to set EXIF metadata: %s\n", G_STRFUNC, (*error)->message);
|
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
||||||
g_clear_error (error);
|
g_clear_error (error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
g_printerr ("%s: EXIF metadata not set\n", G_STRFUNC);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success_xmp && xml_box)
|
if (exif_box)
|
||||||
{
|
{
|
||||||
if (! pika_metadata_set_from_xmp (metadata, xml_box->data, xml_box->len, error))
|
g_byte_array_free (exif_box, TRUE);
|
||||||
{
|
|
||||||
g_printerr ("%s: Failed to set XMP metadata: %s\n", G_STRFUNC, (*error)->message);
|
|
||||||
g_clear_error (error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
if (xml_box)
|
||||||
GEXIV2_ORIENTATION_NORMAL, NULL);
|
{
|
||||||
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata),
|
g_byte_array_free (xml_box, TRUE);
|
||||||
basicinfo.xsize, NULL);
|
}
|
||||||
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
|
||||||
basicinfo.ysize, NULL);
|
|
||||||
pika_image_metadata_load_finish (image, "image/jxl", metadata,
|
|
||||||
PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exif_box)
|
|
||||||
{
|
|
||||||
g_byte_array_free (exif_box, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xml_box)
|
|
||||||
{
|
|
||||||
g_byte_array_free (xml_box, TRUE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gexiv2_metadata_try_set_orientation (GEXIV2_METADATA (metadata),
|
||||||
|
GEXIV2_ORIENTATION_NORMAL, NULL);
|
||||||
|
gexiv2_metadata_try_set_metadata_pixel_width (GEXIV2_METADATA (metadata),
|
||||||
|
basicinfo.xsize, NULL);
|
||||||
|
gexiv2_metadata_try_set_metadata_pixel_height (GEXIV2_METADATA (metadata),
|
||||||
|
basicinfo.ysize, NULL);
|
||||||
|
|
||||||
|
*flags = PIKA_METADATA_LOAD_COMMENT | PIKA_METADATA_LOAD_RESOLUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
JxlThreadParallelRunnerDestroy (runner);
|
JxlThreadParallelRunnerDestroy (runner);
|
||||||
|
@ -1158,7 +1164,7 @@ jpegxl_load (PikaProcedure *procedure,
|
||||||
|
|
||||||
gegl_init (NULL, NULL);
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
image = load_image (file, run_mode, &error);
|
image = load_image (file, run_mode, metadata, flags, &error);
|
||||||
|
|
||||||
if (! image)
|
if (! image)
|
||||||
return pika_procedure_new_return_values (procedure,
|
return pika_procedure_new_return_values (procedure,
|
||||||
|
|
|
@ -886,12 +886,13 @@ gui_single (PikaProcedure *procedure,
|
||||||
PikaProcedureConfig *config,
|
PikaProcedureConfig *config,
|
||||||
PikaImage *image)
|
PikaImage *image)
|
||||||
{
|
{
|
||||||
GtkWidget *window;
|
GtkWidget *window;
|
||||||
GtkWidget *widget;
|
GtkWidget *widget;
|
||||||
GList *missing_fonts;
|
PikaLayer **layers;
|
||||||
GList *dialog_props = NULL;
|
GList *missing_fonts;
|
||||||
gboolean run;
|
GList *dialog_props = NULL;
|
||||||
gint32 n_layers;
|
gboolean run;
|
||||||
|
gint32 n_layers;
|
||||||
|
|
||||||
pika_ui_init (PLUG_IN_BINARY);
|
pika_ui_init (PLUG_IN_BINARY);
|
||||||
|
|
||||||
|
@ -910,7 +911,13 @@ gui_single (PikaProcedure *procedure,
|
||||||
widget = pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (window),
|
widget = pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (window),
|
||||||
"pages-frame", "layers-as-pages", FALSE,
|
"pages-frame", "layers-as-pages", FALSE,
|
||||||
"pages-box");
|
"pages-box");
|
||||||
g_free (pika_image_get_layers (multi_page.images[0], &n_layers));
|
/* Enable "layers-as-pages" if more than one layer, or there's a single
|
||||||
|
* layer group has more than one layer */
|
||||||
|
layers = pika_image_get_layers (multi_page.images[0], &n_layers);
|
||||||
|
if (n_layers == 1 && pika_item_is_group (PIKA_ITEM (layers[0])))
|
||||||
|
g_free (pika_item_get_children (PIKA_ITEM (layers[0]), &n_layers));
|
||||||
|
g_free (layers);
|
||||||
|
|
||||||
gtk_widget_set_sensitive (widget, n_layers > 1);
|
gtk_widget_set_sensitive (widget, n_layers > 1);
|
||||||
|
|
||||||
/* Warning for missing fonts (non-embeddable with rasterization
|
/* Warning for missing fonts (non-embeddable with rasterization
|
||||||
|
|
|
@ -65,6 +65,7 @@ typedef enum _PngExportformat
|
||||||
PNG_FORMAT_GRAYA16
|
PNG_FORMAT_GRAYA16
|
||||||
} PngExportFormat;
|
} PngExportFormat;
|
||||||
|
|
||||||
|
static GSList *safe_to_copy_chunks;
|
||||||
|
|
||||||
typedef struct _Png Png;
|
typedef struct _Png Png;
|
||||||
typedef struct _PngClass PngClass;
|
typedef struct _PngClass PngClass;
|
||||||
|
@ -139,6 +140,9 @@ static gboolean ia_has_transparent_pixels (GeglBuffer *buffer);
|
||||||
static gint find_unused_ia_color (GeglBuffer *buffer,
|
static gint find_unused_ia_color (GeglBuffer *buffer,
|
||||||
gint *colors);
|
gint *colors);
|
||||||
|
|
||||||
|
static gint read_unknown_chunk (png_structp png_ptr,
|
||||||
|
png_unknown_chunkp chunk);
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (Png, png, PIKA_TYPE_PLUG_IN)
|
G_DEFINE_TYPE (Png, png, PIKA_TYPE_PLUG_IN)
|
||||||
|
|
||||||
|
@ -602,6 +606,7 @@ load_image (GFile *file,
|
||||||
const Babl *file_format; /* BABL format for layer */
|
const Babl *file_format; /* BABL format for layer */
|
||||||
png_structp pp; /* PNG read pointer */
|
png_structp pp; /* PNG read pointer */
|
||||||
png_infop info; /* PNG info pointers */
|
png_infop info; /* PNG info pointers */
|
||||||
|
png_voidp user_chunkp; /* PNG unknown chunk pointer */
|
||||||
guchar **pixels; /* Pixel rows */
|
guchar **pixels; /* Pixel rows */
|
||||||
guchar *pixel; /* Pixel data */
|
guchar *pixel; /* Pixel data */
|
||||||
guchar alpha[256]; /* Index -> Alpha */
|
guchar alpha[256]; /* Index -> Alpha */
|
||||||
|
@ -609,6 +614,8 @@ load_image (GFile *file,
|
||||||
gint num_texts;
|
gint num_texts;
|
||||||
struct read_error_data error_data;
|
struct read_error_data error_data;
|
||||||
|
|
||||||
|
safe_to_copy_chunks = NULL;
|
||||||
|
|
||||||
pp = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
pp = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
if (! pp)
|
if (! pp)
|
||||||
{
|
{
|
||||||
|
@ -667,6 +674,11 @@ load_image (GFile *file,
|
||||||
png_init_io (pp, fp);
|
png_init_io (pp, fp);
|
||||||
png_set_compression_buffer_size (pp, 512);
|
png_set_compression_buffer_size (pp, 512);
|
||||||
|
|
||||||
|
/* Set up callback to save "safe to copy" chunks */
|
||||||
|
png_set_keep_unknown_chunks (pp, PNG_HANDLE_CHUNK_IF_SAFE, NULL, 0);
|
||||||
|
user_chunkp = png_get_user_chunk_ptr (pp);
|
||||||
|
png_set_read_user_chunk_fn (pp, user_chunkp, read_unknown_chunk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the image info
|
* Get the image info
|
||||||
*/
|
*/
|
||||||
|
@ -1184,6 +1196,23 @@ load_image (GFile *file,
|
||||||
g_object_unref (buffer);
|
g_object_unref (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If any safe-to-copy chunks were saved,
|
||||||
|
* store them in the image as parasite */
|
||||||
|
if (safe_to_copy_chunks)
|
||||||
|
{
|
||||||
|
GSList *iter;
|
||||||
|
|
||||||
|
for (iter = safe_to_copy_chunks; iter; iter = iter->next)
|
||||||
|
{
|
||||||
|
PikaParasite *parasite = iter->data;
|
||||||
|
|
||||||
|
pika_image_attach_parasite ((PikaImage *) image, parasite);
|
||||||
|
pika_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free (safe_to_copy_chunks);
|
||||||
|
}
|
||||||
|
|
||||||
return (PikaImage *) image;
|
return (PikaImage *) image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1292,6 +1321,7 @@ save_image (GFile *file,
|
||||||
gint num; /* Number of rows to load */
|
gint num; /* Number of rows to load */
|
||||||
FILE *fp; /* File pointer */
|
FILE *fp; /* File pointer */
|
||||||
PikaColorProfile *profile = NULL; /* Color profile */
|
PikaColorProfile *profile = NULL; /* Color profile */
|
||||||
|
gchar **parasites; /* Safe-to-copy chunks */
|
||||||
gboolean out_linear; /* Save linear RGB */
|
gboolean out_linear; /* Save linear RGB */
|
||||||
GeglBuffer *buffer; /* GEGL buffer for layer */
|
GeglBuffer *buffer; /* GEGL buffer for layer */
|
||||||
const Babl *file_format = NULL; /* BABL format of file */
|
const Babl *file_format = NULL; /* BABL format of file */
|
||||||
|
@ -1914,6 +1944,51 @@ save_image (GFile *file,
|
||||||
if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
|
if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
|
||||||
png_set_swap (pp);
|
png_set_swap (pp);
|
||||||
|
|
||||||
|
/* Write any safe-to-copy chunks saved from import */
|
||||||
|
parasites = pika_image_get_parasite_list (image);
|
||||||
|
|
||||||
|
if (parasites)
|
||||||
|
{
|
||||||
|
gint count;
|
||||||
|
|
||||||
|
count = g_strv_length (parasites);
|
||||||
|
for (gint i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (strncmp (parasites[i], "png", 3) == 0)
|
||||||
|
{
|
||||||
|
PikaParasite *parasite;
|
||||||
|
|
||||||
|
parasite = pika_image_get_parasite (image, parasites[i]);
|
||||||
|
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
gchar buf[1024];
|
||||||
|
gchar *chunk_name;
|
||||||
|
|
||||||
|
g_strlcpy (buf, parasites[i], sizeof (buf));
|
||||||
|
chunk_name = strchr (buf, '/');
|
||||||
|
chunk_name++;
|
||||||
|
|
||||||
|
if (chunk_name)
|
||||||
|
{
|
||||||
|
png_byte name[4];
|
||||||
|
const guint8 *data;
|
||||||
|
guint32 len;
|
||||||
|
|
||||||
|
for (gint j = 0; j < 4; j++)
|
||||||
|
name[j] = chunk_name[j];
|
||||||
|
|
||||||
|
data = (const guint8 *) pika_parasite_get_data (parasite, &len);
|
||||||
|
|
||||||
|
png_write_chunk (pp, name, data, len);
|
||||||
|
}
|
||||||
|
pika_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_strfreev (parasites);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turn on interlace handling...
|
* Turn on interlace handling...
|
||||||
*/
|
*/
|
||||||
|
@ -2263,6 +2338,28 @@ respin_cmap (png_structp pp,
|
||||||
return get_bit_depth_for_palette (colors);
|
return get_bit_depth_for_palette (colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
read_unknown_chunk (png_structp png_ptr,
|
||||||
|
png_unknown_chunkp chunk)
|
||||||
|
{
|
||||||
|
/* Chunks with a lowercase letter in the 4th byte
|
||||||
|
* are safe to copy */
|
||||||
|
if (g_ascii_islower (chunk->name[3]))
|
||||||
|
{
|
||||||
|
PikaParasite *parasite;
|
||||||
|
gchar pname[255];
|
||||||
|
|
||||||
|
g_snprintf (pname, sizeof (pname), "png/%s", chunk->name);
|
||||||
|
|
||||||
|
if ((parasite = pika_parasite_new (pname,
|
||||||
|
PIKA_PARASITE_PERSISTENT,
|
||||||
|
chunk->size, chunk->data)))
|
||||||
|
safe_to_copy_chunks = g_slist_prepend (safe_to_copy_chunks, parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
save_dialog (PikaImage *image,
|
save_dialog (PikaImage *image,
|
||||||
PikaProcedure *procedure,
|
PikaProcedure *procedure,
|
||||||
|
|
|
@ -944,7 +944,7 @@ process_pam_header (PNMScanner *scan,
|
||||||
{
|
{
|
||||||
/* skip unknown headers but recognize xv's thumbnail format */
|
/* skip unknown headers but recognize xv's thumbnail format */
|
||||||
CHECK_FOR_ERROR (g_ascii_isdigit (*buf), pnminfo->jmpbuf,
|
CHECK_FOR_ERROR (g_ascii_isdigit (*buf), pnminfo->jmpbuf,
|
||||||
_("PAM: Unsupported inofficial PNM variant."));
|
_("PAM: Unsupported unofficial PNM variant."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CHECK_FOR_ERROR (pnmscanner_eof (scan), pnminfo->jmpbuf,
|
CHECK_FOR_ERROR (pnmscanner_eof (scan), pnminfo->jmpbuf,
|
||||||
|
|
|
@ -77,7 +77,7 @@ struct _LicClass
|
||||||
|
|
||||||
|
|
||||||
#define LIC_TYPE (lic_get_type ())
|
#define LIC_TYPE (lic_get_type ())
|
||||||
#define LIC (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LIC_TYPE, Lic))
|
#define LIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LIC_TYPE, Lic))
|
||||||
|
|
||||||
GType lic_get_type (void) G_GNUC_CONST;
|
GType lic_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
|
|
@ -381,6 +381,7 @@ load_image (GFile *file,
|
||||||
_("Unsupported compression (%u) in BMP file from '%s'"),
|
_("Unsupported compression (%u) in BMP file from '%s'"),
|
||||||
bitmap_head.biCompr,
|
bitmap_head.biCompr,
|
||||||
pika_file_get_utf8_name (file));
|
pika_file_get_utf8_name (file));
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -42,10 +42,6 @@
|
||||||
#define LOAD_PROC "file-dds-load"
|
#define LOAD_PROC "file-dds-load"
|
||||||
#define SAVE_PROC "file-dds-save"
|
#define SAVE_PROC "file-dds-save"
|
||||||
|
|
||||||
#define DECODE_YCOCG_PROC "color-decode-ycocg"
|
|
||||||
#define DECODE_YCOCG_SCALED_PROC "color-decode-ycocg-scaled"
|
|
||||||
#define DECODE_ALPHA_EXP_PROC "color-decode-alpha-exp"
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _Dds Dds;
|
typedef struct _Dds Dds;
|
||||||
typedef struct _DdsClass DdsClass;
|
typedef struct _DdsClass DdsClass;
|
||||||
|
@ -86,15 +82,6 @@ static PikaValueArray * dds_save (PikaProcedure *procedure,
|
||||||
PikaMetadata *metadata,
|
PikaMetadata *metadata,
|
||||||
PikaProcedureConfig *config,
|
PikaProcedureConfig *config,
|
||||||
gpointer run_data);
|
gpointer run_data);
|
||||||
#if 0
|
|
||||||
static PikaValueArray * dds_decode (PikaProcedure *procedure,
|
|
||||||
PikaRunMode run_mode,
|
|
||||||
PikaImage *image,
|
|
||||||
gint n_drawables,
|
|
||||||
PikaDrawable **drawables,
|
|
||||||
PikaProcedureConfig *config,
|
|
||||||
gpointer run_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (Dds, dds, PIKA_TYPE_PLUG_IN)
|
G_DEFINE_TYPE (Dds, dds, PIKA_TYPE_PLUG_IN)
|
||||||
|
@ -125,11 +112,6 @@ dds_query_procedures (PikaPlugIn *plug_in)
|
||||||
|
|
||||||
list = g_list_append (list, g_strdup (LOAD_PROC));
|
list = g_list_append (list, g_strdup (LOAD_PROC));
|
||||||
list = g_list_append (list, g_strdup (SAVE_PROC));
|
list = g_list_append (list, g_strdup (SAVE_PROC));
|
||||||
#if 0
|
|
||||||
list = g_list_append (list, g_strdup (DECODE_YCOCG_PROC));
|
|
||||||
list = g_list_append (list, g_strdup (DECODE_YCOCG_SCALED_PROC));
|
|
||||||
list = g_list_append (list, g_strdup (DECODE_ALPHA_EXP_PROC));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -170,10 +152,10 @@ dds_create_procedure (PikaPlugIn *plug_in,
|
||||||
TRUE,
|
TRUE,
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
PIKA_PROC_ARG_BOOLEAN (procedure, "decode-images",
|
PIKA_PROC_ARG_BOOLEAN (procedure, "flip-image",
|
||||||
_("Automatically decode YCoCg/AE_xp images when detected"),
|
_("Flip image _vertically"),
|
||||||
_("Decode YCoCg/AExp images when detected"),
|
_("Flip the image vertically on import"),
|
||||||
TRUE,
|
FALSE,
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
}
|
}
|
||||||
else if (! strcmp (name, SAVE_PROC))
|
else if (! strcmp (name, SAVE_PROC))
|
||||||
|
@ -249,13 +231,17 @@ dds_create_procedure (PikaPlugIn *plug_in,
|
||||||
"default",
|
"default",
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
PIKA_PROC_ARG_INT (procedure, "save-type",
|
PIKA_PROC_ARG_CHOICE (procedure, "save-type",
|
||||||
"Save type",
|
_("Sav_e type"),
|
||||||
"How to save the image (0 = selected layer, "
|
_("How to save the image"),
|
||||||
"1 = cube map, 2 = volume map, 3 = texture array, "
|
pika_choice_new_with_values ("layer", DDS_SAVE_SELECTED_LAYER, _("Selected layer"), NULL,
|
||||||
"4 = all visible layers)",
|
"canvas", DDS_SAVE_VISIBLE_LAYERS, _("All visible layers"), NULL,
|
||||||
0, 4, DDS_SAVE_SELECTED_LAYER,
|
"cube", DDS_SAVE_CUBEMAP, _("As cube map"), NULL,
|
||||||
G_PARAM_READWRITE);
|
"volume", DDS_SAVE_VOLUMEMAP, _("As volume map"), NULL,
|
||||||
|
"array", DDS_SAVE_ARRAY, _("As texture array"), NULL,
|
||||||
|
NULL),
|
||||||
|
"layer",
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
PIKA_PROC_ARG_BOOLEAN (procedure, "flip-image",
|
PIKA_PROC_ARG_BOOLEAN (procedure, "flip-image",
|
||||||
_("Flip image _vertically on export"),
|
_("Flip image _vertically on export"),
|
||||||
|
@ -276,26 +262,29 @@ dds_create_procedure (PikaPlugIn *plug_in,
|
||||||
0, 255, 0,
|
0, 255, 0,
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
PIKA_PROC_ARG_INT (procedure, "mipmaps",
|
PIKA_PROC_ARG_CHOICE (procedure, "mipmaps",
|
||||||
"Mipmaps",
|
_("_Mipmaps"),
|
||||||
"How to handle mipmaps (0 = No mipmaps, "
|
_("How to handle mipmaps"),
|
||||||
"1 = Generate mipmaps, "
|
pika_choice_new_with_values ("none", DDS_MIPMAP_NONE, _("No mipmaps"), NULL,
|
||||||
"2 = Use existing mipmaps (layers)",
|
"generate", DDS_MIPMAP_GENERATE, _("Generate mipmaps"), NULL,
|
||||||
0, 2, DDS_MIPMAP_NONE,
|
"existing", DDS_MIPMAP_EXISTING, _("Use existing mipmaps"), NULL,
|
||||||
G_PARAM_READWRITE);
|
NULL),
|
||||||
|
"none",
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
PIKA_PROC_ARG_CHOICE (procedure, "mipmap-filter",
|
PIKA_PROC_ARG_CHOICE (procedure, "mipmap-filter",
|
||||||
_("F_ilter"),
|
_("F_ilter"),
|
||||||
_("Filtering to use when generating mipmaps"),
|
_("Filtering to use when generating mipmaps"),
|
||||||
pika_choice_new_with_values ("default", DDS_MIPMAP_FILTER_DEFAULT, _("Default"), NULL,
|
pika_choice_new_with_values ("default", DDS_MIPMAP_FILTER_DEFAULT, _("Default"), NULL,
|
||||||
"nearest", DDS_MIPMAP_FILTER_NEAREST, _("Nearest"), NULL,
|
"nearest", DDS_MIPMAP_FILTER_NEAREST, _("Nearest"), NULL,
|
||||||
"box", DDS_MIPMAP_FILTER_BOX, _("Box"), NULL,
|
"box", DDS_MIPMAP_FILTER_BOX, _("Box"), NULL,
|
||||||
"triangle", DDS_MIPMAP_FILTER_TRIANGLE, _("Triangle"), NULL,
|
"triangle", DDS_MIPMAP_FILTER_TRIANGLE, _("Triangle"), NULL,
|
||||||
"quadratic", DDS_MIPMAP_FILTER_QUADRATIC, _("Quadratic"), NULL,
|
"quadratic", DDS_MIPMAP_FILTER_QUADRATIC, _("Quadratic"), NULL,
|
||||||
"bspline", DDS_MIPMAP_FILTER_BSPLINE, _("B-Spline"), NULL,
|
"bspline", DDS_MIPMAP_FILTER_BSPLINE, _("B-Spline"), NULL,
|
||||||
"mitchell", DDS_MIPMAP_FILTER_MITCHELL, _("Mitchell"), NULL,
|
"mitchell", DDS_MIPMAP_FILTER_MITCHELL, _("Mitchell"), NULL,
|
||||||
"lanczos", DDS_MIPMAP_FILTER_LANCZOS, _("Lanczos"), NULL,
|
"catrom", DDS_MIPMAP_FILTER_CATROM, _("Catmull-Rom"), NULL,
|
||||||
"kaiser", DDS_MIPMAP_FILTER_KAISER, _("Kaiser"), NULL,
|
"lanczos", DDS_MIPMAP_FILTER_LANCZOS, _("Lanczos"), NULL,
|
||||||
|
"kaiser", DDS_MIPMAP_FILTER_KAISER, _("Kaiser"), NULL,
|
||||||
NULL),
|
NULL),
|
||||||
"default",
|
"default",
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
|
@ -343,78 +332,6 @@ dds_create_procedure (PikaPlugIn *plug_in,
|
||||||
0.0, 1.0, 0.5,
|
0.0, 1.0, 0.5,
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
else if (! strcmp (name, DECODE_YCOCG_PROC))
|
|
||||||
{
|
|
||||||
procedure = pika_image_procedure_new (plug_in, name,
|
|
||||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
|
||||||
dds_decode, NULL, NULL);
|
|
||||||
|
|
||||||
pika_procedure_set_image_types (procedure, "RGBA");
|
|
||||||
pika_procedure_set_sensitivity_mask (procedure,
|
|
||||||
PIKA_PROCEDURE_SENSITIVE_DRAWABLE);
|
|
||||||
|
|
||||||
pika_procedure_set_menu_label (procedure, _("Decode YCoCg"));
|
|
||||||
/* pika_procedure_add_menu_path (procedure, "<Image>/Filters/Colors"); */
|
|
||||||
|
|
||||||
pika_procedure_set_documentation (procedure,
|
|
||||||
_("Converts YCoCg encoded pixels to RGB"),
|
|
||||||
_("Converts YCoCg encoded pixels to RGB"),
|
|
||||||
name);
|
|
||||||
pika_procedure_set_attribution (procedure,
|
|
||||||
"Shawn Kirst",
|
|
||||||
"Shawn Kirst",
|
|
||||||
"2008");
|
|
||||||
}
|
|
||||||
else if (! strcmp (name, DECODE_YCOCG_SCALED_PROC))
|
|
||||||
{
|
|
||||||
procedure = pika_image_procedure_new (plug_in, name,
|
|
||||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
|
||||||
dds_decode, NULL, NULL);
|
|
||||||
|
|
||||||
pika_procedure_set_image_types (procedure, "RGBA");
|
|
||||||
pika_procedure_set_sensitivity_mask (procedure,
|
|
||||||
PIKA_PROCEDURE_SENSITIVE_DRAWABLE);
|
|
||||||
|
|
||||||
pika_procedure_set_menu_label (procedure, _("Decode YCoCg (scaled)"));
|
|
||||||
/* pika_procedure_add_menu_path (procedure, "<Image>/Filters/Colors"); */
|
|
||||||
|
|
||||||
pika_procedure_set_documentation (procedure,
|
|
||||||
_("Converts YCoCg (scaled) encoded "
|
|
||||||
"pixels to RGB"),
|
|
||||||
_("Converts YCoCg (scaled) encoded "
|
|
||||||
"pixels to RGB"),
|
|
||||||
name);
|
|
||||||
pika_procedure_set_attribution (procedure,
|
|
||||||
"Shawn Kirst",
|
|
||||||
"Shawn Kirst",
|
|
||||||
"2008");
|
|
||||||
}
|
|
||||||
else if (! strcmp (name, DECODE_ALPHA_EXP_PROC))
|
|
||||||
{
|
|
||||||
procedure = pika_image_procedure_new (plug_in, name,
|
|
||||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
|
||||||
dds_decode, NULL, NULL);
|
|
||||||
|
|
||||||
pika_procedure_set_image_types (procedure, "RGBA");
|
|
||||||
pika_procedure_set_sensitivity_mask (procedure,
|
|
||||||
PIKA_PROCEDURE_SENSITIVE_DRAWABLE);
|
|
||||||
|
|
||||||
pika_procedure_set_menu_label (procedure, _("Decode Alpha exponent"));
|
|
||||||
/* pika_procedure_add_menu_path (procedure, "<Image>/Filters/Colors"); */
|
|
||||||
|
|
||||||
pika_procedure_set_documentation (procedure,
|
|
||||||
_("Converts alpha exponent encoded "
|
|
||||||
"pixels to RGB",
|
|
||||||
_("Converts alpha exponent encoded "
|
|
||||||
"pixels to RGB"),
|
|
||||||
name);
|
|
||||||
pika_procedure_set_attribution (procedure,
|
|
||||||
"Shawn Kirst",
|
|
||||||
"Shawn Kirst",
|
|
||||||
"2008");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return procedure;
|
return procedure;
|
||||||
}
|
}
|
||||||
|
@ -436,7 +353,7 @@ dds_load (PikaProcedure *procedure,
|
||||||
gegl_init (NULL, NULL);
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
status = read_dds (file, &image, run_mode == PIKA_RUN_INTERACTIVE,
|
status = read_dds (file, &image, run_mode == PIKA_RUN_INTERACTIVE,
|
||||||
procedure, G_OBJECT (config), &error);
|
procedure, config, &error);
|
||||||
|
|
||||||
if (status != PIKA_PDB_SUCCESS)
|
if (status != PIKA_PDB_SUCCESS)
|
||||||
return pika_procedure_new_return_values (procedure, status, error);
|
return pika_procedure_new_return_values (procedure, status, error);
|
||||||
|
@ -520,53 +437,3 @@ dds_save (PikaProcedure *procedure,
|
||||||
|
|
||||||
return pika_procedure_new_return_values (procedure, status, error);
|
return pika_procedure_new_return_values (procedure, status, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static PikaValueArray *
|
|
||||||
dds_decode (PikaProcedure *procedure,
|
|
||||||
PikaRunMode run_mode,
|
|
||||||
PikaImage *image,
|
|
||||||
gint n_drawables,
|
|
||||||
PikaDrawable **drawables,
|
|
||||||
PikaProcedureConfig *config,
|
|
||||||
gpointer run_data)
|
|
||||||
{
|
|
||||||
const gchar *name = pika_procedure_get_name (procedure);
|
|
||||||
PikaDrawable *drawable,
|
|
||||||
|
|
||||||
if (n_drawables != 1)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
g_set_error (&error, PIKA_PLUG_IN_ERROR, 0,
|
|
||||||
_("Procedure '%s' only works with one drawable."),
|
|
||||||
name);
|
|
||||||
|
|
||||||
return pika_procedure_new_return_values (procedure,
|
|
||||||
PIKA_PDB_EXECUTION_ERROR,
|
|
||||||
error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
drawable = drawables[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! strcmp (name, DECODE_YCOCG_PROC))
|
|
||||||
{
|
|
||||||
decode_ycocg_image (drawable, TRUE);
|
|
||||||
}
|
|
||||||
else if (! strcmp (name, DECODE_YCOCG_SCALED_PROC))
|
|
||||||
{
|
|
||||||
decode_ycocg_scaled_image (drawable, TRUE);
|
|
||||||
}
|
|
||||||
else if (! strcmp (name, DECODE_ALPHA_EXP_PROC))
|
|
||||||
{
|
|
||||||
decode_alpha_exp_image (drawable, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (run_mode != PIKA_RUN_NONINTERACTIVE)
|
|
||||||
pika_displays_flush ();
|
|
||||||
|
|
||||||
return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#ifndef __DDS_H__
|
#ifndef __DDS_H__
|
||||||
#define __DDS_H__
|
#define __DDS_H__
|
||||||
|
|
||||||
|
|
||||||
#define DDS_PLUGIN_VERSION_MAJOR 3
|
#define DDS_PLUGIN_VERSION_MAJOR 3
|
||||||
#define DDS_PLUGIN_VERSION_MINOR 9
|
#define DDS_PLUGIN_VERSION_MINOR 9
|
||||||
#define DDS_PLUGIN_VERSION_REVISION 92
|
#define DDS_PLUGIN_VERSION_REVISION 92
|
||||||
|
@ -101,6 +102,7 @@ typedef enum
|
||||||
DDS_MIPMAP_FILTER_QUADRATIC,
|
DDS_MIPMAP_FILTER_QUADRATIC,
|
||||||
DDS_MIPMAP_FILTER_BSPLINE,
|
DDS_MIPMAP_FILTER_BSPLINE,
|
||||||
DDS_MIPMAP_FILTER_MITCHELL,
|
DDS_MIPMAP_FILTER_MITCHELL,
|
||||||
|
DDS_MIPMAP_FILTER_CATROM,
|
||||||
DDS_MIPMAP_FILTER_LANCZOS,
|
DDS_MIPMAP_FILTER_LANCZOS,
|
||||||
DDS_MIPMAP_FILTER_KAISER,
|
DDS_MIPMAP_FILTER_KAISER,
|
||||||
DDS_MIPMAP_FILTER_MAX
|
DDS_MIPMAP_FILTER_MAX
|
||||||
|
@ -115,6 +117,7 @@ typedef enum
|
||||||
DDS_MIPMAP_WRAP_MAX
|
DDS_MIPMAP_WRAP_MAX
|
||||||
} DDS_MIPMAP_WRAP;
|
} DDS_MIPMAP_WRAP;
|
||||||
|
|
||||||
|
|
||||||
#define DDS_HEADERSIZE 128
|
#define DDS_HEADERSIZE 128
|
||||||
#define DDS_HEADERSIZE_DX10 20
|
#define DDS_HEADERSIZE_DX10 20
|
||||||
|
|
||||||
|
@ -122,18 +125,43 @@ typedef enum
|
||||||
#define DDSD_HEIGHT 0x00000002
|
#define DDSD_HEIGHT 0x00000002
|
||||||
#define DDSD_WIDTH 0x00000004
|
#define DDSD_WIDTH 0x00000004
|
||||||
#define DDSD_PITCH 0x00000008
|
#define DDSD_PITCH 0x00000008
|
||||||
|
#define DDSD_BACKBUFFERCOUNT 0x00000020
|
||||||
|
#define DDSD_ZBUFFERBITDEPTH 0x00000040
|
||||||
|
#define DDSD_ALPHABITDEPTH 0x00000080
|
||||||
|
#define DDSD_LPSURFACE 0x00000800
|
||||||
#define DDSD_PIXELFORMAT 0x00001000
|
#define DDSD_PIXELFORMAT 0x00001000
|
||||||
|
#define DDSD_CKDESTOVERLAY 0x00002000
|
||||||
|
#define DDSD_CKDESTBLT 0x00004000
|
||||||
|
#define DDSD_CKSRCOVERLAY 0x00008000
|
||||||
|
#define DDSD_CKSRCBLT 0x00010000
|
||||||
#define DDSD_MIPMAPCOUNT 0x00020000
|
#define DDSD_MIPMAPCOUNT 0x00020000
|
||||||
|
#define DDSD_REFRESHRATE 0x00040000
|
||||||
#define DDSD_LINEARSIZE 0x00080000
|
#define DDSD_LINEARSIZE 0x00080000
|
||||||
|
#define DDSD_TEXTURESTAGE 0x00100000
|
||||||
|
#define DDSD_FVF 0x00200000
|
||||||
|
#define DDSD_SRCVBHANDLE 0x00400000
|
||||||
#define DDSD_DEPTH 0x00800000
|
#define DDSD_DEPTH 0x00800000
|
||||||
|
|
||||||
#define DDPF_ALPHAPIXELS 0x00000001
|
#define DDPF_ALPHAPIXELS 0x00000001
|
||||||
#define DDPF_ALPHA 0x00000002
|
#define DDPF_ALPHA 0x00000002
|
||||||
#define DDPF_FOURCC 0x00000004
|
#define DDPF_FOURCC 0x00000004
|
||||||
|
#define DDPF_PALETTEINDEXED4 0x00000008
|
||||||
|
#define DDPF_PALETTEINDEXEDTO8 0x00000010
|
||||||
#define DDPF_PALETTEINDEXED8 0x00000020
|
#define DDPF_PALETTEINDEXED8 0x00000020
|
||||||
#define DDPF_RGB 0x00000040
|
#define DDPF_RGB 0x00000040
|
||||||
|
#define DDPF_COMPRESSED 0x00000080
|
||||||
|
#define DDPF_RGBTOYUV 0x00000100
|
||||||
|
#define DDPF_YUV 0x00000200
|
||||||
|
#define DDPF_ZBUFFER 0x00000400
|
||||||
|
#define DDPF_PALETTEINDEXED1 0x00000800
|
||||||
|
#define DDPF_PALETTEINDEXED2 0x00001000
|
||||||
|
#define DDPF_ZPIXELS 0x00002000
|
||||||
|
#define DDPF_STENCILBUFFER 0x00004000
|
||||||
|
#define DDPF_ALPHAPREMULT 0x00008000
|
||||||
#define DDPF_LUMINANCE 0x00020000
|
#define DDPF_LUMINANCE 0x00020000
|
||||||
#define DDPF_NORMAL 0x80000000 // nvidia specific
|
#define DDPF_BUMPLUMINANCE 0x00040000
|
||||||
|
#define DDPF_BUMPDUDV 0x00080000
|
||||||
|
#define DDPF_NORMAL 0x80000000 /* NVidia specific */
|
||||||
|
|
||||||
#define DDSCAPS_COMPLEX 0x00000008
|
#define DDSCAPS_COMPLEX 0x00000008
|
||||||
#define DDSCAPS_TEXTURE 0x00001000
|
#define DDSCAPS_TEXTURE 0x00001000
|
||||||
|
@ -159,6 +187,7 @@ typedef enum
|
||||||
#define D3D10_RESOURCE_DIMENSION_TEXTURE2D 3
|
#define D3D10_RESOURCE_DIMENSION_TEXTURE2D 3
|
||||||
#define D3D10_RESOURCE_DIMENSION_TEXTURE3D 4
|
#define D3D10_RESOURCE_DIMENSION_TEXTURE3D 4
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
|
@ -192,8 +221,8 @@ typedef struct
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned int magic1; // FOURCC "PIKA"
|
unsigned int magic1; /* FOURCC "PIKA" */
|
||||||
unsigned int magic2; // FOURCC "-DDS"
|
unsigned int magic2; /* FOURCC "-DDS" */
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
unsigned int extra_fourcc;
|
unsigned int extra_fourcc;
|
||||||
} pika_dds_special;
|
} pika_dds_special;
|
||||||
|
@ -204,6 +233,7 @@ typedef struct
|
||||||
unsigned int reserved2;
|
unsigned int reserved2;
|
||||||
} dds_header_t;
|
} dds_header_t;
|
||||||
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
DXGI_FORMAT_UNKNOWN = 0,
|
DXGI_FORMAT_UNKNOWN = 0,
|
||||||
|
@ -334,4 +364,70 @@ typedef struct
|
||||||
unsigned int reserved;
|
unsigned int reserved;
|
||||||
} dds_header_dx10_t;
|
} dds_header_dx10_t;
|
||||||
|
|
||||||
|
/* Format values that can be found in the FOURCC field */
|
||||||
|
typedef enum _D3DFORMAT {
|
||||||
|
D3DFMT_R8G8B8 = 20,
|
||||||
|
D3DFMT_A8R8G8B8 = 21,
|
||||||
|
D3DFMT_X8R8G8B8 = 22,
|
||||||
|
D3DFMT_R5G6B5 = 23,
|
||||||
|
D3DFMT_X1R5G5B5 = 24,
|
||||||
|
D3DFMT_A1R5G5B5 = 25,
|
||||||
|
D3DFMT_A4R4G4B4 = 26,
|
||||||
|
D3DFMT_R3G3B2 = 27,
|
||||||
|
D3DFMT_A8 = 28,
|
||||||
|
D3DFMT_A8R3G3B2 = 29,
|
||||||
|
D3DFMT_X4R4G4B4 = 30,
|
||||||
|
D3DFMT_A2B10G10R10 = 31,
|
||||||
|
D3DFMT_A8B8G8R8 = 32,
|
||||||
|
D3DFMT_X8B8G8R8 = 33,
|
||||||
|
D3DFMT_G16R16 = 34,
|
||||||
|
D3DFMT_A2R10G10B10 = 35,
|
||||||
|
D3DFMT_A16B16G16R16 = 36,
|
||||||
|
|
||||||
|
D3DFMT_A8P8 = 40,
|
||||||
|
D3DFMT_P8 = 41,
|
||||||
|
|
||||||
|
D3DFMT_L8 = 50,
|
||||||
|
D3DFMT_A8L8 = 51,
|
||||||
|
D3DFMT_A4L4 = 52,
|
||||||
|
|
||||||
|
D3DFMT_V8U8 = 60,
|
||||||
|
D3DFMT_L6V5U5 = 61,
|
||||||
|
D3DFMT_X8L8V8U8 = 62,
|
||||||
|
D3DFMT_Q8W8V8U8 = 63,
|
||||||
|
D3DFMT_V16U16 = 64,
|
||||||
|
D3DFMT_A2W10V10U10 = 67,
|
||||||
|
|
||||||
|
D3DFMT_D16_LOCKABLE = 70,
|
||||||
|
D3DFMT_D32 = 71,
|
||||||
|
D3DFMT_D15S1 = 73,
|
||||||
|
D3DFMT_D24S8 = 75,
|
||||||
|
D3DFMT_D24X8 = 77,
|
||||||
|
D3DFMT_D24X4S4 = 79,
|
||||||
|
D3DFMT_D16 = 80,
|
||||||
|
D3DFMT_L16 = 81,
|
||||||
|
D3DFMT_D32F_LOCKABLE = 82,
|
||||||
|
D3DFMT_D24FS8 = 83,
|
||||||
|
D3DFMT_D32_LOCKABLE = 84,
|
||||||
|
D3DFMT_S8_LOCKABLE = 85,
|
||||||
|
|
||||||
|
D3DFMT_VERTEXDATA = 100,
|
||||||
|
D3DFMT_INDEX16 = 101,
|
||||||
|
D3DFMT_INDEX32 = 102,
|
||||||
|
|
||||||
|
D3DFMT_Q16W16V16U16 = 110,
|
||||||
|
D3DFMT_R16F = 111,
|
||||||
|
D3DFMT_G16R16F = 112,
|
||||||
|
D3DFMT_A16B16G16R16F = 113,
|
||||||
|
D3DFMT_R32F = 114,
|
||||||
|
D3DFMT_G32R32F = 115,
|
||||||
|
D3DFMT_A32B32G32R32F = 116,
|
||||||
|
D3DFMT_CxV8U8 = 117,
|
||||||
|
|
||||||
|
D3DFMT_A1 = 118,
|
||||||
|
D3DFMT_A2B10G10R10_XR_BIAS = 119,
|
||||||
|
D3DFMT_BINARYBUFFER = 199,
|
||||||
|
} D3DFORMAT;
|
||||||
|
|
||||||
|
|
||||||
#endif /* __DDS_H__ */
|
#endif /* __DDS_H__ */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -22,12 +22,12 @@
|
||||||
#define __DDSREAD_H__
|
#define __DDSREAD_H__
|
||||||
|
|
||||||
|
|
||||||
extern PikaPDBStatusType read_dds (GFile *file,
|
extern PikaPDBStatusType read_dds (GFile *file,
|
||||||
PikaImage **image,
|
PikaImage **image,
|
||||||
gboolean interactive,
|
gboolean interactive,
|
||||||
PikaProcedure *procedure,
|
PikaProcedure *procedure,
|
||||||
GObject *config,
|
PikaProcedureConfig *config,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __DDSREAD_H__ */
|
#endif /* __DDSREAD_H__ */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,11 +34,14 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <libpika/pika.h>
|
||||||
|
|
||||||
#include "dds.h"
|
#include "dds.h"
|
||||||
#include "dxt.h"
|
#include "dxt.h"
|
||||||
#include "endian_rw.h"
|
#include "endian_rw.h"
|
||||||
#include "mipmap.h"
|
|
||||||
#include "imath.h"
|
#include "imath.h"
|
||||||
|
#include "mipmap.h"
|
||||||
|
#include "misc.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
#include "dxt_tables.h"
|
#include "dxt_tables.h"
|
||||||
|
@ -757,181 +760,6 @@ encode_color_block (unsigned char *dst,
|
||||||
PUTL32(dst + 4, indices);
|
PUTL32(dst + 4, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
get_min_max_YCoCg (const unsigned char *block,
|
|
||||||
unsigned char *mincolor,
|
|
||||||
unsigned char *maxcolor)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
mincolor[2] = mincolor[1] = 255;
|
|
||||||
maxcolor[2] = maxcolor[1] = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
if (block[4 * i + 2] < mincolor[2]) mincolor[2] = block[4 * i + 2];
|
|
||||||
if (block[4 * i + 1] < mincolor[1]) mincolor[1] = block[4 * i + 1];
|
|
||||||
if (block[4 * i + 2] > maxcolor[2]) maxcolor[2] = block[4 * i + 2];
|
|
||||||
if (block[4 * i + 1] > maxcolor[1]) maxcolor[1] = block[4 * i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
scale_YCoCg (unsigned char *block,
|
|
||||||
unsigned char *mincolor,
|
|
||||||
unsigned char *maxcolor)
|
|
||||||
{
|
|
||||||
const int s0 = 128 / 2 - 1;
|
|
||||||
const int s1 = 128 / 4 - 1;
|
|
||||||
int m0, m1, m2, m3;
|
|
||||||
int mask0, mask1, scale;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
m0 = abs(mincolor[2] - 128);
|
|
||||||
m1 = abs(mincolor[1] - 128);
|
|
||||||
m2 = abs(maxcolor[2] - 128);
|
|
||||||
m3 = abs(maxcolor[1] - 128);
|
|
||||||
|
|
||||||
if (m1 > m0) m0 = m1;
|
|
||||||
if (m3 > m2) m2 = m3;
|
|
||||||
if (m2 > m0) m0 = m2;
|
|
||||||
|
|
||||||
mask0 = -(m0 <= s0);
|
|
||||||
mask1 = -(m0 <= s1);
|
|
||||||
scale = 1 + (1 & mask0) + (2 & mask1);
|
|
||||||
|
|
||||||
mincolor[2] = (mincolor[2] - 128) * scale + 128;
|
|
||||||
mincolor[1] = (mincolor[1] - 128) * scale + 128;
|
|
||||||
mincolor[0] = (scale - 1) << 3;
|
|
||||||
|
|
||||||
maxcolor[2] = (maxcolor[2] - 128) * scale + 128;
|
|
||||||
maxcolor[1] = (maxcolor[1] - 128) * scale + 128;
|
|
||||||
maxcolor[0] = (scale - 1) << 3;
|
|
||||||
|
|
||||||
for (i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
block[i * 4 + 2] = (block[i * 4 + 2] - 128) * scale + 128;
|
|
||||||
block[i * 4 + 1] = (block[i * 4 + 1] - 128) * scale + 128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define INSET_SHIFT 4
|
|
||||||
|
|
||||||
static void
|
|
||||||
inset_bbox_YCoCg (unsigned char *mincolor,
|
|
||||||
unsigned char *maxcolor)
|
|
||||||
{
|
|
||||||
int inset[4], mini[4], maxi[4];
|
|
||||||
|
|
||||||
inset[2] = (maxcolor[2] - mincolor[2]) - ((1 << (INSET_SHIFT - 1)) - 1);
|
|
||||||
inset[1] = (maxcolor[1] - mincolor[1]) - ((1 << (INSET_SHIFT - 1)) - 1);
|
|
||||||
|
|
||||||
mini[2] = ((mincolor[2] << INSET_SHIFT) + inset[2]) >> INSET_SHIFT;
|
|
||||||
mini[1] = ((mincolor[1] << INSET_SHIFT) + inset[1]) >> INSET_SHIFT;
|
|
||||||
|
|
||||||
maxi[2] = ((maxcolor[2] << INSET_SHIFT) - inset[2]) >> INSET_SHIFT;
|
|
||||||
maxi[1] = ((maxcolor[1] << INSET_SHIFT) - inset[1]) >> INSET_SHIFT;
|
|
||||||
|
|
||||||
mini[2] = (mini[2] >= 0) ? mini[2] : 0;
|
|
||||||
mini[1] = (mini[1] >= 0) ? mini[1] : 0;
|
|
||||||
|
|
||||||
maxi[2] = (maxi[2] <= 255) ? maxi[2] : 255;
|
|
||||||
maxi[1] = (maxi[1] <= 255) ? maxi[1] : 255;
|
|
||||||
|
|
||||||
mincolor[2] = (mini[2] & 0xf8) | (mini[2] >> 5);
|
|
||||||
mincolor[1] = (mini[1] & 0xfc) | (mini[1] >> 6);
|
|
||||||
|
|
||||||
maxcolor[2] = (maxi[2] & 0xf8) | (maxi[2] >> 5);
|
|
||||||
maxcolor[1] = (maxi[1] & 0xfc) | (maxi[1] >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
select_diagonal_YCoCg (const unsigned char *block,
|
|
||||||
unsigned char *mincolor,
|
|
||||||
unsigned char *maxcolor)
|
|
||||||
{
|
|
||||||
unsigned char mid0, mid1, side, mask, b0, b1, c0, c1;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
mid0 = ((int)mincolor[2] + maxcolor[2] + 1) >> 1;
|
|
||||||
mid1 = ((int)mincolor[1] + maxcolor[1] + 1) >> 1;
|
|
||||||
|
|
||||||
side = 0;
|
|
||||||
for (i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
b0 = block[i * 4 + 2] >= mid0;
|
|
||||||
b1 = block[i * 4 + 1] >= mid1;
|
|
||||||
side += (b0 ^ b1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mask = -(side > 8);
|
|
||||||
mask &= -(mincolor[2] != maxcolor[2]);
|
|
||||||
|
|
||||||
c0 = mincolor[1];
|
|
||||||
c1 = maxcolor[1];
|
|
||||||
|
|
||||||
c0 ^= c1;
|
|
||||||
c1 ^= c0 & mask;
|
|
||||||
c0 ^= c1;
|
|
||||||
|
|
||||||
mincolor[1] = c0;
|
|
||||||
maxcolor[1] = c1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
encode_YCoCg_block (unsigned char *dst,
|
|
||||||
unsigned char *block)
|
|
||||||
{
|
|
||||||
unsigned char colors[4][3], *maxcolor, *mincolor;
|
|
||||||
unsigned int mask;
|
|
||||||
int c0, c1, d0, d1, d2, d3;
|
|
||||||
int b0, b1, b2, b3, b4;
|
|
||||||
int x0, x1, x2;
|
|
||||||
int i, idx;
|
|
||||||
|
|
||||||
maxcolor = &colors[0][0];
|
|
||||||
mincolor = &colors[1][0];
|
|
||||||
|
|
||||||
get_min_max_YCoCg(block, mincolor, maxcolor);
|
|
||||||
scale_YCoCg(block, mincolor, maxcolor);
|
|
||||||
inset_bbox_YCoCg(mincolor, maxcolor);
|
|
||||||
select_diagonal_YCoCg(block, mincolor, maxcolor);
|
|
||||||
|
|
||||||
lerp_rgb13(&colors[2][0], maxcolor, mincolor);
|
|
||||||
lerp_rgb13(&colors[3][0], mincolor, maxcolor);
|
|
||||||
|
|
||||||
mask = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 16; ++i)
|
|
||||||
{
|
|
||||||
c0 = block[4 * i + 2];
|
|
||||||
c1 = block[4 * i + 1];
|
|
||||||
|
|
||||||
d0 = abs(colors[0][2] - c0) + abs(colors[0][1] - c1);
|
|
||||||
d1 = abs(colors[1][2] - c0) + abs(colors[1][1] - c1);
|
|
||||||
d2 = abs(colors[2][2] - c0) + abs(colors[2][1] - c1);
|
|
||||||
d3 = abs(colors[3][2] - c0) + abs(colors[3][1] - c1);
|
|
||||||
|
|
||||||
b0 = d0 > d3;
|
|
||||||
b1 = d1 > d2;
|
|
||||||
b2 = d0 > d2;
|
|
||||||
b3 = d1 > d3;
|
|
||||||
b4 = d2 > d3;
|
|
||||||
|
|
||||||
x0 = b1 & b2;
|
|
||||||
x1 = b0 & b3;
|
|
||||||
x2 = b0 & b4;
|
|
||||||
|
|
||||||
idx = (x2 | ((x0 | x1) << 1));
|
|
||||||
|
|
||||||
mask |= idx << (2 * i);
|
|
||||||
}
|
|
||||||
|
|
||||||
PUTL16(dst + 0, pack_rgb565(maxcolor));
|
|
||||||
PUTL16(dst + 2, pack_rgb565(mincolor));
|
|
||||||
PUTL32(dst + 4, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write DXT3 alpha block */
|
/* write DXT3 alpha block */
|
||||||
static void
|
static void
|
||||||
encode_alpha_block_BC2 (unsigned char *dst,
|
encode_alpha_block_BC2 (unsigned char *dst,
|
||||||
|
@ -1288,33 +1116,35 @@ dxt_compress (unsigned char *dst,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
decode_color_block (unsigned char *block,
|
decode_color_block (guchar *block,
|
||||||
unsigned char *src,
|
guchar *src,
|
||||||
int format)
|
gint format)
|
||||||
{
|
{
|
||||||
int i, x, y;
|
guchar *d = block;
|
||||||
unsigned char *d = block;
|
guint indices, idx;
|
||||||
unsigned int indices, idx;
|
guchar colors[4][3];
|
||||||
unsigned char colors[4][3];
|
gushort c0, c1;
|
||||||
unsigned short c0, c1;
|
gint i, x, y;
|
||||||
|
|
||||||
c0 = GETL16(&src[0]);
|
c0 = GETL16 (&src[0]);
|
||||||
c1 = GETL16(&src[2]);
|
c1 = GETL16 (&src[2]);
|
||||||
|
|
||||||
unpack_rgb565(colors[0], c0);
|
unpack_rgb565 (colors[0], c0);
|
||||||
unpack_rgb565(colors[1], c1);
|
unpack_rgb565 (colors[1], c1);
|
||||||
|
|
||||||
if ((c0 > c1) || (format == DDS_COMPRESS_BC3))
|
if ((c0 > c1) || (format == DDS_COMPRESS_BC3))
|
||||||
{
|
{
|
||||||
lerp_rgb13(colors[2], colors[0], colors[1]);
|
/* Four-color mode */
|
||||||
lerp_rgb13(colors[3], colors[1], colors[0]);
|
lerp_rgb13 (colors[2], colors[0], colors[1]);
|
||||||
|
lerp_rgb13 (colors[3], colors[1], colors[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Three-color mode */
|
||||||
for (i = 0; i < 3; ++i)
|
for (i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
colors[2][i] = (colors[0][i] + colors[1][i] + 1) >> 1;
|
colors[2][i] = (colors[0][i] + colors[1][i] + 1) >> 1;
|
||||||
colors[3][i] = 255;
|
colors[3][i] = 0; /* Three-color mode index 11 is always black */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ plugin_name = 'file-dds'
|
||||||
|
|
||||||
plugin_sources = [
|
plugin_sources = [
|
||||||
'dds.c',
|
'dds.c',
|
||||||
'color.c',
|
|
||||||
'ddsread.c',
|
'ddsread.c',
|
||||||
'ddswrite.c',
|
'ddswrite.c',
|
||||||
'dxt.c',
|
'dxt.c',
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -21,55 +21,56 @@
|
||||||
#ifndef __MIPMAP_H__
|
#ifndef __MIPMAP_H__
|
||||||
#define __MIPMAP_H__
|
#define __MIPMAP_H__
|
||||||
|
|
||||||
int get_num_mipmaps (int width,
|
|
||||||
int height);
|
|
||||||
unsigned int get_mipmapped_size (int width,
|
|
||||||
int height,
|
|
||||||
int bpp,
|
|
||||||
int level,
|
|
||||||
int num,
|
|
||||||
int format);
|
|
||||||
unsigned int get_volume_mipmapped_size (int width,
|
|
||||||
int height,
|
|
||||||
int depth,
|
|
||||||
int bpp,
|
|
||||||
int level,
|
|
||||||
int num,
|
|
||||||
int format);
|
|
||||||
int get_next_mipmap_dimensions (int *next_w,
|
|
||||||
int *next_h,
|
|
||||||
int curr_w,
|
|
||||||
int curr_h);
|
|
||||||
|
|
||||||
float cubic_interpolate (float a,
|
gint get_num_mipmaps (gint width,
|
||||||
float b,
|
gint height);
|
||||||
float c,
|
|
||||||
float d,
|
guint get_mipmapped_size (gint width,
|
||||||
float x);
|
gint height,
|
||||||
int generate_mipmaps (unsigned char *dst,
|
gint bpp,
|
||||||
unsigned char *src,
|
gint level,
|
||||||
unsigned int width,
|
gint num,
|
||||||
unsigned int height,
|
gint format);
|
||||||
int bpp,
|
|
||||||
int indexed,
|
guint get_volume_mipmapped_size (gint width,
|
||||||
int mipmaps,
|
gint height,
|
||||||
int filter,
|
gint depth,
|
||||||
int wrap,
|
gint bpp,
|
||||||
int gamma_correct,
|
gint level,
|
||||||
float gamma,
|
gint num,
|
||||||
int preserve_alpha_test_coverage,
|
gint format);
|
||||||
float alpha_test_threshold);
|
|
||||||
int generate_volume_mipmaps (unsigned char *dst,
|
gint get_next_mipmap_dimensions (gint *next_w,
|
||||||
unsigned char *src,
|
gint *next_h,
|
||||||
unsigned int width,
|
gint curr_w,
|
||||||
unsigned int height,
|
gint curr_h);
|
||||||
unsigned int depth,
|
|
||||||
int bpp,
|
gint generate_mipmaps (guchar *dst,
|
||||||
int indexed,
|
guchar *src,
|
||||||
int mipmaps,
|
guint width,
|
||||||
int filter,
|
guint height,
|
||||||
int wrap,
|
gint bpp,
|
||||||
int gamma_correct,
|
gint indexed,
|
||||||
float gamma);
|
gint mipmaps,
|
||||||
|
gint filter,
|
||||||
|
gint wrap,
|
||||||
|
gint gamma_correct,
|
||||||
|
gfloat gamma,
|
||||||
|
gint preserve_alpha_test_coverage,
|
||||||
|
gfloat alpha_test_threshold);
|
||||||
|
|
||||||
|
gint generate_volume_mipmaps (guchar *dst,
|
||||||
|
guchar *src,
|
||||||
|
guint width,
|
||||||
|
guint height,
|
||||||
|
guint depth,
|
||||||
|
gint bpp,
|
||||||
|
gint indexed,
|
||||||
|
gint mipmaps,
|
||||||
|
gint filter,
|
||||||
|
gint wrap,
|
||||||
|
gint gamma_correct,
|
||||||
|
gfloat gamma);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __MIPMAP_H__ */
|
#endif /* __MIPMAP_H__ */
|
||||||
|
|
|
@ -4,56 +4,53 @@
|
||||||
* Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.com>,
|
* Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.com>,
|
||||||
* with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
|
* with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* modify it under the terms of the GNU General Public
|
* it under the terms of the GNU General Public License as published by
|
||||||
* License as published by the Free Software Foundation; either
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; see the file COPYING. If not, write to
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libpika/pika.h>
|
#include <libpika/pika.h>
|
||||||
|
|
||||||
|
#include "endian_rw.h"
|
||||||
|
#include "imath.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
static inline float
|
|
||||||
saturate (float a)
|
|
||||||
{
|
|
||||||
if(a < 0) a = 0;
|
|
||||||
if(a > 1) a = 1;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decoding Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline gfloat
|
||||||
|
saturate (gfloat a)
|
||||||
|
{
|
||||||
|
if (a < 0) a = 0;
|
||||||
|
if (a > 1) a = 1;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decode_ycocg_image (PikaDrawable *drawable,
|
decode_ycocg (PikaDrawable *drawable)
|
||||||
gboolean shadow)
|
|
||||||
{
|
{
|
||||||
GeglBuffer *buffer, *sbuffer;
|
GeglBuffer *buffer;
|
||||||
const Babl *format;
|
const Babl *format;
|
||||||
unsigned char *data;
|
guchar *data;
|
||||||
unsigned int i, w, h, num_pixels;
|
guint num_pixels;
|
||||||
|
guint i, w, h;
|
||||||
const float offset = 0.5f * 256.0f / 255.0f;
|
const gfloat offset = 0.5f * 256.0f / 255.0f;
|
||||||
float Y, Co, Cg, R, G, B;
|
gfloat Y, Co, Cg;
|
||||||
|
gfloat R, G, B;
|
||||||
|
|
||||||
buffer = pika_drawable_get_buffer (drawable);
|
buffer = pika_drawable_get_buffer (drawable);
|
||||||
|
|
||||||
if (shadow)
|
|
||||||
{
|
|
||||||
sbuffer = pika_drawable_get_shadow_buffer (drawable);
|
|
||||||
gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL);
|
|
||||||
g_object_unref (buffer);
|
|
||||||
buffer = sbuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
format = babl_format ("R'G'B'A u8");
|
format = babl_format ("R'G'B'A u8");
|
||||||
|
|
||||||
w = gegl_buffer_get_width (buffer);
|
w = gegl_buffer_get_width (buffer);
|
||||||
|
@ -62,46 +59,43 @@ decode_ycocg_image (PikaDrawable *drawable,
|
||||||
|
|
||||||
data = g_malloc (num_pixels * 4);
|
data = g_malloc (num_pixels * 4);
|
||||||
|
|
||||||
gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data,
|
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data,
|
||||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
pika_progress_init ("Decoding YCoCg pixels...");
|
pika_progress_init ("Decoding YCoCg pixels...");
|
||||||
|
|
||||||
for (i = 0; i < num_pixels; ++i)
|
for (i = 0; i < num_pixels; ++i)
|
||||||
{
|
{
|
||||||
Y = (float)data[4 * i + 3] / 255.0f;
|
Y = (gfloat) data[4 * i + 3] / 255.0f;
|
||||||
Co = (float)data[4 * i + 0] / 255.0f;
|
Co = (gfloat) data[4 * i + 0] / 255.0f;
|
||||||
Cg = (float)data[4 * i + 1] / 255.0f;
|
Cg = (gfloat) data[4 * i + 1] / 255.0f;
|
||||||
|
|
||||||
/* convert YCoCg to RGB */
|
/* convert YCoCg to RGB */
|
||||||
Co -= offset;
|
Co -= offset;
|
||||||
Cg -= offset;
|
Cg -= offset;
|
||||||
|
|
||||||
R = saturate(Y + Co - Cg);
|
R = saturate (Y + Co - Cg);
|
||||||
G = saturate(Y + Cg);
|
G = saturate (Y + Cg);
|
||||||
B = saturate(Y - Co - Cg);
|
B = saturate (Y - Co - Cg);
|
||||||
|
|
||||||
/* copy new alpha from blue */
|
/* copy new alpha from blue */
|
||||||
data[4 * i + 3] = data[4 * i + 2];
|
data[4 * i + 3] = data[4 * i + 2];
|
||||||
|
|
||||||
data[4 * i + 0] = (unsigned char)(R * 255.0f);
|
data[4 * i + 0] = (guchar) (R * 255.0f);
|
||||||
data[4 * i + 1] = (unsigned char)(G * 255.0f);
|
data[4 * i + 1] = (guchar) (G * 255.0f);
|
||||||
data[4 * i + 2] = (unsigned char)(B * 255.0f);
|
data[4 * i + 2] = (guchar) (B * 255.0f);
|
||||||
|
|
||||||
if ((i & 0x7fff) == 0)
|
if ((i & 0x7fff) == 0)
|
||||||
pika_progress_update ((float)i / (float)num_pixels);
|
pika_progress_update ((gdouble) i / (gdouble) num_pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data,
|
||||||
GEGL_AUTO_ROWSTRIDE);
|
GEGL_AUTO_ROWSTRIDE);
|
||||||
|
|
||||||
pika_progress_update (1.0);
|
pika_progress_update (1.0);
|
||||||
|
|
||||||
gegl_buffer_flush (buffer);
|
gegl_buffer_flush (buffer);
|
||||||
|
|
||||||
if (shadow)
|
|
||||||
pika_drawable_merge_shadow (drawable, TRUE);
|
|
||||||
|
|
||||||
pika_drawable_update (drawable, 0, 0, w, h);
|
pika_drawable_update (drawable, 0, 0, w, h);
|
||||||
|
|
||||||
g_free (data);
|
g_free (data);
|
||||||
|
@ -110,27 +104,19 @@ decode_ycocg_image (PikaDrawable *drawable,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decode_ycocg_scaled_image (PikaDrawable *drawable,
|
decode_ycocg_scaled (PikaDrawable *drawable)
|
||||||
gboolean shadow)
|
|
||||||
{
|
{
|
||||||
GeglBuffer *buffer, *sbuffer;
|
GeglBuffer *buffer;
|
||||||
const Babl *format;
|
const Babl *format;
|
||||||
unsigned char *data;
|
guchar *data;
|
||||||
unsigned int i, w, h, num_pixels;
|
guint num_pixels;
|
||||||
|
guint i, w, h;
|
||||||
const float offset = 0.5f * 256.0f / 255.0f;
|
const gfloat offset = 0.5f * 256.0f / 255.0f;
|
||||||
float Y, Co, Cg, R, G, B, s;
|
gfloat Y, Co, Cg;
|
||||||
|
gfloat R, G, B, s;
|
||||||
|
|
||||||
buffer = pika_drawable_get_buffer (drawable);
|
buffer = pika_drawable_get_buffer (drawable);
|
||||||
|
|
||||||
if (shadow)
|
|
||||||
{
|
|
||||||
sbuffer = pika_drawable_get_shadow_buffer (drawable);
|
|
||||||
gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL);
|
|
||||||
g_object_unref (buffer);
|
|
||||||
buffer = sbuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
format = babl_format ("R'G'B'A u8");
|
format = babl_format ("R'G'B'A u8");
|
||||||
|
|
||||||
w = gegl_buffer_get_width (buffer);
|
w = gegl_buffer_get_width (buffer);
|
||||||
|
@ -139,17 +125,17 @@ decode_ycocg_scaled_image (PikaDrawable *drawable,
|
||||||
|
|
||||||
data = g_malloc (num_pixels * 4);
|
data = g_malloc (num_pixels * 4);
|
||||||
|
|
||||||
gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data,
|
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data,
|
||||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
pika_progress_init ("Decoding YCoCg (scaled) pixels...");
|
pika_progress_init ("Decoding YCoCg (scaled) pixels...");
|
||||||
|
|
||||||
for (i = 0; i < num_pixels; ++i)
|
for (i = 0; i < num_pixels; ++i)
|
||||||
{
|
{
|
||||||
Y = (float)data[4 * i + 3] / 255.0f;
|
Y = (gfloat) data[4 * i + 3] / 255.0f;
|
||||||
Co = (float)data[4 * i + 0] / 255.0f;
|
Co = (gfloat) data[4 * i + 0] / 255.0f;
|
||||||
Cg = (float)data[4 * i + 1] / 255.0f;
|
Cg = (gfloat) data[4 * i + 1] / 255.0f;
|
||||||
s = (float)data[4 * i + 2] / 255.0f;
|
s = (gfloat) data[4 * i + 2] / 255.0f;
|
||||||
|
|
||||||
/* convert YCoCg to RGB */
|
/* convert YCoCg to RGB */
|
||||||
s = 1.0f / ((255.0f / 8.0f) * s + 1.0f);
|
s = 1.0f / ((255.0f / 8.0f) * s + 1.0f);
|
||||||
|
@ -157,31 +143,28 @@ decode_ycocg_scaled_image (PikaDrawable *drawable,
|
||||||
Co = (Co - offset) * s;
|
Co = (Co - offset) * s;
|
||||||
Cg = (Cg - offset) * s;
|
Cg = (Cg - offset) * s;
|
||||||
|
|
||||||
R = saturate(Y + Co - Cg);
|
R = saturate (Y + Co - Cg);
|
||||||
G = saturate(Y + Cg);
|
G = saturate (Y + Cg);
|
||||||
B = saturate(Y - Co - Cg);
|
B = saturate (Y - Co - Cg);
|
||||||
|
|
||||||
data[4 * i + 0] = (unsigned char)(R * 255.0f);
|
data[4 * i + 0] = (guchar) (R * 255.0f);
|
||||||
data[4 * i + 1] = (unsigned char)(G * 255.0f);
|
data[4 * i + 1] = (guchar) (G * 255.0f);
|
||||||
data[4 * i + 2] = (unsigned char)(B * 255.0f);
|
data[4 * i + 2] = (guchar) (B * 255.0f);
|
||||||
|
|
||||||
/* set alpha to 1 */
|
/* set alpha to 1 */
|
||||||
data[4 * i + 3] = 255;
|
data[4 * i + 3] = 255;
|
||||||
|
|
||||||
if ((i & 0x7fff) == 0)
|
if ((i & 0x7fff) == 0)
|
||||||
pika_progress_update ((float)i / (float)num_pixels);
|
pika_progress_update ((gdouble) i / (gdouble) num_pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data,
|
||||||
GEGL_AUTO_ROWSTRIDE);
|
GEGL_AUTO_ROWSTRIDE);
|
||||||
|
|
||||||
pika_progress_update (1.0);
|
pika_progress_update (1.0);
|
||||||
|
|
||||||
gegl_buffer_flush (buffer);
|
gegl_buffer_flush (buffer);
|
||||||
|
|
||||||
if (shadow)
|
|
||||||
pika_drawable_merge_shadow (drawable, TRUE);
|
|
||||||
|
|
||||||
pika_drawable_update (drawable, 0, 0, w, h);
|
pika_drawable_update (drawable, 0, 0, w, h);
|
||||||
|
|
||||||
g_free (data);
|
g_free (data);
|
||||||
|
@ -190,25 +173,17 @@ decode_ycocg_scaled_image (PikaDrawable *drawable,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decode_alpha_exp_image (PikaDrawable *drawable,
|
decode_alpha_exponent (PikaDrawable *drawable)
|
||||||
gboolean shadow)
|
|
||||||
{
|
{
|
||||||
GeglBuffer *buffer, *sbuffer;
|
GeglBuffer *buffer;
|
||||||
const Babl *format;
|
const Babl *format;
|
||||||
unsigned char *data;
|
guchar *data;
|
||||||
unsigned int i, w, h, num_pixels;
|
guint num_pixels;
|
||||||
int R, G, B, A;
|
guint i, w, h;
|
||||||
|
gint R, G, B, A;
|
||||||
|
|
||||||
buffer = pika_drawable_get_buffer (drawable);
|
buffer = pika_drawable_get_buffer (drawable);
|
||||||
|
|
||||||
if (shadow)
|
|
||||||
{
|
|
||||||
sbuffer = pika_drawable_get_shadow_buffer (drawable);
|
|
||||||
gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, sbuffer, NULL);
|
|
||||||
g_object_unref (buffer);
|
|
||||||
buffer = sbuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
format = babl_format ("R'G'B'A u8");
|
format = babl_format ("R'G'B'A u8");
|
||||||
|
|
||||||
w = gegl_buffer_get_width (buffer);
|
w = gegl_buffer_get_width (buffer);
|
||||||
|
@ -217,7 +192,7 @@ decode_alpha_exp_image (PikaDrawable *drawable,
|
||||||
|
|
||||||
data = g_malloc (num_pixels * 4);
|
data = g_malloc (num_pixels * 4);
|
||||||
|
|
||||||
gegl_buffer_get (buffer, GEGL_RECTANGLE(0, 0, w, h), 1.0, format, data,
|
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, data,
|
||||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
pika_progress_init ("Decoding Alpha-exponent pixels...");
|
pika_progress_init ("Decoding Alpha-exponent pixels...");
|
||||||
|
@ -240,22 +215,268 @@ decode_alpha_exp_image (PikaDrawable *drawable,
|
||||||
data[4 * i + 3] = A;
|
data[4 * i + 3] = A;
|
||||||
|
|
||||||
if ((i & 0x7fff) == 0)
|
if ((i & 0x7fff) == 0)
|
||||||
pika_progress_update ((float)i / (float)num_pixels);
|
pika_progress_update ((gdouble) i / (gdouble) num_pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
gegl_buffer_set (buffer, GEGL_RECTANGLE(0, 0, w, h), 0, format, data,
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, w, h), 0, format, data,
|
||||||
GEGL_AUTO_ROWSTRIDE);
|
GEGL_AUTO_ROWSTRIDE);
|
||||||
|
|
||||||
pika_progress_update (1.0);
|
pika_progress_update (1.0);
|
||||||
|
|
||||||
gegl_buffer_flush (buffer);
|
gegl_buffer_flush (buffer);
|
||||||
|
|
||||||
if (shadow)
|
|
||||||
pika_drawable_merge_shadow (drawable, TRUE);
|
|
||||||
|
|
||||||
pika_drawable_update (drawable, 0, 0, w, h);
|
pika_drawable_update (drawable, 0, 0, w, h);
|
||||||
|
|
||||||
g_free (data);
|
g_free (data);
|
||||||
|
|
||||||
g_object_unref (buffer);
|
g_object_unref (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encoding Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
encode_ycocg (guchar *dst,
|
||||||
|
gint r,
|
||||||
|
gint g,
|
||||||
|
gint b)
|
||||||
|
{
|
||||||
|
gint y = ((r + (g << 1) + b) + 2) >> 2;
|
||||||
|
gint co = ((((r << 1) - (b << 1)) + 2) >> 2) + 128;
|
||||||
|
gint cg = (((-r + (g << 1) - b) + 2) >> 2) + 128;
|
||||||
|
|
||||||
|
dst[0] = 255;
|
||||||
|
dst[1] = (cg > 255 ? 255 : (cg < 0 ? 0 : cg));
|
||||||
|
dst[2] = (co > 255 ? 255 : (co < 0 ? 0 : co));
|
||||||
|
dst[3] = (y > 255 ? 255 : (y < 0 ? 0 : y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
encode_alpha_exponent (guchar *dst,
|
||||||
|
gint r,
|
||||||
|
gint g,
|
||||||
|
gint b,
|
||||||
|
gint a)
|
||||||
|
{
|
||||||
|
gfloat ar, ag, ab, aa;
|
||||||
|
|
||||||
|
ar = (gfloat) r / 255.0f;
|
||||||
|
ag = (gfloat) g / 255.0f;
|
||||||
|
ab = (gfloat) b / 255.0f;
|
||||||
|
|
||||||
|
aa = MAX (ar, MAX (ag, ab));
|
||||||
|
|
||||||
|
if (aa < 1e-04f)
|
||||||
|
{
|
||||||
|
dst[0] = b;
|
||||||
|
dst[1] = g;
|
||||||
|
dst[2] = r;
|
||||||
|
dst[3] = 255;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar /= aa;
|
||||||
|
ag /= aa;
|
||||||
|
ab /= aa;
|
||||||
|
|
||||||
|
r = (gint) floorf (255.0f * ar + 0.5f);
|
||||||
|
g = (gint) floorf (255.0f * ag + 0.5f);
|
||||||
|
b = (gint) floorf (255.0f * ab + 0.5f);
|
||||||
|
a = (gint) floorf (255.0f * aa + 0.5f);
|
||||||
|
|
||||||
|
dst[0] = MAX (0, MIN (255, b));
|
||||||
|
dst[1] = MAX (0, MIN (255, g));
|
||||||
|
dst[2] = MAX (0, MIN (255, r));
|
||||||
|
dst[3] = MAX (0, MIN (255, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compression Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_min_max_YCoCg (const guchar *block,
|
||||||
|
guchar *mincolor,
|
||||||
|
guchar *maxcolor)
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
mincolor[2] = mincolor[1] = 255;
|
||||||
|
maxcolor[2] = maxcolor[1] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
if (block[4 * i + 2] < mincolor[2]) mincolor[2] = block[4 * i + 2];
|
||||||
|
if (block[4 * i + 1] < mincolor[1]) mincolor[1] = block[4 * i + 1];
|
||||||
|
if (block[4 * i + 2] > maxcolor[2]) maxcolor[2] = block[4 * i + 2];
|
||||||
|
if (block[4 * i + 1] > maxcolor[1]) maxcolor[1] = block[4 * i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scale_YCoCg (guchar *block,
|
||||||
|
guchar *mincolor,
|
||||||
|
guchar *maxcolor)
|
||||||
|
{
|
||||||
|
const gint s0 = 128 / 2 - 1;
|
||||||
|
const gint s1 = 128 / 4 - 1;
|
||||||
|
gint m0, m1, m2, m3;
|
||||||
|
gint mask0, mask1, scale;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
m0 = abs (mincolor[2] - 128);
|
||||||
|
m1 = abs (mincolor[1] - 128);
|
||||||
|
m2 = abs (maxcolor[2] - 128);
|
||||||
|
m3 = abs (maxcolor[1] - 128);
|
||||||
|
|
||||||
|
if (m1 > m0) m0 = m1;
|
||||||
|
if (m3 > m2) m2 = m3;
|
||||||
|
if (m2 > m0) m0 = m2;
|
||||||
|
|
||||||
|
mask0 = -(m0 <= s0);
|
||||||
|
mask1 = -(m0 <= s1);
|
||||||
|
scale = 1 + (1 & mask0) + (2 & mask1);
|
||||||
|
|
||||||
|
mincolor[2] = (mincolor[2] - 128) * scale + 128;
|
||||||
|
mincolor[1] = (mincolor[1] - 128) * scale + 128;
|
||||||
|
mincolor[0] = (scale - 1) << 3;
|
||||||
|
|
||||||
|
maxcolor[2] = (maxcolor[2] - 128) * scale + 128;
|
||||||
|
maxcolor[1] = (maxcolor[1] - 128) * scale + 128;
|
||||||
|
maxcolor[0] = (scale - 1) << 3;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
block[i * 4 + 2] = (block[i * 4 + 2] - 128) * scale + 128;
|
||||||
|
block[i * 4 + 1] = (block[i * 4 + 1] - 128) * scale + 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INSET_SHIFT 4
|
||||||
|
|
||||||
|
static void
|
||||||
|
inset_bbox_YCoCg (guchar *mincolor,
|
||||||
|
guchar *maxcolor)
|
||||||
|
{
|
||||||
|
gint inset[4], mini[4], maxi[4];
|
||||||
|
|
||||||
|
inset[2] = (maxcolor[2] - mincolor[2]) - ((1 << (INSET_SHIFT - 1)) - 1);
|
||||||
|
inset[1] = (maxcolor[1] - mincolor[1]) - ((1 << (INSET_SHIFT - 1)) - 1);
|
||||||
|
|
||||||
|
mini[2] = ((mincolor[2] << INSET_SHIFT) + inset[2]) >> INSET_SHIFT;
|
||||||
|
mini[1] = ((mincolor[1] << INSET_SHIFT) + inset[1]) >> INSET_SHIFT;
|
||||||
|
|
||||||
|
maxi[2] = ((maxcolor[2] << INSET_SHIFT) - inset[2]) >> INSET_SHIFT;
|
||||||
|
maxi[1] = ((maxcolor[1] << INSET_SHIFT) - inset[1]) >> INSET_SHIFT;
|
||||||
|
|
||||||
|
mini[2] = (mini[2] >= 0) ? mini[2] : 0;
|
||||||
|
mini[1] = (mini[1] >= 0) ? mini[1] : 0;
|
||||||
|
|
||||||
|
maxi[2] = (maxi[2] <= 255) ? maxi[2] : 255;
|
||||||
|
maxi[1] = (maxi[1] <= 255) ? maxi[1] : 255;
|
||||||
|
|
||||||
|
mincolor[2] = (mini[2] & 0xf8) | (mini[2] >> 5);
|
||||||
|
mincolor[1] = (mini[1] & 0xfc) | (mini[1] >> 6);
|
||||||
|
|
||||||
|
maxcolor[2] = (maxi[2] & 0xf8) | (maxi[2] >> 5);
|
||||||
|
maxcolor[1] = (maxi[1] & 0xfc) | (maxi[1] >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
select_diagonal_YCoCg (const guchar *block,
|
||||||
|
guchar *mincolor,
|
||||||
|
guchar *maxcolor)
|
||||||
|
{
|
||||||
|
guchar mid0, mid1, side, mask, b0, b1, c0, c1;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
mid0 = ((gint) mincolor[2] + maxcolor[2] + 1) >> 1;
|
||||||
|
mid1 = ((gint) mincolor[1] + maxcolor[1] + 1) >> 1;
|
||||||
|
|
||||||
|
side = 0;
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
b0 = block[i * 4 + 2] >= mid0;
|
||||||
|
b1 = block[i * 4 + 1] >= mid1;
|
||||||
|
side += (b0 ^ b1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = -(side > 8);
|
||||||
|
mask &= -(mincolor[2] != maxcolor[2]);
|
||||||
|
|
||||||
|
c0 = mincolor[1];
|
||||||
|
c1 = maxcolor[1];
|
||||||
|
|
||||||
|
c0 ^= c1;
|
||||||
|
c1 ^= c0 & mask;
|
||||||
|
c0 ^= c1;
|
||||||
|
|
||||||
|
mincolor[1] = c0;
|
||||||
|
maxcolor[1] = c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
encode_YCoCg_block (guchar *dst,
|
||||||
|
guchar *block)
|
||||||
|
{
|
||||||
|
guchar colors[4][3], *maxcolor, *mincolor;
|
||||||
|
guint mask;
|
||||||
|
gint c0, c1, d0, d1, d2, d3;
|
||||||
|
gint b0, b1, b2, b3, b4;
|
||||||
|
gint x0, x1, x2;
|
||||||
|
gint i, idx;
|
||||||
|
|
||||||
|
maxcolor = &colors[0][0];
|
||||||
|
mincolor = &colors[1][0];
|
||||||
|
|
||||||
|
get_min_max_YCoCg (block, mincolor, maxcolor);
|
||||||
|
scale_YCoCg (block, mincolor, maxcolor);
|
||||||
|
inset_bbox_YCoCg (mincolor, maxcolor);
|
||||||
|
select_diagonal_YCoCg (block, mincolor, maxcolor);
|
||||||
|
|
||||||
|
colors[2][0] = (2 * maxcolor[0] + mincolor[0]) / 3;
|
||||||
|
colors[2][1] = (2 * maxcolor[1] + mincolor[1]) / 3;
|
||||||
|
colors[2][2] = (2 * maxcolor[2] + mincolor[2]) / 3;
|
||||||
|
|
||||||
|
colors[3][0] = (2 * mincolor[0] + maxcolor[0]) / 3;
|
||||||
|
colors[3][1] = (2 * mincolor[1] + maxcolor[1]) / 3;
|
||||||
|
colors[3][2] = (2 * mincolor[2] + maxcolor[2]) / 3;
|
||||||
|
|
||||||
|
mask = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
c0 = block[4 * i + 2];
|
||||||
|
c1 = block[4 * i + 1];
|
||||||
|
|
||||||
|
d0 = abs (colors[0][2] - c0) + abs (colors[0][1] - c1);
|
||||||
|
d1 = abs (colors[1][2] - c0) + abs (colors[1][1] - c1);
|
||||||
|
d2 = abs (colors[2][2] - c0) + abs (colors[2][1] - c1);
|
||||||
|
d3 = abs (colors[3][2] - c0) + abs (colors[3][1] - c1);
|
||||||
|
|
||||||
|
b0 = d0 > d3;
|
||||||
|
b1 = d1 > d2;
|
||||||
|
b2 = d0 > d2;
|
||||||
|
b3 = d1 > d3;
|
||||||
|
b4 = d2 > d3;
|
||||||
|
|
||||||
|
x0 = b1 & b2;
|
||||||
|
x1 = b0 & b3;
|
||||||
|
x2 = b0 & b4;
|
||||||
|
|
||||||
|
idx = (x2 | ((x0 | x1) << 1));
|
||||||
|
|
||||||
|
mask |= idx << (2 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
PUTL16 (dst + 0, (mul8bit (maxcolor[2], 31) << 11) |
|
||||||
|
(mul8bit (maxcolor[1], 63) << 5) |
|
||||||
|
(mul8bit (maxcolor[0], 31) ));
|
||||||
|
PUTL16 (dst + 2, (mul8bit (mincolor[2], 31) << 11) |
|
||||||
|
(mul8bit (mincolor[1], 63) << 5) |
|
||||||
|
(mul8bit (mincolor[0], 31) ));
|
||||||
|
PUTL32 (dst + 4, mask);
|
||||||
|
}
|
||||||
|
|
|
@ -21,11 +21,26 @@
|
||||||
#ifndef __MISC_H__
|
#ifndef __MISC_H__
|
||||||
#define __MISC_H__
|
#define __MISC_H__
|
||||||
|
|
||||||
void decode_ycocg_image (PikaDrawable *drawable,
|
|
||||||
gboolean shadow);
|
void decode_ycocg (PikaDrawable *drawable);
|
||||||
void decode_ycocg_scaled_image (PikaDrawable *drawable,
|
|
||||||
gboolean shadow);
|
void decode_ycocg_scaled (PikaDrawable *drawable);
|
||||||
void decode_alpha_exp_image (PikaDrawable *drawable,
|
|
||||||
gboolean shadow);
|
void decode_alpha_exponent (PikaDrawable *drawable);
|
||||||
|
|
||||||
|
void encode_ycocg (guchar *dst,
|
||||||
|
gint r,
|
||||||
|
gint g,
|
||||||
|
gint b);
|
||||||
|
|
||||||
|
void encode_alpha_exponent (guchar *dst,
|
||||||
|
gint r,
|
||||||
|
gint g,
|
||||||
|
gint b,
|
||||||
|
gint a);
|
||||||
|
|
||||||
|
void encode_YCoCg_block (guchar *dst,
|
||||||
|
guchar *block);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __MISC_H__ */
|
#endif /* __MISC_H__ */
|
||||||
|
|
|
@ -40,6 +40,23 @@
|
||||||
|
|
||||||
static gboolean callback_lock;
|
static gboolean callback_lock;
|
||||||
|
|
||||||
|
static void select_web_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
static void select_ftp_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
static void select_gopher_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
static void select_other_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
static void select_file_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
static void select_wais_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
static void select_telnet_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
static void select_email_cb (GtkWidget *widget,
|
||||||
|
AreaInfoDialog_t *param);
|
||||||
|
|
||||||
|
|
||||||
static gchar*
|
static gchar*
|
||||||
relative_filter(const char *name, gpointer data)
|
relative_filter(const char *name, gpointer data)
|
||||||
|
@ -77,7 +94,23 @@ url_changed (GtkWidget *widget,
|
||||||
button = param->other;
|
button = param->other;
|
||||||
|
|
||||||
callback_lock = TRUE;
|
callback_lock = TRUE;
|
||||||
|
g_signal_handlers_block_by_func (param->web_site, G_CALLBACK (select_web_cb), data);
|
||||||
|
g_signal_handlers_block_by_func (param->ftp_site, G_CALLBACK (select_ftp_cb), data);
|
||||||
|
g_signal_handlers_block_by_func (param->gopher, G_CALLBACK (select_gopher_cb), data);
|
||||||
|
g_signal_handlers_block_by_func (param->other, G_CALLBACK (select_other_cb), data);
|
||||||
|
g_signal_handlers_block_by_func (param->file, G_CALLBACK (select_file_cb), data);
|
||||||
|
g_signal_handlers_block_by_func (param->wais, G_CALLBACK (select_wais_cb), data);
|
||||||
|
g_signal_handlers_block_by_func (param->telnet, G_CALLBACK (select_telnet_cb), data);
|
||||||
|
g_signal_handlers_block_by_func (param->email, G_CALLBACK (select_email_cb), data);
|
||||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
|
||||||
|
g_signal_handlers_unblock_by_func (param->web_site, G_CALLBACK (select_web_cb), data);
|
||||||
|
g_signal_handlers_unblock_by_func (param->ftp_site, G_CALLBACK (select_ftp_cb), data);
|
||||||
|
g_signal_handlers_unblock_by_func (param->gopher, G_CALLBACK (select_gopher_cb), data);
|
||||||
|
g_signal_handlers_unblock_by_func (param->other, G_CALLBACK (select_other_cb), data);
|
||||||
|
g_signal_handlers_unblock_by_func (param->file, G_CALLBACK (select_file_cb), data);
|
||||||
|
g_signal_handlers_unblock_by_func (param->wais, G_CALLBACK (select_wais_cb), data);
|
||||||
|
g_signal_handlers_unblock_by_func (param->telnet, G_CALLBACK (select_telnet_cb), data);
|
||||||
|
g_signal_handlers_unblock_by_func (param->email, G_CALLBACK (select_email_cb), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -76,6 +76,10 @@ static PikaProcedure * metadata_create_procedure (PikaPlugIn *plug_in
|
||||||
const gchar *name);
|
const gchar *name);
|
||||||
|
|
||||||
static PikaValueArray * metadata_run (PikaProcedure *procedure,
|
static PikaValueArray * metadata_run (PikaProcedure *procedure,
|
||||||
|
PikaRunMode run_mode,
|
||||||
|
PikaImage *image,
|
||||||
|
gint n_drawables,
|
||||||
|
PikaDrawable **drawables,
|
||||||
PikaProcedureConfig *config,
|
PikaProcedureConfig *config,
|
||||||
gpointer run_data);
|
gpointer run_data);
|
||||||
|
|
||||||
|
@ -747,9 +751,9 @@ metadata_create_procedure (PikaPlugIn *plug_in,
|
||||||
|
|
||||||
if (! strcmp (name, PLUG_IN_PROC))
|
if (! strcmp (name, PLUG_IN_PROC))
|
||||||
{
|
{
|
||||||
procedure = pika_procedure_new (plug_in, name,
|
procedure = pika_image_procedure_new (plug_in, name,
|
||||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
PIKA_PDB_PROC_TYPE_PLUGIN,
|
||||||
metadata_run, NULL, NULL);
|
metadata_run, NULL, NULL);
|
||||||
|
|
||||||
pika_procedure_set_image_types (procedure, "*");
|
pika_procedure_set_image_types (procedure, "*");
|
||||||
|
|
||||||
|
@ -768,19 +772,6 @@ metadata_create_procedure (PikaPlugIn *plug_in,
|
||||||
"Ben Touchette",
|
"Ben Touchette",
|
||||||
"Ben Touchette",
|
"Ben Touchette",
|
||||||
"2017");
|
"2017");
|
||||||
|
|
||||||
PIKA_PROC_ARG_ENUM (procedure, "run-mode",
|
|
||||||
"Run mode",
|
|
||||||
"The run mode",
|
|
||||||
PIKA_TYPE_RUN_MODE,
|
|
||||||
PIKA_RUN_INTERACTIVE,
|
|
||||||
G_PARAM_READWRITE);
|
|
||||||
|
|
||||||
PIKA_PROC_ARG_IMAGE (procedure, "image",
|
|
||||||
"Image",
|
|
||||||
"The input image",
|
|
||||||
FALSE,
|
|
||||||
G_PARAM_READWRITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return procedure;
|
return procedure;
|
||||||
|
@ -788,17 +779,18 @@ metadata_create_procedure (PikaPlugIn *plug_in,
|
||||||
|
|
||||||
static PikaValueArray *
|
static PikaValueArray *
|
||||||
metadata_run (PikaProcedure *procedure,
|
metadata_run (PikaProcedure *procedure,
|
||||||
|
PikaRunMode run_mode,
|
||||||
|
PikaImage *image,
|
||||||
|
gint n_drawables,
|
||||||
|
PikaDrawable **drawables,
|
||||||
PikaProcedureConfig *config,
|
PikaProcedureConfig *config,
|
||||||
gpointer run_data)
|
gpointer run_data)
|
||||||
{
|
{
|
||||||
PikaImage *image;
|
|
||||||
PikaMetadata *metadata;
|
PikaMetadata *metadata;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
pika_ui_init (PLUG_IN_BINARY);
|
pika_ui_init (PLUG_IN_BINARY);
|
||||||
|
|
||||||
g_object_get (config, "image", &image, NULL);
|
|
||||||
|
|
||||||
metadata = pika_image_get_metadata (image);
|
metadata = pika_image_get_metadata (image);
|
||||||
|
|
||||||
/* Always show metadata dialog so we can add appropriate iptc data
|
/* Always show metadata dialog so we can add appropriate iptc data
|
||||||
|
|
|
@ -97,6 +97,10 @@ static PikaProcedure * metadata_create_procedure (PikaPlugIn *plug_in
|
||||||
const gchar *name);
|
const gchar *name);
|
||||||
|
|
||||||
static PikaValueArray * metadata_run (PikaProcedure *procedure,
|
static PikaValueArray * metadata_run (PikaProcedure *procedure,
|
||||||
|
PikaRunMode run_mode,
|
||||||
|
PikaImage *image,
|
||||||
|
gint n_drawables,
|
||||||
|
PikaDrawable **drawables,
|
||||||
PikaProcedureConfig *config,
|
PikaProcedureConfig *config,
|
||||||
gpointer run_data);
|
gpointer run_data);
|
||||||
|
|
||||||
|
@ -172,9 +176,9 @@ metadata_create_procedure (PikaPlugIn *plug_in,
|
||||||
|
|
||||||
if (! strcmp (name, PLUG_IN_PROC))
|
if (! strcmp (name, PLUG_IN_PROC))
|
||||||
{
|
{
|
||||||
procedure = pika_procedure_new (plug_in, name,
|
procedure = pika_image_procedure_new (plug_in, name,
|
||||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
PIKA_PDB_PROC_TYPE_PLUGIN,
|
||||||
metadata_run, NULL, NULL);
|
metadata_run, NULL, NULL);
|
||||||
|
|
||||||
pika_procedure_set_image_types (procedure, "*");
|
pika_procedure_set_image_types (procedure, "*");
|
||||||
|
|
||||||
|
@ -194,19 +198,6 @@ metadata_create_procedure (PikaPlugIn *plug_in,
|
||||||
"Hartmut Kuhse, Michael Natterer, "
|
"Hartmut Kuhse, Michael Natterer, "
|
||||||
"Ben Touchette",
|
"Ben Touchette",
|
||||||
"2013, 2017");
|
"2013, 2017");
|
||||||
|
|
||||||
PIKA_PROC_ARG_ENUM (procedure, "run-mode",
|
|
||||||
"Run mode",
|
|
||||||
"The run mode",
|
|
||||||
PIKA_TYPE_RUN_MODE,
|
|
||||||
PIKA_RUN_INTERACTIVE,
|
|
||||||
G_PARAM_READWRITE);
|
|
||||||
|
|
||||||
PIKA_PROC_ARG_IMAGE (procedure, "image",
|
|
||||||
"Image",
|
|
||||||
"The input image",
|
|
||||||
FALSE,
|
|
||||||
G_PARAM_READWRITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return procedure;
|
return procedure;
|
||||||
|
@ -214,17 +205,18 @@ metadata_create_procedure (PikaPlugIn *plug_in,
|
||||||
|
|
||||||
static PikaValueArray *
|
static PikaValueArray *
|
||||||
metadata_run (PikaProcedure *procedure,
|
metadata_run (PikaProcedure *procedure,
|
||||||
|
PikaRunMode run_mode,
|
||||||
|
PikaImage *image,
|
||||||
|
gint n_drawables,
|
||||||
|
PikaDrawable **drawables,
|
||||||
PikaProcedureConfig *config,
|
PikaProcedureConfig *config,
|
||||||
gpointer run_data)
|
gpointer run_data)
|
||||||
{
|
{
|
||||||
PikaImage *image;
|
|
||||||
PikaMetadata *metadata;
|
PikaMetadata *metadata;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
pika_ui_init (PLUG_IN_BINARY);
|
pika_ui_init (PLUG_IN_BINARY);
|
||||||
|
|
||||||
g_object_get (config, "image", &image, NULL);
|
|
||||||
|
|
||||||
metadata = pika_image_get_metadata (image);
|
metadata = pika_image_get_metadata (image);
|
||||||
|
|
||||||
/* Always show metadata dialog so we can add appropriate iptc data
|
/* Always show metadata dialog so we can add appropriate iptc data
|
||||||
|
|
|
@ -77,6 +77,7 @@ marshal_vector_to_drawable_array (scheme *sc,
|
||||||
PikaDrawable **drawable_array;
|
PikaDrawable **drawable_array;
|
||||||
gint id;
|
gint id;
|
||||||
pointer error;
|
pointer error;
|
||||||
|
GType actual_type = PIKA_TYPE_DRAWABLE;
|
||||||
|
|
||||||
guint num_elements = sc->vptr->vector_length (vector);
|
guint num_elements = sc->vptr->vector_length (vector);
|
||||||
g_debug ("vector has %d elements", num_elements);
|
g_debug ("vector has %d elements", num_elements);
|
||||||
|
@ -104,10 +105,15 @@ marshal_vector_to_drawable_array (scheme *sc,
|
||||||
g_free (drawable_array);
|
g_free (drawable_array);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parameters are validated based on the actual type inside the object
|
||||||
|
array. So we set that type here instead of a generic drawable. */
|
||||||
|
if (j == 0)
|
||||||
|
actual_type = G_OBJECT_TYPE (drawable_array[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shallow copy. */
|
/* Shallow copy. */
|
||||||
pika_value_set_object_array (value, PIKA_TYPE_DRAWABLE, (GObject**)drawable_array, num_elements);
|
pika_value_set_object_array (value, actual_type, (GObject**)drawable_array, num_elements);
|
||||||
|
|
||||||
g_free (drawable_array);
|
g_free (drawable_array);
|
||||||
|
|
||||||
|
|
|
@ -615,7 +615,7 @@ script_fu_resource_widget (const gchar *title,
|
||||||
{
|
{
|
||||||
GtkWidget *result_widget = NULL;
|
GtkWidget *result_widget = NULL;
|
||||||
|
|
||||||
g_debug ("%s type: %ld", G_STRFUNC, resource_type);
|
g_debug ("%s type: %" G_GSIZE_FORMAT, G_STRFUNC, resource_type);
|
||||||
|
|
||||||
/* Passing NULL resource sets initial choice to resource from context.
|
/* Passing NULL resource sets initial choice to resource from context.
|
||||||
* Passing empty string for outer widget label, since we provide our own.
|
* Passing empty string for outer widget label, since we provide our own.
|
||||||
|
@ -824,6 +824,10 @@ script_fu_update_models (SFScript *script)
|
||||||
FALSE);
|
FALSE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Silence warnings about unhandled enumeration values */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue