configure.in plug-ins/Makefile.am plug-ins/winicon/Makefile.am
2004-04-15 Sven Neumann <sven@gimp.org> * configure.in * plug-ins/Makefile.am * plug-ins/winicon/Makefile.am * plug-ins/winicon/icodialog.[ch] * plug-ins/winicon/icoload.[ch] * plug-ins/winicon/icosave.[ch] * plug-ins/winicon/main.[ch]: added plug-in to load and save Windows icon files. Plug-in written by Christian Kreibich, port to GIMP-2.0 API by Gregor Riepl, massive code cleanup by me. Fixes bug #139160.
This commit is contained in:
parent
957190d750
commit
48bf883825
15 changed files with 2606 additions and 1 deletions
13
ChangeLog
13
ChangeLog
|
|
@ -1,3 +1,16 @@
|
|||
2004-04-15 Sven Neumann <sven@gimp.org>
|
||||
|
||||
* configure.in
|
||||
* plug-ins/Makefile.am
|
||||
* plug-ins/winicon/Makefile.am
|
||||
* plug-ins/winicon/icodialog.[ch]
|
||||
* plug-ins/winicon/icoload.[ch]
|
||||
* plug-ins/winicon/icosave.[ch]
|
||||
* plug-ins/winicon/main.[ch]: added plug-in to load and save
|
||||
Windows icon files. Plug-in written by Christian Kreibich, port to
|
||||
GIMP-2.0 API by Gregor Riepl, massive code cleanup by me. Fixes
|
||||
bug #139160.
|
||||
|
||||
2004-04-15 Michael Natterer <mitch@gimp.org>
|
||||
|
||||
* app/widgets/gimpdnd.c (gimp_dnd_data_source_add)
|
||||
|
|
|
|||
|
|
@ -1551,6 +1551,7 @@ plug-ins/rcm/Makefile
|
|||
plug-ins/sel2path/Makefile
|
||||
plug-ins/sgi/Makefile
|
||||
plug-ins/twain/Makefile
|
||||
plug-ins/winicon/Makefile
|
||||
plug-ins/winsnap/Makefile
|
||||
modules/Makefile
|
||||
devel-docs/Makefile
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ SUBDIRS = \
|
|||
rcm \
|
||||
sgi \
|
||||
sel2path \
|
||||
winicon \
|
||||
$(win32dirs) \
|
||||
$(xjt) \
|
||||
common
|
||||
|
|
|
|||
6
plug-ins/winicon/.cvsignore
Normal file
6
plug-ins/winicon/.cvsignore
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Makefile.in
|
||||
Makefile
|
||||
.deps
|
||||
_libs
|
||||
.libs
|
||||
winicon
|
||||
44
plug-ins/winicon/Makefile.am
Normal file
44
plug-ins/winicon/Makefile.am
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
|
||||
libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
|
||||
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
|
||||
libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
|
||||
libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
|
||||
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
|
||||
|
||||
if OS_WIN32
|
||||
mwindows = -mwindows
|
||||
endif
|
||||
|
||||
AM_LDFLAGS = $(mwindows)
|
||||
|
||||
libexecdir = $(gimpplugindir)/plug-ins
|
||||
|
||||
libexec_PROGRAMS = winicon
|
||||
|
||||
winicon_SOURCES = \
|
||||
icodialog.c \
|
||||
icodialog.h \
|
||||
icoload.c \
|
||||
icoload.h \
|
||||
icosave.c \
|
||||
icosave.h \
|
||||
main.c \
|
||||
main.h
|
||||
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir) \
|
||||
$(GTK_CFLAGS) \
|
||||
-I$(includedir)
|
||||
|
||||
LDADD = \
|
||||
$(libgimpui) \
|
||||
$(libgimpwidgets) \
|
||||
$(libgimp) \
|
||||
$(libgimpcolor) \
|
||||
$(libgimpmath) \
|
||||
$(libgimpbase) \
|
||||
$(GTK_LIBS) \
|
||||
$(RT_LIBS) \
|
||||
$(INTLLIBS)
|
||||
461
plug-ins/winicon/icodialog.c
Normal file
461
plug-ins/winicon/icodialog.c
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#undef GTK_DISABLE_DEPRECATED
|
||||
#include <gtk/gtkpreview.h>
|
||||
#define GTK_DISABLE_DEPRECATED
|
||||
|
||||
#include <libgimp/gimp.h>
|
||||
#include <libgimp/gimpui.h>
|
||||
|
||||
#define ICO_DBG
|
||||
|
||||
#include "icodialog.h"
|
||||
#include "main.h"
|
||||
|
||||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
|
||||
static GtkWidget *ico_preview_new (gint32 layer);
|
||||
static void ico_fill_preview_with_thumb (GtkWidget *widget,
|
||||
gint32 drawable_ID);
|
||||
static void on_1bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox);
|
||||
static void on_4bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox);
|
||||
static void on_8bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox);
|
||||
static void on_32bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox);
|
||||
|
||||
|
||||
static GtkWidget *
|
||||
ico_preview_new(gint32 layer)
|
||||
{
|
||||
GtkWidget *icon_preview;
|
||||
|
||||
icon_preview = gtk_preview_new (GTK_PREVIEW_COLOR);
|
||||
ico_fill_preview_with_thumb (icon_preview, layer);
|
||||
|
||||
return icon_preview;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_fill_preview_with_thumb (GtkWidget *widget,
|
||||
gint32 drawable_ID)
|
||||
{
|
||||
guchar *drawable_data;
|
||||
gint bpp;
|
||||
gint x,y;
|
||||
gint width;
|
||||
gint height;
|
||||
guchar *src;
|
||||
gdouble r, g, b, a;
|
||||
gdouble c0, c1;
|
||||
guchar *p0, *p1;
|
||||
guchar *even, *odd;
|
||||
|
||||
width = gimp_drawable_width (drawable_ID);
|
||||
height = gimp_drawable_height (drawable_ID);
|
||||
bpp = 0; /* Only returned */
|
||||
|
||||
if (width > 128)
|
||||
width = 128;
|
||||
if (height > 128)
|
||||
height = 128;
|
||||
|
||||
drawable_data =
|
||||
gimp_drawable_get_thumbnail_data (drawable_ID, &width, &height, &bpp);
|
||||
|
||||
if (width < 1 || height < 1)
|
||||
return;
|
||||
|
||||
gtk_preview_size (GTK_PREVIEW (widget), width, height);
|
||||
|
||||
even = g_malloc (width * 3);
|
||||
odd = g_malloc (width * 3);
|
||||
src = drawable_data;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
p0 = even;
|
||||
p1 = odd;
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
if (bpp == 4)
|
||||
{
|
||||
r = ((gdouble) src[x*4 + 0]) / 255.0;
|
||||
g = ((gdouble) src[x*4 + 1]) / 255.0;
|
||||
b = ((gdouble) src[x*4 + 2]) / 255.0;
|
||||
a = ((gdouble) src[x*4 + 3]) / 255.0;
|
||||
}
|
||||
else if (bpp == 3)
|
||||
{
|
||||
r = ((gdouble) src[x*3 + 0]) / 255.0;
|
||||
g = ((gdouble) src[x*3 + 1]) / 255.0;
|
||||
b = ((gdouble) src[x*3 + 2]) / 255.0;
|
||||
a = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = ((gdouble) src[x*bpp + 0]) / 255.0;
|
||||
g = b = r;
|
||||
if (bpp == 2)
|
||||
a = ((gdouble) src[x*2 + 1]) / 255.0;
|
||||
else
|
||||
a = 1.0;
|
||||
}
|
||||
|
||||
if ((x / GIMP_CHECK_SIZE_SM) & 1)
|
||||
{
|
||||
c0 = GIMP_CHECK_LIGHT;
|
||||
c1 = GIMP_CHECK_DARK;
|
||||
}
|
||||
else
|
||||
{
|
||||
c0 = GIMP_CHECK_DARK;
|
||||
c1 = GIMP_CHECK_LIGHT;
|
||||
}
|
||||
|
||||
*p0++ = (c0 + (r - c0) * a) * 255.0;
|
||||
*p0++ = (c0 + (g - c0) * a) * 255.0;
|
||||
*p0++ = (c0 + (b - c0) * a) * 255.0;
|
||||
|
||||
*p1++ = (c1 + (r - c1) * a) * 255.0;
|
||||
*p1++ = (c1 + (g - c1) * a) * 255.0;
|
||||
*p1++ = (c1 + (b - c1) * a) * 255.0;
|
||||
|
||||
}
|
||||
|
||||
if ((y / GIMP_CHECK_SIZE_SM) & 1)
|
||||
gtk_preview_draw_row (GTK_PREVIEW (widget), odd, 0, y, width);
|
||||
else
|
||||
gtk_preview_draw_row (GTK_PREVIEW (widget), even, 0, y, width);
|
||||
|
||||
src += width * bpp;
|
||||
}
|
||||
|
||||
g_free (even);
|
||||
g_free (odd);
|
||||
g_free (drawable_data);
|
||||
}
|
||||
|
||||
|
||||
/* This function creates and returns an hbox for an icon,
|
||||
which then gets added to the dialog's main vbox. */
|
||||
static GtkWidget*
|
||||
ico_create_icon_hbox (GtkWidget *icon_preview,
|
||||
gint32 layer,
|
||||
gint layer_num)
|
||||
{
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *optionmenu;
|
||||
GtkWidget *optionmenu_menu;
|
||||
GtkWidget *menuitem;
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
|
||||
/* To make life easier for the callbacks, we store the
|
||||
layer's ID and stacking number with the hbox. */
|
||||
|
||||
g_object_set_data (G_OBJECT (hbox),
|
||||
"icon_layer", GINT_TO_POINTER (layer));
|
||||
g_object_set_data (G_OBJECT (hbox),
|
||||
"icon_layer_num", GINT_TO_POINTER (layer_num));
|
||||
|
||||
g_object_set_data (G_OBJECT (hbox), "icon_preview", icon_preview);
|
||||
gtk_widget_show (icon_preview);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), icon_preview, TRUE, TRUE, 0);
|
||||
|
||||
optionmenu = gtk_option_menu_new ();
|
||||
g_object_set_data (G_OBJECT (hbox), "icon_optionmenu", optionmenu);
|
||||
gtk_widget_show (optionmenu);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), optionmenu, FALSE, FALSE, 0);
|
||||
optionmenu_menu = gtk_menu_new ();
|
||||
|
||||
menuitem =
|
||||
gtk_menu_item_new_with_label (_("1 bpp, 1-bit alpha, 2-slot palette"));
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (on_1bpp_menu_selected),
|
||||
hbox);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (optionmenu_menu), menuitem);
|
||||
|
||||
menuitem =
|
||||
gtk_menu_item_new_with_label (_("4 bpp, 1-bit alpha, 16-slot palette"));
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (on_4bpp_menu_selected),
|
||||
hbox);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (optionmenu_menu), menuitem);
|
||||
|
||||
menuitem =
|
||||
gtk_menu_item_new_with_label (_("8 bpp, 1-bit alpha, 256-slot palette"));
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (on_8bpp_menu_selected),
|
||||
hbox);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (optionmenu_menu), menuitem);
|
||||
|
||||
menuitem =
|
||||
gtk_menu_item_new_with_label (_("32 bpp, 8-bit alpha, no palette"));
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (on_32bpp_menu_selected),
|
||||
hbox);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (optionmenu_menu), menuitem);
|
||||
|
||||
gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu),
|
||||
optionmenu_menu);
|
||||
gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), 3);
|
||||
|
||||
return hbox;
|
||||
}
|
||||
|
||||
|
||||
GtkWidget*
|
||||
ico_specs_dialog_new (gint num_layers)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *scrolledwindow;
|
||||
GtkWidget *viewport;
|
||||
gint *icon_depths, i;
|
||||
|
||||
dialog = gimp_dialog_new (_("GIMP Windows Icon Plugin"), "winicon",
|
||||
NULL, 0,
|
||||
gimp_standard_help_func, "plug-in-winicon",
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
|
||||
/* We store an array that holds each icon's requested bit depth
|
||||
with the dialog. It's queried when the dialog is closed so the
|
||||
save routine knows what colormaps etc to generate in the saved
|
||||
file. We store twice the number necessary because in the second
|
||||
set, the color depths that are automatically suggested are stored
|
||||
for later comparison.
|
||||
*/
|
||||
|
||||
icon_depths = g_new (gint, 2 * num_layers);
|
||||
for (i = 0; i < 2 * num_layers; i++)
|
||||
icon_depths[i] = 32;
|
||||
|
||||
g_object_set_data (G_OBJECT (dialog), "icon_depths", icon_depths);
|
||||
|
||||
vbox = GTK_DIALOG (dialog)->vbox;
|
||||
|
||||
frame = gtk_frame_new (_("Icon details"));
|
||||
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow), 5);
|
||||
gtk_container_add (GTK_CONTAINER (frame), scrolledwindow);
|
||||
gtk_widget_show (scrolledwindow);
|
||||
|
||||
viewport = gtk_viewport_new (NULL, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (scrolledwindow), viewport);
|
||||
gtk_widget_show (viewport);
|
||||
|
||||
vbox = gtk_vbox_new (TRUE, 0);
|
||||
g_object_set_data (G_OBJECT (dialog), "icons_vbox", vbox);
|
||||
gtk_container_add (GTK_CONTAINER (viewport), vbox);
|
||||
gtk_widget_show (vbox);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
ico_specs_dialog_get_layer_preview (GtkWidget *dialog,
|
||||
gint32 layer)
|
||||
{
|
||||
GtkWidget *preview;
|
||||
GtkWidget *icon_hbox;
|
||||
gchar key[MAXLEN];
|
||||
|
||||
g_snprintf (key, MAXLEN, "layer_%i_hbox", layer);
|
||||
icon_hbox = g_object_get_data (G_OBJECT (dialog), key);
|
||||
|
||||
if (!icon_hbox)
|
||||
{
|
||||
D(("Something's wrong -- couldn't look up hbox by layer ID\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
preview = g_object_get_data (G_OBJECT (icon_hbox), "icon_preview");
|
||||
|
||||
if (!icon_hbox)
|
||||
{
|
||||
D(("Something's wrong -- couldn't look up preview from hbox\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_specs_dialog_add_icon (GtkWidget *dialog,
|
||||
gint32 layer,
|
||||
gint layer_num)
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *preview;
|
||||
gchar key[MAXLEN];
|
||||
|
||||
vbox = g_object_get_data (G_OBJECT (dialog), "icons_vbox");
|
||||
preview = ico_preview_new (layer);
|
||||
hbox = ico_create_icon_hbox (preview, layer, layer_num);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 2);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
/* Let's make the hbox accessible through the layer ID */
|
||||
g_snprintf (key, MAXLEN, "layer_%i_hbox", layer);
|
||||
g_object_set_data (G_OBJECT (dialog), key, hbox);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_specs_dialog_update_icon_preview (GtkWidget *dialog,
|
||||
gint32 layer,
|
||||
gint bpp)
|
||||
{
|
||||
GtkWidget *preview;
|
||||
GimpPixelRgn src_pixel_rgn, dst_pixel_rgn;
|
||||
gint32 tmp_image;
|
||||
gint32 tmp_layer;
|
||||
gint w, h;
|
||||
guchar *buffer;
|
||||
gboolean result;
|
||||
|
||||
tmp_image = gimp_image_new (gimp_drawable_width (layer),
|
||||
gimp_drawable_height (layer),
|
||||
GIMP_RGB);
|
||||
|
||||
w = gimp_drawable_width (layer);
|
||||
h = gimp_drawable_height (layer);
|
||||
|
||||
tmp_layer = gimp_layer_new (tmp_image, "temporary", w, h,
|
||||
GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE);
|
||||
gimp_image_add_layer (tmp_image, tmp_layer, 0);
|
||||
|
||||
gimp_pixel_rgn_init (&src_pixel_rgn, gimp_drawable_get (layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_init (&dst_pixel_rgn, gimp_drawable_get (tmp_layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
|
||||
buffer = g_malloc (w * h * 4);
|
||||
gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
|
||||
gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
|
||||
|
||||
if (bpp < 32)
|
||||
{
|
||||
result = gimp_image_convert_indexed (tmp_image,
|
||||
GIMP_FS_DITHER,
|
||||
GIMP_MAKE_PALETTE,
|
||||
1 << bpp,
|
||||
TRUE,
|
||||
FALSE,
|
||||
"dummy");
|
||||
}
|
||||
|
||||
preview = ico_specs_dialog_get_layer_preview (dialog, layer);
|
||||
ico_fill_preview_with_thumb (preview, tmp_layer);
|
||||
gtk_widget_queue_draw (preview);
|
||||
|
||||
gimp_image_delete (tmp_image);
|
||||
g_free (buffer);
|
||||
}
|
||||
|
||||
|
||||
/* meta-callback for color depth changes in an icon */
|
||||
static void
|
||||
on_bpp_change (GtkWidget *icon_hbox,
|
||||
gint bpp)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
gint32 layer;
|
||||
gint layer_num;
|
||||
gint *icon_depths;
|
||||
|
||||
dialog = gtk_widget_get_toplevel (icon_hbox);
|
||||
|
||||
layer = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (icon_hbox),
|
||||
"icon_layer"));
|
||||
layer_num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (icon_hbox),
|
||||
"icon_layer_num"));
|
||||
icon_depths = g_object_get_data (G_OBJECT (dialog), "icon_depths");
|
||||
|
||||
if (! icon_depths)
|
||||
{
|
||||
D(("Something's wrong -- can't get icon_depths array from dialog ...\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update vector entry for later when we're actually saving,
|
||||
and update the preview right away ... */
|
||||
icon_depths[layer_num] = bpp;
|
||||
ico_specs_dialog_update_icon_preview (dialog, layer, bpp);
|
||||
}
|
||||
|
||||
static void
|
||||
on_1bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox)
|
||||
{
|
||||
on_bpp_change (icon_hbox, 1);
|
||||
item = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_4bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox)
|
||||
{
|
||||
on_bpp_change (icon_hbox, 4);
|
||||
item = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_8bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox)
|
||||
{
|
||||
on_bpp_change (icon_hbox, 8);
|
||||
item = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_32bpp_menu_selected (GtkWidget *item,
|
||||
GtkWidget *icon_hbox)
|
||||
{
|
||||
on_bpp_change (icon_hbox, 32);
|
||||
item = NULL;
|
||||
}
|
||||
35
plug-ins/winicon/icodialog.h
Normal file
35
plug-ins/winicon/icodialog.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ICO_DIALOG_H__
|
||||
#define __ICO_DIALOG_H__
|
||||
|
||||
|
||||
GtkWidget * ico_specs_dialog_new (gint num_layers);
|
||||
void ico_specs_dialog_add_icon (GtkWidget *dialog,
|
||||
gint32 layer,
|
||||
gint layer_num);
|
||||
void ico_specs_dialog_update_icon_preview (GtkWidget *dialog,
|
||||
gint32 layer,
|
||||
gint bpp);
|
||||
|
||||
|
||||
#endif
|
||||
537
plug-ins/winicon/icoload.c
Normal file
537
plug-ins/winicon/icoload.c
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <libgimp/gimp.h>
|
||||
|
||||
/* #define ICO_DBG */
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
|
||||
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
|
||||
|
||||
#define A_VAL(p) ((guchar *)(p))[0]
|
||||
#define R_VAL(p) ((guchar *)(p))[1]
|
||||
#define G_VAL(p) ((guchar *)(p))[2]
|
||||
#define B_VAL(p) ((guchar *)(p))[3]
|
||||
|
||||
#elif (G_BYTE_ORDER == G_LITTLE_ENDIAN)
|
||||
|
||||
#define A_VAL(p) ((guchar *)(p))[3]
|
||||
#define R_VAL(p) ((guchar *)(p))[2]
|
||||
#define G_VAL(p) ((guchar *)(p))[1]
|
||||
#define B_VAL(p) ((guchar *)(p))[0]
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static gint ico_read_int8 (FILE *fp, guint8 *data, gint count);
|
||||
static gint ico_read_int16 (FILE *fp, guint16 *data, gint count);
|
||||
static gint ico_read_int32 (FILE *fp, guint32 *data, gint count);
|
||||
static gboolean ico_init (const gchar *filename, MsIcon *ico);
|
||||
static void ico_read_entry (MsIcon *ico, MsIconEntry* entry);
|
||||
static void ico_read_data (MsIcon *ico, gint icon_num);
|
||||
static void ico_load (MsIcon *ico);
|
||||
static gint32 ico_to_gimp (MsIcon *ico);
|
||||
|
||||
|
||||
static gint
|
||||
ico_read_int32 (FILE *fp,
|
||||
guint32 *data,
|
||||
gint count)
|
||||
{
|
||||
gint i, total;
|
||||
|
||||
total = count;
|
||||
if (count > 0)
|
||||
{
|
||||
ico_read_int8 (fp, (guint8*) data, count * 4);
|
||||
for (i = 0; i < count; i++)
|
||||
data[i] = GUINT32_FROM_LE (data[i]);
|
||||
}
|
||||
|
||||
return total * 4;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
ico_read_int16 (FILE *fp,
|
||||
guint16 *data,
|
||||
gint count)
|
||||
{
|
||||
gint i, total;
|
||||
|
||||
total = count;
|
||||
if (count > 0)
|
||||
{
|
||||
ico_read_int8 (fp, (guint8*) data, count * 2);
|
||||
for (i = 0; i < count; i++)
|
||||
data[i] = GUINT16_FROM_LE (data[i]);
|
||||
}
|
||||
|
||||
return total * 2;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
ico_read_int8 (FILE *fp,
|
||||
guint8 *data,
|
||||
gint count)
|
||||
{
|
||||
gint total;
|
||||
gint bytes;
|
||||
|
||||
total = count;
|
||||
while (count > 0)
|
||||
{
|
||||
bytes = fread ((gchar *) data, sizeof (gchar), count, fp);
|
||||
if (bytes <= 0) /* something bad happened */
|
||||
break;
|
||||
count -= bytes;
|
||||
data += bytes;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
ico_init (const gchar *filename,
|
||||
MsIcon *ico)
|
||||
{
|
||||
memset (ico, 0, sizeof (MsIcon));
|
||||
|
||||
if (! (ico->fp = fopen (filename, "r")))
|
||||
{
|
||||
g_message (_("Could not open '%s' for reading: %s"),
|
||||
gimp_filename_to_utf8 (filename), g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ico->filename = filename;
|
||||
|
||||
ico->cp += ico_read_int16 (ico->fp, &ico->reserved, 1);
|
||||
ico->cp += ico_read_int16 (ico->fp, &ico->resource_type, 1);
|
||||
|
||||
/* Icon files use 1 as resource type, that's what I wrote this for.
|
||||
From descriptions on the web it seems as if this loader should
|
||||
also be able to handle Win 3.11 - Win 95 cursor files (.cur),
|
||||
which use resource type 2. I haven't tested this though. */
|
||||
if (ico->reserved != 0 ||
|
||||
(ico->resource_type != 1 && ico->resource_type != 2))
|
||||
{
|
||||
ico_cleanup (ico);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_read_entry (MsIcon *ico,
|
||||
MsIconEntry *entry)
|
||||
{
|
||||
if (!ico || !entry)
|
||||
return;
|
||||
|
||||
ico->cp += ico_read_int8 (ico->fp, &entry->width, 1);
|
||||
ico->cp += ico_read_int8 (ico->fp, &entry->height, 1);
|
||||
ico->cp += ico_read_int8 (ico->fp, &entry->num_colors, 1);
|
||||
ico->cp += ico_read_int8 (ico->fp, &entry->reserved, 1);
|
||||
|
||||
ico->cp += ico_read_int16 (ico->fp, &entry->num_planes, 1);
|
||||
ico->cp += ico_read_int16 (ico->fp, &entry->bpp, 1);
|
||||
|
||||
ico->cp += ico_read_int32 (ico->fp, &entry->size, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &entry->offset, 1);
|
||||
|
||||
D(("Read entry with w: "
|
||||
"%i, h: %i, num_colors: %i, bpp: %i, size %i, offset %i\n",
|
||||
entry->width, entry->height, entry->num_colors, entry->bpp,
|
||||
entry->size, entry->offset));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_read_data (MsIcon *ico,
|
||||
gint icon_num)
|
||||
{
|
||||
MsIconData *data;
|
||||
MsIconEntry *entry;
|
||||
gint length;
|
||||
|
||||
if (!ico)
|
||||
return;
|
||||
|
||||
D(("Reading data for icon %i ------------------------------\n", icon_num));
|
||||
|
||||
entry = &ico->icon_dir[icon_num];
|
||||
data = &ico->icon_data[icon_num];
|
||||
|
||||
ico->cp = entry->offset;
|
||||
|
||||
if (fseek (ico->fp, entry->offset, SEEK_SET) < 0)
|
||||
return;
|
||||
|
||||
D((" starting at offset %i\n", entry->offset));
|
||||
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->header_size, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->width, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->height, 1);
|
||||
|
||||
ico->cp += ico_read_int16 (ico->fp, &data->planes, 1);
|
||||
ico->cp += ico_read_int16 (ico->fp, &data->bpp, 1);
|
||||
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->compression, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->image_size, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->x_res, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->y_res, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->used_clrs, 1);
|
||||
ico->cp += ico_read_int32 (ico->fp, &data->important_clrs, 1);
|
||||
|
||||
D((" header size %i, "
|
||||
"w %i, h %i, planes %i, size %i, bpp %i, used %i, imp %i.\n",
|
||||
data->header_size, data->width, data->height,
|
||||
data->planes, data->image_size, data->bpp,
|
||||
data->used_clrs, data->important_clrs));
|
||||
|
||||
if (data->bpp <= 8)
|
||||
{
|
||||
if (data->used_clrs == 0)
|
||||
data->used_clrs = (1 << data->bpp);
|
||||
|
||||
D((" allocating a %i-slot palette for %i bpp.\n",
|
||||
data->used_clrs, data->bpp));
|
||||
|
||||
data->palette = g_new0 (guint32, data->used_clrs);
|
||||
ico->cp += ico_read_int32 (ico->fp, data->palette, data->used_clrs);
|
||||
}
|
||||
|
||||
data->xor_map = ico_alloc_map (entry->width, entry->height,
|
||||
data->bpp, &length);
|
||||
ico->cp += ico_read_int8 (ico->fp, data->xor_map, length);
|
||||
D((" length of xor_map: %i\n", length));
|
||||
|
||||
/* Read in and_map. It's padded out to 32 bits per line: */
|
||||
data->and_map = ico_alloc_map (entry->width, entry->height, 1, &length);
|
||||
ico->cp += ico_read_int8 (ico->fp, data->and_map, length);
|
||||
D((" length of and_map: %i\n", length));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_load (MsIcon *ico)
|
||||
{
|
||||
gint i;
|
||||
|
||||
if (!ico)
|
||||
return;
|
||||
|
||||
ico->cp += ico_read_int16 (ico->fp, &ico->icon_count, 1);
|
||||
ico->icon_dir = g_new0 (MsIconEntry, ico->icon_count);
|
||||
ico->icon_data = g_new0 (MsIconData, ico->icon_count);
|
||||
|
||||
D(("*** %s: Microsoft icon file, containing %i icon(s)\n",
|
||||
ico->filename, ico->icon_count));
|
||||
|
||||
for (i = 0; i < ico->icon_count; i++)
|
||||
ico_read_entry(ico, &ico->icon_dir[i]);
|
||||
|
||||
for (i = 0; i < ico->icon_count; i++)
|
||||
ico_read_data(ico, i);
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
ico_get_bit_from_data (guint8 *data,
|
||||
gint line_width,
|
||||
gint bit)
|
||||
{
|
||||
gint line;
|
||||
gint width32;
|
||||
gint offset;
|
||||
gint result;
|
||||
|
||||
/* width per line in multiples of 32 bits */
|
||||
width32 = (line_width % 32 == 0 ? line_width/32 : line_width/32 + 1);
|
||||
line = bit / line_width;
|
||||
offset = bit % line_width;
|
||||
|
||||
result = (data[line * width32 * 4 + offset/8] & (1 << (7 - (bit % 8))));
|
||||
|
||||
return (result ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
ico_get_nibble_from_data (guint8 *data,
|
||||
gint line_width,
|
||||
gint nibble)
|
||||
{
|
||||
gint line;
|
||||
gint width32;
|
||||
gint offset;
|
||||
gint result;
|
||||
|
||||
/* width per line in multiples of 32 bits */
|
||||
width32 = (line_width % 8 == 0 ? line_width/8 : line_width/8 + 1);
|
||||
line = nibble / line_width;
|
||||
offset = nibble % line_width;
|
||||
|
||||
result = (data[line * width32 * 4 + offset/2] & (0x0F << (4 * (1 - nibble % 2))));
|
||||
|
||||
if (nibble % 2 == 0)
|
||||
result = result >> 4;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
ico_get_byte_from_data (guint8 *data,
|
||||
gint line_width,
|
||||
gint byte)
|
||||
{
|
||||
gint line;
|
||||
gint width32;
|
||||
gint offset;
|
||||
|
||||
/* width per line in multiples of 32 bits */
|
||||
width32 = (line_width % 4 == 0 ? line_width/4 : line_width/4 + 1);
|
||||
line = byte / line_width;
|
||||
offset = byte % line_width;
|
||||
|
||||
return data[line * width32 * 4 + offset];
|
||||
}
|
||||
|
||||
|
||||
static gint32
|
||||
ico_to_gimp (MsIcon *ico)
|
||||
{
|
||||
gint icon_nr, x, y, w, h, max_w, max_h;
|
||||
guint8 *xor_map;
|
||||
guint8 *and_map;
|
||||
guint32 *palette;
|
||||
MsIconData *idata;
|
||||
MsIconEntry *ientry;
|
||||
gint32 image, layer, first_layer = -1;
|
||||
const char *layer_name = N_("Icon #%i");
|
||||
char s[MAXLEN];
|
||||
guint32 *dest_vec;
|
||||
GimpDrawable *drawable;
|
||||
|
||||
/* Do a quick scan of the icons in the file to find the
|
||||
largest icon contained ... */
|
||||
|
||||
max_w = 0; max_h = 0;
|
||||
|
||||
for (icon_nr = 0; icon_nr < ico->icon_count; icon_nr++)
|
||||
{
|
||||
if (ico->icon_dir[icon_nr].width > max_w)
|
||||
max_w = ico->icon_dir[icon_nr].width;
|
||||
if (ico->icon_dir[icon_nr].height > max_h)
|
||||
max_h = ico->icon_dir[icon_nr].height;
|
||||
}
|
||||
|
||||
/* Allocate the Gimp image */
|
||||
|
||||
image = gimp_image_new (max_w, max_h, GIMP_RGB);
|
||||
gimp_image_set_filename (image, ico->filename);
|
||||
|
||||
/* Scan icons again and set up a layer for each icon */
|
||||
|
||||
for (icon_nr = 0; icon_nr < ico->icon_count; icon_nr++)
|
||||
{
|
||||
GimpPixelRgn pixel_rgn;
|
||||
|
||||
if (interactive_ico)
|
||||
gimp_progress_update ((gdouble) icon_nr / (gdouble) ico->icon_count);
|
||||
|
||||
w = ico->icon_dir[icon_nr].width;
|
||||
h = ico->icon_dir[icon_nr].height;
|
||||
palette = ico->icon_data[icon_nr].palette;
|
||||
xor_map = ico->icon_data[icon_nr].xor_map;
|
||||
and_map = ico->icon_data[icon_nr].and_map;
|
||||
idata = &ico->icon_data[icon_nr];
|
||||
ientry = &ico->icon_dir[icon_nr];
|
||||
|
||||
g_snprintf (s, MAXLEN, gettext (layer_name), icon_nr + 1);
|
||||
|
||||
layer = gimp_layer_new (image, s, w, h,
|
||||
GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE);
|
||||
|
||||
if (first_layer == -1)
|
||||
first_layer = layer;
|
||||
|
||||
gimp_image_add_layer (image, layer, icon_nr);
|
||||
drawable = gimp_drawable_get (layer);
|
||||
|
||||
dest_vec = g_malloc (w * h * 4);
|
||||
|
||||
switch (idata->bpp)
|
||||
{
|
||||
case 1:
|
||||
for (y = 0; y < h; y++)
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
guint32 color = palette[ico_get_bit_from_data (xor_map,
|
||||
w, y * w + x)];
|
||||
guint32 *dest = &(dest_vec[(h-1-y) * w + x]);
|
||||
|
||||
B_VAL (dest) = R_VAL (&color);
|
||||
G_VAL (dest) = G_VAL (&color);
|
||||
R_VAL (dest) = B_VAL (&color);
|
||||
|
||||
if (ico_get_bit_from_data (and_map, w, y*w + x))
|
||||
A_VAL (dest) = 0;
|
||||
else
|
||||
A_VAL (dest) = 255;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for (y = 0; y < h; y++)
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
guint32 color = palette[ico_get_nibble_from_data (xor_map,
|
||||
w, y * w + x)];
|
||||
guint32 *dest = &(dest_vec[(h-1-y) * w + x]);
|
||||
|
||||
B_VAL (dest) = R_VAL (&color);
|
||||
G_VAL (dest) = G_VAL (&color);
|
||||
R_VAL (dest) = B_VAL (&color);
|
||||
|
||||
if (ico_get_bit_from_data (and_map, w, y*w + x))
|
||||
A_VAL (dest) = 0;
|
||||
else
|
||||
A_VAL (dest) = 255;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
for (y = 0; y < h; y++)
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
guint32 color = palette[ico_get_byte_from_data (xor_map,
|
||||
w, y * w + x)];
|
||||
guint32 *dest = &(dest_vec[(h-1-y) * w + x]);
|
||||
|
||||
B_VAL (dest) = R_VAL (&color);
|
||||
G_VAL (dest) = G_VAL (&color);
|
||||
R_VAL (dest) = B_VAL (&color);
|
||||
|
||||
if (ico_get_bit_from_data (and_map, w, y*w + x))
|
||||
A_VAL (dest) = 0;
|
||||
else
|
||||
A_VAL (dest) = 255;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
int bytespp = idata->bpp/8;
|
||||
|
||||
for (y = 0; y < h; y++)
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
guint32 *dest = &(dest_vec[(h-1-y) * w + x]);
|
||||
|
||||
R_VAL(dest) = xor_map[(y * w + x) * bytespp];
|
||||
G_VAL(dest) = xor_map[(y * w + x) * bytespp + 1];
|
||||
B_VAL(dest) = xor_map[(y * w + x) * bytespp + 2];
|
||||
|
||||
if (idata->bpp < 32)
|
||||
{
|
||||
if (ico_get_bit_from_data (and_map, w, y*w + x))
|
||||
A_VAL (dest) = 0;
|
||||
else
|
||||
A_VAL (dest) = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_VAL (dest) = xor_map[(y * w + x) * bytespp + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gimp_pixel_rgn_init (&pixel_rgn, drawable,
|
||||
0, 0, drawable->width, drawable->height,
|
||||
TRUE, FALSE);
|
||||
gimp_pixel_rgn_set_rect (&pixel_rgn, (guchar*) dest_vec,
|
||||
0, 0, drawable->width, drawable->height);
|
||||
|
||||
g_free(dest_vec);
|
||||
gimp_drawable_flush (drawable);
|
||||
gimp_drawable_detach (drawable);
|
||||
}
|
||||
|
||||
gimp_image_set_active_layer (image, first_layer);
|
||||
|
||||
if (interactive_ico)
|
||||
gimp_progress_update (1.0);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
gint32
|
||||
LoadICO (const gchar *filename)
|
||||
{
|
||||
gint32 image_ID;
|
||||
MsIcon ico;
|
||||
|
||||
if (interactive_ico)
|
||||
{
|
||||
guchar *temp = g_strdup_printf (_("Loading %s:"),
|
||||
gimp_filename_to_utf8 (filename));
|
||||
gimp_progress_init (temp);
|
||||
g_free (temp);
|
||||
}
|
||||
|
||||
if (! ico_init (filename, &ico))
|
||||
return -1;
|
||||
|
||||
ico_load (&ico);
|
||||
|
||||
if ( (image_ID = ico_to_gimp (&ico)) < 0)
|
||||
{
|
||||
ico_cleanup (&ico);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ico_cleanup (&ico);
|
||||
|
||||
D(("*** icon successfully loaded.\n\n"));
|
||||
|
||||
return image_ID;
|
||||
}
|
||||
33
plug-ins/winicon/icoload.h
Normal file
33
plug-ins/winicon/icoload.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ICO_LOAD_H__
|
||||
#define __ICO_LOAD_H__
|
||||
|
||||
|
||||
gint ico_get_bit_from_data (guint8 *data, gint line_width, gint bit);
|
||||
gint ico_get_nibble_from_data (guint8 *data, gint line_width, gint nibble);
|
||||
gint ico_get_byte_from_data (guint8 *data, gint line_width, gint byte);
|
||||
|
||||
gint32 LoadICO (const gchar *file_name);
|
||||
|
||||
|
||||
#endif
|
||||
798
plug-ins/winicon/icosave.c
Normal file
798
plug-ins/winicon/icosave.c
Normal file
|
|
@ -0,0 +1,798 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <libgimp/gimp.h>
|
||||
#include <libgimp/gimpui.h>
|
||||
|
||||
/* #define ICO_DBG */
|
||||
|
||||
#include "main.h"
|
||||
#include "icoload.h"
|
||||
#include "icodialog.h"
|
||||
|
||||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
|
||||
static gint ico_write_int8 (FILE *fp, guint8 *data, gint count);
|
||||
static gint ico_write_int16 (FILE *fp, guint16 *data, gint count);
|
||||
static gint ico_write_int32 (FILE *fp, guint32 *data, gint count);
|
||||
|
||||
static gint * ico_show_icon_dialog (gint32 image_ID, gint *num_icons);
|
||||
|
||||
/* Helpers to set bits in a *cleared* data chunk */
|
||||
static void ico_set_bit_in_data (guint8 *data, gint line_width,
|
||||
gint bit_num, gint bit_val);
|
||||
static void ico_set_nibble_in_data (guint8 *data, gint line_width,
|
||||
gint nibble_num, gint nibble_val);
|
||||
static void ico_set_byte_in_data (guint8 *data, gint line_width,
|
||||
gint byte_num, gint byte_val);
|
||||
|
||||
|
||||
|
||||
static gint
|
||||
ico_write_int32 (FILE *fp,
|
||||
guint32 *data,
|
||||
gint count)
|
||||
{
|
||||
gint i, total;
|
||||
|
||||
total = count;
|
||||
if (count > 0)
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
data[i] = GUINT32_FROM_LE (data[i]);
|
||||
|
||||
ico_write_int8 (fp, (guint8*) data, count * 4);
|
||||
}
|
||||
|
||||
return total * 4;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
ico_write_int16 (FILE *fp,
|
||||
guint16 *data,
|
||||
gint count)
|
||||
{
|
||||
gint i, total;
|
||||
|
||||
total = count;
|
||||
if (count > 0)
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
data[i] = GUINT16_FROM_LE (data[i]);
|
||||
|
||||
ico_write_int8 (fp, (guint8*) data, count * 2);
|
||||
}
|
||||
|
||||
return total * 2;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
ico_write_int8 (FILE *fp,
|
||||
guint8 *data,
|
||||
gint count)
|
||||
{
|
||||
gint total;
|
||||
gint bytes;
|
||||
|
||||
total = count;
|
||||
while (count > 0)
|
||||
{
|
||||
bytes = fwrite ((gchar *) data, sizeof (gchar), count, fp);
|
||||
if (bytes <= 0) /* something bad happened */
|
||||
break;
|
||||
count -= bytes;
|
||||
data += bytes;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
static gint*
|
||||
ico_show_icon_dialog (gint32 image_ID,
|
||||
gint *num_icons)
|
||||
{
|
||||
GtkWidget *dialog, *hbox;
|
||||
GtkWidget *icon_optionmenu;
|
||||
gint *layers, *icon_depths = NULL;
|
||||
gint num_layers, i, num_colors;
|
||||
gboolean uses_alpha_values;
|
||||
gchar key[MAXLEN];
|
||||
|
||||
*num_icons = 0;
|
||||
|
||||
gimp_ui_init ("winicon", TRUE);
|
||||
|
||||
layers = gimp_image_get_layers (image_ID, &num_layers);
|
||||
dialog = ico_specs_dialog_new (num_layers);
|
||||
|
||||
for (i = 0; i < num_layers; i++)
|
||||
{
|
||||
/* if (gimp_layer_get_visible(layers[i])) */
|
||||
ico_specs_dialog_add_icon (dialog, layers[i], i);
|
||||
}
|
||||
|
||||
/* Scale the thing to approximately fit its content, but not too large ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (dialog),
|
||||
350,
|
||||
(num_layers > 5 ? 500 : num_layers * 100));
|
||||
|
||||
icon_depths = g_object_get_data (G_OBJECT (dialog), "icon_depths");
|
||||
|
||||
/* Limit the color depths to values that don't cause any color loss --
|
||||
the user should pick these anyway, so we can save her some time.
|
||||
If the user wants to lose some colors, the settings can always be changed
|
||||
in the dialog: */
|
||||
for (i = 0; i < num_layers; i++)
|
||||
{
|
||||
num_colors = ico_get_layer_num_colors (layers[i], &uses_alpha_values);
|
||||
|
||||
g_snprintf (key, MAXLEN, "layer_%i_hbox", layers[i]);
|
||||
hbox = g_object_get_data (G_OBJECT (dialog), key);
|
||||
icon_optionmenu = g_object_get_data (G_OBJECT(hbox), "icon_optionmenu");
|
||||
|
||||
if (!uses_alpha_values)
|
||||
{
|
||||
if (num_colors <= 2)
|
||||
{
|
||||
/* Let's suggest monochrome */
|
||||
icon_depths[i] = 1;
|
||||
icon_depths[num_layers + i] = 1;
|
||||
ico_specs_dialog_update_icon_preview (dialog, layers[i], 2);
|
||||
gtk_option_menu_set_history (GTK_OPTION_MENU (icon_optionmenu), 0);
|
||||
}
|
||||
else if (num_colors <= 16)
|
||||
{
|
||||
/* Let's suggest 4bpp */
|
||||
icon_depths[i] = 4;
|
||||
icon_depths[num_layers + i] = 4;
|
||||
ico_specs_dialog_update_icon_preview (dialog, layers[i], 4);
|
||||
gtk_option_menu_set_history (GTK_OPTION_MENU (icon_optionmenu), 1);
|
||||
}
|
||||
else if (num_colors <= 256)
|
||||
{
|
||||
/* Let's suggest 8bpp */
|
||||
icon_depths[i] = 8;
|
||||
icon_depths[num_layers + i] = 8;
|
||||
ico_specs_dialog_update_icon_preview (dialog, layers[i], 8);
|
||||
gtk_option_menu_set_history (GTK_OPTION_MENU (icon_optionmenu), 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, or if real alpha levels are used, stick with 32bpp */
|
||||
}
|
||||
|
||||
g_free (layers);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
if (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK)
|
||||
*num_icons = num_layers;
|
||||
else
|
||||
icon_depths = NULL;
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
|
||||
return icon_depths;
|
||||
}
|
||||
|
||||
|
||||
static GimpPDBStatusType
|
||||
ico_init (const gchar *filename,
|
||||
MsIcon *ico,
|
||||
gint num_icons)
|
||||
{
|
||||
memset (ico, 0, sizeof(MsIcon));
|
||||
|
||||
if (! (ico->fp = fopen (filename, "wb")))
|
||||
{
|
||||
g_message (_("Could not open '%s' for writing: %s"),
|
||||
gimp_filename_to_utf8 (filename), g_strerror (errno));
|
||||
return GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
ico->filename = filename;
|
||||
ico->reserved = 0;
|
||||
ico->resource_type = GUINT16_FROM_LE (1);
|
||||
ico->icon_count = num_icons;
|
||||
ico->icon_dir = g_new0 (MsIconEntry, num_icons);
|
||||
ico->icon_data = g_new0 (MsIconData, num_icons);
|
||||
|
||||
return GIMP_PDB_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_init_direntry (MsIconEntry *entry,
|
||||
gint32 layer,
|
||||
gint bpp)
|
||||
{
|
||||
/* Was calloc'd, so initialized to 0. */
|
||||
entry->width = gimp_drawable_width (layer);
|
||||
entry->height = gimp_drawable_height (layer);
|
||||
|
||||
if (bpp < 8)
|
||||
entry->num_colors = (1 << bpp);
|
||||
|
||||
entry->num_planes = 1;
|
||||
entry->bpp = bpp;
|
||||
|
||||
D(("Initialized entry to w %i, h %i, bpp %i\n",
|
||||
gimp_drawable_width (layer), entry->width, entry->bpp));
|
||||
|
||||
/* We'll set size and offset when writing things out */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_set_bit_in_data (guint8 *data,
|
||||
gint line_width,
|
||||
gint bit_num,
|
||||
gint bit_val)
|
||||
{
|
||||
gint line;
|
||||
gint width32;
|
||||
gint offset;
|
||||
|
||||
/* width per line in multiples of 32 bits */
|
||||
width32 = (line_width % 32 == 0 ? line_width/32 : line_width/32 + 1);
|
||||
|
||||
line = bit_num / line_width;
|
||||
offset = bit_num % line_width;
|
||||
bit_val = bit_val & 0x00000001;
|
||||
|
||||
data[line * width32 * 4 + offset/8] |= (bit_val << (7 - (bit_num % 8)));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_set_nibble_in_data (guint8 *data,
|
||||
gint line_width,
|
||||
gint nibble_num,
|
||||
gint nibble_val)
|
||||
{
|
||||
gint line;
|
||||
gint width8;
|
||||
gint offset;
|
||||
|
||||
/* width per line in multiples of 32 bits */
|
||||
width8 = (line_width % 8 == 0 ? line_width/8 : line_width/8 + 1);
|
||||
|
||||
line = nibble_num / line_width;
|
||||
offset = nibble_num % line_width;
|
||||
nibble_val = nibble_val & 0x0000000F;
|
||||
|
||||
data[line * width8 * 4 + offset/2] |= (nibble_val << (4 * (1 - (nibble_num % 2))));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_set_byte_in_data (guint8 *data,
|
||||
gint line_width,
|
||||
gint byte_num,
|
||||
gint byte_val)
|
||||
{
|
||||
gint line;
|
||||
gint width4;
|
||||
gint offset;
|
||||
gint byte;
|
||||
|
||||
/* width per line in multiples of 32 bits */
|
||||
width4 = (line_width % 4 == 0 ? line_width/4 : line_width/4 + 1);
|
||||
|
||||
line = byte_num / line_width;
|
||||
offset = byte_num % line_width;
|
||||
byte = byte_val & 0x000000FF;
|
||||
|
||||
data[line * width4 * 4 + offset] = byte;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create a colormap from the given buffer data */
|
||||
static guint32 *
|
||||
ico_create_palette(guchar *cmap,
|
||||
gint num_colors,
|
||||
gint num_colors_used,
|
||||
gint *black_slot)
|
||||
{
|
||||
guchar *palette;
|
||||
gint i;
|
||||
|
||||
palette = g_new0 (guchar, num_colors * 4);
|
||||
*black_slot = -1;
|
||||
|
||||
for (i = 0; i < num_colors_used; i++)
|
||||
{
|
||||
palette[i * 4 + 2] = cmap[i * 3];
|
||||
palette[i * 4 + 1] = cmap[i * 3 + 1];
|
||||
palette[i * 4] = cmap[i * 3 + 2];
|
||||
|
||||
if ((cmap[i*3] == 0) &&
|
||||
(cmap[i*3 + 1] == 0) &&
|
||||
(cmap[i*3 + 2] == 0))
|
||||
{
|
||||
*black_slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (*black_slot == -1)
|
||||
{
|
||||
if (num_colors_used == num_colors)
|
||||
{
|
||||
D(("WARNING -- no room for black, this shouldn't happen.\n"));
|
||||
*black_slot = num_colors - 1;
|
||||
|
||||
palette[(num_colors-1) * 4] = 0;
|
||||
palette[(num_colors-1) * 4 + 1] = 0;
|
||||
palette[(num_colors-1) * 4 + 2] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*black_slot = num_colors_used;
|
||||
}
|
||||
}
|
||||
|
||||
return (guint32*) palette;
|
||||
}
|
||||
|
||||
|
||||
static GHashTable *
|
||||
ico_create_color_to_palette_map (guint32 *palette,
|
||||
gint num_colors)
|
||||
{
|
||||
GHashTable *hash;
|
||||
gint i;
|
||||
|
||||
hash = g_hash_table_new (g_int_hash, g_int_equal);
|
||||
|
||||
for (i = 0; i < num_colors; i++)
|
||||
{
|
||||
gint *color, *slot;
|
||||
guint8 *pixel = (guint8*) &palette[i];
|
||||
|
||||
color = g_new (gint, 1);
|
||||
slot = g_new (gint, 1);
|
||||
|
||||
*color = (pixel[2] << 16 | pixel[1] << 8 | pixel[0]);
|
||||
*slot = i;
|
||||
|
||||
g_hash_table_insert (hash, color, slot);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_free_hash_item (gpointer data1,
|
||||
gpointer data2,
|
||||
gpointer data3)
|
||||
{
|
||||
g_free (data1);
|
||||
g_free (data2);
|
||||
|
||||
/* Shut up warnings: */
|
||||
data3 = NULL;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
ico_get_palette_index (GHashTable *hash,
|
||||
gint red,
|
||||
gint green,
|
||||
gint blue)
|
||||
{
|
||||
gint color = 0;
|
||||
gint *slot;
|
||||
|
||||
color = (red << 16 | green << 8 | blue);
|
||||
slot = g_hash_table_lookup (hash, &color);
|
||||
|
||||
if (!slot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return *slot;
|
||||
}
|
||||
|
||||
static void
|
||||
ico_init_data (MsIcon *ico,
|
||||
gint num_icon,
|
||||
gint32 layer,
|
||||
gint bpp)
|
||||
{
|
||||
MsIconEntry *entry;
|
||||
MsIconData *data;
|
||||
gint and_len, xor_len, palette_index, x, y;
|
||||
gint num_colors = 0, num_colors_used = 0, buf_bpp, black_index;
|
||||
guchar *buffer = NULL, *pixel;
|
||||
guint32 *buffer32;
|
||||
guchar *palette;
|
||||
GHashTable *color_to_slot = NULL;
|
||||
|
||||
D(("Creating data structures for icon %i ------------------------\n", num_icon));
|
||||
|
||||
/* Shortcuts, for convenience */
|
||||
entry = &ico->icon_dir[num_icon];
|
||||
data = &ico->icon_data[num_icon];
|
||||
|
||||
/* Entries and data were calloc'd, so initialized to 0. */
|
||||
|
||||
data->header_size = 40;
|
||||
data->width = gimp_drawable_width (layer);
|
||||
data->height = 2 * gimp_drawable_height (layer);
|
||||
data->planes = 1;
|
||||
data->bpp = bpp;
|
||||
|
||||
num_colors = (1L << bpp);
|
||||
|
||||
D((" header size %i, w %i, h %i, planes %i, bpp %i\n",
|
||||
data->header_size, data->width, data->height, data->planes, data->bpp));
|
||||
|
||||
/* Reduce colors in copy of image */
|
||||
ico_image_get_reduced_buf (layer, bpp, &num_colors_used,
|
||||
&palette, &buffer, &buf_bpp);
|
||||
buffer32 = (guint32*) buffer;
|
||||
|
||||
/* Set up colormap and andmap when necessary: */
|
||||
if (bpp <= 8)
|
||||
{
|
||||
/* Create a colormap */
|
||||
data->palette = ico_create_palette (palette,
|
||||
num_colors, num_colors_used,
|
||||
&black_index);
|
||||
data->palette_len = num_colors * 4;
|
||||
|
||||
color_to_slot = ico_create_color_to_palette_map (data->palette,
|
||||
num_colors_used);
|
||||
D((" created %i-slot colormap with %i colors, black at slot %i\n",
|
||||
num_colors, num_colors_used, black_index));
|
||||
}
|
||||
|
||||
/* Create and_map. It's padded out to 32 bits per line: */
|
||||
data->and_map = ico_alloc_map (entry->width, entry->height, 1, &and_len);
|
||||
data->and_len = and_len;
|
||||
|
||||
for (y = 0; y < entry->height; y++)
|
||||
for (x = 0; x < entry->width; x++)
|
||||
{
|
||||
pixel = (guint8*) &buffer32[y * entry->width + x];
|
||||
|
||||
ico_set_bit_in_data (data->and_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x,
|
||||
(pixel[3] == 255 ? 0 : 1));
|
||||
}
|
||||
|
||||
data->xor_map = ico_alloc_map(entry->width, entry->height, bpp, &xor_len);
|
||||
data->xor_len = xor_len;
|
||||
|
||||
/* Now fill in the xor map */
|
||||
switch (bpp)
|
||||
{
|
||||
case 1:
|
||||
for (y = 0; y < entry->height; y++)
|
||||
for (x = 0; x < entry->width; x++)
|
||||
{
|
||||
pixel = (guint8*) &buffer32[y * entry->width + x];
|
||||
palette_index = ico_get_palette_index (color_to_slot,
|
||||
pixel[0], pixel[1], pixel[2]);
|
||||
|
||||
if (ico_get_bit_from_data (data->and_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x))
|
||||
{
|
||||
ico_set_bit_in_data (data->xor_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x,
|
||||
black_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
ico_set_bit_in_data (data->xor_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x,
|
||||
palette_index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for (y = 0; y < entry->height; y++)
|
||||
for (x = 0; x < entry->width; x++)
|
||||
{
|
||||
pixel = (guint8*) &buffer32[y * entry->width + x];
|
||||
palette_index = ico_get_palette_index(color_to_slot,
|
||||
pixel[0], pixel[1], pixel[2]);
|
||||
|
||||
if (ico_get_bit_from_data (data->and_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x))
|
||||
{
|
||||
ico_set_nibble_in_data (data->xor_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x,
|
||||
black_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
ico_set_nibble_in_data (data->xor_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x,
|
||||
palette_index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
for (y = 0; y < entry->height; y++)
|
||||
for (x = 0; x < entry->width; x++)
|
||||
{
|
||||
pixel = (guint8*) &buffer32[y * entry->width + x];
|
||||
palette_index = ico_get_palette_index (color_to_slot,
|
||||
pixel[0], pixel[1], pixel[2]);
|
||||
|
||||
if (ico_get_bit_from_data (data->and_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x))
|
||||
{
|
||||
ico_set_byte_in_data (data->xor_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x,
|
||||
black_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
ico_set_byte_in_data (data->xor_map, entry->width,
|
||||
(entry->height-y-1) * entry->width + x,
|
||||
palette_index);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
for (y = 0; y < entry->height; y++)
|
||||
for (x = 0; x < entry->width; x++)
|
||||
{
|
||||
pixel = (guint8*) &buffer32[y * entry->width + x];
|
||||
|
||||
((guint32*) data->xor_map)[(entry->height-y-1) * entry->width + x] =
|
||||
((pixel[0] << 16) | (pixel[1] << 8) | pixel[2] | (pixel[3] << 24));
|
||||
}
|
||||
}
|
||||
|
||||
D((" filled and_map of length %i, xor_map of length %i\n",
|
||||
data->and_len, data->xor_len));
|
||||
|
||||
if (color_to_slot)
|
||||
{
|
||||
g_hash_table_foreach (color_to_slot, ico_free_hash_item, NULL);
|
||||
g_hash_table_destroy (color_to_slot);
|
||||
}
|
||||
|
||||
g_free(palette);
|
||||
g_free(buffer);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_setup (MsIcon *ico,
|
||||
gint32 image,
|
||||
gint *icon_depths,
|
||||
gint num_icons)
|
||||
{
|
||||
gint *layers;
|
||||
gint i;
|
||||
gint offset;
|
||||
|
||||
layers = gimp_image_get_layers(image, &num_icons);
|
||||
|
||||
/* Set up icon entries */
|
||||
for (i = 0; i < num_icons; i++)
|
||||
{
|
||||
ico_init_direntry (&ico->icon_dir[i], layers[i], icon_depths[i]);
|
||||
if (interactive_ico)
|
||||
gimp_progress_update ((gdouble) i / (gdouble) num_icons * 0.3);
|
||||
}
|
||||
|
||||
/* Set up data entries (the actual icons), and calculate each one's size */
|
||||
for (i = 0; i < num_icons; i++)
|
||||
{
|
||||
ico_init_data (ico, i, layers[i], icon_depths[i]);
|
||||
|
||||
ico->icon_dir[i].size =
|
||||
ico->icon_data[i].header_size +
|
||||
ico->icon_data[i].palette_len +
|
||||
ico->icon_data[i].xor_len +
|
||||
ico->icon_data[i].and_len;
|
||||
|
||||
if (interactive_ico)
|
||||
gimp_progress_update (0.3 + (gdouble) i / (gdouble) num_icons * 0.3);
|
||||
}
|
||||
|
||||
/* Finally, calculate offsets for each icon and store them in each entry */
|
||||
offset = 3 * sizeof (guint16) + ico->icon_count * sizeof (MsIconEntry);
|
||||
|
||||
for (i = 0; i < num_icons; i++)
|
||||
{
|
||||
ico->icon_dir[i].offset = offset;
|
||||
offset += ico->icon_dir[i].size;
|
||||
|
||||
if (interactive_ico)
|
||||
gimp_progress_update (0.6 + (gdouble) i / (gdouble) num_icons * 0.3);
|
||||
}
|
||||
|
||||
if (interactive_ico)
|
||||
gimp_progress_update (1.0);
|
||||
|
||||
g_free(layers);
|
||||
}
|
||||
|
||||
|
||||
static GimpPDBStatusType
|
||||
ico_save (MsIcon *ico)
|
||||
{
|
||||
MsIconEntry *entry;
|
||||
MsIconData *data;
|
||||
int i;
|
||||
|
||||
ico->cp += ico_write_int16 (ico->fp, &ico->reserved, 3);
|
||||
|
||||
for (i = 0; i < ico->icon_count; i++)
|
||||
{
|
||||
entry = &ico->icon_dir[i];
|
||||
|
||||
ico->cp += ico_write_int8 (ico->fp, (guint8*) entry, 4);
|
||||
ico->cp += ico_write_int16 (ico->fp, &entry->num_planes, 2);
|
||||
ico->cp += ico_write_int32 (ico->fp, &entry->size, 2);
|
||||
}
|
||||
|
||||
for (i = 0; i < ico->icon_count; i++)
|
||||
{
|
||||
data = &ico->icon_data[i];
|
||||
|
||||
ico->cp += ico_write_int32 (ico->fp, (guint32*) data, 3);
|
||||
ico->cp += ico_write_int16 (ico->fp, &data->planes, 2);
|
||||
ico->cp += ico_write_int32 (ico->fp, &data->compression, 6);
|
||||
|
||||
if (data->palette)
|
||||
ico->cp += ico_write_int32 (ico->fp,
|
||||
data->palette, data->palette_len / 4);
|
||||
|
||||
ico->cp += ico_write_int8 (ico->fp, data->xor_map, data->xor_len);
|
||||
ico->cp += ico_write_int8 (ico->fp, data->and_map, data->and_len);
|
||||
}
|
||||
|
||||
return GIMP_PDB_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_sync_image_to_ico (gint32 image,
|
||||
gint *icon_depths)
|
||||
{
|
||||
gint *layers;
|
||||
gint i, num_layers;
|
||||
|
||||
layers = gimp_image_get_layers(image, &num_layers);
|
||||
|
||||
for (i = 0; i < num_layers; i++)
|
||||
{
|
||||
if (icon_depths[i] < icon_depths[num_layers + i])
|
||||
{
|
||||
D(("Layer '%s' was reduced to %i bpp -- updating source image.\n",
|
||||
gimp_layer_get_name (layers[i]), icon_depths[i]));
|
||||
|
||||
ico_image_reduce_layer_bpp (layers[i], icon_depths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(layers);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
ico_layers_too_big (gint32 image)
|
||||
{
|
||||
gint *layers;
|
||||
gint i, num_layers;
|
||||
|
||||
layers = gimp_image_get_layers (image, &num_layers);
|
||||
|
||||
for (i = 0; i < num_layers; i++)
|
||||
{
|
||||
if ((gimp_drawable_width (layers[i]) > 255) ||
|
||||
(gimp_drawable_height (layers[i]) > 255))
|
||||
{
|
||||
g_free (layers);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (layers);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
GimpPDBStatusType
|
||||
SaveICO (const gchar *filename,
|
||||
gint32 image)
|
||||
{
|
||||
MsIcon ico;
|
||||
gint *icon_depths = NULL;
|
||||
gint num_icons;
|
||||
GimpPDBStatusType exit_state;
|
||||
|
||||
D(("*** Saving Microsoft icon file %s\n", filename));
|
||||
|
||||
if (ico_layers_too_big(image))
|
||||
{
|
||||
g_message (_("Windows icons cannot be higher or wider than 255 pixels."));
|
||||
return GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
if (gimp_image_base_type (image) != GIMP_RGB)
|
||||
{
|
||||
if (! gimp_image_convert_rgb (image))
|
||||
return GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
/* First, set up the icon specs dialog and show it: */
|
||||
if ((icon_depths = ico_show_icon_dialog(image, &num_icons)) == NULL)
|
||||
return GIMP_PDB_CANCEL;
|
||||
|
||||
if (interactive_ico)
|
||||
{
|
||||
guchar *temp_buf = g_strdup_printf (_("Saving %s:"),
|
||||
gimp_filename_to_utf8 (filename));
|
||||
gimp_progress_init (temp_buf);
|
||||
g_free (temp_buf);
|
||||
}
|
||||
|
||||
/* Okay, let's actually save the thing with the depths the
|
||||
user specified. */
|
||||
|
||||
if ((exit_state = ico_init (filename, &ico, num_icons) != GIMP_PDB_SUCCESS))
|
||||
return exit_state;
|
||||
|
||||
D(("icon initialized ...\n"));
|
||||
|
||||
ico_setup (&ico, image, icon_depths, num_icons);
|
||||
|
||||
D(("icon data created ...\n"));
|
||||
|
||||
if ( (exit_state = ico_save(&ico)) == GIMP_PDB_SUCCESS)
|
||||
{
|
||||
ico_sync_image_to_ico (image, icon_depths);
|
||||
}
|
||||
|
||||
D(("*** icon saved, exit status %i.\n\n", exit_state));
|
||||
|
||||
ico_cleanup (&ico);
|
||||
g_free (icon_depths);
|
||||
|
||||
return exit_state;
|
||||
}
|
||||
30
plug-ins/winicon/icosave.h
Normal file
30
plug-ins/winicon/icosave.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ICO_SAVE_H__
|
||||
#define __ICO_SAVE_H__
|
||||
|
||||
|
||||
GimpPDBStatusType SaveICO (const gchar *file_name,
|
||||
gint32 image_ID);
|
||||
|
||||
|
||||
#endif
|
||||
526
plug-ins/winicon/main.c
Normal file
526
plug-ins/winicon/main.c
Normal file
|
|
@ -0,0 +1,526 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <libgimp/gimp.h>
|
||||
#include <libgimp/gimpui.h>
|
||||
|
||||
/* #define ICO_DBG */
|
||||
|
||||
#include "main.h"
|
||||
#include "icoload.h"
|
||||
#include "icosave.h"
|
||||
|
||||
#include "libgimp/stdplugins-intl.h"
|
||||
|
||||
|
||||
gboolean interactive_ico = FALSE;
|
||||
|
||||
|
||||
static void query (void);
|
||||
static void run (const gchar *name,
|
||||
gint nparams,
|
||||
const GimpParam *param,
|
||||
gint *nreturn_vals,
|
||||
GimpParam **return_vals);
|
||||
|
||||
|
||||
GimpPlugInInfo PLUG_IN_INFO =
|
||||
{
|
||||
NULL, /* init_proc */
|
||||
NULL, /* quit_proc */
|
||||
query, /* query_proc */
|
||||
run, /* run_proc */
|
||||
};
|
||||
|
||||
MAIN ()
|
||||
|
||||
static void
|
||||
query (void)
|
||||
{
|
||||
static GimpParamDef load_args[] =
|
||||
{
|
||||
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
|
||||
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
|
||||
{ GIMP_PDB_STRING, "raw_filename", "The name entered" }
|
||||
};
|
||||
static GimpParamDef load_return_vals[] =
|
||||
{
|
||||
{ GIMP_PDB_IMAGE, "image", "Output image" },
|
||||
};
|
||||
|
||||
static GimpParamDef save_args[] =
|
||||
{
|
||||
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
|
||||
{ GIMP_PDB_IMAGE, "image", "Input image" },
|
||||
{ GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
|
||||
{ GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
|
||||
{ GIMP_PDB_STRING, "raw_filename", "The name entered" },
|
||||
};
|
||||
|
||||
gimp_install_procedure ("file_ico_load",
|
||||
"Loads files of Windows ICO file format",
|
||||
"Loads files of Windows ICO file format",
|
||||
"Christian Kreibich <christian@whoop.org>",
|
||||
"Christian Kreibich <christian@whoop.org>",
|
||||
"2002",
|
||||
N_("<Load>/ICO"),
|
||||
NULL,
|
||||
GIMP_PLUGIN,
|
||||
G_N_ELEMENTS (load_args),
|
||||
G_N_ELEMENTS (load_return_vals),
|
||||
load_args, load_return_vals);
|
||||
|
||||
gimp_install_procedure ("file_ico_save",
|
||||
"Saves files in Windows ICO file format",
|
||||
"Saves files in Windows ICO file format",
|
||||
"Christian Kreibich <christian@whoop.org>",
|
||||
"Christian Kreibich <christian@whoop.org>",
|
||||
"2002",
|
||||
N_("<Save>/ICO"),
|
||||
"INDEXEDA, GRAYA, RGBA",
|
||||
GIMP_PLUGIN,
|
||||
G_N_ELEMENTS (save_args), 0,
|
||||
save_args, NULL);
|
||||
|
||||
gimp_register_magic_load_handler ("file_ico_load",
|
||||
"ico,wico",
|
||||
"",
|
||||
"0,string,\\000\\001\\000\\000,0,string,\\000\\002\\000\\000");
|
||||
gimp_register_save_handler ("file_ico_save",
|
||||
"ico,wico",
|
||||
"");
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
run (const gchar *name,
|
||||
gint nparams,
|
||||
const GimpParam *param,
|
||||
gint *nreturn_vals,
|
||||
GimpParam **return_vals)
|
||||
{
|
||||
static GimpParam values[2];
|
||||
gint32 image_ID;
|
||||
gint32 drawable_ID;
|
||||
GimpRunMode run_mode;
|
||||
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
||||
GimpExportReturn export = GIMP_EXPORT_CANCEL;
|
||||
|
||||
INIT_I18N ();
|
||||
|
||||
run_mode = param[0].data.d_int32;
|
||||
|
||||
*nreturn_vals = 1;
|
||||
*return_vals = values;
|
||||
values[0].type = GIMP_PDB_STATUS;
|
||||
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
||||
|
||||
if (strcmp (name, "file_ico_load") == 0)
|
||||
{
|
||||
switch (run_mode)
|
||||
{
|
||||
case GIMP_RUN_INTERACTIVE:
|
||||
interactive_ico = TRUE;
|
||||
break;
|
||||
|
||||
case GIMP_RUN_NONINTERACTIVE:
|
||||
interactive_ico = FALSE;
|
||||
if (nparams != 3)
|
||||
status = GIMP_PDB_CALLING_ERROR;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == GIMP_PDB_SUCCESS)
|
||||
{
|
||||
image_ID = LoadICO (param[1].data.d_string);
|
||||
|
||||
if (image_ID != -1)
|
||||
{
|
||||
*nreturn_vals = 2;
|
||||
values[1].type = GIMP_PDB_IMAGE;
|
||||
values[1].data.d_image = image_ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = GIMP_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp (name, "file_ico_save") == 0)
|
||||
{
|
||||
gchar *file_name;
|
||||
|
||||
image_ID = param[1].data.d_int32;
|
||||
drawable_ID = param[2].data.d_int32;
|
||||
file_name = param[3].data.d_string;
|
||||
|
||||
switch (run_mode)
|
||||
{
|
||||
case GIMP_RUN_INTERACTIVE:
|
||||
interactive_ico = TRUE;
|
||||
break;
|
||||
|
||||
case GIMP_RUN_NONINTERACTIVE:
|
||||
interactive_ico = FALSE;
|
||||
/* Make sure all the arguments are there! */
|
||||
if (nparams < 5)
|
||||
status = GIMP_PDB_CALLING_ERROR;
|
||||
break;
|
||||
|
||||
case GIMP_RUN_WITH_LAST_VALS:
|
||||
interactive_ico = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == GIMP_PDB_SUCCESS)
|
||||
{
|
||||
status = SaveICO (file_name, image_ID);
|
||||
}
|
||||
|
||||
if (export == GIMP_EXPORT_EXPORT)
|
||||
gimp_image_delete (image_ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = GIMP_PDB_CALLING_ERROR;
|
||||
}
|
||||
|
||||
values[0].type = GIMP_PDB_STATUS;
|
||||
values[0].data.d_status = status;
|
||||
}
|
||||
|
||||
|
||||
guint8 *
|
||||
ico_alloc_map(gint width,
|
||||
gint height,
|
||||
gint bpp,
|
||||
gint *length)
|
||||
{
|
||||
gint len = 0;
|
||||
guint8 *map = NULL;
|
||||
|
||||
switch (bpp)
|
||||
{
|
||||
case 1:
|
||||
if ((width % 32) == 0)
|
||||
len = (width * height / 8);
|
||||
else
|
||||
len = 4 * ((width/32 + 1) * height);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ((width % 8) == 0)
|
||||
len = (width * height / 2);
|
||||
else
|
||||
len = 4 * ((width/8 + 1) * height);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
if ((width % 4) == 0)
|
||||
len = width * height;
|
||||
else
|
||||
len = 4 * ((width/4 + 1) * height);
|
||||
break;
|
||||
|
||||
default:
|
||||
len = width * height * (bpp/8);
|
||||
}
|
||||
|
||||
*length = len;
|
||||
map = g_new0(guint8, len);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
ico_cmap_contains_black (guchar *cmap,
|
||||
gint num_colors)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < num_colors; i++)
|
||||
{
|
||||
if ((cmap[3*i] == 0) &&
|
||||
(cmap[3*i+1] == 0) &&
|
||||
(cmap[3*i+2] == 0))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_image_reduce_layer_bpp (guint32 layer,
|
||||
gint bpp)
|
||||
{
|
||||
GimpPixelRgn src_pixel_rgn, dst_pixel_rgn;
|
||||
gint32 tmp_image;
|
||||
gint32 tmp_layer;
|
||||
gint w, h;
|
||||
guchar *buffer;
|
||||
|
||||
w = gimp_drawable_width(layer);
|
||||
h = gimp_drawable_height(layer);
|
||||
|
||||
if (bpp <= 8)
|
||||
{
|
||||
buffer = g_new (guchar, w * h * 4);
|
||||
|
||||
tmp_image = gimp_image_new (gimp_drawable_width (layer),
|
||||
gimp_drawable_height (layer),
|
||||
GIMP_RGB);
|
||||
|
||||
tmp_layer = gimp_layer_new (tmp_image, "tmp", w, h,
|
||||
GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE);
|
||||
gimp_pixel_rgn_init (&src_pixel_rgn, gimp_drawable_get(layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_init (&dst_pixel_rgn, gimp_drawable_get(tmp_layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
|
||||
gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
|
||||
gimp_image_add_layer (tmp_image, tmp_layer, 0);
|
||||
|
||||
gimp_image_convert_indexed (tmp_image,
|
||||
GIMP_FS_DITHER,
|
||||
GIMP_MAKE_PALETTE,
|
||||
1 << bpp,
|
||||
TRUE,
|
||||
FALSE,
|
||||
"dummy");
|
||||
|
||||
gimp_image_convert_rgb (tmp_image);
|
||||
|
||||
gimp_pixel_rgn_init (&dst_pixel_rgn, gimp_drawable_get (tmp_layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_get_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
|
||||
gimp_pixel_rgn_set_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
|
||||
|
||||
gimp_image_delete (tmp_image);
|
||||
|
||||
gimp_drawable_update (layer, 0, 0, w ,h);
|
||||
/* WTF! What else can I do to make the layer dialog update??? */
|
||||
|
||||
g_free (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ico_image_get_reduced_buf (guint32 layer,
|
||||
gint bpp,
|
||||
gint *num_colors,
|
||||
guchar **cmap_out,
|
||||
guchar **buf_out,
|
||||
gint *buf_bpp)
|
||||
{
|
||||
GimpPixelRgn src_pixel_rgn, dst_pixel_rgn;
|
||||
gint32 tmp_image;
|
||||
gint32 tmp_layer;
|
||||
gint w, h;
|
||||
guchar *buffer;
|
||||
guchar *cmap;
|
||||
gboolean result;
|
||||
GimpDrawable *drawable;
|
||||
|
||||
w = gimp_drawable_width (layer);
|
||||
h = gimp_drawable_height (layer);
|
||||
*cmap_out = NULL;
|
||||
*num_colors = 0;
|
||||
|
||||
buffer = g_new (guchar, w * h * 4);
|
||||
|
||||
if (bpp <= 8)
|
||||
{
|
||||
tmp_image = gimp_image_new (gimp_drawable_width (layer),
|
||||
gimp_drawable_height (layer),
|
||||
GIMP_RGB);
|
||||
|
||||
tmp_layer = gimp_layer_new (tmp_image, "tmp", w, h,
|
||||
GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE);
|
||||
gimp_pixel_rgn_init (&src_pixel_rgn, gimp_drawable_get(layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_init (&dst_pixel_rgn, gimp_drawable_get(tmp_layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
|
||||
gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
|
||||
gimp_image_add_layer (tmp_image, tmp_layer, 0);
|
||||
|
||||
result = gimp_image_convert_indexed(tmp_image,
|
||||
GIMP_FS_DITHER,
|
||||
GIMP_MAKE_PALETTE,
|
||||
1 << bpp,
|
||||
TRUE,
|
||||
FALSE,
|
||||
"dummy");
|
||||
|
||||
cmap = gimp_image_get_cmap (tmp_image, num_colors);
|
||||
|
||||
if (*num_colors == (1 << bpp) &&
|
||||
!ico_cmap_contains_black(cmap, *num_colors))
|
||||
{
|
||||
/* Damn. Windows icons with color maps need the color black.
|
||||
We need to eliminate one more color to make room for black: */
|
||||
|
||||
result = gimp_image_convert_rgb(tmp_image);
|
||||
|
||||
gimp_pixel_rgn_init (&dst_pixel_rgn, gimp_drawable_get(tmp_layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
|
||||
|
||||
result = gimp_image_convert_indexed(tmp_image,
|
||||
GIMP_FS_DITHER,
|
||||
GIMP_MAKE_PALETTE,
|
||||
(1 << bpp) - 1,
|
||||
TRUE,
|
||||
FALSE,
|
||||
"dummy");
|
||||
}
|
||||
|
||||
cmap = gimp_image_get_cmap(tmp_image, num_colors);
|
||||
*cmap_out = g_memdup (cmap, *num_colors * 3);
|
||||
|
||||
result = gimp_image_convert_rgb(tmp_image);
|
||||
|
||||
gimp_pixel_rgn_init (&dst_pixel_rgn, gimp_drawable_get(tmp_layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_get_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
|
||||
|
||||
drawable = gimp_drawable_get(tmp_layer);
|
||||
*buf_bpp = drawable->bpp;
|
||||
|
||||
gimp_image_delete(tmp_image);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_pixel_rgn_init (&dst_pixel_rgn, gimp_drawable_get(layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_get_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
|
||||
|
||||
drawable = gimp_drawable_get (layer);
|
||||
*buf_bpp = drawable->bpp;
|
||||
}
|
||||
|
||||
*buf_out = buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ico_free_color_item (gpointer data1,
|
||||
gpointer data2,
|
||||
gpointer data3)
|
||||
{
|
||||
g_free (data1);
|
||||
|
||||
/* Shut up warnings: */
|
||||
data2 = NULL;
|
||||
data3 = NULL;
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
ico_get_layer_num_colors (gint32 layer,
|
||||
gboolean *uses_alpha_levels)
|
||||
{
|
||||
GimpPixelRgn pixel_rgn;
|
||||
gint x, y, w, h, alpha, num_colors = 0;
|
||||
guint32 *buffer = NULL, *color;
|
||||
GHashTable *hash;
|
||||
|
||||
w = gimp_drawable_width (layer);
|
||||
h = gimp_drawable_height (layer);
|
||||
buffer = g_new (gint32, w * h);
|
||||
|
||||
gimp_pixel_rgn_init (&pixel_rgn, gimp_drawable_get (layer),
|
||||
0, 0, w, h, TRUE, FALSE);
|
||||
gimp_pixel_rgn_get_rect (&pixel_rgn, (guchar*) buffer, 0, 0, w, h);
|
||||
|
||||
hash = g_hash_table_new (g_int_hash, g_int_equal);
|
||||
*uses_alpha_levels = FALSE;
|
||||
|
||||
for (y = 0; y < h; y++)
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
color = g_new0 (guint32, 1);
|
||||
*color = buffer[y * w + x];
|
||||
alpha = ((guint8*) color)[3];
|
||||
|
||||
if (alpha != 0 && alpha != 255)
|
||||
*uses_alpha_levels = TRUE;
|
||||
|
||||
g_hash_table_insert(hash, color, color);
|
||||
}
|
||||
|
||||
num_colors = g_hash_table_size(hash);
|
||||
|
||||
g_hash_table_foreach (hash, ico_free_color_item, NULL);
|
||||
g_hash_table_destroy (hash);
|
||||
|
||||
g_free(buffer);
|
||||
|
||||
return num_colors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ico_cleanup (MsIcon *ico)
|
||||
{
|
||||
gint i;
|
||||
|
||||
if (!ico)
|
||||
return;
|
||||
|
||||
if (ico->fp)
|
||||
fclose(ico->fp);
|
||||
|
||||
if (ico->icon_dir)
|
||||
g_free (ico->icon_dir);
|
||||
|
||||
if (ico->icon_data)
|
||||
{
|
||||
for (i = 0; i < ico->icon_count; i++)
|
||||
{
|
||||
g_free (ico->icon_data[i].palette);
|
||||
g_free (ico->icon_data[i].xor_map);
|
||||
g_free (ico->icon_data[i].and_map);
|
||||
}
|
||||
g_free (ico->icon_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
115
plug-ins/winicon/main.h
Normal file
115
plug-ins/winicon/main.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* GIMP Plug-in for Windows Icon files.
|
||||
* Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAIN_H__
|
||||
#define __MAIN_H__
|
||||
|
||||
|
||||
extern gboolean interactive_ico;
|
||||
|
||||
|
||||
#ifdef ICO_DBG
|
||||
#define D(x) \
|
||||
{ \
|
||||
printf("ICO plugin: "); \
|
||||
printf x; \
|
||||
}
|
||||
#else
|
||||
#define D(x)
|
||||
#endif
|
||||
|
||||
|
||||
#define MAXLEN 4096
|
||||
|
||||
typedef struct _MsIconEntry
|
||||
{
|
||||
guint8 width; /* Width of icon in pixels */
|
||||
guint8 height; /* Height of icon in pixels */
|
||||
guint8 num_colors; /* Maximum number of colors */
|
||||
guint8 reserved; /* Not used */
|
||||
guint16 num_planes; /* Not used */
|
||||
guint16 bpp;
|
||||
guint32 size; /* Length of icon bitmap in bytes */
|
||||
guint32 offset; /* Offset position of icon bitmap in file */
|
||||
} MsIconEntry;
|
||||
|
||||
typedef struct _MsIconData
|
||||
{
|
||||
/* Bitmap header data */
|
||||
guint32 header_size; /* = 40 Bytes */
|
||||
guint32 width;
|
||||
guint32 height;
|
||||
guint16 planes;
|
||||
guint16 bpp;
|
||||
guint32 compression; /* not used for icons */
|
||||
guint32 image_size; /* size of image */
|
||||
guint32 x_res;
|
||||
guint32 y_res;
|
||||
guint32 used_clrs;
|
||||
guint32 important_clrs;
|
||||
|
||||
guint32 *palette; /* Color palette, only if bpp <= 8. */
|
||||
guint8 *xor_map; /* Icon bitmap */
|
||||
guint8 *and_map; /* Display bit mask */
|
||||
|
||||
/* Only used when saving: */
|
||||
gint palette_len;
|
||||
gint xor_len;
|
||||
gint and_len;
|
||||
} MsIconData;
|
||||
|
||||
typedef struct _MsIcon
|
||||
{
|
||||
FILE *fp;
|
||||
guint cp;
|
||||
const gchar *filename;
|
||||
|
||||
guint16 reserved;
|
||||
guint16 resource_type;
|
||||
guint16 icon_count;
|
||||
MsIconEntry *icon_dir;
|
||||
MsIconData *icon_data;
|
||||
} MsIcon;
|
||||
|
||||
|
||||
/* Miscellaneous helper functions below: */
|
||||
|
||||
/* Allocates a 32-bit padded bitmap for various color depths.
|
||||
Returns the allocated array directly, and the length of the
|
||||
array in the len pointer */
|
||||
guint8 * ico_alloc_map (gint width,
|
||||
gint height,
|
||||
gint bpp,
|
||||
gint *len);
|
||||
void ico_image_reduce_layer_bpp (guint32 layer,
|
||||
gint bpp);
|
||||
void ico_image_get_reduced_buf (guint32 layer,
|
||||
gint bpp,
|
||||
gint *num_colors,
|
||||
guchar **cmap,
|
||||
guchar **buffer,
|
||||
gint *buf_bpp);
|
||||
gint ico_get_layer_num_colors (gint32 layer,
|
||||
gboolean *uses_alpha_levels);
|
||||
void ico_cleanup (MsIcon *ico);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
2004-04-15 Sven Neumann <sven@gimp.org>
|
||||
|
||||
* POTFILES.in: removed plug-ins/common/gicon.c.
|
||||
* POTFILES.in: removed plug-ins/common/gicon.c; added new files
|
||||
for winicon plug-in.
|
||||
|
||||
2004-04-13 Dmitry G. Mastrukov <dmitry@taurussoft.org>
|
||||
|
||||
|
|
|
|||
|
|
@ -248,5 +248,9 @@ plug-ins/sel2path/pxl-outline.c
|
|||
plug-ins/sel2path/sel2path.c
|
||||
plug-ins/sgi/sgi.c
|
||||
plug-ins/twain/twain.c
|
||||
plug-ins/winicon/icodialog.c
|
||||
plug-ins/winicon/icoload.c
|
||||
plug-ins/winicon/icosave.c
|
||||
plug-ins/winicon/main.c
|
||||
plug-ins/winsnap/winsnap.c
|
||||
plug-ins/xjt/xjt.c
|
||||
|
|
|
|||
Loading…
Reference in a new issue