FileUtils.c: fix CERT VU#575804
[oweals/cde.git] / cde / lib / DtHelp / Graphics.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /************************************<+>*************************************
24  ****************************************************************************
25  **
26  **  File:      Graphics.c
27  **
28  **  Project:    CDE Help System
29  **
30  **  Description: This code processes a graphic (X11 bitmap, X11 pixmap,
31  **               X11 XWD file, and TIFF). It will degrade graphics to
32  **               match the type of monitor the image is displayed upon.
33  **
34  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
35  **
36  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
37  **  (c) Copyright 1993, 1994 International Business Machines Corp.
38  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39  **  (c) Copyright 1993, 1994 Novell, Inc.
40  **
41  ****************************************************************************
42  ************************************<+>*************************************/
43 /******************************************************************************
44  **  The GreyScale and Perform_Dither routine were take and modified from
45  **  the g-job 'xgedit' created by Mark F. Cook. The following is the
46  **  disclaimer from the dither.c source code
47  ******************************************************************************
48  **  Program:           xgedit.c
49  **
50  **  Description:       X11-based graphics editor
51  **
52  **  File:              dither.c, containing the following
53  **                     subroutines/functions:
54  **                       Dither_Image()
55  **                       Perform_Dither()
56  **
57  **  Copyright 1988 by Mark F. Cook and Hewlett-Packard, Corvallis
58  **  Workstation Operation.  All rights reserved.
59  **
60  **  Permission to use, copy, and modify this software is granted, provided
61  **  that this copyright appears in all copies and that both this copyright
62  **  and permission notice appear in all supporting documentation, and that
63  **  the name of Mark F. Cook and/or Hewlett-Packard not be used in advertising
64  **  without specific, written prior permission.  Neither Mark F. Cook or
65  **  Hewlett-Packard make any representations about the suitibility of this
66  **  software for any purpose.  It is provided "as is" without express or
67  **  implied warranty.
68  **
69  ******************************************************************************
70  **  CHANGE LOG:
71  **
72  **     1.00.00 - 1/11/89 - Start of Rev. number.
73  **
74  ** @@@ 4.05.00 - 12/07/89 - Created Dither_Image() and Perform_Dither() to
75  ** @@@           allow conversion of color images into a dithered black &
76  ** @@@           white image suitable for output on a laser printer.
77  **
78  ******************************************************************************/
79
80 /*
81 static char rcs_id[]="$XConsortium: Graphics.c /main/23 1996/12/06 11:12:54 cde-hp $";
82 */
83
84 #include <limits.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <malloc.h>
89 #include <errno.h>
90 #include <sys/stat.h>
91 #include <X11/Xlib.h>
92 #include <X11/XWDFile.h>
93 #ifndef STUB
94 #include "il.h"
95 #include "ilfile.h"
96 #include "ilX.h"
97 #include "ilerrors.h"
98 #endif
99 #include <Xm/Xm.h>
100 #include <Dt/Dts.h>
101 #include <Dt/xpm.h>
102
103 #include "GraphicsP.h"
104 #include "GraphicsI.h"
105 #include "StringFuncsI.h"
106 #include "GifUtilsI.h"
107 #include "XbmUtilsI.h"
108 #include "JpegUtilsI.h"
109 #include "Lock.h"
110
111 /*****************************************************************************/
112 /*                    Private data                                           */
113 /*****************************************************************************/
114 #define GR_SUCCESS            0       /* everything okay */
115 #define GR_DRAWABLE_ERR       1       /* couldn't get drawable attr/geom */
116 #define GR_FILE_ERR           2       /* file open/read/write problem */
117 #define GR_REQUEST_ERR        3       /* bad placement or size */
118 #define GR_ALLOC_ERR          4       /* memory allocation failure */
119 #define GR_HEADER_ERR         5       /* file header version/size problem */
120
121 #define MAX_GREY_COLORS         8
122
123 #define RES_TOLERANCE           25      /* resolution scaling tolerance */
124
125 static  short           GreyAllocated = False;
126 static  Pixel           GreyScalePixels[MAX_GREY_COLORS];
127 static  char            *GreyScaleColors[MAX_GREY_COLORS] =
128                         {
129                                 "#212121212121",
130                                 "#424242424242",
131                                 "#636363636363",
132                                 "#737373737373",
133                                 "#949494949494",
134                                 "#adadadadadad",
135                                 "#bdbdbdbdbdbd",
136                                 "#dededededede",
137                         };
138
139 #define Missing_bm_width 75
140 #define Missing_bm_height 47
141 static unsigned char Missing_bm_bits[] = {
142    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
145    0xff, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146    0xff, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
147    0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00,
148    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00,
149    0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x04, 0x01, 0x00, 0x00, 0x00,
150    0x00, 0x00, 0xc0, 0x00, 0x18, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
151    0xc0, 0x00, 0x18, 0x8c, 0x21, 0x00, 0x00, 0x20, 0x00, 0x00, 0xc0, 0x00,
152    0x18, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x24,
153    0x31, 0xf0, 0xf0, 0x30, 0xe8, 0xf0, 0xc1, 0x00, 0x18, 0x04, 0x21, 0x08,
154    0x08, 0x20, 0x18, 0x09, 0xc1, 0x00, 0x18, 0x04, 0x21, 0xf0, 0xf0, 0x20,
155    0x08, 0x09, 0xc1, 0x00, 0x18, 0x04, 0x21, 0x00, 0x01, 0x21, 0x08, 0x09,
156    0xc1, 0x00, 0x18, 0x04, 0x21, 0x08, 0x09, 0x21, 0x08, 0x09, 0xc1, 0x00,
157    0x18, 0x04, 0x71, 0xf0, 0xf0, 0x70, 0x08, 0xf1, 0xc1, 0x00, 0x18, 0x00,
158    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x18, 0x00, 0x00, 0x00,
159    0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
160    0x00, 0xf0, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161    0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
162    0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0xf0,
163    0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x08, 0x01, 0x00,
164    0x00, 0x08, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x08, 0x00, 0x00, 0x00, 0x08,
165    0x20, 0x00, 0xc0, 0x00, 0x18, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
166    0xc0, 0x00, 0x18, 0x08, 0xd8, 0xf0, 0xe8, 0xf8, 0x30, 0xf0, 0xc0, 0x00,
167    0x18, 0xc8, 0x31, 0x01, 0x19, 0x09, 0x21, 0x08, 0xc1, 0x00, 0x18, 0x08,
168    0x11, 0xf0, 0x09, 0x09, 0x21, 0x08, 0xc0, 0x00, 0x18, 0x08, 0x11, 0x08,
169    0x09, 0x09, 0x21, 0x08, 0xc0, 0x00, 0x18, 0x08, 0x11, 0x08, 0x09, 0x09,
170    0x21, 0x08, 0xc1, 0x00, 0x18, 0xf0, 0x10, 0xf0, 0xf9, 0x08, 0x71, 0xf0,
171    0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xc0, 0x00,
172    0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00,
173    0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00,
174    0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
175    0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176    0xc0, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
177    0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf8, 0xff,
178    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
179    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181    0x00, 0x00};
182
183 /* Used to hold image type converter registry info */
184 typedef struct {
185     char *image_type;
186     _DtGrLoadProc convert_proc;
187     _DtGrDestroyContextProc destroy_context_proc;
188 } _DtGrRegistryRec;
189
190 /* 
191  * This array maps image file name extensions to the corresponding
192  * CDE data type.  It is used by the DetermineImageType function.
193  * The array must be NULL-terminated.
194  */
195 static char * img_extensions[] = {
196     "xpm",  "PM",
197     "pm",   "PM",
198     "gif",  "GIF",
199     "jpeg", "JPEG",
200     "jpg",  "JPEG",
201     "xbm",  "BM",
202     "bm",   "BM",
203     "tiff", "TIFF",
204     "tif",  "TIFF",
205     "xwd",  "XWD",
206     "cgm",  "CGM",
207     NULL
208 };
209    
210 /*****************************************************************************/
211 /*                    Private declarations                                   */
212 /*****************************************************************************/
213
214 static int              Do_Direct(
215                                 Display *dpy,
216                                 int      screen,
217                                 XWDFileHeader *header,
218                                 Colormap colormap,
219                                 int ncolors,
220                                 XColor *colors,
221                                 enum _DtGrColorModel    force,
222                                 XImage *in_image,
223                                 XImage *out_image,
224                                 unsigned long **ret_colors,
225                                 int  *ret_number );
226 static int              Do_Pseudo(
227                                 Display *dpy,
228                                 int      screen,
229                                 Colormap colormap,
230                                 int ncolors,
231                                 XColor *colors,
232                                 enum _DtGrColorModel    force,
233                                 XImage *in_image,
234                                 XImage *out_image,
235                                 unsigned long **ret_colors,
236                                 int  *ret_number );
237 static int              GreyScale (
238                                 Display   *dpy,
239                                 int        screen,
240                                 Colormap   cmap,
241                                 XImage    *in_image,
242                                 XImage    *out_image,
243                                 XColor    *colors,
244                                 int        ncolors,
245                                 enum _DtGrColorModel    force,
246                                 int        rshift,
247                                 int        gshift,
248                                 int        bshift,
249                                 Pixel      rmask,
250                                 Pixel      gmask,
251                                 Pixel      bmask );
252 static unsigned int     Image_Size(
253                                 XImage *image );
254 static void             Perform_Dither(
255                                 Display *dpy,
256                                 int      screen,
257                                 XImage  *image,
258                                 int     *greyscale );
259 static enum _DtGrLoadStatus processBitmap(
260                                 _DtGrStream           *image,
261                                 Screen                *screen,
262                                 int                   depth,
263                                 Colormap              colormap,
264                                 Visual                *visual,
265                                 Pixel                 foreground,
266                                 Pixel                 background,
267                                 GC                    gc,
268                                 enum _DtGrColorModel  color_model,
269                                 Boolean               allow_reduced_colors,
270                                 Dimension             *in_out_width,
271                                 Dimension             *in_out_height,
272                                 unsigned short        media_resolution,
273                                 Pixmap                *ret_pixmap,
274                                 Pixmap                *ret_mask,
275                                 Pixel                 **ret_colors,
276                                 int                   *ret_num_colors,
277                                 _DtGrContext          *context);
278 #ifndef STUB
279 static enum _DtGrLoadStatus processTiff(
280                                 _DtGrStream           *stream,
281                                 Screen                *screen,
282                                 int                   depth,
283                                 Colormap              colormap,
284                                 Visual                *visual,
285                                 Pixel                 foreground,
286                                 Pixel                 background,
287                                 GC                    gc,
288                                 enum _DtGrColorModel  color_model,
289                                 Boolean               allow_reduced_colors,
290                                 Dimension             *in_out_width,
291                                 Dimension             *in_out_height,
292                                 unsigned short        media_resolution,
293                                 Pixmap                *ret_pixmap,
294                                 Pixmap                *ret_mask,
295                                 Pixel                 **ret_colors,
296                                 int                   *ret_num_colors,
297                                 _DtGrContext          *context);
298 static void destroyTiffContext(
299                                 _DtGrContext          *context);
300 #endif
301 static enum _DtGrLoadStatus processXwd(
302                                 _DtGrStream           *stream,
303                                 Screen                *screen,
304                                 int                   depth,
305                                 Colormap              colormap,
306                                 Visual                *visual,
307                                 Pixel                 foreground,
308                                 Pixel                 background,
309                                 GC                    gc,
310                                 enum _DtGrColorModel  color_model,
311                                 Boolean               allow_reduced_colors,
312                                 Dimension             *in_out_width,
313                                 Dimension             *in_out_height,
314                                 unsigned short        media_resolution,
315                                 Pixmap                *ret_pixmap,
316                                 Pixmap                *ret_mask,
317                                 Pixel                 **ret_colors,
318                                 int                   *ret_num_colors,
319                                 _DtGrContext          *context);
320 static void             _swaplong (
321                                 register char *bp,
322                                 register unsigned n );
323 static void             _swapshort (
324                                 register char *bp,
325                                 register unsigned n );
326 static  int             XwdFileToPixmap (
327                                 Display  *dpy,
328                                 int       screen,
329                                 int       depth,
330                                 Pixmap    pixmap,
331                                 Colormap  colormap,
332                                 Visual   *visual,
333                                 GC        gc,
334                                 enum _DtGrColorModel  color_model,
335                                 int       src_x,
336                                 int       src_y,
337                                 int       dst_x,
338                                 int       dst_y,
339                                 int       width,
340                                 int       height,
341                                 _DtGrStream *stream,
342                                 unsigned long **ret_colors,
343                                 int      *ret_number );
344 static enum _DtGrLoadStatus processXpm(
345                                 _DtGrStream           *stream,
346                                 Screen                *screen,
347                                 int                   depth,
348                                 Colormap              colormap,
349                                 Visual                *visual,
350                                 Pixel                 foreground,
351                                 Pixel                 background,
352                                 GC                    gc,
353                                 enum _DtGrColorModel  color_model,
354                                 Boolean               allow_reduced_colors,
355                                 Dimension             *in_out_width,
356                                 Dimension             *in_out_height,
357                                 unsigned short        media_resolution,
358                                 Pixmap                *ret_pixmap,
359                                 Pixmap                *ret_mask,
360                                 Pixel                 **ret_colors,
361                                 int                   *ret_num_colors,
362                                 _DtGrContext          *context);
363 static enum _DtGrLoadStatus processGIF(
364                                 _DtGrStream           *image,
365                                 Screen                *screen,
366                                 int                   depth,
367                                 Colormap              colormap,
368                                 Visual                *visual,
369                                 Pixel                 foreground,
370                                 Pixel                 background,
371                                 GC                    gc,
372                                 enum _DtGrColorModel  color_model,
373                                 Boolean               allow_reduced_colors,
374                                 Dimension             *in_out_width,
375                                 Dimension             *in_out_height,
376                                 unsigned short        media_resolution,
377                                 Pixmap                *ret_pixmap,
378                                 Pixmap                *ret_mask,
379                                 Pixel                 **ret_colors,
380                                 int                   *ret_num_colors,
381                                 _DtGrContext          *context);
382 static enum _DtGrLoadStatus processJPEG(
383                                 _DtGrStream           *image,
384                                 Screen                *screen,
385                                 int                   depth,
386                                 Colormap              colormap,
387                                 Visual                *visual,
388                                 Pixel                 foreground,
389                                 Pixel                 background,
390                                 GC                    gc,
391                                 enum _DtGrColorModel  color_model,
392                                 Boolean               allow_reduced_colors,
393                                 Dimension             *in_out_width,
394                                 Dimension             *in_out_height,
395                                 unsigned short        media_resolution,
396                                 Pixmap                *ret_pixmap,
397                                 Pixmap                *ret_mask,
398                                 Pixel                 **ret_colors,
399                                 int                   *ret_num_colors,
400                                 _DtGrContext          *context);
401 static enum _DtGrLoadStatus DetermineImageType(
402                                 _DtGrStream *stream,
403                                 char        *image_type);
404 static enum _DtGrLoadStatus GetConverterAndDestructor(
405                                 char *image_type, 
406                                 _DtGrLoadProc *converter,
407                                 _DtGrDestroyContextProc *destructor);
408 static float ComputeRatio(int media_res, int image_res);
409
410 /***************************************************************************** 
411  *         Image type registry declarations
412  *****************************************************************************/
413
414 /* Registry of converters and destructors for default image types */
415 static _DtGrRegistryRec registry[] =
416 {
417     {
418         "PM",
419         processXpm,
420         NULL
421     },
422
423     {
424         "BM",
425         processBitmap,
426         NULL
427     },
428
429     {
430         "GIF",
431         processGIF,
432         NULL
433     },
434
435     {
436         "JPEG",
437         processJPEG,
438         NULL
439     },
440
441     {
442         "TIFF",
443         processTiff,
444         destroyTiffContext
445     },
446
447     {
448         "XWD",
449         processXwd,
450         NULL
451     },
452 };
453
454 static int registry_count = XtNumber(registry);
455
456 /* Registry of converters and destructors for non-default image types */
457 static _DtGrRegistryRec *new_registry = NULL;
458 static new_registry_count = 0;
459
460 /***************************************************************************** 
461  *         Private Routines
462  *****************************************************************************/
463 /***************************************************************************** 
464  * taken straight out of xwud and modified.
465  *****************************************************************************/
466 /* Copyright 1985, 1986, 1988 Massachusetts Institute of Technology */
467
468 static void
469 _swapshort (
470     register char *bp,
471     register unsigned n )
472 {
473     register char c;
474     register char *ep = bp + n;
475
476     while (bp < ep) {
477         c = *bp;
478         *bp = *(bp + 1);
479         bp++;
480         *bp++ = c;
481     }
482 }
483
484 static void
485 _swaplong (
486     register char *bp,
487     register unsigned n )
488 {
489     register char c;
490     register char *ep = bp + n;
491     register char *sp;
492
493     while (bp < ep) {
494         sp = bp + 3;
495         c = *sp;
496         *sp = *bp;
497         *bp++ = c;
498         sp = bp + 1;
499         c = *sp;
500         *sp = *bp;
501         *bp++ = c;
502         bp += 2;
503     }
504 }
505
506 static float
507 ComputeRatio(int media_res, int image_res)
508 {
509     float ratio;
510     int iratio, dx;
511
512     if (media_res >= image_res) {
513         ratio = (float)media_res / (float)image_res;
514         if (media_res % image_res == 0)
515             return ratio;
516         iratio = ratio + 0.5;
517         dx = media_res - image_res * iratio;
518         if (dx >= -RES_TOLERANCE && dx <= RES_TOLERANCE)
519             ratio = (float)iratio;
520     } else {
521         ratio = (float)image_res / (float)media_res;
522         if (image_res % media_res == 0)
523             return 1.0 / ratio;
524         iratio = ratio + 0.5;
525         dx = image_res - media_res * iratio;
526         if (dx >= -RES_TOLERANCE && dx <= RES_TOLERANCE)
527             ratio = (float)iratio;
528         ratio = 1.0 / ratio;
529     }
530     return ratio;
531 }
532
533 /*****************************************************************************
534  * Function: GreyScale
535  *
536  * Turn a color image into a 8 grey color image
537  * If it can't create a grey scale image, GreyScale will call
538  * Perform_Dither to create a bi-tonal image.
539  *
540  *****************************************************************************
541  * The GreyScale code was ported from xgedit and changed to fit our needs
542  *****************************************************************************/
543 static  int
544 GreyScale (
545     Display   *dpy,
546     int        screen,
547     Colormap   cmap,
548     XImage    *in_image,
549     XImage    *out_image,
550     XColor    *colors,
551     int        ncolors,
552     enum _DtGrColorModel force,
553     int        rshift,
554     int        gshift,
555     int        bshift,
556     Pixel      rmask,
557     Pixel      gmask,
558     Pixel      bmask )
559 {
560   int i, j, x;
561   int     inc;
562   int     count;
563   int     width = in_image->width;
564   int     height = in_image->height;
565   int     value;
566   int    *grey_scale;
567   Pixel   valueArray[256];
568   Pixel   n;
569   XColor  ret_color;
570
571 /*--- allocate an array big enough to map each pixel in the image  ---*/
572 /*--- into a corresponding greyscale value (in the range [0-255]). ---*/
573
574   grey_scale = (int *) calloc(width*height, sizeof(int));
575   if (grey_scale == NULL) {
576      return GR_ALLOC_ERR;
577    }
578
579 /*---          < ESTABLISH THE GREYSCALE IMAGE >            ---*/
580 /*--- The NTSC formula for converting an RGB value into the ---*/
581 /*--- corresponding greyscale value is:                     ---*/
582 /*---      luminosity = .299 red + .587 green + .114 blue   ---*/
583
584   /*
585    * zero the flag array
586    */
587   for (i = 0; i < 256; i++)
588       valueArray [i] = 0;
589
590   for (j=0, x = 0; j<height; j++)
591     for (i=0; i<width; i++, x++) {
592       n = XGetPixel(in_image, i, j);
593       if (rshift)
594         {
595           ret_color.red   = (n >> rshift) & rmask;
596           ret_color.green = (n >> gshift) & gmask;
597           ret_color.blue  = (n >> bshift) & bmask;
598           if (ncolors)
599             {
600               ret_color.red   = colors[ret_color.red  ].red;
601               ret_color.green = colors[ret_color.green].green;
602               ret_color.blue  = colors[ret_color.blue ].blue;
603             }
604           else
605             {
606               ret_color.red   = (((Pixel) ret_color.red  ) * 65535) / rmask;
607               ret_color.green = (((Pixel) ret_color.green) * 65535) / gmask;
608               ret_color.blue  = (((Pixel) ret_color.blue ) * 65535) / bmask;
609             }
610
611           value = (((int)(ret_color.red*299) + (int)(ret_color.green*587) +
612                                 (int)(ret_color.blue*114)) / 1000) >> 8;
613         }
614       else
615           value = (((int)(colors[n].red*299) + (int)(colors[n].green*587) +
616                                 (int)(colors[n].blue*114)) / 1000) >> 8;
617       grey_scale[x] = value;
618       valueArray[value]++;
619      } /* for(i...) */
620
621   /*
622    * Find out if we can/have allocate the pre-defined grey colors.
623    */
624   _DtHelpProcessLock();
625   if (!GreyAllocated && force != _DtGrBITONAL)
626     {
627       for (i = 0; !GreyAllocated && i < MAX_GREY_COLORS; i++)
628         {
629           if (!XParseColor (dpy, cmap, GreyScaleColors[i], &ret_color) ||
630                 !XAllocColor (dpy, cmap, &ret_color))
631             {
632               /*
633                * Have a problem allocating one of the pre-defined
634                * grey colors. Free the already allocated pixels
635                * and set the flag.
636                */
637               if (i)
638                   XFreeColors (dpy, cmap, GreyScalePixels, i, 0);
639               GreyAllocated = -1;
640             }
641           else
642               GreyScalePixels[i] = ret_color.pixel;
643         }
644       if (!GreyAllocated)
645           GreyAllocated = True;
646     }
647
648   /*
649    * Had a problem allocating the pre-defined grey colors.
650    * Try to dither into black and white.
651    */
652   if (force == _DtGrBITONAL || GreyAllocated == -1)
653     {
654       Perform_Dither (dpy, screen, out_image, grey_scale);
655       free(grey_scale);
656       _DtHelpProcessUnlock();
657       return GR_SUCCESS;
658     }
659   _DtHelpProcessUnlock();
660
661   /*
662    * Find out how many grey scale colors there are.
663    */
664   for (count = 0, i = 0; i < 256; i++)
665       if (valueArray[i])
666           count++;
667
668   /*
669    * If we have less than maximum grey colors we want to spread the load
670    * between the colors
671    */
672   if (count < MAX_GREY_COLORS)
673       inc = count;
674   else
675       inc = MAX_GREY_COLORS;
676
677   /*
678    * This is rather esoteric code.
679    * The line
680    *    valueArray[n] = GreyScalePixels[i * MAX_GREY_COLORS / inc]
681    *
682    * causes the colors to be evenly distributed if the total number
683    * of calculated grey shades is less than the number of pre-defined
684    * grey colors.
685    *
686    * The if stmt
687    *    if (j >= count / (MAX_GREY_COLORS - i))
688    *
689    * uniformly reduces the calculated grey shades into the pre-defined
690    * grey colors, if the total number of grey shades is greater than
691    * the number of pre-defined grey colors.
692    *
693    * If after reading the following code, the reader still doesn't
694    * understand it, pick a couple of numbers between 1-255 for 'count'
695    * and walk each of them thru the 'for' loop. Hopefully it will help.
696    * (Suggestion - pick a large number for one value and pick
697    * a number less than 8 for the other value).
698    */
699   for (i = 0, n = 0, j = 0; n < 256 && count && i < MAX_GREY_COLORS; n++)
700     {
701       if (valueArray[n])
702         {
703           _DtHelpProcessLock();
704           valueArray[n] = GreyScalePixels[i * MAX_GREY_COLORS / inc];
705           _DtHelpProcessUnlock();
706           j++;
707           if (j >= count / (MAX_GREY_COLORS - i))
708             {
709               count -= j;
710               i++;
711               j = 0;
712             }
713         }
714     }
715
716   /*
717    * Now replace the image pixels with the grey pixels
718    */
719   for (j = 0, x = 0; j < height; j++)
720     for (i = 0; i < width; i++, x++) {
721       XPutPixel (out_image, i, j, valueArray[grey_scale[x]]);
722      } /* for(i...) */
723
724   free(grey_scale);
725
726   return GR_SUCCESS;
727 }
728
729 /***************************************************************************
730  *                                                                         *
731  * Routine:   Perform_Dither                                               *
732  *                                                                         *
733  * Purpose:   Given a color XImage and a greyscale representation of it,   *
734  *            for each pixel in the image, determine whether it should be  *
735  *            coverted to Black or White base on the weighted average of   *
736  *            the greyscale value of it and the pixels surrounding it.     *
737  *            Be sure to do bounds checking for pixels that are at the     *
738  *            edge of the image.                                           *
739  *                                                                         *
740  *            The dithering is done using the Floyd-Steinberg error        *
741  *            diffusion algorithm, which incorporates a Stucki error       *
742  *            filter (specifics can be found in Chapter 8, "Dithering      *
743  *            with Blue Noise", of the book "Digital Halftoning" by        *
744  *            Robert Ulichney (MIT Press, 1988).                           *
745  *                                                                         *
746  *X11***********************************************************************/
747 static  void
748 Perform_Dither(
749     Display *dpy,
750     int      screen,
751     XImage  *image,
752     int   *greyscale )
753 {
754   int i, j, width, height;
755   int result, error, max_lum;
756   Pixel    blackPixel = XBlackPixel (dpy, screen);
757   Pixel    whitePixel = XWhitePixel (dpy, screen);
758
759   width  = image->width;
760   height = image->height;
761   max_lum = 256;
762
763   for (j=0; j<height; j++) /* rows */
764     for (i=0; i<width; i++) { /* columns */
765       if (greyscale[(j*width)+i] < (max_lum/2))
766         result = 0;
767       else
768         result = max_lum - 1;
769       error = greyscale[(j*width)+i] - result;
770       if (i+1 < width)                  /*--- G [j] [i+1] ---*/
771         greyscale[(j*width)+i+1] += (error * 8)/42;
772       if (i+2 < width)                  /*--- G [j] [i+2] ---*/
773         greyscale[(j*width)+i+2] += (error * 4)/42;
774
775       if (j+1 < height) {
776         if (i-2 >= 0)                   /*--- G [j+1] [i-2] ---*/
777           greyscale[((j+1)*width)+i-2] += (error * 2)/42;
778         if (i-1 >= 0)                   /*--- G [j+1] [i-1] ---*/
779           greyscale[((j+1)*width)+i-1] += (error * 4)/42;
780         /*--- G [j+1] [i] ---*/
781         greyscale[((j+1)*width)+i] += (error * 8)/42;
782         if (i+1 < width)                /*--- G [j+1] [i+1] ---*/
783           greyscale[((j+1)*width)+i+1] += (error * 4)/42;
784         if (i+2 < width)                /*--- G [j+1] [i+2] ---*/
785           greyscale[((j+1)*width)+i+2] += (error * 2)/42;
786        }
787
788       if (j+2 < height) {
789         if (i-2 >= 0)                   /*--- G [j+2] [i-2] ---*/
790           greyscale[((j+2)*width)+i-2] += error/42;
791         if (i-1 >= 0)                   /*--- G [j+2] [i-1] ---*/
792           greyscale[((j+2)*width)+i-1] += (error * 2)/42;
793         /*--- G [j+2] [i] ---*/
794         greyscale[((j+2)*width)+i] += (error * 4)/42;
795         if (i+1 < width)                /*--- G [j+2] [i+1] ---*/
796           greyscale[((j+2)*width)+i+1] += (error * 2)/42;
797         if (i+2 < width)                /*--- G [j+2] [i+2] ---*/
798           greyscale[((j+2)*width)+i+2] += error/42;
799        }
800
801       if (result)
802         XPutPixel(image, i, j, whitePixel);
803       else
804         XPutPixel(image, i, j, blackPixel);
805      } /* for(i...) */
806 }
807
808
809 static int
810 Do_Pseudo(
811     Display *dpy,
812     int      screen,
813     Colormap colormap,
814     int ncolors,
815     XColor *colors,
816     enum _DtGrColorModel force,
817     XImage *in_image,
818     XImage *out_image,
819     unsigned long **ret_colors,
820     int  *ret_number )
821 {
822     register int i, x, y, colorCount = 0;
823     register XColor *color;
824     int      result = 0;
825     Pixel    pixel;
826
827     for (i = 0; i < ncolors; i++)
828         colors[i].flags = 0;
829
830     *ret_colors = NULL;
831     *ret_number = 0;
832
833     /*
834      * beware 'result'.
835      * It is set to one upon entering this routine.
836      * The only way it can be modified is by the call to XAllocColor.
837      */
838     if (force == _DtGrCOLOR)
839         result = 1;
840
841     for (y = 0; result && y < in_image->height; y++)
842       {
843         for (x = 0; result && x < in_image->width; x++)
844           {
845             pixel = XGetPixel(in_image, x, y);
846             color = &colors[pixel];
847             if (!color->flags)
848               {
849                 color->flags = DoRed | DoGreen | DoBlue;
850                 result = XAllocColor(dpy, colormap, color);
851                 if (!result)
852                     color->flags = 0;
853                 else
854                     colorCount++;
855               }
856             if (result)
857                 XPutPixel(out_image, x, y, color->pixel);
858           }
859       }
860
861     /*
862      * If result == 0, a call to XAllocColor failed
863      * Try to grey scale the image.
864      */
865     if (!result)
866       {
867         if (colorCount)
868           {
869             for (i = 0; i < ncolors; i++)
870               {
871                 if (colors[i].flags)
872                   {
873                     XFreeColors (dpy, colormap, &(colors[i].pixel), 1, 0);
874                     colors[i].flags = 0;
875                   }
876               }
877           }
878         result = GreyScale (dpy, screen, colormap, in_image, out_image, colors,
879                         ncolors, force, 0, 0, 0, 0, 0, 0);
880       }
881     else if (colorCount)
882       {
883         result = GR_SUCCESS;
884         *ret_colors = (unsigned long *) malloc (
885                                         sizeof (unsigned long) * colorCount);
886         if (*ret_colors == NULL)
887           {
888             colorCount = 0;
889             result = GR_ALLOC_ERR;
890           }
891
892         for (i = 0, x = 0; i < ncolors && x < colorCount; i++)
893             if (colors[i].flags)
894                 (*ret_colors)[x++] = colors[i].pixel;
895
896         *ret_number = colorCount;
897       }
898
899     /*
900      * result was set to a XHPIF value via the 'else' stmt or
901      * returned from GreyScale routine.
902      */
903     return result;
904 }
905
906 static int
907 Do_Direct(
908     Display *dpy,
909     int      screen,
910     XWDFileHeader *header,
911     Colormap colormap,
912     int ncolors,
913     XColor *colors,
914     enum _DtGrColorModel force,
915     XImage *in_image,
916     XImage *out_image,
917     unsigned long **ret_colors,
918     int  *ret_number )
919 {
920     register int x, y;
921     XColor color;
922     unsigned long rmask, gmask, bmask;
923     int   rshift = 0, gshift = 0, bshift = 0;
924     int   i;
925     int   result;
926     int   pixMax = 256;
927     int   pixI   = 0;
928     Pixel pix;
929     Pixel *oldPixels;
930     Pixel *newPixels;
931
932     oldPixels = (Pixel *) malloc (sizeof (Pixel) * pixMax);
933     newPixels = (Pixel *) malloc (sizeof (Pixel) * pixMax);
934
935     if (oldPixels == NULL || newPixels == NULL)
936       {
937         if (oldPixels)
938             free (oldPixels);
939         if (newPixels)
940             free (newPixels);
941
942         return GR_ALLOC_ERR;
943       }
944
945     rmask = header->red_mask;
946     while (!(rmask & 1)) {
947         rmask >>= 1;
948         rshift++;
949     }
950     gmask = header->green_mask;
951     while (!(gmask & 1)) {
952         gmask >>= 1;
953         gshift++;
954     }
955     bmask = header->blue_mask;
956     while (!(bmask & 1)) {
957         bmask >>= 1;
958         bshift++;
959     }
960     if (in_image->depth <= 12)
961         pix = 1 << in_image->depth;
962
963     if (force == _DtGrCOLOR)
964         color.flags = DoRed | DoGreen | DoBlue;
965     else
966         color.flags = 0;
967
968     for (y = 0; color.flags && y < in_image->height; y++)
969       {
970         for (x = 0; color.flags && x < in_image->width; x++)
971           {
972             pix = XGetPixel(in_image, x, y);
973
974             i = 0;
975             while (i < pixI && oldPixels[i] != pix)
976                 i++;
977
978             if (i == pixI)
979               {
980                 color.red = (pix >> rshift) & rmask;
981                 color.green = (pix >> gshift) & gmask;
982                 color.blue = (pix >> bshift) & bmask;
983                 if (ncolors) {
984                     color.red = colors[color.red].red;
985                     color.green = colors[color.green].green;
986                     color.blue = colors[color.blue].blue;
987                 } else {
988                     color.red = ((unsigned long)color.red * 65535) / rmask;
989                     color.green = ((unsigned long)color.green * 65535) / gmask;
990                     color.blue = ((unsigned long)color.blue * 65535) / bmask;
991                 }
992                 if (!XAllocColor(dpy, colormap, &color))
993                     color.flags = 0;
994                 else 
995                   {
996                     if (pixI >= pixMax)
997                       {
998                         pixMax += 128;
999                         oldPixels = (Pixel *) realloc ((void *) oldPixels,
1000                                         (sizeof (Pixel) * pixMax));
1001                         newPixels = (Pixel *) realloc ((void *) newPixels,
1002                                         (sizeof (Pixel) * pixMax));
1003
1004                         /*
1005                          * check the realloc
1006                          */
1007                         if (oldPixels == NULL || newPixels == NULL)
1008                           {
1009                             if (oldPixels)
1010                                 free (oldPixels);
1011
1012                             if (newPixels)
1013                               {
1014                                 XFreeColors(dpy, colormap, newPixels, pixI, 0);
1015                                 free (newPixels);
1016                               }
1017
1018                             return GR_ALLOC_ERR;
1019                           }
1020                       }
1021                     oldPixels[pixI]   = pix;
1022                     newPixels[pixI++] = color.pixel;
1023                   }
1024               }
1025             if (color.flags)
1026                 XPutPixel(out_image, x, y, newPixels[i]);
1027           }
1028       }
1029     if (color.flags)
1030       {
1031         result = GR_SUCCESS;
1032         if (pixI < pixMax)
1033           {
1034             newPixels = (Pixel *) realloc ((void *) newPixels,
1035                                         (sizeof (Pixel) * pixI));
1036             if (newPixels == NULL)
1037                 result = GR_ALLOC_ERR;
1038           }
1039
1040         free (oldPixels);
1041
1042         *ret_colors = newPixels;
1043         *ret_number = pixI;
1044       }
1045     else
1046       {
1047         if (pixI)
1048             XFreeColors (dpy, colormap, newPixels, pixI, 0);
1049
1050         free (oldPixels);
1051         free (newPixels);
1052
1053         result = GreyScale(dpy, screen, colormap, in_image, out_image, colors,
1054                         ncolors, force, rshift, gshift, bshift, rmask, gmask, bmask);
1055       }
1056
1057     return result;
1058 }
1059
1060 static unsigned int
1061 Image_Size(
1062      XImage *image )
1063 {
1064     if (image->format != ZPixmap)
1065       return(image->bytes_per_line * image->height * image->depth);
1066
1067     return((unsigned)image->bytes_per_line * image->height);
1068 }
1069
1070 static int
1071 XwdFileToPixmap (
1072     Display  *dpy,
1073     int       screen,
1074     int       depth,
1075     Pixmap    pixmap,
1076     Colormap  colormap,
1077     Visual   *visual,
1078     GC        gc,
1079     enum _DtGrColorModel  color_model,
1080     int       src_x,
1081     int       src_y,
1082     int       dst_x,
1083     int       dst_y,
1084     int       width,
1085     int       height,
1086     _DtGrStream *stream,
1087     unsigned long **ret_colors,
1088     int      *ret_number )
1089 {
1090     int result;
1091     register int i;
1092     XImage in_image, *out_image;
1093     register char *buffer;
1094     unsigned long swaptest = 1;
1095     int count;
1096     unsigned buffer_size;
1097     int ncolors;
1098     Bool rawbits = False;
1099     XColor *colors = NULL;
1100 #ifdef __alpha
1101 /* Use a different structure for compatibility with 32-bit platform */
1102     XWDColor   xwd_color;
1103 #endif /* __alpha */
1104      XWDFileHeader header;
1105
1106     /* Reset the pointer to the beginning of the stream */
1107     _DtGrSeek(stream, 0, SEEK_SET);
1108     
1109     /*
1110      * Read in header information.
1111      */
1112     if(_DtGrRead((char *)&header, sizeof(header), 1, stream) != 1)
1113       {
1114         return GR_HEADER_ERR;
1115       }
1116
1117     if (*(char *) &swaptest)
1118         _swaplong((char *) &header, sizeof(header));
1119
1120     /* check to see if the dump file is in the proper format */
1121     if (header.file_version != XWD_FILE_VERSION)
1122       {
1123         return GR_HEADER_ERR;
1124       }
1125
1126     if (header.header_size < sizeof(header))
1127       {
1128         return GR_HEADER_ERR;
1129       }
1130
1131      /*
1132       * skip the window name
1133       */
1134     if (_DtGrSeek(stream, (header.header_size - sizeof(header)), 1))
1135       {
1136         return GR_FILE_ERR; 
1137       }
1138
1139     /*
1140      * initialize the input image
1141      */
1142     in_image.width = (int) header.pixmap_width;
1143     in_image.height = (int) header.pixmap_height;
1144     in_image.xoffset = (int) header.xoffset;
1145     in_image.format = (int) header.pixmap_format;
1146     in_image.byte_order = (int) header.byte_order;
1147     in_image.bitmap_unit = (int) header.bitmap_unit;
1148     in_image.bitmap_bit_order = (int) header.bitmap_bit_order;
1149     in_image.bitmap_pad = (int) header.bitmap_pad;
1150     in_image.depth = (int) header.pixmap_depth;
1151     in_image.bits_per_pixel = (int) header.bits_per_pixel;
1152     in_image.bytes_per_line = (int) header.bytes_per_line;
1153     in_image.red_mask = header.red_mask;
1154     in_image.green_mask = header.green_mask;
1155     in_image.blue_mask = header.blue_mask;
1156     in_image.obdata = NULL;
1157     _XInitImageFuncPtrs(&in_image);
1158
1159     /* read in the color map buffer */
1160     ncolors = header.ncolors;
1161     if (ncolors) {
1162         colors = (XColor *)malloc((unsigned) ncolors * sizeof(XColor));
1163         if (!colors)
1164           {
1165             return GR_ALLOC_ERR;
1166           }
1167
1168 #ifdef __alpha
1169 /* Use XWDColor instead of XColor. Byte-swapping if it is necessary.
1170  * Move values back into Xcolor structure.
1171  */
1172         for (i = 0; i < ncolors; i++) {
1173             if (_DtGrRead( (char *) &xwd_color, sizeof(XWDColor), 1 , stream)  != 1 )
1174             {
1175                 XFree ((char *) colors);
1176                 return GR_FILE_ERR;
1177             }
1178
1179             if (*(char *) &swaptest) {
1180                 _swaplong((char *) &xwd_color.pixel, sizeof(xwd_color.pixel));
1181                 _swapshort((char *) &xwd_color.red, 3 * sizeof(xwd_color.red));
1182             }
1183
1184             colors[i].pixel = xwd_color.pixel;
1185             colors[i].red   = xwd_color.red;
1186             colors[i].green = xwd_color.green;
1187             colors[i].blue  = xwd_color.blue;
1188             colors[i].flags = xwd_color.flags;
1189         }
1190 #else
1191         if(_DtGrRead((char *) colors, sizeof(XColor), ncolors, stream) != ncolors)
1192           {
1193             XFree ((char *) colors);
1194             return GR_FILE_ERR;
1195           }
1196
1197         if (*(char *) &swaptest) {
1198             for (i = 0; i < ncolors; i++) {
1199                 _swaplong((char *) &colors[i].pixel, sizeof(long));
1200                 _swapshort((char *) &colors[i].red, 3 * sizeof(short));
1201             }
1202         }
1203 #endif /* __alpha */
1204     }
1205
1206     /*
1207      * alloc the pixel buffer
1208      */
1209     buffer_size = Image_Size(&in_image);
1210     buffer = (char *) malloc(buffer_size);
1211     if (buffer == NULL)
1212       {
1213         if (NULL != colors)
1214             XFree ((char *) colors);
1215         return GR_ALLOC_ERR;
1216       }
1217
1218     /* read in the image data */
1219     count = _DtGrRead(buffer, sizeof(char), (int)buffer_size, stream);
1220
1221     if (count != buffer_size)
1222       {
1223         if (NULL != colors)
1224             XFree ((char *) colors);
1225         XFree (buffer);
1226         return GR_FILE_ERR;
1227       }
1228
1229     if (in_image.depth == 1) {
1230         in_image.format = XYBitmap;
1231         rawbits = True;
1232     }
1233     in_image.data = buffer;
1234
1235     /* create the output image */
1236     result = GR_SUCCESS;
1237
1238     if (rawbits) {
1239         out_image = &in_image;
1240     } else {
1241         out_image = XCreateImage(dpy, visual, depth,
1242                          (depth == 1) ? XYBitmap : in_image.format,
1243                                  in_image.xoffset, NULL,
1244                                  in_image.width, in_image.height,
1245                                  XBitmapPad(dpy), 0);
1246
1247         out_image->data = (char *) malloc(Image_Size(out_image));
1248
1249         if ((header.visual_class == TrueColor) ||
1250                    (header.visual_class == DirectColor))
1251             result = Do_Direct(dpy, screen, &header, colormap, ncolors, colors,
1252                         color_model,
1253                       &in_image, out_image, ret_colors, ret_number);
1254         else
1255             result = Do_Pseudo(dpy, screen, colormap, ncolors, colors, color_model,
1256                         &in_image, out_image, ret_colors, ret_number);
1257     }
1258
1259     if (result != GR_ALLOC_ERR)
1260
1261     _XmPutScaledImage(dpy, pixmap, gc, out_image,
1262                       src_x, src_y, dst_x, dst_y,
1263                       in_image.width, in_image.height,
1264                       width, height);
1265
1266     /*
1267      * free the buffers
1268      */
1269     if (NULL != colors)
1270         XFree ((char *) colors);
1271     XFree (buffer);
1272     if (!rawbits)
1273         XDestroyImage (out_image);
1274
1275     return result;
1276 }
1277
1278 /*****************************************************************************/
1279 /*  General functions for changing a file into a pixmap                      */
1280 /*                                                                           */
1281 /*****************************************************************************/
1282 /***********
1283  *
1284  * Function processBitmap
1285  *
1286  * takes a string.
1287  *      Make a bitmap into the pixmap for the graphic.
1288  *
1289  ***********/
1290 static enum _DtGrLoadStatus processBitmap(
1291     _DtGrStream           *stream,
1292     Screen                *screen,
1293     int                   depth,
1294     Colormap              colormap,
1295     Visual                *visual,
1296     Pixel                 foreground,
1297     Pixel                 background,
1298     GC                    gc,
1299     enum _DtGrColorModel  color_model,
1300     Boolean               allow_reduced_colors,
1301     Dimension             *in_out_width,
1302     Dimension             *in_out_height,
1303     unsigned short        media_resolution,
1304     Pixmap                *ret_pixmap,
1305     Pixmap                *ret_mask,
1306     Pixel                 **ret_colors,
1307     int                   *ret_num_colors,
1308     _DtGrContext          *context
1309 )
1310 {
1311     int           result;
1312     int           junk;
1313     unsigned int  width, height;
1314     unsigned char *data;
1315     Pixmap        scaled_pixmap=NULL;
1316     Display       *dpy = DisplayOfScreen(screen);
1317     Drawable      drawable = RootWindowOfScreen(screen);
1318     XImage        ximage;
1319     float          ratio = 1.0;
1320
1321     if (media_resolution == 0) 
1322         return(_DtGrCONVERT_FAILURE);
1323
1324     if (*in_out_width == 0 && *in_out_height == 0) 
1325          ratio = ComputeRatio(media_resolution, 100);
1326
1327     if (stream->type == _DtGrNONE)
1328         return(_DtGrCONVERT_FAILURE);
1329
1330     result = _DtGrReadBitmapStreamData (stream,
1331                                         &width, &height, &data, &junk, &junk);
1332
1333     /*  Be sure to implement XvpCopyPlane later         */
1334     if (result == BitmapSuccess)
1335     {
1336         ximage.height = height;
1337         ximage.width = width;
1338         ximage.depth = 1;
1339         ximage.bits_per_pixel = 1;
1340         ximage.xoffset = 0;
1341         ximage.format = XYBitmap;
1342         ximage.data = (char *)data;
1343         ximage.byte_order = LSBFirst;
1344         ximage.bitmap_unit = 8;
1345         ximage.bitmap_bit_order = LSBFirst;
1346         ximage.bitmap_pad = 8;
1347         ximage.bytes_per_line = (width+7)/8;
1348         XInitImage(&ximage);
1349
1350         *in_out_width = (Dimension) width * ratio + 0.5;
1351         *in_out_height = (Dimension) height * ratio + 0.5;
1352         if (*in_out_width == 0)
1353            *in_out_width = 1;
1354         if (*in_out_height == 0) 
1355            *in_out_height = 1;
1356
1357         scaled_pixmap = XCreatePixmap (dpy, drawable, (*in_out_width),
1358                                        (*in_out_height), depth);
1359        _XmPutScaledImage(dpy, scaled_pixmap, gc, &ximage,0, 0, 0, 0,
1360                          width,height,(*in_out_width),(*in_out_height));
1361        XFree((char *)data);
1362        *ret_pixmap = scaled_pixmap;
1363     }
1364
1365     if (result == BitmapSuccess)
1366         return(_DtGrSUCCESS);
1367     else if (result == BitmapOpenFailed)
1368         return(_DtGrOPEN_FAILED);
1369     else if (result == BitmapFileInvalid)
1370         return(_DtGrFILE_INVALID);
1371     else if (result == BitmapNoMemory)
1372         return(_DtGrNO_MEMORY);
1373     else 
1374         return(_DtGrCONVERT_FAILURE);
1375 }
1376
1377 #ifndef STUB
1378 /***********
1379  *
1380  * Function processTiff
1381  *
1382  * takes a string.
1383  *      Make a tiff into the pixmap for the graphic.
1384  *
1385  ***********/
1386 static enum _DtGrLoadStatus processTiff(
1387     _DtGrStream           *stream,
1388     Screen                *screen,
1389     int                   depth,
1390     Colormap              colormap,
1391     Visual                *visual,
1392     Pixel                 foreground,
1393     Pixel                 background,
1394     GC                    gc,
1395     enum _DtGrColorModel  color_model,
1396     Boolean               allow_reduced_colors,
1397     Dimension             *in_out_width,
1398     Dimension             *in_out_height,
1399     unsigned short        media_resolution,
1400     Pixmap                *ret_pixmap,
1401     Pixmap                *ret_mask,
1402     Pixel                 **ret_colors,
1403     int                   *ret_num_colors,
1404     _DtGrContext          *context
1405 )
1406 {
1407     int          result = -1;
1408     Pixmap       pixmap = NULL;
1409     ilFile       inFile;
1410     ilPipe       inPipe;
1411     ilFileImage  inImage;
1412     const ilImageDes   *inDes;
1413     static ilContext    IlContext = NULL;
1414     Display      *dpy = DisplayOfScreen(screen);
1415     Drawable      drawable = RootWindowOfScreen(screen);  
1416     ilXWC        *tiff_xwc;
1417     float         ratio = 1.0;
1418
1419     _DtHelpProcessLock();
1420     if ((context == NULL) || (stream->type == _DtGrNONE))
1421       {
1422         _DtHelpProcessUnlock();
1423         return (_DtGrCONVERT_FAILURE);
1424       }
1425
1426     if (media_resolution == 0) 
1427       {
1428         _DtHelpProcessUnlock();
1429         return(_DtGrCONVERT_FAILURE);
1430       }
1431
1432     tiff_xwc =  (ilXWC *) &(context->context);
1433     if (IlContext == NULL)
1434       {
1435         if (IL_CREATE_CONTEXT (&IlContext, 0))
1436           {
1437             IlContext = NULL;
1438             _DtHelpProcessUnlock();
1439             return (_DtGrCONVERT_FAILURE);
1440           }
1441       }
1442
1443     if (*tiff_xwc == NULL)
1444       {
1445         /* Fill in the context record fields */
1446         *tiff_xwc = ilCreateXWC (IlContext, dpy, visual, colormap, gc, 0, 0);
1447         if (*tiff_xwc == NULL)
1448           {
1449             _DtHelpProcessUnlock();
1450             return(_DtGrCONVERT_FAILURE);
1451           }
1452         context->image_type = XtNewString("TIFF");
1453       }
1454
1455     inFile = ilConnectFile (IlContext, stream, 0, 0);
1456     if (inFile)
1457       {
1458         inImage = ilListFileImages (inFile, 0);
1459         if (inImage)
1460           {
1461             int image_resolution = 100 ; /* assume that if not in file */
1462
1463
1464             if (inImage->xRes != 0) {
1465                 image_resolution = inImage->xRes ; /* dpi from the file */
1466             }
1467
1468             if (*in_out_width == 0 && *in_out_height == 0)
1469                 ratio = ComputeRatio(media_resolution, image_resolution);
1470
1471             *in_out_width = inImage->width * ratio + 0.5;
1472             *in_out_height = inImage->height * ratio + 0.5;
1473             if (*in_out_width == 0)
1474                 *in_out_width = 1;
1475             if (*in_out_height == 0) 
1476                 *in_out_height = 1;
1477
1478             pixmap = XCreatePixmap (dpy, drawable, (*in_out_width),
1479                                 (*in_out_height), depth);
1480             if (pixmap)
1481               {
1482                 inPipe = ilCreatePipe (IlContext, 0);
1483                 if (inPipe)
1484                   {
1485                     if (color_model == _DtGrGRAY_SCALE)
1486                         inDes = IL_DES_GRAY;
1487                     else if (color_model == _DtGrBITONAL)
1488                         inDes = IL_DES_BITONAL;
1489
1490                     result = 0;
1491                     if (!ilReadFileImage (inPipe, inImage, (ilRect *) NULL, 0))
1492                         result = -1;
1493
1494                     if (result == 0 && color_model != _DtGrCOLOR &&
1495                         ilConvert (inPipe, inDes, ((ilImageFormat *) NULL), 0, NULL) != True)
1496                         result  = -1;
1497
1498                     if (result == 0 &&
1499                         ilWriteXDrawable (inPipe, pixmap, *tiff_xwc,
1500                                                 (ilRect *) NULL, 0, 0, 0))
1501                       {
1502                         ilExecutePipe (inPipe, 0, ratio);
1503                         if (IlContext->error != 0)
1504                             result = -1;
1505                       }
1506                     ilDestroyObject (inPipe);
1507                   }
1508                 if (result == -1)
1509                   {
1510                     XFreePixmap (dpy, pixmap);
1511                     pixmap = NULL;
1512                   }
1513               }
1514           }
1515         ilDestroyObject (inFile);
1516       }
1517
1518     *ret_pixmap = pixmap;
1519     if (result < 0)
1520       {
1521         if ((IlContext->error == IL_ERROR_FILE_IO) ||
1522             (IlContext->error == IL_ERROR_FILE_NOT_TIFF))
1523           {
1524              _DtHelpProcessUnlock();
1525              return(_DtGrFILE_INVALID);
1526           }
1527         else if (IlContext->error == IL_ERROR_MALLOC)
1528           {
1529              _DtHelpProcessUnlock();
1530              return(_DtGrNO_MEMORY);
1531           }
1532         else
1533           {
1534              _DtHelpProcessUnlock();
1535              return(_DtGrCONVERT_FAILURE);
1536           }
1537       }
1538     else
1539       {
1540         _DtHelpProcessUnlock();
1541         return(_DtGrSUCCESS);
1542       }
1543 }
1544 #endif
1545
1546 /***********
1547  *
1548  * Function processXwd
1549  *
1550  * takes a string.
1551  *      Make an XWD file into the pixmap for the graphic.
1552  *
1553  ***********/
1554 static enum _DtGrLoadStatus processXwd(
1555     _DtGrStream           *stream,
1556     Screen                *screen,
1557     int                   depth,
1558     Colormap              colormap,
1559     Visual                *visual,
1560     Pixel                 foreground,
1561     Pixel                 background,
1562     GC                    gc,
1563     enum _DtGrColorModel  color_model,
1564     Boolean               allow_reduced_colors,
1565     Dimension             *in_out_width,
1566     Dimension             *in_out_height,
1567     unsigned short        media_resolution,
1568     Pixmap                *ret_pixmap,
1569     Pixmap                *ret_mask,
1570     Pixel                 **ret_colors,
1571     int                   *ret_num_colors,
1572     _DtGrContext          *context
1573 )
1574 {
1575     Pixmap         pixmap;
1576     XWDFileHeader  header;
1577     int            result;
1578     unsigned long swaptest = TRUE;
1579     Display       *dpy = DisplayOfScreen(screen);
1580     Drawable       drawable = RootWindowOfScreen(screen);  
1581     int            screen_num = XScreenNumberOfScreen(screen);
1582     float          ratio = 1.0;
1583
1584     if (media_resolution == 0) 
1585         return(_DtGrCONVERT_FAILURE);
1586
1587     if (stream->type == _DtGrNONE)
1588         return(_DtGrCONVERT_FAILURE);
1589
1590     /* Read in XWDFileHeader structure */
1591     result = _DtGrRead((char *)&header, sizeof(header), 1, stream);
1592
1593     if (result == 1 && *(char *) &swaptest)
1594         _swaplong((char *) &header, sizeof(header));
1595
1596     if (result != 1 || header.file_version != XWD_FILE_VERSION)
1597         return (_DtGrFILE_INVALID);
1598
1599     if (*in_out_width == 0 && *in_out_height == 0) 
1600          ratio = ComputeRatio(media_resolution, 100);
1601
1602     *in_out_width = header.pixmap_width * ratio + 0.5;
1603     *in_out_height = header.pixmap_height * ratio + 0.5;
1604
1605      if (*in_out_width == 0)
1606         *in_out_width = 1;
1607      if (*in_out_height == 0) 
1608         *in_out_height = 1;
1609
1610     pixmap = XCreatePixmap (dpy, drawable, (*in_out_width), 
1611                              (*in_out_height),depth);
1612
1613     if (pixmap) {
1614         if ((result=XwdFileToPixmap (dpy, screen_num, depth, pixmap, colormap, 
1615                 visual, gc, color_model, 0, 0, 0, 0,
1616                 (*in_out_width), (*in_out_height), stream,
1617                 ret_colors, ret_num_colors))
1618                         == GR_SUCCESS) {
1619             *ret_pixmap = pixmap;
1620             return (_DtGrSUCCESS);
1621         }
1622         else if (result == GR_HEADER_ERR)
1623             return (_DtGrFILE_INVALID);
1624         else if (result == GR_FILE_ERR)
1625             return (_DtGrFILE_INVALID);
1626         else if (result == GR_ALLOC_ERR)
1627             return (_DtGrNO_MEMORY);
1628         else
1629             return (_DtGrCONVERT_FAILURE);
1630     }
1631     else
1632         return (_DtGrNO_MEMORY);
1633 }
1634
1635 /************************************
1636  * myXpmReadFileToPixmap
1637  ***********************************/
1638 static int
1639 myXpmReadFileToPixmap(
1640     Display        *display,
1641     Screen         *screen,
1642     Drawable        d,
1643     _DtGrStream    *stream,
1644     Pixmap         *pixmap_return,
1645     Pixmap         *shapemask_return,
1646     XpmAttributes  *attributes,
1647     GC              gc,
1648     Pixel           bg,
1649     Pixel           fg,
1650     int             depth,
1651     float           ratio
1652 )
1653 {
1654     XImage *image, **imageptr = NULL;
1655     XImage *shapeimage, **shapeimageptr = NULL;
1656     int ErrorStatus;
1657     int switchFlag = 0;
1658     int scaledWidth, scaledHeight;
1659     /*
1660      * initialize return values
1661      */
1662
1663     if (pixmap_return) {
1664         *pixmap_return = NULL;
1665         imageptr = &image;
1666     }
1667     if (shapemask_return) {
1668         *shapemask_return = NULL;
1669         shapeimageptr = &shapeimage;
1670     }
1671
1672     /*
1673      * create the images
1674      */
1675
1676     if (stream->type == _DtGrFILE)
1677     {
1678         if (stream->source.file.uncompressed_filename != NULL)
1679             ErrorStatus = _DtXpmReadFileToImage(display, 
1680                                     stream->source.file.uncompressed_filename, 
1681                                     imageptr, shapeimageptr, attributes);
1682         else
1683             ErrorStatus = _DtXpmReadFileToImage(display, 
1684                                     stream->source.file.filename, 
1685                                     imageptr, shapeimageptr, attributes);
1686     }
1687     else if (stream->type == _DtGrBUFFER)
1688     {
1689             ErrorStatus = XpmCreateImageFromBuffer(display, 
1690                                     (char *) stream->source.buffer.base, 
1691                                     imageptr, shapeimageptr, attributes);
1692     }
1693     else
1694         ErrorStatus = XpmFileInvalid; /* stream type of _DtGrNONE */
1695
1696     if (ErrorStatus < 0)
1697         return (ErrorStatus);
1698
1699     /*
1700      * Check to see if we will need to switch the foreground and
1701      * background colors.  When forced to a depth of 1, the Xpm call
1702      * returns a ZPixmap ready to place in pixmap of depth 1.
1703      * Unfortunately, usually the pixmap is of a different depth.  This
1704      * causes a depth mismatch for the XPutImage.  Therefore, we change
1705      * the format type to XYBitmap and XPutImage is happy.  But on
1706      * servers where BlackPixel is not at pixel 1 in the colormap, this
1707      * causes the image to be inverted.  So by switching the foreground
1708      * and background in the gc, the image is corrected for these
1709      * systems.
1710      *
1711      * The other way of doing this, is to create a pixmap of depth 1 and
1712      * do an XPutImage to it.  Then do a XCopyPlane to a pixmap of the
1713      * correct depth.  But this is a major performance hit compared to
1714      * switching the colors.
1715      *
1716      * The downside of switching colors is that it works only when
1717      * BlackPixel and WhitePixel fill colormap entries 0 and 1.  But
1718      * since this is the 99.9% case, we'll go with it.
1719      */
1720     if (image->depth == 1 && BlackPixelOfScreen(screen) != 1L)
1721         switchFlag = 1;
1722
1723     /*
1724      * create the pixmaps
1725      */
1726     if (imageptr && image) {
1727         scaledWidth = image->width * ratio + 0.5;
1728         scaledHeight = image->height * ratio + 0.5;
1729
1730         if (scaledWidth == 0)
1731             scaledWidth = 1;
1732         if (scaledHeight == 0)
1733             scaledHeight = 1;
1734         
1735         *pixmap_return = XCreatePixmap(display, d, scaledWidth,
1736                                        scaledHeight, depth);
1737         if (image->depth == 1)
1738             image->format = XYBitmap;
1739
1740         if (switchFlag)
1741           {
1742             XSetBackground (display, gc, fg);
1743             XSetForeground (display, gc, bg);
1744           }
1745         _XmPutScaledImage(display, *pixmap_return, gc, image, 
1746                           0, 0, 0, 0,
1747                           image->width, image->height,
1748                           scaledWidth, scaledHeight);
1749         if (switchFlag)
1750           {
1751             XSetBackground (display, gc, bg);
1752             XSetForeground (display, gc, fg);
1753           }
1754
1755         XDestroyImage(image);
1756     }
1757
1758     if (shapeimageptr && shapeimage)
1759         XDestroyImage(shapeimage);
1760
1761     return (ErrorStatus);
1762 }
1763
1764 static XpmColorSymbol colorSymbol = {"none", NULL, 0};
1765
1766 /***********
1767  *
1768  * Function processXpm
1769  *
1770  * takes a string.
1771  *      Make an XPM file into the pixmap for the graphic.
1772  *
1773  ***********/
1774
1775 static enum _DtGrLoadStatus processXpm(
1776     _DtGrStream           *stream,
1777     Screen                *screen,
1778     int                   depth,
1779     Colormap              colormap,
1780     Visual                *visual,
1781     Pixel                 foreground,
1782     Pixel                 background,
1783     GC                    gc,
1784     enum _DtGrColorModel  color_model,
1785     Boolean               allow_reduced_colors,
1786     Dimension             *in_out_width,
1787     Dimension             *in_out_height,
1788     unsigned short        media_resolution,
1789     Pixmap                *ret_pixmap,
1790     Pixmap                *ret_mask,
1791     Pixel                 **ret_colors,
1792     int                   *ret_num_colors,
1793     _DtGrContext          *context
1794 )
1795 {
1796     int             i, j;
1797     int             result;
1798     short           done;
1799     Pixmap          pixmap  = NULL;
1800     XpmAttributes   xpmAttr;
1801     Visual          vis2;
1802     XGCValues       gcvalues;
1803     float           ratio = 1.0;
1804
1805     enum _DtGrLoadStatus status = _DtGrSUCCESS;
1806
1807     if (media_resolution == 0) 
1808         return(_DtGrCONVERT_FAILURE);
1809
1810     if (stream->type == _DtGrNONE)
1811         return(_DtGrCONVERT_FAILURE); /* stream type of _DtGrNONE */
1812
1813
1814     _DtHelpProcessLock();
1815     do
1816       {
1817         colorSymbol.pixel = background;
1818
1819         xpmAttr.valuemask    = XpmVisual       | XpmReturnPixels |
1820                                XpmColorSymbols | XpmColormap     | XpmDepth;
1821         xpmAttr.visual       = visual;
1822         xpmAttr.colorsymbols = &colorSymbol;
1823         xpmAttr.colormap     = colormap;
1824         xpmAttr.numsymbols   = 1;
1825         xpmAttr.depth        = depth;
1826         xpmAttr.pixels       = NULL;
1827
1828         /*
1829          * If not color, force to black and white.
1830          */
1831         if (color_model != _DtGrCOLOR)
1832           {
1833             memcpy (&vis2, xpmAttr.visual, sizeof(Visual));
1834
1835             vis2.class       = StaticGray;
1836             vis2.map_entries = 2;
1837
1838             xpmAttr.depth  = 1;
1839             xpmAttr.visual = &vis2;
1840           }
1841         if (*in_out_width == 0 && *in_out_height == 0) 
1842             ratio = ComputeRatio(media_resolution, 100);
1843
1844         result = myXpmReadFileToPixmap (DisplayOfScreen(screen), 
1845                                         screen, 
1846                                         RootWindowOfScreen(screen), 
1847                                         stream, ret_pixmap,
1848                                         ret_mask, &xpmAttr, gc,
1849                                         background, foreground, depth,
1850                                         ratio);
1851         done = True;
1852         /*
1853          * if we did not successfully get our icon, force the color
1854          * to black and white.
1855          */
1856         if (result == XpmColorFailed && color_model != _DtGrBITONAL)
1857           {
1858             if (allow_reduced_colors)
1859             {
1860                 color_model = _DtGrBITONAL;
1861                 status = _DtGrCOLOR_REDUCE;
1862                 done = False;
1863             }
1864             else
1865                 status = _DtGrCOLOR_FAILED;
1866           }
1867
1868       } while (done == False);
1869
1870     if (result == XpmSuccess || result == XpmColorError)
1871       {
1872         *in_out_width   = xpmAttr.width * ratio + 0.5;
1873         *in_out_height  = xpmAttr.height * ratio + 0.5;
1874         if (*in_out_width == 0)
1875            *in_out_width = 1;
1876         if (*in_out_height == 0) 
1877            *in_out_height = 1;
1878         *ret_colors     = xpmAttr.pixels;
1879         *ret_num_colors = xpmAttr.npixels;
1880
1881         /*
1882          * squeeze out the pixel used for the transparent color since we
1883          * don't want to free it when we free the other colors
1884          */
1885         i = 0;
1886         while (i < xpmAttr.npixels && xpmAttr.pixels[i] != colorSymbol.pixel)
1887             i++;
1888
1889         if (i < xpmAttr.npixels)
1890           {
1891             for (j = i, i = i + 1; i < xpmAttr.npixels; i++, j++)
1892                 xpmAttr.pixels[j] = xpmAttr.pixels[i];
1893
1894             *ret_num_colors = j;
1895           }
1896       }
1897     _DtHelpProcessUnlock();
1898
1899     if (result == XpmOpenFailed)
1900         status = _DtGrOPEN_FAILED;
1901     else if (result == XpmFileInvalid)
1902         status = _DtGrFILE_INVALID;
1903     else if (result == XpmNoMemory)
1904         status = _DtGrNO_MEMORY;
1905     else if (result == XpmColorFailed)
1906         status = _DtGrCOLOR_FAILED;
1907
1908     return(status);
1909 }
1910
1911 /******************************************************************************
1912  *
1913  * Function processGIF
1914  *
1915  * Default gif converter, creates a pixmap from a file-associated or 
1916  * buffer-associated stream of gif data.
1917  *
1918  *****************************************************************************/
1919 static enum _DtGrLoadStatus processGIF(
1920     _DtGrStream           *stream,
1921     Screen                *screen,
1922     int                   depth,
1923     Colormap              colormap,
1924     Visual                *visual,
1925     Pixel                 foreground,
1926     Pixel                 background,
1927     GC                    gc,
1928     enum _DtGrColorModel  color_model,
1929     Boolean               allow_reduced_colors,
1930     Dimension             *in_out_width,
1931     Dimension             *in_out_height,
1932     unsigned short        media_resolution,
1933     Pixmap                *ret_pixmap,
1934     Pixmap                *ret_mask,
1935     Pixel                 **ret_colors,
1936     int                   *ret_num_colors,
1937     _DtGrContext          *context
1938 )
1939 {
1940     struct stat stbuf;
1941     char *buffer;
1942     GifObj g;
1943     enum _DtGrLoadStatus status;
1944     Display *display = DisplayOfScreen(screen);   
1945     Drawable drawable = RootWindowOfScreen(screen);
1946     int i, size=0;
1947     float ratio = 1.0;
1948
1949     if (media_resolution == 0) 
1950         return(_DtGrCONVERT_FAILURE);
1951
1952     if (stream->type == _DtGrNONE)
1953         return(_DtGrCONVERT_FAILURE); /* stream type of _DtGrNONE */
1954
1955     *ret_pixmap = 0; /* Initialize the return pixmap to zero */
1956
1957     /* 
1958     ** The gif-to-pixmap utilities operate only on in-memory buffers,
1959     ** so if this is a buffer-based stream, simply pass the buffer, and
1960     ** if this is a file-based stream, read the file contents into a buffer 
1961     ** and pass that.
1962     */
1963
1964     if (stream->type == _DtGrBUFFER)
1965     {
1966         buffer = (char *) stream->source.buffer.base;
1967         size = stream->source.buffer.size;
1968     }
1969     else
1970     {
1971        if (stream->source.file.uncompressed_filename != NULL)
1972            stat (stream->source.file.uncompressed_filename, &stbuf);
1973        else
1974            stat (stream->source.file.filename, &stbuf);
1975        size = stbuf.st_size;
1976        buffer = XtMalloc(size);
1977        fread (buffer, 1, size, stream->source.file.fileptr);  
1978     }
1979
1980     /* Initialize the gif object */
1981     status = InitGifObject (&g, display, drawable, screen, depth, colormap, 
1982                             visual, gc, color_model, allow_reduced_colors);
1983
1984     if (*in_out_width == 0 && *in_out_height == 0) 
1985          ratio = ComputeRatio(media_resolution, 100);
1986
1987     /* Create an X pixmap from the gif object */
1988     if ((status == _DtGrSUCCESS) || (status == _DtGrCOLOR_REDUCE))
1989         *ret_pixmap = gif_to_pixmap (&g, (unsigned char *) buffer, size, 
1990                                      in_out_width, in_out_height, 
1991                                      g.f_black, g.f_white, ratio);
1992
1993     /* Set the returned colors parameters */
1994     if (*ret_pixmap != NULL)
1995     {
1996         if (g.f_do_visual == DO_COLOR)
1997         {
1998             *ret_num_colors = g.total_colors;       
1999             *ret_colors = (Pixel *) malloc(*ret_num_colors * sizeof(Pixel));
2000             for (i=0; i<*ret_num_colors; i++)
2001                 (*ret_colors)[i] = g.GifCMap[i].pixel;
2002         }
2003         else /* DO_GREY */
2004         {
2005             *ret_num_colors = g.f_total_greys;       
2006             *ret_colors = (Pixel *) malloc(*ret_num_colors * sizeof(Pixel));
2007             for (i=0; i<*ret_num_colors; i++)
2008                 (*ret_colors)[i] = g.GifGMap[i];
2009         }
2010     }
2011
2012     /* Free up any resources associated with the gif object */
2013     DeleteGifObjectResources (&g);
2014
2015     /* If we allocated a buffer, free it */
2016     if (stream->type == _DtGrFILE)
2017         XtFree(buffer);
2018
2019     /* Return the status */
2020     return (status);
2021 }
2022
2023 /******************************************************************************
2024  *
2025  * Function processJPEG
2026  *
2027  * Default jpeg converter, creates a pixmap from a file-associated or 
2028  * buffer-associated stream of jpeg data.
2029  *
2030  * The function first converts the jpeg stream to an XImage with a virtual
2031  * colormap using the jpeg_to_ximage call, then generates a new XImage that
2032  * uses the X colormap by calling the Do_Pseudo routine.  The Do_Pseudo 
2033  * routine, which is also used by the XWD converter, automatically handles X 
2034  * color allocation and color model degradation where necessary.  Finally,
2035  * a pixmap is generated from the XImage returned by Do_Pseudo.
2036  *
2037  *****************************************************************************/
2038 static enum _DtGrLoadStatus processJPEG(
2039     _DtGrStream           *stream,
2040     Screen                *screen,
2041     int                   depth,
2042     Colormap              colormap,
2043     Visual                *visual,
2044     Pixel                 foreground,
2045     Pixel                 background,
2046     GC                    gc,
2047     enum _DtGrColorModel  color_model,
2048     Boolean               allow_reduced_colors,
2049     Dimension             *in_out_width,
2050     Dimension             *in_out_height,
2051     unsigned short        media_resolution,
2052     Pixmap                *ret_pixmap,
2053     Pixmap                *ret_mask,
2054     Pixel                 **ret_colors,
2055     int                   *ret_num_colors,
2056     _DtGrContext          *context
2057 )
2058 {
2059     enum _DtGrLoadStatus status;
2060     XImage *in_image, *out_image;
2061     XColor *colors;
2062     int ncolors;
2063     int xres;
2064     int result = GR_SUCCESS;
2065     Display *dpy = DisplayOfScreen(screen); 
2066     int screen_num = XScreenNumberOfScreen(screen);
2067     Drawable drawable = RootWindowOfScreen(screen); 
2068     float ratio = 1.0;
2069     unsigned int scaledWidth,scaledHeight;
2070
2071     if (media_resolution == 0) 
2072         return(_DtGrCONVERT_FAILURE);
2073
2074     if (*in_out_width == 0 && *in_out_height == 0) 
2075         ratio = 0.0;
2076
2077     if (stream->type == _DtGrNONE)
2078         return(_DtGrCONVERT_FAILURE); /* stream type of _DtGrNONE */
2079
2080     /*
2081     ** Convert the stream to an XImage with a virtual colormap
2082     */
2083     status = jpeg_to_ximage (stream, screen, visual, in_out_width,
2084                              in_out_height, &in_image, &colors, &ncolors,
2085                              &xres);
2086
2087     if (ratio == 0.0) {
2088         if (!xres)
2089             xres = 100;
2090         ratio = ComputeRatio(media_resolution, xres);
2091     }
2092
2093     if (status == _DtGrSUCCESS)
2094     {
2095         if (in_image->depth == 1)
2096         {
2097             /*
2098             ** Bitmap, no further image transformation necessary 
2099             */
2100             out_image = in_image; 
2101             result = GR_SUCCESS;
2102         }
2103         else
2104         {
2105             /*
2106             ** Create an output image and have Do_Pseudo allocate the needed
2107             ** pixels and store image data that uses these pixels into
2108             ** the output image.
2109             */
2110             out_image = XCreateImage(dpy, visual, depth,
2111                                    (depth == 1) ? XYBitmap : in_image->format,
2112                                    in_image->xoffset, NULL,
2113                                    in_image->width, in_image->height,
2114                                    XBitmapPad(dpy), 0);
2115
2116             out_image->data = (char *) malloc(Image_Size(out_image));
2117
2118             result = Do_Pseudo(dpy, screen_num, colormap, ncolors, colors, 
2119                                color_model, in_image, out_image, 
2120                                ret_colors, ret_num_colors);
2121         }
2122
2123         /*
2124         ** If we've got a good XImage, go ahead and make a pixmap out of it
2125         */
2126         if (result != GR_ALLOC_ERR)
2127         {
2128             /*
2129             ** Create a pixmap the same size as the XImage 
2130             */        
2131
2132             scaledWidth = out_image->width * ratio + 0.5;
2133             scaledHeight = out_image->height * ratio + 0.5;
2134
2135             if (scaledWidth == 0)
2136                 scaledWidth = 1;
2137             if (scaledHeight == 0)
2138                 scaledHeight = 1;
2139         
2140             *ret_pixmap = XCreatePixmap (dpy, drawable, scaledWidth, 
2141                                          scaledHeight, depth);
2142             if (*ret_pixmap)
2143             {
2144                 /*
2145                 ** Copy the XImage into the pixmap and set the other
2146                 ** return parameters.
2147                 */
2148                 _XmPutScaledImage(dpy, *ret_pixmap, gc, out_image, 0, 0, 0, 0, 
2149                                   out_image->width, out_image->height, 
2150                                   scaledWidth, scaledHeight); 
2151
2152                 *in_out_width = scaledWidth;
2153                 *in_out_height = scaledHeight;              
2154                 status = _DtGrSUCCESS;
2155             }
2156             else 
2157                 status = _DtGrNO_MEMORY;
2158
2159             if (out_image != in_image)
2160                 XDestroyImage (out_image);
2161         }
2162         else
2163             status = _DtGrNO_MEMORY;
2164
2165         /*
2166         ** Free the colors array and the initial XImage 
2167         */
2168         XFree ((char *) colors);
2169         XDestroyImage (in_image);
2170     }
2171
2172     return (status);
2173 }
2174
2175 /******************************************************************************
2176  *
2177  * Function destroyTiffContext
2178  *
2179  * Default tiff context destructor, destroys the ilXWC object pointed to
2180  * by context->context and frees the context->image_type string.
2181  *
2182  *****************************************************************************/
2183 static void destroyTiffContext(
2184     _DtGrContext          *context)
2185 {
2186     if (context != NULL)
2187     {
2188         if (context->context != NULL)
2189           {
2190             _DtHelpProcessLock();
2191             ilDestroyObject ((ilObject) context->context);
2192             _DtHelpProcessUnlock();
2193           }
2194         if (context->image_type != NULL)
2195             XtFree(context->image_type);
2196     }
2197 }
2198
2199 /******************************************************************************
2200  *
2201  * Function DetermineImageType
2202  *
2203  * Determines the image type of the specified stream and copies the
2204  * string representing that image type into the image_type buffer.
2205  *
2206  * If the stream is a buffer, the buffer is passed to DtDtsBufferToData
2207  * in hopes that the file might be identified through content criteria.
2208  * 
2209  * If the stream is a file, the following checks are made:
2210  *
2211  *   1. The file name extension is checked against a list of known image file 
2212  *      type extensions.
2213  *   2. The filename is passed to DtDtsFileToDataType in hopes that the file
2214  *      type might be identified through filename extension or content 
2215  *      criteria. 
2216  *   3. If the file was uncompressed into a temporary file, the temporary
2217  *      filename is passed to DtDtsFileToDataType in hopes that the file
2218  *      type might be identified through content criteria.
2219  *
2220  * If none of these checks are successful, _DtCONVERT_FAILURE is returned.
2221  * Otherwise, _DtGrSUCCESS is returned.
2222  *
2223  *****************************************************************************/
2224 static enum _DtGrLoadStatus DetermineImageType(
2225     _DtGrStream *stream,
2226     char        *image_type)
2227 {
2228     int i=0;
2229     char *ext;
2230
2231     if (stream->type == _DtGrFILE)
2232     {
2233         /* First try to match the file name extension to a known mapping */
2234         if (stream->source.file.filename != NULL)
2235         {
2236             /* Get the filename extension */
2237             if (_DtHelpCeStrrchr(stream->source.file.filename, ".", 
2238                                  MB_CUR_MAX, &ext) == 0)
2239             {
2240                 ext++; /* Increment past the dot */
2241                 while (img_extensions[i] != NULL)
2242                 {
2243                     if (strcmp(ext, img_extensions[i]) == 0)
2244                     {
2245                         /* Found a match */
2246                         strcpy (image_type,img_extensions[++i]);
2247                         return (_DtGrSUCCESS);
2248                     }
2249                     /* Skip two ahead to the next file extension name */
2250                     i += 2;
2251                 }
2252             }
2253         }
2254
2255         /* 
2256          * Didn't work, see if CDE datatyping can determine the image type.  
2257          * First try the filename, then try the uncompressed temporary 
2258          * filename, if it exists.
2259          */
2260         if ((ext = DtDtsFileToDataType(stream->source.file.filename)) == NULL)
2261             if (stream->source.file.uncompressed_filename != NULL)
2262                 ext = DtDtsFileToDataType(
2263                                    stream->source.file.uncompressed_filename);
2264
2265         /* If successful, save the image type and return */
2266         if (ext != NULL)
2267         {
2268             strcpy (image_type, ext);
2269             DtDtsFreeDataType(ext);
2270             return (_DtGrSUCCESS);
2271         }
2272     }
2273     else if (stream->type == _DtGrBUFFER)
2274     {
2275         /* See if the CDE datatyping mechanism can determine the image type */
2276         ext = DtDtsBufferToDataType (stream->source.buffer.base,
2277                                      stream->source.buffer.size,
2278                                      NULL);
2279
2280         /* If successful, save the image type and return */
2281         if (ext != NULL)
2282         {
2283             strcpy (image_type, ext);
2284             DtDtsFreeDataType(ext);
2285             return (_DtGrSUCCESS);
2286         }
2287      }
2288
2289     /* Couldn't figure out the type, return failure */
2290     return (_DtGrCONVERT_FAILURE);
2291 }
2292
2293 /******************************************************************************
2294  *
2295  * Function GetConverterAndDestructor
2296  *
2297  * This function returns the converter and context destructor functions for
2298  * the specified image type.  The registry of default image types is searched
2299  * first, followed by the registry of new image types, until a match is made.
2300  * The function returns _DtGrSUCCESS if the image_type has been registered 
2301  * and _DtGrCONVERT_FAILURE if it has not.
2302  *
2303  *****************************************************************************/
2304 static enum _DtGrLoadStatus GetConverterAndDestructor(
2305     char *image_type, 
2306     _DtGrLoadProc *converter,
2307     _DtGrDestroyContextProc *destructor)
2308 {
2309     int i;
2310
2311     /* No image_type string, return failure */
2312     if (image_type == NULL)
2313         return (_DtGrCONVERT_FAILURE);
2314
2315     /* Search the default image type registry for the specified image type */
2316     _DtHelpProcessLock();
2317     for (i=0; i<registry_count; i++)
2318     {
2319         if (strcmp (registry[i].image_type, image_type) == 0)
2320         {
2321             /* Found it, return the converter and destructor */
2322             *converter = registry[i].convert_proc;
2323             *destructor = registry[i].destroy_context_proc;
2324             _DtHelpProcessUnlock();
2325             return (_DtGrSUCCESS);
2326         }
2327     }    
2328
2329     /* Search the new image type registry for the specified image type */
2330     for (i=0; i<new_registry_count; i++)
2331     {
2332         if (strcmp (new_registry[i].image_type, image_type) == 0)
2333         {
2334             /* Found it, return the converter */
2335             *converter = new_registry[i].convert_proc;
2336             *destructor = registry[i].destroy_context_proc;
2337             _DtHelpProcessUnlock();
2338             return (_DtGrSUCCESS);
2339         }
2340     }    
2341     _DtHelpProcessUnlock();
2342
2343     /* Image type wasn't registered, return failure */
2344     return (_DtGrCONVERT_FAILURE);
2345 }
2346
2347 /******************************************************************************
2348  *
2349  * Public Functions
2350  *
2351  *****************************************************************************/
2352 /******************************************************************************
2353  *
2354  * Function _DtHelpProcessGraphic
2355  *
2356  * takes a string.
2357  *      Get the pixmap for the graphic.
2358  *
2359  *****************************************************************************/
2360 Pixmap 
2361 _DtHelpProcessGraphic(
2362         Display    *dpy,
2363         Drawable    drawable,
2364         int         screen,
2365         int         depth,
2366         GC          gc,
2367         Pixmap     *def_pix,
2368         Dimension  *def_pix_width,
2369         Dimension  *def_pix_height,
2370         _DtGrContext *context,
2371         Colormap    colormap,
2372         Visual     *visual,
2373         Pixel       fore_ground,
2374         Pixel       back_ground,
2375         char       *filename,
2376         unsigned short media_resolution,
2377         Dimension  *width,
2378         Dimension  *height,
2379         Pixmap     *ret_mask,
2380         Pixel     **ret_colors,
2381         int        *ret_number )
2382 {
2383
2384     unsigned int    pixWidth  = 0;
2385     unsigned int    pixHeight = 0; 
2386     Dimension       pWidth, pHeight;
2387     char  *ptr;
2388     Pixmap pix = NULL, mask = NULL;
2389     _DtGrStream stream;
2390     Screen *scrptr = ScreenOfDisplay (dpy, screen);
2391     static enum _DtGrColorModel ForceColor = _DtGrCOLOR;
2392     static Boolean first_time = TRUE;
2393
2394     /*
2395      * initialize the return values
2396      */
2397     *ret_colors = NULL;
2398     *ret_number = 0;
2399     *ret_mask   = None;
2400
2401     /*
2402      * Initialize the Force Variable if this is the first time
2403      */
2404     _DtHelpProcessLock();
2405     if (first_time)
2406       {
2407         char    *ptr;
2408         char    *ptr2;
2409         char    *xrmName  = NULL;
2410         char    *xrmClass = NULL;
2411         char    *retStrType;
2412         XrmValue retValue;
2413
2414         ForceColor = _DtGrCOLOR;
2415
2416         XtGetApplicationNameAndClass (dpy, &ptr, &ptr2);
2417         xrmName  = malloc (strlen (ptr) + 14);
2418         xrmClass = malloc (strlen (ptr2) + 14);
2419         if (xrmName && xrmClass)
2420           {
2421             strcpy (xrmName , ptr);
2422             strcat (xrmName , ".helpColorUse");
2423
2424             strcpy (xrmClass, ptr2);
2425             strcat (xrmClass, ".HelpColorUse");
2426
2427             if (XrmGetResource (XtDatabase (dpy), xrmName, xrmClass,
2428                                         &retStrType, &retValue) == True)
2429               {
2430                 ptr = (char *) retValue.addr;
2431                 /*
2432                  * check for GreyScale
2433                  */
2434                 if (*ptr == 'G' || *ptr == 'g')
2435                     ForceColor = _DtGrGRAY_SCALE;
2436                 /*
2437                  * check for BlackWhite
2438                  */
2439                 else if (*ptr == 'B' || *ptr == 'b')
2440                     ForceColor = _DtGrBITONAL;
2441               }
2442
2443             free (xrmName);
2444             free (xrmClass);
2445           }
2446
2447         /*
2448          * choose the correct visual type to use
2449          */
2450         if (ForceColor == _DtGrCOLOR &&
2451                 (visual->class == GrayScale || visual->class == StaticGray))
2452             ForceColor = _DtGrGRAY_SCALE;
2453
2454         if (ForceColor != _DtGrBITONAL && depth == 1)
2455             ForceColor = _DtGrBITONAL;
2456
2457         first_time = FALSE;
2458       }
2459     _DtHelpProcessUnlock();
2460
2461     if (filename != NULL)
2462       {
2463         int   result;
2464
2465         /* Open the file and associate with a stream */
2466         result = _DtGrOpenFile(&stream, filename);
2467
2468         if (result != 0)
2469             pix = NULL;
2470         else 
2471         {
2472             /* Create a pixmap from the image data stream */
2473            _DtGrLoad(&stream, NULL, scrptr, depth, colormap, visual,
2474                      fore_ground, back_ground, gc, ForceColor, TRUE, &pWidth, 
2475                      &pHeight, media_resolution, &pix, &mask, ret_colors, 
2476                      ret_number, context);
2477            pixWidth = pWidth;
2478            pixHeight = pHeight;
2479            /* Close the stream and the file associated with it */
2480            _DtGrCloseStream( &stream );
2481
2482         }
2483       }
2484
2485     if (pix == NULL)
2486       {
2487         /*
2488          * Try to get a localized pixmap
2489          * NOTE....
2490          * This is a cached pixmap.....
2491          * Make sure XFreePixmaps does not free this one.
2492          */
2493         if (*def_pix == NULL)
2494           {
2495             *def_pix = XmGetPixmap(scrptr, "Dthgraphic", fore_ground, back_ground);
2496             if (*def_pix != XmUNSPECIFIED_PIXMAP)
2497               {
2498                 Window        root_id;
2499                 int           x, y;
2500                 unsigned int  border;
2501                 unsigned int  depth;
2502
2503                 if (XGetGeometry(dpy, *def_pix, &root_id, &x, &y,
2504                                 &pixWidth, &pixHeight, &border, &depth) == 0)
2505                   {
2506                     XmDestroyPixmap(scrptr, *def_pix);
2507                     *def_pix = NULL;
2508                   }
2509               }
2510             else
2511                 *def_pix = NULL;
2512
2513             /*
2514              * couldn't get a localized pixmap, go with a build in default
2515              */
2516             if (*def_pix == NULL)
2517               {
2518                 pixWidth  = Missing_bm_width;
2519                 pixHeight = Missing_bm_height;
2520                 *def_pix  = XCreatePixmapFromBitmapData ( dpy, drawable,
2521                                         (char *) Missing_bm_bits,
2522                                         pixWidth, pixHeight,
2523                                         fore_ground, back_ground, depth);
2524               }
2525
2526             *def_pix_width  = (Dimension) pixWidth;
2527             *def_pix_height = (Dimension) pixHeight;
2528           }
2529
2530         pix       = *def_pix;
2531         pixWidth  = *def_pix_width;
2532         pixHeight = *def_pix_height;
2533       }
2534
2535     *width  = (Dimension) pixWidth;
2536     *height = (Dimension) pixHeight;
2537
2538     return pix;
2539 }
2540
2541
2542 /******************************************************************************
2543  *
2544  * Function _DtGrLoad
2545  *
2546  * Determines the image type of the specified stream and calls the appropriate
2547  * imagetype-to-pixmap converter function.  If the conversion is successful
2548  * and the caller passed the address of a pointer to NULL in the image_type
2549  * parameter, a copy of the image type string is allocated and stored at this
2550  * address.  The caller is responsible for freeing this string.  The caller
2551  * is also responsible for freeing the values passed back in the ret_pixmap,
2552  * ret_mask, ret_colors, and context parameters.  The _DtGrLoad function 
2553  * returns _DtGrCONVERT_FAILURE if the appropriate converter could not be
2554  * determined, otherwise it returns the value returned by the converter.
2555  *
2556  *****************************************************************************/
2557 enum _DtGrLoadStatus _DtGrLoad(
2558     _DtGrStream           *stream,
2559     char                  **image_type,
2560     Screen                *screen,
2561     int                   depth,
2562     Colormap              colormap,
2563     Visual                *visual,
2564     Pixel                 foreground,
2565     Pixel                 background,
2566     GC                    gc,
2567     enum _DtGrColorModel  color_model,
2568     Boolean               allow_reduced_colors,
2569     Dimension             *in_out_width,
2570     Dimension             *in_out_height,
2571     unsigned short        media_resolution,
2572     Pixmap                *ret_pixmap,
2573     Pixmap                *ret_mask,
2574     Pixel                 **ret_colors,
2575     int                   *ret_num_colors,
2576     _DtGrContext          *context
2577 )
2578 {
2579     enum _DtGrLoadStatus status;
2580     _DtGrLoadProc converter;
2581     _DtGrDestroyContextProc destructor;
2582     char buf[20],*itype;
2583
2584     /* Determine the image type */
2585     if ((image_type != NULL) && (*image_type != NULL))
2586         itype = *image_type; /* Caller specified image type */
2587     else
2588     {
2589         /* Image type not specified by caller, try to figure it out */
2590         if ((status = DetermineImageType(stream, buf)) != _DtGrSUCCESS)
2591             return (status); /* Return failure if image type is unknown */
2592         itype = &buf[0];     
2593     }
2594
2595     /* Look up the proper converter for this image type */
2596     if ((status=GetConverterAndDestructor(itype, &converter, &destructor)) == 
2597                                                              _DtGrSUCCESS)
2598     {
2599         /* Call the converter */
2600         if (converter != NULL)
2601         {
2602             status = (*converter)(stream, screen, depth, colormap, visual,
2603                                   foreground, background, gc, color_model, 
2604                                   allow_reduced_colors, in_out_width,
2605                                   in_out_height, media_resolution, ret_pixmap, 
2606                                   ret_mask, ret_colors, ret_num_colors, 
2607                                   context);
2608         }
2609         else
2610             status = _DtGrCONVERT_FAILURE;
2611     }
2612     
2613     /* Return a copy of the image type string if successful */
2614     if (status == _DtGrSUCCESS || status == _DtGrCOLOR_REDUCE)
2615         if ((image_type != NULL) && (*image_type == NULL) && (itype != NULL))
2616             *image_type = XtNewString(itype);
2617
2618     /* Return the conversion status */
2619     return (status);
2620 }
2621
2622 /******************************************************************************
2623  *
2624  * Function _DtGrDestroyContext
2625  *
2626  * Obtains and calls the context destructor function for the image type
2627  * indicated by the context parameter.
2628  *
2629  *****************************************************************************/
2630 void _DtGrDestroyContext(
2631     _DtGrContext *context)
2632 {
2633     _DtGrLoadProc converter;
2634     _DtGrDestroyContextProc destructor;
2635
2636     if (GetConverterAndDestructor(context->image_type, &converter, 
2637                                   &destructor) == _DtGrSUCCESS)
2638     {
2639         if (destructor != NULL)
2640             (*destructor)(context);
2641     }
2642 }
2643
2644 /******************************************************************************
2645  *
2646  * Function _DtGrRegisterConverter
2647  *
2648  * Registers a converter and context destructor function for the specified
2649  * image type.  If the image_type has not been registered, a new record for
2650  * it is created in the new image type registry.  If the image_type has been
2651  * registered, the current converter and context destructor functions are
2652  * replaced by those specified by the caller.  If the caller passes valid
2653  * addresses in the current_convert_proc and current_destroy_proc parameters, 
2654  * the current converter and context destructor functions will be saved there
2655  * first so that the caller may restore them at a later time.
2656  *
2657  *****************************************************************************/
2658 void _DtGrRegisterConverter(
2659     char                    *image_type,
2660     _DtGrLoadProc           convert_proc,
2661     _DtGrDestroyContextProc destroy_context_proc,
2662     _DtGrLoadProc           *current_convert_proc,
2663     _DtGrDestroyContextProc *current_destroy_proc)
2664 {
2665     int i;
2666
2667     if (image_type == NULL)
2668         return;
2669
2670     /* Search the default converter registry for the specified image type */
2671     _DtHelpProcessLock();
2672     for (i=0; i<registry_count; i++)
2673     {
2674         if (strcmp (registry[i].image_type, image_type) == 0)
2675         {
2676             /* Found it, save the current procs, then replace them */
2677             /* with the new ones and return                        */
2678             if (current_convert_proc != NULL)
2679                 *current_convert_proc = registry[i].convert_proc;
2680             if (current_destroy_proc != NULL)
2681                 *current_destroy_proc = registry[i].destroy_context_proc;
2682             registry[i].convert_proc = convert_proc;
2683             registry[i].destroy_context_proc = destroy_context_proc;
2684             _DtHelpProcessUnlock();
2685             return;
2686         }
2687     }    
2688
2689     /* Search the new converter registry for the specified image type */
2690     for (i=0; i<new_registry_count; i++)
2691     {
2692         if (strcmp (new_registry[i].image_type, image_type) == 0)
2693         {
2694             /* Found it, save the current procs, then replace them */
2695             /* with the new ones and return                        */
2696             if (current_convert_proc != NULL)
2697                 *current_convert_proc = new_registry[i].convert_proc;
2698             if (current_destroy_proc != NULL)
2699                 *current_destroy_proc = new_registry[i].destroy_context_proc;
2700             new_registry[i].convert_proc = convert_proc;
2701             new_registry[i].destroy_context_proc = destroy_context_proc;
2702             _DtHelpProcessUnlock();
2703             return;
2704         }
2705     }    
2706     
2707     /* If we make it here, we've got a new image type to register */
2708     new_registry = (_DtGrRegistryRec *) XtRealloc ((char *) new_registry, 
2709                     sizeof(_DtGrRegistryRec) * (new_registry_count + 1));
2710     new_registry[new_registry_count].image_type = XtNewString (image_type);
2711     new_registry[new_registry_count].convert_proc = convert_proc;
2712     new_registry[new_registry_count].destroy_context_proc = 
2713                                                         destroy_context_proc;
2714     new_registry_count++;
2715     _DtHelpProcessUnlock();
2716
2717     /* Newly registered type, so return NULL for current function params */
2718     if (current_convert_proc != NULL)
2719         *current_convert_proc = NULL;
2720     if (current_destroy_proc != NULL)
2721         *current_destroy_proc = NULL;
2722
2723     return;
2724 }
2725
2726 /******************************************************************************
2727  *
2728  * Input stream functions
2729  * 
2730  * These functions allow the creation and manipulation of a stream that
2731  * can be associated with either a file or a buffer.  They are intended to
2732  * be used by image data to pixmap converter functions that need to handle
2733  * both image files and in-memory buffers containing file data.
2734  *
2735  *****************************************************************************/
2736
2737 /******************************************************************************
2738  *
2739  * Function _DtGrOpenFile
2740  *
2741  * Opens a file for reading and associates it with the specified stream.  If 
2742  * the file is compressed, the function uncompresses it prior to opening.  
2743  * Returns 0 for success, -1 or the value of errno as set by fopen for 
2744  * failure.
2745  *
2746  *****************************************************************************/
2747 int _DtGrOpenFile(
2748     _DtGrStream *stream,
2749     const char  *path)
2750 {
2751     char *fname = NULL;
2752
2753     if (stream == NULL) 
2754         return (-1);    /* Failure */
2755
2756     /* Uncompress the file if necessary and obtain the new filename */
2757     if (_DtHelpCeGetUncompressedFileName(path, &fname) == -1)
2758     {
2759         stream->type = _DtGrNONE;
2760         return (-1);  /* Failure */
2761     }
2762
2763     /* Open the file */
2764     stream->source.file.fileptr = fopen(fname,"r");
2765     if (stream->source.file.fileptr == NULL)
2766     {
2767         /* Failure, couldn't open the file */
2768         stream->type = _DtGrNONE;
2769         if ((fname != path) && (fname != NULL))
2770         {
2771             unlink (fname);
2772             free (fname);             
2773         }   
2774         return(errno);
2775     }
2776
2777     /* Set the stream type and copy the filename */
2778     stream->type = _DtGrFILE;
2779     stream->source.file.filename = XtNewString(path);
2780
2781     /* If the file was uncompressed and renamed, save the new name */
2782     if (fname == path)
2783         stream->source.file.uncompressed_filename = NULL;
2784     else
2785         stream->source.file.uncompressed_filename = fname;
2786
2787     return(0);    /* Success */
2788 }
2789
2790 /******************************************************************************
2791  *
2792  * Function _DtGrOpenBuffer
2793  *
2794  * Associates the specified in-memory buffer with the specified stream.
2795  * The function returns 0 for success and the EINVAL error code for failure.
2796  *
2797  *****************************************************************************/
2798 int _DtGrOpenBuffer(
2799     _DtGrStream *stream,
2800     const char  *buffer,
2801     int         buffer_size)
2802 {
2803     if ((stream == NULL) || (buffer == NULL) || (buffer_size < 0))
2804     {
2805         if (stream != NULL)
2806             stream->type = _DtGrNONE;
2807         return(EINVAL); /* Failure */
2808     }
2809
2810     /* Set the appropriate stream fields */
2811     stream->type = _DtGrBUFFER;
2812     stream->source.buffer.base = buffer;
2813     stream->source.buffer.size = buffer_size;
2814     stream->source.buffer.current = (char *)buffer;
2815     stream->source.buffer.end = (char *)(buffer + buffer_size - 1);
2816     return(0); /* Success */
2817 }
2818
2819 /******************************************************************************
2820  *
2821  * Function _DtGrCloseStream
2822  *
2823  * The function closes the specified stream by setting the stream type to
2824  * _DtGrNONE.  If the stream is associated with a file, then the file is
2825  * closed and the filename in the stream structure is freed.  If the file
2826  * required decompression, then the uncompressed file is unlinked and the
2827  * uncompressed filename is freed. 
2828  *
2829  *****************************************************************************/
2830 int _DtGrCloseStream(
2831     _DtGrStream *stream)
2832 {
2833     int status;
2834
2835     if ((stream == NULL) || (stream->type == _DtGrNONE))
2836         return(EOF);    /* Failure */
2837
2838     if (stream->type == _DtGrFILE)
2839     {
2840         /* Close the file and free the filename */
2841         status = fclose(stream->source.file.fileptr);
2842         if (stream->source.file.filename != NULL)
2843             XtFree(stream->source.file.filename);      
2844         if (stream->source.file.uncompressed_filename != NULL)
2845         { 
2846             /* Unlink the uncompressed file and free the filename */
2847             unlink(stream->source.file.uncompressed_filename);
2848             free(stream->source.file.uncompressed_filename);
2849         }
2850     }
2851     else if (stream->type == _DtGrBUFFER)
2852     {
2853         status = 0;    /* Success */
2854     }
2855
2856     stream->type = _DtGrNONE;
2857     return (status);
2858 }
2859
2860
2861 /******************************************************************************
2862  *
2863  * Function _DtGrRead
2864  *
2865  * Stream version of fread, reads data from a stream into a buffer.  If the 
2866  * stream is file-associated, a call to fread is made.  If the stream is
2867  * buffer-associated, an analogous operation is performed on the stream 
2868  * buffer.  The number of items read from the stream is returned to the caller.
2869  *
2870  *****************************************************************************/
2871 size_t _DtGrRead(
2872     void        *buffer,
2873     size_t      size,
2874     size_t      num_items,
2875     _DtGrStream *stream)
2876 {
2877     size_t num_items_read;
2878     unsigned nleft;
2879     int n;
2880
2881     if ((stream == NULL) || (stream->type == _DtGrNONE))
2882         return(0);
2883
2884     if (stream->type == _DtGrFILE)
2885     {
2886         return (fread(buffer, size, num_items, stream->source.file.fileptr));
2887     }
2888     else if (stream->type == _DtGrBUFFER)
2889     {
2890         /* This code mirrors that of fread in libc */
2891
2892         if (size <= 0 || num_items <= 0)
2893             return (0);
2894
2895         for (nleft = num_items * size; ; ) 
2896         {
2897             if (stream->source.buffer.current > stream->source.buffer.end) 
2898             { 
2899                 /* past end of stream */
2900                 if (stream->source.buffer.current == 
2901                     stream->source.buffer.end + 1)
2902                     return (num_items - (nleft + size - 1)/size);
2903                 stream->source.buffer.current--;
2904             }
2905             n = (nleft < stream->source.buffer.end - 
2906                          stream->source.buffer.current + 1 ? nleft :
2907                  stream->source.buffer.end - 
2908                  stream->source.buffer.current + 1); 
2909             /* Copy the items into the caller-supplied buffer */
2910             buffer = (char *)memcpy(buffer, 
2911                                    (void *) stream->source.buffer.current, 
2912                                    (size_t)n) + n;
2913             stream->source.buffer.current += n;
2914             if ((nleft -= n) == 0)
2915                 return (num_items);
2916         }
2917     }
2918 }
2919
2920 /******************************************************************************
2921  *
2922  * Function _DtGrSeek
2923  *
2924  * Stream version of fseek, repositions the file or buffer pointer of a 
2925  * stream.  If the stream is file-associated, the return value is the value
2926  * returned by fseek.  If the stream is buffer-associated, 0 is returned if
2927  * the requested position is inside the buffer, -1 if it is not.
2928  *
2929  *****************************************************************************/
2930 int _DtGrSeek(
2931     _DtGrStream *stream,
2932     long        offset,
2933     int         whence)
2934 {        
2935     long newpos;
2936
2937     if ((stream == NULL) || (stream->type == _DtGrNONE))
2938         return(-1); /* Failure */
2939
2940     if (stream->type == _DtGrFILE)
2941     {
2942         return (fseek(stream->source.file.fileptr,offset,whence));
2943     }
2944     else if (stream->type == _DtGrBUFFER)
2945     {
2946         switch (whence) 
2947         {
2948             case SEEK_SET:
2949                 newpos = (long)stream->source.buffer.base + offset;
2950                 break;
2951             case SEEK_CUR:
2952                 newpos = (long)stream->source.buffer.current + offset;
2953                 break;
2954             case SEEK_END:
2955                 newpos = (long)stream->source.buffer.end + 1 + offset;
2956                 break;
2957             default:
2958                 return (-1);
2959         }
2960
2961         if ((newpos >= (long)stream->source.buffer.base) &&
2962             (newpos <= (long)stream->source.buffer.end))
2963         {
2964             /* New position is within buffer, reposition pointer */
2965             stream->source.buffer.current = (char *)newpos;
2966             return(0); /* Success */
2967         }
2968         else
2969             return(-1); /* Failure */
2970     }
2971 }
2972
2973 /******************************************************************************
2974  *
2975  * Function _DtGrGetChar
2976  *
2977  * Stream version of fgetc, reads  a character from a stream and advances the 
2978  * stream position.  The next byte in the stream is returned, or EOF if an
2979  * error occurs or the end of the stream is reached.
2980  *
2981  *****************************************************************************/
2982 int _DtGrGetChar(
2983     _DtGrStream *stream)
2984 {
2985     if ((stream == NULL) || (stream->type == _DtGrNONE))
2986         return(EOF);
2987
2988     if (stream->type == _DtGrFILE)
2989     {
2990         return (fgetc(stream->source.file.fileptr));
2991     }
2992     else if (stream->type == _DtGrBUFFER)
2993     {
2994         if (stream->source.buffer.current > stream->source.buffer.end)
2995             return (EOF);
2996         else
2997             return ((unsigned char) *(stream->source.buffer.current++));
2998     }
2999 }
3000
3001 /******************************************************************************
3002  *
3003  * Function _DtGrGetString
3004  *
3005  * Stream version of fgets, reads a string from a stream and advances the 
3006  * stream position.  If an error occurs or the end of the stream is 
3007  * encountered and no characters have been read, no characters are transferred
3008  * to the buffer and a NULL pointer is returned.  Otherwise, the buffer is
3009  * returned.
3010  *
3011  *****************************************************************************/
3012 char *_DtGrGetString(
3013     char        *buffer,
3014     int         num_bytes,
3015     _DtGrStream *stream)
3016 {
3017     char *p, *save = buffer;
3018     int i;
3019
3020     if ((stream == NULL) || (stream->type == _DtGrNONE))
3021         return(NULL); /* Failure */
3022
3023     if (stream->type == _DtGrFILE)
3024     {
3025         return (fgets(buffer,num_bytes,stream->source.file.fileptr));
3026     }
3027     else if (stream->type == _DtGrBUFFER)
3028     {
3029         /* This code mirrors that of fgets in libc */
3030         for (num_bytes--; num_bytes > 0; num_bytes -= i) 
3031         {
3032             if (stream->source.buffer.current > stream->source.buffer.end) 
3033             {
3034                 if (stream->source.buffer.current == 
3035                     stream->source.buffer.end + 1)
3036                 {
3037                     if (save == buffer)
3038                         return (NULL);
3039                     break; /* no more data */
3040                 }
3041                 stream->source.buffer.current--;
3042             }
3043             i = (num_bytes < stream->source.buffer.end - 
3044                              stream->source.buffer.current + 1 ? num_bytes :
3045                              stream->source.buffer.end - 
3046                              stream->source.buffer.current + 1);
3047             /* Copy the data into the buffer */
3048             if ((p = memccpy((void *)buffer,
3049                              (void *)stream->source.buffer.current,
3050                              (int)'\n',(size_t)i)) != NULL)
3051                 i = p - buffer;
3052             buffer += i;
3053             stream->source.buffer.current += i;
3054             if (p != NULL)
3055                 break; /* found '\n' in buffer */
3056         }
3057         *buffer = '\0';
3058         return (save);
3059     }
3060 }