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