2006-12-09 21:33:38 +00:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1998-11-06 00:51:39 +00:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2016-02-16 02:35:43 +01:00
|
|
|
* X10 and X11 bitmap (XBM) loading and exporting file filter for GIMP.
|
1998-11-06 00:51:39 +00:00
|
|
|
* XBM code Copyright (C) 1998 Gordon Matzigkeit
|
|
|
|
*
|
|
|
|
* The XBM reading and writing code was written from scratch by Gordon
|
|
|
|
* Matzigkeit <gord@gnu.org> based on the XReadBitmapFile(3X11) manual
|
|
|
|
* page distributed with X11R6 and by staring at valid XBM files. It
|
|
|
|
* does not contain any code written for other XBM file loaders.
|
|
|
|
*
|
2009-01-17 22:28:01 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1998-11-06 00:51:39 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-17 22:28:01 +00:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1998-11-06 00:51:39 +00:00
|
|
|
* (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
|
2018-07-11 23:27:07 +02:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2009-01-17 22:28:01 +00:00
|
|
|
*/
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Release 1.0, 1998-02-04, Gordon Matzigkeit <gord@gnu.org>:
|
|
|
|
* - Load and save X10 and X11 bitmaps.
|
|
|
|
* - Allow the user to specify the C identifier prefix.
|
|
|
|
*
|
|
|
|
* TODO:
|
|
|
|
* - Parsing is very tolerant, and the algorithms are quite hairy, so
|
|
|
|
* load_image should be carefully tested to make sure there are no XBM's
|
|
|
|
* that fail.
|
|
|
|
*/
|
|
|
|
|
1999-05-29 16:35:47 +00:00
|
|
|
#include "config.h"
|
2000-01-11 15:48:00 +00:00
|
|
|
|
2003-06-13 14:37:00 +00:00
|
|
|
#include <errno.h>
|
1998-11-06 00:51:39 +00:00
|
|
|
#include <string.h>
|
2000-01-11 15:48:00 +00:00
|
|
|
|
2005-03-04 15:12:29 +00:00
|
|
|
#include <glib/gstdio.h>
|
2000-01-11 15:48:00 +00:00
|
|
|
|
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include <libgimp/gimpui.h>
|
|
|
|
|
1999-05-29 16:35:47 +00:00
|
|
|
#include "libgimp/stdplugins-intl.h"
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2000-05-01 20:22:55 +00:00
|
|
|
|
2005-08-15 22:42:34 +00:00
|
|
|
#define LOAD_PROC "file-xbm-load"
|
2024-04-13 15:10:25 +00:00
|
|
|
#define EXPORT_PROC "file-xbm-export"
|
2008-08-11 10:06:13 +00:00
|
|
|
#define PLUG_IN_BINARY "file-xbm"
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
#define MAX_COMMENT 72
|
|
|
|
#define MAX_MASK_EXT 32
|
|
|
|
#define MAX_PREFIX 64
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
|
|
|
|
typedef struct _Xbm Xbm;
|
|
|
|
typedef struct _XbmClass XbmClass;
|
|
|
|
|
|
|
|
struct _Xbm
|
|
|
|
{
|
|
|
|
GimpPlugIn parent_instance;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _XbmClass
|
|
|
|
{
|
|
|
|
GimpPlugInClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#define XBM_TYPE (xbm_get_type ())
|
2023-10-18 18:29:37 +02:00
|
|
|
#define XBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XBM_TYPE, Xbm))
|
2019-08-24 10:58:34 +02:00
|
|
|
|
|
|
|
GType xbm_get_type (void) G_GNUC_CONST;
|
|
|
|
|
2023-08-06 02:56:44 +02:00
|
|
|
static GList * xbm_query_procedures (GimpPlugIn *plug_in);
|
|
|
|
static GimpProcedure * xbm_create_procedure (GimpPlugIn *plug_in,
|
|
|
|
const gchar *name);
|
|
|
|
|
|
|
|
static GimpValueArray * xbm_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data);
|
2024-04-13 15:10:25 +00:00
|
|
|
static GimpValueArray * xbm_export (GimpProcedure *procedure,
|
2023-08-06 02:56:44 +02:00
|
|
|
GimpRunMode run_mode,
|
|
|
|
GimpImage *image,
|
|
|
|
GFile *file,
|
2024-05-06 18:38:12 +00:00
|
|
|
GimpExportOptions *options,
|
2023-08-06 02:56:44 +02:00
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data);
|
|
|
|
|
|
|
|
static GimpImage * load_image (GFile *file,
|
|
|
|
GError **error);
|
2024-04-13 15:10:25 +00:00
|
|
|
static gboolean export_image (GFile *file,
|
2023-08-06 02:56:44 +02:00
|
|
|
const gchar *prefix,
|
|
|
|
gboolean save_mask,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GObject *config,
|
|
|
|
GError **error);
|
|
|
|
static gboolean save_dialog (GimpImage *image,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GimpProcedure *procedure,
|
|
|
|
GObject *config);
|
|
|
|
|
|
|
|
static gboolean print (GOutputStream *output,
|
|
|
|
GError **error,
|
|
|
|
const gchar *format,
|
2019-08-24 10:58:34 +02:00
|
|
|
...) G_GNUC_PRINTF (3, 4);
|
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (Xbm, xbm, GIMP_TYPE_PLUG_IN)
|
|
|
|
|
|
|
|
GIMP_MAIN (XBM_TYPE)
|
2022-05-26 00:59:36 +02:00
|
|
|
DEFINE_STD_SET_I18N
|
2019-08-24 10:58:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
xbm_class_init (XbmClass *klass)
|
|
|
|
{
|
|
|
|
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
|
2008-08-18 19:08:54 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
plug_in_class->query_procedures = xbm_query_procedures;
|
|
|
|
plug_in_class->create_procedure = xbm_create_procedure;
|
2022-05-26 00:59:36 +02:00
|
|
|
plug_in_class->set_i18n = STD_SET_I18N;
|
2019-08-24 10:58:34 +02:00
|
|
|
}
|
2000-06-05 11:38:35 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
static void
|
|
|
|
xbm_init (Xbm *xbm)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2019-08-24 10:58:34 +02:00
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
static GList *
|
|
|
|
xbm_query_procedures (GimpPlugIn *plug_in)
|
|
|
|
{
|
|
|
|
GList *list = NULL;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
list = g_list_append (list, g_strdup (LOAD_PROC));
|
2024-04-13 15:10:25 +00:00
|
|
|
list = g_list_append (list, g_strdup (EXPORT_PROC));
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
return list;
|
|
|
|
}
|
2008-08-18 19:08:54 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
static GimpProcedure *
|
|
|
|
xbm_create_procedure (GimpPlugIn *plug_in,
|
|
|
|
const gchar *name)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2019-08-24 10:58:34 +02:00
|
|
|
GimpProcedure *procedure = NULL;
|
2000-05-01 20:22:55 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
if (! strcmp (name, LOAD_PROC))
|
|
|
|
{
|
2023-08-06 03:21:27 +02:00
|
|
|
procedure = gimp_load_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
|
|
|
xbm_load, NULL, NULL);
|
2019-08-24 10:58:34 +02:00
|
|
|
|
2022-07-04 22:50:53 +02:00
|
|
|
gimp_procedure_set_menu_label (procedure, _("X BitMap image"));
|
2019-08-24 10:58:34 +02:00
|
|
|
|
|
|
|
gimp_procedure_set_documentation (procedure,
|
2023-04-19 12:32:06 +00:00
|
|
|
_("Load a file in X10 or X11 bitmap "
|
|
|
|
"(XBM) file format"),
|
|
|
|
_("Load a file in X10 or X11 bitmap "
|
|
|
|
"(XBM) file format. XBM is a lossless "
|
|
|
|
"format for flat black-and-white "
|
|
|
|
"(two color indexed) images."),
|
2019-08-24 10:58:34 +02:00
|
|
|
name);
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Gordon Matzigkeit",
|
|
|
|
"Gordon Matzigkeit",
|
|
|
|
"1998");
|
|
|
|
|
|
|
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"image/x-xbitmap");
|
|
|
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"xbm,icon,bitmap");
|
|
|
|
}
|
2024-04-13 15:10:25 +00:00
|
|
|
else if (! strcmp (name, EXPORT_PROC))
|
2019-08-24 10:58:34 +02:00
|
|
|
{
|
2024-04-20 03:08:57 +00:00
|
|
|
procedure = gimp_export_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
|
|
|
FALSE, xbm_export, NULL, NULL);
|
2019-08-24 10:58:34 +02:00
|
|
|
|
|
|
|
gimp_procedure_set_image_types (procedure, "INDEXED");
|
|
|
|
|
2022-07-04 22:50:53 +02:00
|
|
|
gimp_procedure_set_menu_label (procedure, _("X BitMap image"));
|
2019-08-24 10:58:34 +02:00
|
|
|
|
|
|
|
gimp_procedure_set_documentation (procedure,
|
2023-04-19 12:32:06 +00:00
|
|
|
_("Export a file in X10 or X11 bitmap "
|
|
|
|
"(XBM) file format"),
|
|
|
|
_("X10 or X11 bitmap "
|
|
|
|
"(XBM) file format. XBM is a lossless "
|
|
|
|
"format for flat black-and-white "
|
|
|
|
"(two color indexed) images."),
|
2019-08-24 10:58:34 +02:00
|
|
|
name);
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Gordon Matzigkeit",
|
|
|
|
"Gordon Matzigkeit",
|
|
|
|
"1998");
|
|
|
|
|
2023-04-19 12:32:06 +00:00
|
|
|
gimp_file_procedure_set_format_name (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
_("XBM"));
|
2019-08-24 10:58:34 +02:00
|
|
|
gimp_file_procedure_set_handles_remote (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
TRUE);
|
|
|
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"image/x-xbitmap");
|
|
|
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"xbm,icon,bitmap");
|
|
|
|
|
2024-05-06 18:38:12 +00:00
|
|
|
gimp_export_procedure_set_capabilities (GIMP_EXPORT_PROCEDURE (procedure),
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_BITMAP |
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_ALPHA,
|
app, libgimp*, pdb, plug-ins: review and enhance MR !1549.
- Fix annotations for gimp_export_options_get_image() to make it
actually introspectable with the GimpImage being both input and
output. Even though the logic doesn't change much (the input image may
be overriden or not), it doesn't matter for introspection because
images are handled centrally by libgimp and therefore must not be
freed. Actually deleting the image from the central list of images
though remains a manual action depending on code logic, not some
automatic action to be handled by binding engines.
- Add G_GNUC_WARN_UNUSED_RESULT to gimp_export_options_get_image()
because ignoring the returned value is rarely a good idea (as you
usually want to delete the image).
- Remove gimp_export_options_new(): we don't need this constructor
because at this point, the best is to tell plug-in developers to just
pass NULL everywhere. This leaves us free to create a more useful
default constructor if needed, in the future. Main description for
GimpExportOptions has also been updated to say this.
- Add a data_destroy callback for the user data passed in
gimp_export_procedure_set_capabilities().
- Fixing annotations of 'export_options' object from pdb/pdb.pl: input
args would actually be (nullable) and would not transfer ownership
(calling code must still free the object). Return value's ownership on
the other hand is fully transfered.
- Add C and Python unit testing for GimpExportOptions and
gimp_export_options_get_image() in particular.
- Fix or improve various details.
Note that I have also considered for a long time changing the signature
of gimp_export_options_get_image() to return a boolean indicating
whether `image` had been replaced (hence needed deletion) or not. This
also meant getting rid of the GimpExportReturn enum. Right now it would
work because there are no third case, but I was considering the future
possibility that for instance we got some impossible conversion for some
future capability. I'm not sure it would ever happen; and for sure, this
is not desirable because it implies an export failure a bit late in the
workflow. But just in case, let's keep the enum return value. It does
not even make the using code that much more complicated (well just a
value comparison instead of a simple boolean test).
2024-08-17 15:06:27 +02:00
|
|
|
NULL, NULL, NULL);
|
2024-05-06 18:38:12 +00:00
|
|
|
|
2025-01-20 16:06:45 +01:00
|
|
|
gimp_procedure_add_boolean_argument (procedure, "include-comment",
|
2024-06-12 16:53:12 +00:00
|
|
|
_("_Write comment"),
|
|
|
|
_("Write a comment at the beginning of the file."),
|
|
|
|
FALSE, /* *NOT* gimp_export_comment() */
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_string_argument (procedure, "gimp-comment",
|
|
|
|
_("Co_mment"),
|
|
|
|
_("Image description (maximum 72 bytes)"),
|
|
|
|
gimp_get_default_comment (),
|
|
|
|
G_PARAM_READWRITE);
|
2019-08-24 10:58:34 +02:00
|
|
|
|
2020-06-15 23:54:09 +02:00
|
|
|
gimp_procedure_set_argument_sync (procedure, "gimp-comment",
|
|
|
|
GIMP_ARGUMENT_SYNC_PARASITE);
|
|
|
|
|
2024-06-12 16:53:12 +00:00
|
|
|
gimp_procedure_add_boolean_argument (procedure, "x10-format",
|
|
|
|
_("_X10 format bitmap"),
|
|
|
|
_("Export in X10 format"),
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_boolean_argument (procedure, "use-hot-spot",
|
|
|
|
_("Write hot spot _values"),
|
|
|
|
_("Write hotspot information"),
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_int_argument (procedure, "hot-spot-x",
|
|
|
|
_("Hot s_pot X"),
|
|
|
|
_("X coordinate of hotspot"),
|
|
|
|
0, GIMP_MAX_IMAGE_SIZE, 0,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_int_argument (procedure, "hot-spot-y",
|
|
|
|
_("Hot spot _Y"),
|
|
|
|
_("Y coordinate of hotspot"),
|
|
|
|
0, GIMP_MAX_IMAGE_SIZE, 0,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_string_argument (procedure, "prefix",
|
|
|
|
_("I_dentifier prefix"),
|
|
|
|
_("Identifier prefix [determined from filename]"),
|
|
|
|
"bitmap",
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_boolean_argument (procedure, "write-mask",
|
|
|
|
_("Write extra mask _file"),
|
|
|
|
_("Write extra mask file"),
|
|
|
|
FALSE,
|
|
|
|
G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
gimp_procedure_add_string_argument (procedure, "mask-suffix",
|
|
|
|
_("Mas_k file extensions"),
|
|
|
|
_("Suffix of the mask file"),
|
|
|
|
"-mask",
|
|
|
|
G_PARAM_READWRITE);
|
2019-08-24 10:58:34 +02:00
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
return procedure;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpValueArray *
|
2023-08-06 02:56:44 +02:00
|
|
|
xbm_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data)
|
2019-08-24 10:58:34 +02:00
|
|
|
{
|
|
|
|
GimpValueArray *return_vals;
|
|
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
|
|
|
GimpImage *image;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
gegl_init (NULL, NULL);
|
|
|
|
|
2019-09-11 21:48:34 +02:00
|
|
|
image = load_image (file, &error);
|
2019-08-24 10:58:34 +02:00
|
|
|
|
|
|
|
if (! image)
|
|
|
|
return gimp_procedure_new_return_values (procedure, status, error);
|
|
|
|
|
|
|
|
return_vals = gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_SUCCESS,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
|
|
|
|
|
|
|
return return_vals;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2000-06-05 11:38:35 +00:00
|
|
|
static gchar *
|
2019-10-07 20:09:08 +02:00
|
|
|
init_prefix (GFile *file,
|
|
|
|
GObject *config)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2000-01-25 17:46:56 +00:00
|
|
|
gchar *p, *prefix;
|
2019-09-11 21:48:34 +02:00
|
|
|
gint len;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2021-10-01 22:58:14 +02:00
|
|
|
prefix = g_file_get_basename (file);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
g_object_set (config,
|
|
|
|
"prefix", NULL,
|
|
|
|
NULL);
|
2001-07-29 09:43:09 +00:00
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
{
|
2005-08-09 20:49:55 +00:00
|
|
|
/* Strip any extension. */
|
2001-07-29 09:43:09 +00:00
|
|
|
p = strrchr (prefix, '.');
|
|
|
|
if (p && p != prefix)
|
|
|
|
len = MIN (MAX_PREFIX, p - prefix);
|
|
|
|
else
|
|
|
|
len = MAX_PREFIX;
|
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
prefix[len] = '\0';
|
|
|
|
|
|
|
|
g_object_set (config,
|
|
|
|
"prefix", prefix,
|
|
|
|
NULL);
|
2001-07-29 09:43:09 +00:00
|
|
|
}
|
2000-06-05 11:38:35 +00:00
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
return prefix;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
static GimpValueArray *
|
2024-04-13 15:10:25 +00:00
|
|
|
xbm_export (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GimpImage *image,
|
|
|
|
GFile *file,
|
2024-05-06 18:38:12 +00:00
|
|
|
GimpExportOptions *options,
|
2024-04-13 15:10:25 +00:00
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2019-10-07 20:09:08 +02:00
|
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
2024-04-30 04:25:51 +00:00
|
|
|
GimpExportReturn export = GIMP_EXPORT_IGNORE;
|
2024-04-30 13:50:24 +00:00
|
|
|
GList *drawables;
|
2019-10-07 20:09:08 +02:00
|
|
|
gchar *mask_basename = NULL;
|
|
|
|
GError *error = NULL;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2012-11-18 23:22:07 +01:00
|
|
|
gegl_init (NULL, NULL);
|
2003-03-25 16:38:19 +00:00
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE ||
|
|
|
|
run_mode == GIMP_RUN_WITH_LAST_VALS)
|
2019-08-24 10:58:34 +02:00
|
|
|
{
|
|
|
|
/* Always override the prefix with the filename. */
|
2019-10-07 20:09:08 +02:00
|
|
|
mask_basename = g_strdup (init_prefix (file, G_OBJECT (config)));
|
2019-08-24 10:58:34 +02:00
|
|
|
}
|
2008-10-20 06:04:39 +00:00
|
|
|
|
2024-05-06 18:38:12 +00:00
|
|
|
export = gimp_export_options_get_image (options, &image);
|
2024-07-14 20:12:57 +00:00
|
|
|
drawables = gimp_image_list_layers (image);
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
|
|
{
|
|
|
|
GimpParasite *parasite;
|
2008-10-20 06:04:39 +00:00
|
|
|
|
2024-07-14 20:12:57 +00:00
|
|
|
gimp_ui_init (PLUG_IN_BINARY);
|
2019-08-24 10:58:34 +02:00
|
|
|
parasite = gimp_image_get_parasite (image, "hot-spot");
|
|
|
|
|
|
|
|
if (parasite)
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
2021-01-30 00:20:34 +01:00
|
|
|
gchar *parasite_data;
|
|
|
|
guint32 parasite_size;
|
|
|
|
gint x, y;
|
2000-03-04 00:24:39 +00:00
|
|
|
|
2021-01-30 00:20:34 +01:00
|
|
|
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)
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
2019-10-07 20:09:08 +02:00
|
|
|
g_object_set (config,
|
|
|
|
"use-hot-spot", TRUE,
|
|
|
|
"hot-spot-x", x,
|
|
|
|
"hot-spot-y", y,
|
|
|
|
NULL);
|
2008-10-20 06:04:39 +00:00
|
|
|
}
|
2000-03-05 00:06:11 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
gimp_parasite_free (parasite);
|
2021-01-30 00:20:34 +01:00
|
|
|
g_free (parasite_data);
|
2008-10-20 06:04:39 +00:00
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2024-04-30 13:50:24 +00:00
|
|
|
if (! save_dialog (image, drawables->data, procedure, G_OBJECT (config)))
|
2019-10-07 20:09:08 +02:00
|
|
|
status = GIMP_PDB_CANCEL;
|
2019-08-24 10:58:34 +02:00
|
|
|
}
|
2008-10-20 06:04:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
|
|
{
|
2019-10-07 20:09:08 +02:00
|
|
|
GFile *mask_file;
|
|
|
|
GFile *dir;
|
|
|
|
gchar *mask_prefix;
|
|
|
|
gchar *mask_ext;
|
|
|
|
gchar *prefix;
|
|
|
|
gchar *temp;
|
|
|
|
gboolean write_mask;
|
|
|
|
|
|
|
|
g_object_get (config,
|
|
|
|
"prefix", &prefix,
|
|
|
|
"mask-suffix", &mask_ext,
|
|
|
|
"write-mask", &write_mask,
|
|
|
|
NULL);
|
2008-10-20 06:04:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
dir = g_file_get_parent (file);
|
2019-10-07 20:09:08 +02:00
|
|
|
temp = g_strdup_printf ("%s%s.xbm", mask_basename, mask_ext);
|
2008-10-20 06:04:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
mask_file = g_file_get_child (dir, temp);
|
2008-10-20 06:04:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
g_free (temp);
|
|
|
|
g_object_unref (dir);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
/* Change any non-alphanumeric prefix characters to underscores. */
|
2019-10-07 20:09:08 +02:00
|
|
|
for (temp = prefix; *temp; temp++)
|
2019-08-24 10:58:34 +02:00
|
|
|
if (! g_ascii_isalnum (*temp))
|
|
|
|
*temp = '_';
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
g_object_set (config,
|
|
|
|
"prefix", prefix,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
mask_prefix = g_strdup_printf ("%s%s", prefix, mask_ext);
|
2005-08-09 20:49:55 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
for (temp = mask_prefix; *temp; temp++)
|
|
|
|
if (! g_ascii_isalnum (*temp))
|
|
|
|
*temp = '_';
|
2008-10-20 06:04:39 +00:00
|
|
|
|
2024-04-13 15:10:25 +00:00
|
|
|
if (! export_image (file,
|
|
|
|
prefix,
|
|
|
|
FALSE,
|
2024-04-30 13:50:24 +00:00
|
|
|
image, drawables->data,
|
2024-04-13 15:10:25 +00:00
|
|
|
G_OBJECT (config),
|
|
|
|
&error)
|
2019-10-07 20:09:08 +02:00
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
(write_mask &&
|
2024-04-13 15:10:25 +00:00
|
|
|
! export_image (mask_file,
|
|
|
|
mask_prefix,
|
|
|
|
TRUE,
|
2024-04-30 13:50:24 +00:00
|
|
|
image, drawables->data,
|
2024-04-13 15:10:25 +00:00
|
|
|
G_OBJECT (config),
|
|
|
|
&error)))
|
2019-08-24 10:58:34 +02:00
|
|
|
{
|
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
2008-10-20 06:04:39 +00:00
|
|
|
}
|
1999-10-14 02:11:52 +00:00
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
g_free (prefix);
|
2019-08-24 10:58:34 +02:00
|
|
|
g_free (mask_prefix);
|
2019-10-07 20:09:08 +02:00
|
|
|
g_free (mask_ext);
|
2019-08-24 10:58:34 +02:00
|
|
|
g_free (mask_basename);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
g_object_unref (mask_file);
|
2008-08-18 19:08:54 +00:00
|
|
|
}
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
if (export == GIMP_EXPORT_EXPORT)
|
2024-04-30 13:50:24 +00:00
|
|
|
gimp_image_delete (image);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2024-04-30 13:50:24 +00:00
|
|
|
g_list_free (drawables);
|
2019-08-24 10:58:34 +02:00
|
|
|
return gimp_procedure_new_return_values (procedure, status, error);
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Return the value of a digit. */
|
|
|
|
static gint
|
2003-11-06 15:27:05 +00:00
|
|
|
getval (gint c,
|
2008-10-20 06:04:39 +00:00
|
|
|
gint base)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2003-07-03 13:26:06 +00:00
|
|
|
const gchar *digits = "0123456789abcdefABCDEF";
|
|
|
|
gint val;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Include uppercase hex digits. */
|
|
|
|
if (base == 16)
|
|
|
|
base = 22;
|
|
|
|
|
|
|
|
/* Find a match. */
|
|
|
|
for (val = 0; val < base; val ++)
|
|
|
|
if (c == digits[val])
|
|
|
|
return (val < 16) ? val : (val - 6);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-03-04 00:24:39 +00:00
|
|
|
/* Get a comment */
|
|
|
|
static gchar *
|
|
|
|
fgetcomment (FILE *fp)
|
|
|
|
{
|
|
|
|
GString *str = NULL;
|
|
|
|
gint comment, c;
|
|
|
|
|
|
|
|
comment = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (comment)
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
if (c == '*')
|
|
|
|
{
|
|
|
|
/* In a comment, with potential to leave. */
|
|
|
|
comment = 1;
|
|
|
|
}
|
|
|
|
else if (comment == 1 && c == '/')
|
|
|
|
{
|
|
|
|
gchar *retval;
|
|
|
|
|
|
|
|
/* Leaving a comment. */
|
|
|
|
comment = 0;
|
|
|
|
|
|
|
|
retval = g_strstrip (g_strdup (str->str));
|
|
|
|
g_string_free (str, TRUE);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* In a comment, with no potential to leave. */
|
|
|
|
comment = 2;
|
|
|
|
g_string_append_c (str, c);
|
|
|
|
}
|
|
|
|
}
|
2000-03-04 00:24:39 +00:00
|
|
|
else
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
/* Not in a comment. */
|
|
|
|
if (c == '/')
|
|
|
|
{
|
|
|
|
/* Potential to enter a comment. */
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (c == '*')
|
|
|
|
{
|
|
|
|
/* Entered a comment, with no potential to leave. */
|
|
|
|
comment = 2;
|
|
|
|
str = g_string_new (NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* put everything back and return */
|
|
|
|
ungetc (c, fp);
|
|
|
|
c = '/';
|
|
|
|
ungetc (c, fp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (c != EOF && g_ascii_isspace (c))
|
|
|
|
{
|
|
|
|
/* Skip leading whitespace */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2000-03-04 00:24:39 +00:00
|
|
|
}
|
|
|
|
while (comment && c != EOF);
|
|
|
|
|
|
|
|
if (str)
|
|
|
|
g_string_free (str, TRUE);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-11-06 00:51:39 +00:00
|
|
|
/* Same as fgetc, but skip C-style comments and insert whitespace. */
|
|
|
|
static gint
|
|
|
|
cpp_fgetc (FILE *fp)
|
|
|
|
{
|
2000-01-25 17:46:56 +00:00
|
|
|
gint comment, c;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* FIXME: insert whitespace as advertised. */
|
|
|
|
comment = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (comment)
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
if (c == '*')
|
|
|
|
/* In a comment, with potential to leave. */
|
|
|
|
comment = 1;
|
|
|
|
else if (comment == 1 && c == '/')
|
|
|
|
/* Leaving a comment. */
|
|
|
|
comment = 0;
|
|
|
|
else
|
|
|
|
/* In a comment, with no potential to leave. */
|
|
|
|
comment = 2;
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
else
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
/* Not in a comment. */
|
|
|
|
if (c == '/')
|
|
|
|
{
|
|
|
|
/* Potential to enter a comment. */
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (c == '*')
|
|
|
|
/* Entered a comment, with no potential to leave. */
|
|
|
|
comment = 2;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Just a slash in the open. */
|
|
|
|
ungetc (c, fp);
|
|
|
|
c = '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
while (comment && c != EOF);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Match a string with a file. */
|
|
|
|
static gint
|
2008-09-17 08:37:24 +00:00
|
|
|
match (FILE *fp,
|
|
|
|
const gchar *s)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2000-01-25 17:46:56 +00:00
|
|
|
gint c;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (c == *s)
|
2008-10-20 06:04:39 +00:00
|
|
|
s ++;
|
1998-11-06 00:51:39 +00:00
|
|
|
else
|
2008-10-20 06:04:39 +00:00
|
|
|
break;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
while (c != EOF && *s);
|
|
|
|
|
|
|
|
if (!*s)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (c != EOF)
|
|
|
|
ungetc (c, fp);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Read the next integer from the file, skipping all non-integers. */
|
|
|
|
static gint
|
|
|
|
get_int (FILE *fp)
|
|
|
|
{
|
|
|
|
int digval, base, val, c;
|
|
|
|
|
|
|
|
do
|
|
|
|
c = cpp_fgetc (fp);
|
2003-11-26 19:20:24 +00:00
|
|
|
while (c != EOF && ! g_ascii_isdigit (c));
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
if (c == EOF)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Check for the base. */
|
|
|
|
if (c == '0')
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (c == 'x' || c == 'X')
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
base = 16;
|
|
|
|
}
|
2003-11-26 19:20:24 +00:00
|
|
|
else if (g_ascii_isdigit (c))
|
2008-10-20 06:04:39 +00:00
|
|
|
base = 8;
|
1998-11-06 00:51:39 +00:00
|
|
|
else
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
ungetc (c, fp);
|
|
|
|
return 0;
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
base = 10;
|
|
|
|
|
|
|
|
val = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
digval = getval (c, base);
|
|
|
|
if (digval == -1)
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
ungetc (c, fp);
|
|
|
|
break;
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
val *= base;
|
|
|
|
val += digval;
|
|
|
|
c = fgetc (fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
static GimpImage *
|
2019-09-11 21:48:34 +02:00
|
|
|
load_image (GFile *file,
|
|
|
|
GError **error)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2019-10-07 20:09:08 +02:00
|
|
|
FILE *fp;
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
|
|
|
guchar *data;
|
|
|
|
gint intbits;
|
|
|
|
gint width = 0;
|
|
|
|
gint height = 0;
|
|
|
|
gint x_hot = 0;
|
|
|
|
gint y_hot = 0;
|
|
|
|
gint c, i, j, k;
|
|
|
|
gint tileheight, rowoffset;
|
|
|
|
gchar *comment;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2005-02-13 00:11:24 +00:00
|
|
|
const guchar cmap[] =
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2008-10-20 06:04:39 +00:00
|
|
|
0x00, 0x00, 0x00, /* black */
|
|
|
|
0xff, 0xff, 0xff /* white */
|
1998-11-06 00:51:39 +00:00
|
|
|
};
|
|
|
|
|
2014-07-23 16:39:00 +02:00
|
|
|
gimp_progress_init_printf (_("Opening '%s'"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
2014-07-23 16:39:00 +02:00
|
|
|
|
2021-10-01 22:58:14 +02:00
|
|
|
fp = g_fopen (g_file_peek_path (file), "rb");
|
2019-09-11 21:48:34 +02:00
|
|
|
|
2008-08-18 19:08:54 +00:00
|
|
|
if (! fp)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2008-08-18 19:08:54 +00:00
|
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
|
|
_("Could not open '%s' for reading: %s"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file), g_strerror (errno));
|
2019-08-24 10:58:34 +02:00
|
|
|
return NULL;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2000-03-04 00:24:39 +00:00
|
|
|
comment = fgetcomment (fp);
|
|
|
|
|
1998-11-06 00:51:39 +00:00
|
|
|
/* Loosely parse the header */
|
|
|
|
intbits = height = width = 0;
|
|
|
|
c = ' ';
|
|
|
|
do
|
|
|
|
{
|
2003-11-26 19:20:24 +00:00
|
|
|
if (g_ascii_isspace (c))
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
if (match (fp, "char"))
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (g_ascii_isspace (c))
|
|
|
|
{
|
|
|
|
intbits = 8;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (match (fp, "short"))
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (g_ascii_isspace (c))
|
|
|
|
{
|
|
|
|
intbits = 16;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
if (c == '_')
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
if (match (fp, "width"))
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (g_ascii_isspace (c))
|
|
|
|
{
|
|
|
|
width = get_int (fp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (match (fp, "height"))
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (g_ascii_isspace (c))
|
|
|
|
{
|
|
|
|
height = get_int (fp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (match (fp, "x_hot"))
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (g_ascii_isspace (c))
|
|
|
|
{
|
|
|
|
x_hot = get_int (fp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (match (fp, "y_hot"))
|
|
|
|
{
|
|
|
|
c = fgetc (fp);
|
|
|
|
if (g_ascii_isspace (c))
|
|
|
|
{
|
|
|
|
y_hot = get_int (fp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
c = cpp_fgetc (fp);
|
|
|
|
}
|
|
|
|
while (c != '{' && c != EOF);
|
|
|
|
|
|
|
|
if (c == EOF)
|
|
|
|
{
|
2003-11-15 13:53:33 +00:00
|
|
|
g_message (_("'%s':\nCould not read header (ftell == %ld)"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file), ftell (fp));
|
2018-08-23 10:05:34 +02:00
|
|
|
fclose (fp);
|
2019-08-24 10:58:34 +02:00
|
|
|
return NULL;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 23:32:15 +00:00
|
|
|
if (width <= 0)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2004-01-19 03:06:04 +00:00
|
|
|
g_message (_("'%s':\nNo image width specified"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
2018-08-23 10:05:34 +02:00
|
|
|
fclose (fp);
|
2019-08-24 10:58:34 +02:00
|
|
|
return NULL;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 23:32:15 +00:00
|
|
|
if (width > GIMP_MAX_IMAGE_SIZE)
|
|
|
|
{
|
|
|
|
g_message (_("'%s':\nImage width is larger than GIMP can handle"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
2018-08-23 10:05:34 +02:00
|
|
|
fclose (fp);
|
2019-08-24 10:58:34 +02:00
|
|
|
return NULL;
|
2007-07-04 23:32:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (height <= 0)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2004-01-19 03:06:04 +00:00
|
|
|
g_message (_("'%s':\nNo image height specified"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
2018-08-23 10:05:34 +02:00
|
|
|
fclose (fp);
|
2019-08-24 10:58:34 +02:00
|
|
|
return NULL;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 23:32:15 +00:00
|
|
|
if (height > GIMP_MAX_IMAGE_SIZE)
|
|
|
|
{
|
|
|
|
g_message (_("'%s':\nImage height is larger than GIMP can handle"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
2018-08-23 10:05:34 +02:00
|
|
|
fclose (fp);
|
2019-08-24 10:58:34 +02:00
|
|
|
return NULL;
|
2007-07-04 23:32:15 +00:00
|
|
|
}
|
|
|
|
|
1998-11-06 00:51:39 +00:00
|
|
|
if (intbits == 0)
|
|
|
|
{
|
2004-01-19 03:06:04 +00:00
|
|
|
g_message (_("'%s':\nNo image data type specified"),
|
2019-09-11 21:48:34 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
2018-08-23 10:05:34 +02:00
|
|
|
fclose (fp);
|
2019-08-24 10:58:34 +02:00
|
|
|
return NULL;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
image = gimp_image_new (width, height, GIMP_INDEXED);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2000-03-04 00:24:39 +00:00
|
|
|
if (comment)
|
|
|
|
{
|
2000-05-26 22:28:40 +00:00
|
|
|
GimpParasite *parasite;
|
2000-03-04 00:24:39 +00:00
|
|
|
|
2000-05-26 22:28:40 +00:00
|
|
|
parasite = gimp_parasite_new ("gimp-comment",
|
2008-10-20 06:04:39 +00:00
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
strlen (comment) + 1, (gpointer) comment);
|
2019-08-24 10:58:34 +02:00
|
|
|
gimp_image_attach_parasite (image, parasite);
|
2000-05-26 22:28:40 +00:00
|
|
|
gimp_parasite_free (parasite);
|
2000-03-04 00:24:39 +00:00
|
|
|
|
|
|
|
g_free (comment);
|
|
|
|
}
|
|
|
|
|
|
|
|
x_hot = CLAMP (x_hot, 0, width);
|
|
|
|
y_hot = CLAMP (y_hot, 0, height);
|
|
|
|
|
|
|
|
if (x_hot > 0 || y_hot > 0)
|
|
|
|
{
|
2000-05-26 22:28:40 +00:00
|
|
|
GimpParasite *parasite;
|
|
|
|
gchar *str;
|
2000-03-04 00:24:39 +00:00
|
|
|
|
|
|
|
str = g_strdup_printf ("%d %d", x_hot, y_hot);
|
2000-05-26 22:28:40 +00:00
|
|
|
parasite = gimp_parasite_new ("hot-spot",
|
2008-10-20 06:04:39 +00:00
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
strlen (str) + 1, (gpointer) str);
|
2000-03-04 00:24:39 +00:00
|
|
|
g_free (str);
|
2019-08-24 10:58:34 +02:00
|
|
|
gimp_image_attach_parasite (image, parasite);
|
2000-05-26 22:28:40 +00:00
|
|
|
gimp_parasite_free (parasite);
|
2000-03-04 00:24:39 +00:00
|
|
|
}
|
|
|
|
|
1998-11-06 00:51:39 +00:00
|
|
|
/* Set a black-and-white colormap. */
|
2024-09-23 15:17:04 +02:00
|
|
|
gimp_palette_set_colormap (gimp_image_get_palette (image), babl_format ("R'G'B' u8"), (guint8 *) cmap, 2 * 3);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
layer = gimp_layer_new (image,
|
|
|
|
_("Background"),
|
|
|
|
width, height,
|
|
|
|
GIMP_INDEXED_IMAGE,
|
|
|
|
100,
|
|
|
|
gimp_image_get_default_new_layer_mode (image));
|
|
|
|
gimp_image_insert_layer (image, layer, NULL, 0);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Allocate the data. */
|
|
|
|
tileheight = gimp_tile_height ();
|
|
|
|
data = (guchar *) g_malloc (width * tileheight);
|
|
|
|
|
|
|
|
for (i = 0; i < height; i += tileheight)
|
|
|
|
{
|
|
|
|
tileheight = MIN (tileheight, height - i);
|
|
|
|
|
|
|
|
/* Parse the data from the file */
|
|
|
|
for (j = 0; j < tileheight; j ++)
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
/* Read each row. */
|
|
|
|
rowoffset = j * width;
|
|
|
|
for (k = 0; k < width; k ++)
|
|
|
|
{
|
|
|
|
/* Expand each integer into INTBITS pixels. */
|
|
|
|
if (k % intbits == 0)
|
|
|
|
{
|
|
|
|
c = get_int (fp);
|
|
|
|
|
|
|
|
/* Flip all the bits so that 1's become black and
|
1998-11-06 00:51:39 +00:00
|
|
|
0's become white. */
|
2008-10-20 06:04:39 +00:00
|
|
|
c ^= 0xffff;
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2008-10-20 06:04:39 +00:00
|
|
|
data[rowoffset + k] = c & 1;
|
|
|
|
c >>= 1;
|
|
|
|
}
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Put the data into the image. */
|
2012-11-18 23:22:07 +01:00
|
|
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, i, width, tileheight), 0,
|
|
|
|
NULL, data, GEGL_AUTO_ROWSTRIDE);
|
|
|
|
|
1998-11-06 00:51:39 +00:00
|
|
|
gimp_progress_update ((double) (i + tileheight) / (double) height);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (data);
|
2012-11-18 23:22:07 +01:00
|
|
|
g_object_unref (buffer);
|
1998-11-06 00:51:39 +00:00
|
|
|
fclose (fp);
|
2000-01-25 17:46:56 +00:00
|
|
|
|
2012-11-18 23:22:07 +01:00
|
|
|
gimp_progress_update (1.0);
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
return image;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2000-06-05 11:38:35 +00:00
|
|
|
static gboolean
|
2024-04-13 15:10:25 +00:00
|
|
|
export_image (GFile *file,
|
|
|
|
const gchar *prefix,
|
|
|
|
gboolean save_mask,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GObject *config,
|
|
|
|
GError **error)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2014-10-05 18:06:03 +02:00
|
|
|
GOutputStream *output;
|
|
|
|
GeglBuffer *buffer;
|
2018-11-27 12:27:20 +01:00
|
|
|
GCancellable *cancellable;
|
2014-10-05 18:06:03 +02:00
|
|
|
gint width, height, colors, dark;
|
|
|
|
gint intbits, lineints, need_comma, nints, rowoffset, tileheight;
|
|
|
|
gint c, i, j, k, thisbit;
|
|
|
|
gboolean has_alpha;
|
|
|
|
gint bpp;
|
|
|
|
guchar *data = NULL;
|
|
|
|
guchar *cmap;
|
|
|
|
const gchar *intfmt;
|
2019-10-10 01:32:28 +02:00
|
|
|
gboolean config_save_comment;
|
2019-10-07 20:09:08 +02:00
|
|
|
gchar *config_comment;
|
|
|
|
gint config_x10_format;
|
|
|
|
gint config_use_hot;
|
|
|
|
gint config_x_hot;
|
|
|
|
gint config_y_hot;
|
|
|
|
|
|
|
|
g_object_get (config,
|
2025-01-20 16:06:45 +01:00
|
|
|
"include-comment", &config_save_comment,
|
|
|
|
"gimp-comment", &config_comment,
|
|
|
|
"x10-format", &config_x10_format,
|
|
|
|
"use-hot-spot", &config_use_hot,
|
|
|
|
"hot-spot-x", &config_x_hot,
|
|
|
|
"hot-spot-y", &config_y_hot,
|
2019-10-07 20:09:08 +02:00
|
|
|
NULL);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2005-08-09 20:49:55 +00:00
|
|
|
#if 0
|
|
|
|
if (save_mask)
|
|
|
|
g_printerr ("%s: save_mask '%s'\n", G_STRFUNC, prefix);
|
|
|
|
else
|
|
|
|
g_printerr ("%s: save_image '%s'\n", G_STRFUNC, prefix);
|
|
|
|
#endif
|
|
|
|
|
2024-09-23 15:17:04 +02:00
|
|
|
cmap = gimp_palette_get_colormap (gimp_image_get_palette (image), babl_format ("R'G'B' u8"), &colors, NULL);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
if (! gimp_drawable_is_indexed (drawable) || colors > 2)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
|
|
|
/* The image is not black-and-white. */
|
2016-02-16 02:35:43 +01:00
|
|
|
g_message (_("The image which you are trying to export as "
|
2008-10-20 06:04:39 +00:00
|
|
|
"an XBM contains more than two colors.\n\n"
|
|
|
|
"Please convert it to a black and white "
|
|
|
|
"(1-bit) indexed image and try again."));
|
2012-11-18 23:22:07 +01:00
|
|
|
g_free (cmap);
|
2000-06-05 11:38:35 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
has_alpha = gimp_drawable_has_alpha (drawable);
|
2000-06-05 11:38:35 +00:00
|
|
|
|
2008-08-18 19:08:54 +00:00
|
|
|
if (! has_alpha && save_mask)
|
2000-06-05 11:38:35 +00:00
|
|
|
{
|
|
|
|
g_message (_("You cannot save a cursor mask for an image\n"
|
2008-10-20 06:04:39 +00:00
|
|
|
"which has no alpha channel."));
|
1998-11-06 00:51:39 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2019-08-24 10:58:34 +02:00
|
|
|
buffer = gimp_drawable_get_buffer (drawable);
|
2012-11-18 23:22:07 +01:00
|
|
|
width = gegl_buffer_get_width (buffer);
|
|
|
|
height = gegl_buffer_get_height (buffer);
|
2021-04-06 14:28:40 +02:00
|
|
|
bpp = gimp_drawable_get_bpp (drawable);
|
2000-06-05 11:38:35 +00:00
|
|
|
|
1998-11-06 00:51:39 +00:00
|
|
|
/* Figure out which color is black, and which is white. */
|
|
|
|
dark = 0;
|
|
|
|
if (colors > 1)
|
|
|
|
{
|
2000-06-05 11:38:35 +00:00
|
|
|
gint first, second;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Maybe the second color is darker than the first. */
|
2000-06-05 11:38:35 +00:00
|
|
|
first = (cmap[0] * cmap[0]) + (cmap[1] * cmap[1]) + (cmap[2] * cmap[2]);
|
1998-11-06 00:51:39 +00:00
|
|
|
second = (cmap[3] * cmap[3]) + (cmap[4] * cmap[4]) + (cmap[5] * cmap[5]);
|
|
|
|
|
|
|
|
if (second < first)
|
2008-10-20 06:04:39 +00:00
|
|
|
dark = 1;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2016-02-16 02:35:43 +01:00
|
|
|
gimp_progress_init_printf (_("Exporting '%s'"),
|
2014-10-05 18:06:03 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
2014-07-23 16:39:00 +02:00
|
|
|
|
2014-10-05 18:06:03 +02:00
|
|
|
output = G_OUTPUT_STREAM (g_file_replace (file,
|
|
|
|
NULL, FALSE, G_FILE_CREATE_NONE,
|
|
|
|
NULL, error));
|
|
|
|
if (output)
|
|
|
|
{
|
|
|
|
GOutputStream *buffered;
|
|
|
|
|
|
|
|
buffered = g_buffered_output_stream_new (output);
|
|
|
|
g_object_unref (output);
|
|
|
|
|
|
|
|
output = buffered;
|
|
|
|
}
|
|
|
|
else
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Maybe write the image comment. */
|
2019-10-10 01:32:28 +02:00
|
|
|
if (config_save_comment && config_comment && *config_comment)
|
2014-10-05 18:06:03 +02:00
|
|
|
{
|
2019-10-07 20:09:08 +02:00
|
|
|
if (! print (output, error, "/* %s */\n", config_comment))
|
2014-10-05 18:06:03 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Write out the image height and width. */
|
2014-10-05 18:06:03 +02:00
|
|
|
if (! print (output, error, "#define %s_width %d\n", prefix, width) ||
|
|
|
|
! print (output, error, "#define %s_height %d\n", prefix, height))
|
|
|
|
goto fail;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Write out the hotspot, if any. */
|
2019-10-07 20:09:08 +02:00
|
|
|
if (config_use_hot)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
2014-10-05 18:06:03 +02:00
|
|
|
if (! print (output, error,
|
2019-10-07 20:09:08 +02:00
|
|
|
"#define %s_x_hot %d\n", prefix, config_x_hot) ||
|
2014-10-05 18:06:03 +02:00
|
|
|
! print (output, error,
|
2019-10-07 20:09:08 +02:00
|
|
|
"#define %s_y_hot %d\n", prefix, config_y_hot))
|
2014-10-05 18:06:03 +02:00
|
|
|
goto fail;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now write the actual data. */
|
2019-10-07 20:09:08 +02:00
|
|
|
if (config_x10_format)
|
1998-11-06 00:51:39 +00:00
|
|
|
{
|
|
|
|
/* We can fit 9 hex shorts on a single line. */
|
|
|
|
lineints = 9;
|
|
|
|
intbits = 16;
|
|
|
|
intfmt = " 0x%04x";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* We can fit 12 hex chars on a single line. */
|
|
|
|
lineints = 12;
|
|
|
|
intbits = 8;
|
|
|
|
intfmt = " 0x%02x";
|
|
|
|
}
|
|
|
|
|
2014-10-05 18:06:03 +02:00
|
|
|
if (! print (output, error,
|
|
|
|
"static %s %s_bits[] = {\n ",
|
2019-10-07 20:09:08 +02:00
|
|
|
config_x10_format ? "unsigned short" : "unsigned char", prefix))
|
2014-10-05 18:06:03 +02:00
|
|
|
goto fail;
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Allocate a new set of pixels. */
|
|
|
|
tileheight = gimp_tile_height ();
|
2000-06-05 11:38:35 +00:00
|
|
|
data = (guchar *) g_malloc (width * tileheight * bpp);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
/* Write out the integers. */
|
|
|
|
need_comma = 0;
|
|
|
|
nints = 0;
|
|
|
|
for (i = 0; i < height; i += tileheight)
|
|
|
|
{
|
|
|
|
/* Get a horizontal slice of the image. */
|
|
|
|
tileheight = MIN (tileheight, height - i);
|
2012-11-18 23:22:07 +01:00
|
|
|
|
|
|
|
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, i, width, tileheight), 1.0,
|
|
|
|
NULL, data,
|
|
|
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
for (j = 0; j < tileheight; j ++)
|
2008-10-20 06:04:39 +00:00
|
|
|
{
|
|
|
|
/* Write out a row at a time. */
|
|
|
|
rowoffset = j * width * bpp;
|
|
|
|
c = 0;
|
|
|
|
thisbit = 0;
|
|
|
|
|
|
|
|
for (k = 0; k < width * bpp; k += bpp)
|
|
|
|
{
|
|
|
|
if (k != 0 && thisbit == intbits)
|
|
|
|
{
|
|
|
|
/* Output a completed integer. */
|
|
|
|
if (need_comma)
|
2014-10-05 18:06:03 +02:00
|
|
|
{
|
|
|
|
if (! print (output, error, ","))
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2008-10-20 06:04:39 +00:00
|
|
|
need_comma = 1;
|
|
|
|
|
|
|
|
/* Maybe start a new line. */
|
|
|
|
if (nints ++ >= lineints)
|
|
|
|
{
|
|
|
|
nints = 1;
|
2014-10-05 18:06:03 +02:00
|
|
|
|
|
|
|
if (! print (output, error, "\n "))
|
|
|
|
goto fail;
|
2008-10-20 06:04:39 +00:00
|
|
|
}
|
2014-10-05 18:06:03 +02:00
|
|
|
|
|
|
|
if (! print (output, error, intfmt, c))
|
|
|
|
goto fail;
|
2008-10-20 06:04:39 +00:00
|
|
|
|
|
|
|
/* Start a new integer. */
|
|
|
|
c = 0;
|
|
|
|
thisbit = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pack INTBITS pixels into an integer. */
|
|
|
|
if (save_mask)
|
|
|
|
{
|
|
|
|
c |= ((data[rowoffset + k + 1] < 128) ? 0 : 1) << (thisbit ++);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (has_alpha && (data[rowoffset + k + 1] < 128))
|
|
|
|
c |= 0 << (thisbit ++);
|
|
|
|
else
|
|
|
|
c |= ((data[rowoffset + k] == dark) ? 1 : 0) << (thisbit ++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thisbit != 0)
|
|
|
|
{
|
|
|
|
/* Write out the last oddball int. */
|
|
|
|
if (need_comma)
|
2014-10-05 18:06:03 +02:00
|
|
|
{
|
|
|
|
if (! print (output, error, ","))
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2008-10-20 06:04:39 +00:00
|
|
|
need_comma = 1;
|
|
|
|
|
|
|
|
/* Maybe start a new line. */
|
|
|
|
if (nints ++ == lineints)
|
|
|
|
{
|
|
|
|
nints = 1;
|
2014-10-05 18:06:03 +02:00
|
|
|
|
|
|
|
if (! print (output, error, "\n "))
|
|
|
|
goto fail;
|
2008-10-20 06:04:39 +00:00
|
|
|
}
|
2014-10-05 18:06:03 +02:00
|
|
|
|
|
|
|
if (! print (output, error, intfmt, c))
|
|
|
|
goto fail;
|
2008-10-20 06:04:39 +00:00
|
|
|
}
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
|
|
|
gimp_progress_update ((double) (i + tileheight) / (double) height);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write the trailer. */
|
2014-10-05 18:06:03 +02:00
|
|
|
if (! print (output, error, " };\n"))
|
|
|
|
goto fail;
|
2012-11-18 23:22:07 +01:00
|
|
|
|
2014-10-05 18:06:03 +02:00
|
|
|
if (! g_output_stream_close (output, NULL, error))
|
|
|
|
goto fail;
|
2008-08-18 19:08:54 +00:00
|
|
|
|
2013-01-16 18:48:13 -05:00
|
|
|
g_free (data);
|
2014-10-05 18:06:03 +02:00
|
|
|
g_object_unref (buffer);
|
|
|
|
g_object_unref (output);
|
2013-01-16 18:48:13 -05:00
|
|
|
|
2012-11-18 23:22:07 +01:00
|
|
|
gimp_progress_update (1.0);
|
|
|
|
|
1998-11-06 00:51:39 +00:00
|
|
|
return TRUE;
|
2014-10-05 18:06:03 +02:00
|
|
|
|
|
|
|
fail:
|
|
|
|
|
2018-11-27 12:27:20 +01:00
|
|
|
cancellable = g_cancellable_new ();
|
|
|
|
g_cancellable_cancel (cancellable);
|
|
|
|
g_output_stream_close (output, cancellable, NULL);
|
|
|
|
g_object_unref (cancellable);
|
|
|
|
|
2014-10-05 18:06:03 +02:00
|
|
|
g_free (data);
|
|
|
|
g_object_unref (buffer);
|
|
|
|
g_object_unref (output);
|
|
|
|
|
|
|
|
return FALSE;
|
1998-11-06 00:51:39 +00:00
|
|
|
}
|
|
|
|
|
2004-05-20 01:19:47 +00:00
|
|
|
static gboolean
|
2023-04-19 12:32:06 +00:00
|
|
|
save_dialog (GimpImage *image,
|
|
|
|
GimpDrawable *drawable,
|
2019-10-07 20:09:08 +02:00
|
|
|
GimpProcedure *procedure,
|
|
|
|
GObject *config)
|
1999-10-14 02:11:52 +00:00
|
|
|
{
|
2019-10-07 20:09:08 +02:00
|
|
|
GtkWidget *dialog;
|
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *frame;
|
|
|
|
GtkWidget *hint;
|
|
|
|
gboolean run;
|
|
|
|
|
2024-04-20 03:08:57 +00:00
|
|
|
dialog = gimp_export_procedure_dialog_new (GIMP_EXPORT_PROCEDURE (procedure),
|
|
|
|
GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
image);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2000-01-25 17:46:56 +00:00
|
|
|
/* comment string. */
|
2019-10-07 20:09:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
hint = g_object_new (GIMP_TYPE_HINT_BOX,
|
|
|
|
"icon-name", GIMP_ICON_DIALOG_WARNING,
|
|
|
|
"hint", _("Writing a comment will make the XBM "
|
|
|
|
"file unreadable by some applications.\n"
|
|
|
|
"The comment will not affect embedding "
|
|
|
|
"the XBM in C source code."),
|
|
|
|
NULL);
|
|
|
|
|
2023-04-19 12:32:06 +00:00
|
|
|
vbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"comment-vbox", "gimp-comment", NULL);
|
2019-10-07 20:09:08 +02:00
|
|
|
|
2023-04-19 12:32:06 +00:00
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), hint, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_set_visible (hint, TRUE);
|
|
|
|
gtk_box_reorder_child (GTK_BOX (vbox), hint, 0);
|
|
|
|
gtk_widget_set_margin_end (hint, 24);
|
|
|
|
|
|
|
|
frame = gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
|
2025-01-20 16:06:45 +01:00
|
|
|
"comment-frame", "include-comment",
|
2023-04-19 12:32:06 +00:00
|
|
|
FALSE, "comment-vbox");
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2000-03-04 00:24:39 +00:00
|
|
|
/* hotspot toggle */
|
2023-04-19 12:32:06 +00:00
|
|
|
gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"hot-spot-vbox", "hot-spot-x", "hot-spot-y",
|
|
|
|
NULL);
|
2014-06-22 23:01:31 +02:00
|
|
|
|
2023-04-19 12:32:06 +00:00
|
|
|
frame = gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"hot-spot-frame", "use-hot-spot",
|
|
|
|
FALSE, "hot-spot-vbox");
|
2000-06-05 11:38:35 +00:00
|
|
|
|
2023-04-19 12:32:06 +00:00
|
|
|
/* mask file */
|
|
|
|
frame = gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"mask-frame", "write-mask",
|
|
|
|
FALSE, "mask-suffix");
|
2019-10-07 20:09:08 +02:00
|
|
|
gtk_widget_set_sensitive (frame, gimp_drawable_has_alpha (drawable));
|
|
|
|
|
2023-04-19 12:32:06 +00:00
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"x10-format", "prefix", "comment-frame",
|
|
|
|
"hot-spot-frame", "mask-frame", NULL);
|
2000-06-05 11:38:35 +00:00
|
|
|
|
2005-09-09 18:38:00 +00:00
|
|
|
gtk_widget_show (dialog);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2019-10-07 20:09:08 +02:00
|
|
|
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2005-09-09 18:38:00 +00:00
|
|
|
gtk_widget_destroy (dialog);
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2003-11-06 15:27:05 +00:00
|
|
|
return run;
|
|
|
|
}
|
1998-11-06 00:51:39 +00:00
|
|
|
|
2014-10-05 18:06:03 +02:00
|
|
|
static gboolean
|
|
|
|
print (GOutputStream *output,
|
|
|
|
GError **error,
|
|
|
|
const gchar *format,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
success = g_output_stream_vprintf (output, NULL, NULL,
|
|
|
|
error, format, args);
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|