mirror of https://github.com/GNOME/gimp.git
plug-ins: Add .ani file import/export
This commit is contained in:
parent
e7faae1dc3
commit
aa51b9e19e
|
@ -38,10 +38,16 @@ static void ico_dialog_toggle_compress (GtkWidget *checkbox,
|
||||||
GObject *hbox);
|
GObject *hbox);
|
||||||
static void ico_dialog_check_compat (GtkWidget *dialog,
|
static void ico_dialog_check_compat (GtkWidget *dialog,
|
||||||
IcoSaveInfo *info);
|
IcoSaveInfo *info);
|
||||||
|
static void ico_dialog_ani_update_inam (GtkEntry *entry,
|
||||||
|
gpointer data);
|
||||||
|
static void ico_dialog_ani_update_iart (GtkEntry *entry,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
ico_dialog_new (IcoSaveInfo *info)
|
ico_dialog_new (IcoSaveInfo *info,
|
||||||
|
AniFileHeader *ani_header,
|
||||||
|
AniSaveInfo *ani_info)
|
||||||
{
|
{
|
||||||
GtkWidget *dialog;
|
GtkWidget *dialog;
|
||||||
GtkWidget *main_vbox;
|
GtkWidget *main_vbox;
|
||||||
|
@ -51,7 +57,8 @@ ico_dialog_new (IcoSaveInfo *info)
|
||||||
GtkWidget *viewport;
|
GtkWidget *viewport;
|
||||||
GtkWidget *warning;
|
GtkWidget *warning;
|
||||||
|
|
||||||
dialog = gimp_export_dialog_new (info->is_cursor ?
|
dialog = gimp_export_dialog_new (ani_header ?
|
||||||
|
_("Windows Animated Cursor") : info->is_cursor ?
|
||||||
_("Windows Cursor") : _("Windows Icon"),
|
_("Windows Cursor") : _("Windows Icon"),
|
||||||
PLUG_IN_BINARY,
|
PLUG_IN_BINARY,
|
||||||
"plug-in-winicon");
|
"plug-in-winicon");
|
||||||
|
@ -65,6 +72,11 @@ ico_dialog_new (IcoSaveInfo *info)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g_object_set_data (G_OBJECT (dialog), "save_info", info);
|
g_object_set_data (G_OBJECT (dialog), "save_info", info);
|
||||||
|
if (ani_header)
|
||||||
|
{
|
||||||
|
g_object_set_data (G_OBJECT (dialog), "save_ani_header", ani_header);
|
||||||
|
g_object_set_data (G_OBJECT (dialog), "save_ani_info", ani_info);
|
||||||
|
}
|
||||||
|
|
||||||
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||||
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
|
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
|
||||||
|
@ -72,6 +84,82 @@ ico_dialog_new (IcoSaveInfo *info)
|
||||||
main_vbox, TRUE, TRUE, 0);
|
main_vbox, TRUE, TRUE, 0);
|
||||||
gtk_widget_show (main_vbox);
|
gtk_widget_show (main_vbox);
|
||||||
|
|
||||||
|
/*Animated Cursor */
|
||||||
|
if (ani_header)
|
||||||
|
{
|
||||||
|
GtkWidget *grid;
|
||||||
|
GtkAdjustment *adjustment;
|
||||||
|
GtkWidget *spin;
|
||||||
|
GtkWidget *label;
|
||||||
|
GtkWidget *hbox;
|
||||||
|
GtkWidget *entry;
|
||||||
|
|
||||||
|
frame = gimp_frame_new (_("Animated Cursor Settings"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (frame);
|
||||||
|
|
||||||
|
grid = gtk_grid_new ();
|
||||||
|
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||||
|
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||||
|
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||||
|
gtk_widget_show (grid);
|
||||||
|
|
||||||
|
/* Cursor Name */
|
||||||
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||||
|
gimp_grid_attach_aligned (GTK_GRID (grid), 0, 1,
|
||||||
|
_("_Cursor Name (Optional)"),
|
||||||
|
0.0, 0.5,
|
||||||
|
hbox, 1);
|
||||||
|
|
||||||
|
entry = gtk_entry_new ();
|
||||||
|
gtk_entry_set_text (GTK_ENTRY (entry),
|
||||||
|
ani_info->inam ? ani_info->inam : "");
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (entry);
|
||||||
|
|
||||||
|
g_signal_connect (GTK_ENTRY (entry), "focus-out-event",
|
||||||
|
G_CALLBACK (ico_dialog_ani_update_inam),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Author Name */
|
||||||
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||||
|
gimp_grid_attach_aligned (GTK_GRID (grid), 0, 3,
|
||||||
|
_("_Author Name (Optional)"),
|
||||||
|
0.0, 0.5,
|
||||||
|
hbox, 1);
|
||||||
|
|
||||||
|
entry = gtk_entry_new ();
|
||||||
|
gtk_entry_set_text (GTK_ENTRY (entry),
|
||||||
|
ani_info->iart ? ani_info->iart : "");
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (entry);
|
||||||
|
|
||||||
|
g_signal_connect (GTK_ENTRY (entry), "focus-out-event",
|
||||||
|
G_CALLBACK (ico_dialog_ani_update_iart),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Default delay spin */
|
||||||
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||||
|
gimp_grid_attach_aligned (GTK_GRID (grid), 0, 5,
|
||||||
|
_("_Delay between frames:"),
|
||||||
|
0.0, 0.5,
|
||||||
|
hbox, 1);
|
||||||
|
|
||||||
|
adjustment = gtk_adjustment_new (ani_header->jif_rate, 1, G_MAXINT,
|
||||||
|
1, 10, 0);
|
||||||
|
spin = gimp_spin_button_new (adjustment, 1, 0);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (spin);
|
||||||
|
|
||||||
|
label = gtk_label_new (_(" jiffies (16.66 ms)"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
|
||||||
|
g_signal_connect (adjustment, "value-changed",
|
||||||
|
G_CALLBACK (gimp_int_adjustment_update),
|
||||||
|
&ani_header->jif_rate);
|
||||||
|
}
|
||||||
|
|
||||||
/* Cursor */
|
/* Cursor */
|
||||||
frame = gimp_frame_new (_("Icon Details"));
|
frame = gimp_frame_new (_("Icon Details"));
|
||||||
gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 4);
|
gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 4);
|
||||||
|
@ -572,3 +660,29 @@ ico_dialog_check_compat (GtkWidget *dialog,
|
||||||
|
|
||||||
gtk_widget_set_visible (warning, warn);
|
gtk_widget_set_visible (warning, warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ico_dialog_ani_update_inam (GtkEntry *entry,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
AniSaveInfo *ani_info;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
|
||||||
|
dialog = gtk_widget_get_toplevel (GTK_WIDGET (entry));
|
||||||
|
|
||||||
|
ani_info = g_object_get_data (G_OBJECT (dialog), "save_ani_info");
|
||||||
|
ani_info->inam = g_strdup_printf ("%s", gtk_entry_get_text (entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ico_dialog_ani_update_iart (GtkEntry *entry,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
AniSaveInfo *ani_info;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
|
||||||
|
dialog = gtk_widget_get_toplevel (GTK_WIDGET (entry));
|
||||||
|
|
||||||
|
ani_info = g_object_get_data (G_OBJECT (dialog), "save_ani_info");
|
||||||
|
ani_info->iart = g_strdup_printf ("%s", gtk_entry_get_text (entry));
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
#define __ICO_DIALOG_H__
|
#define __ICO_DIALOG_H__
|
||||||
|
|
||||||
|
|
||||||
GtkWidget * ico_dialog_new (IcoSaveInfo *info);
|
GtkWidget * ico_dialog_new (IcoSaveInfo *info,
|
||||||
|
AniFileHeader *ani_header,
|
||||||
|
AniSaveInfo *ani_info);
|
||||||
void ico_dialog_add_icon (GtkWidget *dialog,
|
void ico_dialog_add_icon (GtkWidget *dialog,
|
||||||
GimpDrawable *layer,
|
GimpDrawable *layer,
|
||||||
gint layer_num);
|
gint layer_num);
|
||||||
|
|
|
@ -142,6 +142,7 @@ ico_read_init (FILE *fp)
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ico_read_size (FILE *fp,
|
ico_read_size (FILE *fp,
|
||||||
|
gint32 file_offset,
|
||||||
IcoLoadInfo *info)
|
IcoLoadInfo *info)
|
||||||
{
|
{
|
||||||
png_structp png_ptr;
|
png_structp png_ptr;
|
||||||
|
@ -151,7 +152,7 @@ ico_read_size (FILE *fp,
|
||||||
gint32 color_type;
|
gint32 color_type;
|
||||||
guint32 magic;
|
guint32 magic;
|
||||||
|
|
||||||
if (fseek (fp, info->offset, SEEK_SET) < 0)
|
if (fseek (fp, info->offset + file_offset, SEEK_SET) < 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
ico_read_int32 (fp, &magic, 1);
|
ico_read_int32 (fp, &magic, 1);
|
||||||
|
@ -208,6 +209,7 @@ ico_read_size (FILE *fp,
|
||||||
static IcoLoadInfo*
|
static IcoLoadInfo*
|
||||||
ico_read_info (FILE *fp,
|
ico_read_info (FILE *fp,
|
||||||
gint icon_count,
|
gint icon_count,
|
||||||
|
gint32 file_offset,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
|
@ -237,7 +239,7 @@ ico_read_info (FILE *fp,
|
||||||
|
|
||||||
if (info[i].width == 0 || info[i].height == 0)
|
if (info[i].width == 0 || info[i].height == 0)
|
||||||
{
|
{
|
||||||
ico_read_size (fp, info + i);
|
ico_read_size (fp, file_offset, info + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
D(("ico_read_info: %ix%i (%i bits, size: %i, offset: %i)\n",
|
D(("ico_read_info: %ix%i (%i bits, size: %i, offset: %i)\n",
|
||||||
|
@ -605,6 +607,7 @@ ico_load_layer (FILE *fp,
|
||||||
gint32 icon_num,
|
gint32 icon_num,
|
||||||
guchar *buf,
|
guchar *buf,
|
||||||
gint maxsize,
|
gint maxsize,
|
||||||
|
gint32 file_offset,
|
||||||
IcoLoadInfo *info)
|
IcoLoadInfo *info)
|
||||||
{
|
{
|
||||||
gint width, height;
|
gint width, height;
|
||||||
|
@ -613,7 +616,7 @@ ico_load_layer (FILE *fp,
|
||||||
GeglBuffer *buffer;
|
GeglBuffer *buffer;
|
||||||
gchar name[ICO_MAXBUF];
|
gchar name[ICO_MAXBUF];
|
||||||
|
|
||||||
if (fseek (fp, info->offset, SEEK_SET) < 0 ||
|
if (fseek (fp, info->offset + file_offset, SEEK_SET) < 0 ||
|
||||||
! ico_read_int32 (fp, &first_bytes, 1))
|
! ico_read_int32 (fp, &first_bytes, 1))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -653,6 +656,7 @@ ico_load_layer (FILE *fp,
|
||||||
|
|
||||||
GimpImage *
|
GimpImage *
|
||||||
ico_load_image (GFile *file,
|
ico_load_image (GFile *file,
|
||||||
|
gint32 *file_offset,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
@ -666,6 +670,7 @@ ico_load_image (GFile *file,
|
||||||
gint maxsize;
|
gint maxsize;
|
||||||
gchar *str;
|
gchar *str;
|
||||||
|
|
||||||
|
if (! file_offset)
|
||||||
gimp_progress_init_printf (_("Opening '%s'"),
|
gimp_progress_init_printf (_("Opening '%s'"),
|
||||||
gimp_file_get_utf8_name (file));
|
gimp_file_get_utf8_name (file));
|
||||||
|
|
||||||
|
@ -679,6 +684,9 @@ ico_load_image (GFile *file,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file_offset)
|
||||||
|
fseek (fp, *file_offset, SEEK_SET);
|
||||||
|
|
||||||
header = ico_read_init (fp);
|
header = ico_read_init (fp);
|
||||||
icon_count = header.icon_count;
|
icon_count = header.icon_count;
|
||||||
if (!icon_count)
|
if (!icon_count)
|
||||||
|
@ -687,7 +695,7 @@ ico_load_image (GFile *file,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
info = ico_read_info (fp, icon_count, error);
|
info = ico_read_info (fp, icon_count, file_offset ? *file_offset : 0, error);
|
||||||
if (! info)
|
if (! info)
|
||||||
{
|
{
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
|
@ -713,6 +721,7 @@ ico_load_image (GFile *file,
|
||||||
D(("image size: %ix%i\n", max_width, max_height));
|
D(("image size: %ix%i\n", max_width, max_height));
|
||||||
|
|
||||||
image = gimp_image_new (max_width, max_height, GIMP_RGB);
|
image = gimp_image_new (max_width, max_height, GIMP_RGB);
|
||||||
|
if (! file_offset)
|
||||||
gimp_image_set_file (image, file);
|
gimp_image_set_file (image, file);
|
||||||
|
|
||||||
maxsize = max_width * max_height * 4;
|
maxsize = max_width * max_height * 4;
|
||||||
|
@ -721,7 +730,7 @@ ico_load_image (GFile *file,
|
||||||
{
|
{
|
||||||
GimpLayer *layer;
|
GimpLayer *layer;
|
||||||
|
|
||||||
layer = ico_load_layer (fp, image, i, buf, maxsize, info+i);
|
layer = ico_load_layer (fp, image, i, buf, maxsize, file_offset ? *file_offset : 0, info+i);
|
||||||
|
|
||||||
/* Save CUR hot spot information */
|
/* Save CUR hot spot information */
|
||||||
if (header.resource_type == 2)
|
if (header.resource_type == 2)
|
||||||
|
@ -737,10 +746,172 @@ ico_load_image (GFile *file,
|
||||||
gimp_parasite_free (parasite);
|
gimp_parasite_free (parasite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file_offset)
|
||||||
|
*file_offset = ftell (fp);
|
||||||
|
|
||||||
g_free (buf);
|
g_free (buf);
|
||||||
g_free (info);
|
g_free (info);
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
|
|
||||||
|
/* Don't update progress here if .ani file */
|
||||||
|
if (! file_offset)
|
||||||
|
gimp_progress_update (1.0);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ported from James Huang's ani.c code, under the GPL license, version 3
|
||||||
|
* or any later version of the license */
|
||||||
|
GimpImage *
|
||||||
|
ani_load_image (GFile *file,
|
||||||
|
gboolean load_thumb,
|
||||||
|
gint *width,
|
||||||
|
gint *height,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
GimpImage *image = NULL;
|
||||||
|
GimpParasite *parasite;
|
||||||
|
gchar id[4];
|
||||||
|
guint32 size;
|
||||||
|
gint32 file_offset;
|
||||||
|
gint frame = 1;
|
||||||
|
AniFileHeader header;
|
||||||
|
gchar inam[G_MAXSHORT] = {0};
|
||||||
|
gchar iart[G_MAXSHORT] = {0};
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
gimp_progress_init_printf (_("Opening '%s'"),
|
||||||
|
gimp_file_get_utf8_name (file));
|
||||||
|
|
||||||
|
fp = g_fopen (g_file_peek_path (file), "rb");
|
||||||
|
|
||||||
|
if (! fp)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||||
|
_("Could not open '%s' for reading: %s"),
|
||||||
|
gimp_file_get_utf8_name (file), g_strerror (errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fread (id, 1, 4, fp) == 4)
|
||||||
|
{
|
||||||
|
if (memcmp (id, "RIFF", 4) == 0 )
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
}
|
||||||
|
else if (memcmp (id, "anih", 4) == 0)
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
fread (&header, sizeof (header), 1, fp);
|
||||||
|
}
|
||||||
|
else if (memcmp (id, "rate", 4) == 0)
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
fseek (fp, size, SEEK_CUR);
|
||||||
|
}
|
||||||
|
else if (memcmp (id, "seq ", 4) == 0)
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
fseek (fp, size, SEEK_CUR);
|
||||||
|
}
|
||||||
|
else if (memcmp (id, "LIST", 4) == 0)
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
}
|
||||||
|
else if (memcmp (id, "INAM", 4) == 0)
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
fread (&inam, sizeof (char), size, fp);
|
||||||
|
inam[size] = '\0';
|
||||||
|
}
|
||||||
|
else if (memcmp (id, "IART", 4) == 0)
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
fread (&iart, sizeof (char), size, fp);
|
||||||
|
iart[size] = '\0';
|
||||||
|
}
|
||||||
|
else if (memcmp (id, "icon", 4) == 0)
|
||||||
|
{
|
||||||
|
fread (&size, sizeof (size), 1, fp);
|
||||||
|
file_offset = ftell (fp);
|
||||||
|
if (load_thumb)
|
||||||
|
{
|
||||||
|
image = ico_load_thumbnail_image (file, width, height, file_offset, error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (! image)
|
||||||
|
{
|
||||||
|
image = ico_load_image (file, &file_offset, error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GimpImage *temp_image = NULL;
|
||||||
|
GimpLayer **layers;
|
||||||
|
GimpLayer *new_layer;
|
||||||
|
gint nlayers;
|
||||||
|
|
||||||
|
temp_image = ico_load_image (file, &file_offset, error);
|
||||||
|
layers = gimp_image_get_layers (temp_image, &nlayers);
|
||||||
|
if (layers)
|
||||||
|
{
|
||||||
|
for (gint i = 0; i < nlayers; i++)
|
||||||
|
{
|
||||||
|
new_layer = gimp_layer_new_from_drawable (GIMP_DRAWABLE (layers[i]),
|
||||||
|
image);
|
||||||
|
gimp_image_insert_layer (image, new_layer, NULL, frame);
|
||||||
|
frame++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gimp_image_delete (temp_image);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update position after reading icon data */
|
||||||
|
fseek (fp, file_offset, SEEK_SET);
|
||||||
|
if (header.frames > 0)
|
||||||
|
gimp_progress_update ((gdouble) frame /
|
||||||
|
(gdouble) header.frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose (fp);
|
||||||
|
|
||||||
|
/* Saving header metadata */
|
||||||
|
str = g_strdup_printf ("%d", header.jif_rate);
|
||||||
|
parasite = gimp_parasite_new ("ani-header",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (str) + 1, (gpointer) str);
|
||||||
|
g_free (str);
|
||||||
|
gimp_image_attach_parasite (image, parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
|
||||||
|
/* Saving INFO block */
|
||||||
|
if (strlen (inam) > 0)
|
||||||
|
{
|
||||||
|
str = g_strdup_printf ("%s", inam);
|
||||||
|
parasite = gimp_parasite_new ("ani-info-inam",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (str) + 1, (gpointer) str);
|
||||||
|
g_free (str);
|
||||||
|
gimp_image_attach_parasite (image, parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen (iart) > 0)
|
||||||
|
{
|
||||||
|
str = g_strdup_printf ("%s", iart);
|
||||||
|
parasite = gimp_parasite_new ("ani-info-iart",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (str) + 1, (gpointer) str);
|
||||||
|
g_free (str);
|
||||||
|
gimp_image_attach_parasite (image, parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_image_set_file (image, file);
|
||||||
gimp_progress_update (1.0);
|
gimp_progress_update (1.0);
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
@ -750,6 +921,7 @@ GimpImage *
|
||||||
ico_load_thumbnail_image (GFile *file,
|
ico_load_thumbnail_image (GFile *file,
|
||||||
gint *width,
|
gint *width,
|
||||||
gint *height,
|
gint *height,
|
||||||
|
gint32 file_offset,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
@ -776,6 +948,9 @@ ico_load_thumbnail_image (GFile *file,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file_offset > 0)
|
||||||
|
fseek (fp, file_offset, SEEK_SET);
|
||||||
|
|
||||||
header = ico_read_init (fp);
|
header = ico_read_init (fp);
|
||||||
icon_count = header.icon_count;
|
icon_count = header.icon_count;
|
||||||
if (! icon_count)
|
if (! icon_count)
|
||||||
|
@ -787,7 +962,7 @@ ico_load_thumbnail_image (GFile *file,
|
||||||
D(("*** %s: Microsoft icon file, containing %i icon(s)\n",
|
D(("*** %s: Microsoft icon file, containing %i icon(s)\n",
|
||||||
gimp_file_get_utf8_name (file), icon_count));
|
gimp_file_get_utf8_name (file), icon_count));
|
||||||
|
|
||||||
info = ico_read_info (fp, icon_count, error);
|
info = ico_read_info (fp, icon_count, file_offset, error);
|
||||||
if (! info)
|
if (! info)
|
||||||
{
|
{
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
|
@ -821,7 +996,7 @@ ico_load_thumbnail_image (GFile *file,
|
||||||
|
|
||||||
image = gimp_image_new (w, h, GIMP_RGB);
|
image = gimp_image_new (w, h, GIMP_RGB);
|
||||||
buf = g_new (guchar, w*h*4);
|
buf = g_new (guchar, w*h*4);
|
||||||
ico_load_layer (fp, image, match, buf, w*h*4, info+match);
|
ico_load_layer (fp, image, match, buf, w*h*4, file_offset, info+match);
|
||||||
g_free (buf);
|
g_free (buf);
|
||||||
|
|
||||||
*width = w;
|
*width = w;
|
||||||
|
|
|
@ -23,10 +23,17 @@
|
||||||
|
|
||||||
|
|
||||||
GimpImage * ico_load_image (GFile *file,
|
GimpImage * ico_load_image (GFile *file,
|
||||||
|
gint32 *file_offset,
|
||||||
|
GError **error);
|
||||||
|
GimpImage * ani_load_image (GFile *file,
|
||||||
|
gboolean load_thumb,
|
||||||
|
gint *width,
|
||||||
|
gint *height,
|
||||||
GError **error);
|
GError **error);
|
||||||
GimpImage * ico_load_thumbnail_image (GFile *file,
|
GimpImage * ico_load_thumbnail_image (GFile *file,
|
||||||
gint *width,
|
gint *width,
|
||||||
gint *height,
|
gint *height,
|
||||||
|
gint32 file_offset,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
gint ico_get_bit_from_data (const guint8 *data,
|
gint ico_get_bit_from_data (const guint8 *data,
|
||||||
|
|
|
@ -82,12 +82,15 @@ static gboolean ico_save_init (GimpImage *image,
|
||||||
GError **error);
|
GError **error);
|
||||||
static GimpPDBStatusType
|
static GimpPDBStatusType
|
||||||
shared_save_image (GFile *file,
|
shared_save_image (GFile *file,
|
||||||
|
FILE *fp_ani,
|
||||||
GimpImage *image,
|
GimpImage *image,
|
||||||
gint32 run_mode,
|
gint32 run_mode,
|
||||||
gint *n_hot_spot_x,
|
gint *n_hot_spot_x,
|
||||||
gint32 **hot_spot_x,
|
gint32 **hot_spot_x,
|
||||||
gint *n_hot_spot_y,
|
gint *n_hot_spot_y,
|
||||||
gint32 **hot_spot_y,
|
gint32 **hot_spot_y,
|
||||||
|
gint32 file_offset,
|
||||||
|
gint icon_index,
|
||||||
GError **error,
|
GError **error,
|
||||||
IcoSaveInfo *info);
|
IcoSaveInfo *info);
|
||||||
|
|
||||||
|
@ -303,7 +306,9 @@ ico_save_init (GimpImage *image,
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ico_save_dialog (GimpImage *image,
|
ico_save_dialog (GimpImage *image,
|
||||||
IcoSaveInfo *info)
|
IcoSaveInfo *info,
|
||||||
|
AniFileHeader *ani_header,
|
||||||
|
AniSaveInfo *ani_info)
|
||||||
{
|
{
|
||||||
GtkWidget *dialog;
|
GtkWidget *dialog;
|
||||||
GList *iter;
|
GList *iter;
|
||||||
|
@ -312,7 +317,7 @@ ico_save_dialog (GimpImage *image,
|
||||||
|
|
||||||
gimp_ui_init (PLUG_IN_BINARY);
|
gimp_ui_init (PLUG_IN_BINARY);
|
||||||
|
|
||||||
dialog = ico_dialog_new (info);
|
dialog = ico_dialog_new (info, ani_header, ani_info);
|
||||||
for (iter = info->layers, i = 0;
|
for (iter = info->layers, i = 0;
|
||||||
iter;
|
iter;
|
||||||
iter = g_list_next (iter), i++)
|
iter = g_list_next (iter), i++)
|
||||||
|
@ -1174,9 +1179,9 @@ ico_save_image (GFile *file,
|
||||||
|
|
||||||
info.is_cursor = FALSE;
|
info.is_cursor = FALSE;
|
||||||
|
|
||||||
return shared_save_image (file, image, run_mode,
|
return shared_save_image (file, NULL, image, run_mode,
|
||||||
0, NULL, 0, NULL,
|
0, NULL, 0, NULL,
|
||||||
error, &info);
|
0, 0, error, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
GimpPDBStatusType
|
GimpPDBStatusType
|
||||||
|
@ -1196,49 +1201,122 @@ cur_save_image (GFile *file,
|
||||||
|
|
||||||
info.is_cursor = TRUE;
|
info.is_cursor = TRUE;
|
||||||
|
|
||||||
return shared_save_image (file, image, run_mode,
|
return shared_save_image (file, NULL, image, run_mode,
|
||||||
n_hot_spot_x, hot_spot_x,
|
n_hot_spot_x, hot_spot_x,
|
||||||
n_hot_spot_y, hot_spot_y,
|
n_hot_spot_y, hot_spot_y,
|
||||||
error, &info);
|
0, 0, error, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ported from James Huang's ani.c code, under the GPL v3 license */
|
||||||
GimpPDBStatusType
|
GimpPDBStatusType
|
||||||
shared_save_image (GFile *file,
|
ani_save_image (GFile *file,
|
||||||
GimpImage *image,
|
GimpImage *image,
|
||||||
gint32 run_mode,
|
gint32 run_mode,
|
||||||
gint *n_hot_spot_x,
|
gint *n_hot_spot_x,
|
||||||
gint32 **hot_spot_x,
|
gint32 **hot_spot_x,
|
||||||
gint *n_hot_spot_y,
|
gint *n_hot_spot_y,
|
||||||
gint32 **hot_spot_y,
|
gint32 **hot_spot_y,
|
||||||
GError **error,
|
AniFileHeader *header,
|
||||||
IcoSaveInfo *info)
|
AniSaveInfo *ani_info,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
GList *iter;
|
gint32 i;
|
||||||
gint width;
|
|
||||||
gint height;
|
|
||||||
IcoFileHeader header;
|
|
||||||
IcoFileEntry *entries;
|
|
||||||
gboolean saved;
|
|
||||||
gint i;
|
|
||||||
GimpParasite *parasite = NULL;
|
|
||||||
gchar *str;
|
gchar *str;
|
||||||
|
GimpParasite *parasite = NULL;
|
||||||
|
gchar id[5];
|
||||||
|
guint32 size;
|
||||||
|
gint32 offset, ofs_size_riff, ofs_size_list, ofs_size_icon;
|
||||||
|
gint32 ofs_size_info = 0;
|
||||||
|
IcoSaveInfo info;
|
||||||
|
|
||||||
if (! ico_save_init (image, run_mode, info,
|
if (! ico_save_init (image, run_mode, &info,
|
||||||
n_hot_spot_x ? *n_hot_spot_x : 0,
|
*n_hot_spot_x, *hot_spot_x,
|
||||||
hot_spot_x ? *hot_spot_x : NULL,
|
*n_hot_spot_y, *hot_spot_y,
|
||||||
n_hot_spot_y ? *n_hot_spot_y : 0,
|
|
||||||
hot_spot_y ? *hot_spot_y : NULL,
|
|
||||||
error))
|
error))
|
||||||
{
|
{
|
||||||
return GIMP_PDB_EXECUTION_ERROR;
|
return GIMP_PDB_EXECUTION_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Save individual frames as .cur so we can retain
|
||||||
|
* the hotspot information
|
||||||
|
*/
|
||||||
|
info.is_cursor = TRUE;
|
||||||
|
|
||||||
|
/* Default header values */
|
||||||
|
header->bSizeOf = sizeof (*header);
|
||||||
|
header->frames = info.num_icons;
|
||||||
|
header->steps = info.num_icons;
|
||||||
|
header->x = 0;
|
||||||
|
header->y = 0;
|
||||||
|
if (info.depths[0] == 24)
|
||||||
|
{
|
||||||
|
header->bpp = 4;
|
||||||
|
header->planes = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
header->bpp = 0;
|
||||||
|
header->planes = 0;
|
||||||
|
}
|
||||||
|
header->flags = 1;
|
||||||
|
|
||||||
|
/* Load metadata from parasite */
|
||||||
|
parasite = gimp_image_get_parasite (image, "ani-header");
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
gchar *parasite_data;
|
||||||
|
guint32 parasite_size;
|
||||||
|
gint jif_rate;
|
||||||
|
|
||||||
|
parasite_data = (gchar *) gimp_parasite_get_data (parasite, ¶site_size);
|
||||||
|
parasite_data = g_strndup (parasite_data, parasite_size);
|
||||||
|
|
||||||
|
if (sscanf (parasite_data, "%i", &jif_rate) == 1)
|
||||||
|
{
|
||||||
|
header->jif_rate = jif_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
g_free (parasite_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
parasite = gimp_image_get_parasite (image, "ani-info-inam");
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
guint32 parasite_size;
|
||||||
|
gchar *inam = NULL;
|
||||||
|
|
||||||
|
inam = (gchar *) gimp_parasite_get_data (parasite, ¶site_size);
|
||||||
|
ani_info->inam = g_strndup (inam, parasite_size);
|
||||||
|
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
parasite = gimp_image_get_parasite (image, "ani-info-iart");
|
||||||
|
if (parasite)
|
||||||
|
{
|
||||||
|
guint32 parasite_size;
|
||||||
|
gchar *iart = NULL;
|
||||||
|
|
||||||
|
iart = (gchar *) gimp_parasite_get_data (parasite, ¶site_size);
|
||||||
|
ani_info->iart = g_strndup (iart, parasite_size);
|
||||||
|
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
if (run_mode == GIMP_RUN_INTERACTIVE)
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
||||||
{
|
{
|
||||||
/* Allow user to override default values */
|
if (! ico_save_dialog (image, &info,
|
||||||
if ( !ico_save_dialog (image, info))
|
header, ani_info))
|
||||||
return GIMP_PDB_CANCEL;
|
return GIMP_PDB_CANCEL;
|
||||||
|
|
||||||
|
for (i = 1; i < info.num_icons; i++)
|
||||||
|
{
|
||||||
|
info.depths[i] = info.depths[0];
|
||||||
|
info.default_depths[i] = info.default_depths[0];
|
||||||
|
info.compress[i] = info.compress[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gimp_progress_init_printf (_("Exporting '%s'"),
|
gimp_progress_init_printf (_("Exporting '%s'"),
|
||||||
|
@ -1246,6 +1324,212 @@ shared_save_image (GFile *file,
|
||||||
|
|
||||||
fp = g_fopen (g_file_peek_path (file), "wb");
|
fp = g_fopen (g_file_peek_path (file), "wb");
|
||||||
|
|
||||||
|
if (! fp)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||||
|
_("Could not open '%s' for writing: %s"),
|
||||||
|
gimp_file_get_utf8_name (file), g_strerror (errno));
|
||||||
|
return GIMP_PDB_EXECUTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Writing the .ani header data */
|
||||||
|
strcpy (id, "RIFF");
|
||||||
|
size = 0;
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
ofs_size_riff = ftell (fp);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
|
||||||
|
strcpy (id, "ACON");
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
|
||||||
|
if ((ani_info->inam && strlen (ani_info->inam) > 0) ||
|
||||||
|
(ani_info->iart && strlen (ani_info->iart) > 0))
|
||||||
|
{
|
||||||
|
gint32 string_size;
|
||||||
|
|
||||||
|
strcpy (id, "LIST");
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
ofs_size_info = ftell (fp);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
|
||||||
|
strcpy (id, "INFO");
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
if (ani_info->inam && strlen (ani_info->inam) > 0) /* Cursor name */
|
||||||
|
{
|
||||||
|
strcpy (id, "INAM");
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
string_size = strlen (ani_info->inam) + 1;
|
||||||
|
fwrite (&string_size, 4, 1, fp);
|
||||||
|
fwrite (ani_info->inam, string_size, 1, fp);
|
||||||
|
}
|
||||||
|
if (ani_info->iart && strlen (ani_info->iart) > 0) /* Author name */
|
||||||
|
{
|
||||||
|
strcpy (id, "IART");
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
string_size = strlen (ani_info->iart) + 1;
|
||||||
|
fwrite (&string_size, 4, 1, fp);
|
||||||
|
fwrite (ani_info->iart, string_size, 1, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go back and update info list size */
|
||||||
|
fseek (fp, 0L, SEEK_END);
|
||||||
|
size = ftell (fp) - ofs_size_info - 4;
|
||||||
|
fseek (fp, ofs_size_info, SEEK_SET);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
fseek (fp, 0L, SEEK_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy (id, "anih");
|
||||||
|
size = sizeof (*header);
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
fwrite (header, sizeof (*header), 1, fp);
|
||||||
|
|
||||||
|
strcpy (id, "LIST");
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
ofs_size_list = ftell (fp);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
|
||||||
|
strcpy (id, "fram");
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
|
||||||
|
strcpy (id, "icon");
|
||||||
|
for (i = 0; i < info.num_icons; i++ )
|
||||||
|
{
|
||||||
|
GimpPDBStatusType status;
|
||||||
|
fwrite (id, 4, 1, fp);
|
||||||
|
ofs_size_icon = ftell (fp);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
offset = ftell (fp);
|
||||||
|
status = shared_save_image (file, fp, image, run_mode,
|
||||||
|
n_hot_spot_x, hot_spot_x,
|
||||||
|
n_hot_spot_y, hot_spot_y,
|
||||||
|
offset, i, error, &info);
|
||||||
|
|
||||||
|
if (status != GIMP_PDB_SUCCESS)
|
||||||
|
{
|
||||||
|
ico_save_info_free (&info);
|
||||||
|
g_free (ani_info->inam);
|
||||||
|
g_free (ani_info->iart);
|
||||||
|
fclose (fp);
|
||||||
|
return GIMP_PDB_EXECUTION_ERROR;
|
||||||
|
}
|
||||||
|
fseek (fp, 0L, SEEK_END);
|
||||||
|
size = ftell (fp) - offset;
|
||||||
|
fseek (fp, ofs_size_icon, SEEK_SET);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
fseek (fp, 0L, SEEK_END);
|
||||||
|
|
||||||
|
gimp_progress_update ((gdouble) i / (gdouble) info.num_icons);
|
||||||
|
}
|
||||||
|
ico_save_info_free (&info);
|
||||||
|
|
||||||
|
fseek (fp, 0L, SEEK_END);
|
||||||
|
size = ftell (fp);
|
||||||
|
fseek (fp, ofs_size_riff, SEEK_SET);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
|
||||||
|
size -= ofs_size_list;
|
||||||
|
fseek (fp, ofs_size_list, SEEK_SET);
|
||||||
|
fwrite (&size, sizeof (size), 1, fp);
|
||||||
|
fclose (fp);
|
||||||
|
|
||||||
|
/* Update metadata if needed */
|
||||||
|
str = g_strdup_printf ("%d", header->jif_rate);
|
||||||
|
parasite = gimp_parasite_new ("ani-header",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (str) + 1, (gpointer) str);
|
||||||
|
g_free (str);
|
||||||
|
gimp_image_attach_parasite (image, parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
|
||||||
|
if (ani_info->inam && strlen (ani_info->inam) > 0)
|
||||||
|
{
|
||||||
|
str = g_strdup_printf ("%s", ani_info->inam);
|
||||||
|
parasite = gimp_parasite_new ("ani-info-inam",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (ani_info->inam) + 1, (gpointer) str);
|
||||||
|
g_free (str);
|
||||||
|
gimp_image_attach_parasite (image, parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
if (ani_info->iart && strlen (ani_info->iart) > 0)
|
||||||
|
{
|
||||||
|
str = g_strdup_printf ("%s", ani_info->iart);
|
||||||
|
parasite = gimp_parasite_new ("ani-info-iart",
|
||||||
|
GIMP_PARASITE_PERSISTENT,
|
||||||
|
strlen (ani_info->iart) + 1, (gpointer) str);
|
||||||
|
g_free (str);
|
||||||
|
gimp_image_attach_parasite (image, parasite);
|
||||||
|
gimp_parasite_free (parasite);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_progress_update (1.0);
|
||||||
|
|
||||||
|
return GIMP_PDB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
GimpPDBStatusType
|
||||||
|
shared_save_image (GFile *file,
|
||||||
|
FILE *fp_ani,
|
||||||
|
GimpImage *image,
|
||||||
|
gint32 run_mode,
|
||||||
|
gint *n_hot_spot_x,
|
||||||
|
gint32 **hot_spot_x,
|
||||||
|
gint *n_hot_spot_y,
|
||||||
|
gint32 **hot_spot_y,
|
||||||
|
gint32 file_offset,
|
||||||
|
gint icon_index,
|
||||||
|
GError **error,
|
||||||
|
IcoSaveInfo *info)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
GList *iter;
|
||||||
|
gint width;
|
||||||
|
gint height;
|
||||||
|
IcoFileHeader header;
|
||||||
|
IcoFileEntry *entries;
|
||||||
|
gboolean saved;
|
||||||
|
gint i;
|
||||||
|
gint num_icons;
|
||||||
|
GimpParasite *parasite = NULL;
|
||||||
|
gchar *str;
|
||||||
|
|
||||||
|
if (! fp_ani &&
|
||||||
|
! ico_save_init (image, run_mode, info,
|
||||||
|
n_hot_spot_x ? *n_hot_spot_x : 0,
|
||||||
|
hot_spot_x ? *hot_spot_x : NULL,
|
||||||
|
n_hot_spot_y ? *n_hot_spot_y : 0,
|
||||||
|
hot_spot_y ? *hot_spot_y : NULL,
|
||||||
|
error))
|
||||||
|
{
|
||||||
|
return GIMP_PDB_EXECUTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (run_mode == GIMP_RUN_INTERACTIVE && ! fp_ani)
|
||||||
|
{
|
||||||
|
/* Allow user to override default values */
|
||||||
|
if ( !ico_save_dialog (image, info,
|
||||||
|
NULL, NULL))
|
||||||
|
return GIMP_PDB_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_icons = (fp_ani) ? 1 : info->num_icons;
|
||||||
|
|
||||||
|
if (! fp_ani)
|
||||||
|
gimp_progress_init_printf (_("Exporting '%s'"),
|
||||||
|
gimp_file_get_utf8_name (file));
|
||||||
|
|
||||||
|
/* If saving an .ani file, we append the next icon frame. */
|
||||||
|
if (! fp_ani)
|
||||||
|
{
|
||||||
|
fp = g_fopen (g_file_peek_path (file), "wb");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fp = fp_ani;
|
||||||
|
}
|
||||||
|
|
||||||
if (! fp)
|
if (! fp)
|
||||||
{
|
{
|
||||||
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||||
|
@ -1258,7 +1542,7 @@ shared_save_image (GFile *file,
|
||||||
header.resource_type = 1;
|
header.resource_type = 1;
|
||||||
if (info->is_cursor)
|
if (info->is_cursor)
|
||||||
header.resource_type = 2;
|
header.resource_type = 2;
|
||||||
header.icon_count = info->num_icons;
|
header.icon_count = num_icons;
|
||||||
if (! ico_write_int16 (fp, &header.reserved, 1) ||
|
if (! ico_write_int16 (fp, &header.reserved, 1) ||
|
||||||
! ico_write_int16 (fp, &header.resource_type, 1) ||
|
! ico_write_int16 (fp, &header.resource_type, 1) ||
|
||||||
! ico_write_int16 (fp, &header.icon_count, 1))
|
! ico_write_int16 (fp, &header.icon_count, 1))
|
||||||
|
@ -1268,8 +1552,8 @@ shared_save_image (GFile *file,
|
||||||
return GIMP_PDB_EXECUTION_ERROR;
|
return GIMP_PDB_EXECUTION_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
entries = g_new0 (IcoFileEntry, info->num_icons);
|
entries = g_new0 (IcoFileEntry, num_icons);
|
||||||
if (fwrite (entries, sizeof (IcoFileEntry), info->num_icons, fp) <= 0)
|
if (fwrite (entries, sizeof (IcoFileEntry), num_icons, fp) <= 0)
|
||||||
{
|
{
|
||||||
ico_save_info_free (info);
|
ico_save_info_free (info);
|
||||||
g_free (entries);
|
g_free (entries);
|
||||||
|
@ -1281,8 +1565,13 @@ shared_save_image (GFile *file,
|
||||||
iter;
|
iter;
|
||||||
iter = g_list_next (iter), i++)
|
iter = g_list_next (iter), i++)
|
||||||
{
|
{
|
||||||
|
if (! fp_ani)
|
||||||
gimp_progress_update ((gdouble)i / (gdouble)info->num_icons);
|
gimp_progress_update ((gdouble)i / (gdouble)info->num_icons);
|
||||||
|
|
||||||
|
/* If saving .ani file, jump to the correct frame */
|
||||||
|
if (fp_ani)
|
||||||
|
iter = g_list_nth (info->layers, icon_index);
|
||||||
|
|
||||||
width = gimp_drawable_get_width (iter->data);
|
width = gimp_drawable_get_width (iter->data);
|
||||||
height = gimp_drawable_get_height (iter->data);
|
height = gimp_drawable_get_height (iter->data);
|
||||||
if (width <= 255 && height <= 255)
|
if (width <= 255 && height <= 255)
|
||||||
|
@ -1305,10 +1594,12 @@ shared_save_image (GFile *file,
|
||||||
/* .cur file reuses these fields for cursor offsets */
|
/* .cur file reuses these fields for cursor offsets */
|
||||||
if (info->is_cursor)
|
if (info->is_cursor)
|
||||||
{
|
{
|
||||||
entries[i].planes = info->hot_spot_x[i];
|
gint hot_spot_index = icon_index ? icon_index : i;
|
||||||
entries[i].bpp = info->hot_spot_y[i];
|
|
||||||
|
entries[i].planes = info->hot_spot_x[hot_spot_index];
|
||||||
|
entries[i].bpp = info->hot_spot_y[hot_spot_index];
|
||||||
}
|
}
|
||||||
entries[i].offset = ftell (fp);
|
entries[i].offset = ftell (fp) - file_offset;
|
||||||
|
|
||||||
if (info->compress[i])
|
if (info->compress[i])
|
||||||
saved = ico_write_png (fp, iter->data, info->depths[i]);
|
saved = ico_write_png (fp, iter->data, info->depths[i]);
|
||||||
|
@ -1322,10 +1613,13 @@ shared_save_image (GFile *file,
|
||||||
return GIMP_PDB_EXECUTION_ERROR;
|
return GIMP_PDB_EXECUTION_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
entries[i].size = ftell (fp) - entries[i].offset;
|
entries[i].size = ftell (fp) - file_offset - entries[i].offset;
|
||||||
|
|
||||||
|
if (fp_ani)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < info->num_icons; i++)
|
for (i = 0; i < num_icons; i++)
|
||||||
{
|
{
|
||||||
entries[i].planes = GUINT16_TO_LE (entries[i].planes);
|
entries[i].planes = GUINT16_TO_LE (entries[i].planes);
|
||||||
entries[i].bpp = GUINT16_TO_LE (entries[i].bpp);
|
entries[i].bpp = GUINT16_TO_LE (entries[i].bpp);
|
||||||
|
@ -1333,14 +1627,15 @@ shared_save_image (GFile *file,
|
||||||
entries[i].offset = GUINT32_TO_LE (entries[i].offset);
|
entries[i].offset = GUINT32_TO_LE (entries[i].offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fseek (fp, sizeof(IcoFileHeader), SEEK_SET) < 0
|
if (fseek (fp, sizeof (IcoFileHeader) + file_offset, SEEK_SET) < 0 ||
|
||||||
|| fwrite (entries, sizeof (IcoFileEntry), info->num_icons, fp) <= 0)
|
fwrite (entries, sizeof (IcoFileEntry), num_icons, fp) <= 0)
|
||||||
{
|
{
|
||||||
ico_save_info_free (info);
|
ico_save_info_free (info);
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
return GIMP_PDB_EXECUTION_ERROR;
|
return GIMP_PDB_EXECUTION_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! fp_ani)
|
||||||
gimp_progress_update (1.0);
|
gimp_progress_update (1.0);
|
||||||
|
|
||||||
/* Updating parasite hot spots if needed */
|
/* Updating parasite hot spots if needed */
|
||||||
|
@ -1360,6 +1655,8 @@ shared_save_image (GFile *file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! fp_ani)
|
||||||
|
{
|
||||||
if (hot_spot_x)
|
if (hot_spot_x)
|
||||||
{
|
{
|
||||||
*hot_spot_x = info->hot_spot_x;
|
*hot_spot_x = info->hot_spot_x;
|
||||||
|
@ -1371,12 +1668,19 @@ shared_save_image (GFile *file,
|
||||||
info->hot_spot_y = NULL;
|
info->hot_spot_y = NULL;
|
||||||
}
|
}
|
||||||
if (n_hot_spot_x)
|
if (n_hot_spot_x)
|
||||||
*n_hot_spot_x = info->num_icons;
|
*n_hot_spot_x = num_icons;
|
||||||
if (n_hot_spot_y)
|
if (n_hot_spot_y)
|
||||||
*n_hot_spot_y = info->num_icons;
|
*n_hot_spot_y = num_icons;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If saving .ani file, don't clear until
|
||||||
|
* all icons are saved in ani_save_image ()
|
||||||
|
*/
|
||||||
|
if (! file_offset)
|
||||||
|
{
|
||||||
ico_save_info_free (info);
|
ico_save_info_free (info);
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
|
}
|
||||||
g_free (entries);
|
g_free (entries);
|
||||||
|
|
||||||
return GIMP_PDB_SUCCESS;
|
return GIMP_PDB_SUCCESS;
|
||||||
|
|
|
@ -36,6 +36,17 @@ GimpPDBStatusType cur_save_image (GFile *file,
|
||||||
gint32 **hot_spot_y,
|
gint32 **hot_spot_y,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
GimpPDBStatusType ani_save_image (GFile *file,
|
||||||
|
GimpImage *image,
|
||||||
|
gint32 run_mode,
|
||||||
|
gint *n_hot_spot_x,
|
||||||
|
gint32 **hot_spot_x,
|
||||||
|
gint *n_hot_spot_y,
|
||||||
|
gint32 **hot_spot_y,
|
||||||
|
AniFileHeader *header,
|
||||||
|
AniSaveInfo *ani_info,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean ico_cmap_contains_black (const guchar *cmap,
|
gboolean ico_cmap_contains_black (const guchar *cmap,
|
||||||
gint num_colors);
|
gint num_colors);
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,11 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
#include <libgimp/gimp.h>
|
#include <libgimp/gimp.h>
|
||||||
#include <libgimp/gimpui.h>
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
@ -35,9 +38,12 @@
|
||||||
|
|
||||||
#define LOAD_PROC "file-ico-load"
|
#define LOAD_PROC "file-ico-load"
|
||||||
#define LOAD_CUR_PROC "file-cur-load"
|
#define LOAD_CUR_PROC "file-cur-load"
|
||||||
|
#define LOAD_ANI_PROC "file-ani-load"
|
||||||
#define LOAD_THUMB_PROC "file-ico-load-thumb"
|
#define LOAD_THUMB_PROC "file-ico-load-thumb"
|
||||||
|
#define LOAD_ANI_THUMB_PROC "file-ani-load-thumb"
|
||||||
#define SAVE_PROC "file-ico-save"
|
#define SAVE_PROC "file-ico-save"
|
||||||
#define SAVE_CUR_PROC "file-cur-save"
|
#define SAVE_CUR_PROC "file-cur-save"
|
||||||
|
#define SAVE_ANI_PROC "file-ani-save"
|
||||||
|
|
||||||
|
|
||||||
typedef struct _Ico Ico;
|
typedef struct _Ico Ico;
|
||||||
|
@ -68,11 +74,21 @@ static GimpValueArray * ico_load (GimpProcedure *procedure,
|
||||||
GFile *file,
|
GFile *file,
|
||||||
const GimpValueArray *args,
|
const GimpValueArray *args,
|
||||||
gpointer run_data);
|
gpointer run_data);
|
||||||
|
static GimpValueArray * ani_load (GimpProcedure *procedure,
|
||||||
|
GimpRunMode run_mode,
|
||||||
|
GFile *file,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
gpointer run_data);
|
||||||
static GimpValueArray * ico_load_thumb (GimpProcedure *procedure,
|
static GimpValueArray * ico_load_thumb (GimpProcedure *procedure,
|
||||||
GFile *file,
|
GFile *file,
|
||||||
gint size,
|
gint size,
|
||||||
const GimpValueArray *args,
|
const GimpValueArray *args,
|
||||||
gpointer run_data);
|
gpointer run_data);
|
||||||
|
static GimpValueArray * ani_load_thumb (GimpProcedure *procedure,
|
||||||
|
GFile *file,
|
||||||
|
gint size,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
gpointer run_data);
|
||||||
static GimpValueArray * ico_save (GimpProcedure *procedure,
|
static GimpValueArray * ico_save (GimpProcedure *procedure,
|
||||||
GimpRunMode run_mode,
|
GimpRunMode run_mode,
|
||||||
GimpImage *image,
|
GimpImage *image,
|
||||||
|
@ -89,6 +105,14 @@ static GimpValueArray * cur_save (GimpProcedure *procedure,
|
||||||
GFile *file,
|
GFile *file,
|
||||||
const GimpValueArray *args,
|
const GimpValueArray *args,
|
||||||
gpointer run_data);
|
gpointer run_data);
|
||||||
|
static GimpValueArray * ani_save (GimpProcedure *procedure,
|
||||||
|
GimpRunMode run_mode,
|
||||||
|
GimpImage *image,
|
||||||
|
gint n_drawables,
|
||||||
|
GimpDrawable **drawables,
|
||||||
|
GFile *file,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
gpointer run_data);
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (Ico, ico, GIMP_TYPE_PLUG_IN)
|
G_DEFINE_TYPE (Ico, ico, GIMP_TYPE_PLUG_IN)
|
||||||
|
@ -118,10 +142,13 @@ ico_query_procedures (GimpPlugIn *plug_in)
|
||||||
GList *list = NULL;
|
GList *list = NULL;
|
||||||
|
|
||||||
list = g_list_append (list, g_strdup (LOAD_THUMB_PROC));
|
list = g_list_append (list, g_strdup (LOAD_THUMB_PROC));
|
||||||
|
list = g_list_append (list, g_strdup (LOAD_ANI_THUMB_PROC));
|
||||||
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 (LOAD_CUR_PROC));
|
list = g_list_append (list, g_strdup (LOAD_CUR_PROC));
|
||||||
|
list = g_list_append (list, g_strdup (LOAD_ANI_PROC));
|
||||||
list = g_list_append (list, g_strdup (SAVE_PROC));
|
list = g_list_append (list, g_strdup (SAVE_PROC));
|
||||||
list = g_list_append (list, g_strdup (SAVE_CUR_PROC));
|
list = g_list_append (list, g_strdup (SAVE_CUR_PROC));
|
||||||
|
list = g_list_append (list, g_strdup (SAVE_ANI_PROC));
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -190,6 +217,36 @@ ico_create_procedure (GimpPlugIn *plug_in,
|
||||||
gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
|
gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
|
||||||
LOAD_THUMB_PROC);
|
LOAD_THUMB_PROC);
|
||||||
}
|
}
|
||||||
|
else if (! strcmp (name, LOAD_ANI_PROC))
|
||||||
|
{
|
||||||
|
procedure = gimp_load_procedure_new (plug_in, name,
|
||||||
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
||||||
|
ani_load, NULL, NULL);
|
||||||
|
|
||||||
|
gimp_procedure_set_menu_label (procedure, _("Microsoft Windows animated cursor"));
|
||||||
|
gimp_procedure_set_icon_name (procedure, GIMP_ICON_BRUSH);
|
||||||
|
|
||||||
|
gimp_procedure_set_documentation (procedure,
|
||||||
|
_("Loads files of Windows ANI file format"),
|
||||||
|
"Loads files of Windows ANI file format",
|
||||||
|
name);
|
||||||
|
gimp_procedure_set_attribution (procedure,
|
||||||
|
"Christian Kreibich <christian@whoop.org>, "
|
||||||
|
"James Huang, Alex S.",
|
||||||
|
"Christian Kreibich <christian@whoop.org>, "
|
||||||
|
"James Huang, Alex S.",
|
||||||
|
"2007-2022");
|
||||||
|
|
||||||
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
||||||
|
"application/x-navi-animation");
|
||||||
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
||||||
|
"ani");
|
||||||
|
gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
|
||||||
|
"0,string,RIFF");
|
||||||
|
|
||||||
|
gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
|
||||||
|
LOAD_ANI_THUMB_PROC);
|
||||||
|
}
|
||||||
else if (! strcmp (name, LOAD_THUMB_PROC))
|
else if (! strcmp (name, LOAD_THUMB_PROC))
|
||||||
{
|
{
|
||||||
procedure = gimp_thumbnail_procedure_new (plug_in, name,
|
procedure = gimp_thumbnail_procedure_new (plug_in, name,
|
||||||
|
@ -205,6 +262,24 @@ ico_create_procedure (GimpPlugIn *plug_in,
|
||||||
"Sven Neumann <sven@gimp.org>",
|
"Sven Neumann <sven@gimp.org>",
|
||||||
"2005");
|
"2005");
|
||||||
}
|
}
|
||||||
|
else if (! strcmp (name, LOAD_ANI_THUMB_PROC))
|
||||||
|
{
|
||||||
|
procedure = gimp_thumbnail_procedure_new (plug_in, name,
|
||||||
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
||||||
|
ani_load_thumb, NULL, NULL);
|
||||||
|
|
||||||
|
gimp_procedure_set_documentation (procedure,
|
||||||
|
_("Loads a preview from a Windows ANI files"),
|
||||||
|
"",
|
||||||
|
name);
|
||||||
|
gimp_procedure_set_attribution (procedure,
|
||||||
|
"Dom Lachowicz, Sven Neumann, James Huang, "
|
||||||
|
"Alex S.",
|
||||||
|
"Dom Lachowicz, "
|
||||||
|
"Sven Neumann <sven@gimp.org>, "
|
||||||
|
"James Huang, Alex S.",
|
||||||
|
"2007-2022");
|
||||||
|
}
|
||||||
else if (! strcmp (name, SAVE_PROC))
|
else if (! strcmp (name, SAVE_PROC))
|
||||||
{
|
{
|
||||||
procedure = gimp_save_procedure_new (plug_in, name,
|
procedure = gimp_save_procedure_new (plug_in, name,
|
||||||
|
@ -277,6 +352,72 @@ ico_create_procedure (GimpPlugIn *plug_in,
|
||||||
"Y coordinates of hot spot (one per layer)",
|
"Y coordinates of hot spot (one per layer)",
|
||||||
G_PARAM_READWRITE);
|
G_PARAM_READWRITE);
|
||||||
}
|
}
|
||||||
|
else if (! strcmp (name, SAVE_ANI_PROC))
|
||||||
|
{
|
||||||
|
procedure = gimp_save_procedure_new (plug_in, name,
|
||||||
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
||||||
|
ani_save, NULL, NULL);
|
||||||
|
|
||||||
|
gimp_procedure_set_image_types (procedure, "*");
|
||||||
|
|
||||||
|
gimp_procedure_set_menu_label (procedure, _("Microsoft Windows animated cursor"));
|
||||||
|
gimp_procedure_set_icon_name (procedure, GIMP_ICON_BRUSH);
|
||||||
|
|
||||||
|
gimp_procedure_set_documentation (procedure,
|
||||||
|
_("Saves files in Windows ANI file format"),
|
||||||
|
_("Saves files in Windows ANI file format"),
|
||||||
|
name);
|
||||||
|
gimp_procedure_set_attribution (procedure,
|
||||||
|
"Christian Kreibich <christian@whoop.org>, "
|
||||||
|
"James Huang, Alex S.",
|
||||||
|
"Christian Kreibich <christian@whoop.org>, "
|
||||||
|
"James Huang, Alex S.",
|
||||||
|
"2007-2022");
|
||||||
|
|
||||||
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
||||||
|
"application/x-navi-animation");
|
||||||
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
||||||
|
"ani");
|
||||||
|
|
||||||
|
GIMP_PROC_ARG_STRING (procedure, "cursor-name",
|
||||||
|
"Cursor Name",
|
||||||
|
_("Cursor Name (Optional)"),
|
||||||
|
NULL,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
GIMP_PROC_ARG_STRING (procedure, "author-name",
|
||||||
|
"Cursor Author",
|
||||||
|
_("Cursor Author (Optional)"),
|
||||||
|
NULL,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
GIMP_PROC_ARG_INT (procedure, "default-delay",
|
||||||
|
"Default delay",
|
||||||
|
"Default delay between frames "
|
||||||
|
"in jiffies (1/60 of a second)",
|
||||||
|
0, G_MAXINT, 8,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
GIMP_PROC_ARG_INT (procedure, "n-hot-spot-x",
|
||||||
|
"Number of hot spot's X coordinates",
|
||||||
|
"Number of hot spot's X coordinates",
|
||||||
|
0, G_MAXINT, 0,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
GIMP_PROC_ARG_INT32_ARRAY (procedure, "hot-spot-x",
|
||||||
|
"Hot spot X",
|
||||||
|
"X coordinates of hot spot (one per layer)",
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
GIMP_PROC_ARG_INT (procedure, "n-hot-spot-y",
|
||||||
|
"Number of hot spot's Y coordinates",
|
||||||
|
"Number of hot spot's Y coordinates",
|
||||||
|
0, G_MAXINT, 0,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
GIMP_PROC_ARG_INT32_ARRAY (procedure, "hot-spot-y",
|
||||||
|
"Hot spot Y",
|
||||||
|
"Y coordinates of hot spot (one per layer)",
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
return procedure;
|
return procedure;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +435,37 @@ ico_load (GimpProcedure *procedure,
|
||||||
|
|
||||||
gegl_init (NULL, NULL);
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
image = ico_load_image (file, &error);
|
image = ico_load_image (file, NULL, &error);
|
||||||
|
|
||||||
|
if (! image)
|
||||||
|
return gimp_procedure_new_return_values (procedure,
|
||||||
|
GIMP_PDB_EXECUTION_ERROR,
|
||||||
|
error);
|
||||||
|
|
||||||
|
return_vals = gimp_procedure_new_return_values (procedure,
|
||||||
|
GIMP_PDB_SUCCESS,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
||||||
|
|
||||||
|
return return_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
ani_load (GimpProcedure *procedure,
|
||||||
|
GimpRunMode run_mode,
|
||||||
|
GFile *file,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
gpointer run_data)
|
||||||
|
{
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
GimpImage *image;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
|
image = ani_load_image (file, FALSE,
|
||||||
|
NULL, NULL, &error);
|
||||||
|
|
||||||
if (! image)
|
if (! image)
|
||||||
return gimp_procedure_new_return_values (procedure,
|
return gimp_procedure_new_return_values (procedure,
|
||||||
|
@ -329,6 +500,45 @@ ico_load_thumb (GimpProcedure *procedure,
|
||||||
height = size;
|
height = size;
|
||||||
|
|
||||||
image = ico_load_thumbnail_image (file,
|
image = ico_load_thumbnail_image (file,
|
||||||
|
&width, &height, 0, &error);
|
||||||
|
|
||||||
|
if (image)
|
||||||
|
return gimp_procedure_new_return_values (procedure,
|
||||||
|
GIMP_PDB_EXECUTION_ERROR,
|
||||||
|
error);
|
||||||
|
|
||||||
|
return_vals = gimp_procedure_new_return_values (procedure,
|
||||||
|
GIMP_PDB_SUCCESS,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
||||||
|
GIMP_VALUES_SET_INT (return_vals, 2, width);
|
||||||
|
GIMP_VALUES_SET_INT (return_vals, 3, height);
|
||||||
|
|
||||||
|
gimp_value_array_truncate (return_vals, 4);
|
||||||
|
|
||||||
|
return return_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
ani_load_thumb (GimpProcedure *procedure,
|
||||||
|
GFile *file,
|
||||||
|
gint size,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
gpointer run_data)
|
||||||
|
{
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
gint width;
|
||||||
|
gint height;
|
||||||
|
GimpImage *image;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
|
width = size;
|
||||||
|
height = size;
|
||||||
|
|
||||||
|
image = ani_load_image (file, TRUE,
|
||||||
&width, &height, &error);
|
&width, &height, &error);
|
||||||
|
|
||||||
if (image)
|
if (image)
|
||||||
|
@ -426,6 +636,85 @@ cur_save (GimpProcedure *procedure,
|
||||||
return gimp_procedure_new_return_values (procedure, status, error);
|
return gimp_procedure_new_return_values (procedure, status, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
ani_save (GimpProcedure *procedure,
|
||||||
|
GimpRunMode run_mode,
|
||||||
|
GimpImage *image,
|
||||||
|
gint n_drawables,
|
||||||
|
GimpDrawable **drawables,
|
||||||
|
GFile *file,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
gpointer run_data)
|
||||||
|
{
|
||||||
|
GimpProcedureConfig *config;
|
||||||
|
GimpPDBStatusType status;
|
||||||
|
GError *error = NULL;
|
||||||
|
gchar *inam = NULL;
|
||||||
|
gchar *iart = NULL;
|
||||||
|
gint jif_rate = 0;
|
||||||
|
gint32 *hot_spot_x = NULL;
|
||||||
|
gint32 *hot_spot_y = NULL;
|
||||||
|
gint n_hot_spot_x = 0;
|
||||||
|
gint n_hot_spot_y = 0;
|
||||||
|
AniFileHeader header;
|
||||||
|
AniSaveInfo ani_info;
|
||||||
|
|
||||||
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
|
config = gimp_procedure_create_config (procedure);
|
||||||
|
gimp_procedure_config_begin_run (config, image, run_mode, args);
|
||||||
|
|
||||||
|
g_object_get (config,
|
||||||
|
"cursor-name", &inam,
|
||||||
|
"author-name", &iart,
|
||||||
|
"default-delay", &jif_rate,
|
||||||
|
"n-hot-spot-x", &n_hot_spot_x,
|
||||||
|
"n-hot-spot-y", &n_hot_spot_y,
|
||||||
|
"hot-spot-x", &hot_spot_x,
|
||||||
|
"hot-spot-y", &hot_spot_y,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Jiffies (1/60th of a second) used if rate chunk not present. */
|
||||||
|
header.jif_rate = jif_rate;
|
||||||
|
ani_info.inam = inam;
|
||||||
|
ani_info.iart = iart;
|
||||||
|
|
||||||
|
status = ani_save_image (file, image, run_mode,
|
||||||
|
&n_hot_spot_x, &hot_spot_x,
|
||||||
|
&n_hot_spot_y, &hot_spot_y,
|
||||||
|
&header, &ani_info, &error);
|
||||||
|
|
||||||
|
if (status == GIMP_PDB_SUCCESS)
|
||||||
|
{
|
||||||
|
/* XXX: seems libgimpconfig is not able to serialize
|
||||||
|
* GimpInt32Array args yet anyway. Still leave this here for now,
|
||||||
|
* as reminder of missing feature when we see the warnings.
|
||||||
|
*/
|
||||||
|
g_object_set (config,
|
||||||
|
"cursor-name", NULL,
|
||||||
|
"author-name", NULL,
|
||||||
|
"default-delay", header.jif_rate,
|
||||||
|
"n-hot-spot-x", n_hot_spot_x,
|
||||||
|
"n-hot-spot-y", n_hot_spot_y,
|
||||||
|
/*"hot-spot-x", hot_spot_x,*/
|
||||||
|
/*"hot-spot-y", hot_spot_y,*/
|
||||||
|
NULL);
|
||||||
|
g_free (hot_spot_x);
|
||||||
|
g_free (hot_spot_y);
|
||||||
|
|
||||||
|
g_free (inam);
|
||||||
|
g_free (iart);
|
||||||
|
g_free (ani_info.inam);
|
||||||
|
g_free (ani_info.iart);
|
||||||
|
memset (&ani_info, 0, sizeof (AniSaveInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_procedure_config_end_run (config, status);
|
||||||
|
g_object_unref (config);
|
||||||
|
|
||||||
|
return gimp_procedure_new_return_values (procedure, status, error);
|
||||||
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
ico_rowstride (gint width,
|
ico_rowstride (gint width,
|
||||||
gint bpp)
|
gint bpp)
|
||||||
|
|
|
@ -97,6 +97,22 @@ typedef struct _IcoSaveInfo
|
||||||
gint *hot_spot_y;
|
gint *hot_spot_y;
|
||||||
} IcoSaveInfo;
|
} IcoSaveInfo;
|
||||||
|
|
||||||
|
typedef struct _AniFileHeader
|
||||||
|
{
|
||||||
|
guint32 bSizeOf; /* Number of bytes in AniFileHeader (36 bytes) */
|
||||||
|
guint32 frames; /* Number of unique icons in this cursor */
|
||||||
|
guint32 steps; /* Number of Blits before the animation cycles */
|
||||||
|
guint32 x, y; /* Reserved, must be zero. */
|
||||||
|
guint32 bpp, planes; /* Reserved, must be zero. */
|
||||||
|
guint32 jif_rate; /* Default Jiffies (1/60th of a second) if rate chunk's not present. */
|
||||||
|
guint32 flags; /* Animation Flag */
|
||||||
|
} AniFileHeader;
|
||||||
|
|
||||||
|
typedef struct _AniSaveInfo
|
||||||
|
{
|
||||||
|
gchar *inam; /* Cursor name metadata */
|
||||||
|
gchar *iart; /* Author name metadata */
|
||||||
|
} AniSaveInfo;
|
||||||
|
|
||||||
/* Miscellaneous helper functions below: */
|
/* Miscellaneous helper functions below: */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue