mirror of https://github.com/GNOME/gimp.git
2074 lines
55 KiB
C
2074 lines
55 KiB
C
/* The GIMP -- an image manipulation program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
* XWD reading and writing code Copyright (C) 1996 Peter Kirchgessner
|
|
* (email: pkirchg@aol.com, WWW: http://members.aol.com/pkirchg)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* XWD-input/output was written by Peter Kirchgessner (pkirchg@aol.com).
|
|
* Examples from mainly used UNIX-systems have been used for testing.
|
|
* If a file does not work, please return a small (!!) compressed example.
|
|
* Currently the following formats are supported:
|
|
* pixmap_format | pixmap_depth | bits_per_pixel
|
|
* ---------------------------------------------
|
|
* 0 | 1 | 1
|
|
* 1 | 1,...,24 | 1
|
|
* 2 | 1 | 1
|
|
* 2 | 1,...,8 | 8
|
|
* 2 | 1,...,16 | 16
|
|
* 2 | 1,...,24 | 24
|
|
* 2 | 1,...,24 | 32
|
|
*/
|
|
/* Event history:
|
|
* V 1.00, PK, xx-Aug-96: First try
|
|
* V 1.01, PK, 03-Sep-96: Check for bitmap_bit_order
|
|
* V 1.90, PK, 17-Mar-97: Upgrade to work with GIMP V0.99
|
|
* Use visual class 3 to write indexed image
|
|
* Set gimp b/w-colormap if no xwdcolormap present
|
|
* V 1.91, PK, 05-Apr-97: Return all arguments, even in case of an error
|
|
* V 1.92, PK, 12-Oct-97: No progress bars for non-interactive mode
|
|
* V 1.93, PK, 11-Apr-98: Fix problem with overwriting memory
|
|
*/
|
|
static char ident[] = "@(#) GIMP XWD file-plugin v1.93 11-Apr-98";
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "gtk/gtk.h"
|
|
#include "libgimp/gimp.h"
|
|
|
|
typedef unsigned long L_CARD32;
|
|
typedef unsigned short L_CARD16;
|
|
typedef unsigned char L_CARD8;
|
|
|
|
typedef struct {
|
|
L_CARD32 l_header_size; /* Header size */
|
|
|
|
L_CARD32 l_file_version; /* File version (7) */
|
|
L_CARD32 l_pixmap_format; /* Image type */
|
|
L_CARD32 l_pixmap_depth; /* Number of planes */
|
|
L_CARD32 l_pixmap_width; /* Image width */
|
|
L_CARD32 l_pixmap_height; /* Image height */
|
|
L_CARD32 l_xoffset; /* x-offset (0 ?) */
|
|
L_CARD32 l_byte_order; /* Byte ordering */
|
|
|
|
L_CARD32 l_bitmap_unit;
|
|
L_CARD32 l_bitmap_bit_order; /* Bit order */
|
|
L_CARD32 l_bitmap_pad;
|
|
L_CARD32 l_bits_per_pixel; /* Number of bits per pixel */
|
|
|
|
L_CARD32 l_bytes_per_line; /* Number of bytes per scanline */
|
|
L_CARD32 l_visual_class; /* Visual class */
|
|
L_CARD32 l_red_mask; /* Red mask */
|
|
L_CARD32 l_green_mask; /* Green mask */
|
|
L_CARD32 l_blue_mask; /* Blue mask */
|
|
L_CARD32 l_bits_per_rgb; /* Number of bits per RGB-part */
|
|
L_CARD32 l_colormap_entries; /* Number of colours in colour table (?) */
|
|
L_CARD32 l_ncolors; /* Number of xwdcolor structures */
|
|
L_CARD32 l_window_width; /* Window width */
|
|
L_CARD32 l_window_height; /* Window height */
|
|
L_CARD32 l_window_x; /* Window position x */
|
|
L_CARD32 l_window_y; /* Window position y */
|
|
L_CARD32 l_window_bdrwidth;/* Window border width */
|
|
} L_XWDFILEHEADER;
|
|
|
|
typedef struct {
|
|
L_CARD32 l_pixel; /* Colour index */
|
|
L_CARD16 l_red, l_green, l_blue; /* RGB-values */
|
|
L_CARD8 l_flags, l_pad;
|
|
} L_XWDCOLOR;
|
|
|
|
|
|
/* Some structures for mapping up to 32bit-pixel */
|
|
/* values which are kept in the XWD-Colormap */
|
|
|
|
#define MAPPERBITS 12
|
|
#define MAPPERMASK ((1 << MAPPERBITS)-1)
|
|
|
|
typedef struct {
|
|
L_CARD32 pixel_val;
|
|
unsigned char red,green,blue;
|
|
} PMAP;
|
|
|
|
typedef struct {
|
|
int npixel; /* Number of pixel values in map */
|
|
unsigned char pixel_in_map[1 << MAPPERBITS];
|
|
PMAP pmap[256];
|
|
} PIXEL_MAP;
|
|
|
|
#define XWDHDR_PAD 0 /* Total number of padding bytes for XWD header */
|
|
#define XWDCOL_PAD 0 /* Total number of padding bytes for each XWD color */
|
|
|
|
/* Declare some local functions.
|
|
*/
|
|
static void query (void);
|
|
static void run (char *name,
|
|
int nparams,
|
|
GParam *param,
|
|
int *nreturn_vals,
|
|
GParam **return_vals);
|
|
|
|
static gint32 load_image (char *filename);
|
|
static gint save_image (char *filename,
|
|
gint32 image_ID,
|
|
gint32 drawable_ID);
|
|
static gint32 create_new_image (char *filename, guint width, guint height,
|
|
GImageType type, gint32 *layer_ID, GDrawable **drawable,
|
|
GPixelRgn *pixel_rgn);
|
|
|
|
static int set_pixelmap (int, L_XWDCOLOR *,PIXEL_MAP *);
|
|
static int get_pixelmap (L_CARD32, PIXEL_MAP *,unsigned char *,
|
|
unsigned char *, unsigned char *);
|
|
static void set_bw_color_table (gint32);
|
|
static void set_color_table (gint32, L_XWDFILEHEADER *, L_XWDCOLOR *);
|
|
|
|
static gint32 load_xwd_f2_d1_b1 (char *, FILE *, L_XWDFILEHEADER *,
|
|
L_XWDCOLOR *);
|
|
static gint32 load_xwd_f2_d8_b8 (char *, FILE *, L_XWDFILEHEADER *,
|
|
L_XWDCOLOR *);
|
|
static gint32 load_xwd_f2_d16_b16 (char *, FILE *, L_XWDFILEHEADER *,
|
|
L_XWDCOLOR *);
|
|
static gint32 load_xwd_f2_d24_b32 (char *, FILE *, L_XWDFILEHEADER *,
|
|
L_XWDCOLOR *);
|
|
static gint32 load_xwd_f1_d24_b1 (char *, FILE *, L_XWDFILEHEADER *,
|
|
L_XWDCOLOR *);
|
|
|
|
static L_CARD32 read_card32 (FILE *, int *);
|
|
static L_CARD16 read_card16 (FILE *, int *);
|
|
static L_CARD8 read_card8 (FILE *, int *);
|
|
|
|
static void write_card32 (FILE *, L_CARD32);
|
|
static void write_card16 (FILE *, L_CARD32);
|
|
static void write_card8 (FILE *, L_CARD32);
|
|
|
|
static void read_xwd_header (FILE *, L_XWDFILEHEADER *);
|
|
static void write_xwd_header (FILE *, L_XWDFILEHEADER *);
|
|
static void read_xwd_cols (FILE *, L_XWDFILEHEADER *, L_XWDCOLOR *);
|
|
static void write_xwd_cols (FILE *, L_XWDFILEHEADER *, L_XWDCOLOR *);
|
|
|
|
static gint save_index (FILE *, gint32, gint32, int);
|
|
static gint save_rgb (FILE *, gint32, gint32);
|
|
|
|
static void show_message (char *);
|
|
|
|
static int read_msb_first = 1;
|
|
|
|
|
|
GPlugInInfo PLUG_IN_INFO =
|
|
{
|
|
NULL, /* init_proc */
|
|
NULL, /* quit_proc */
|
|
query, /* query_proc */
|
|
run, /* run_proc */
|
|
};
|
|
|
|
|
|
/* The run mode */
|
|
static GRunModeType l_run_mode;
|
|
|
|
|
|
MAIN ()
|
|
|
|
|
|
static void
|
|
query (void)
|
|
|
|
{
|
|
static GParamDef load_args[] =
|
|
{
|
|
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
|
|
{ PARAM_STRING, "filename", "The name of the file to load" },
|
|
{ PARAM_STRING, "raw_filename", "The name of the file to load" },
|
|
};
|
|
static GParamDef load_return_vals[] =
|
|
{
|
|
{ PARAM_IMAGE, "image", "Output image" },
|
|
};
|
|
static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
|
|
static int nload_return_vals = sizeof (load_return_vals)
|
|
/ sizeof (load_return_vals[0]);
|
|
|
|
static GParamDef save_args[] =
|
|
{
|
|
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
|
|
{ PARAM_IMAGE, "image", "Input image" },
|
|
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
|
|
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
|
|
{ PARAM_STRING, "raw_filename",
|
|
"The name of the file to save the image in" }
|
|
};
|
|
static int nsave_args = sizeof (save_args) / sizeof (save_args[0]);
|
|
|
|
gimp_install_procedure ("file_xwd_load",
|
|
"load file of the XWD file format",
|
|
"load file of the XWD file format",
|
|
"Peter Kirchgessner",
|
|
"Peter Kirchgessner",
|
|
"1996",
|
|
"<Load>/XWD",
|
|
NULL,
|
|
PROC_PLUG_IN,
|
|
nload_args, nload_return_vals,
|
|
load_args, load_return_vals);
|
|
|
|
gimp_install_procedure ("file_xwd_save",
|
|
"saves files in the XWD file format",
|
|
"XWD saving handles all image types except \
|
|
those with alpha channels.",
|
|
"Peter Kirchgessner",
|
|
"Peter Kirchgessner",
|
|
"1996",
|
|
"<Save>/XWD",
|
|
"RGB*, GRAY*, INDEXED*",
|
|
PROC_PLUG_IN,
|
|
nsave_args, 0,
|
|
save_args, NULL);
|
|
|
|
gimp_register_magic_load_handler ("file_xwd_load", "xwd", "",
|
|
"4,long,0x00000007,4,long,0x07000000");
|
|
gimp_register_save_handler ("file_xwd_save", "xwd", "");
|
|
}
|
|
|
|
|
|
static void
|
|
run (char *name,
|
|
int nparams,
|
|
GParam *param,
|
|
int *nreturn_vals,
|
|
GParam **return_vals)
|
|
|
|
{
|
|
static GParam values[2];
|
|
GRunModeType run_mode;
|
|
GStatusType status = STATUS_SUCCESS;
|
|
gint32 image_ID;
|
|
int ev;
|
|
|
|
l_run_mode = run_mode = param[0].data.d_int32;
|
|
|
|
*nreturn_vals = 1;
|
|
*return_vals = values;
|
|
values[0].type = PARAM_STATUS;
|
|
values[0].data.d_status = STATUS_CALLING_ERROR;
|
|
|
|
if (strcmp (name, "file_xwd_load") == 0)
|
|
{
|
|
image_ID = load_image (param[1].data.d_string);
|
|
|
|
*nreturn_vals = 2;
|
|
status = (image_ID != -1) ? STATUS_SUCCESS : STATUS_EXECUTION_ERROR;
|
|
values[0].data.d_status = status;
|
|
values[1].type = PARAM_IMAGE;
|
|
values[1].data.d_image = image_ID;
|
|
}
|
|
else if (strcmp (name, "file_xwd_save") == 0)
|
|
{
|
|
switch (run_mode)
|
|
{
|
|
case RUN_INTERACTIVE:
|
|
case RUN_WITH_LAST_VALS:
|
|
/* No additional data to retrieve */
|
|
break;
|
|
|
|
case RUN_NONINTERACTIVE:
|
|
/* Make sure all the arguments are there! */
|
|
if (nparams != 5)
|
|
status = STATUS_CALLING_ERROR;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
ev = save_image (param[3].data.d_string, param[1].data.d_int32,
|
|
param[2].data.d_int32);
|
|
status = ev ? STATUS_SUCCESS : STATUS_EXECUTION_ERROR;
|
|
}
|
|
values[0].data.d_status = status;
|
|
}
|
|
}
|
|
|
|
|
|
static gint32
|
|
load_image (char *filename)
|
|
|
|
{
|
|
FILE *ifp;
|
|
int depth, bpp;
|
|
char *temp;
|
|
gint32 image_ID;
|
|
L_XWDFILEHEADER xwdhdr;
|
|
L_XWDCOLOR *xwdcolmap = NULL;
|
|
|
|
ifp = fopen (filename, "rb");
|
|
if (!ifp)
|
|
{
|
|
show_message ("can't open file for reading");
|
|
return (-1);
|
|
}
|
|
|
|
read_msb_first = 1; /* Start reading with most significant byte first */
|
|
|
|
read_xwd_header (ifp, &xwdhdr);
|
|
if (xwdhdr.l_file_version != 7)
|
|
{
|
|
read_msb_first = 0; /* Try reading with least significant byte first */
|
|
|
|
fseek (ifp, 0, SEEK_SET);
|
|
|
|
read_xwd_header (ifp, &xwdhdr);
|
|
if (xwdhdr.l_file_version != 7)
|
|
{
|
|
show_message("can't open file as XWD file");
|
|
fclose (ifp);
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
/* Position to start of XWDColor structures */
|
|
fseek (ifp, (long)xwdhdr.l_header_size, SEEK_SET);
|
|
|
|
if (xwdhdr.l_colormap_entries > 0)
|
|
{
|
|
xwdcolmap = (L_XWDCOLOR *)g_malloc (sizeof (L_XWDCOLOR)
|
|
* xwdhdr.l_colormap_entries);
|
|
if (xwdcolmap == NULL)
|
|
{
|
|
show_message ("cant get memory for colormap");
|
|
fclose (ifp);
|
|
return (-1);
|
|
}
|
|
|
|
read_xwd_cols (ifp, &xwdhdr, xwdcolmap);
|
|
#ifdef XWD_COL_DEBUG
|
|
{int j;
|
|
printf ("File %s\n",filename);
|
|
for (j=0; j < xwdhdr.l_colormap_entries; j++)
|
|
printf ("Entry 0x%08lx: 0x%04lx, 0x%04lx, 0x%04lx, %d\n",
|
|
(long)xwdcolmap[j].l_pixel,(long)xwdcolmap[j].l_red,
|
|
(long)xwdcolmap[j].l_green,(long)xwdcolmap[j].l_blue,
|
|
(int)xwdcolmap[j].l_flags);
|
|
}
|
|
#endif
|
|
if (xwdhdr.l_file_version != 7)
|
|
{
|
|
show_message ("cant read colour entries");
|
|
g_free (xwdcolmap);
|
|
fclose (ifp);
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
if (l_run_mode != RUN_NONINTERACTIVE)
|
|
{
|
|
temp = g_malloc (strlen (filename) + 11);
|
|
sprintf (temp, "Loading %s:", filename);
|
|
gimp_progress_init (temp);
|
|
g_free (temp);
|
|
}
|
|
|
|
depth = xwdhdr.l_pixmap_depth;
|
|
bpp = xwdhdr.l_bits_per_pixel;
|
|
|
|
image_ID = -1;
|
|
switch (xwdhdr.l_pixmap_format)
|
|
{
|
|
case 0: /* Single plane bitmap */
|
|
if ((depth == 1) && (bpp == 1))
|
|
{ /* Can be performed by format 2 loader */
|
|
image_ID = load_xwd_f2_d1_b1 (filename, ifp, &xwdhdr, xwdcolmap);
|
|
}
|
|
break;
|
|
|
|
case 1: /* Single plane pixmap */
|
|
if ((depth <= 24) && (bpp == 1))
|
|
{
|
|
image_ID = load_xwd_f1_d24_b1 (filename, ifp, &xwdhdr, xwdcolmap);
|
|
}
|
|
break;
|
|
|
|
case 2: /* Multiplane pixmaps */
|
|
if ((depth == 1) && (bpp == 1))
|
|
{
|
|
image_ID = load_xwd_f2_d1_b1 (filename, ifp, &xwdhdr, xwdcolmap);
|
|
}
|
|
else if ((depth <= 8) && (bpp == 8))
|
|
{
|
|
image_ID = load_xwd_f2_d8_b8 (filename, ifp, &xwdhdr, xwdcolmap);
|
|
}
|
|
else if ((depth <= 16) && (bpp == 16))
|
|
{
|
|
image_ID = load_xwd_f2_d16_b16 (filename, ifp, &xwdhdr, xwdcolmap);
|
|
}
|
|
else if ((depth <= 24) && ((bpp == 24) || (bpp == 32)))
|
|
{
|
|
image_ID = load_xwd_f2_d24_b32 (filename, ifp, &xwdhdr, xwdcolmap);
|
|
}
|
|
break;
|
|
}
|
|
|
|
fclose (ifp);
|
|
|
|
if (xwdcolmap != NULL) g_free ((char *)xwdcolmap);
|
|
|
|
if (image_ID == -1)
|
|
{
|
|
temp = g_malloc (strlen (filename)+256);
|
|
if (temp == NULL)
|
|
{
|
|
show_message ("this image depth/format is not supported");
|
|
}
|
|
else
|
|
{
|
|
sprintf (temp, "load_image (xwd): XWD-file %s has format %d, depth %d\n\
|
|
and bits per pixel %d.\nCurrently this is not supported.\n",
|
|
filename, (int)xwdhdr.l_pixmap_format, depth, bpp);
|
|
show_message (temp);
|
|
g_free (temp);
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
return (image_ID);
|
|
}
|
|
|
|
static gint
|
|
save_image (char *filename,
|
|
gint32 image_ID,
|
|
gint32 drawable_ID)
|
|
|
|
{
|
|
FILE* ofp;
|
|
GDrawableType drawable_type;
|
|
gint retval;
|
|
char *temp;
|
|
|
|
drawable_type = gimp_drawable_type (drawable_ID);
|
|
|
|
/* Make sure we're not saving an image with an alpha channel */
|
|
if (gimp_drawable_has_alpha (drawable_ID))
|
|
{
|
|
show_message ("XWD save cannot handle images with alpha channels");
|
|
return FALSE;
|
|
}
|
|
|
|
switch (drawable_type)
|
|
{
|
|
case INDEXED_IMAGE:
|
|
case GRAY_IMAGE:
|
|
case RGB_IMAGE:
|
|
break;
|
|
default:
|
|
show_message ("cannot operate on unknown image types");
|
|
return (FALSE);
|
|
break;
|
|
}
|
|
|
|
/* Open the output file. */
|
|
ofp = fopen (filename, "wb");
|
|
if (!ofp)
|
|
{
|
|
show_message ("cant open file for writing");
|
|
return (FALSE);
|
|
}
|
|
|
|
if (l_run_mode != RUN_NONINTERACTIVE)
|
|
{
|
|
temp = g_malloc (strlen (filename) + 11);
|
|
sprintf (temp, "Saving %s:", filename);
|
|
gimp_progress_init (temp);
|
|
g_free (temp);
|
|
}
|
|
|
|
if (drawable_type == INDEXED_IMAGE)
|
|
retval = save_index (ofp, image_ID, drawable_ID, 0);
|
|
else if (drawable_type == GRAY_IMAGE)
|
|
retval = save_index (ofp, image_ID, drawable_ID, 1);
|
|
else if (drawable_type == RGB_IMAGE)
|
|
retval = save_rgb (ofp, image_ID, drawable_ID);
|
|
else
|
|
retval = FALSE;
|
|
|
|
fclose (ofp);
|
|
|
|
return (retval);
|
|
}
|
|
|
|
|
|
static L_CARD32 read_card32 (FILE *ifp,
|
|
int *err)
|
|
|
|
{L_CARD32 c;
|
|
|
|
if (read_msb_first)
|
|
{
|
|
c = (((L_CARD32)(getc (ifp))) << 24);
|
|
c |= (((L_CARD32)(getc (ifp))) << 16);
|
|
c |= (((L_CARD32)(getc (ifp))) << 8);
|
|
c |= ((L_CARD32)(*err = getc (ifp)));
|
|
}
|
|
else
|
|
{
|
|
c = ((L_CARD32)(getc (ifp)));
|
|
c |= (((L_CARD32)(getc (ifp))) << 8);
|
|
c |= (((L_CARD32)(getc (ifp))) << 16);
|
|
c |= (((L_CARD32)(*err = getc (ifp))) << 24);
|
|
}
|
|
|
|
*err = (*err < 0);
|
|
return (c);
|
|
}
|
|
|
|
|
|
static L_CARD16 read_card16 (FILE *ifp,
|
|
int *err)
|
|
|
|
{L_CARD16 c;
|
|
|
|
if (read_msb_first)
|
|
{
|
|
c = (((L_CARD16)(getc (ifp))) << 8);
|
|
c |= ((L_CARD16)(*err = getc (ifp)));
|
|
}
|
|
else
|
|
{
|
|
c = ((L_CARD16)(getc (ifp)));
|
|
c |= (((L_CARD16)(*err = getc (ifp))) << 8);
|
|
}
|
|
|
|
*err = (*err < 0);
|
|
return (c);
|
|
}
|
|
|
|
|
|
static L_CARD8 read_card8 (FILE *ifp,
|
|
int *err)
|
|
|
|
{L_CARD8 c;
|
|
|
|
c = ((L_CARD8)(*err = getc (ifp)));
|
|
|
|
*err = (*err < 0);
|
|
return (c);
|
|
}
|
|
|
|
static void write_card32 (FILE *ofp,
|
|
L_CARD32 c)
|
|
|
|
{
|
|
putc ((int)((c >> 24) & 0xff), ofp);
|
|
putc ((int)((c >> 16) & 0xff), ofp);
|
|
putc ((int)((c >> 8) & 0xff), ofp);
|
|
putc ((int)((c) & 0xff), ofp);
|
|
}
|
|
|
|
|
|
static void write_card16 (FILE *ofp,
|
|
L_CARD32 c)
|
|
|
|
{
|
|
putc ((int)((c >> 8) & 0xff), ofp);
|
|
putc ((int)((c) & 0xff), ofp);
|
|
}
|
|
|
|
|
|
static void write_card8 (FILE *ofp,
|
|
L_CARD32 c)
|
|
|
|
{
|
|
putc ((int)((c) & 0xff), ofp);
|
|
}
|
|
|
|
|
|
static void
|
|
read_xwd_header (FILE *ifp,
|
|
L_XWDFILEHEADER *xwdhdr)
|
|
|
|
{int j, err;
|
|
L_CARD32 *cp;
|
|
|
|
cp = (L_CARD32 *)xwdhdr;
|
|
|
|
/* Read in all 32-bit values of the header and check for byte order */
|
|
for (j = 0; j < sizeof (L_XWDFILEHEADER)/sizeof(xwdhdr->l_file_version); j++)
|
|
{
|
|
*(cp++) = read_card32 (ifp, &err);
|
|
if (err) break;
|
|
}
|
|
|
|
if (err) xwdhdr->l_file_version = 0; /* Not a valid XWD-file */
|
|
}
|
|
|
|
|
|
/* Write out an XWD-fileheader. The header size is calculated here */
|
|
|
|
static void
|
|
write_xwd_header (FILE *ofp,
|
|
L_XWDFILEHEADER *xwdhdr)
|
|
|
|
{int j, hdrpad, hdr_entries;
|
|
L_CARD32 *cp;
|
|
|
|
hdrpad = XWDHDR_PAD;
|
|
hdr_entries = sizeof (L_XWDFILEHEADER)/sizeof(xwdhdr->l_file_version);
|
|
xwdhdr->l_header_size = hdr_entries * 4 + hdrpad;
|
|
|
|
cp = (L_CARD32 *)xwdhdr;
|
|
|
|
/* Write out all 32-bit values of the header and check for byte order */
|
|
for (j = 0; j < sizeof (L_XWDFILEHEADER)/sizeof(xwdhdr->l_file_version); j++)
|
|
{
|
|
write_card32 (ofp, *(cp++));
|
|
}
|
|
|
|
/* Add padding bytes after XWD header */
|
|
for (j = 0; j < hdrpad; j++)
|
|
write_card8 (ofp, (L_CARD32)0);
|
|
}
|
|
|
|
|
|
static void
|
|
read_xwd_cols (FILE *ifp,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *colormap)
|
|
|
|
{int j, err = 0;
|
|
int flag_is_bad, index_is_bad;
|
|
int indexed = (xwdhdr->l_pixmap_depth <= 8);
|
|
long colmappos = ftell (ifp);
|
|
|
|
/* Read in XWD-Color structures (the usual case) */
|
|
flag_is_bad = index_is_bad = 0;
|
|
for (j = 0; j < xwdhdr->l_ncolors; j++)
|
|
{
|
|
colormap[j].l_pixel = read_card32 (ifp, &err);
|
|
|
|
colormap[j].l_red = read_card16 (ifp, &err);
|
|
colormap[j].l_green = read_card16 (ifp, &err);
|
|
colormap[j].l_blue = read_card16 (ifp, &err);
|
|
|
|
colormap[j].l_flags = read_card8 (ifp, &err);
|
|
colormap[j].l_pad = read_card8 (ifp, &err);
|
|
|
|
if (colormap[j].l_flags > 7)
|
|
flag_is_bad++;
|
|
|
|
if (indexed && (colormap[j].l_pixel > 255))
|
|
index_is_bad++;
|
|
|
|
if (err) break;
|
|
}
|
|
|
|
if (err) /* Not a valid XWD-file ? */
|
|
xwdhdr->l_file_version = 0;
|
|
if (err || ((flag_is_bad == 0) && (index_is_bad == 0)))
|
|
return;
|
|
|
|
/* Read in XWD-Color structures (with 4 bytes inserted infront of RGB) */
|
|
fseek (ifp, colmappos, SEEK_SET);
|
|
flag_is_bad = index_is_bad = 0;
|
|
for (j = 0; j < xwdhdr->l_ncolors; j++)
|
|
{
|
|
colormap[j].l_pixel = read_card32 (ifp, &err);
|
|
|
|
read_card32 (ifp, &err); /* Empty bytes on Alpha OSF */
|
|
|
|
colormap[j].l_red = read_card16 (ifp, &err);
|
|
colormap[j].l_green = read_card16 (ifp, &err);
|
|
colormap[j].l_blue = read_card16 (ifp, &err);
|
|
|
|
colormap[j].l_flags = read_card8 (ifp, &err);
|
|
colormap[j].l_pad = read_card8 (ifp, &err);
|
|
|
|
if ((colormap[j].l_flags == 0) || (colormap[j].l_flags > 7))
|
|
flag_is_bad++;
|
|
|
|
if (indexed && (colormap[j].l_pixel > 255))
|
|
index_is_bad++;
|
|
|
|
if (err) break;
|
|
}
|
|
|
|
if (err) /* Not a valid XWD-file ? */
|
|
xwdhdr->l_file_version = 0;
|
|
if (err || ((flag_is_bad == 0) && (index_is_bad == 0)))
|
|
return;
|
|
|
|
/* Read in XWD-Color structures (with 2 bytes inserted infront of RGB) */
|
|
fseek (ifp, colmappos, SEEK_SET);
|
|
flag_is_bad = index_is_bad = 0;
|
|
for (j = 0; j < xwdhdr->l_ncolors; j++)
|
|
{
|
|
colormap[j].l_pixel = read_card32 (ifp, &err);
|
|
|
|
read_card16 (ifp, &err); /* Empty bytes (from where ?) */
|
|
|
|
colormap[j].l_red = read_card16 (ifp, &err);
|
|
colormap[j].l_green = read_card16 (ifp, &err);
|
|
colormap[j].l_blue = read_card16 (ifp, &err);
|
|
|
|
colormap[j].l_flags = read_card8 (ifp, &err);
|
|
colormap[j].l_pad = read_card8 (ifp, &err);
|
|
|
|
if ((colormap[j].l_flags == 0) || (colormap[j].l_flags > 7))
|
|
flag_is_bad++;
|
|
|
|
if (indexed && (colormap[j].l_pixel > 255))
|
|
index_is_bad++;
|
|
|
|
if (err) break;
|
|
}
|
|
|
|
if (err) /* Not a valid XWD-file ? */
|
|
xwdhdr->l_file_version = 0;
|
|
if (err || ((flag_is_bad == 0) && (index_is_bad == 0)))
|
|
return;
|
|
|
|
/* Read in XWD-Color structures (every value is 8 bytes from a CRAY) */
|
|
fseek (ifp, colmappos, SEEK_SET);
|
|
flag_is_bad = index_is_bad = 0;
|
|
for (j = 0; j < xwdhdr->l_ncolors; j++)
|
|
{
|
|
read_card32 (ifp, &err);
|
|
colormap[j].l_pixel = read_card32 (ifp, &err);
|
|
|
|
read_card32 (ifp, &err);
|
|
colormap[j].l_red = read_card32 (ifp, &err);
|
|
read_card32 (ifp, &err);
|
|
colormap[j].l_green = read_card32 (ifp, &err);
|
|
read_card32 (ifp, &err);
|
|
colormap[j].l_blue = read_card32 (ifp, &err);
|
|
|
|
/* The flag byte is kept in the first byte */
|
|
colormap[j].l_flags = read_card8 (ifp, &err);
|
|
colormap[j].l_pad = read_card8 (ifp, &err);
|
|
read_card16 (ifp, &err);
|
|
read_card32 (ifp, &err);
|
|
|
|
if ((colormap[j].l_flags == 0) || (colormap[j].l_flags > 7))
|
|
flag_is_bad++;
|
|
|
|
if (indexed && (colormap[j].l_pixel > 255))
|
|
index_is_bad++;
|
|
|
|
if (err) break;
|
|
}
|
|
|
|
if (flag_is_bad || index_is_bad)
|
|
{
|
|
printf ("xwd: Warning. Error in XWD-color-structure (");
|
|
|
|
if (flag_is_bad) printf ("flag");
|
|
if (index_is_bad) printf ("index");
|
|
|
|
printf (")\n");
|
|
}
|
|
if (err) xwdhdr->l_file_version = 0; /* Not a valid XWD-file */
|
|
}
|
|
|
|
|
|
static void
|
|
write_xwd_cols (FILE *ofp,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *colormap)
|
|
|
|
{int j;
|
|
|
|
for (j = 0; j < xwdhdr->l_colormap_entries; j++)
|
|
{
|
|
#ifdef CRAY
|
|
write_card32 (ofp, (L_CARD32)0);
|
|
write_card32 (ofp, colormap[j].l_pixel);
|
|
write_card32 (ofp, (L_CARD32)0);
|
|
write_card32 (ofp, (L_CARD32)colormap[j].l_red);
|
|
write_card32 (ofp, (L_CARD32)0);
|
|
write_card32 (ofp, (L_CARD32)colormap[j].l_green);
|
|
write_card32 (ofp, (L_CARD32)0);
|
|
write_card32 (ofp, (L_CARD32)colormap[j].l_blue);
|
|
write_card8 (ofp, (L_CARD32)colormap[j].l_flags);
|
|
write_card8 (ofp, (L_CARD32)colormap[j].l_pad);
|
|
write_card16 (ofp, (L_CARD32)0);
|
|
write_card32 (ofp, (L_CARD32)0);
|
|
#else
|
|
#ifdef __alpha
|
|
write_card32 (ofp, colormap[j].l_pixel);
|
|
write_card32 (ofp, (L_CARD32)0);
|
|
write_card16 (ofp, (L_CARD32)colormap[j].l_red);
|
|
write_card16 (ofp, (L_CARD32)colormap[j].l_green);
|
|
write_card16 (ofp, (L_CARD32)colormap[j].l_blue);
|
|
write_card8 (ofp, (L_CARD32)colormap[j].l_flags);
|
|
write_card8 (ofp, (L_CARD32)colormap[j].l_pad);
|
|
#else
|
|
write_card32 (ofp, colormap[j].l_pixel);
|
|
write_card16 (ofp, (L_CARD32)colormap[j].l_red);
|
|
write_card16 (ofp, (L_CARD32)colormap[j].l_green);
|
|
write_card16 (ofp, (L_CARD32)colormap[j].l_blue);
|
|
write_card8 (ofp, (L_CARD32)colormap[j].l_flags);
|
|
write_card8 (ofp, (L_CARD32)colormap[j].l_pad);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/* Create a map for mapping up to 32 bit pixelvalues to RGB. */
|
|
/* Returns number of colors kept in the map (up to 256) */
|
|
|
|
static int set_pixelmap (int ncols,
|
|
L_XWDCOLOR *xwdcol,
|
|
PIXEL_MAP *pixelmap)
|
|
|
|
{int i, j, k, maxcols;
|
|
L_CARD32 pixel_val;
|
|
|
|
memset ((char *)pixelmap,0,sizeof (PIXEL_MAP));
|
|
|
|
maxcols = 0;
|
|
|
|
for (j = 0; j < ncols; j++) /* For each entry of the XWD colormap */
|
|
{
|
|
pixel_val = xwdcol[j].l_pixel;
|
|
for (k = 0; k < maxcols; k++) /* Where to insert in list ? */
|
|
{
|
|
if (pixel_val <= pixelmap->pmap[k].pixel_val)
|
|
break;
|
|
}
|
|
if ((k < maxcols) && (pixel_val == pixelmap->pmap[k].pixel_val))
|
|
break; /* It was already in list */
|
|
|
|
if (k >= 256) break;
|
|
|
|
if (k < maxcols) /* Must move entries to the back ? */
|
|
{
|
|
for (i = maxcols-1; i >= k; i--)
|
|
memcpy ((char *)&(pixelmap->pmap[i+1]),(char *)&(pixelmap->pmap[i]),
|
|
sizeof (PMAP));
|
|
}
|
|
pixelmap->pmap[k].pixel_val = pixel_val;
|
|
pixelmap->pmap[k].red = xwdcol[j].l_red >> 8;
|
|
pixelmap->pmap[k].green = xwdcol[j].l_green >> 8;
|
|
pixelmap->pmap[k].blue = xwdcol[j].l_blue >> 8;
|
|
pixelmap->pixel_in_map[pixel_val & MAPPERMASK] = 1;
|
|
maxcols++;
|
|
}
|
|
pixelmap->npixel = maxcols;
|
|
#ifdef XWD_COL_DEBUG
|
|
printf ("Colours in pixelmap: %d\n",pixelmap->npixel);
|
|
for (j=0; j<pixelmap->npixel; j++)
|
|
printf ("Pixelvalue 0x%08lx, 0x%02x 0x%02x 0x%02x\n",
|
|
pixelmap->pmap[j].pixel_val,
|
|
pixelmap->pmap[j].red,pixelmap->pmap[j].green,
|
|
pixelmap->pmap[j].blue);
|
|
for (j=0; j<=MAPPERMASK; j++)
|
|
printf ("0x%08lx: %d\n",(long)j,pixelmap->pixel_in_map[j]);
|
|
#endif
|
|
return (pixelmap->npixel);
|
|
}
|
|
|
|
|
|
/* Search a pixel value in the pixel map. Returns 0 if the */
|
|
/* pixelval was not found in map. Returns 1 if found. */
|
|
|
|
static int get_pixelmap (L_CARD32 pixelval,
|
|
PIXEL_MAP *pixelmap,
|
|
unsigned char *red,
|
|
unsigned char *green,
|
|
unsigned char *blue)
|
|
|
|
{register PMAP *low, *high, *middle;
|
|
|
|
if (pixelmap->npixel == 0) return (0);
|
|
if (!(pixelmap->pixel_in_map[pixelval & MAPPERMASK])) return (0);
|
|
|
|
low = &(pixelmap->pmap[0]);
|
|
high = &(pixelmap->pmap[pixelmap->npixel-1]);
|
|
|
|
/* Do a binary search on the array */
|
|
while (low < high)
|
|
{
|
|
middle = low + ((high - low)/2);
|
|
if (pixelval <= middle->pixel_val)
|
|
high = middle;
|
|
else
|
|
low = middle+1;
|
|
}
|
|
|
|
if (pixelval == low->pixel_val)
|
|
{
|
|
*red = low->red; *green = low->green; *blue = low->blue;
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
static void set_bw_color_table (gint32 image_ID)
|
|
|
|
{static unsigned char BWColorMap[2*3] = { 255, 255, 255, 0, 0, 0 };
|
|
|
|
#ifdef XWD_COL_DEBUG
|
|
printf ("Set GIMP b/w-colortable:\n");
|
|
#endif
|
|
|
|
gimp_image_set_cmap (image_ID, BWColorMap, 2);
|
|
}
|
|
|
|
|
|
static void set_color_table (gint32 image_ID,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *xwdcolmap)
|
|
|
|
{int ncols, i, j;
|
|
unsigned char ColorMap[256*3];
|
|
|
|
ncols = xwdhdr->l_colormap_entries;
|
|
if (xwdhdr->l_ncolors < ncols) ncols = xwdhdr->l_ncolors;
|
|
if (ncols <= 0) return;
|
|
if (ncols > 256) ncols = 256;
|
|
|
|
memset ((char *)ColorMap,0,sizeof (ColorMap));
|
|
|
|
for (j = 0; j < ncols; j++)
|
|
{
|
|
i = xwdcolmap[j].l_pixel;
|
|
if ((i >= 0) && (i < 256))
|
|
{
|
|
ColorMap[i*3] = (xwdcolmap[j].l_red) >> 8;
|
|
ColorMap[i*3+1] = (xwdcolmap[j].l_green) >> 8;
|
|
ColorMap[i*3+2] = (xwdcolmap[j].l_blue) >> 8;
|
|
}
|
|
}
|
|
|
|
#ifdef XWD_COL_DEBUG
|
|
printf ("Set GIMP colortable:\n");
|
|
for (j = 0; j < ncols; j++)
|
|
printf ("%3d: 0x%02x 0x%02x 0x%02x\n", j,
|
|
ColorMap[j*3], ColorMap[j*3+1], ColorMap[j*3+2]);
|
|
#endif
|
|
gimp_image_set_cmap (image_ID, ColorMap, ncols);
|
|
}
|
|
|
|
|
|
/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
|
|
static gint32
|
|
create_new_image (char *filename,
|
|
guint width,
|
|
guint height,
|
|
GImageType type,
|
|
gint32 *layer_ID,
|
|
GDrawable **drawable,
|
|
GPixelRgn *pixel_rgn)
|
|
|
|
{gint32 image_ID;
|
|
GDrawableType gdtype;
|
|
|
|
if (type == GRAY) gdtype = GRAY_IMAGE;
|
|
else if (type == INDEXED) gdtype = INDEXED_IMAGE;
|
|
else gdtype = RGB_IMAGE;
|
|
|
|
image_ID = gimp_image_new (width, height, type);
|
|
gimp_image_set_filename (image_ID, filename);
|
|
|
|
*layer_ID = gimp_layer_new (image_ID, "Background", width, height,
|
|
gdtype, 100, NORMAL_MODE);
|
|
gimp_image_add_layer (image_ID, *layer_ID, 0);
|
|
|
|
*drawable = gimp_drawable_get (*layer_ID);
|
|
gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width,
|
|
(*drawable)->height, TRUE, FALSE);
|
|
return (image_ID);
|
|
}
|
|
|
|
|
|
/* Load XWD with pixmap_format 2, pixmap_depth 1, bits_per_pixel 1 */
|
|
|
|
static gint32
|
|
load_xwd_f2_d1_b1 (char *filename,
|
|
FILE *ifp,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *xwdcolmap)
|
|
|
|
{register int pix8;
|
|
register unsigned char *dest, *src;
|
|
unsigned char c1, c2, c3, c4;
|
|
int width, height, linepad, scan_lines, tile_height;
|
|
int i, j, ncols;
|
|
char *temp = ident; /* Just to satisfy lint/gcc */
|
|
unsigned char bit2byte[256*8];
|
|
unsigned char *data, *scanline;
|
|
int err = 0;
|
|
gint32 layer_ID, image_ID;
|
|
GPixelRgn pixel_rgn;
|
|
GDrawable *drawable;
|
|
|
|
#ifdef XWD_DEBUG
|
|
printf ("load_xwd_f2_d1_b1 (%s)\n", filename);
|
|
#endif
|
|
|
|
width = xwdhdr->l_pixmap_width;
|
|
height = xwdhdr->l_pixmap_height;
|
|
|
|
image_ID = create_new_image (filename, width, height, INDEXED,
|
|
&layer_ID, &drawable, &pixel_rgn);
|
|
|
|
tile_height = gimp_tile_height ();
|
|
data = g_malloc (tile_height * width);
|
|
|
|
scanline = (unsigned char *)g_malloc (xwdhdr->l_bytes_per_line+8);
|
|
if (scanline == NULL) return (-1);
|
|
|
|
ncols = xwdhdr->l_colormap_entries;
|
|
if (xwdhdr->l_ncolors < ncols) ncols = xwdhdr->l_ncolors;
|
|
|
|
if (ncols < 2)
|
|
set_bw_color_table (image_ID);
|
|
else
|
|
set_color_table (image_ID, xwdhdr, xwdcolmap);
|
|
|
|
temp = (char *)bit2byte;
|
|
|
|
/* Get an array for mapping 8 bits in a byte to 8 bytes */
|
|
if (!xwdhdr->l_bitmap_bit_order)
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
for (i = 0; i < 8; i++)
|
|
*(temp++) = ((j & (1 << i)) != 0);
|
|
}
|
|
else
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
for (i = 7; i >= 0; i--)
|
|
*(temp++) = ((j & (1 << i)) != 0);
|
|
}
|
|
|
|
linepad = xwdhdr->l_bytes_per_line - (xwdhdr->l_pixmap_width+7)/8;
|
|
if (linepad < 0) linepad = 0;
|
|
|
|
dest = data;
|
|
scan_lines = 0;
|
|
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
if (fread (scanline, xwdhdr->l_bytes_per_line, 1, ifp) != 1)
|
|
{
|
|
err = 1;
|
|
break;
|
|
}
|
|
|
|
/* Need to check byte order ? */
|
|
if (xwdhdr->l_bitmap_bit_order != xwdhdr->l_byte_order)
|
|
{
|
|
src = scanline;
|
|
switch (xwdhdr->l_bitmap_unit)
|
|
{
|
|
case 16:
|
|
j = xwdhdr->l_bytes_per_line;
|
|
while (j > 0)
|
|
{
|
|
c1 = src[0]; c2 = src[1];
|
|
*(src++) = c2; *(src++) = c1;
|
|
j -= 2;
|
|
}
|
|
break;
|
|
|
|
case 32:
|
|
j = xwdhdr->l_bytes_per_line;
|
|
while (j > 0)
|
|
{
|
|
c1 = src[0]; c2 = src[1]; c3 = src[2]; c4 = src[3];
|
|
*(src++) = c4; *(src++) = c3; *(src++) = c2; *(src++) = c1;
|
|
j -= 4;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
src = scanline;
|
|
j = width;
|
|
while (j >= 8)
|
|
{
|
|
pix8 = *(src++);
|
|
memcpy (dest, bit2byte + pix8*8, 8);
|
|
dest += 8;
|
|
j -= 8;
|
|
}
|
|
if (j > 0)
|
|
{
|
|
pix8 = *(src++);
|
|
memcpy (dest, bit2byte + pix8*8, j);
|
|
dest += j;
|
|
}
|
|
|
|
scan_lines++;
|
|
|
|
if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0))
|
|
gimp_progress_update ((double)(i+1) / (double)height);
|
|
|
|
if ((scan_lines == tile_height) || ((i+1) == height))
|
|
{
|
|
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1,
|
|
width, scan_lines);
|
|
scan_lines = 0;
|
|
dest = data;
|
|
}
|
|
if (err) break;
|
|
}
|
|
g_free (data);
|
|
g_free (scanline);
|
|
|
|
if (err)
|
|
show_message ("EOF encountered on ");
|
|
|
|
gimp_drawable_flush (drawable);
|
|
|
|
return (err ? -1 : image_ID);
|
|
}
|
|
|
|
|
|
/* Load XWD with pixmap_format 2, pixmap_depth 8, bits_per_pixel 8 */
|
|
|
|
static gint32
|
|
load_xwd_f2_d8_b8 (char *filename,
|
|
FILE *ifp,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *xwdcolmap)
|
|
|
|
{int width, height, linepad, tile_height, scan_lines;
|
|
int i, j, ncols;
|
|
int greyscale;
|
|
unsigned char *dest, *data;
|
|
int err = 0;
|
|
gint32 layer_ID, image_ID;
|
|
GPixelRgn pixel_rgn;
|
|
GDrawable *drawable;
|
|
|
|
#ifdef XWD_DEBUG
|
|
printf ("load_xwd_f2_d8_b8 (%s)\n", filename);
|
|
#endif
|
|
|
|
width = xwdhdr->l_pixmap_width;
|
|
height = xwdhdr->l_pixmap_height;
|
|
|
|
/* This could also be a greyscale image. Check it */
|
|
greyscale = 0;
|
|
if ((xwdhdr->l_ncolors == 256) && (xwdhdr->l_colormap_entries == 256))
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
if ( (xwdcolmap[j].l_pixel != j)
|
|
|| ((xwdcolmap[j].l_red >> 8) != j)
|
|
|| ((xwdcolmap[j].l_green >> 8) != j)
|
|
|| ((xwdcolmap[j].l_blue >> 8) != j))
|
|
break;
|
|
}
|
|
greyscale = (j == 256);
|
|
}
|
|
|
|
image_ID = create_new_image (filename, width, height,
|
|
greyscale ? GRAY : INDEXED,
|
|
&layer_ID, &drawable, &pixel_rgn);
|
|
|
|
tile_height = gimp_tile_height ();
|
|
data = g_malloc (tile_height * width);
|
|
|
|
if (!greyscale)
|
|
{
|
|
ncols = xwdhdr->l_colormap_entries;
|
|
if (xwdhdr->l_ncolors < ncols) ncols = xwdhdr->l_ncolors;
|
|
if (ncols < 2)
|
|
set_bw_color_table (image_ID);
|
|
else
|
|
set_color_table (image_ID, xwdhdr, xwdcolmap);
|
|
}
|
|
|
|
linepad = xwdhdr->l_bytes_per_line - xwdhdr->l_pixmap_width;
|
|
if (linepad < 0) linepad = 0;
|
|
|
|
dest = data;
|
|
scan_lines = 0;
|
|
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
if (fread (dest, 1, width, ifp) != width)
|
|
{
|
|
err = 1;
|
|
break;
|
|
}
|
|
dest += width;
|
|
|
|
for (j = 0; j < linepad; j++)
|
|
getc (ifp);
|
|
|
|
scan_lines++;
|
|
|
|
if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0))
|
|
gimp_progress_update ((double)(i+1) / (double)height);
|
|
|
|
if ((scan_lines == tile_height) || ((i+1) == height))
|
|
{
|
|
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1,
|
|
width, scan_lines);
|
|
scan_lines = 0;
|
|
dest = data;
|
|
}
|
|
}
|
|
g_free (data);
|
|
|
|
if (err)
|
|
show_message ("EOF encountered on reading");
|
|
|
|
gimp_drawable_flush (drawable);
|
|
|
|
return (err ? -1 : image_ID);
|
|
}
|
|
|
|
|
|
/* Load XWD with pixmap_format 2, pixmap_depth up to 16, bits_per_pixel 16 */
|
|
|
|
static gint32
|
|
load_xwd_f2_d16_b16 (char *filename,
|
|
FILE *ifp,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *xwdcolmap)
|
|
|
|
{register unsigned char *dest, lsbyte_first;
|
|
int width, height, linepad, i, j, c0, c1, ncols;
|
|
int red, green, blue, redval, greenval, blueval;
|
|
int maxred, maxgreen, maxblue;
|
|
int tile_height, scan_lines;
|
|
unsigned long redmask, greenmask, bluemask;
|
|
unsigned int redshift, greenshift, blueshift;
|
|
unsigned long maxval;
|
|
unsigned char *ColorMap, *cm, *data;
|
|
int err = 0;
|
|
gint32 layer_ID, image_ID;
|
|
GPixelRgn pixel_rgn;
|
|
GDrawable *drawable;
|
|
|
|
#ifdef XWD_DEBUG
|
|
printf ("load_xwd_f2_d16_b16 (%s)\n", filename);
|
|
#endif
|
|
|
|
width = xwdhdr->l_pixmap_width;
|
|
height = xwdhdr->l_pixmap_height;
|
|
|
|
image_ID = create_new_image (filename, width, height, RGB,
|
|
&layer_ID, &drawable, &pixel_rgn);
|
|
|
|
tile_height = gimp_tile_height ();
|
|
data = g_malloc (tile_height * width * 3);
|
|
|
|
/* Get memory for mapping 16 bit XWD-pixel to GIMP-RGB */
|
|
maxval = 0x10000 * 3;
|
|
ColorMap = (unsigned char *)g_malloc (maxval);
|
|
if (ColorMap == NULL)
|
|
{
|
|
show_message ("No memory for mapping colors");
|
|
return (-1);
|
|
}
|
|
memset (ColorMap,0,maxval);
|
|
|
|
redmask = xwdhdr->l_red_mask;
|
|
greenmask = xwdhdr->l_green_mask;
|
|
bluemask = xwdhdr->l_blue_mask;
|
|
|
|
/* How to shift RGB to be right aligned ? */
|
|
/* (We rely on the the mask bits are grouped and not mixed) */
|
|
redshift = greenshift = blueshift = 0;
|
|
|
|
while (((1 << redshift) & redmask) == 0) redshift++;
|
|
while (((1 << greenshift) & greenmask) == 0) greenshift++;
|
|
while (((1 << blueshift) & bluemask) == 0) blueshift++;
|
|
|
|
/* The bits_per_rgb may not be correct. Use redmask instead */
|
|
maxred = 0; while (redmask >> (redshift + maxred)) maxred++;
|
|
maxred = (1 << maxred) - 1;
|
|
|
|
maxgreen = 0; while (greenmask >> (greenshift + maxgreen)) maxgreen++;
|
|
maxgreen = (1 << maxgreen) - 1;
|
|
|
|
maxblue = 0; while (bluemask >> (blueshift + maxblue)) maxblue++;
|
|
maxblue = (1 << maxblue) - 1;
|
|
|
|
/* Built up the array to map XWD-pixel value to GIMP-RGB */
|
|
for (red = 0; red <= maxred; red++)
|
|
{
|
|
redval = (red * 255) / maxred;
|
|
for (green = 0; green <= maxgreen; green++)
|
|
{
|
|
greenval = (green * 255) / maxgreen;
|
|
for (blue = 0; blue <= maxblue; blue++)
|
|
{
|
|
blueval = (blue * 255) / maxblue;
|
|
cm = ColorMap + ((red << redshift) + (green << greenshift)
|
|
+ (blue << blueshift)) * 3;
|
|
*(cm++) = redval;
|
|
*(cm++) = greenval;
|
|
*cm = blueval;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now look what was written to the XWD-Colormap */
|
|
|
|
ncols = xwdhdr->l_colormap_entries;
|
|
if (xwdhdr->l_ncolors < ncols) ncols = xwdhdr->l_ncolors;
|
|
|
|
for (j = 0; j < ncols; j++)
|
|
{
|
|
cm = ColorMap + xwdcolmap[j].l_pixel * 3;
|
|
*(cm++) = (xwdcolmap[j].l_red >> 8);
|
|
*(cm++) = (xwdcolmap[j].l_green >> 8);
|
|
*cm = (xwdcolmap[j].l_blue >> 8);
|
|
}
|
|
|
|
/* What do we have to consume after a line has finished ? */
|
|
linepad = xwdhdr->l_bytes_per_line
|
|
- (xwdhdr->l_pixmap_width*xwdhdr->l_bits_per_pixel)/8;
|
|
if (linepad < 0) linepad = 0;
|
|
|
|
lsbyte_first = (xwdhdr->l_byte_order == 0);
|
|
|
|
dest = data;
|
|
scan_lines = 0;
|
|
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
for (j = 0; j < width; j++)
|
|
{
|
|
c0 = getc (ifp);
|
|
c1 = getc (ifp);
|
|
if (c1 < 0)
|
|
{
|
|
err = 1;
|
|
break;
|
|
}
|
|
|
|
if (lsbyte_first)
|
|
c0 = c0 | (c1 << 8);
|
|
else
|
|
c0 = (c0 << 8) | c1;
|
|
|
|
cm = ColorMap + c0 * 3;
|
|
*(dest++) = *(cm++);
|
|
*(dest++) = *(cm++);
|
|
*(dest++) = *cm;
|
|
}
|
|
|
|
if (err) break;
|
|
|
|
for (j = 0; j < linepad; j++)
|
|
getc (ifp);
|
|
|
|
scan_lines++;
|
|
|
|
if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0))
|
|
gimp_progress_update ((double)(i+1) / (double)height);
|
|
|
|
if ((scan_lines == tile_height) || ((i+1) == height))
|
|
{
|
|
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1,
|
|
width, scan_lines);
|
|
scan_lines = 0;
|
|
dest = data;
|
|
}
|
|
}
|
|
g_free (data);
|
|
g_free (ColorMap);
|
|
|
|
if (err)
|
|
show_message ("EOF encountered on reading");
|
|
|
|
gimp_drawable_flush (drawable);
|
|
|
|
return (err ? -1 : image_ID);
|
|
}
|
|
|
|
|
|
/* Load XWD with pixmap_format 2, pixmap_depth up to 24, bits_per_pixel 24/32 */
|
|
|
|
static gint32
|
|
load_xwd_f2_d24_b32 (char *filename,
|
|
FILE *ifp,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *xwdcolmap)
|
|
|
|
{register unsigned char *dest, lsbyte_first;
|
|
int width, height, linepad, i, j, c0, c1, c2, c3;
|
|
int tile_height, scan_lines;
|
|
L_CARD32 pixelval;
|
|
int red, green, blue, ncols;
|
|
int maxred, maxgreen, maxblue;
|
|
unsigned long redmask, greenmask, bluemask;
|
|
unsigned int redshift, greenshift, blueshift;
|
|
unsigned char redmap[256],greenmap[256],bluemap[256];
|
|
unsigned char *data;
|
|
PIXEL_MAP pixel_map;
|
|
int err = 0;
|
|
gint32 layer_ID, image_ID;
|
|
GPixelRgn pixel_rgn;
|
|
GDrawable *drawable;
|
|
|
|
#ifdef XWD_DEBUG
|
|
printf ("load_xwd_f2_d24_b32 (%s)\n", filename);
|
|
#endif
|
|
|
|
width = xwdhdr->l_pixmap_width;
|
|
height = xwdhdr->l_pixmap_height;
|
|
|
|
image_ID = create_new_image (filename, width, height, RGB,
|
|
&layer_ID, &drawable, &pixel_rgn);
|
|
|
|
tile_height = gimp_tile_height ();
|
|
data = g_malloc (tile_height * width * 3);
|
|
|
|
redmask = xwdhdr->l_red_mask;
|
|
greenmask = xwdhdr->l_green_mask;
|
|
bluemask = xwdhdr->l_blue_mask;
|
|
|
|
if (redmask == 0) redmask = 0xff0000;
|
|
if (greenmask == 0) greenmask = 0x00ff00;
|
|
if (bluemask == 0) bluemask = 0x0000ff;
|
|
|
|
/* How to shift RGB to be right aligned ? */
|
|
/* (We rely on the the mask bits are grouped and not mixed) */
|
|
redshift = greenshift = blueshift = 0;
|
|
|
|
while (((1 << redshift) & redmask) == 0) redshift++;
|
|
while (((1 << greenshift) & greenmask) == 0) greenshift++;
|
|
while (((1 << blueshift) & bluemask) == 0) blueshift++;
|
|
|
|
/* The bits_per_rgb may not be correct. Use redmask instead */
|
|
|
|
maxred = 0; while (redmask >> (redshift + maxred)) maxred++;
|
|
maxred = (1 << maxred) - 1;
|
|
|
|
maxgreen = 0; while (greenmask >> (greenshift + maxgreen)) maxgreen++;
|
|
maxgreen = (1 << maxgreen) - 1;
|
|
|
|
maxblue = 0; while (bluemask >> (blueshift + maxblue)) maxblue++;
|
|
maxblue = (1 << maxblue) - 1;
|
|
|
|
/* Set map-arrays for red, green, blue */
|
|
for (red = 0; red <= maxred; red++)
|
|
redmap[red] = (red * 255) / maxred;
|
|
for (green = 0; green <= maxgreen; green++)
|
|
greenmap[green] = (green * 255) / maxgreen;
|
|
for (blue = 0; blue <= maxblue; blue++)
|
|
bluemap[blue] = (blue * 255) / maxblue;
|
|
|
|
ncols = xwdhdr->l_colormap_entries;
|
|
if (xwdhdr->l_ncolors < ncols) ncols = xwdhdr->l_ncolors;
|
|
|
|
ncols = set_pixelmap (ncols, xwdcolmap, &pixel_map);
|
|
|
|
/* What do we have to consume after a line has finished ? */
|
|
linepad = xwdhdr->l_bytes_per_line
|
|
- (xwdhdr->l_pixmap_width*xwdhdr->l_bits_per_pixel)/8;
|
|
if (linepad < 0) linepad = 0;
|
|
|
|
lsbyte_first = (xwdhdr->l_byte_order == 0);
|
|
|
|
dest = data;
|
|
scan_lines = 0;
|
|
|
|
if (xwdhdr->l_bits_per_pixel == 32)
|
|
{
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
for (j = 0; j < width; j++)
|
|
{
|
|
c0 = getc (ifp);
|
|
c1 = getc (ifp);
|
|
c2 = getc (ifp);
|
|
c3 = getc (ifp);
|
|
if (c3 < 0)
|
|
{
|
|
err = 1;
|
|
break;
|
|
}
|
|
if (lsbyte_first)
|
|
pixelval = c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
|
|
else
|
|
pixelval = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
|
|
|
|
if (get_pixelmap (pixelval, &pixel_map, dest, dest+1, dest+2))
|
|
{
|
|
dest += 3;
|
|
}
|
|
else
|
|
{
|
|
*(dest++) = redmap[(pixelval & redmask) >> redshift];
|
|
*(dest++) = greenmap[(pixelval & greenmask) >> greenshift];
|
|
*(dest++) = bluemap[(pixelval & bluemask) >> blueshift];
|
|
}
|
|
}
|
|
scan_lines++;
|
|
|
|
if (err) break;
|
|
|
|
for (j = 0; j < linepad; j++)
|
|
getc (ifp);
|
|
|
|
if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0))
|
|
gimp_progress_update ((double)(i+1) / (double)height);
|
|
|
|
if ((scan_lines == tile_height) || ((i+1) == height))
|
|
{
|
|
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1,
|
|
width, scan_lines);
|
|
scan_lines = 0;
|
|
dest = data;
|
|
}
|
|
}
|
|
}
|
|
else /* 24 bits per pixel */
|
|
{
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
for (j = 0; j < width; j++)
|
|
{
|
|
c0 = getc (ifp);
|
|
c1 = getc (ifp);
|
|
c2 = getc (ifp);
|
|
if (c2 < 0)
|
|
{
|
|
err = 1;
|
|
break;
|
|
}
|
|
if (lsbyte_first)
|
|
pixelval = c0 | (c1 << 8) | (c2 << 16);
|
|
else
|
|
pixelval = (c0 << 16) | (c1 << 8) | c2;
|
|
|
|
if (get_pixelmap (pixelval, &pixel_map, dest, dest+1, dest+2))
|
|
{
|
|
dest += 3;
|
|
}
|
|
else
|
|
{
|
|
*(dest++) = redmap[(pixelval & redmask) >> redshift];
|
|
*(dest++) = greenmap[(pixelval & greenmask) >> greenshift];
|
|
*(dest++) = bluemap[(pixelval & bluemask) >> blueshift];
|
|
}
|
|
}
|
|
scan_lines++;
|
|
|
|
if (err) break;
|
|
|
|
for (j = 0; j < linepad; j++)
|
|
getc (ifp);
|
|
|
|
if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0))
|
|
gimp_progress_update ((double)(i+1) / (double)height);
|
|
|
|
if ((scan_lines == tile_height) || ((i+1) == height))
|
|
{
|
|
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1,
|
|
width, scan_lines);
|
|
scan_lines = 0;
|
|
dest = data;
|
|
}
|
|
}
|
|
}
|
|
g_free (data);
|
|
|
|
if (err)
|
|
show_message ("EOF encountered on reading");
|
|
|
|
gimp_drawable_flush (drawable);
|
|
|
|
return (err ? -1 : image_ID);
|
|
}
|
|
|
|
|
|
/* Load XWD with pixmap_format 1, pixmap_depth up to 24, bits_per_pixel 1 */
|
|
|
|
static gint32
|
|
load_xwd_f1_d24_b1 (char *filename,
|
|
FILE *ifp,
|
|
L_XWDFILEHEADER *xwdhdr,
|
|
L_XWDCOLOR *xwdcolmap)
|
|
|
|
{register unsigned char *dest, outmask, inmask, do_reverse;
|
|
int width, height, linepad, i, j, plane, fromright;
|
|
int tile_height, tile_start, tile_end;
|
|
int indexed, bytes_per_pixel;
|
|
int maxred, maxgreen, maxblue;
|
|
int red, green, blue, ncols, standard_rgb;
|
|
long data_offset, plane_offset, tile_offset;
|
|
unsigned long redmask, greenmask, bluemask;
|
|
unsigned int redshift, greenshift, blueshift;
|
|
unsigned long g;
|
|
unsigned char redmap[256], greenmap[256], bluemap[256];
|
|
unsigned char bit_reverse[256];
|
|
unsigned char *xwddata, *xwdin, *data;
|
|
L_CARD32 pixelval;
|
|
PIXEL_MAP pixel_map;
|
|
int err = 0;
|
|
gint32 layer_ID, image_ID;
|
|
GPixelRgn pixel_rgn;
|
|
GDrawable *drawable;
|
|
|
|
#ifdef XWD_DEBUG
|
|
printf ("load_xwd_f1_d24_b1 (%s)\n", filename);
|
|
#endif
|
|
|
|
xwddata = g_malloc (xwdhdr->l_bytes_per_line);
|
|
if (xwddata == NULL) return (-1);
|
|
|
|
width = xwdhdr->l_pixmap_width;
|
|
height = xwdhdr->l_pixmap_height;
|
|
indexed = (xwdhdr->l_pixmap_depth <= 8);
|
|
bytes_per_pixel = (indexed ? 1 : 3);
|
|
|
|
image_ID = create_new_image (filename, width, height, indexed ? INDEXED : RGB,
|
|
&layer_ID, &drawable, &pixel_rgn);
|
|
|
|
tile_height = gimp_tile_height ();
|
|
data = g_malloc (tile_height * width * bytes_per_pixel);
|
|
|
|
linepad = xwdhdr->l_bytes_per_line
|
|
- (xwdhdr->l_pixmap_width+7)/8;
|
|
if (linepad < 0) linepad = 0;
|
|
|
|
for (j = 0; j < 256; j++) /* Create an array for reversing bits */
|
|
{
|
|
inmask = 0;
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
inmask <<= 1;
|
|
if (j & (1 << i)) inmask |= 1;
|
|
}
|
|
bit_reverse[j] = inmask;
|
|
}
|
|
|
|
redmask = xwdhdr->l_red_mask;
|
|
greenmask = xwdhdr->l_green_mask;
|
|
bluemask = xwdhdr->l_blue_mask;
|
|
|
|
if (redmask == 0) redmask = 0xff0000;
|
|
if (greenmask == 0) greenmask = 0x00ff00;
|
|
if (bluemask == 0) bluemask = 0x0000ff;
|
|
|
|
standard_rgb = (redmask == 0xff0000) && (greenmask == 0x00ff00)
|
|
&& (bluemask == 0x0000ff);
|
|
redshift = greenshift = blueshift = 0;
|
|
|
|
if (!standard_rgb) /* Do we need to re-map the pixel-values ? */
|
|
{
|
|
/* How to shift RGB to be right aligned ? */
|
|
/* (We rely on the the mask bits are grouped and not mixed) */
|
|
|
|
while (((1 << redshift) & redmask) == 0) redshift++;
|
|
while (((1 << greenshift) & greenmask) == 0) greenshift++;
|
|
while (((1 << blueshift) & bluemask) == 0) blueshift++;
|
|
|
|
/* The bits_per_rgb may not be correct. Use redmask instead */
|
|
|
|
maxred = 0; while (redmask >> (redshift + maxred)) maxred++;
|
|
maxred = (1 << maxred) - 1;
|
|
|
|
maxgreen = 0; while (greenmask >> (greenshift + maxgreen)) maxgreen++;
|
|
maxgreen = (1 << maxgreen) - 1;
|
|
|
|
maxblue = 0; while (bluemask >> (blueshift + maxblue)) maxblue++;
|
|
maxblue = (1 << maxblue) - 1;
|
|
|
|
/* Set map-arrays for red, green, blue */
|
|
for (red = 0; red <= maxred; red++)
|
|
redmap[red] = (red * 255) / maxred;
|
|
for (green = 0; green <= maxgreen; green++)
|
|
greenmap[green] = (green * 255) / maxgreen;
|
|
for (blue = 0; blue <= maxblue; blue++)
|
|
bluemap[blue] = (blue * 255) / maxblue;
|
|
}
|
|
|
|
ncols = xwdhdr->l_colormap_entries;
|
|
if (xwdhdr->l_ncolors < ncols) ncols = xwdhdr->l_ncolors;
|
|
if (indexed)
|
|
{
|
|
if (ncols < 2)
|
|
set_bw_color_table (image_ID);
|
|
else
|
|
set_color_table (image_ID, xwdhdr, xwdcolmap);
|
|
}
|
|
else
|
|
{
|
|
ncols = set_pixelmap (ncols, xwdcolmap, &pixel_map);
|
|
}
|
|
|
|
do_reverse = !xwdhdr->l_bitmap_bit_order;
|
|
|
|
/* This is where the image data starts within the file */
|
|
data_offset = ftell (ifp);
|
|
|
|
for (tile_start = 0; tile_start < height; tile_start += tile_height)
|
|
{
|
|
memset (data, 0, width*tile_height*bytes_per_pixel);
|
|
|
|
tile_end = tile_start + tile_height - 1;
|
|
if (tile_end >= height) tile_end = height - 1;
|
|
|
|
for (plane = 0; plane < xwdhdr->l_pixmap_depth; plane++)
|
|
{
|
|
dest = data; /* Position to start of tile within the plane */
|
|
plane_offset = data_offset + plane*height*xwdhdr->l_bytes_per_line;
|
|
tile_offset = plane_offset + tile_start*xwdhdr->l_bytes_per_line;
|
|
fseek (ifp, tile_offset, SEEK_SET);
|
|
|
|
/* Place the last plane at the least significant bit */
|
|
|
|
if (indexed) /* Only 1 byte per pixel */
|
|
{
|
|
fromright = xwdhdr->l_pixmap_depth-1-plane;
|
|
outmask = (1 << fromright);
|
|
}
|
|
else /* 3 bytes per pixel */
|
|
{
|
|
fromright = xwdhdr->l_pixmap_depth-1-plane;
|
|
dest += 2 - fromright/8;
|
|
outmask = (1 << (fromright % 8));
|
|
}
|
|
|
|
for (i = tile_start; i <= tile_end; i++)
|
|
{
|
|
if (fread (xwddata,xwdhdr->l_bytes_per_line,1,ifp) != 1)
|
|
{
|
|
err = 1;
|
|
break;
|
|
}
|
|
xwdin = xwddata;
|
|
|
|
/* Handle bitmap unit */
|
|
if (xwdhdr->l_bitmap_unit == 16)
|
|
{
|
|
if (xwdhdr->l_bitmap_bit_order != xwdhdr->l_byte_order)
|
|
{
|
|
j = xwdhdr->l_bytes_per_line/2;
|
|
while (j--)
|
|
{
|
|
inmask = xwdin[0]; xwdin[0] = xwdin[1]; xwdin[1] = inmask;
|
|
xwdin += 2;
|
|
}
|
|
xwdin = xwddata;
|
|
}
|
|
}
|
|
else if (xwdhdr->l_bitmap_unit == 32)
|
|
{
|
|
if (xwdhdr->l_bitmap_bit_order != xwdhdr->l_byte_order)
|
|
{
|
|
j = xwdhdr->l_bytes_per_line/4;
|
|
while (j--)
|
|
{
|
|
inmask = xwdin[0]; xwdin[0] = xwdin[3]; xwdin[3] = inmask;
|
|
inmask = xwdin[1]; xwdin[1] = xwdin[2]; xwdin[2] = inmask;
|
|
xwdin += 4;
|
|
}
|
|
xwdin = xwddata;
|
|
}
|
|
}
|
|
|
|
g = inmask = 0;
|
|
for (j = 0; j < width; j++)
|
|
{
|
|
if (!inmask)
|
|
{
|
|
g = *(xwdin++);
|
|
if (do_reverse) g = bit_reverse[g];
|
|
inmask = 0x80;
|
|
}
|
|
|
|
if (g & inmask) *dest |= outmask;
|
|
dest += bytes_per_pixel;
|
|
|
|
inmask >>= 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* For indexed images, the mapping to colors is done by the color table. */
|
|
/* Otherwise we must do the mapping by ourself. */
|
|
if (!indexed)
|
|
{
|
|
dest = data;
|
|
for (i = tile_start; i <= tile_end; i++)
|
|
{
|
|
for (j = 0; j < width; j++)
|
|
{
|
|
pixelval = (*dest << 16) | (*(dest+1) << 8) | *(dest+2);
|
|
if ( get_pixelmap (pixelval, &pixel_map, dest, dest+1, dest+2)
|
|
|| standard_rgb)
|
|
{
|
|
dest += 3;
|
|
}
|
|
else /* We have to map RGB to 0,...,255 */
|
|
{
|
|
*(dest++) = redmap[(pixelval & redmask) >> redshift];
|
|
*(dest++) = greenmap[(pixelval & greenmask) >> greenshift];
|
|
*(dest++) = bluemap[(pixelval & bluemask) >> blueshift];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (l_run_mode != RUN_NONINTERACTIVE)
|
|
gimp_progress_update ((double)(tile_end) / (double)(height));
|
|
|
|
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, tile_start,
|
|
width, tile_end-tile_start+1);
|
|
}
|
|
g_free (data);
|
|
g_free (xwddata);
|
|
|
|
if (err)
|
|
show_message ("EOF encountered on reading");
|
|
|
|
gimp_drawable_flush (drawable);
|
|
|
|
return (err ? -1 : image_ID);
|
|
}
|
|
|
|
|
|
static gint
|
|
save_index (FILE *ofp,
|
|
gint32 image_ID,
|
|
gint32 drawable_ID,
|
|
int grey)
|
|
|
|
{ int height, width, linepad, tile_height, i, j;
|
|
int ncolors, vclass;
|
|
long tmp = 0;
|
|
unsigned char *data, *src, *cmap;
|
|
L_XWDFILEHEADER xwdhdr;
|
|
L_XWDCOLOR xwdcolmap[256];
|
|
GPixelRgn pixel_rgn;
|
|
GDrawable *drawable;
|
|
GDrawableType drawable_type;
|
|
|
|
#ifdef XWD_DEBUG
|
|
printf ("save_index ()\n");
|
|
#endif
|
|
|
|
drawable = gimp_drawable_get (drawable_ID);
|
|
drawable_type = gimp_drawable_type (drawable_ID);
|
|
width = drawable->width;
|
|
height = drawable->height;
|
|
tile_height = gimp_tile_height ();
|
|
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
|
|
|
|
/* allocate a buffer for retrieving information from the pixel region */
|
|
src = data = (unsigned char *)g_malloc (tile_height * width * drawable->bpp);
|
|
|
|
linepad = width % 4;
|
|
if (linepad) linepad = 4 - linepad;
|
|
|
|
/* Fill XWD-color map */
|
|
if (grey)
|
|
{
|
|
vclass = 0;
|
|
ncolors = 256;
|
|
|
|
for (j = 0; j < ncolors; j++)
|
|
{
|
|
xwdcolmap[j].l_pixel = j;
|
|
xwdcolmap[j].l_red = (j << 8) | j;
|
|
xwdcolmap[j].l_green = (j << 8) | j;
|
|
xwdcolmap[j].l_blue = (j << 8) | j;
|
|
xwdcolmap[j].l_flags = 7;
|
|
xwdcolmap[j].l_pad = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vclass = 3;
|
|
cmap = gimp_image_get_cmap (image_ID, &ncolors);
|
|
|
|
for (j = 0; j < ncolors; j++)
|
|
{
|
|
xwdcolmap[j].l_pixel = j;
|
|
xwdcolmap[j].l_red = ((*cmap) << 8) | *cmap; cmap++;
|
|
xwdcolmap[j].l_green = ((*cmap) << 8) | *cmap; cmap++;
|
|
xwdcolmap[j].l_blue = ((*cmap) << 8) | *cmap; cmap++;
|
|
xwdcolmap[j].l_flags = 7;
|
|
xwdcolmap[j].l_pad = 0;
|
|
}
|
|
}
|
|
|
|
/* Fill in the XWD header (header_size is evaluated by write_xwd_hdr ()) */
|
|
xwdhdr.l_header_size = 0;
|
|
xwdhdr.l_file_version = 7;
|
|
xwdhdr.l_pixmap_format = 2;
|
|
xwdhdr.l_pixmap_depth = 8;
|
|
xwdhdr.l_pixmap_width = width;
|
|
xwdhdr.l_pixmap_height = height;
|
|
xwdhdr.l_xoffset = 0;
|
|
xwdhdr.l_byte_order = 1;
|
|
xwdhdr.l_bitmap_unit = 32;
|
|
xwdhdr.l_bitmap_bit_order = 1;
|
|
xwdhdr.l_bitmap_pad = 32;
|
|
xwdhdr.l_bits_per_pixel = 8;
|
|
xwdhdr.l_bytes_per_line = width + linepad;
|
|
xwdhdr.l_visual_class = vclass;
|
|
xwdhdr.l_red_mask = 0x000000;
|
|
xwdhdr.l_green_mask = 0x000000;
|
|
xwdhdr.l_blue_mask = 0x000000;
|
|
xwdhdr.l_bits_per_rgb = 8;
|
|
xwdhdr.l_colormap_entries = ncolors;
|
|
xwdhdr.l_ncolors = ncolors;
|
|
xwdhdr.l_window_width = width;
|
|
xwdhdr.l_window_height = height;
|
|
xwdhdr.l_window_x = 64;
|
|
xwdhdr.l_window_y = 64;
|
|
xwdhdr.l_window_bdrwidth = 0;
|
|
|
|
write_xwd_header (ofp, &xwdhdr);
|
|
write_xwd_cols (ofp, &xwdhdr, xwdcolmap);
|
|
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
if ((i % tile_height) == 0) /* Get more data */
|
|
{int scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
|
|
|
|
gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, i, width, scan_lines);
|
|
src = data;
|
|
}
|
|
fwrite (src, width, 1, ofp);
|
|
if (linepad) fwrite ((char *)&tmp, linepad, 1, ofp);
|
|
src += width;
|
|
|
|
if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0))
|
|
gimp_progress_update ((double) i / (double) height);
|
|
}
|
|
g_free (data);
|
|
|
|
gimp_drawable_detach (drawable);
|
|
|
|
if (ferror (ofp))
|
|
{
|
|
show_message ("Error during writing indexed/grey image");
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
static gint
|
|
save_rgb (FILE *ofp,
|
|
gint32 image_ID,
|
|
gint32 drawable_ID)
|
|
|
|
{ int height, width, linepad, tile_height, i;
|
|
long tmp = 0;
|
|
unsigned char *data, *src;
|
|
L_XWDFILEHEADER xwdhdr;
|
|
GPixelRgn pixel_rgn;
|
|
GDrawable *drawable;
|
|
GDrawableType drawable_type;
|
|
|
|
#ifdef XWD_DEBUG
|
|
printf ("save_rgb ()\n");
|
|
#endif
|
|
|
|
drawable = gimp_drawable_get (drawable_ID);
|
|
drawable_type = gimp_drawable_type (drawable_ID);
|
|
width = drawable->width;
|
|
height = drawable->height;
|
|
tile_height = gimp_tile_height ();
|
|
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
|
|
|
|
/* allocate a buffer for retrieving information from the pixel region */
|
|
src = data = (unsigned char *)g_malloc (tile_height * width * drawable->bpp);
|
|
|
|
linepad = (width * 3) % 4;
|
|
if (linepad) linepad = 4 - linepad;
|
|
|
|
/* Fill in the XWD header (header_size is evaluated by write_xwd_hdr ()) */
|
|
xwdhdr.l_header_size = 0;
|
|
xwdhdr.l_file_version = 7;
|
|
xwdhdr.l_pixmap_format = 2;
|
|
xwdhdr.l_pixmap_depth = 24;
|
|
xwdhdr.l_pixmap_width = width;
|
|
xwdhdr.l_pixmap_height = height;
|
|
xwdhdr.l_xoffset = 0;
|
|
xwdhdr.l_byte_order = 1;
|
|
|
|
xwdhdr.l_bitmap_unit = 32;
|
|
xwdhdr.l_bitmap_bit_order = 1;
|
|
xwdhdr.l_bitmap_pad = 32;
|
|
xwdhdr.l_bits_per_pixel = 24;
|
|
|
|
xwdhdr.l_bytes_per_line = width * 3 + linepad;
|
|
xwdhdr.l_visual_class = 5;
|
|
xwdhdr.l_red_mask = 0xff0000;
|
|
xwdhdr.l_green_mask = 0x00ff00;
|
|
xwdhdr.l_blue_mask = 0x0000ff;
|
|
xwdhdr.l_bits_per_rgb = 8;
|
|
xwdhdr.l_colormap_entries = 0;
|
|
xwdhdr.l_ncolors = 0;
|
|
xwdhdr.l_window_width = width;
|
|
xwdhdr.l_window_height = height;
|
|
xwdhdr.l_window_x = 64;
|
|
xwdhdr.l_window_y = 64;
|
|
xwdhdr.l_window_bdrwidth = 0;
|
|
|
|
write_xwd_header (ofp, &xwdhdr);
|
|
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
if ((i % tile_height) == 0) /* Get more data */
|
|
{int scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i);
|
|
|
|
gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, i, width, scan_lines);
|
|
src = data;
|
|
}
|
|
fwrite (src, width*3, 1, ofp);
|
|
if (linepad) fwrite ((char *)&tmp, linepad, 1, ofp);
|
|
src += width*3;
|
|
|
|
if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0))
|
|
gimp_progress_update ((double) i / (double) height);
|
|
}
|
|
g_free (data);
|
|
|
|
gimp_drawable_detach (drawable);
|
|
|
|
if (ferror (ofp))
|
|
{
|
|
show_message ("Error during writing rgb image");
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
/* Show a message. Where to show it, depends on the runmode */
|
|
static void show_message (char *message)
|
|
|
|
{
|
|
/* If there would be a simple message box like the one */
|
|
/* used in ../app/interface.h, I would like to use it. */
|
|
if (l_run_mode == RUN_INTERACTIVE)
|
|
g_warning (message);
|
|
else
|
|
fprintf (stderr, "xwd: %s\n", message);
|
|
}
|