mirror of https://github.com/GNOME/gimp.git
Issue #526 - Add Import/Export for Windows .CUR files
This commit is contained in:
parent
d25b7301d6
commit
a22fd4f43a
|
@ -43,13 +43,16 @@ static void ico_dialog_check_compat (GtkWidget *dialog,
|
|||
GtkWidget *
|
||||
ico_dialog_new (IcoSaveInfo *info)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *main_vbox;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *viewport;
|
||||
GtkWidget *warning;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *main_vbox;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *viewport;
|
||||
GtkWidget *grid;
|
||||
GtkAdjustment *adj;
|
||||
GtkWidget *spinbutton;
|
||||
GtkWidget *warning;
|
||||
|
||||
dialog = gimp_export_dialog_new (_("Windows Icon"),
|
||||
PLUG_IN_BINARY,
|
||||
|
@ -65,14 +68,55 @@ ico_dialog_new (IcoSaveInfo *info)
|
|||
|
||||
g_object_set_data (G_OBJECT (dialog), "save_info", info);
|
||||
|
||||
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
|
||||
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
|
||||
gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
|
||||
main_vbox, TRUE, TRUE, 0);
|
||||
gtk_widget_show (main_vbox);
|
||||
|
||||
/* Cursor */
|
||||
if (info->is_cursor)
|
||||
{
|
||||
frame = gimp_frame_new (_("Cursor Hot spot"));
|
||||
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 4);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
gtk_container_add (GTK_CONTAINER (frame), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
adj = (GtkAdjustment *)
|
||||
gtk_adjustment_new (info->hot_spot_x, 0,
|
||||
G_MAXUINT16, 1, 10, 0);
|
||||
spinbutton = gimp_spin_button_new (adj, 1.0, 0);
|
||||
gtk_spin_button_set_range (GTK_SPIN_BUTTON (spinbutton),
|
||||
0, G_MAXUINT16);
|
||||
gimp_grid_attach_aligned (GTK_GRID (grid), 0, 0,
|
||||
_("Hot spot _X:"), 0.0, 0.5,
|
||||
spinbutton, 1);
|
||||
g_signal_connect (adj, "value-changed",
|
||||
G_CALLBACK (gimp_int_adjustment_update),
|
||||
&info->hot_spot_x);
|
||||
|
||||
adj = (GtkAdjustment *)
|
||||
gtk_adjustment_new (info->hot_spot_y, 0,
|
||||
G_MAXUINT16, 1, 10, 0);
|
||||
spinbutton = gimp_spin_button_new (adj, 1.0, 0);
|
||||
gtk_spin_button_set_range (GTK_SPIN_BUTTON (spinbutton),
|
||||
0, G_MAXUINT16);
|
||||
gimp_grid_attach_aligned (GTK_GRID (grid), 0, 1,
|
||||
_("Hot spot _Y:"), 0.0, 0.5,
|
||||
spinbutton, 1);
|
||||
g_signal_connect (adj, "value-changed",
|
||||
G_CALLBACK (gimp_int_adjustment_update),
|
||||
&info->hot_spot_y);
|
||||
}
|
||||
|
||||
/* Cursor */
|
||||
frame = gimp_frame_new (_("Icon Details"));
|
||||
gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
|
||||
gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 4);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
||||
|
@ -98,7 +142,7 @@ ico_dialog_new (IcoSaveInfo *info)
|
|||
"by all programs. Older applications may not "
|
||||
"open this file correctly."),
|
||||
NULL);
|
||||
gtk_box_pack_end (GTK_BOX (main_vbox), warning, FALSE, FALSE, 0);
|
||||
gtk_box_pack_end (GTK_BOX (main_vbox), warning, FALSE, FALSE, 12);
|
||||
/* don't show the warning here */
|
||||
|
||||
g_object_set_data (G_OBJECT (dialog), "warning", warning);
|
||||
|
|
|
@ -120,7 +120,7 @@ ico_read_int8 (FILE *fp,
|
|||
}
|
||||
|
||||
|
||||
static guint32
|
||||
static IcoFileHeader
|
||||
ico_read_init (FILE *fp)
|
||||
{
|
||||
IcoFileHeader header;
|
||||
|
@ -130,12 +130,13 @@ ico_read_init (FILE *fp)
|
|||
! ico_read_int16 (fp, &header.resource_type, 1) ||
|
||||
! ico_read_int16 (fp, &header.icon_count, 1) ||
|
||||
header.reserved != 0 ||
|
||||
header.resource_type != 1)
|
||||
(header.resource_type != 1 && header.resource_type != 2))
|
||||
{
|
||||
return 0;
|
||||
header.icon_count = 0;
|
||||
return header;
|
||||
}
|
||||
|
||||
return header.icon_count;
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
|
@ -229,6 +230,7 @@ ico_read_info (FILE *fp,
|
|||
{
|
||||
info[i].width = entries[i].width;
|
||||
info[i].height = entries[i].height;
|
||||
info[i].planes = entries[i].planes;
|
||||
info[i].bpp = GUINT16_FROM_LE (entries[i].bpp);
|
||||
info[i].size = GUINT32_FROM_LE (entries[i].size);
|
||||
info[i].offset = GUINT32_FROM_LE (entries[i].offset);
|
||||
|
@ -653,14 +655,17 @@ GimpImage *
|
|||
ico_load_image (GFile *file,
|
||||
GError **error)
|
||||
{
|
||||
FILE *fp;
|
||||
IcoLoadInfo *info;
|
||||
gint max_width, max_height;
|
||||
gint i;
|
||||
GimpImage *image;
|
||||
guchar *buf;
|
||||
guint icon_count;
|
||||
gint maxsize;
|
||||
FILE *fp;
|
||||
IcoFileHeader header;
|
||||
IcoLoadInfo *info;
|
||||
gint max_width, max_height;
|
||||
gint i;
|
||||
GimpImage *image;
|
||||
guchar *buf;
|
||||
guint icon_count;
|
||||
gint maxsize;
|
||||
GimpParasite *parasite;
|
||||
gchar *str;
|
||||
|
||||
gimp_progress_init_printf (_("Opening '%s'"),
|
||||
gimp_file_get_utf8_name (file));
|
||||
|
@ -675,7 +680,8 @@ ico_load_image (GFile *file,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
icon_count = ico_read_init (fp);
|
||||
header = ico_read_init (fp);
|
||||
icon_count = header.icon_count;
|
||||
if (!icon_count)
|
||||
{
|
||||
fclose (fp);
|
||||
|
@ -710,6 +716,18 @@ ico_load_image (GFile *file,
|
|||
image = gimp_image_new (max_width, max_height, GIMP_RGB);
|
||||
gimp_image_set_file (image, file);
|
||||
|
||||
/* Save CUR hot spot information */
|
||||
if (header.resource_type == 2)
|
||||
{
|
||||
str = g_strdup_printf ("%d %d", info[0].planes, info[0].bpp);
|
||||
parasite = gimp_parasite_new ("cur-hot-spot",
|
||||
GIMP_PARASITE_PERSISTENT,
|
||||
strlen (str) + 1, (gpointer) str);
|
||||
g_free (str);
|
||||
gimp_image_attach_parasite (image, parasite);
|
||||
gimp_parasite_free (parasite);
|
||||
}
|
||||
|
||||
maxsize = max_width * max_height * 4;
|
||||
buf = g_new (guchar, max_width * max_height * 4);
|
||||
for (i = 0; i < icon_count; i++)
|
||||
|
@ -731,15 +749,16 @@ ico_load_thumbnail_image (GFile *file,
|
|||
gint *height,
|
||||
GError **error)
|
||||
{
|
||||
FILE *fp;
|
||||
IcoLoadInfo *info;
|
||||
GimpImage *image;
|
||||
gint w = 0;
|
||||
gint h = 0;
|
||||
gint bpp = 0;
|
||||
gint match = 0;
|
||||
gint i, icon_count;
|
||||
guchar *buf;
|
||||
FILE *fp;
|
||||
IcoLoadInfo *info;
|
||||
IcoFileHeader header;
|
||||
GimpImage *image;
|
||||
gint w = 0;
|
||||
gint h = 0;
|
||||
gint bpp = 0;
|
||||
gint match = 0;
|
||||
gint i, icon_count;
|
||||
guchar *buf;
|
||||
|
||||
gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
|
||||
gimp_file_get_utf8_name (file));
|
||||
|
@ -754,7 +773,8 @@ ico_load_thumbnail_image (GFile *file,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
icon_count = ico_read_init (fp);
|
||||
header = ico_read_init (fp);
|
||||
icon_count = header.icon_count;
|
||||
if (! icon_count)
|
||||
{
|
||||
fclose (fp);
|
||||
|
|
|
@ -233,13 +233,36 @@ static gboolean
|
|||
ico_save_dialog (GimpImage *image,
|
||||
IcoSaveInfo *info)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GList *iter;
|
||||
gint i;
|
||||
gint response;
|
||||
GtkWidget *dialog;
|
||||
GList *iter;
|
||||
gint i;
|
||||
gint response;
|
||||
GimpParasite *parasite = NULL;
|
||||
|
||||
gimp_ui_init (PLUG_IN_BINARY);
|
||||
|
||||
/* Loading hot spots for cursors if applicable */
|
||||
parasite = gimp_image_get_parasite (image, "cur-hot-spot");
|
||||
|
||||
if (parasite)
|
||||
{
|
||||
gchar *parasite_data;
|
||||
guint32 parasite_size;
|
||||
gint x, y;
|
||||
|
||||
parasite_data = (gchar *) gimp_parasite_get_data (parasite, ¶site_size);
|
||||
parasite_data = g_strndup (parasite_data, parasite_size);
|
||||
|
||||
if (sscanf (parasite_data, "%i %i", &x, &y) == 2)
|
||||
{
|
||||
info->hot_spot_x = x;
|
||||
info->hot_spot_y = y;
|
||||
}
|
||||
|
||||
gimp_parasite_free (parasite);
|
||||
g_free (parasite_data);
|
||||
}
|
||||
|
||||
dialog = ico_dialog_new (info);
|
||||
for (iter = info->layers, i = 0;
|
||||
iter;
|
||||
|
@ -1066,25 +1089,60 @@ ico_save_image (GFile *file,
|
|||
gint32 run_mode,
|
||||
GError **error)
|
||||
{
|
||||
FILE *fp;
|
||||
GList *iter;
|
||||
gint width;
|
||||
gint height;
|
||||
IcoSaveInfo info;
|
||||
IcoFileHeader header;
|
||||
IcoFileEntry *entries;
|
||||
gboolean saved;
|
||||
gint i;
|
||||
|
||||
D(("*** Exporting Microsoft icon file %s\n",
|
||||
gimp_file_get_utf8_name (file)));
|
||||
|
||||
ico_save_init (image, &info);
|
||||
info.is_cursor = FALSE;
|
||||
|
||||
return shared_save_image (file, image, run_mode, error, &info);
|
||||
}
|
||||
|
||||
GimpPDBStatusType
|
||||
cur_save_image (GFile *file,
|
||||
GimpImage *image,
|
||||
gint32 run_mode,
|
||||
gint32 hot_spot_x,
|
||||
gint32 hot_spot_y,
|
||||
GError **error)
|
||||
{
|
||||
IcoSaveInfo info;
|
||||
|
||||
D(("*** Exporting Microsoft cursor file %s\n",
|
||||
gimp_file_get_utf8_name (file)));
|
||||
|
||||
info.is_cursor = TRUE;
|
||||
info.hot_spot_x = hot_spot_x;
|
||||
info.hot_spot_y = hot_spot_y;
|
||||
|
||||
return shared_save_image (file, image, run_mode, error, &info);
|
||||
}
|
||||
|
||||
GimpPDBStatusType
|
||||
shared_save_image (GFile *file,
|
||||
GimpImage *image,
|
||||
gint32 run_mode,
|
||||
GError **error,
|
||||
IcoSaveInfo *info)
|
||||
{
|
||||
FILE *fp;
|
||||
GList *iter;
|
||||
gint width;
|
||||
gint height;
|
||||
IcoFileHeader header;
|
||||
IcoFileEntry *entries;
|
||||
gboolean saved;
|
||||
gint i;
|
||||
GimpParasite *parasite = NULL;
|
||||
gchar *str;
|
||||
|
||||
ico_save_init (image, info);
|
||||
|
||||
if (run_mode == GIMP_RUN_INTERACTIVE)
|
||||
{
|
||||
/* Allow user to override default values */
|
||||
if ( !ico_save_dialog (image, &info))
|
||||
if ( !ico_save_dialog (image, info))
|
||||
return GIMP_PDB_CANCEL;
|
||||
}
|
||||
|
||||
|
@ -1103,30 +1161,32 @@ ico_save_image (GFile *file,
|
|||
|
||||
header.reserved = 0;
|
||||
header.resource_type = 1;
|
||||
header.icon_count = info.num_icons;
|
||||
if (info->is_cursor)
|
||||
header.resource_type = 2;
|
||||
header.icon_count = info->num_icons;
|
||||
if (! ico_write_int16 (fp, &header.reserved, 1) ||
|
||||
! ico_write_int16 (fp, &header.resource_type, 1) ||
|
||||
! ico_write_int16 (fp, &header.icon_count, 1))
|
||||
{
|
||||
ico_save_info_free (&info);
|
||||
ico_save_info_free (info);
|
||||
fclose (fp);
|
||||
return GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
entries = g_new0 (IcoFileEntry, info.num_icons);
|
||||
if (fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
|
||||
entries = g_new0 (IcoFileEntry, info->num_icons);
|
||||
if (fwrite (entries, sizeof (IcoFileEntry), info->num_icons, fp) <= 0)
|
||||
{
|
||||
ico_save_info_free (&info);
|
||||
ico_save_info_free (info);
|
||||
g_free (entries);
|
||||
fclose (fp);
|
||||
return GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
for (iter = info.layers, i = 0;
|
||||
for (iter = info->layers, i = 0;
|
||||
iter;
|
||||
iter = g_list_next (iter), i++)
|
||||
{
|
||||
gimp_progress_update ((gdouble)i / (gdouble)info.num_icons);
|
||||
gimp_progress_update ((gdouble)i / (gdouble)info->num_icons);
|
||||
|
||||
width = gimp_drawable_get_width (iter->data);
|
||||
height = gimp_drawable_get_height (iter->data);
|
||||
|
@ -1140,23 +1200,29 @@ ico_save_image (GFile *file,
|
|||
entries[i].width = 0;
|
||||
entries[i].height = 0;
|
||||
}
|
||||
if ( info.depths[i] <= 8 )
|
||||
entries[i].num_colors = 1 << info.depths[i];
|
||||
if (info->depths[i] <= 8 )
|
||||
entries[i].num_colors = 1 << info->depths[i];
|
||||
else
|
||||
entries[i].num_colors = 0;
|
||||
entries[i].reserved = 0;
|
||||
entries[i].planes = 1;
|
||||
entries[i].bpp = info.depths[i];
|
||||
entries[i].bpp = info->depths[i];
|
||||
/* .cur file reuses these fields for cursor offsets */
|
||||
if (info->is_cursor)
|
||||
{
|
||||
entries[i].planes = info->hot_spot_x;
|
||||
entries[i].bpp = info->hot_spot_y;
|
||||
}
|
||||
entries[i].offset = ftell (fp);
|
||||
|
||||
if (info.compress[i])
|
||||
saved = ico_write_png (fp, iter->data, info.depths[i]);
|
||||
if (info->compress[i])
|
||||
saved = ico_write_png (fp, iter->data, info->depths[i]);
|
||||
else
|
||||
saved = ico_write_icon (fp, iter->data, info.depths[i]);
|
||||
saved = ico_write_icon (fp, iter->data, info->depths[i]);
|
||||
|
||||
if (!saved)
|
||||
{
|
||||
ico_save_info_free (&info);
|
||||
ico_save_info_free (info);
|
||||
fclose (fp);
|
||||
return GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
@ -1164,7 +1230,7 @@ ico_save_image (GFile *file,
|
|||
entries[i].size = ftell (fp) - entries[i].offset;
|
||||
}
|
||||
|
||||
for (i = 0; i < info.num_icons; i++)
|
||||
for (i = 0; i < info->num_icons; i++)
|
||||
{
|
||||
entries[i].planes = GUINT16_TO_LE (entries[i].planes);
|
||||
entries[i].bpp = GUINT16_TO_LE (entries[i].bpp);
|
||||
|
@ -1173,16 +1239,28 @@ ico_save_image (GFile *file,
|
|||
}
|
||||
|
||||
if (fseek (fp, sizeof(IcoFileHeader), SEEK_SET) < 0
|
||||
|| fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
|
||||
|| fwrite (entries, sizeof (IcoFileEntry), info->num_icons, fp) <= 0)
|
||||
{
|
||||
ico_save_info_free (&info);
|
||||
ico_save_info_free (info);
|
||||
fclose (fp);
|
||||
return GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
gimp_progress_update (1.0);
|
||||
|
||||
ico_save_info_free (&info);
|
||||
/* Updating parasite hot spots if needed */
|
||||
if (info->is_cursor)
|
||||
{
|
||||
str = g_strdup_printf ("%d %d", info->hot_spot_x, info->hot_spot_y);
|
||||
parasite = gimp_parasite_new ("cur-hot-spot",
|
||||
GIMP_PARASITE_PERSISTENT,
|
||||
strlen (str) + 1, (gpointer) str);
|
||||
g_free (str);
|
||||
gimp_image_attach_parasite (image, parasite);
|
||||
gimp_parasite_free (parasite);
|
||||
}
|
||||
|
||||
ico_save_info_free (info);
|
||||
fclose (fp);
|
||||
g_free (entries);
|
||||
|
||||
|
|
|
@ -27,6 +27,19 @@ GimpPDBStatusType ico_save_image (GFile *file,
|
|||
gint32 run_mode,
|
||||
GError **error);
|
||||
|
||||
GimpPDBStatusType cur_save_image (GFile *file,
|
||||
GimpImage *image,
|
||||
gint32 run_mode,
|
||||
gint32 hot_spot_x,
|
||||
gint32 hot_spot_y,
|
||||
GError **error);
|
||||
|
||||
GimpPDBStatusType shared_save_image (GFile *file,
|
||||
GimpImage *image,
|
||||
gint32 run_mode,
|
||||
GError **error,
|
||||
IcoSaveInfo *info);
|
||||
|
||||
gboolean ico_cmap_contains_black (const guchar *cmap,
|
||||
gint num_colors);
|
||||
|
||||
|
|
|
@ -34,8 +34,10 @@
|
|||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
#define LOAD_PROC "file-ico-load"
|
||||
#define LOAD_CUR_PROC "file-cur-load"
|
||||
#define LOAD_THUMB_PROC "file-ico-load-thumb"
|
||||
#define SAVE_PROC "file-ico-save"
|
||||
#define SAVE_CUR_PROC "file-cur-save"
|
||||
|
||||
|
||||
typedef struct _Ico Ico;
|
||||
|
@ -79,6 +81,14 @@ static GimpValueArray * ico_save (GimpProcedure *procedure,
|
|||
GFile *file,
|
||||
const GimpValueArray *args,
|
||||
gpointer run_data);
|
||||
static GimpValueArray * cur_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)
|
||||
|
@ -107,7 +117,9 @@ ico_query_procedures (GimpPlugIn *plug_in)
|
|||
|
||||
list = g_list_append (list, g_strdup (LOAD_THUMB_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 (SAVE_PROC));
|
||||
list = g_list_append (list, g_strdup (SAVE_CUR_PROC));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
@ -143,6 +155,36 @@ ico_create_procedure (GimpPlugIn *plug_in,
|
|||
gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
|
||||
"0,string,\\000\\001\\000\\000,0,string,\\000\\002\\000\\000");
|
||||
|
||||
gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
|
||||
LOAD_THUMB_PROC);
|
||||
}
|
||||
else if (! strcmp (name, LOAD_CUR_PROC))
|
||||
{
|
||||
procedure = gimp_load_procedure_new (plug_in, name,
|
||||
GIMP_PDB_PROC_TYPE_PLUGIN,
|
||||
ico_load, NULL, NULL);
|
||||
|
||||
gimp_procedure_set_menu_label (procedure, N_("Microsoft Windows cursor"));
|
||||
gimp_procedure_set_icon_name (procedure, GIMP_ICON_BRUSH);
|
||||
|
||||
gimp_procedure_set_documentation (procedure,
|
||||
"Loads files of Windows CUR file format",
|
||||
"Loads files of Windows CUR file format",
|
||||
name);
|
||||
gimp_procedure_set_attribution (procedure,
|
||||
"Christian Kreibich <christian@whoop.org>, "
|
||||
"Nikc M.",
|
||||
"Christian Kreibich <christian@whoop.org>, "
|
||||
"Nikc M.",
|
||||
"2002-2022");
|
||||
|
||||
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
||||
"image/vnd.microsoft.icon");
|
||||
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
||||
"cur");
|
||||
gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
|
||||
"0,string,\\000\\001\\000\\000,0,string,\\000\\002\\000\\000");
|
||||
|
||||
gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
|
||||
LOAD_THUMB_PROC);
|
||||
}
|
||||
|
@ -153,7 +195,7 @@ ico_create_procedure (GimpPlugIn *plug_in,
|
|||
ico_load_thumb, NULL, NULL);
|
||||
|
||||
gimp_procedure_set_documentation (procedure,
|
||||
"Loads a preview from an Windows ICO file",
|
||||
"Loads a preview from a Windows ICO or CUR files",
|
||||
"",
|
||||
name);
|
||||
gimp_procedure_set_attribution (procedure,
|
||||
|
@ -186,6 +228,45 @@ ico_create_procedure (GimpPlugIn *plug_in,
|
|||
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
||||
"ico");
|
||||
}
|
||||
else if (! strcmp (name, SAVE_CUR_PROC))
|
||||
{
|
||||
procedure = gimp_save_procedure_new (plug_in, name,
|
||||
GIMP_PDB_PROC_TYPE_PLUGIN,
|
||||
cur_save, NULL, NULL);
|
||||
|
||||
gimp_procedure_set_image_types (procedure, "*");
|
||||
|
||||
gimp_procedure_set_menu_label (procedure, N_("Microsoft Windows cursor"));
|
||||
gimp_procedure_set_icon_name (procedure, GIMP_ICON_BRUSH);
|
||||
|
||||
gimp_procedure_set_documentation (procedure,
|
||||
"Saves files in Windows CUR file format",
|
||||
"Saves files in Windows CUR file format",
|
||||
name);
|
||||
gimp_procedure_set_attribution (procedure,
|
||||
"Christian Kreibich <christian@whoop.org>, "
|
||||
"Nikc M.",
|
||||
"Christian Kreibich <christian@whoop.org>, "
|
||||
"Nikc M.",
|
||||
"2002-2022");
|
||||
|
||||
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
||||
"image/vnd.microsoft.icon");
|
||||
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
||||
"cur");
|
||||
|
||||
GIMP_PROC_ARG_INT (procedure, "hot-spot-x",
|
||||
"Hot spot X",
|
||||
"X coordinate of hot spot",
|
||||
0, G_MAXUINT16, 0,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
GIMP_PROC_ARG_INT (procedure, "hot-spot-y",
|
||||
"Hot spot Y",
|
||||
"Y coordinate of hot spot",
|
||||
0, G_MAXUINT16, 0,
|
||||
G_PARAM_READWRITE);
|
||||
}
|
||||
|
||||
return procedure;
|
||||
}
|
||||
|
@ -281,6 +362,41 @@ ico_save (GimpProcedure *procedure,
|
|||
return gimp_procedure_new_return_values (procedure, status, error);
|
||||
}
|
||||
|
||||
static GimpValueArray *
|
||||
cur_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;
|
||||
gint hot_spot_x = 0;
|
||||
gint hot_spot_y = 0;
|
||||
|
||||
INIT_I18N ();
|
||||
gegl_init (NULL, NULL);
|
||||
|
||||
config = gimp_procedure_create_config (procedure);
|
||||
gimp_procedure_config_begin_run (config, image, run_mode, args);
|
||||
|
||||
g_object_get (config,
|
||||
"hot-spot-x", &hot_spot_x,
|
||||
"hot-spot-y", &hot_spot_y,
|
||||
NULL);
|
||||
|
||||
status = cur_save_image (file, image, run_mode, hot_spot_x, hot_spot_y, &error);
|
||||
|
||||
gimp_procedure_config_end_run (config, status);
|
||||
g_object_unref (config);
|
||||
|
||||
return gimp_procedure_new_return_values (procedure, status, error);
|
||||
}
|
||||
|
||||
gint
|
||||
ico_rowstride (gint width,
|
||||
gint bpp)
|
||||
|
|
|
@ -80,6 +80,7 @@ typedef struct _IcoLoadInfo
|
|||
guint width;
|
||||
guint height;
|
||||
gint bpp;
|
||||
gint planes;
|
||||
gint offset;
|
||||
gint size;
|
||||
} IcoLoadInfo;
|
||||
|
@ -91,6 +92,9 @@ typedef struct _IcoSaveInfo
|
|||
gboolean *compress;
|
||||
GList *layers;
|
||||
gint num_icons;
|
||||
gboolean is_cursor;
|
||||
gint hot_spot_x;
|
||||
gint hot_spot_y;
|
||||
} IcoSaveInfo;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue