1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/lib/DtHelp/Graphics.c
Jose Rubio 0086a7067e Fix to compile warnings.
* discarded-qualifiers warnings.
* Function definitions, the .h doesn't match the .c.
* Added some include to ensure the .c has function definition.
2019-10-11 10:49:48 +02:00

3061 lines
92 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/************************************<+>*************************************
****************************************************************************
**
** File: Graphics.c
**
** Project: CDE Help System
**
** Description: This code processes a graphic (X11 bitmap, X11 pixmap,
** X11 XWD file, and TIFF). It will degrade graphics to
** match the type of monitor the image is displayed upon.
**
** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
**
** (c) Copyright 1993, 1994 Hewlett-Packard Company
** (c) Copyright 1993, 1994 International Business Machines Corp.
** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
** (c) Copyright 1993, 1994 Novell, Inc.
**
****************************************************************************
************************************<+>*************************************/
/******************************************************************************
** The GreyScale and Perform_Dither routine were take and modified from
** the g-job 'xgedit' created by Mark F. Cook. The following is the
** disclaimer from the dither.c source code
******************************************************************************
** Program: xgedit.c
**
** Description: X11-based graphics editor
**
** File: dither.c, containing the following
** subroutines/functions:
** Dither_Image()
** Perform_Dither()
**
** Copyright 1988 by Mark F. Cook and Hewlett-Packard, Corvallis
** Workstation Operation. All rights reserved.
**
** Permission to use, copy, and modify this software is granted, provided
** that this copyright appears in all copies and that both this copyright
** and permission notice appear in all supporting documentation, and that
** the name of Mark F. Cook and/or Hewlett-Packard not be used in advertising
** without specific, written prior permission. Neither Mark F. Cook or
** Hewlett-Packard make any representations about the suitibility of this
** software for any purpose. It is provided "as is" without express or
** implied warranty.
**
******************************************************************************
** CHANGE LOG:
**
** 1.00.00 - 1/11/89 - Start of Rev. number.
**
** @@@ 4.05.00 - 12/07/89 - Created Dither_Image() and Perform_Dither() to
** @@@ allow conversion of color images into a dithered black &
** @@@ white image suitable for output on a laser printer.
**
******************************************************************************/
/*
static char rcs_id[]="$XConsortium: Graphics.c /main/23 1996/12/06 11:12:54 cde-hp $";
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <X11/Xlib.h>
#include <X11/XWDFile.h>
#include <X11/ImUtil.h>
#ifndef STUB
#include "il.h"
#include "ilfile.h"
#include "ilX.h"
#include "ilerrors.h"
#endif
#include <Xm/Xm.h>
#include <Xm/XmPrivate.h>
#include <Dt/Dts.h>
#include <Dt/xpm.h>
#include "bufioI.h"
#include "Access.h"
#include "AccessI.h"
#include "GraphicsP.h"
#include "GraphicsI.h"
#include "StringFuncsI.h"
#include "GifUtilsI.h"
#include "XbmUtilsI.h"
#include "JpegUtilsI.h"
#include "Lock.h"
/*****************************************************************************/
/* Private data */
/*****************************************************************************/
#define GR_SUCCESS 0 /* everything okay */
#define GR_DRAWABLE_ERR 1 /* couldn't get drawable attr/geom */
#define GR_FILE_ERR 2 /* file open/read/write problem */
#define GR_REQUEST_ERR 3 /* bad placement or size */
#define GR_ALLOC_ERR 4 /* memory allocation failure */
#define GR_HEADER_ERR 5 /* file header version/size problem */
#define MAX_GREY_COLORS 8
#define RES_TOLERANCE 25 /* resolution scaling tolerance */
static short GreyAllocated = False;
static Pixel GreyScalePixels[MAX_GREY_COLORS];
static char *GreyScaleColors[MAX_GREY_COLORS] =
{
"#212121212121",
"#424242424242",
"#636363636363",
"#737373737373",
"#949494949494",
"#adadadadadad",
"#bdbdbdbdbdbd",
"#dededededede",
};
#define Missing_bm_width 75
#define Missing_bm_height 47
static unsigned char Missing_bm_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x04, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x00, 0x18, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x18, 0x8c, 0x21, 0x00, 0x00, 0x20, 0x00, 0x00, 0xc0, 0x00,
0x18, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x24,
0x31, 0xf0, 0xf0, 0x30, 0xe8, 0xf0, 0xc1, 0x00, 0x18, 0x04, 0x21, 0x08,
0x08, 0x20, 0x18, 0x09, 0xc1, 0x00, 0x18, 0x04, 0x21, 0xf0, 0xf0, 0x20,
0x08, 0x09, 0xc1, 0x00, 0x18, 0x04, 0x21, 0x00, 0x01, 0x21, 0x08, 0x09,
0xc1, 0x00, 0x18, 0x04, 0x21, 0x08, 0x09, 0x21, 0x08, 0x09, 0xc1, 0x00,
0x18, 0x04, 0x71, 0xf0, 0xf0, 0x70, 0x08, 0xf1, 0xc1, 0x00, 0x18, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf0, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0xf0,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x08, 0x01, 0x00,
0x00, 0x08, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x08, 0x00, 0x00, 0x00, 0x08,
0x20, 0x00, 0xc0, 0x00, 0x18, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
0xc0, 0x00, 0x18, 0x08, 0xd8, 0xf0, 0xe8, 0xf8, 0x30, 0xf0, 0xc0, 0x00,
0x18, 0xc8, 0x31, 0x01, 0x19, 0x09, 0x21, 0x08, 0xc1, 0x00, 0x18, 0x08,
0x11, 0xf0, 0x09, 0x09, 0x21, 0x08, 0xc0, 0x00, 0x18, 0x08, 0x11, 0x08,
0x09, 0x09, 0x21, 0x08, 0xc0, 0x00, 0x18, 0x08, 0x11, 0x08, 0x09, 0x09,
0x21, 0x08, 0xc1, 0x00, 0x18, 0xf0, 0x10, 0xf0, 0xf9, 0x08, 0x71, 0xf0,
0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xc0, 0x00,
0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf8, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00};
/* Used to hold image type converter registry info */
typedef struct {
char *image_type;
_DtGrLoadProc convert_proc;
_DtGrDestroyContextProc destroy_context_proc;
} _DtGrRegistryRec;
/*
* This array maps image file name extensions to the corresponding
* CDE data type. It is used by the DetermineImageType function.
* The array must be NULL-terminated.
*/
static char * img_extensions[] = {
"xpm", "PM",
"pm", "PM",
"gif", "GIF",
"jpeg", "JPEG",
"jpg", "JPEG",
"xbm", "BM",
"bm", "BM",
"tiff", "TIFF",
"tif", "TIFF",
"xwd", "XWD",
"cgm", "CGM",
NULL
};
/*****************************************************************************/
/* Private declarations */
/*****************************************************************************/
static int Do_Direct(
Display *dpy,
int screen,
XWDFileHeader *header,
Colormap colormap,
int ncolors,
XColor *colors,
enum _DtGrColorModel force,
XImage *in_image,
XImage *out_image,
unsigned long **ret_colors,
int *ret_number );
static int Do_Pseudo(
Display *dpy,
int screen,
Colormap colormap,
int ncolors,
XColor *colors,
enum _DtGrColorModel force,
XImage *in_image,
XImage *out_image,
unsigned long **ret_colors,
int *ret_number );
static int GreyScale (
Display *dpy,
int screen,
Colormap cmap,
XImage *in_image,
XImage *out_image,
XColor *colors,
int ncolors,
enum _DtGrColorModel force,
int rshift,
int gshift,
int bshift,
Pixel rmask,
Pixel gmask,
Pixel bmask );
static unsigned int Image_Size(
XImage *image );
static void Perform_Dither(
Display *dpy,
int screen,
XImage *image,
int *greyscale );
static enum _DtGrLoadStatus processBitmap(
_DtGrStream *image,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context);
#ifndef STUB
static enum _DtGrLoadStatus processTiff(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context);
static void destroyTiffContext(
_DtGrContext *context);
#endif
static enum _DtGrLoadStatus processXwd(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context);
static void _swaplong (
char *bp,
unsigned n );
static void _swapshort (
char *bp,
unsigned n );
static int XwdFileToPixmap (
Display *dpy,
int screen,
int depth,
Pixmap pixmap,
Colormap colormap,
Visual *visual,
GC gc,
enum _DtGrColorModel color_model,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height,
_DtGrStream *stream,
unsigned long **ret_colors,
int *ret_number );
static enum _DtGrLoadStatus processXpm(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context);
static enum _DtGrLoadStatus processGIF(
_DtGrStream *image,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context);
static enum _DtGrLoadStatus processJPEG(
_DtGrStream *image,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context);
static enum _DtGrLoadStatus DetermineImageType(
_DtGrStream *stream,
char *image_type);
static enum _DtGrLoadStatus GetConverterAndDestructor(
char *image_type,
_DtGrLoadProc *converter,
_DtGrDestroyContextProc *destructor);
static float ComputeRatio(int media_res, int image_res);
/*****************************************************************************
* Image type registry declarations
*****************************************************************************/
/* Registry of converters and destructors for default image types */
static _DtGrRegistryRec registry[] =
{
{
"PM",
processXpm,
NULL
},
{
"BM",
processBitmap,
NULL
},
{
"GIF",
processGIF,
NULL
},
{
"JPEG",
processJPEG,
NULL
},
{
"TIFF",
processTiff,
destroyTiffContext
},
{
"XWD",
processXwd,
NULL
},
};
static int registry_count = XtNumber(registry);
/* Registry of converters and destructors for non-default image types */
static _DtGrRegistryRec *new_registry = NULL;
static int new_registry_count = 0;
/*****************************************************************************
* Private Routines
*****************************************************************************/
/*****************************************************************************
* taken straight out of xwud and modified.
*****************************************************************************/
/* Copyright 1985, 1986, 1988 Massachusetts Institute of Technology */
static void
_swapshort (
char *bp,
unsigned n )
{
char c;
char *ep = bp + n;
while (bp < ep) {
c = *bp;
*bp = *(bp + 1);
bp++;
*bp++ = c;
}
}
static void
_swaplong (
char *bp,
unsigned n )
{
char c;
char *ep = bp + n;
char *sp;
while (bp < ep) {
sp = bp + 3;
c = *sp;
*sp = *bp;
*bp++ = c;
sp = bp + 1;
c = *sp;
*sp = *bp;
*bp++ = c;
bp += 2;
}
}
static float
ComputeRatio(int media_res, int image_res)
{
float ratio;
int iratio, dx;
if (media_res >= image_res) {
ratio = (float)media_res / (float)image_res;
if (media_res % image_res == 0)
return ratio;
iratio = ratio + 0.5;
dx = media_res - image_res * iratio;
if (dx >= -RES_TOLERANCE && dx <= RES_TOLERANCE)
ratio = (float)iratio;
} else {
ratio = (float)image_res / (float)media_res;
if (image_res % media_res == 0)
return 1.0 / ratio;
iratio = ratio + 0.5;
dx = image_res - media_res * iratio;
if (dx >= -RES_TOLERANCE && dx <= RES_TOLERANCE)
ratio = (float)iratio;
ratio = 1.0 / ratio;
}
return ratio;
}
/*****************************************************************************
* Function: GreyScale
*
* Turn a color image into a 8 grey color image
* If it can't create a grey scale image, GreyScale will call
* Perform_Dither to create a bi-tonal image.
*
*****************************************************************************
* The GreyScale code was ported from xgedit and changed to fit our needs
*****************************************************************************/
static int
GreyScale (
Display *dpy,
int screen,
Colormap cmap,
XImage *in_image,
XImage *out_image,
XColor *colors,
int ncolors,
enum _DtGrColorModel force,
int rshift,
int gshift,
int bshift,
Pixel rmask,
Pixel gmask,
Pixel bmask )
{
int i, j, x;
int inc;
int count;
int width = in_image->width;
int height = in_image->height;
int value;
int *grey_scale;
Pixel valueArray[256];
Pixel n;
XColor ret_color;
/*--- allocate an array big enough to map each pixel in the image ---*/
/*--- into a corresponding greyscale value (in the range [0-255]). ---*/
grey_scale = (int *) calloc(width*height, sizeof(int));
if (grey_scale == NULL) {
return GR_ALLOC_ERR;
}
/*--- < ESTABLISH THE GREYSCALE IMAGE > ---*/
/*--- The NTSC formula for converting an RGB value into the ---*/
/*--- corresponding greyscale value is: ---*/
/*--- luminosity = .299 red + .587 green + .114 blue ---*/
/*
* zero the flag array
*/
for (i = 0; i < 256; i++)
valueArray [i] = 0;
for (j=0, x = 0; j<height; j++)
for (i=0; i<width; i++, x++) {
n = XGetPixel(in_image, i, j);
if (rshift)
{
ret_color.red = (n >> rshift) & rmask;
ret_color.green = (n >> gshift) & gmask;
ret_color.blue = (n >> bshift) & bmask;
if (ncolors)
{
ret_color.red = colors[ret_color.red ].red;
ret_color.green = colors[ret_color.green].green;
ret_color.blue = colors[ret_color.blue ].blue;
}
else
{
ret_color.red = (((Pixel) ret_color.red ) * 65535) / rmask;
ret_color.green = (((Pixel) ret_color.green) * 65535) / gmask;
ret_color.blue = (((Pixel) ret_color.blue ) * 65535) / bmask;
}
value = (((int)(ret_color.red*299) + (int)(ret_color.green*587) +
(int)(ret_color.blue*114)) / 1000) >> 8;
}
else
value = (((int)(colors[n].red*299) + (int)(colors[n].green*587) +
(int)(colors[n].blue*114)) / 1000) >> 8;
grey_scale[x] = value;
valueArray[value]++;
} /* for(i...) */
/*
* Find out if we can/have allocate the pre-defined grey colors.
*/
_DtHelpProcessLock();
if (!GreyAllocated && force != _DtGrBITONAL)
{
for (i = 0; !GreyAllocated && i < MAX_GREY_COLORS; i++)
{
if (!XParseColor (dpy, cmap, GreyScaleColors[i], &ret_color) ||
!XAllocColor (dpy, cmap, &ret_color))
{
/*
* Have a problem allocating one of the pre-defined
* grey colors. Free the already allocated pixels
* and set the flag.
*/
if (i)
XFreeColors (dpy, cmap, GreyScalePixels, i, 0);
GreyAllocated = -1;
}
else
GreyScalePixels[i] = ret_color.pixel;
}
if (!GreyAllocated)
GreyAllocated = True;
}
/*
* Had a problem allocating the pre-defined grey colors.
* Try to dither into black and white.
*/
if (force == _DtGrBITONAL || GreyAllocated == -1)
{
Perform_Dither (dpy, screen, out_image, grey_scale);
free(grey_scale);
_DtHelpProcessUnlock();
return GR_SUCCESS;
}
_DtHelpProcessUnlock();
/*
* Find out how many grey scale colors there are.
*/
for (count = 0, i = 0; i < 256; i++)
if (valueArray[i])
count++;
/*
* If we have less than maximum grey colors we want to spread the load
* between the colors
*/
if (count < MAX_GREY_COLORS)
inc = count;
else
inc = MAX_GREY_COLORS;
/*
* This is rather esoteric code.
* The line
* valueArray[n] = GreyScalePixels[i * MAX_GREY_COLORS / inc]
*
* causes the colors to be evenly distributed if the total number
* of calculated grey shades is less than the number of pre-defined
* grey colors.
*
* The if stmt
* if (j >= count / (MAX_GREY_COLORS - i))
*
* uniformly reduces the calculated grey shades into the pre-defined
* grey colors, if the total number of grey shades is greater than
* the number of pre-defined grey colors.
*
* If after reading the following code, the reader still doesn't
* understand it, pick a couple of numbers between 1-255 for 'count'
* and walk each of them thru the 'for' loop. Hopefully it will help.
* (Suggestion - pick a large number for one value and pick
* a number less than 8 for the other value).
*/
for (i = 0, n = 0, j = 0; n < 256 && count && i < MAX_GREY_COLORS; n++)
{
if (valueArray[n])
{
_DtHelpProcessLock();
valueArray[n] = GreyScalePixels[i * MAX_GREY_COLORS / inc];
_DtHelpProcessUnlock();
j++;
if (j >= count / (MAX_GREY_COLORS - i))
{
count -= j;
i++;
j = 0;
}
}
}
/*
* Now replace the image pixels with the grey pixels
*/
for (j = 0, x = 0; j < height; j++)
for (i = 0; i < width; i++, x++) {
XPutPixel (out_image, i, j, valueArray[grey_scale[x]]);
} /* for(i...) */
free(grey_scale);
return GR_SUCCESS;
}
/***************************************************************************
* *
* Routine: Perform_Dither *
* *
* Purpose: Given a color XImage and a greyscale representation of it, *
* for each pixel in the image, determine whether it should be *
* coverted to Black or White base on the weighted average of *
* the greyscale value of it and the pixels surrounding it. *
* Be sure to do bounds checking for pixels that are at the *
* edge of the image. *
* *
* The dithering is done using the Floyd-Steinberg error *
* diffusion algorithm, which incorporates a Stucki error *
* filter (specifics can be found in Chapter 8, "Dithering *
* with Blue Noise", of the book "Digital Halftoning" by *
* Robert Ulichney (MIT Press, 1988). *
* *
*X11***********************************************************************/
static void
Perform_Dither(
Display *dpy,
int screen,
XImage *image,
int *greyscale )
{
int i, j, width, height;
int result, error, max_lum;
Pixel blackPixel = XBlackPixel (dpy, screen);
Pixel whitePixel = XWhitePixel (dpy, screen);
width = image->width;
height = image->height;
max_lum = 256;
for (j=0; j<height; j++) /* rows */
for (i=0; i<width; i++) { /* columns */
if (greyscale[(j*width)+i] < (max_lum/2))
result = 0;
else
result = max_lum - 1;
error = greyscale[(j*width)+i] - result;
if (i+1 < width) /*--- G [j] [i+1] ---*/
greyscale[(j*width)+i+1] += (error * 8)/42;
if (i+2 < width) /*--- G [j] [i+2] ---*/
greyscale[(j*width)+i+2] += (error * 4)/42;
if (j+1 < height) {
if (i-2 >= 0) /*--- G [j+1] [i-2] ---*/
greyscale[((j+1)*width)+i-2] += (error * 2)/42;
if (i-1 >= 0) /*--- G [j+1] [i-1] ---*/
greyscale[((j+1)*width)+i-1] += (error * 4)/42;
/*--- G [j+1] [i] ---*/
greyscale[((j+1)*width)+i] += (error * 8)/42;
if (i+1 < width) /*--- G [j+1] [i+1] ---*/
greyscale[((j+1)*width)+i+1] += (error * 4)/42;
if (i+2 < width) /*--- G [j+1] [i+2] ---*/
greyscale[((j+1)*width)+i+2] += (error * 2)/42;
}
if (j+2 < height) {
if (i-2 >= 0) /*--- G [j+2] [i-2] ---*/
greyscale[((j+2)*width)+i-2] += error/42;
if (i-1 >= 0) /*--- G [j+2] [i-1] ---*/
greyscale[((j+2)*width)+i-1] += (error * 2)/42;
/*--- G [j+2] [i] ---*/
greyscale[((j+2)*width)+i] += (error * 4)/42;
if (i+1 < width) /*--- G [j+2] [i+1] ---*/
greyscale[((j+2)*width)+i+1] += (error * 2)/42;
if (i+2 < width) /*--- G [j+2] [i+2] ---*/
greyscale[((j+2)*width)+i+2] += error/42;
}
if (result)
XPutPixel(image, i, j, whitePixel);
else
XPutPixel(image, i, j, blackPixel);
} /* for(i...) */
}
static int
Do_Pseudo(
Display *dpy,
int screen,
Colormap colormap,
int ncolors,
XColor *colors,
enum _DtGrColorModel force,
XImage *in_image,
XImage *out_image,
unsigned long **ret_colors,
int *ret_number )
{
int i, x, y, colorCount = 0;
XColor *color;
int result = 0;
Pixel pixel;
for (i = 0; i < ncolors; i++)
colors[i].flags = 0;
*ret_colors = NULL;
*ret_number = 0;
/*
* beware 'result'.
* It is set to one upon entering this routine.
* The only way it can be modified is by the call to XAllocColor.
*/
if (force == _DtGrCOLOR)
result = 1;
for (y = 0; result && y < in_image->height; y++)
{
for (x = 0; result && x < in_image->width; x++)
{
pixel = XGetPixel(in_image, x, y);
color = &colors[pixel];
if (!color->flags)
{
color->flags = DoRed | DoGreen | DoBlue;
result = XAllocColor(dpy, colormap, color);
if (!result)
color->flags = 0;
else
colorCount++;
}
if (result)
XPutPixel(out_image, x, y, color->pixel);
}
}
/*
* If result == 0, a call to XAllocColor failed
* Try to grey scale the image.
*/
if (!result)
{
if (colorCount)
{
for (i = 0; i < ncolors; i++)
{
if (colors[i].flags)
{
XFreeColors (dpy, colormap, &(colors[i].pixel), 1, 0);
colors[i].flags = 0;
}
}
}
result = GreyScale (dpy, screen, colormap, in_image, out_image, colors,
ncolors, force, 0, 0, 0, 0, 0, 0);
}
else if (colorCount)
{
result = GR_SUCCESS;
*ret_colors = (unsigned long *) malloc (
sizeof (unsigned long) * colorCount);
if (*ret_colors == NULL)
{
colorCount = 0;
result = GR_ALLOC_ERR;
}
for (i = 0, x = 0; i < ncolors && x < colorCount; i++)
if (colors[i].flags)
(*ret_colors)[x++] = colors[i].pixel;
*ret_number = colorCount;
}
/*
* result was set to a XHPIF value via the 'else' stmt or
* returned from GreyScale routine.
*/
return result;
}
static int
Do_Direct(
Display *dpy,
int screen,
XWDFileHeader *header,
Colormap colormap,
int ncolors,
XColor *colors,
enum _DtGrColorModel force,
XImage *in_image,
XImage *out_image,
unsigned long **ret_colors,
int *ret_number )
{
int x, y;
XColor color;
unsigned long rmask, gmask, bmask;
int rshift = 0, gshift = 0, bshift = 0;
int i;
int result;
int pixMax = 256;
int pixI = 0;
Pixel pix;
Pixel *oldPixels;
Pixel *newPixels;
oldPixels = (Pixel *) malloc (sizeof (Pixel) * pixMax);
newPixels = (Pixel *) malloc (sizeof (Pixel) * pixMax);
if (oldPixels == NULL || newPixels == NULL)
{
if (oldPixels)
free (oldPixels);
if (newPixels)
free (newPixels);
return GR_ALLOC_ERR;
}
rmask = header->red_mask;
while (!(rmask & 1)) {
rmask >>= 1;
rshift++;
}
gmask = header->green_mask;
while (!(gmask & 1)) {
gmask >>= 1;
gshift++;
}
bmask = header->blue_mask;
while (!(bmask & 1)) {
bmask >>= 1;
bshift++;
}
if (in_image->depth <= 12)
pix = 1 << in_image->depth;
if (force == _DtGrCOLOR)
color.flags = DoRed | DoGreen | DoBlue;
else
color.flags = 0;
for (y = 0; color.flags && y < in_image->height; y++)
{
for (x = 0; color.flags && x < in_image->width; x++)
{
pix = XGetPixel(in_image, x, y);
i = 0;
while (i < pixI && oldPixels[i] != pix)
i++;
if (i == pixI)
{
color.red = (pix >> rshift) & rmask;
color.green = (pix >> gshift) & gmask;
color.blue = (pix >> bshift) & bmask;
if (ncolors) {
color.red = colors[color.red].red;
color.green = colors[color.green].green;
color.blue = colors[color.blue].blue;
} else {
color.red = ((unsigned long)color.red * 65535) / rmask;
color.green = ((unsigned long)color.green * 65535) / gmask;
color.blue = ((unsigned long)color.blue * 65535) / bmask;
}
if (!XAllocColor(dpy, colormap, &color))
color.flags = 0;
else
{
if (pixI >= pixMax)
{
pixMax += 128;
oldPixels = (Pixel *) realloc ((void *) oldPixels,
(sizeof (Pixel) * pixMax));
newPixels = (Pixel *) realloc ((void *) newPixels,
(sizeof (Pixel) * pixMax));
/*
* check the realloc
*/
if (oldPixels == NULL || newPixels == NULL)
{
if (oldPixels)
free (oldPixels);
if (newPixels)
{
XFreeColors(dpy, colormap, newPixels, pixI, 0);
free (newPixels);
}
return GR_ALLOC_ERR;
}
}
oldPixels[pixI] = pix;
newPixels[pixI++] = color.pixel;
}
}
if (color.flags)
XPutPixel(out_image, x, y, newPixels[i]);
}
}
if (color.flags)
{
result = GR_SUCCESS;
if (pixI < pixMax)
{
newPixels = (Pixel *) realloc ((void *) newPixels,
(sizeof (Pixel) * pixI));
if (newPixels == NULL)
result = GR_ALLOC_ERR;
}
free (oldPixels);
*ret_colors = newPixels;
*ret_number = pixI;
}
else
{
if (pixI)
XFreeColors (dpy, colormap, newPixels, pixI, 0);
free (oldPixels);
free (newPixels);
result = GreyScale(dpy, screen, colormap, in_image, out_image, colors,
ncolors, force, rshift, gshift, bshift, rmask, gmask, bmask);
}
return result;
}
static unsigned int
Image_Size(
XImage *image )
{
if (image->format != ZPixmap)
return(image->bytes_per_line * image->height * image->depth);
return((unsigned)image->bytes_per_line * image->height);
}
static int
XwdFileToPixmap (
Display *dpy,
int screen,
int depth,
Pixmap pixmap,
Colormap colormap,
Visual *visual,
GC gc,
enum _DtGrColorModel color_model,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height,
_DtGrStream *stream,
unsigned long **ret_colors,
int *ret_number )
{
int result;
int i;
XImage in_image, *out_image;
char *buffer;
unsigned long swaptest = 1;
int count;
unsigned buffer_size;
int ncolors;
Bool rawbits = False;
XColor *colors = NULL;
#ifdef __alpha
/* Use a different structure for compatibility with 32-bit platform */
XWDColor xwd_color;
#endif /* __alpha */
XWDFileHeader header;
/* Reset the pointer to the beginning of the stream */
_DtGrSeek(stream, 0, SEEK_SET);
/*
* Read in header information.
*/
if(_DtGrRead((char *)&header, sizeof(header), 1, stream) != 1)
{
return GR_HEADER_ERR;
}
if (*(char *) &swaptest)
_swaplong((char *) &header, sizeof(header));
/* check to see if the dump file is in the proper format */
if (header.file_version != XWD_FILE_VERSION)
{
return GR_HEADER_ERR;
}
if (header.header_size < sizeof(header))
{
return GR_HEADER_ERR;
}
/*
* skip the window name
*/
if (_DtGrSeek(stream, (header.header_size - sizeof(header)), 1))
{
return GR_FILE_ERR;
}
/*
* initialize the input image
*/
in_image.width = (int) header.pixmap_width;
in_image.height = (int) header.pixmap_height;
in_image.xoffset = (int) header.xoffset;
in_image.format = (int) header.pixmap_format;
in_image.byte_order = (int) header.byte_order;
in_image.bitmap_unit = (int) header.bitmap_unit;
in_image.bitmap_bit_order = (int) header.bitmap_bit_order;
in_image.bitmap_pad = (int) header.bitmap_pad;
in_image.depth = (int) header.pixmap_depth;
in_image.bits_per_pixel = (int) header.bits_per_pixel;
in_image.bytes_per_line = (int) header.bytes_per_line;
in_image.red_mask = header.red_mask;
in_image.green_mask = header.green_mask;
in_image.blue_mask = header.blue_mask;
in_image.obdata = NULL;
_XInitImageFuncPtrs(&in_image);
/* read in the color map buffer */
ncolors = header.ncolors;
if (ncolors) {
colors = (XColor *)malloc((unsigned) ncolors * sizeof(XColor));
if (!colors)
{
return GR_ALLOC_ERR;
}
#ifdef __alpha
/* Use XWDColor instead of XColor. Byte-swapping if it is necessary.
* Move values back into Xcolor structure.
*/
for (i = 0; i < ncolors; i++) {
if (_DtGrRead( (char *) &xwd_color, sizeof(XWDColor), 1 , stream) != 1 )
{
XFree ((char *) colors);
return GR_FILE_ERR;
}
if (*(char *) &swaptest) {
_swaplong((char *) &xwd_color.pixel, sizeof(xwd_color.pixel));
_swapshort((char *) &xwd_color.red, 3 * sizeof(xwd_color.red));
}
colors[i].pixel = xwd_color.pixel;
colors[i].red = xwd_color.red;
colors[i].green = xwd_color.green;
colors[i].blue = xwd_color.blue;
colors[i].flags = xwd_color.flags;
}
#else
if(_DtGrRead((char *) colors, sizeof(XColor), ncolors, stream) != ncolors)
{
XFree ((char *) colors);
return GR_FILE_ERR;
}
if (*(char *) &swaptest) {
for (i = 0; i < ncolors; i++) {
_swaplong((char *) &colors[i].pixel, sizeof(long));
_swapshort((char *) &colors[i].red, 3 * sizeof(short));
}
}
#endif /* __alpha */
}
/*
* alloc the pixel buffer
*/
buffer_size = Image_Size(&in_image);
buffer = (char *) malloc(buffer_size);
if (buffer == NULL)
{
if (NULL != colors)
XFree ((char *) colors);
return GR_ALLOC_ERR;
}
/* read in the image data */
count = _DtGrRead(buffer, sizeof(char), (int)buffer_size, stream);
if (count != buffer_size)
{
if (NULL != colors)
XFree ((char *) colors);
XFree (buffer);
return GR_FILE_ERR;
}
if (in_image.depth == 1) {
in_image.format = XYBitmap;
rawbits = True;
}
in_image.data = buffer;
/* create the output image */
result = GR_SUCCESS;
if (rawbits) {
out_image = &in_image;
} else {
out_image = XCreateImage(dpy, visual, depth,
(depth == 1) ? XYBitmap : in_image.format,
in_image.xoffset, NULL,
in_image.width, in_image.height,
XBitmapPad(dpy), 0);
out_image->data = (char *) malloc(Image_Size(out_image));
if ((header.visual_class == TrueColor) ||
(header.visual_class == DirectColor))
result = Do_Direct(dpy, screen, &header, colormap, ncolors, colors,
color_model,
&in_image, out_image, ret_colors, ret_number);
else
result = Do_Pseudo(dpy, screen, colormap, ncolors, colors, color_model,
&in_image, out_image, ret_colors, ret_number);
}
if (result != GR_ALLOC_ERR)
_XmPutScaledImage(dpy, pixmap, gc, out_image,
src_x, src_y, dst_x, dst_y,
in_image.width, in_image.height,
width, height);
/*
* free the buffers
*/
if (NULL != colors)
XFree ((char *) colors);
XFree (buffer);
if (!rawbits)
XDestroyImage (out_image);
return result;
}
/*****************************************************************************/
/* General functions for changing a file into a pixmap */
/* */
/*****************************************************************************/
/***********
*
* Function processBitmap
*
* takes a string.
* Make a bitmap into the pixmap for the graphic.
*
***********/
static enum _DtGrLoadStatus processBitmap(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context
)
{
int result;
int junk;
unsigned int width, height;
unsigned char *data;
Pixmap scaled_pixmap = 0;
Display *dpy = DisplayOfScreen(screen);
Drawable drawable = RootWindowOfScreen(screen);
XImage ximage;
float ratio = 1.0;
if (media_resolution == 0)
return(_DtGrCONVERT_FAILURE);
if (*in_out_width == 0 && *in_out_height == 0)
ratio = ComputeRatio(media_resolution, 100);
if (stream->type == _DtGrNONE)
return(_DtGrCONVERT_FAILURE);
result = _DtGrReadBitmapStreamData (stream,
&width, &height, &data, &junk, &junk);
/* Be sure to implement XvpCopyPlane later */
if (result == BitmapSuccess)
{
ximage.height = height;
ximage.width = width;
ximage.depth = 1;
ximage.bits_per_pixel = 1;
ximage.xoffset = 0;
ximage.format = XYBitmap;
ximage.data = (char *)data;
ximage.byte_order = LSBFirst;
ximage.bitmap_unit = 8;
ximage.bitmap_bit_order = LSBFirst;
ximage.bitmap_pad = 8;
ximage.bytes_per_line = (width+7)/8;
XInitImage(&ximage);
*in_out_width = (Dimension) width * ratio + 0.5;
*in_out_height = (Dimension) height * ratio + 0.5;
if (*in_out_width == 0)
*in_out_width = 1;
if (*in_out_height == 0)
*in_out_height = 1;
scaled_pixmap = XCreatePixmap (dpy, drawable, (*in_out_width),
(*in_out_height), depth);
_XmPutScaledImage(dpy, scaled_pixmap, gc, &ximage,0, 0, 0, 0,
width,height,(*in_out_width),(*in_out_height));
XFree((char *)data);
*ret_pixmap = scaled_pixmap;
}
if (result == BitmapSuccess)
return(_DtGrSUCCESS);
else if (result == BitmapOpenFailed)
return(_DtGrOPEN_FAILED);
else if (result == BitmapFileInvalid)
return(_DtGrFILE_INVALID);
else if (result == BitmapNoMemory)
return(_DtGrNO_MEMORY);
else
return(_DtGrCONVERT_FAILURE);
}
#ifndef STUB
/***********
*
* Function processTiff
*
* takes a string.
* Make a tiff into the pixmap for the graphic.
*
***********/
static enum _DtGrLoadStatus processTiff(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context
)
{
int result = -1;
Pixmap pixmap = 0;
ilFile inFile;
ilPipe inPipe;
ilFileImage inImage;
const ilImageDes *inDes;
static ilContext IlContext = NULL;
Display *dpy = DisplayOfScreen(screen);
Drawable drawable = RootWindowOfScreen(screen);
ilXWC *tiff_xwc;
float ratio = 1.0;
_DtHelpProcessLock();
if ((context == NULL) || (stream->type == _DtGrNONE))
{
_DtHelpProcessUnlock();
return (_DtGrCONVERT_FAILURE);
}
if (media_resolution == 0)
{
_DtHelpProcessUnlock();
return(_DtGrCONVERT_FAILURE);
}
tiff_xwc = (ilXWC *) &(context->context);
if (IlContext == NULL)
{
if (IL_CREATE_CONTEXT (&IlContext, 0))
{
IlContext = NULL;
_DtHelpProcessUnlock();
return (_DtGrCONVERT_FAILURE);
}
}
if (*tiff_xwc == NULL)
{
/* Fill in the context record fields */
*tiff_xwc = ilCreateXWC (IlContext, dpy, visual, colormap, gc, 0, 0);
if (*tiff_xwc == NULL)
{
_DtHelpProcessUnlock();
return(_DtGrCONVERT_FAILURE);
}
context->image_type = XtNewString("TIFF");
}
inFile = ilConnectFile (IlContext, stream, 0, 0);
if (inFile)
{
inImage = ilListFileImages (inFile, 0);
if (inImage)
{
int image_resolution = 100 ; /* assume that if not in file */
if (inImage->xRes != 0) {
image_resolution = inImage->xRes ; /* dpi from the file */
}
if (*in_out_width == 0 && *in_out_height == 0)
ratio = ComputeRatio(media_resolution, image_resolution);
*in_out_width = inImage->width * ratio + 0.5;
*in_out_height = inImage->height * ratio + 0.5;
if (*in_out_width == 0)
*in_out_width = 1;
if (*in_out_height == 0)
*in_out_height = 1;
pixmap = XCreatePixmap (dpy, drawable, (*in_out_width),
(*in_out_height), depth);
if (pixmap)
{
inPipe = ilCreatePipe (IlContext, 0);
if (inPipe)
{
if (color_model == _DtGrGRAY_SCALE)
inDes = IL_DES_GRAY;
else if (color_model == _DtGrBITONAL)
inDes = IL_DES_BITONAL;
result = 0;
if (!ilReadFileImage (inPipe, inImage, (ilRect *) NULL, 0))
result = -1;
if (result == 0 && color_model != _DtGrCOLOR &&
ilConvert (inPipe, inDes, ((ilImageFormat *) NULL), 0, NULL) != True)
result = -1;
if (result == 0 &&
ilWriteXDrawable (inPipe, pixmap, *tiff_xwc,
(ilRect *) NULL, 0, 0, 0))
{
ilExecutePipe (inPipe, 0, ratio);
if (IlContext->error != 0)
result = -1;
}
ilDestroyObject (inPipe);
}
if (result == -1)
{
XFreePixmap (dpy, pixmap);
pixmap = 0;
}
}
}
ilDestroyObject (inFile);
}
*ret_pixmap = pixmap;
if (result < 0)
{
if ((IlContext->error == IL_ERROR_FILE_IO) ||
(IlContext->error == IL_ERROR_FILE_NOT_TIFF))
{
_DtHelpProcessUnlock();
return(_DtGrFILE_INVALID);
}
else if (IlContext->error == IL_ERROR_MALLOC)
{
_DtHelpProcessUnlock();
return(_DtGrNO_MEMORY);
}
else
{
_DtHelpProcessUnlock();
return(_DtGrCONVERT_FAILURE);
}
}
else
{
_DtHelpProcessUnlock();
return(_DtGrSUCCESS);
}
}
#endif
/***********
*
* Function processXwd
*
* takes a string.
* Make an XWD file into the pixmap for the graphic.
*
***********/
static enum _DtGrLoadStatus processXwd(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context
)
{
Pixmap pixmap;
XWDFileHeader header;
int result;
unsigned long swaptest = TRUE;
Display *dpy = DisplayOfScreen(screen);
Drawable drawable = RootWindowOfScreen(screen);
int screen_num = XScreenNumberOfScreen(screen);
float ratio = 1.0;
if (media_resolution == 0)
return(_DtGrCONVERT_FAILURE);
if (stream->type == _DtGrNONE)
return(_DtGrCONVERT_FAILURE);
/* Read in XWDFileHeader structure */
result = _DtGrRead((char *)&header, sizeof(header), 1, stream);
if (result == 1 && *(char *) &swaptest)
_swaplong((char *) &header, sizeof(header));
if (result != 1 || header.file_version != XWD_FILE_VERSION)
return (_DtGrFILE_INVALID);
if (*in_out_width == 0 && *in_out_height == 0)
ratio = ComputeRatio(media_resolution, 100);
*in_out_width = header.pixmap_width * ratio + 0.5;
*in_out_height = header.pixmap_height * ratio + 0.5;
if (*in_out_width == 0)
*in_out_width = 1;
if (*in_out_height == 0)
*in_out_height = 1;
pixmap = XCreatePixmap (dpy, drawable, (*in_out_width),
(*in_out_height),depth);
if (pixmap) {
if ((result=XwdFileToPixmap (dpy, screen_num, depth, pixmap, colormap,
visual, gc, color_model, 0, 0, 0, 0,
(*in_out_width), (*in_out_height), stream,
ret_colors, ret_num_colors))
== GR_SUCCESS) {
*ret_pixmap = pixmap;
return (_DtGrSUCCESS);
}
else if (result == GR_HEADER_ERR)
return (_DtGrFILE_INVALID);
else if (result == GR_FILE_ERR)
return (_DtGrFILE_INVALID);
else if (result == GR_ALLOC_ERR)
return (_DtGrNO_MEMORY);
else
return (_DtGrCONVERT_FAILURE);
}
else
return (_DtGrNO_MEMORY);
}
/************************************
* myXpmReadFileToPixmap
***********************************/
static int
myXpmReadFileToPixmap(
Display *display,
Screen *screen,
Drawable d,
_DtGrStream *stream,
Pixmap *pixmap_return,
Pixmap *shapemask_return,
XpmAttributes *attributes,
GC gc,
Pixel bg,
Pixel fg,
int depth,
float ratio
)
{
XImage *image = NULL;
XImage **imageptr = 0;
XImage *shapeimage, **shapeimageptr = NULL;
int ErrorStatus;
int switchFlag = 0;
int scaledWidth, scaledHeight;
/*
* initialize return values
*/
if (pixmap_return) {
*pixmap_return = 0;
imageptr = &image;
}
if (shapemask_return) {
*shapemask_return = 0;
shapeimageptr = &shapeimage;
}
/*
* create the images
*/
if (stream->type == _DtGrFILE)
{
if (stream->source.file.uncompressed_filename != NULL)
ErrorStatus = _DtXpmReadFileToImage(display,
stream->source.file.uncompressed_filename,
imageptr, shapeimageptr, attributes);
else
ErrorStatus = _DtXpmReadFileToImage(display,
stream->source.file.filename,
imageptr, shapeimageptr, attributes);
}
else if (stream->type == _DtGrBUFFER)
{
ErrorStatus = XpmCreateImageFromBuffer(display,
(char *) stream->source.buffer.base,
imageptr, shapeimageptr, attributes);
}
else
ErrorStatus = XpmFileInvalid; /* stream type of _DtGrNONE */
if (ErrorStatus < 0)
return (ErrorStatus);
/*
* Check to see if we will need to switch the foreground and
* background colors. When forced to a depth of 1, the Xpm call
* returns a ZPixmap ready to place in pixmap of depth 1.
* Unfortunately, usually the pixmap is of a different depth. This
* causes a depth mismatch for the XPutImage. Therefore, we change
* the format type to XYBitmap and XPutImage is happy. But on
* servers where BlackPixel is not at pixel 1 in the colormap, this
* causes the image to be inverted. So by switching the foreground
* and background in the gc, the image is corrected for these
* systems.
*
* The other way of doing this, is to create a pixmap of depth 1 and
* do an XPutImage to it. Then do a XCopyPlane to a pixmap of the
* correct depth. But this is a major performance hit compared to
* switching the colors.
*
* The downside of switching colors is that it works only when
* BlackPixel and WhitePixel fill colormap entries 0 and 1. But
* since this is the 99.9% case, we'll go with it.
*/
if (image->depth == 1 && BlackPixelOfScreen(screen) != 1L)
switchFlag = 1;
/*
* create the pixmaps
*/
if (imageptr && image) {
scaledWidth = image->width * ratio + 0.5;
scaledHeight = image->height * ratio + 0.5;
if (scaledWidth == 0)
scaledWidth = 1;
if (scaledHeight == 0)
scaledHeight = 1;
*pixmap_return = XCreatePixmap(display, d, scaledWidth,
scaledHeight, depth);
if (image->depth == 1)
image->format = XYBitmap;
if (switchFlag)
{
XSetBackground (display, gc, fg);
XSetForeground (display, gc, bg);
}
_XmPutScaledImage(display, *pixmap_return, gc, image,
0, 0, 0, 0,
image->width, image->height,
scaledWidth, scaledHeight);
if (switchFlag)
{
XSetBackground (display, gc, bg);
XSetForeground (display, gc, fg);
}
XDestroyImage(image);
}
if (shapeimageptr && shapeimage)
XDestroyImage(shapeimage);
return (ErrorStatus);
}
static XpmColorSymbol colorSymbol = {"none", NULL, 0};
/***********
*
* Function processXpm
*
* takes a string.
* Make an XPM file into the pixmap for the graphic.
*
***********/
static enum _DtGrLoadStatus processXpm(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context
)
{
int i, j;
int result;
short done;
XpmAttributes xpmAttr;
Visual vis2;
float ratio = 1.0;
enum _DtGrLoadStatus status = _DtGrSUCCESS;
if (media_resolution == 0)
return(_DtGrCONVERT_FAILURE);
if (stream->type == _DtGrNONE)
return(_DtGrCONVERT_FAILURE); /* stream type of _DtGrNONE */
_DtHelpProcessLock();
do
{
colorSymbol.pixel = background;
xpmAttr.valuemask = XpmVisual | XpmReturnPixels |
XpmColorSymbols | XpmColormap | XpmDepth;
xpmAttr.visual = visual;
xpmAttr.colorsymbols = &colorSymbol;
xpmAttr.colormap = colormap;
xpmAttr.numsymbols = 1;
xpmAttr.depth = depth;
xpmAttr.pixels = NULL;
/*
* If not color, force to black and white.
*/
if (color_model != _DtGrCOLOR)
{
memcpy (&vis2, xpmAttr.visual, sizeof(Visual));
vis2.class = StaticGray;
vis2.map_entries = 2;
xpmAttr.depth = 1;
xpmAttr.visual = &vis2;
}
if (*in_out_width == 0 && *in_out_height == 0)
ratio = ComputeRatio(media_resolution, 100);
result = myXpmReadFileToPixmap (DisplayOfScreen(screen),
screen,
RootWindowOfScreen(screen),
stream, ret_pixmap,
ret_mask, &xpmAttr, gc,
background, foreground, depth,
ratio);
done = True;
/*
* if we did not successfully get our icon, force the color
* to black and white.
*/
if (result == XpmColorFailed && color_model != _DtGrBITONAL)
{
if (allow_reduced_colors)
{
color_model = _DtGrBITONAL;
status = _DtGrCOLOR_REDUCE;
done = False;
}
else
status = _DtGrCOLOR_FAILED;
}
} while (done == False);
if (result == XpmSuccess || result == XpmColorError)
{
*in_out_width = xpmAttr.width * ratio + 0.5;
*in_out_height = xpmAttr.height * ratio + 0.5;
if (*in_out_width == 0)
*in_out_width = 1;
if (*in_out_height == 0)
*in_out_height = 1;
*ret_colors = xpmAttr.pixels;
*ret_num_colors = xpmAttr.npixels;
/*
* squeeze out the pixel used for the transparent color since we
* don't want to free it when we free the other colors
*/
i = 0;
while (i < xpmAttr.npixels && xpmAttr.pixels[i] != colorSymbol.pixel)
i++;
if (i < xpmAttr.npixels)
{
for (j = i, i = i + 1; i < xpmAttr.npixels; i++, j++)
xpmAttr.pixels[j] = xpmAttr.pixels[i];
*ret_num_colors = j;
}
}
_DtHelpProcessUnlock();
if (result == XpmOpenFailed)
status = _DtGrOPEN_FAILED;
else if (result == XpmFileInvalid)
status = _DtGrFILE_INVALID;
else if (result == XpmNoMemory)
status = _DtGrNO_MEMORY;
else if (result == XpmColorFailed)
status = _DtGrCOLOR_FAILED;
return(status);
}
/******************************************************************************
*
* Function processGIF
*
* Default gif converter, creates a pixmap from a file-associated or
* buffer-associated stream of gif data.
*
*****************************************************************************/
static enum _DtGrLoadStatus processGIF(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context
)
{
struct stat stbuf;
char *buffer;
GifObj g;
enum _DtGrLoadStatus status;
Display *display = DisplayOfScreen(screen);
Drawable drawable = RootWindowOfScreen(screen);
int i, size=0;
float ratio = 1.0;
if (media_resolution == 0)
return(_DtGrCONVERT_FAILURE);
if (stream->type == _DtGrNONE)
return(_DtGrCONVERT_FAILURE); /* stream type of _DtGrNONE */
*ret_pixmap = 0; /* Initialize the return pixmap to zero */
/*
** The gif-to-pixmap utilities operate only on in-memory buffers,
** so if this is a buffer-based stream, simply pass the buffer, and
** if this is a file-based stream, read the file contents into a buffer
** and pass that.
*/
if (stream->type == _DtGrBUFFER)
{
buffer = (char *) stream->source.buffer.base;
size = stream->source.buffer.size;
}
else
{
if (stream->source.file.uncompressed_filename != NULL)
stat (stream->source.file.uncompressed_filename, &stbuf);
else
stat (stream->source.file.filename, &stbuf);
size = stbuf.st_size;
buffer = XtMalloc(size);
fread (buffer, 1, size, stream->source.file.fileptr);
}
/* Initialize the gif object */
status = InitGifObject (&g, display, drawable, screen, depth, colormap,
visual, gc, color_model, allow_reduced_colors);
if (*in_out_width == 0 && *in_out_height == 0)
ratio = ComputeRatio(media_resolution, 100);
/* Create an X pixmap from the gif object */
if ((status == _DtGrSUCCESS) || (status == _DtGrCOLOR_REDUCE))
*ret_pixmap = gif_to_pixmap (&g, (unsigned char *) buffer, size,
in_out_width, in_out_height,
g.f_black, g.f_white, ratio);
/* Set the returned colors parameters */
if (*ret_pixmap != 0)
{
if (g.f_do_visual == DO_COLOR)
{
*ret_num_colors = g.total_colors;
*ret_colors = (Pixel *) malloc(*ret_num_colors * sizeof(Pixel));
for (i=0; i<*ret_num_colors; i++)
(*ret_colors)[i] = g.GifCMap[i].pixel;
}
else /* DO_GREY */
{
*ret_num_colors = g.f_total_greys;
*ret_colors = (Pixel *) malloc(*ret_num_colors * sizeof(Pixel));
for (i=0; i<*ret_num_colors; i++)
(*ret_colors)[i] = g.GifGMap[i];
}
}
/* Free up any resources associated with the gif object */
DeleteGifObjectResources (&g);
/* If we allocated a buffer, free it */
if (stream->type == _DtGrFILE)
XtFree(buffer);
/* Return the status */
return (status);
}
/******************************************************************************
*
* Function processJPEG
*
* Default jpeg converter, creates a pixmap from a file-associated or
* buffer-associated stream of jpeg data.
*
* The function first converts the jpeg stream to an XImage with a virtual
* colormap using the jpeg_to_ximage call, then generates a new XImage that
* uses the X colormap by calling the Do_Pseudo routine. The Do_Pseudo
* routine, which is also used by the XWD converter, automatically handles X
* color allocation and color model degradation where necessary. Finally,
* a pixmap is generated from the XImage returned by Do_Pseudo.
*
*****************************************************************************/
static enum _DtGrLoadStatus processJPEG(
_DtGrStream *stream,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context
)
{
enum _DtGrLoadStatus status;
XImage *in_image, *out_image;
XColor *colors;
int ncolors;
int xres;
int result = GR_SUCCESS;
Display *dpy = DisplayOfScreen(screen);
int screen_num = XScreenNumberOfScreen(screen);
Drawable drawable = RootWindowOfScreen(screen);
float ratio = 1.0;
unsigned int scaledWidth,scaledHeight;
if (media_resolution == 0)
return(_DtGrCONVERT_FAILURE);
if (*in_out_width == 0 && *in_out_height == 0)
ratio = 0.0;
if (stream->type == _DtGrNONE)
return(_DtGrCONVERT_FAILURE); /* stream type of _DtGrNONE */
/*
** Convert the stream to an XImage with a virtual colormap
*/
status = jpeg_to_ximage (stream, screen, visual, in_out_width,
in_out_height, &in_image, &colors, &ncolors,
&xres);
if (ratio == 0.0) {
if (!xres)
xres = 100;
ratio = ComputeRatio(media_resolution, xres);
}
if (status == _DtGrSUCCESS)
{
if (in_image->depth == 1)
{
/*
** Bitmap, no further image transformation necessary
*/
out_image = in_image;
result = GR_SUCCESS;
}
else
{
/*
** Create an output image and have Do_Pseudo allocate the needed
** pixels and store image data that uses these pixels into
** the output image.
*/
out_image = XCreateImage(dpy, visual, depth,
(depth == 1) ? XYBitmap : in_image->format,
in_image->xoffset, NULL,
in_image->width, in_image->height,
XBitmapPad(dpy), 0);
out_image->data = (char *) malloc(Image_Size(out_image));
result = Do_Pseudo(dpy, screen_num, colormap, ncolors, colors,
color_model, in_image, out_image,
ret_colors, ret_num_colors);
}
/*
** If we've got a good XImage, go ahead and make a pixmap out of it
*/
if (result != GR_ALLOC_ERR)
{
/*
** Create a pixmap the same size as the XImage
*/
scaledWidth = out_image->width * ratio + 0.5;
scaledHeight = out_image->height * ratio + 0.5;
if (scaledWidth == 0)
scaledWidth = 1;
if (scaledHeight == 0)
scaledHeight = 1;
*ret_pixmap = XCreatePixmap (dpy, drawable, scaledWidth,
scaledHeight, depth);
if (*ret_pixmap)
{
/*
** Copy the XImage into the pixmap and set the other
** return parameters.
*/
_XmPutScaledImage(dpy, *ret_pixmap, gc, out_image, 0, 0, 0, 0,
out_image->width, out_image->height,
scaledWidth, scaledHeight);
*in_out_width = scaledWidth;
*in_out_height = scaledHeight;
status = _DtGrSUCCESS;
}
else
status = _DtGrNO_MEMORY;
if (out_image != in_image)
XDestroyImage (out_image);
}
else
status = _DtGrNO_MEMORY;
/*
** Free the colors array and the initial XImage
*/
XFree ((char *) colors);
XDestroyImage (in_image);
}
return (status);
}
/******************************************************************************
*
* Function destroyTiffContext
*
* Default tiff context destructor, destroys the ilXWC object pointed to
* by context->context and frees the context->image_type string.
*
*****************************************************************************/
static void destroyTiffContext(
_DtGrContext *context)
{
if (context != NULL)
{
if (context->context != NULL)
{
_DtHelpProcessLock();
ilDestroyObject ((ilObject) context->context);
_DtHelpProcessUnlock();
}
if (context->image_type != NULL)
XtFree(context->image_type);
}
}
/******************************************************************************
*
* Function DetermineImageType
*
* Determines the image type of the specified stream and copies the
* string representing that image type into the image_type buffer.
*
* If the stream is a buffer, the buffer is passed to DtDtsBufferToData
* in hopes that the file might be identified through content criteria.
*
* If the stream is a file, the following checks are made:
*
* 1. The file name extension is checked against a list of known image file
* type extensions.
* 2. The filename is passed to DtDtsFileToDataType in hopes that the file
* type might be identified through filename extension or content
* criteria.
* 3. If the file was uncompressed into a temporary file, the temporary
* filename is passed to DtDtsFileToDataType in hopes that the file
* type might be identified through content criteria.
*
* If none of these checks are successful, _DtCONVERT_FAILURE is returned.
* Otherwise, _DtGrSUCCESS is returned.
*
*****************************************************************************/
static enum _DtGrLoadStatus DetermineImageType(
_DtGrStream *stream,
char *image_type)
{
int i=0;
char *ext;
if (stream->type == _DtGrFILE)
{
/* First try to match the file name extension to a known mapping */
if (stream->source.file.filename != NULL)
{
/* Get the filename extension */
if (_DtHelpCeStrrchr(stream->source.file.filename, ".",
MB_CUR_MAX, &ext) == 0)
{
ext++; /* Increment past the dot */
while (img_extensions[i] != NULL)
{
if (strcmp(ext, img_extensions[i]) == 0)
{
/* Found a match */
strcpy (image_type,img_extensions[++i]);
return (_DtGrSUCCESS);
}
/* Skip two ahead to the next file extension name */
i += 2;
}
}
}
/*
* Didn't work, see if CDE datatyping can determine the image type.
* First try the filename, then try the uncompressed temporary
* filename, if it exists.
*/
if ((ext = DtDtsFileToDataType(stream->source.file.filename)) == NULL)
if (stream->source.file.uncompressed_filename != NULL)
ext = DtDtsFileToDataType(
stream->source.file.uncompressed_filename);
/* If successful, save the image type and return */
if (ext != NULL)
{
strcpy (image_type, ext);
DtDtsFreeDataType(ext);
return (_DtGrSUCCESS);
}
}
else if (stream->type == _DtGrBUFFER)
{
/* See if the CDE datatyping mechanism can determine the image type */
ext = DtDtsBufferToDataType (stream->source.buffer.base,
stream->source.buffer.size,
NULL);
/* If successful, save the image type and return */
if (ext != NULL)
{
strcpy (image_type, ext);
DtDtsFreeDataType(ext);
return (_DtGrSUCCESS);
}
}
/* Couldn't figure out the type, return failure */
return (_DtGrCONVERT_FAILURE);
}
/******************************************************************************
*
* Function GetConverterAndDestructor
*
* This function returns the converter and context destructor functions for
* the specified image type. The registry of default image types is searched
* first, followed by the registry of new image types, until a match is made.
* The function returns _DtGrSUCCESS if the image_type has been registered
* and _DtGrCONVERT_FAILURE if it has not.
*
*****************************************************************************/
static enum _DtGrLoadStatus GetConverterAndDestructor(
char *image_type,
_DtGrLoadProc *converter,
_DtGrDestroyContextProc *destructor)
{
int i;
/* No image_type string, return failure */
if (image_type == NULL)
return (_DtGrCONVERT_FAILURE);
/* Search the default image type registry for the specified image type */
_DtHelpProcessLock();
for (i=0; i<registry_count; i++)
{
if (strcmp (registry[i].image_type, image_type) == 0)
{
/* Found it, return the converter and destructor */
*converter = registry[i].convert_proc;
*destructor = registry[i].destroy_context_proc;
_DtHelpProcessUnlock();
return (_DtGrSUCCESS);
}
}
/* Search the new image type registry for the specified image type */
for (i=0; i<new_registry_count; i++)
{
if (strcmp (new_registry[i].image_type, image_type) == 0)
{
/* Found it, return the converter */
*converter = new_registry[i].convert_proc;
*destructor = registry[i].destroy_context_proc;
_DtHelpProcessUnlock();
return (_DtGrSUCCESS);
}
}
_DtHelpProcessUnlock();
/* Image type wasn't registered, return failure */
return (_DtGrCONVERT_FAILURE);
}
/******************************************************************************
*
* Public Functions
*
*****************************************************************************/
/******************************************************************************
*
* Function _DtHelpProcessGraphic
*
* takes a string.
* Get the pixmap for the graphic.
*
*****************************************************************************/
Pixmap
_DtHelpProcessGraphic(
Display *dpy,
Drawable drawable,
int screen,
int depth,
GC gc,
Pixmap *def_pix,
Dimension *def_pix_width,
Dimension *def_pix_height,
_DtGrContext *context,
Colormap colormap,
Visual *visual,
Pixel fore_ground,
Pixel back_ground,
char *filename,
unsigned short media_resolution,
Dimension *width,
Dimension *height,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_number )
{
unsigned int pixWidth = 0;
unsigned int pixHeight = 0;
Dimension pWidth, pHeight;
Pixmap pix = 0, mask = 0;
_DtGrStream stream;
Screen *scrptr = ScreenOfDisplay (dpy, screen);
static enum _DtGrColorModel ForceColor = _DtGrCOLOR;
static Boolean first_time = TRUE;
/*
* initialize the return values
*/
*ret_colors = NULL;
*ret_number = 0;
*ret_mask = None;
/*
* Initialize the Force Variable if this is the first time
*/
_DtHelpProcessLock();
if (first_time)
{
char *ptr;
char *ptr2;
char *xrmName = NULL;
char *xrmClass = NULL;
char *retStrType;
XrmValue retValue;
ForceColor = _DtGrCOLOR;
XtGetApplicationNameAndClass (dpy, &ptr, &ptr2);
xrmName = malloc (strlen (ptr) + 14);
xrmClass = malloc (strlen (ptr2) + 14);
if (xrmName && xrmClass)
{
strcpy (xrmName , ptr);
strcat (xrmName , ".helpColorUse");
strcpy (xrmClass, ptr2);
strcat (xrmClass, ".HelpColorUse");
if (XrmGetResource (XtDatabase (dpy), xrmName, xrmClass,
&retStrType, &retValue) == True)
{
ptr = (char *) retValue.addr;
/*
* check for GreyScale
*/
if (*ptr == 'G' || *ptr == 'g')
ForceColor = _DtGrGRAY_SCALE;
/*
* check for BlackWhite
*/
else if (*ptr == 'B' || *ptr == 'b')
ForceColor = _DtGrBITONAL;
}
}
free (xrmName);
free (xrmClass);
/*
* choose the correct visual type to use
*/
if (ForceColor == _DtGrCOLOR &&
(visual->class == GrayScale || visual->class == StaticGray))
ForceColor = _DtGrGRAY_SCALE;
if (ForceColor != _DtGrBITONAL && depth == 1)
ForceColor = _DtGrBITONAL;
first_time = FALSE;
}
_DtHelpProcessUnlock();
if (filename != NULL)
{
int result;
/* Open the file and associate with a stream */
result = _DtGrOpenFile(&stream, filename);
if (result != 0)
pix = 0;
else
{
/* Create a pixmap from the image data stream */
_DtGrLoad(&stream, NULL, scrptr, depth, colormap, visual,
fore_ground, back_ground, gc, ForceColor, TRUE, &pWidth,
&pHeight, media_resolution, &pix, &mask, ret_colors,
ret_number, context);
pixWidth = pWidth;
pixHeight = pHeight;
/* Close the stream and the file associated with it */
_DtGrCloseStream( &stream );
}
}
if (pix == 0)
{
/*
* Try to get a localized pixmap
* NOTE....
* This is a cached pixmap.....
* Make sure XFreePixmaps does not free this one.
*/
if (*def_pix == 0)
{
*def_pix = XmGetPixmap(scrptr, "Dthgraphic", fore_ground, back_ground);
if (*def_pix != XmUNSPECIFIED_PIXMAP)
{
Window root_id;
int x, y;
unsigned int border;
unsigned int depth;
if (XGetGeometry(dpy, *def_pix, &root_id, &x, &y,
&pixWidth, &pixHeight, &border, &depth) == 0)
{
XmDestroyPixmap(scrptr, *def_pix);
*def_pix = 0;
}
}
else
*def_pix = 0;
/*
* couldn't get a localized pixmap, go with a build in default
*/
if (*def_pix == 0)
{
pixWidth = Missing_bm_width;
pixHeight = Missing_bm_height;
*def_pix = XCreatePixmapFromBitmapData ( dpy, drawable,
(char *) Missing_bm_bits,
pixWidth, pixHeight,
fore_ground, back_ground, depth);
}
*def_pix_width = (Dimension) pixWidth;
*def_pix_height = (Dimension) pixHeight;
}
pix = *def_pix;
pixWidth = *def_pix_width;
pixHeight = *def_pix_height;
}
*width = (Dimension) pixWidth;
*height = (Dimension) pixHeight;
return pix;
}
/******************************************************************************
*
* Function _DtGrLoad
*
* Determines the image type of the specified stream and calls the appropriate
* imagetype-to-pixmap converter function. If the conversion is successful
* and the caller passed the address of a pointer to NULL in the image_type
* parameter, a copy of the image type string is allocated and stored at this
* address. The caller is responsible for freeing this string. The caller
* is also responsible for freeing the values passed back in the ret_pixmap,
* ret_mask, ret_colors, and context parameters. The _DtGrLoad function
* returns _DtGrCONVERT_FAILURE if the appropriate converter could not be
* determined, otherwise it returns the value returned by the converter.
*
*****************************************************************************/
enum _DtGrLoadStatus _DtGrLoad(
_DtGrStream *stream,
char **image_type,
Screen *screen,
int depth,
Colormap colormap,
Visual *visual,
Pixel foreground,
Pixel background,
GC gc,
enum _DtGrColorModel color_model,
Boolean allow_reduced_colors,
Dimension *in_out_width,
Dimension *in_out_height,
unsigned short media_resolution,
Pixmap *ret_pixmap,
Pixmap *ret_mask,
Pixel **ret_colors,
int *ret_num_colors,
_DtGrContext *context
)
{
enum _DtGrLoadStatus status;
_DtGrLoadProc converter;
_DtGrDestroyContextProc destructor;
char buf[20],*itype;
/* Determine the image type */
if ((image_type != NULL) && (*image_type != NULL))
itype = *image_type; /* Caller specified image type */
else
{
/* Image type not specified by caller, try to figure it out */
if ((status = DetermineImageType(stream, buf)) != _DtGrSUCCESS)
return (status); /* Return failure if image type is unknown */
itype = &buf[0];
}
/* Look up the proper converter for this image type */
if ((status=GetConverterAndDestructor(itype, &converter, &destructor)) ==
_DtGrSUCCESS)
{
/* Call the converter */
if (converter != NULL)
{
status = (*converter)(stream, screen, depth, colormap, visual,
foreground, background, gc, color_model,
allow_reduced_colors, in_out_width,
in_out_height, media_resolution, ret_pixmap,
ret_mask, ret_colors, ret_num_colors,
context);
}
else
status = _DtGrCONVERT_FAILURE;
}
/* Return a copy of the image type string if successful */
if (status == _DtGrSUCCESS || status == _DtGrCOLOR_REDUCE)
if ((image_type != NULL) && (*image_type == NULL) && (itype != NULL))
*image_type = XtNewString(itype);
/* Return the conversion status */
return (status);
}
/******************************************************************************
*
* Function _DtGrDestroyContext
*
* Obtains and calls the context destructor function for the image type
* indicated by the context parameter.
*
*****************************************************************************/
void _DtGrDestroyContext(
_DtGrContext *context)
{
_DtGrLoadProc converter;
_DtGrDestroyContextProc destructor;
if (GetConverterAndDestructor(context->image_type, &converter,
&destructor) == _DtGrSUCCESS)
{
if (destructor != NULL)
(*destructor)(context);
}
}
/******************************************************************************
*
* Function _DtGrRegisterConverter
*
* Registers a converter and context destructor function for the specified
* image type. If the image_type has not been registered, a new record for
* it is created in the new image type registry. If the image_type has been
* registered, the current converter and context destructor functions are
* replaced by those specified by the caller. If the caller passes valid
* addresses in the current_convert_proc and current_destroy_proc parameters,
* the current converter and context destructor functions will be saved there
* first so that the caller may restore them at a later time.
*
*****************************************************************************/
void _DtGrRegisterConverter(
char *image_type,
_DtGrLoadProc convert_proc,
_DtGrDestroyContextProc destroy_context_proc,
_DtGrLoadProc *current_convert_proc,
_DtGrDestroyContextProc *current_destroy_proc)
{
int i;
if (image_type == NULL)
return;
/* Search the default converter registry for the specified image type */
_DtHelpProcessLock();
for (i=0; i<registry_count; i++)
{
if (strcmp (registry[i].image_type, image_type) == 0)
{
/* Found it, save the current procs, then replace them */
/* with the new ones and return */
if (current_convert_proc != NULL)
*current_convert_proc = registry[i].convert_proc;
if (current_destroy_proc != NULL)
*current_destroy_proc = registry[i].destroy_context_proc;
registry[i].convert_proc = convert_proc;
registry[i].destroy_context_proc = destroy_context_proc;
_DtHelpProcessUnlock();
return;
}
}
/* Search the new converter registry for the specified image type */
for (i=0; i<new_registry_count; i++)
{
if (strcmp (new_registry[i].image_type, image_type) == 0)
{
/* Found it, save the current procs, then replace them */
/* with the new ones and return */
if (current_convert_proc != NULL)
*current_convert_proc = new_registry[i].convert_proc;
if (current_destroy_proc != NULL)
*current_destroy_proc = new_registry[i].destroy_context_proc;
new_registry[i].convert_proc = convert_proc;
new_registry[i].destroy_context_proc = destroy_context_proc;
_DtHelpProcessUnlock();
return;
}
}
/* If we make it here, we've got a new image type to register */
new_registry = (_DtGrRegistryRec *) XtRealloc ((char *) new_registry,
sizeof(_DtGrRegistryRec) * (new_registry_count + 1));
new_registry[new_registry_count].image_type = XtNewString (image_type);
new_registry[new_registry_count].convert_proc = convert_proc;
new_registry[new_registry_count].destroy_context_proc =
destroy_context_proc;
new_registry_count++;
_DtHelpProcessUnlock();
/* Newly registered type, so return NULL for current function params */
if (current_convert_proc != NULL)
*current_convert_proc = NULL;
if (current_destroy_proc != NULL)
*current_destroy_proc = NULL;
return;
}
/******************************************************************************
*
* Input stream functions
*
* These functions allow the creation and manipulation of a stream that
* can be associated with either a file or a buffer. They are intended to
* be used by image data to pixmap converter functions that need to handle
* both image files and in-memory buffers containing file data.
*
*****************************************************************************/
/******************************************************************************
*
* Function _DtGrOpenFile
*
* Opens a file for reading and associates it with the specified stream. If
* the file is compressed, the function uncompresses it prior to opening.
* Returns 0 for success, -1 or the value of errno as set by fopen for
* failure.
*
*****************************************************************************/
int _DtGrOpenFile(
_DtGrStream *stream,
char *path)
{
char *fname = NULL;
if (stream == NULL)
return (-1); /* Failure */
/* Uncompress the file if necessary and obtain the new filename */
if (_DtHelpCeGetUncompressedFileName(path, &fname) == -1)
{
stream->type = _DtGrNONE;
return (-1); /* Failure */
}
/* Open the file */
stream->source.file.fileptr = fopen(fname,"r");
if (stream->source.file.fileptr == NULL)
{
/* Failure, couldn't open the file */
stream->type = _DtGrNONE;
if ((fname != path) && (fname != NULL))
{
unlink (fname);
free (fname);
}
return(errno);
}
/* Set the stream type and copy the filename */
stream->type = _DtGrFILE;
stream->source.file.filename = XtNewString(path);
/* If the file was uncompressed and renamed, save the new name */
if (fname == path)
stream->source.file.uncompressed_filename = NULL;
else
stream->source.file.uncompressed_filename = fname;
return(0); /* Success */
}
/******************************************************************************
*
* Function _DtGrOpenBuffer
*
* Associates the specified in-memory buffer with the specified stream.
* The function returns 0 for success and the EINVAL error code for failure.
*
*****************************************************************************/
int _DtGrOpenBuffer(
_DtGrStream *stream,
const char *buffer,
int buffer_size)
{
if ((stream == NULL) || (buffer == NULL) || (buffer_size < 0))
{
if (stream != NULL)
stream->type = _DtGrNONE;
return(EINVAL); /* Failure */
}
/* Set the appropriate stream fields */
stream->type = _DtGrBUFFER;
stream->source.buffer.base = buffer;
stream->source.buffer.size = buffer_size;
stream->source.buffer.current = (char *)buffer;
stream->source.buffer.end = (char *)(buffer + buffer_size - 1);
return(0); /* Success */
}
/******************************************************************************
*
* Function _DtGrCloseStream
*
* The function closes the specified stream by setting the stream type to
* _DtGrNONE. If the stream is associated with a file, then the file is
* closed and the filename in the stream structure is freed. If the file
* required decompression, then the uncompressed file is unlinked and the
* uncompressed filename is freed.
*
*****************************************************************************/
int _DtGrCloseStream(
_DtGrStream *stream)
{
int status;
if ((stream == NULL) || (stream->type == _DtGrNONE))
return(EOF); /* Failure */
if (stream->type == _DtGrFILE)
{
/* Close the file and free the filename */
status = fclose(stream->source.file.fileptr);
if (stream->source.file.filename != NULL)
XtFree(stream->source.file.filename);
if (stream->source.file.uncompressed_filename != NULL)
{
/* Unlink the uncompressed file and free the filename */
unlink(stream->source.file.uncompressed_filename);
free(stream->source.file.uncompressed_filename);
}
}
else if (stream->type == _DtGrBUFFER)
{
status = 0; /* Success */
}
stream->type = _DtGrNONE;
return (status);
}
/******************************************************************************
*
* Function _DtGrRead
*
* Stream version of fread, reads data from a stream into a buffer. If the
* stream is file-associated, a call to fread is made. If the stream is
* buffer-associated, an analogous operation is performed on the stream
* buffer. The number of items read from the stream is returned to the caller.
*
*****************************************************************************/
size_t _DtGrRead(
void *buffer,
size_t size,
size_t num_items,
_DtGrStream *stream)
{
unsigned nleft;
int n;
if ((stream == NULL) || (stream->type == _DtGrNONE))
return(0);
if (stream->type == _DtGrFILE)
{
return (fread(buffer, size, num_items, stream->source.file.fileptr));
}
else if (stream->type == _DtGrBUFFER)
{
/* This code mirrors that of fread in libc */
if (size <= 0 || num_items <= 0)
return (0);
for (nleft = num_items * size; ; )
{
if (stream->source.buffer.current > stream->source.buffer.end)
{
/* past end of stream */
if (stream->source.buffer.current ==
stream->source.buffer.end + 1)
return (num_items - (nleft + size - 1)/size);
stream->source.buffer.current--;
}
n = (nleft < stream->source.buffer.end -
stream->source.buffer.current + 1 ? nleft :
stream->source.buffer.end -
stream->source.buffer.current + 1);
/* Copy the items into the caller-supplied buffer */
buffer = (char *)memcpy(buffer,
(void *) stream->source.buffer.current,
(size_t)n) + n;
stream->source.buffer.current += n;
if ((nleft -= n) == 0)
return (num_items);
}
}
}
/******************************************************************************
*
* Function _DtGrSeek
*
* Stream version of fseek, repositions the file or buffer pointer of a
* stream. If the stream is file-associated, the return value is the value
* returned by fseek. If the stream is buffer-associated, 0 is returned if
* the requested position is inside the buffer, -1 if it is not.
*
*****************************************************************************/
int _DtGrSeek(
_DtGrStream *stream,
long offset,
int whence)
{
long newpos;
if ((stream == NULL) || (stream->type == _DtGrNONE))
return(-1); /* Failure */
if (stream->type == _DtGrFILE)
{
return (fseek(stream->source.file.fileptr,offset,whence));
}
else if (stream->type == _DtGrBUFFER)
{
switch (whence)
{
case SEEK_SET:
newpos = (long)stream->source.buffer.base + offset;
break;
case SEEK_CUR:
newpos = (long)stream->source.buffer.current + offset;
break;
case SEEK_END:
newpos = (long)stream->source.buffer.end + 1 + offset;
break;
default:
return (-1);
}
if ((newpos >= (long)stream->source.buffer.base) &&
(newpos <= (long)stream->source.buffer.end))
{
/* New position is within buffer, reposition pointer */
stream->source.buffer.current = (char *)newpos;
return(0); /* Success */
}
else
return(-1); /* Failure */
}
}
/******************************************************************************
*
* Function _DtGrGetChar
*
* Stream version of fgetc, reads a character from a stream and advances the
* stream position. The next byte in the stream is returned, or EOF if an
* error occurs or the end of the stream is reached.
*
*****************************************************************************/
int _DtGrGetChar(
_DtGrStream *stream)
{
if ((stream == NULL) || (stream->type == _DtGrNONE))
return(EOF);
if (stream->type == _DtGrFILE)
{
return (fgetc(stream->source.file.fileptr));
}
else if (stream->type == _DtGrBUFFER)
{
if (stream->source.buffer.current > stream->source.buffer.end)
return (EOF);
else
return ((unsigned char) *(stream->source.buffer.current++));
}
}
/******************************************************************************
*
* Function _DtGrGetString
*
* Stream version of fgets, reads a string from a stream and advances the
* stream position. If an error occurs or the end of the stream is
* encountered and no characters have been read, no characters are transferred
* to the buffer and a NULL pointer is returned. Otherwise, the buffer is
* returned.
*
*****************************************************************************/
char *_DtGrGetString(
char *buffer,
int num_bytes,
_DtGrStream *stream)
{
char *p, *save = buffer;
int i;
if ((stream == NULL) || (stream->type == _DtGrNONE))
return(NULL); /* Failure */
if (stream->type == _DtGrFILE)
{
return (fgets(buffer,num_bytes,stream->source.file.fileptr));
}
else if (stream->type == _DtGrBUFFER)
{
/* This code mirrors that of fgets in libc */
for (num_bytes--; num_bytes > 0; num_bytes -= i)
{
if (stream->source.buffer.current > stream->source.buffer.end)
{
if (stream->source.buffer.current ==
stream->source.buffer.end + 1)
{
if (save == buffer)
return (NULL);
break; /* no more data */
}
stream->source.buffer.current--;
}
i = (num_bytes < stream->source.buffer.end -
stream->source.buffer.current + 1 ? num_bytes :
stream->source.buffer.end -
stream->source.buffer.current + 1);
/* Copy the data into the buffer */
if ((p = memccpy((void *)buffer,
(void *)stream->source.buffer.current,
(int)'\n',(size_t)i)) != NULL)
i = p - buffer;
buffer += i;
stream->source.buffer.current += i;
if (p != NULL)
break; /* found '\n' in buffer */
}
*buffer = '\0';
return (save);
}
}