2005-06-01 03:10:46 +08:00
|
|
|
/*
|
2016-02-16 09:35:43 +08:00
|
|
|
* pcx.c GIMP plug-in for loading & exporting PCX files
|
2005-06-01 03:10:46 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2005-06-01 03:10:46 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2005-06-01 03:10:46 +08: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-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2005-06-01 03:10:46 +08:00
|
|
|
*/
|
1998-01-25 09:24:46 +08:00
|
|
|
|
|
|
|
/* This code is based in parts on code by Francisco Bustamante, but the
|
|
|
|
largest portion of the code has been rewritten and is now maintained
|
1998-05-31 14:49:20 +08:00
|
|
|
occasionally by Nick Lamb njl195@zepler.org.uk */
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
2003-06-13 22:37:00 +08:00
|
|
|
#include <errno.h>
|
1997-11-25 06:05:25 +08:00
|
|
|
#include <string.h>
|
2000-01-26 01:46:56 +08:00
|
|
|
|
2005-03-04 23:12:29 +08:00
|
|
|
#include <glib/gstdio.h>
|
2000-01-26 01:46:56 +08:00
|
|
|
|
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include <libgimp/gimpui.h>
|
|
|
|
|
2000-01-01 15:35:13 +08:00
|
|
|
#include "libgimp/stdplugins-intl.h"
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-05-02 01:01:18 +08:00
|
|
|
|
2005-08-15 19:07:27 +08:00
|
|
|
#define LOAD_PROC "file-pcx-load"
|
2023-04-05 20:32:31 +08:00
|
|
|
#define LOAD_PROC_DCX "file-dcx-load"
|
2024-04-13 23:10:25 +08:00
|
|
|
#define EXPORT_PROC "file-pcx-export"
|
2008-08-11 18:06:13 +08:00
|
|
|
#define PLUG_IN_BINARY "file-pcx"
|
2011-04-09 02:31:34 +08:00
|
|
|
#define PLUG_IN_ROLE "gimp-file-pcx"
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
typedef struct _Pcx Pcx;
|
|
|
|
typedef struct _PcxClass PcxClass;
|
|
|
|
|
|
|
|
struct _Pcx
|
|
|
|
{
|
|
|
|
GimpPlugIn parent_instance;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _PcxClass
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2019-08-25 01:27:46 +08:00
|
|
|
GimpPlugInClass parent_class;
|
2000-01-26 01:46:56 +08:00
|
|
|
};
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
|
|
|
|
#define PCX_TYPE (pcx_get_type ())
|
2023-10-19 00:29:37 +08:00
|
|
|
#define PCX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PCX_TYPE, Pcx))
|
2019-08-25 01:27:46 +08:00
|
|
|
|
|
|
|
GType pcx_get_type (void) G_GNUC_CONST;
|
|
|
|
|
2023-08-06 08:56:44 +08:00
|
|
|
static GList * pcx_query_procedures (GimpPlugIn *plug_in);
|
|
|
|
static GimpProcedure * pcx_create_procedure (GimpPlugIn *plug_in,
|
|
|
|
const gchar *name);
|
|
|
|
|
|
|
|
static GimpValueArray * pcx_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data);
|
|
|
|
static GimpValueArray * dcx_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data);
|
2024-04-13 23:10:25 +08:00
|
|
|
static GimpValueArray * pcx_export (GimpProcedure *procedure,
|
2023-08-06 08:56:44 +08:00
|
|
|
GimpRunMode run_mode,
|
|
|
|
GimpImage *image,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data);
|
|
|
|
|
|
|
|
static GimpImage * load_single (GimpProcedure *procedure,
|
|
|
|
GFile *file,
|
|
|
|
GObject *config,
|
|
|
|
gint run_mode,
|
|
|
|
GError **error);
|
|
|
|
static GimpImage * load_multi (GimpProcedure *procedure,
|
|
|
|
GFile *file,
|
|
|
|
GObject *config,
|
|
|
|
gint run_mode,
|
|
|
|
GError **error);
|
|
|
|
|
|
|
|
static GimpImage * load_image (GimpProcedure *procedure,
|
|
|
|
FILE *fd,
|
|
|
|
const gchar *filename,
|
|
|
|
GObject *config,
|
|
|
|
gint run_mode,
|
|
|
|
gint image_num,
|
|
|
|
GError **error);
|
|
|
|
static gboolean pcx_load_dialog (GimpProcedure *procedure,
|
|
|
|
GObject *config);
|
|
|
|
|
|
|
|
static void load_1 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
guchar *buf,
|
|
|
|
guint16 bytes);
|
|
|
|
static void load_4 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
guchar *buf,
|
|
|
|
guint16 bytes);
|
|
|
|
static void load_sub_8 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gint bpp,
|
|
|
|
gint plane,
|
|
|
|
guchar *buf,
|
|
|
|
guint16 bytes);
|
|
|
|
static void load_8 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
guchar *buf,
|
|
|
|
guint16 bytes);
|
|
|
|
static void load_24 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
guchar *buf,
|
|
|
|
guint16 bytes,
|
|
|
|
guint8 planes);
|
|
|
|
static void readline (FILE *fp,
|
|
|
|
guchar *buf,
|
|
|
|
gint bytes);
|
|
|
|
|
2024-04-13 23:10:25 +08:00
|
|
|
static gboolean export_image (GFile *file,
|
2023-08-06 08:56:44 +08:00
|
|
|
GimpImage *image,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GError **error);
|
|
|
|
static void save_less_than_8 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
const gint bpp,
|
|
|
|
const guchar *buf,
|
|
|
|
gboolean padding);
|
|
|
|
static void save_8 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
const guchar *buf,
|
|
|
|
gboolean padding);
|
|
|
|
static void save_24 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
const guchar *buf,
|
|
|
|
gboolean padding);
|
|
|
|
static void writeline (FILE *fp,
|
|
|
|
const guchar *buf,
|
|
|
|
gint bytes);
|
2019-08-25 01:27:46 +08:00
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (Pcx, pcx, GIMP_TYPE_PLUG_IN)
|
|
|
|
|
|
|
|
GIMP_MAIN (PCX_TYPE)
|
2022-05-26 06:59:36 +08:00
|
|
|
DEFINE_STD_SET_I18N
|
2019-08-25 01:27:46 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2019-08-25 01:27:46 +08:00
|
|
|
pcx_class_init (PcxClass *klass)
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2019-08-25 01:27:46 +08:00
|
|
|
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
|
|
|
|
|
|
|
|
plug_in_class->query_procedures = pcx_query_procedures;
|
|
|
|
plug_in_class->create_procedure = pcx_create_procedure;
|
2022-05-26 06:59:36 +08:00
|
|
|
plug_in_class->set_i18n = STD_SET_I18N;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2019-08-25 01:27:46 +08:00
|
|
|
pcx_init (Pcx *pcx)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2019-08-25 01:27:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
static GList *
|
|
|
|
pcx_query_procedures (GimpPlugIn *plug_in)
|
|
|
|
{
|
|
|
|
GList *list = NULL;
|
2012-11-20 05:26:04 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
list = g_list_append (list, g_strdup (LOAD_PROC));
|
2023-04-05 20:32:31 +08:00
|
|
|
list = g_list_append (list, g_strdup (LOAD_PROC_DCX));
|
2024-04-13 23:10:25 +08:00
|
|
|
list = g_list_append (list, g_strdup (EXPORT_PROC));
|
2003-03-26 00:38:19 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
return list;
|
|
|
|
}
|
2005-08-15 19:07:27 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
static GimpProcedure *
|
|
|
|
pcx_create_procedure (GimpPlugIn *plug_in,
|
|
|
|
const gchar *name)
|
|
|
|
{
|
|
|
|
GimpProcedure *procedure = NULL;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
if (! strcmp (name, LOAD_PROC))
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2023-08-06 09:21:27 +08:00
|
|
|
procedure = gimp_load_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
|
|
|
pcx_load, NULL, NULL);
|
2019-08-19 18:05:12 +08:00
|
|
|
|
2022-07-05 04:50:53 +08:00
|
|
|
gimp_procedure_set_menu_label (procedure, _("ZSoft PCX image"));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
gimp_procedure_set_documentation (procedure,
|
2023-04-05 20:32:31 +08:00
|
|
|
_("Loads files in Zsoft PCX file format"),
|
2019-08-25 01:27:46 +08:00
|
|
|
"FIXME: write help for pcx_load",
|
|
|
|
name);
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Francisco Bustamante & Nick Lamb",
|
|
|
|
"Nick Lamb <njl195@zepler.org.uk>",
|
|
|
|
"January 1997");
|
|
|
|
|
2024-07-14 12:12:26 +08:00
|
|
|
gimp_procedure_add_choice_argument (procedure, "override-palette",
|
|
|
|
_("_Palette Options"),
|
|
|
|
_("Whether to use the built-in palette or "
|
|
|
|
"a black and white palette for 1 bit images."),
|
|
|
|
gimp_choice_new_with_values ("use-built-in-palette", 0, _("Use PCX image's built-in palette"), NULL,
|
|
|
|
"use-bw-palette", 1, _("Use black and white palette"), NULL,
|
|
|
|
NULL),
|
|
|
|
"use-built-in-palette",
|
|
|
|
G_PARAM_READWRITE);
|
2023-03-19 11:01:13 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"image/x-pcx");
|
|
|
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"pcx,pcc");
|
|
|
|
gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"0&,byte,10,2&,byte,1,3&,byte,>0,3,byte,<9");
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
2023-04-05 20:32:31 +08:00
|
|
|
else if (! strcmp (name, LOAD_PROC_DCX))
|
|
|
|
{
|
2023-08-06 09:21:27 +08:00
|
|
|
procedure = gimp_load_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
|
|
|
dcx_load, NULL, NULL);
|
2023-04-05 20:32:31 +08:00
|
|
|
|
|
|
|
gimp_procedure_set_menu_label (procedure, _("ZSoft DCX image"));
|
|
|
|
|
|
|
|
gimp_procedure_set_documentation (procedure,
|
|
|
|
_("Loads files in Zsoft DCX file format"),
|
|
|
|
"FIXME: write help for dcx_load",
|
|
|
|
name);
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Francisco Bustamante, Nick Lamb, Alex S.",
|
|
|
|
"Alex S.",
|
|
|
|
"2023");
|
|
|
|
|
2024-07-14 12:12:26 +08:00
|
|
|
gimp_procedure_add_choice_argument (procedure, "override-palette",
|
|
|
|
_("_Palette Options"),
|
|
|
|
_("Whether to use the built-in palette or "
|
|
|
|
"a black and white palette for 1 bit images."),
|
|
|
|
gimp_choice_new_with_values ("use-built-in-palette", 0, _("Use PCX image's built-in palette"), NULL,
|
|
|
|
"use-bw-palette", 1, _("Use black and white palette"), NULL,
|
|
|
|
NULL),
|
|
|
|
"use-built-in-palette",
|
|
|
|
G_PARAM_READWRITE);
|
2023-04-05 20:32:31 +08:00
|
|
|
|
|
|
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"image/x-dcx");
|
|
|
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"dcx");
|
|
|
|
gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"0,string,\xB1\x68\xDE\x3A");
|
|
|
|
}
|
2024-04-13 23:10:25 +08:00
|
|
|
else if (! strcmp (name, EXPORT_PROC))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2024-04-20 11:08:57 +08:00
|
|
|
procedure = gimp_export_procedure_new (plug_in, name,
|
|
|
|
GIMP_PDB_PROC_TYPE_PLUGIN,
|
|
|
|
FALSE, pcx_export, NULL, NULL);
|
2019-08-19 18:05:12 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
gimp_procedure_set_image_types (procedure, "INDEXED, RGB, GRAY");
|
1999-10-10 03:06:14 +08:00
|
|
|
|
2022-07-05 04:50:53 +08:00
|
|
|
gimp_procedure_set_menu_label (procedure, _("ZSoft PCX image"));
|
2008-08-18 14:31:03 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
gimp_procedure_set_documentation (procedure,
|
2024-06-13 00:53:12 +08:00
|
|
|
_("Exports files in ZSoft PCX file format"),
|
2024-04-13 23:10:25 +08:00
|
|
|
"FIXME: write help for pcx_export",
|
2019-08-25 01:27:46 +08:00
|
|
|
name);
|
|
|
|
gimp_procedure_set_attribution (procedure,
|
|
|
|
"Francisco Bustamante & Nick Lamb",
|
|
|
|
"Nick Lamb <njl195@zepler.org.uk>",
|
|
|
|
"January 1997");
|
2013-11-10 07:18:48 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"image/x-pcx");
|
|
|
|
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
|
|
|
|
"pcx,pcc");
|
|
|
|
}
|
1999-10-10 03:06:14 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
return procedure;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
static GimpValueArray *
|
2023-08-06 08:56:44 +08:00
|
|
|
pcx_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data)
|
2019-08-25 01:27:46 +08:00
|
|
|
{
|
2023-08-06 08:56:44 +08:00
|
|
|
GimpValueArray *return_vals;
|
|
|
|
GimpImage *image;
|
|
|
|
GError *error = NULL;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
gegl_init (NULL, NULL);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2023-04-05 20:32:31 +08:00
|
|
|
image = load_single (procedure, file, G_OBJECT (config), run_mode, &error);
|
|
|
|
|
|
|
|
if (! image)
|
2023-08-06 08:56:44 +08:00
|
|
|
return gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_EXECUTION_ERROR,
|
|
|
|
error);
|
2023-04-05 20:32:31 +08:00
|
|
|
|
|
|
|
return_vals = gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_SUCCESS,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
|
|
|
|
|
|
|
return return_vals;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpValueArray *
|
2023-08-06 08:56:44 +08:00
|
|
|
dcx_load (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpMetadataLoadFlags *flags,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data)
|
2023-04-05 20:32:31 +08:00
|
|
|
{
|
2023-08-06 08:56:44 +08:00
|
|
|
GimpValueArray *return_vals;
|
|
|
|
GimpImage *image;
|
|
|
|
GError *error = NULL;
|
2023-04-05 20:32:31 +08:00
|
|
|
|
|
|
|
gegl_init (NULL, NULL);
|
|
|
|
|
|
|
|
image = load_multi (procedure, file, G_OBJECT (config), run_mode, &error);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
if (! image)
|
2023-08-06 08:56:44 +08:00
|
|
|
return gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_EXECUTION_ERROR,
|
|
|
|
error);
|
2003-11-06 23:27:05 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
return_vals = gimp_procedure_new_return_values (procedure,
|
|
|
|
GIMP_PDB_SUCCESS,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
|
|
|
|
|
|
|
|
return return_vals;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpValueArray *
|
2024-04-13 23:10:25 +08:00
|
|
|
pcx_export (GimpProcedure *procedure,
|
|
|
|
GimpRunMode run_mode,
|
|
|
|
GimpImage *image,
|
|
|
|
GFile *file,
|
|
|
|
GimpMetadata *metadata,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
gpointer run_data)
|
2019-08-25 01:27:46 +08:00
|
|
|
{
|
|
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
2024-04-30 12:25:51 +08:00
|
|
|
GimpExportReturn export = GIMP_EXPORT_IGNORE;
|
2024-04-30 21:50:24 +08:00
|
|
|
GList *drawables;
|
2023-03-19 11:01:13 +08:00
|
|
|
GError *error = NULL;
|
2019-08-25 01:27:46 +08:00
|
|
|
|
|
|
|
gegl_init (NULL, NULL);
|
|
|
|
|
2024-07-15 04:12:57 +08:00
|
|
|
export = gimp_export_image (&image,
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_RGB |
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_GRAY |
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_INDEXED);
|
2024-04-30 21:50:24 +08:00
|
|
|
drawables = gimp_image_list_layers (image);
|
2020-04-14 17:46:17 +08:00
|
|
|
|
2024-04-13 23:10:25 +08:00
|
|
|
if (! export_image (file,
|
2024-04-30 21:50:24 +08:00
|
|
|
image, drawables->data,
|
2024-04-13 23:10:25 +08:00
|
|
|
&error))
|
2008-08-18 14:31:03 +08:00
|
|
|
{
|
2019-08-25 01:27:46 +08:00
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
2008-08-18 14:31:03 +08:00
|
|
|
}
|
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
if (export == GIMP_EXPORT_EXPORT)
|
2024-04-30 21:50:24 +08:00
|
|
|
gimp_image_delete (image);
|
2019-08-25 01:27:46 +08:00
|
|
|
|
2024-04-30 21:50:24 +08:00
|
|
|
g_list_free (drawables);
|
2019-08-25 01:27:46 +08:00
|
|
|
return gimp_procedure_new_return_values (procedure, status, error);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static struct
|
|
|
|
{
|
2007-08-30 19:49:52 +08:00
|
|
|
guint8 manufacturer;
|
|
|
|
guint8 version;
|
|
|
|
guint8 compression;
|
|
|
|
guint8 bpp;
|
|
|
|
guint16 x1, y1;
|
|
|
|
guint16 x2, y2;
|
|
|
|
guint16 hdpi;
|
|
|
|
guint16 vdpi;
|
|
|
|
guint8 colormap[48];
|
|
|
|
guint8 reserved;
|
|
|
|
guint8 planes;
|
|
|
|
guint16 bytesperline;
|
|
|
|
guint16 color;
|
|
|
|
guint8 filler[58];
|
1997-11-25 06:05:25 +08:00
|
|
|
} pcx_header;
|
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
static struct {
|
|
|
|
size_t size;
|
|
|
|
gpointer address;
|
2009-02-25 18:56:41 +08:00
|
|
|
} const pcx_header_buf_xlate[] = {
|
2007-08-30 19:49:52 +08:00
|
|
|
{ 1, &pcx_header.manufacturer },
|
2009-02-25 18:56:41 +08:00
|
|
|
{ 1, &pcx_header.version },
|
|
|
|
{ 1, &pcx_header.compression },
|
|
|
|
{ 1, &pcx_header.bpp },
|
|
|
|
{ 2, &pcx_header.x1 },
|
|
|
|
{ 2, &pcx_header.y1 },
|
|
|
|
{ 2, &pcx_header.x2 },
|
|
|
|
{ 2, &pcx_header.y2 },
|
|
|
|
{ 2, &pcx_header.hdpi },
|
|
|
|
{ 2, &pcx_header.vdpi },
|
|
|
|
{ 48, &pcx_header.colormap },
|
|
|
|
{ 1, &pcx_header.reserved },
|
|
|
|
{ 1, &pcx_header.planes },
|
2007-08-30 19:49:52 +08:00
|
|
|
{ 2, &pcx_header.bytesperline },
|
2009-02-25 18:56:41 +08:00
|
|
|
{ 2, &pcx_header.color },
|
|
|
|
{ 58, &pcx_header.filler },
|
2007-08-30 19:49:52 +08:00
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2007-09-24 01:02:11 +08:00
|
|
|
pcx_header_from_buffer (guint8 *buf)
|
2007-08-30 19:49:52 +08:00
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
gint buf_offset = 0;
|
|
|
|
|
|
|
|
for (i = 0; pcx_header_buf_xlate[i].size != 0; i++)
|
|
|
|
{
|
2014-08-12 21:29:34 +08:00
|
|
|
memmove (pcx_header_buf_xlate[i].address, buf + buf_offset,
|
|
|
|
pcx_header_buf_xlate[i].size);
|
2007-08-30 19:49:52 +08:00
|
|
|
buf_offset += pcx_header_buf_xlate[i].size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-09-24 01:02:11 +08:00
|
|
|
pcx_header_to_buffer (guint8 *buf)
|
2007-08-30 19:49:52 +08:00
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
gint buf_offset = 0;
|
|
|
|
|
|
|
|
for (i = 0; pcx_header_buf_xlate[i].size != 0; i++)
|
|
|
|
{
|
2014-08-12 21:29:34 +08:00
|
|
|
memmove (buf + buf_offset, pcx_header_buf_xlate[i].address,
|
|
|
|
pcx_header_buf_xlate[i].size);
|
2007-08-30 19:49:52 +08:00
|
|
|
buf_offset += pcx_header_buf_xlate[i].size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
static GimpImage *
|
2023-04-05 20:32:31 +08:00
|
|
|
load_single (GimpProcedure *procedure,
|
|
|
|
GFile *file,
|
|
|
|
GObject *config,
|
|
|
|
gint run_mode,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
FILE *fd;
|
|
|
|
GimpImage *image;
|
|
|
|
|
|
|
|
gimp_progress_init_printf (_("Opening '%s'"),
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
|
|
|
|
fd = g_fopen (g_file_peek_path (file), "rb");
|
|
|
|
|
|
|
|
if (! fd)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
|
|
_("Could not open '%s' for reading: %s"),
|
|
|
|
gimp_file_get_utf8_name (file), g_strerror (errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
image = load_image (procedure, fd, gimp_file_get_utf8_name (file),
|
|
|
|
G_OBJECT (config), run_mode, 0, error);
|
|
|
|
fclose (fd);
|
|
|
|
|
|
|
|
if (! image)
|
|
|
|
{
|
2024-03-05 04:52:57 +08:00
|
|
|
g_prefix_error (error,
|
|
|
|
_("Could not load PCX image: "));
|
2023-04-05 20:32:31 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_progress_update (1.0);
|
|
|
|
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpImage *
|
|
|
|
load_multi (GimpProcedure *procedure,
|
2023-03-19 11:01:13 +08:00
|
|
|
GFile *file,
|
|
|
|
GObject *config,
|
|
|
|
gint run_mode,
|
|
|
|
GError **error)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2023-04-05 20:32:31 +08:00
|
|
|
FILE *fd;
|
|
|
|
GimpImage *image = NULL;
|
|
|
|
GimpImage *temp_image = NULL;
|
|
|
|
gint offset;
|
|
|
|
gint next_id = 8;
|
|
|
|
gint valid_offset;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2014-07-23 22:39:00 +08:00
|
|
|
gimp_progress_init_printf (_("Opening '%s'"),
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_file_get_utf8_name (file));
|
2014-07-23 22:39:00 +08:00
|
|
|
|
2021-10-02 00:56:12 +08:00
|
|
|
fd = g_fopen (g_file_peek_path (file), "rb");
|
2008-08-18 14:31:03 +08:00
|
|
|
|
|
|
|
if (! fd)
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2008-08-18 14:31:03 +08:00
|
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
|
|
_("Could not open '%s' for reading: %s"),
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_file_get_utf8_name (file), g_strerror (errno));
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2023-04-05 20:32:31 +08:00
|
|
|
/* Skip header */
|
|
|
|
fread (&offset, 1, 4, fd);
|
|
|
|
|
|
|
|
/* Read the first offset */
|
|
|
|
fread (&offset, 1, 4, fd);
|
|
|
|
valid_offset = fseek (fd, offset, SEEK_SET);
|
|
|
|
|
|
|
|
if (valid_offset != 0)
|
|
|
|
{
|
|
|
|
fclose (fd);
|
|
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
|
|
_("DCX image offset exceeds the file size"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
image = load_image (procedure, fd, gimp_file_get_utf8_name (file),
|
|
|
|
G_OBJECT (config), run_mode, 0, error);
|
|
|
|
|
|
|
|
if (! image)
|
|
|
|
{
|
|
|
|
fclose (fd);
|
2024-03-05 00:32:32 +08:00
|
|
|
g_prefix_error (error,
|
|
|
|
_("Could not load DCX image: "));
|
2023-04-05 20:32:31 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek (fd, next_id, SEEK_SET);
|
|
|
|
|
|
|
|
/* DCX can hold a maximum of 1023 images,
|
|
|
|
* plus a terminal value of 0 */
|
|
|
|
for (gint i = 1; i < 1023; i++)
|
|
|
|
{
|
|
|
|
GimpLayer **layers;
|
|
|
|
GimpLayer *new_layer;
|
|
|
|
gint n_layers;
|
|
|
|
|
|
|
|
fread (&offset, 1, 4, fd);
|
|
|
|
|
|
|
|
if (offset == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
valid_offset = fseek (fd, offset, SEEK_SET);
|
|
|
|
if (valid_offset != 0)
|
|
|
|
{
|
|
|
|
fclose (fd);
|
|
|
|
g_message (_("%s: DCX image offset exceeds the file size: %s\n"),
|
|
|
|
G_STRFUNC, (*error)->message);
|
|
|
|
g_clear_error (error);
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp_image = load_image (procedure, fd, gimp_file_get_utf8_name (file),
|
|
|
|
G_OBJECT (config), run_mode, i, error);
|
|
|
|
|
|
|
|
if (temp_image)
|
|
|
|
{
|
|
|
|
layers = gimp_image_get_layers (temp_image, &n_layers);
|
|
|
|
new_layer = gimp_layer_new_from_drawable (GIMP_DRAWABLE (layers[0]),
|
|
|
|
image);
|
|
|
|
gimp_item_set_name (GIMP_ITEM (new_layer),
|
|
|
|
g_file_get_basename (file));
|
|
|
|
if (! gimp_image_insert_layer (image, new_layer, NULL, 0))
|
|
|
|
g_message (_("Mixed-mode DCX image not loaded"));
|
|
|
|
|
|
|
|
g_free (layers);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fclose (fd);
|
|
|
|
g_message (_("%s: Could not load all DCX images: %s\n"),
|
|
|
|
G_STRFUNC, (*error)->message);
|
|
|
|
g_clear_error (error);
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_id += 4;
|
|
|
|
fseek (fd, next_id, SEEK_SET);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (image)
|
|
|
|
fclose (fd);
|
|
|
|
|
|
|
|
gimp_progress_update (1.0);
|
|
|
|
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpImage *
|
|
|
|
load_image (GimpProcedure *procedure,
|
|
|
|
FILE *fd,
|
|
|
|
const gchar *filename,
|
|
|
|
GObject *config,
|
|
|
|
gint run_mode,
|
|
|
|
gint image_num,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
guint16 offset_x, offset_y, bytesperline;
|
|
|
|
gint32 width, height;
|
|
|
|
guint16 resolution_x, resolution_y;
|
|
|
|
GimpImage *image;
|
|
|
|
GimpLayer *layer;
|
|
|
|
guchar *dest, cmap[768];
|
|
|
|
guint8 header_buf[128];
|
|
|
|
gboolean override_palette = FALSE;
|
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
if (fread (header_buf, 128, 1, fd) == 0)
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2008-08-18 14:31:03 +08:00
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
_("Could not read header from '%s'"),
|
2023-04-05 20:32:31 +08:00
|
|
|
filename);
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
pcx_header_from_buffer (header_buf);
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
if (pcx_header.manufacturer != 10)
|
|
|
|
{
|
2008-08-18 14:31:03 +08:00
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
_("'%s' is not a PCX file"),
|
2023-04-05 20:32:31 +08:00
|
|
|
filename);
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2009-02-25 18:56:41 +08:00
|
|
|
offset_x = GUINT16_FROM_LE (pcx_header.x1);
|
|
|
|
offset_y = GUINT16_FROM_LE (pcx_header.y1);
|
|
|
|
width = GUINT16_FROM_LE (pcx_header.x2) - offset_x + 1;
|
|
|
|
height = GUINT16_FROM_LE (pcx_header.y2) - offset_y + 1;
|
2007-09-18 02:56:34 +08:00
|
|
|
bytesperline = GUINT16_FROM_LE (pcx_header.bytesperline);
|
2013-11-01 20:51:31 +08:00
|
|
|
resolution_x = GUINT16_FROM_LE (pcx_header.hdpi);
|
|
|
|
resolution_y = GUINT16_FROM_LE (pcx_header.vdpi);
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2017-04-07 03:42:44 +08:00
|
|
|
if ((width <= 0) || (width > GIMP_MAX_IMAGE_SIZE))
|
2007-07-06 01:01:41 +08:00
|
|
|
{
|
2024-03-05 00:32:32 +08:00
|
|
|
g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
|
|
|
|
_("Unsupported or invalid image width: %d"),
|
|
|
|
width);
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2007-07-06 01:01:41 +08:00
|
|
|
}
|
2017-04-07 03:42:44 +08:00
|
|
|
if ((height <= 0) || (height > GIMP_MAX_IMAGE_SIZE))
|
2007-07-06 01:01:41 +08:00
|
|
|
{
|
2024-03-05 00:32:32 +08:00
|
|
|
g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
|
|
|
|
_("Unsupported or invalid image height: %d"),
|
|
|
|
height);
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2007-07-06 01:01:41 +08:00
|
|
|
}
|
2024-03-02 02:24:49 +08:00
|
|
|
if ((bytesperline + 1) < ((width * pcx_header.bpp + 7) / 8) ||
|
|
|
|
bytesperline == 0)
|
2007-09-18 02:56:34 +08:00
|
|
|
{
|
2024-03-05 00:32:32 +08:00
|
|
|
g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
|
|
|
|
_("Invalid number of bytes per line in PCX header"));
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2007-09-18 02:56:34 +08:00
|
|
|
}
|
2013-11-01 20:51:31 +08:00
|
|
|
if ((resolution_x < 1) || (resolution_x > GIMP_MAX_RESOLUTION) ||
|
|
|
|
(resolution_y < 1) || (resolution_y > GIMP_MAX_RESOLUTION))
|
|
|
|
{
|
|
|
|
g_message (_("Resolution out of bounds in XCX header, using 72x72"));
|
|
|
|
resolution_x = 72;
|
|
|
|
resolution_y = 72;
|
|
|
|
}
|
2007-07-06 01:01:41 +08:00
|
|
|
|
2009-12-01 22:31:52 +08:00
|
|
|
/* Shield against potential buffer overflows in load_*() functions. */
|
|
|
|
if (G_MAXSIZE / width / height < 3)
|
|
|
|
{
|
2024-03-05 00:32:32 +08:00
|
|
|
g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
|
|
|
|
_("Image dimensions too large: width %d x height %d"),
|
|
|
|
width, height);
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2009-12-01 22:31:52 +08:00
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
if (pcx_header.planes == 3 && pcx_header.bpp == 8)
|
|
|
|
{
|
2019-08-25 01:27:46 +08:00
|
|
|
image = gimp_image_new (width, height, GIMP_RGB);
|
|
|
|
layer = gimp_layer_new (image, _("Background"), width, height,
|
|
|
|
GIMP_RGB_IMAGE,
|
|
|
|
100,
|
|
|
|
gimp_image_get_default_new_layer_mode (image));
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
2023-04-27 04:52:27 +08:00
|
|
|
else if (pcx_header.planes == 4 && pcx_header.bpp == 8)
|
|
|
|
{
|
|
|
|
image = gimp_image_new (width, height, GIMP_RGB);
|
|
|
|
layer = gimp_layer_new (image, _("Background"), width, height,
|
|
|
|
GIMP_RGBA_IMAGE,
|
|
|
|
100,
|
|
|
|
gimp_image_get_default_new_layer_mode (image));
|
|
|
|
}
|
2000-01-26 01:46:56 +08:00
|
|
|
else
|
|
|
|
{
|
2019-08-25 01:27:46 +08:00
|
|
|
image = gimp_image_new (width, height, GIMP_INDEXED);
|
|
|
|
layer = gimp_layer_new (image, _("Background"), width, height,
|
|
|
|
GIMP_INDEXED_IMAGE,
|
|
|
|
100,
|
|
|
|
gimp_image_get_default_new_layer_mode (image));
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
2013-11-01 20:51:31 +08:00
|
|
|
|
|
|
|
gimp_image_set_resolution (image, resolution_x, resolution_y);
|
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
gimp_image_insert_layer (image, layer, NULL, 0);
|
1998-01-25 09:24:46 +08:00
|
|
|
gimp_layer_set_offsets (layer, offset_x, offset_y);
|
2012-11-20 05:26:04 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
if (pcx_header.planes == 1 && pcx_header.bpp == 1)
|
|
|
|
{
|
2019-02-23 00:51:30 +08:00
|
|
|
const guint8 *colormap = pcx_header.colormap;
|
2009-12-02 22:12:17 +08:00
|
|
|
dest = g_new (guchar, ((gsize) width) * height);
|
2007-09-18 02:56:34 +08:00
|
|
|
load_1 (fd, width, height, dest, bytesperline);
|
2023-03-19 11:01:13 +08:00
|
|
|
|
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
|
|
{
|
2024-07-14 12:12:26 +08:00
|
|
|
override_palette = gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
"override-palette");
|
|
|
|
|
2023-04-05 20:32:31 +08:00
|
|
|
/* Only show dialogue once for DCX import */
|
|
|
|
if (image_num == 0 && pcx_load_dialog (procedure, config))
|
2024-07-14 12:12:26 +08:00
|
|
|
override_palette = gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
"override-palette");
|
2023-03-19 11:01:13 +08:00
|
|
|
}
|
2017-06-09 18:56:03 +08:00
|
|
|
/* Monochrome does not mean necessarily B&W. Therefore we still
|
|
|
|
* want to check the header palette, even for just 2 colors.
|
|
|
|
* Hopefully the header palette will always be filled with
|
|
|
|
* meaningful colors and the creator software did not just assume
|
|
|
|
* B&W by being monochrome.
|
|
|
|
* Until now test samples showed that even when B&W the header
|
|
|
|
* palette was correctly filled with these 2 colors and we didn't
|
|
|
|
* find counter-examples.
|
|
|
|
* See bug 159947, comment 21 and 23.
|
|
|
|
*/
|
2019-02-23 00:51:30 +08:00
|
|
|
/* ... Actually, there *are* files out there with a zeroed 1-bit palette,
|
|
|
|
* which are supposed to be displayed as B&W (see issue #2997.) These
|
|
|
|
* files *might* be in the wrong (who knows...) but the fact is that
|
|
|
|
* other software, including older versions of GIMP, do display them
|
|
|
|
* "correctly", so let's follow suit: if the two palette colors are
|
2023-03-19 11:01:13 +08:00
|
|
|
* equal (or if the user chooses the option in the load dialog),
|
|
|
|
* use a B&W palette instead.
|
2019-02-23 00:51:30 +08:00
|
|
|
*/
|
2023-03-19 11:01:13 +08:00
|
|
|
if (! memcmp (colormap, colormap + 3, 3) || override_palette)
|
2019-02-23 00:51:30 +08:00
|
|
|
{
|
|
|
|
static const guint8 bw_colormap[6] = { 0, 0, 0,
|
|
|
|
255, 255, 255};
|
|
|
|
colormap = bw_colormap;
|
|
|
|
}
|
|
|
|
gimp_image_set_colormap (image, colormap, 2);
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
2017-05-14 11:30:53 +08:00
|
|
|
else if (pcx_header.bpp == 1 && pcx_header.planes == 2)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
dest = g_new (guchar, ((gsize) width) * height);
|
2017-05-14 11:30:53 +08:00
|
|
|
load_sub_8 (fd, width, height, 1, 2, dest, bytesperline);
|
|
|
|
gimp_image_set_colormap (image, pcx_header.colormap, 4);
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
2017-05-14 11:30:53 +08:00
|
|
|
else if (pcx_header.bpp == 2 && pcx_header.planes == 1)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
dest = g_new (guchar, ((gsize) width) * height);
|
2017-06-09 18:56:03 +08:00
|
|
|
load_sub_8 (fd, width, height, 2, 1, dest, bytesperline);
|
2017-05-14 11:30:53 +08:00
|
|
|
gimp_image_set_colormap (image, pcx_header.colormap, 4);
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
2017-05-14 11:30:53 +08:00
|
|
|
else if (pcx_header.bpp == 1 && pcx_header.planes == 3)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
dest = g_new (guchar, ((gsize) width) * height);
|
2017-05-14 11:30:53 +08:00
|
|
|
load_sub_8 (fd, width, height, 1, 3, dest, bytesperline);
|
|
|
|
gimp_image_set_colormap (image, pcx_header.colormap, 8);
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
2017-05-14 11:30:53 +08:00
|
|
|
else if (pcx_header.bpp == 1 && pcx_header.planes == 4)
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2009-12-02 22:12:17 +08:00
|
|
|
dest = g_new (guchar, ((gsize) width) * height);
|
2007-09-18 02:56:34 +08:00
|
|
|
load_4 (fd, width, height, dest, bytesperline);
|
2004-11-02 20:00:25 +08:00
|
|
|
gimp_image_set_colormap (image, pcx_header.colormap, 16);
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
2017-05-14 11:30:53 +08:00
|
|
|
else if (pcx_header.bpp == 4 && pcx_header.planes == 1)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
dest = g_new (guchar, ((gsize) width) * height);
|
2017-05-14 11:30:53 +08:00
|
|
|
load_sub_8 (fd, width, height, 4, 1, dest, bytesperline);
|
2017-05-10 19:56:28 +08:00
|
|
|
gimp_image_set_colormap (image, pcx_header.colormap, 16);
|
|
|
|
}
|
2017-05-14 11:30:53 +08:00
|
|
|
else if (pcx_header.bpp == 8 && pcx_header.planes == 1)
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2009-12-02 22:12:17 +08:00
|
|
|
dest = g_new (guchar, ((gsize) width) * height);
|
2007-09-18 02:56:34 +08:00
|
|
|
load_8 (fd, width, height, dest, bytesperline);
|
2007-08-30 19:49:52 +08:00
|
|
|
fseek (fd, -768L, SEEK_END);
|
|
|
|
fread (cmap, 768, 1, fd);
|
2004-11-02 20:00:25 +08:00
|
|
|
gimp_image_set_colormap (image, cmap, 256);
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
2023-04-27 04:52:27 +08:00
|
|
|
else if (pcx_header.bpp == 8 && (pcx_header.planes == 3 || pcx_header.planes == 4))
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2023-04-27 04:52:27 +08:00
|
|
|
dest = g_new (guchar, ((gsize) width) * height * pcx_header.planes);
|
|
|
|
load_24 (fd, width, height, dest, bytesperline, pcx_header.planes);
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-03-05 00:32:32 +08:00
|
|
|
g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
|
|
|
|
_("Unusual PCX flavour, giving up"));
|
|
|
|
g_object_unref (buffer);
|
2019-08-25 01:27:46 +08:00
|
|
|
return NULL;
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
|
|
|
|
NULL, dest, GEGL_AUTO_ROWSTRIDE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
g_free (dest);
|
2012-11-20 05:26:04 +08:00
|
|
|
g_object_unref (buffer);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
return image;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2023-03-19 11:01:13 +08:00
|
|
|
static gboolean
|
|
|
|
pcx_load_dialog (GimpProcedure *procedure,
|
|
|
|
GObject *config)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
gboolean run;
|
|
|
|
|
|
|
|
gimp_ui_init (PLUG_IN_BINARY);
|
|
|
|
|
|
|
|
dialog = gimp_procedure_dialog_new (procedure,
|
|
|
|
GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
_("Import from PCX"));
|
|
|
|
|
2024-07-14 12:12:26 +08:00
|
|
|
gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"override-palette", GIMP_TYPE_INT_RADIO_FRAME);
|
2023-03-19 11:01:13 +08:00
|
|
|
|
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
gtk_widget_show (dialog);
|
|
|
|
|
|
|
|
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
|
|
|
|
|
|
|
|
gtk_widget_destroy (dialog);
|
|
|
|
|
|
|
|
return run;
|
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2007-08-30 19:49:52 +08:00
|
|
|
load_8 (FILE *fp,
|
2008-05-11 02:16:33 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
2012-11-20 05:26:04 +08:00
|
|
|
guchar *buf,
|
2008-05-11 02:16:33 +08:00
|
|
|
guint16 bytes)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2003-07-03 21:26:06 +08:00
|
|
|
gint row;
|
2007-08-30 19:49:52 +08:00
|
|
|
guchar *line = g_new (guchar, bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
for (row = 0; row < height; buf += width, ++row)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
readline (fp, line, bytes);
|
2012-11-20 05:26:04 +08:00
|
|
|
memcpy (buf, line, width);
|
1999-10-10 03:06:14 +08:00
|
|
|
gimp_progress_update ((double) row / (double) height);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
g_free (line);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2007-08-30 19:49:52 +08:00
|
|
|
load_24 (FILE *fp,
|
2008-05-11 02:16:33 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
2012-11-20 05:26:04 +08:00
|
|
|
guchar *buf,
|
2023-04-27 04:52:27 +08:00
|
|
|
guint16 bytes,
|
|
|
|
guint8 planes)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2003-07-03 21:26:06 +08:00
|
|
|
gint x, y, c;
|
2007-08-30 19:49:52 +08:00
|
|
|
guchar *line = g_new (guchar, bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2023-04-27 04:52:27 +08:00
|
|
|
for (y = 0; y < height; buf += width * planes, ++y)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2023-04-27 04:52:27 +08:00
|
|
|
for (c = 0; c < planes; ++c)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
readline (fp, line, bytes);
|
|
|
|
for (x = 0; x < width; ++x)
|
|
|
|
{
|
2023-04-27 04:52:27 +08:00
|
|
|
buf[x * planes + c] = line[x];
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
|
|
|
}
|
1999-10-10 03:06:14 +08:00
|
|
|
gimp_progress_update ((double) y / (double) height);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
2000-01-26 01:46:56 +08:00
|
|
|
|
|
|
|
g_free (line);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2007-08-30 19:49:52 +08:00
|
|
|
load_1 (FILE *fp,
|
2008-05-11 02:16:33 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
2012-11-20 05:26:04 +08:00
|
|
|
guchar *buf,
|
2008-05-11 02:16:33 +08:00
|
|
|
guint16 bytes)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2003-07-03 21:26:06 +08:00
|
|
|
gint x, y;
|
|
|
|
guchar *line = g_new (guchar, bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
for (y = 0; y < height; buf += width, ++y)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
readline (fp, line, bytes);
|
2003-11-06 23:27:05 +08:00
|
|
|
for (x = 0; x < width; ++x)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
if (line[x / 8] & (128 >> (x % 8)))
|
2012-11-20 05:26:04 +08:00
|
|
|
buf[x] = 1;
|
2008-05-11 02:16:33 +08:00
|
|
|
else
|
2012-11-20 05:26:04 +08:00
|
|
|
buf[x] = 0;
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
1999-10-10 03:06:14 +08:00
|
|
|
gimp_progress_update ((double) y / (double) height);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
2000-01-26 01:46:56 +08:00
|
|
|
|
|
|
|
g_free (line);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2007-08-30 19:49:52 +08:00
|
|
|
load_4 (FILE *fp,
|
2008-05-11 02:16:33 +08:00
|
|
|
gint width,
|
|
|
|
gint height,
|
2012-11-20 05:26:04 +08:00
|
|
|
guchar *buf,
|
2008-05-11 02:16:33 +08:00
|
|
|
guint16 bytes)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2003-07-03 21:26:06 +08:00
|
|
|
gint x, y, c;
|
2007-08-30 19:49:52 +08:00
|
|
|
guchar *line = g_new (guchar, bytes);
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
for (y = 0; y < height; buf += width, ++y)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2007-08-30 19:49:52 +08:00
|
|
|
for (x = 0; x < width; ++x)
|
2012-11-20 05:26:04 +08:00
|
|
|
buf[x] = 0;
|
2003-11-06 23:27:05 +08:00
|
|
|
for (c = 0; c < 4; ++c)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
readline(fp, line, bytes);
|
|
|
|
for (x = 0; x < width; ++x)
|
|
|
|
{
|
|
|
|
if (line[x / 8] & (128 >> (x % 8)))
|
2012-11-20 05:26:04 +08:00
|
|
|
buf[x] += (1 << c);
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
|
|
|
}
|
1999-10-10 03:06:14 +08:00
|
|
|
gimp_progress_update ((double) y / (double) height);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
g_free (line);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2017-05-10 19:56:28 +08:00
|
|
|
static void
|
2017-06-09 18:56:03 +08:00
|
|
|
load_sub_8 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gint bpp,
|
|
|
|
gint plane,
|
|
|
|
guchar *buf,
|
|
|
|
guint16 bytes)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
2017-05-14 11:30:53 +08:00
|
|
|
gint x, y, c, b;
|
2017-05-10 19:56:28 +08:00
|
|
|
guchar *line = g_new (guchar, bytes);
|
2017-06-09 18:56:03 +08:00
|
|
|
gint real_bpp = bpp - 1;
|
|
|
|
gint current_bit = 0;
|
2017-05-10 19:56:28 +08:00
|
|
|
|
|
|
|
for (y = 0; y < height; buf += width, ++y)
|
|
|
|
{
|
|
|
|
for (x = 0; x < width; ++x)
|
|
|
|
buf[x] = 0;
|
|
|
|
for (c = 0; c < plane; ++c)
|
|
|
|
{
|
2017-06-09 18:56:03 +08:00
|
|
|
readline (fp, line, bytes);
|
2017-05-10 19:56:28 +08:00
|
|
|
for (x = 0; x < width; ++x)
|
|
|
|
{
|
2017-05-14 11:30:53 +08:00
|
|
|
for (b = 0; b < bpp; b++)
|
|
|
|
{
|
|
|
|
current_bit = bpp * x + b;
|
|
|
|
if (line[current_bit / 8] & (128 >> (current_bit % 8)))
|
|
|
|
buf[x] += (1 << (real_bpp - b + c));
|
|
|
|
}
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
gimp_progress_update ((double) y / (double) height);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (line);
|
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2003-11-06 23:27:05 +08:00
|
|
|
readline (FILE *fp,
|
2012-11-20 05:26:04 +08:00
|
|
|
guchar *buf,
|
2008-05-11 02:16:33 +08:00
|
|
|
gint bytes)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
static guchar count = 0, value = 0;
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
if (pcx_header.compression)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2003-11-06 23:27:05 +08:00
|
|
|
while (bytes--)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
if (count == 0)
|
|
|
|
{
|
|
|
|
value = fgetc (fp);
|
|
|
|
if (value < 0xc0)
|
|
|
|
{
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count = value - 0xc0;
|
|
|
|
value = fgetc (fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
count--;
|
2012-11-20 05:26:04 +08:00
|
|
|
*(buf++) = value;
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
2003-11-06 23:27:05 +08:00
|
|
|
}
|
|
|
|
else
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2012-11-20 05:26:04 +08:00
|
|
|
fread (buf, bytes, 1, fp);
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
static gboolean
|
2024-04-13 23:10:25 +08:00
|
|
|
export_image (GFile *file,
|
|
|
|
GimpImage *image,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GError **error)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2005-08-15 19:07:27 +08:00
|
|
|
FILE *fp;
|
2012-11-20 05:26:04 +08:00
|
|
|
GeglBuffer *buffer;
|
|
|
|
const Babl *format;
|
2005-08-15 19:07:27 +08:00
|
|
|
GimpImageType drawable_type;
|
|
|
|
guchar *cmap= NULL;
|
|
|
|
guchar *pixels;
|
2007-08-30 19:49:52 +08:00
|
|
|
gint offset_x, offset_y;
|
|
|
|
guint width, height;
|
2013-11-01 20:51:31 +08:00
|
|
|
gdouble resolution_x, resolution_y;
|
2005-08-15 19:07:27 +08:00
|
|
|
gint colors, i;
|
2007-08-30 19:49:52 +08:00
|
|
|
guint8 header_buf[128];
|
2018-11-02 05:05:44 +08:00
|
|
|
gboolean padding = FALSE;
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
drawable_type = gimp_drawable_type (drawable);
|
2021-04-06 20:28:40 +08:00
|
|
|
gimp_drawable_get_offsets (drawable, &offset_x, &offset_y);
|
2012-11-20 05:26:04 +08:00
|
|
|
|
2019-08-25 01:27:46 +08:00
|
|
|
buffer = gimp_drawable_get_buffer (drawable);
|
2012-11-20 05:26:04 +08:00
|
|
|
|
|
|
|
width = gegl_buffer_get_width (buffer);
|
|
|
|
height = gegl_buffer_get_height (buffer);
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2016-02-16 09:35:43 +08:00
|
|
|
gimp_progress_init_printf (_("Exporting '%s'"),
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_file_get_utf8_name (file));
|
1998-01-25 09:24:46 +08:00
|
|
|
|
|
|
|
pcx_header.manufacturer = 0x0a;
|
2019-08-25 01:27:46 +08:00
|
|
|
pcx_header.version = 5;
|
|
|
|
pcx_header.compression = 1;
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
switch (drawable_type)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_INDEXED_IMAGE:
|
2023-05-24 05:37:46 +08:00
|
|
|
cmap = gimp_image_get_colormap (image, NULL, &colors);
|
|
|
|
|
2017-06-09 18:56:03 +08:00
|
|
|
if (colors > 16)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
pcx_header.bpp = 8;
|
|
|
|
pcx_header.planes = 1;
|
2018-11-02 05:05:44 +08:00
|
|
|
pcx_header.bytesperline = width;
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
2017-06-09 18:56:03 +08:00
|
|
|
else if (colors > 2)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
pcx_header.bpp = 4;
|
|
|
|
pcx_header.planes = 1;
|
2018-11-02 05:05:44 +08:00
|
|
|
pcx_header.bytesperline = (width + 1) / 2;
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pcx_header.bpp = 1;
|
|
|
|
pcx_header.planes = 1;
|
2018-11-02 05:05:44 +08:00
|
|
|
pcx_header.bytesperline = (width + 7) / 8;
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
2012-11-20 05:26:04 +08:00
|
|
|
pcx_header.color = GUINT16_TO_LE (1);
|
|
|
|
format = NULL;
|
2017-06-09 18:56:03 +08:00
|
|
|
|
|
|
|
/* Some references explain that 2bpp/1plane and 4bpp/1plane files
|
|
|
|
* would use the palette at EOF (not the one from the header) if
|
|
|
|
* we are in version 5 of PCX. Other sources affirm that even in
|
|
|
|
* version 5, EOF palette must be used only when there are more
|
|
|
|
* than 16 colors. We go with this second assumption.
|
|
|
|
* See bug 159947, comment 21 and 23.
|
|
|
|
*/
|
|
|
|
if (colors <= 16)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
2017-06-09 18:56:03 +08:00
|
|
|
for (i = 0; i < (colors * 3); i++)
|
|
|
|
{
|
|
|
|
pcx_header.colormap[i] = cmap[i];
|
|
|
|
}
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
2017-06-09 18:56:03 +08:00
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
break;
|
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RGB_IMAGE:
|
2012-11-20 05:26:04 +08:00
|
|
|
pcx_header.bpp = 8;
|
|
|
|
pcx_header.planes = 3;
|
|
|
|
pcx_header.color = GUINT16_TO_LE (1);
|
2018-11-02 05:05:44 +08:00
|
|
|
pcx_header.bytesperline = width;
|
2012-11-20 05:26:04 +08:00
|
|
|
format = babl_format ("R'G'B' u8");
|
1998-01-25 09:24:46 +08:00
|
|
|
break;
|
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_GRAY_IMAGE:
|
2012-11-20 05:26:04 +08:00
|
|
|
pcx_header.bpp = 8;
|
|
|
|
pcx_header.planes = 1;
|
|
|
|
pcx_header.color = GUINT16_TO_LE (2);
|
2018-11-02 05:05:44 +08:00
|
|
|
pcx_header.bytesperline = width;
|
2012-11-20 05:26:04 +08:00
|
|
|
format = babl_format ("Y' u8");
|
1998-01-25 09:24:46 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-02-16 09:35:43 +08:00
|
|
|
g_message (_("Cannot export images with alpha channel."));
|
2000-01-26 01:46:56 +08:00
|
|
|
return FALSE;
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
2017-06-09 18:56:03 +08:00
|
|
|
|
2017-05-14 11:30:53 +08:00
|
|
|
/* Bytes per Line must be an even number, according to spec */
|
|
|
|
if (pcx_header.bytesperline % 2 != 0)
|
|
|
|
{
|
|
|
|
pcx_header.bytesperline++;
|
2018-11-02 05:05:44 +08:00
|
|
|
padding = TRUE;
|
2017-06-09 18:56:03 +08:00
|
|
|
}
|
2018-11-02 05:05:44 +08:00
|
|
|
pcx_header.bytesperline = GUINT16_TO_LE (pcx_header.bytesperline);
|
2000-01-26 01:46:56 +08:00
|
|
|
|
|
|
|
pixels = (guchar *) g_malloc (width * height * pcx_header.planes);
|
2012-11-20 05:26:04 +08:00
|
|
|
|
|
|
|
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, width, height), 1.0,
|
|
|
|
format, pixels,
|
|
|
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
if ((offset_x < 0) || (offset_x > (1<<16)))
|
|
|
|
{
|
|
|
|
g_message (_("Invalid X offset: %d"), offset_x);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((offset_y < 0) || (offset_y > (1<<16)))
|
|
|
|
{
|
|
|
|
g_message (_("Invalid Y offset: %d"), offset_y);
|
|
|
|
return FALSE;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
if (offset_x + width - 1 > (1<<16))
|
|
|
|
{
|
|
|
|
g_message (_("Right border out of bounds (must be < %d): %d"), (1<<16),
|
|
|
|
offset_x + width - 1);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offset_y + height - 1 > (1<<16))
|
|
|
|
{
|
|
|
|
g_message (_("Bottom border out of bounds (must be < %d): %d"), (1<<16),
|
|
|
|
offset_y + height - 1);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2021-10-02 00:56:12 +08:00
|
|
|
fp = g_fopen (g_file_peek_path (file), "wb");
|
2019-09-12 03:48:34 +08:00
|
|
|
|
|
|
|
if (! fp)
|
2010-11-10 02:06:00 +08:00
|
|
|
{
|
|
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
|
|
_("Could not open '%s' for writing: %s"),
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_file_get_utf8_name (file), g_strerror (errno));
|
2010-11-10 02:06:00 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
pcx_header.x1 = GUINT16_TO_LE ((guint16)offset_x);
|
|
|
|
pcx_header.y1 = GUINT16_TO_LE ((guint16)offset_y);
|
|
|
|
pcx_header.x2 = GUINT16_TO_LE ((guint16)(offset_x + width - 1));
|
|
|
|
pcx_header.y2 = GUINT16_TO_LE ((guint16)(offset_y + height - 1));
|
|
|
|
|
2013-11-01 20:51:31 +08:00
|
|
|
gimp_image_get_resolution (image, &resolution_x, &resolution_y);
|
|
|
|
|
|
|
|
pcx_header.hdpi = GUINT16_TO_LE (RINT (MAX (resolution_x, 1.0)));
|
|
|
|
pcx_header.vdpi = GUINT16_TO_LE (RINT (MAX (resolution_y, 1.0)));
|
1998-01-25 09:24:46 +08:00
|
|
|
pcx_header.reserved = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
pcx_header_to_buffer (header_buf);
|
|
|
|
|
|
|
|
fwrite (header_buf, 128, 1, fp);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
switch (drawable_type)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_INDEXED_IMAGE:
|
2017-06-09 18:56:03 +08:00
|
|
|
if (colors > 16)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
2018-11-02 05:05:44 +08:00
|
|
|
save_8 (fp, width, height, pixels, padding);
|
2017-06-09 18:56:03 +08:00
|
|
|
fputc (0x0c, fp);
|
|
|
|
fwrite (cmap, colors, 3, fp);
|
|
|
|
for (i = colors; i < 256; i++)
|
|
|
|
{
|
|
|
|
fputc (0, fp);
|
|
|
|
fputc (0, fp);
|
|
|
|
fputc (0, fp);
|
|
|
|
}
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
|
|
|
else /* Covers 1 and 4 bpp */
|
|
|
|
{
|
2018-11-02 05:05:44 +08:00
|
|
|
save_less_than_8 (fp, width, height, pcx_header.bpp, pixels, padding);
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
1998-01-25 09:24:46 +08:00
|
|
|
break;
|
2003-06-13 22:37:00 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RGB_IMAGE:
|
2018-11-02 05:05:44 +08:00
|
|
|
save_24 (fp, width, height, pixels, padding);
|
1998-01-25 09:24:46 +08:00
|
|
|
break;
|
2003-06-13 22:37:00 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_GRAY_IMAGE:
|
2018-11-02 05:05:44 +08:00
|
|
|
save_8 (fp, width, height, pixels, padding);
|
2000-01-26 01:46:56 +08:00
|
|
|
fputc (0x0c, fp);
|
2003-11-06 23:27:05 +08:00
|
|
|
for (i = 0; i < 256; i++)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
fputc ((guchar) i, fp);
|
2007-08-30 19:49:52 +08:00
|
|
|
fputc ((guchar) i, fp);
|
|
|
|
fputc ((guchar) i, fp);
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
1998-01-25 09:24:46 +08:00
|
|
|
break;
|
2003-06-13 22:37:00 +08:00
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
default:
|
2000-01-26 01:46:56 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
g_object_unref (buffer);
|
2000-01-26 01:46:56 +08:00
|
|
|
g_free (pixels);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2007-08-30 19:49:52 +08:00
|
|
|
if (fclose (fp) != 0)
|
|
|
|
{
|
2008-08-18 14:31:03 +08:00
|
|
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
|
|
|
_("Writing to file '%s' failed: %s"),
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_file_get_utf8_name (file), g_strerror (errno));
|
2007-08-30 19:49:52 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
2008-08-18 14:31:03 +08:00
|
|
|
|
1998-01-25 09:24:46 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2017-05-10 19:56:28 +08:00
|
|
|
static void
|
|
|
|
save_less_than_8 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
const gint bpp,
|
2018-11-02 05:05:44 +08:00
|
|
|
const guchar *buf,
|
|
|
|
gboolean padding)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
2017-06-09 18:56:03 +08:00
|
|
|
const gint bit_limit = (8 - bpp);
|
|
|
|
const gint buf_size = width * height;
|
|
|
|
const gint line_end = width - 1;
|
|
|
|
gint j = bit_limit;
|
|
|
|
gint count = 0;
|
|
|
|
guchar byte_to_write = 0x00;
|
|
|
|
guchar *line;
|
2017-06-30 00:39:41 +08:00
|
|
|
gint x;
|
2017-05-10 19:56:28 +08:00
|
|
|
|
|
|
|
line = (guchar *) g_malloc (((width + 7) / 8) * bpp);
|
|
|
|
|
2017-06-30 00:39:41 +08:00
|
|
|
for (x = 0; x < buf_size; x++)
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
byte_to_write |= (buf[x] << j);
|
|
|
|
j -= bpp;
|
|
|
|
|
2017-05-14 11:30:53 +08:00
|
|
|
if (j < 0 || (x % width == line_end))
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
line[count] = byte_to_write;
|
|
|
|
count++;
|
|
|
|
byte_to_write = 0x00;
|
|
|
|
j = bit_limit;
|
|
|
|
|
2017-05-14 11:30:53 +08:00
|
|
|
if ((x % width == line_end))
|
2017-05-10 19:56:28 +08:00
|
|
|
{
|
|
|
|
writeline (fp, line, count);
|
|
|
|
count = 0;
|
2018-11-02 05:05:44 +08:00
|
|
|
if (padding)
|
|
|
|
fputc ('\0', fp);
|
2017-05-10 19:56:28 +08:00
|
|
|
gimp_progress_update ((double) x / (double) buf_size);
|
2017-05-14 11:30:53 +08:00
|
|
|
}
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
|
|
|
}
|
2017-05-14 11:30:53 +08:00
|
|
|
g_free (line);
|
2017-05-10 19:56:28 +08:00
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2009-02-25 18:56:41 +08:00
|
|
|
save_8 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
2018-11-02 05:05:44 +08:00
|
|
|
const guchar *buf,
|
|
|
|
gboolean padding)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
1998-01-25 09:24:46 +08:00
|
|
|
int row;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
for (row = 0; row < height; ++row)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2012-11-20 05:26:04 +08:00
|
|
|
writeline (fp, buf, width);
|
|
|
|
buf += width;
|
2018-11-02 05:05:44 +08:00
|
|
|
if (padding)
|
|
|
|
fputc ('\0', fp);
|
2000-01-26 01:46:56 +08:00
|
|
|
gimp_progress_update ((double) row / (double) height);
|
1999-10-10 03:06:14 +08:00
|
|
|
}
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2009-02-25 18:56:41 +08:00
|
|
|
save_24 (FILE *fp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
2018-11-02 05:05:44 +08:00
|
|
|
const guchar *buf,
|
|
|
|
gboolean padding)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2007-08-30 19:49:52 +08:00
|
|
|
int x, y, c;
|
1998-01-25 09:24:46 +08:00
|
|
|
guchar *line;
|
2007-08-30 19:49:52 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
line = (guchar *) g_malloc (width);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
for (y = 0; y < height; ++y)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2003-11-06 23:27:05 +08:00
|
|
|
for (c = 0; c < 3; ++c)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
for (x = 0; x < width; ++x)
|
|
|
|
{
|
2012-11-20 05:26:04 +08:00
|
|
|
line[x] = buf[(3*x) + c];
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
|
|
|
writeline (fp, line, width);
|
2018-11-02 05:05:44 +08:00
|
|
|
if (padding)
|
|
|
|
fputc ('\0', fp);
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
2012-11-20 05:26:04 +08:00
|
|
|
buf += width * 3;
|
2007-08-30 19:49:52 +08:00
|
|
|
gimp_progress_update ((double) y / (double) height);
|
1999-10-10 03:06:14 +08:00
|
|
|
}
|
1998-01-25 09:24:46 +08:00
|
|
|
g_free (line);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static void
|
2009-02-25 18:56:41 +08:00
|
|
|
writeline (FILE *fp,
|
2012-11-20 05:26:04 +08:00
|
|
|
const guchar *buf,
|
2009-02-25 18:56:41 +08:00
|
|
|
gint bytes)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2012-11-20 05:26:04 +08:00
|
|
|
const guchar *finish = buf + bytes;
|
2009-02-25 18:56:41 +08:00
|
|
|
guchar value;
|
|
|
|
guchar count;
|
1998-01-25 09:24:46 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
while (buf < finish)
|
1999-10-10 03:06:14 +08:00
|
|
|
{
|
2012-11-20 05:26:04 +08:00
|
|
|
value = *(buf++);
|
2000-01-26 01:46:56 +08:00
|
|
|
count = 1;
|
2003-11-06 23:27:05 +08:00
|
|
|
|
2012-11-20 05:26:04 +08:00
|
|
|
while (buf < finish && count < 63 && *buf == value)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
2012-11-20 05:26:04 +08:00
|
|
|
count++; buf++;
|
2008-05-11 02:16:33 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-11-06 23:27:05 +08:00
|
|
|
if (value < 0xc0 && count == 1)
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
fputc (value, fp);
|
|
|
|
}
|
2003-11-06 23:27:05 +08:00
|
|
|
else
|
2008-05-11 02:16:33 +08:00
|
|
|
{
|
|
|
|
fputc (0xc0 + count, fp);
|
|
|
|
fputc (value, fp);
|
|
|
|
}
|
1998-01-25 09:24:46 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|