1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 /*
9  * $Header: /src/master/dx/src/exec/dxmods/_postscript.c,v 1.9 2003/07/11 05:50:34 davidt Exp $
10  */
11 
12 #include <dxconfig.h>
13 
14 
15 /*
16  * This file supports writing images to disk files in PostScript 3.0 format.
17  * We also support Encapsulated PostScript format 3.0.
18  * Images can be written out in either 24-bit color or 8-bit gray.
19  */
20 
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <time.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <dx/dx.h>
27 #include "_helper_jea.h"
28 #include "_rw_image.h"
29 #include <sys/types.h>
30 #include <math.h>
31 
32 struct ps_spec {
33         int     filetype;       /* PS or EPSF */
34         int     colormode;      /* FULLCOLOR or GRAY */
35         int     width_dpi;      /* dots per inch in image height */
36         int     height_dpi;     /* dots per inch in image width */
37         int     image_width;    /* width of image in pixels */
38         int     image_height;   /* height of image in pixels */
39         float   page_width;     /* width of page in inches */
40         float   page_height;    /* height of page in inches */
41 	float	page_margin;	/* margin width */
42         int     page_orient;    /* LANDSCAPE or PORTRAIT */
43         int     compress;       /* Do postscript compression */
44 	int	data_size;      /* For miff, size of data block */
45 	long	fptr;		/* File pointer for data size text */
46 	float   gamma;          /* gamma */
47 };
48 /*
49  * This taken from 1st Edition Foley and Van Dam, page 613
50  */
51 #define RGB_TO_BW(r,g,b)        (.30*(r) + .59*(g) + .11*(b))
52 
53 #define LINEOUT(s) if (fprintf(fout, s "\n") <= 0) goto bad_write;
54 
55 #define UPI             72      /* Default units per inch */
56 #define PS              0       /* Regular PostScript */
57 #define EPS             1       /* Encapsulated PostScript */
58 
59 #define RLE_BINARY      1
60 #define RLE_ASCII       0
61 #define RLE_COUNT_PRE   1
62 #define RLE_COUNT_POST  0
63 #define RLE_STUPID      1
64 #define RLE_COMPACT     0
65 
66 #define FULLCOLOR       0
67 #define GRAY            1
68 
69 #define FLOAT_COLOR     1
70 #define UBYTE_COLOR     2
71 #define MAPPED_COLOR    3
72 
73 #define NSCENES_STRING "nscenes="
74 #define DATASIZE_STRING "data_size="
75 
76 #define BUFFSIZE 256
77 
78 static Error parse_format(char *format, struct ps_spec *spec);
79 static Error output_ps(RWImageArgs *iargs, int colormode,int filetype);
80 static Error put_ps_header(FILE *fout, char *filename,
81                                 int frames, struct ps_spec *spec);
82 static Error build_rle_row(ubyte *r, int n_pixels, int bytes_per_pixel,
83                         int compress, ubyte *buff, int *byte_count, int binary, int order, int compact);
84 static Error put_ps_prolog(FILE *fout, struct ps_spec *spec);
85 static Error put_ps_setup(FILE *fout, int frames, struct ps_spec *spec) ;
86 static Error put_colorimage_function(FILE *fout);
87 static Error ps_new_page(FILE *fout, int page, int pages, struct ps_spec *spec);
88 static Error put_ps_page_setup(FILE *fout, struct ps_spec *spec);
89 static Error ps_image_header(FILE *fout, struct ps_spec *spec);
90 static Error ps_out_flc(FILE *fout,
91         Pointer pixels, RGBColor *map, int type, struct ps_spec *spec);
92 static Error ps_out_gry(FILE *fout,
93         Pointer pixels, RGBColor *map, int type, struct ps_spec *spec);
94 static Error ps_end_page(FILE *fout);
95 static Error put_ps_trailer(FILE *fout, struct ps_spec *spec);
96 static Error output_miff(RWImageArgs *iargs);
97 static Error put_miff_header(FILE *fout, char *filename,
98                                 int frame, struct ps_spec *spec, int type, int nframes);
99 static Error read_miff_header(FILE *in, int *frame, struct ps_spec *spec, int *type, int *nframes);
100 static Error miff_out_flc(FILE *fout,
101         Pointer pixels, RGBColor *map, int type, struct ps_spec *spec);
102 
103 #define ORIENT_NOT_SET  0
104 #define LANDSCAPE       1
105 #define PORTRAIT        2
106 #define ORIENT_AUTO	3
107 static void orient_page(struct ps_spec *spec);
108 
109 /*
110  * Jump table target, that writes out color PostScript file.
111  */
112 Error
_dxf_write_ps_color(RWImageArgs * iargs)113 _dxf_write_ps_color(RWImageArgs *iargs)
114 {
115         Error e;
116         e = output_ps(iargs,FULLCOLOR,PS);
117         return e;
118 }
119 /*
120  * Jump table target, that writes out gray level PostScript file.
121  */
122 Error
_dxf_write_ps_gray(RWImageArgs * iargs)123 _dxf_write_ps_gray(RWImageArgs *iargs)
124 {
125         Error e;
126         e = output_ps(iargs,GRAY,PS);
127         return e;
128 }
129 /*
130  * Jump table target, that writes out color Encapsulated PostScript file.
131  */
132 Error
_dxf_write_eps_color(RWImageArgs * iargs)133 _dxf_write_eps_color(RWImageArgs *iargs)
134 {
135         Error e;
136         e = output_ps(iargs,FULLCOLOR,EPS);
137         return e;
138 }
139 /*
140  * Jump table target, that writes out an gray level Encapsulated PostScript
141  * file.
142  */
143 Error
_dxf_write_eps_gray(RWImageArgs * iargs)144 _dxf_write_eps_gray(RWImageArgs *iargs)
145 {
146         Error e;
147         e = output_ps(iargs,GRAY,EPS);
148         return e;
149 }
150 
151 /*
152  * Write out a "ps" (PostScript), formatted image file from the specified
153  * field.  The input field should not be composite, but may be series.
154  * By the time we get called, it has been asserted that we can write
155  * the image to the device, be it ADASD or otherwise.
156  *
157  * NOTE: The semantics here differ from those for RGB images in that
158  * the frame number is ignored, a new file is always created and if
159  * given a series all images in the series are written out.
160  */
161 static Error
output_ps(RWImageArgs * iargs,int colormode,int filetype)162 output_ps(RWImageArgs *iargs, int colormode,int filetype)
163 {
164     char     imagefilename[MAX_IMAGE_NAMELEN];
165     int      firstframe, lastframe, i, series;
166     int      frames, deleteable = 0;
167     struct   ps_spec page_spec;
168     Pointer  pixels;
169     FILE     *fp = NULL;
170     Array    colors, color_map;
171     int      imageType=0;
172     RGBColor *map = NULL;
173     Type     type;
174     int      rank, shape[32];
175 
176     SizeData  image_sizes;  /* Values as found in the image object itself */
177     Field       img = NULL;
178 
179     if (iargs->adasd)
180         DXErrorGoto(ERROR_NOT_IMPLEMENTED,
181                 "PostScript format not supported on disk array");
182 
183     series = iargs->imgclass == CLASS_SERIES;
184 
185     if (series && (filetype == EPS))
186         DXErrorGoto(ERROR_DATA_INVALID,
187           "Series data cannot be written in 'Encapsulated PostScript' format");
188 
189     if ( !_dxf_GetImageAttributes ( (Object)iargs->image, &image_sizes ) )
190         goto error;
191 
192     /*
193      * Always write all frames of a series.
194      */
195     frames = (image_sizes.endframe - image_sizes.startframe + 1);
196     firstframe = 0;
197     lastframe = frames-1;
198 
199 
200     page_spec.width_dpi = 0;
201     page_spec.height_dpi = 0;
202     page_spec.page_height = 11.0;
203     page_spec.page_width = 8.5;
204     page_spec.page_orient = ORIENT_AUTO;
205     page_spec.image_height = image_sizes.height;
206     page_spec.image_width = image_sizes.width;
207     page_spec.page_margin = 0.5;
208     page_spec.gamma = 2.0;
209     if (iargs->format) {
210         if (!parse_format(iargs->format,&page_spec))
211             goto error;
212     }
213 
214    /*
215     * Get some nice statistics
216     */
217     page_spec.colormode = colormode;
218     page_spec.filetype = filetype;
219     orient_page(&page_spec);
220 
221     /*
222      * Attempt to open image file and position to start of frame(s).
223      */
224     if (iargs->pipe == NULL) {
225         /*
226          * Create an appropriate file name.
227          */
228         if (!_dxf_BuildImageFileName(imagefilename,MAX_IMAGE_NAMELEN,
229                         iargs->basename, iargs->imgtyp,iargs->startframe,0))
230                 goto error;
231         if ( (fp = fopen (imagefilename, "w" )) == 0 )
232             ErrorGotoPlus1 ( ERROR_DATA_INVALID,
233                           "Can't open image file (%s)", imagefilename );
234     } else {
235         strcpy(imagefilename,"stdout");
236         fp = iargs->pipe;
237     }
238 
239     /*
240      * Write out the PostScript header, prolog and setup sections.
241      */
242     if (!put_ps_header(fp, imagefilename, frames, &page_spec) ||
243         !put_ps_prolog(fp, &page_spec) ||
244         !put_ps_setup(fp, frames, &page_spec))
245         goto bad_write;
246 
247 
248     img = iargs->image;
249     for (i=firstframe ; i<=lastframe ; i++)
250     {
251         if (series) {
252             if (deleteable) DXDelete((Object)img);
253             img = _dxf_GetFlatSeriesImage((Series)iargs->image,i,
254                         page_spec.image_width,page_spec.image_height,
255                         &deleteable);
256             if (!img)
257                 goto error;
258         }
259 
260         colors = (Array)DXGetComponentValue(img, "colors");
261         if (! colors)
262         {
263             DXSetError(ERROR_DATA_INVALID,
264                 "image does not contain colors component");
265             goto error;
266         }
267 
268         DXGetArrayInfo(colors, NULL, &type, NULL, &rank, shape);
269 
270         if (type == TYPE_FLOAT)
271         {
272             if (rank != 1 || shape[0] != 3)
273             {
274                 DXSetError(ERROR_DATA_INVALID,
275                     "floating-point colors component must be 3-vector");
276                 goto error;
277             }
278 
279             imageType = FLOAT_COLOR;
280         }
281         else if (type == TYPE_UBYTE)
282         {
283             if (rank == 0 || (rank == 1 && shape[0] == 1))
284             {
285                 color_map = (Array)DXGetComponentValue(img, "color map");
286                 if (! color_map)
287                 {
288                     DXSetError(ERROR_DATA_INVALID,
289                         "single-valued ubyte colors component requires a %s",
290                         "color map");
291                     goto error;
292                 }
293 
294                 DXGetArrayInfo(color_map, NULL, &type, NULL, &rank, shape);
295 
296                 if (type != TYPE_FLOAT || rank != 1 || shape[0] != 3)
297                 {
298                     DXSetError(ERROR_DATA_INVALID,
299                         "color map must be floating point 3-vectors");
300                     goto error;
301                 }
302 
303                 map = (RGBColor *)DXGetArrayData(color_map);
304                 imageType = MAPPED_COLOR;
305             }
306             else if (rank != 1 || shape[0] != 3)
307             {
308                 DXSetError(ERROR_DATA_INVALID,
309                     "unsigned byte colors component must be either single %s",
310                     "valued with a color map or 3-vectors");
311                 goto error;
312             }
313             else
314                 imageType = UBYTE_COLOR;;
315         }
316 
317         if (!(pixels = DXGetArrayData(colors)))
318             goto error;
319 
320         /* Put out what ever is necessary for a new page */
321         if (!ps_new_page(fp, i+1,frames, &page_spec))
322            goto bad_write;
323 
324         /*
325          * Write out the pixel data
326          */
327         if (page_spec.colormode == FULLCOLOR) {
328             if (!ps_out_flc(fp, pixels, map, imageType, &page_spec))
329                 goto bad_write;
330         }
331         else if (!ps_out_gry(fp, pixels, map, imageType,  &page_spec))
332             goto bad_write;
333 
334         /* Put out what ever is necessary to close a page */
335         if (!ps_end_page(fp))
336            goto bad_write;
337     }
338 
339     /*
340      * Write out anything that is needed to end the file.  This may work
341      * as a compliment to some of what is done in pu_ps_header(),
342      * put_ps_prolog() and/or put_ps_setup().
343      */
344     if (!put_ps_trailer(fp,&page_spec))
345         goto bad_write;
346 
347     if (fclose(fp) != 0)
348         goto bad_write;
349 
350     if (deleteable && img) DXDelete((Object)img);
351 
352     return OK;
353 
354 bad_write:
355     if ( iargs->pipe == NULL )
356         DXErrorGoto
357             ( ERROR_DATA_INVALID,
358               "Can't write PostScript file." )
359     else
360         DXErrorGoto
361             ( ERROR_BAD_PARAMETER,
362               "Can't send image with specified command." );
363 
364 error:
365     if ( fp ) fclose(fp);
366     if (deleteable && img) DXDelete((Object)img);
367     return ERROR;
368 }
369 
370 /*
371  * Put out anything that is considered document 'setup' (i.e. created
372  * a global dictionary, scale/rotate/translate the origin, define global
373  * variables...).
374  *
375  */
376 static Error
put_ps_setup(FILE * fout,int frames,struct ps_spec * spec)377 put_ps_setup(FILE *fout, int frames, struct ps_spec *spec)
378 {
379     int bytesperpix;
380 
381     bytesperpix = (spec->colormode == FULLCOLOR) ? 3 : 1;
382 
383     if (fprintf(fout,"%%%%BeginSetup\n\n") < 0)
384         goto bad_write;
385 
386     LINEOUT("DXDict begin"              );
387     LINEOUT(""                          );
388     LINEOUT("%% inch scaling"           );
389 
390     if (fprintf(fout,"/inch {%d mul} bind def\n\n", UPI) < 0)
391         goto bad_write;
392 
393     if (fprintf(fout,"/bytesperpix %d def\n", bytesperpix) < 0)
394         goto bad_write;
395 
396     if (fprintf(fout,"%%%%EndSetup\n\n") < 0)
397         goto bad_write;
398 
399    return OK;
400 
401 bad_write:
402     DXErrorGoto(ERROR_DATA_INVALID, "Can't write PostScript file.")
403 
404 error:
405    return ERROR;
406 }
407 /*
408  * Write out PS code to set up the page for an image of given width and height.
409  */
410 static Error
put_ps_page_setup(FILE * fout,struct ps_spec * spec)411 put_ps_page_setup(FILE *fout, struct ps_spec *spec)
412 {
413     if (fprintf(fout,"%%%%BeginPageSetup\n\n") < 0)
414         goto error;
415 
416 
417     if (fprintf(fout,"/pixperrow %d store\n",spec->image_width) < 0)
418         goto error;
419     if (fprintf(fout,"/nrows %d store\n",spec->image_height) < 0)
420         goto error;
421 
422     LINEOUT("/outrow pixperrow bytesperpix mul string def");
423     LINEOUT("/grayrow pixperrow string def"               );
424 
425     if ((fprintf(fout,"%% Number of pixels/inch in image width\n/wppi %d def\n",
426                                                 spec->width_dpi) <= 0) ||
427        (fprintf(fout,"%% Number of pixels/inch in image height\n/hppi %d def\n",
428                                                 spec->height_dpi) <= 0) ||
429         (fprintf(fout,"%% Size of output in inches\n/width %f def\n",
430                                 spec->page_width ) <= 0)                ||
431         (fprintf(fout,"/height %f def\n", spec->page_height) <= 0)      ||
432         (fprintf(fout,"%% Size of image in units\n"
433                       "/iwidth  1 inch wppi div %d mul def\n",
434                                                 spec->image_width) <= 0)  ||
435         (fprintf(fout,"/iheight 1 inch hppi div %d mul def\n",
436                                                 spec->image_height) <= 0))
437         goto error;
438 
439     if (spec->page_orient == LANDSCAPE) {
440         if ((fprintf(fout,"%% Rotate and translate into Landscape mode\n")
441                                                         <= 0) ||
442             (fprintf(fout,"90 rotate\n0 width neg inch cvi translate\n\n")
443                                                         <= 0))
444             goto error;
445     }
446 
447     if ((fprintf(fout,"%% Locate lower left corner of image(s)\n") < 0))
448         goto error;
449     if (spec->page_orient == LANDSCAPE) {
450         if (fprintf(fout, "height inch iwidth  sub 2 div cvi\n"
451                           "width  inch iheight sub 2 div cvi\n"
452                           "translate\n\n") <= 0)
453             goto error;
454     } else {
455         if (fprintf(fout, "width  inch iwidth  sub 2 div cvi\n"
456                           "height inch iheight sub 2 div cvi\n"
457                           "translate\n\n") <= 0)
458             goto error;
459     }
460 
461     if ((fprintf(fout,"%% Image size units \niwidth iheight scale\n\n") <= 0) ||
462         (fprintf(fout,"%%%%EndPageSetup\n\n") <= 0))
463         goto error;
464 
465 
466     return OK;
467 bad_write:
468     DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
469 error:
470     DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
471 }
472 
473 /*
474  * If doing full color images, put out code to define the 'colorimage'
475  * function if it is not available.
476  *
477  */
478 static Error
put_ps_prolog(FILE * fout,struct ps_spec * spec)479 put_ps_prolog(FILE *fout, struct ps_spec *spec)
480 {
481     int bytesperpix=1;
482 
483         if (fprintf(fout,"%%%%BeginProlog\n") <= 0) goto error;
484 
485         if (fprintf(fout,"%%%%BeginResource: procset DXProcs 1.0 0\n") <= 0)
486             goto error;
487 
488         if (fprintf(fout,"/origstate save def\n") <= 0) goto error;
489         if (fprintf(fout,"/DXDict 25 dict def\n") <= 0) goto error;
490         if (fprintf(fout,"DXDict begin\n\n") <= 0) goto error;
491 
492         if (spec->colormode == FULLCOLOR) {
493                 if (!put_colorimage_function(fout))            goto error;
494                 bytesperpix = 3;
495         }
496 
497         LINEOUT("/buffer 1 string def"                             );
498         LINEOUT("/count 0 def"                                     );
499 
500         if (fprintf(fout,"/rgbval %d string def\n\n", bytesperpix) <= 0)
501                 goto error;
502 
503         LINEOUT("/rlerow {"                                        );
504         LINEOUT("  /count 0 store"                                 );
505         LINEOUT("  {"                                              );
506 
507         if (bytesperpix == 1)
508         {
509             if (fprintf(fout,"    count   pixperrow   ge\n") <= 0)
510                 goto error;
511         }
512         else
513         {
514             if (fprintf(fout,"    count   pixperrow %d mul   ge\n", bytesperpix) <= 0)
515                 goto error;
516         }
517 
518         LINEOUT("      {exit} if   %% end of row"                  );
519         LINEOUT("    currentfile buffer readhexstring   pop"       );
520         LINEOUT("    /bcount exch 0 get store"                     );
521         LINEOUT("    bcount 128 ge"                                );
522         LINEOUT("    {"                                            );
523         LINEOUT("      %% not a run block"                         );
524         LINEOUT("      bcount 128 sub {"                           );
525         LINEOUT("        currentfile rgbval readhexstring pop pop" );
526         LINEOUT("        outrow count rgbval putinterval"          );
527 
528         if (fprintf(fout,"        /count count %d add store\n", bytesperpix) <= 0)
529                 goto error;
530 
531         LINEOUT("      } repeat"                                   );
532         LINEOUT("    }"                                            );
533         LINEOUT("    {"                                            );
534         LINEOUT("      %% run block"                               );
535         LINEOUT("      currentfile rgbval readhexstring pop pop"   );
536         LINEOUT("      bcount {"                                   );
537         LINEOUT("        outrow count rgbval putinterval"          );
538 
539         if (fprintf(fout,"        /count count %d add store\n", bytesperpix) <= 0)
540                 goto error;
541 
542         LINEOUT("      } repeat"                                   );
543         LINEOUT("    } ifelse"                                     );
544         LINEOUT("  } loop  %% until end of row"                    );
545         LINEOUT("  outrow"                                         );
546         LINEOUT("} bind def"                                       );
547         LINEOUT("end  %% DXDict"                                   );
548         LINEOUT(""                                                 );
549 
550         if (fprintf(fout,"%%%%EndResource\n") <= 0) goto error;
551 
552         if (fprintf(fout,"%%%%EndProlog\n\n") <= 0) goto error;
553         return OK;
554 bad_write:
555     DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
556 error:
557         return ERROR;
558 }
559 
560 
561 /*
562  * Output everything in a PostScript file up to and including the
563  * '%%EndComments' structuring comment.  When doing Encapsulated
564  * PostScript, this must include the '%%BoundingBox:...' comment.
565  *
566  * Always returns OK.
567  */
568 static Error
put_ps_header(FILE * fout,char * filename,int frames,struct ps_spec * spec)569 put_ps_header(FILE *fout, char *filename, int frames, struct ps_spec *spec)
570 {
571    const time_t t = time(0);
572    char *tod = ctime((const time_t *)&t);
573    int major, minor, micro;
574 
575    if (spec->filetype == PS) {
576       if (fprintf(fout, "%s", "%!PS-Adobe-3.0\n") <= 0) goto error;
577    } else {     /* Encapsulated PostScript */
578       /* Required for EPSF-3.0  */
579       if (fprintf(fout, "%s", "%!PS-Adobe-3.0 EPSF-3.0\n") <= 0) goto error;
580    }
581 
582    DXVersion(&major, &minor, &micro);
583    if (fprintf(fout, "%%%%Creator: IBM/Data Explorer %d.%d.%d\n",
584                                         major,minor,micro) <= 0) goto error;
585    if (fprintf(fout, "%%%%CreationDate: %s", tod) <= 0) goto error;
586    if (fprintf(fout, "%%%%Title:  %s\n",  filename) <= 0) goto error;
587    if (fprintf(fout, "%%%%Pages: %d\n", frames) <= 0) goto error;
588 
589    if (spec->filetype == EPS) {
590       /* Put a Bounding Box specification, required for EPSF-3.0  */
591       int beginx, beginy, endx, endy;
592 
593       float wsize = UPI*spec->image_width / spec->width_dpi;
594       float hsize = UPI*spec->image_height / spec->height_dpi;
595 
596       if (spec->page_orient == LANDSCAPE) {
597           beginx = (spec->page_width  * UPI - hsize)/2 - .5;
598           beginy = (spec->page_height * UPI - wsize)/2 - .5;
599           endx = beginx + hsize + 1.0;
600           endy = beginy + wsize + 1.0;
601       } else {
602           beginx = (spec->page_width  * UPI - wsize)/2 - .5;
603           beginy = (spec->page_height * UPI - hsize)/2 - .5;
604           endx = beginx + wsize + 1.0;
605           endy = beginy + hsize + 1.0;
606       }
607       if (fprintf(fout, "%%%%BoundingBox: %d %d %d %d\n",
608                                 beginx,beginy,endx,endy) <= 0)
609         goto error;
610    }
611 
612    if (fprintf(fout, "%%%%EndComments\n\n") <= 0) goto error;
613 
614    return OK;
615 
616 error:
617     DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
618 }
619 
620 
621 /********  RLE encoding routines  ******************************************/
622 /********  Modified from buffer.c ******************************************/
623 
624 #define DO_COMPRESSION 1
625 
626 #define CHARS_PER_LINE 80
627 
628 #define HEX "0123456789abcdef"
629 #define HEX1(b) (HEX[(b)/16])
630 #define HEX2(b) (HEX[(b)%16])
631 
632 #define ADD_HEX(s, b, nn, binary)         \
633     if (binary == RLE_ASCII) {            \
634 	*s++ = HEX1(b);                   \
635 	*s++ = HEX2(b);                   \
636 	nn += 2;                          \
637 	if (!((nn+1)%(CHARS_PER_LINE+1))) \
638 	    { *s++ = '\n'; nn += 1; }     \
639     } else {                              \
640 	*s++ = b;                         \
641 	nn++;                             \
642     }
643 
644 /***************************************************************************/
645 #define CMP(A,B)       (((char *)(A))[0] == ((char *)(B))[0] && \
646                         ((char *)(A))[1] == ((char *)(B))[1] && \
647                         ((char *)(A))[2] == ((char *)(B))[2])
648 #define ASGN(A,B)      (((char *)(A))[0] =  ((char *)(B))[0], \
649                         ((char *)(A))[1] =  ((char *)(B))[1], \
650                         ((char *)(A))[2] =  ((char *)(B))[2], \
651                         ((char *)(A))[3] =  ((char *)(B))[3])
652 #define PIXSIZE         3
653 #define ENCODE_NAME     encode_24bit_row
654 /***************************************************************************/
ENCODE_NAME(ubyte * pix_row,int n_pix,ubyte * enc_row,int * n_out_bytes,int binary,int order,int compact)655 static Error ENCODE_NAME(ubyte *pix_row, int n_pix,
656                        ubyte *enc_row, int *n_out_bytes, int binary, int order, int compact)
657 {
658     ubyte  *start_p, *p;
659     int    start_i,  i, knt, size, k;
660     int    out_length;
661     int    x, y;
662     int    image_size;
663     int    totknt;
664     ubyte  *segptr;
665     int    max_knt = 127;
666 
667     x = n_pix;
668     y = 1;
669     image_size = x*y;
670     segptr = enc_row;
671     start_p = pix_row;
672     start_i = 0;
673     totknt = 0;
674 
675     if (compact == RLE_STUPID)
676 	max_knt = 256;
677 
678     while (start_i < image_size)
679     {
680         /*
681          * Look for run of identical pixels
682          */
683         i = start_i + 1;
684         p = start_p + PIXSIZE;
685 
686         while (i < image_size)
687         {
688             if (! CMP(start_p, p))
689                 break;
690 
691             i++;
692             p += PIXSIZE;
693         }
694 
695         knt = i - start_i;
696 
697         /*
698          * if knt == 1 then two adjacent pixels differ.  so instead we
699          * look for a run of differing pixels, broken when three
700          * identical pixels are found.
701          */
702         if (knt == 1)
703         {
704             /*
705              * terminate this loop before the comparison goes off
706              * the end of the image.
707              */
708             while ((i < image_size - 2) &&
709 		    (!CMP(p+0, p+PIXSIZE) || !CMP(p+0, p+2*PIXSIZE)))
710                 i++, p += PIXSIZE;
711 
712             /*
713              * Don't bother with rle for last couple of pixels
714              */
715             if (i == image_size-2)
716                 i = image_size;
717 
718             knt = i - start_i;
719 
720             /*
721              * loop parcelling out total run in as many packets
722              * as are necessary
723              */
724             while (knt > 0)
725             {
726                 /*
727                  * Limit run length to packet size
728                  */
729 		int j;
730                 int length = (knt > max_knt) ? max_knt : knt;
731                 int size = length * PIXSIZE;
732 
733                 /*
734                  * decrement total run length by packet run length
735                  */
736                 knt -= length;
737 
738 		if (compact == RLE_COMPACT)
739 		{
740 		    if (order == RLE_COUNT_PRE) {
741 			ADD_HEX(segptr,(0x80 | length), (*n_out_bytes), binary);
742 		    }
743 		    for (k=0; k<size; k++)
744 		    {
745 			ADD_HEX(segptr, (*start_p), (*n_out_bytes), binary);
746 			start_p++;
747 		    }
748 		    if (order == RLE_COUNT_POST) {
749 			ADD_HEX(segptr,(0x80 | length), (*n_out_bytes), binary);
750 		    }
751 		} else for (j=0; j<length; j++) {
752 		    if (order == RLE_COUNT_PRE) {
753 			ADD_HEX(segptr, 0, (*n_out_bytes), binary);
754 		    }
755 		    for (k=0; k<PIXSIZE; k++) {
756 			ADD_HEX(segptr, (*start_p), (*n_out_bytes), binary);
757 			start_p++;
758 		    }
759 		    if (order == RLE_COUNT_POST) {
760 			ADD_HEX(segptr, 0, (*n_out_bytes), binary);
761 		    }
762 		}
763             }
764         }
765         else
766         {
767 
768             while (knt > 0)
769             {
770                 /*
771                  * Limit run length to packet size
772                  */
773                 int length = (knt > max_knt) ? max_knt : knt;
774                 size = PIXSIZE;
775 
776                 /*
777                  * decrement total run length by packet run length
778                  */
779                 knt -= length;
780 
781 		out_length = length;
782 		if (compact == RLE_STUPID) {
783 		    out_length--;
784 		}
785 
786 		if (order == RLE_COUNT_PRE) {
787 		    ADD_HEX(segptr, out_length, (*n_out_bytes), binary);
788 		}
789 		for (k=0; k<size; k++)
790 		{
791 		    ADD_HEX(segptr, (*start_p), (*n_out_bytes), binary);
792 		    start_p++;
793 		}
794 		if (order == RLE_COUNT_POST) {
795 		    ADD_HEX(segptr, out_length, (*n_out_bytes), binary);
796 		}
797 
798             }
799         }
800 
801         start_i = i;
802         start_p = p;
803     }
804 
805     DXDebug("Y", "compaction: %d bytes in %d bytes out",
806                                 image_size*PIXSIZE, totknt);
807 
808     *segptr = '\0';
809     return totknt;
810 
811 }
812 
813 /***************************************************************************/
814 #undef CMP
815 #undef ASGN
816 #undef PIXSIZE
817 #undef ENCODE_NAME
818 
819 #define CMP(A,B)        (*((ubyte *)(A)) == *((ubyte *)(B)))
820 #define ASGN(A,B)       (*((ubyte *)(A)) = *((ubyte *)(B)))
821 #define PIXSIZE         1
822 #define ENCODE_NAME     encode_8bit_row
823 /***************************************************************************/
ENCODE_NAME(ubyte * pix_row,int n_pix,ubyte * enc_row,int * n_out_bytes,int binary,int order,int compact)824 static Error ENCODE_NAME(ubyte *pix_row, int n_pix,
825                        ubyte *enc_row, int *n_out_bytes, int binary, int order, int compact)
826 {
827     ubyte *start_p, *p;
828     int    start_i,  i, knt, size, k;
829     int    out_length;
830     int    x, y;
831     int    image_size;
832     int    totknt;
833     ubyte  *segptr;
834     int    max_knt = 127;
835 
836     x = n_pix;
837     y = 1;
838     image_size = x*y;
839     segptr = enc_row;
840     start_p = pix_row;
841     start_i = 0;
842     totknt = 0;
843 
844     if (compact == RLE_STUPID)
845 	max_knt = 256;
846 
847     while (start_i < image_size)
848     {
849         /*
850          * Look for run of identical pixels
851          */
852         i = start_i + 1;
853         p = start_p + PIXSIZE;
854 
855         while (i < image_size)
856         {
857             if (! CMP(start_p, p))
858                 break;
859 
860             i++;
861             p += PIXSIZE;
862         }
863 
864         knt = i - start_i;
865 
866         /*
867          * if knt == 1 then two adjacent pixels differ.  so instead we
868          * look for a run of differing pixels, broken when three
869          * identical pixels are found.
870          */
871         if (knt == 1)
872         {
873             /*
874              * terminate this loop before the comparison goes off
875              * the end of the image.
876              */
877             while ((!CMP(p+0, p+PIXSIZE) ||
878                     !CMP(p+0, p+2*PIXSIZE)) && i < image_size - 2)
879                 i++, p += PIXSIZE;
880 
881             /*
882              * Don't bother with rle for last couple of pixels
883              */
884             if (i == image_size-2)
885                 i = image_size;
886 
887             knt = i - start_i;
888 
889             /*
890              * loop parcelling out total run in as many packets
891              * as are necessary
892              */
893             while (knt > 0)
894             {
895                 /*
896                  * Limit run length to packet size
897                  */
898                 int length = (knt > max_knt) ? max_knt : knt;
899                 int size = length * PIXSIZE;
900 
901                 /*
902                  * decrement total run length by packet run length
903                  */
904                 knt -= length;
905 
906 		if (compact == RLE_COMPACT)
907 		{
908 		    if (order == RLE_COUNT_PRE) {
909 			ADD_HEX(segptr,(0x80 | length), (*n_out_bytes), binary);
910 		    }
911 		    for (k=0; k<size; k++)
912 		    {
913 			ADD_HEX(segptr, (*start_p), (*n_out_bytes), binary);
914 			start_p++;
915 		    }
916 		    if (order == RLE_COUNT_POST) {
917 			ADD_HEX(segptr,(0x80 | length), (*n_out_bytes), binary);
918 		    }
919 		} else {
920 		    for (k=0; k<length; k++)
921 		    {
922 			if (order == RLE_COUNT_PRE) {
923 			    ADD_HEX(segptr, 0, (*n_out_bytes), binary);
924 			}
925 			ADD_HEX(segptr, (*start_p), (*n_out_bytes), binary);
926 			start_p++;
927 			if (order == RLE_COUNT_POST) {
928 			    ADD_HEX(segptr, 0, (*n_out_bytes), binary);
929 			}
930 		    }
931 		}
932             }
933         }
934         else
935         {
936 
937             while (knt > 0)
938             {
939                 /*
940                  * Limit run length to packet size
941                  */
942                 int length = (knt > max_knt) ? max_knt : knt;
943                 size = PIXSIZE;
944 
945                 /*
946                  * decrement total run length by packet run length
947                  */
948                 knt -= length;
949 
950 		out_length = length;
951 		if (compact == RLE_STUPID) {
952 		    out_length--;
953 		}
954 
955 		if (order == RLE_COUNT_PRE) {
956 		    ADD_HEX(segptr, out_length, (*n_out_bytes), binary);
957 		}
958                 for (k=0; k<size; k++)
959                 {
960                     ADD_HEX(segptr, (*start_p), (*n_out_bytes), binary);
961                     start_p++;
962                 }
963 		if (order == RLE_COUNT_POST) {
964 		    ADD_HEX(segptr, out_length, (*n_out_bytes), binary);
965 		}
966 
967             }
968         }
969 
970         start_i = i;
971         start_p = p;
972     }
973 
974     DXDebug("Y", "compaction: %d bytes in %d bytes out",
975                                 image_size*PIXSIZE, totknt);
976 
977 
978     *segptr = '\0';
979     return totknt;
980 
981 }
982 /***************************************************************************/
983 #undef CMP
984 #undef ASGN
985 #undef PIXSIZE
986 #undef ENCODE_NAME
987 /***************************************************************************/
988 
989 
build_rle_row(ubyte * r,int n_pixels,int bytes_per_pixel,int compress,ubyte * buff,int * byte_count,int binary,int order,int compact)990 static Error build_rle_row(ubyte *r, int n_pixels, int bytes_per_pixel,
991                         int compress, ubyte *buff, int *byte_count, int binary, int order, int compact)
992 {
993     int i;
994 
995     if (compress) {
996         if (bytes_per_pixel==1)
997             encode_8bit_row(r, n_pixels, buff, byte_count, binary, order, compact);
998           else
999             encode_24bit_row(r, n_pixels, buff, byte_count, binary, order, compact);
1000     }
1001     else
1002         for (i=0; i<n_pixels*bytes_per_pixel; i++) {
1003             ADD_HEX(buff, (*r), (*byte_count), RLE_ASCII);
1004             r++;
1005         }
1006     return OK;
1007 }
1008 
1009 
1010 #define CLAMP(p) ( ( (P=(p)) < 0 ) ? 0 : (P<=255) ? P : 255 )
1011 
1012 /*
1013  * This routine writes out the full color image data to the PostScript
1014  * file.  Each line of the image is written out in R, G and B
1015  * to records of length 80.
1016  *
1017  * Note, that PostScript expects its pixels from left to right and
1018  * top to bottom, just the way DX keeps them stored.
1019  *
1020  * Returns OK/ERROR on failure/success.
1021  */
1022 static Error
ps_out_flc(FILE * fout,Pointer pixels,RGBColor * map,int imageType,struct ps_spec * spec)1023 ps_out_flc(FILE *fout, Pointer pixels,
1024         RGBColor *map, int imageType, struct ps_spec *spec)
1025 {
1026    int i, j, P;
1027    ubyte *RGBbuff=NULL, *RGBptr;
1028    char *encbuff=NULL;
1029    int encbuff_size, RGBbuff_size;
1030    int byte_count;
1031    int row_str_length;
1032    ubyte gamma_table[256];
1033 
1034    spec->compress = DO_COMPRESSION;
1035 
1036    _dxf_make_gamma_table(gamma_table, spec->gamma);
1037 
1038    if (!ps_image_header(fout, spec))
1039         goto error;
1040 
1041    RGBbuff_size = spec->image_width*3;
1042    RGBbuff = DXAllocate(RGBbuff_size);
1043 
1044    /* This is a worst-case row buffer size for no runs */
1045    encbuff_size = RGBbuff_size*128*2/127;
1046    /* now add room for newlines and some spare         */
1047    encbuff_size += encbuff_size/CHARS_PER_LINE + 100;
1048    encbuff = DXAllocate(encbuff_size);
1049 
1050    byte_count = 0;
1051 
1052    if (imageType == FLOAT_COLOR)
1053        {
1054            RGBColor *fpixels = (RGBColor *)pixels;
1055            for (i=0; i<spec->image_height; i++) {
1056                for (j=0, RGBptr = RGBbuff; j<spec->image_width; j++, fpixels++) {
1057                   float r = fpixels->r * 255;
1058                   float g = fpixels->g * 255;
1059                   float b = fpixels->b * 255;
1060                   *RGBptr++  = gamma_table[CLAMP(r)];
1061                   *RGBptr++  = gamma_table[CLAMP(g)];
1062                   *RGBptr++  = gamma_table[CLAMP(b)];
1063                }
1064                build_rle_row(RGBbuff, spec->image_width, 3,
1065                             spec->compress, (ubyte *)encbuff, &byte_count, RLE_ASCII, RLE_COUNT_PRE, RLE_COMPACT);
1066                row_str_length = strlen(encbuff);
1067                if (fprintf(fout, "%s", encbuff) != row_str_length)
1068                    goto error;
1069 
1070                /* force newlines after each row if no compression */
1071                if (!spec->compress)
1072                {
1073                    if ((encbuff) && (*encbuff) && (encbuff[strlen(encbuff)-1] != '\n')
1074                        && (fprintf(fout,"\n") != 1))
1075                            goto error;
1076                    byte_count = 0;
1077                }
1078            }
1079        }
1080        else if (imageType == UBYTE_COLOR)
1081        {
1082            RGBByteColor *upixels = (RGBByteColor *)pixels;
1083 
1084            for (i=0; i<spec->image_height; i++) {
1085                for (j=0, RGBptr = RGBbuff; j<spec->image_width; j++, upixels++) {
1086                   *RGBptr++  = gamma_table[upixels->r];
1087                   *RGBptr++  = gamma_table[upixels->g];
1088                   *RGBptr++  = gamma_table[upixels->b];
1089                }
1090                build_rle_row(RGBbuff, spec->image_width, 3,
1091                             spec->compress, (ubyte *)encbuff, &byte_count, RLE_ASCII, RLE_COUNT_PRE, RLE_COMPACT);
1092                row_str_length = strlen(encbuff);
1093                if (fprintf(fout, "%s", encbuff) != row_str_length)
1094                    goto error;
1095 
1096                /* force newlines after each row if no compression */
1097                if (!spec->compress)
1098                {
1099                    if ((encbuff) && (*encbuff) && (encbuff[strlen(encbuff)-1] != '\n')
1100                        && (fprintf(fout,"\n") != 1))
1101                            goto error;
1102                    byte_count = 0;
1103                }
1104            }
1105        }
1106        else
1107        {
1108            ubyte *upixels = (ubyte *)pixels;
1109 
1110            for (i=0; i<spec->image_height; i++) {
1111                for (j=0, RGBptr = RGBbuff; j<spec->image_width; j++, upixels++) {
1112                   float r = map[*upixels].r * 255;
1113                   float g = map[*upixels].g * 255;
1114                   float b = map[*upixels].b * 255;
1115                   *RGBptr++  = gamma_table[CLAMP(r)];
1116                   *RGBptr++  = gamma_table[CLAMP(g)];
1117                   *RGBptr++  = gamma_table[CLAMP(b)];
1118                }
1119                build_rle_row(RGBbuff, spec->image_width, 3,
1120                             spec->compress, (ubyte *)encbuff, &byte_count, RLE_ASCII, RLE_COUNT_PRE, RLE_COMPACT);
1121                row_str_length = strlen(encbuff);
1122                if (fprintf(fout, "%s", encbuff) != row_str_length)
1123                    goto error;
1124 
1125                /* force newlines after each row if no compression */
1126                if (!spec->compress)
1127                {
1128                    if ((encbuff) && (*encbuff) && (encbuff[strlen(encbuff)-1] != '\n')
1129                        && (fprintf(fout,"\n") != 1))
1130                            goto error;
1131                    byte_count = 0;
1132                }
1133            }
1134        }
1135 
1136    if (fprintf(fout,"\n") != 1)
1137        goto error;
1138 
1139    DXFree(RGBbuff);
1140    DXFree(encbuff);
1141    return OK;
1142 error:
1143    DXFree(RGBbuff);
1144    DXFree(encbuff);
1145    DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
1146 }
1147 
1148 
1149 /*
1150  * This routine converts the RGB pixels to gray levels and writes out 8bits
1151  * per pixel to the PostScript.
1152  *
1153  * Note, that PostScript expects its pixels from left to right and
1154  * top to bottom, just the way DX keeps them stored.
1155  *
1156  * Returns OK/ERROR on failure/success.
1157  */
1158 static Error
ps_out_gry(FILE * fout,Pointer pixels,RGBColor * map,int imageType,struct ps_spec * spec)1159 ps_out_gry(FILE *fout,
1160         Pointer pixels, RGBColor *map, int imageType, struct ps_spec *spec)
1161 {
1162    int i, j, P;
1163    ubyte *BWbuff=NULL, *BWptr;
1164    char *encbuff=NULL;
1165    int encbuff_size, BWbuff_size;
1166    int byte_count;
1167    int row_str_length;
1168    ubyte gamma_table[256];
1169    float f;
1170    float g;
1171 
1172    spec->compress = DO_COMPRESSION;
1173 
1174    g = 1.0/spec->gamma;
1175    for (i=0; i<256; i++) {
1176        f = i/255.0;
1177        gamma_table[i] = 255*pow(f, g);
1178    }
1179 
1180    if (!ps_image_header(fout, spec))
1181         goto error;
1182 
1183    BWbuff_size = spec->image_width;
1184    BWbuff = DXAllocate(BWbuff_size);
1185 
1186    /* This is a worst-case row buffer size for no runs */
1187    encbuff_size = spec->image_width*128*2/127;
1188    /* now add room for newlines and some spare         */
1189    encbuff_size += encbuff_size/CHARS_PER_LINE + 100;
1190    encbuff = DXAllocate(encbuff_size);
1191 
1192    byte_count = 0;
1193 
1194    if (imageType == FLOAT_COLOR)
1195        {
1196            RGBColor *fpixels = (RGBColor *)pixels;
1197            for (i=0; i<spec->image_height; i++) {
1198                for (j=0, BWptr = BWbuff; j<spec->image_width; j++, fpixels++) {
1199                   float r = fpixels->r;
1200                   float g = fpixels->g;
1201                   float b = fpixels->b;
1202                   float gray = RGB_TO_BW(r, g, b) * 255;
1203                   *BWptr++  = gamma_table[CLAMP(gray)];
1204                }
1205                build_rle_row(BWbuff, spec->image_width, 1,
1206                             spec->compress, (ubyte *)encbuff, &byte_count, RLE_ASCII, RLE_COUNT_PRE, RLE_COMPACT);
1207                row_str_length = strlen(encbuff);
1208                if (fprintf(fout, "%s", encbuff) != row_str_length)
1209                    goto error;
1210 
1211                /* force newlines after each row if no compression */
1212                if (!spec->compress)
1213                {
1214                    if ((encbuff) && (*encbuff) && (encbuff[strlen(encbuff)-1] != '\n')
1215                        && (fprintf(fout,"\n") != 1))
1216                            goto error;
1217                    byte_count = 0;
1218                }
1219            }
1220        }
1221        else if (imageType == UBYTE_COLOR)
1222        {
1223            RGBByteColor *upixels = (RGBByteColor *)pixels;
1224 
1225            for (i=0; i<spec->image_height; i++) {
1226                for (j=0, BWptr = BWbuff; j<spec->image_width; j++, upixels++) {
1227                   float r = upixels->r;
1228                   float g = upixels->g;
1229                   float b = upixels->b;
1230                   float gray = RGB_TO_BW(r, g, b);
1231                   *BWptr++  = gamma_table[CLAMP(gray)];
1232                }
1233                build_rle_row(BWbuff, spec->image_width, 1,
1234                             spec->compress, (ubyte *)encbuff, &byte_count, RLE_ASCII, RLE_COUNT_PRE, RLE_COMPACT);
1235                row_str_length = strlen(encbuff);
1236                if (fprintf(fout, "%s", encbuff) != row_str_length)
1237                    goto error;
1238 
1239                /* force newlines after each row if no compression */
1240                if (!spec->compress)
1241                {
1242                    if ((encbuff) && (*encbuff) && (encbuff[strlen(encbuff)-1] != '\n')
1243                        && (fprintf(fout,"\n") != 1))
1244                            goto error;
1245                    byte_count = 0;
1246                }
1247            }
1248        }
1249        else
1250        {
1251            ubyte *upixels = (ubyte *)pixels;
1252 
1253            for (i=0; i<spec->image_height; i++) {
1254                for (j=0, BWptr = BWbuff; j<spec->image_width; j++, upixels++) {
1255                   float r = map[*upixels].r;
1256                   float g = map[*upixels].g;
1257                   float b = map[*upixels].b;
1258                   float gray = RGB_TO_BW(r, g, b) * 255;
1259                   *BWptr++  = gamma_table[CLAMP(gray)];
1260                }
1261                build_rle_row(BWbuff, spec->image_width, 1,
1262                             spec->compress, (ubyte *)encbuff, &byte_count, RLE_ASCII, RLE_COUNT_PRE, RLE_COMPACT);
1263                row_str_length = strlen(encbuff);
1264                if (fprintf(fout, "%s", encbuff) != row_str_length)
1265                    goto error;
1266 
1267                /* force newlines after each row if no compression */
1268                if (!spec->compress)
1269                {
1270                    if ((encbuff) && (*encbuff) && (encbuff[strlen(encbuff)-1] != '\n')
1271                        && (fprintf(fout,"\n") != 1))
1272                            goto error;
1273                    byte_count = 0;
1274                }
1275            }
1276        }
1277 
1278    if (fprintf(fout,"\n") != 1)
1279        goto error;
1280 
1281    DXFree(BWbuff);
1282    DXFree(encbuff);
1283    return OK;
1284 error:
1285    DXFree(BWbuff);
1286    DXFree(encbuff);
1287    DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
1288 }
1289 
1290 /*
1291  * This routine writes out the trailer of the PostScript file
1292  * Undoes some of what was done in put_ps_header().
1293  */
1294 static Error
put_ps_trailer(FILE * fout,struct ps_spec * spec)1295 put_ps_trailer(FILE *fout, struct ps_spec *spec)
1296 {
1297 
1298    if (fprintf(fout, "%%%%Trailer\n") <= 0)
1299         goto error;
1300    if (fprintf(fout, "\n%% Stop using temporary dictionary\nend\n\n") <= 0)
1301         goto error;
1302    if (fprintf(fout, "%% Restore original state\norigstate restore\n\n") <= 0)
1303         goto error;
1304    if (fprintf(fout, "%%%%EOF\n") <= 0)
1305         goto error;
1306    return OK;
1307 
1308 error:
1309    DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
1310 }
1311 
1312 /*
1313  * Put the arguments on the stack and call the correct imaging
1314  * function (either image or colorimage).
1315  * It is assumed that the data for the image will be written out
1316  * immediately following the output here.
1317  *
1318  * Always returns OK.
1319  */
1320 static Error
ps_image_header(FILE * fout,struct ps_spec * spec)1321 ps_image_header(FILE *fout, struct ps_spec *spec)
1322 {
1323 
1324    if (fprintf(fout,"%% Dimensionality of data\n%d %d 8\n\n",
1325                                 spec->image_width,spec->image_height) <= 0)
1326         goto error;
1327    if (fprintf(fout,"%% Mapping matrix\n[ %d 0 0 %d 0 0 ]\n\n",
1328                                 spec->image_width,spec->image_height) <= 0)
1329         goto error;
1330    if (fprintf(fout, "%% Function to read pixels\n") <= 0)
1331         goto error;
1332    if (fprintf(fout, "{ rlerow }\n") <= 0)
1333         goto error;
1334 
1335    if (spec->colormode == FULLCOLOR) {
1336         if (fprintf(fout, "false 3\t\t\t%% Single data source, 3 colors\n")<=0)
1337             goto error;
1338         if (fprintf(fout, "colorimage\n") <= 0)
1339             goto error;
1340    } else {
1341         if (fprintf(fout, "image\n") <= 0)
1342             goto error;
1343    }
1344    return OK;
1345 
1346 error:
1347    DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
1348 }
1349 
1350 /*
1351  * Write out code to test for the colorimage function and to define it
1352  * if it is not defined.
1353  */
1354 static Error
put_colorimage_function(FILE * fout)1355 put_colorimage_function(FILE *fout)
1356 {
1357     LINEOUT("%% Define colorimage procedure if not present"                   );
1358     LINEOUT("/colorimage where   %% colorimage defined?"                      );
1359     LINEOUT("  { pop }           %% yes: pop off dict returned"               );
1360     LINEOUT("  {                 %% no:  define one with grayscale conversion");
1361     LINEOUT("    /colorimage {"                                               );
1362     LINEOUT("      pop"                                                       );
1363     LINEOUT("      pop"                                                       );
1364     LINEOUT("      /hexread exch store"                                       );
1365     LINEOUT("      {"                                                         );
1366     LINEOUT("        hexread"                                                 );
1367     LINEOUT("        /rgbdata exch store    %% call input row 'rgbdata'"      );
1368     LINEOUT("        /rgbindx 0 store"                                        );
1369     LINEOUT("        0 1 pixperrow 2 sub {"                                   );
1370     LINEOUT("          grayrow exch"                                          );
1371     LINEOUT("          rgbdata rgbindx       get 19 mul"                      );
1372     LINEOUT("          rgbdata rgbindx 1 add get 38 mul"                      );
1373     LINEOUT("          rgbdata rgbindx 2 add get  7 mul"                      );
1374     LINEOUT("          add add 64 idiv"                                       );
1375     LINEOUT("          put"                                                   );
1376     LINEOUT("          /rgbindx rgbindx 3 add store"                          );
1377     LINEOUT("        } for"                                                   );
1378     LINEOUT("        grayrow  %% output row converted to grayscale"           );
1379     LINEOUT("      }"                                                         );
1380     LINEOUT("      image"                                                     );
1381     LINEOUT("    } bind def"                                                  );
1382     LINEOUT("  } ifelse"                                                      );
1383 
1384     return OK;
1385 
1386 bad_write:
1387     DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
1388     return ERROR;
1389 }
1390 
1391 /*
1392  * Called before each new image to begin a new page.
1393  */
1394 static Error
ps_new_page(FILE * fout,int page,int pages,struct ps_spec * spec)1395 ps_new_page(FILE *fout,int page, int pages, struct ps_spec *spec)
1396 {
1397         if (fprintf(fout,"\n%%%%Page: %d %d\n\n",page,pages) <= 0)
1398            goto error;
1399         if (!put_ps_page_setup(fout,spec))
1400            goto error;
1401 
1402         return OK;
1403 error:
1404     DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
1405 }
1406 
1407 /*
1408  * Called after every image to end a page.
1409  */
1410 static Error
ps_end_page(FILE * fout)1411 ps_end_page(FILE *fout)
1412 {
1413    if (fprintf(fout, "\nshowpage\n") <= 0)
1414       goto error;
1415    else
1416       return OK;
1417 error:
1418     DXErrorReturn(ERROR_DATA_INVALID, "Can't write PostScript file.");
1419 }
1420 
1421 /*
1422  * Determine the pagemode (PORTRAIT or LANDSCAPE) given the dimensions
1423  * of the image in spec.
1424  *
1425  */
1426 static void
orient_page(struct ps_spec * spec)1427 orient_page(struct ps_spec *spec)
1428 {
1429     int mode = PORTRAIT;
1430     int pagewidth_in_pixels;
1431     int pageheight_in_pixels;
1432     int badfit = 0;
1433     float wx, wy;
1434     float aspect;
1435     float page_aspect;
1436 
1437     if (!spec->width_dpi) {
1438 	wx = spec->page_width - 2*spec->page_margin;
1439 	wy = spec->page_height - 2*spec->page_margin;
1440 	page_aspect = wy/wx;
1441 	aspect = spec->image_height*1.0/spec->image_width;
1442 	if ((aspect>1 && page_aspect>1) || (aspect<1 && page_aspect<1)) {
1443 	    spec->width_dpi = spec->image_width/wx;
1444 	    spec->height_dpi = spec->image_height/wy;
1445 	} else {
1446 	    spec->width_dpi = spec->image_height/wx;
1447 	    spec->height_dpi = spec->image_width/wy;
1448 	}
1449     }
1450 
1451     pagewidth_in_pixels = spec->width_dpi * spec->page_width;
1452     pageheight_in_pixels = spec->height_dpi * spec->page_height;
1453 
1454     if (spec->image_width > pagewidth_in_pixels) {
1455         if (spec->image_height < pageheight_in_pixels) {
1456             mode = LANDSCAPE;
1457         } else
1458             badfit = 1;
1459     } else if (spec->image_height > pageheight_in_pixels) {
1460         if (spec->image_width < pagewidth_in_pixels) {
1461             mode = PORTRAIT;
1462         } else
1463             badfit = 1;
1464     }
1465 
1466     if (badfit)
1467         DXWarning("PostScript image overflows page");
1468 
1469     if (spec->page_orient == ORIENT_NOT_SET || spec->page_orient == ORIENT_AUTO)
1470         spec->page_orient = mode;
1471 
1472 }
1473 #define SKIP_WHITE(p) while (*p && (*p == ' ' || *p == '\t')) p++
1474 #define FIND_EQUAL(p) while (*p && (*p != '=')) p++
1475 
1476 static Error
parse_format(char * fmt,struct ps_spec * spec)1477 parse_format(char *fmt, struct ps_spec *spec)
1478 {
1479     char *format_modifier;
1480     float width,height;
1481     char *p;
1482     char format[1024];
1483     int i, len = strlen(fmt);
1484     int dpi_parsed = 0, width_parsed = 0;
1485     float g;
1486 
1487     if (len >= 1024) {
1488         DXSetError(ERROR_BAD_PARAMETER,"'format' too long.");
1489         return ERROR;
1490     } else {
1491         /* Copy the pattern into a lower case buffer */
1492         for (i=0 ; i<len ; i++) {
1493             char b = fmt[i];
1494             format[i] = (isupper(b) ? tolower(b) : b);
1495         }
1496         format[len] = '\0';
1497     }
1498     /*
1499      * Parse the page size.
1500      */
1501     format_modifier = "page";
1502     if ((p=strstr(format," page"))) {
1503         p += 5;
1504         SKIP_WHITE(p);
1505         if (!p) goto format_error;
1506         FIND_EQUAL(p);
1507         if (!p) goto format_error;
1508             p++;        /*  Skip the '=' */
1509             SKIP_WHITE(p);
1510             if (p && (sscanf(p,"%fx%f",&width,&height) == 2))  {
1511                 spec->page_width = width;
1512                 spec->page_height = height;
1513             } else if (p && (sscanf(p,"%fX%f",&width,&height) == 2))  {
1514                 spec->page_width = width;
1515                 spec->page_height = height;
1516             } else  {
1517                 goto format_error;
1518             }
1519     }
1520     /*
1521      * Parse the dots per inch.
1522      */
1523     format_modifier = "dpi";
1524     if ((p=strstr(format," dpi"))) {
1525         int dpi;
1526         p += 4;
1527         SKIP_WHITE(p);
1528         if (!p) goto format_error;
1529         FIND_EQUAL(p);
1530         if (!p) goto format_error;
1531             p++;        /* Skip the '=' */
1532             SKIP_WHITE(p);
1533             if (!p) goto error;
1534             if (sscanf(p,"%d",&dpi) == 1)  {
1535                 spec->width_dpi  = dpi;
1536                 spec->height_dpi = dpi;
1537             } else  {
1538                 goto format_error;
1539             }
1540             dpi_parsed = 1;
1541     }
1542     /*
1543      * Parse the gamma
1544      */
1545     format_modifier = "gamma";
1546     if ((p=strstr(format," gamma"))) {
1547         p += 4;
1548         SKIP_WHITE(p);
1549         if (!p) goto format_error;
1550         FIND_EQUAL(p);
1551         if (!p) goto format_error;
1552             p++;        /* Skip the '=' */
1553             SKIP_WHITE(p);
1554             if (!p) goto error;
1555             if (sscanf(p,"%f",&g) == 1)  {
1556                 spec->gamma  = g;
1557             } else  {
1558                 goto format_error;
1559             }
1560     }
1561     /*
1562      * Parse the page orientation.
1563      */
1564     format_modifier = "orient";
1565     if ((p=strstr(format," orient"))) {
1566         p += 7;
1567         SKIP_WHITE(p);
1568         if (!p) goto format_error;
1569         FIND_EQUAL(p);
1570         if (!p) goto format_error;
1571             p++;        /* Skip the '=' */
1572             SKIP_WHITE(p);
1573             if (p && !strncmp(p,"landscape",9)) {
1574                 spec->page_orient = LANDSCAPE;
1575             } else if (p && !strncmp(p,"portrait",8)) {
1576                 spec->page_orient = PORTRAIT;
1577             } else if (p && !strncmp(p,"auto",4)) {
1578                 spec->page_orient = ORIENT_AUTO;
1579             } else  {
1580                 goto format_error;
1581             }
1582     }
1583     /*
1584      * Parse the margin.
1585      */
1586     format_modifier = "margin";
1587     if ((p=strstr(format," margin"))) {
1588         p += 7;
1589         SKIP_WHITE(p);
1590         if (!p) goto format_error;
1591         FIND_EQUAL(p);
1592         if (!p) goto format_error;
1593             p++;        /* Skip the '=' */
1594             SKIP_WHITE(p);
1595             if (!p) goto error;
1596             if (sscanf(p,"%f",&g) == 1)  {
1597                 spec->page_margin  = g;
1598             } else  {
1599                 goto format_error;
1600             }
1601     }
1602     /*
1603      * Parse the width image dimensioning spec where width is in inches
1604      * and the width in this case means the dimension of the image that
1605      * goes across the screen.  Width indicates a resolution in both
1606      * height and width (to keep the aspect ratio the same).
1607      * This option will cause the image's width as printed to be the
1608      * given number of inches.
1609      */
1610     format_modifier = "width";
1611     if ((p=strstr(format," width"))) {
1612         p += 6;
1613         SKIP_WHITE(p);
1614         if (!p) goto format_error;
1615         FIND_EQUAL(p);
1616         if (!p) goto format_error;
1617             p++;        /* Skip the '=' */
1618             SKIP_WHITE(p);
1619             if (!p || (sscanf(p,"%f",&width) != 1))  {
1620                 goto format_error;
1621             } else if (width == 0) {
1622                 DXErrorGoto(ERROR_BAD_PARAMETER,
1623                     "PostScript 'width' must be non-zero");
1624             }
1625             width_parsed = 1;
1626             spec->height_dpi = spec->width_dpi = spec->image_width  / width;
1627             if (dpi_parsed)
1628                 DXWarning(
1629                 "'width' overrides 'dpi' PostScript format modifier");
1630     }
1631     /*
1632      * Parse the height image dimensioning spec where height is in inches
1633      * and the height in this case means the dimension of the image that
1634      * goes up and down the screen.  If 'width' was not already given
1635      * then use the same dpi in the width directoin as the height (i.e.
1636      * keep the same aspect ratio).
1637      * This option will cause the image's height as printed to be the
1638      * given number of inches.
1639      */
1640     format_modifier = "height";
1641     if ((p=strstr(format," height"))) {
1642         p += 7;
1643         SKIP_WHITE(p);
1644         if (!p) goto format_error;
1645         FIND_EQUAL(p);
1646         if (!p) goto format_error;
1647             p++;        /* Skip the '=' */
1648             SKIP_WHITE(p);
1649             if (!p || (sscanf(p,"%f",&height) != 1))  {
1650                 goto format_error;
1651             } else if (height == 0) {
1652                 DXErrorGoto(ERROR_BAD_PARAMETER,
1653                     "PostScript 'height' must be non-zero");
1654             }
1655             spec->height_dpi = spec->image_height / height;
1656             if (!width_parsed) {
1657                 spec->width_dpi = spec->height_dpi;
1658                 if (dpi_parsed)
1659                     DXWarning(
1660                     "'height' overrides 'dpi' PostScript format modifier");
1661             }
1662     }
1663 
1664     return OK;
1665 
1666 format_error:
1667     DXSetError(ERROR_BAD_PARAMETER,
1668                 "PostScript format modifier '%s' has incorrect format",
1669                         format_modifier);
1670 error:
1671     return ERROR;
1672 }
1673 
1674 static Error
put_miff_header(FILE * fout,char * filename,int frame,struct ps_spec * spec,int imageType,int nframes)1675 put_miff_header(FILE *fout, char *filename, int frame, struct ps_spec *spec, int imageType, int nframes)
1676 {
1677    const time_t t = time(0);
1678    char *tod = ctime((const time_t *)&t);
1679    int major, minor, micro;
1680 
1681    if (fprintf(fout, "id=ImageMagick\n") <= 0) goto error;
1682    if (imageType != MAPPED_COLOR) {
1683        if (fprintf(fout, "class=DirectClass\n") <= 0) goto error;
1684    } else {
1685        if (fprintf(fout, "class=PseudoClass colors=256\n") <= 0) goto error;
1686    }
1687    /*  Change gamma in the pixels themselves */
1688 #if 0
1689    if (spec->gamma != 1) {
1690        if (fprintf(fout, "gamma=%08.4f\n", spec->gamma) <= 0) goto error;
1691    }
1692 #endif
1693    if (fprintf(fout, "compression=RunlengthEncoded\n") <= 0) goto error;
1694    if (fprintf(fout, "columns=%d  rows=%d depth=8\n",
1695 			spec->image_width, spec->image_height) <= 0) goto error;
1696    if (fprintf(fout, "scene=%d\n", frame) <= 0) goto error;
1697    DXVersion(&major, &minor, &micro);
1698    if (fprintf(fout, "{\nCreated by IBM Data Explorer %d.%d.%d",
1699                                         major,minor,micro) <= 0) goto error;
1700    if (fprintf(fout, "  Date: %s", tod) <= 0) goto error;
1701    if (frame == 0) {
1702        if (fprintf(fout, "DO NOT ALTER NEXT LINE\n") <= 0) goto error;
1703        if (fprintf(fout, NSCENES_STRING) <= 0) goto error;
1704        if (fprintf(fout, "%06d\n", nframes) <= 0) goto error;
1705    }
1706    if (fprintf(fout, DATASIZE_STRING) <= 0) goto error;
1707    spec->fptr = ftell(fout);
1708    if (fprintf(fout, "%08d\n",0) <= 0) goto error;
1709    if (fprintf(fout, "}\n:\n") <= 0) goto error;
1710 
1711    return OK;
1712 
1713 error:
1714    DXErrorReturn(ERROR_DATA_INVALID, "Can't write miff file.");
1715 }
1716 
1717 #define STAT_OK           0
1718 #define STAT_DONE         1
1719 #define STAT_COMPLETE     2
1720 #define STAT_ERROR        4
1721 
1722 static int
get_token(char * b,char * t,char * v)1723 get_token(char *b, char *t, char *v)
1724 {
1725     int l;
1726     int p, q, r;
1727 
1728     *t = *v = '\0';
1729     l = strlen(b);
1730     if (!l)
1731 	return STAT_DONE;
1732     for (p = 0; p<l && isspace(b[p]); p++)
1733 	;
1734     if (b[p] == ':')
1735 	return STAT_COMPLETE;
1736     if (p == l)
1737 	return STAT_DONE;
1738     for (q = p+1; q<l && !isspace(b[q]) && b[q] != '='; q++)
1739 	;
1740     if (b[q] != '=')
1741 	return STAT_ERROR;
1742     strncpy(t, &b[p], (q-p));
1743     t[q-p] = '\0';
1744     for (q++; q<l && isspace(b[q]); q++)
1745 	;
1746     if (q == l)
1747 	return STAT_ERROR;
1748     for (r = q; r<l && !isspace(b[r]); r++)
1749 	;
1750     strncpy(v, &b[q], (r-q));
1751     v[r-q] = '\0';
1752     memmove(b, &b[r], l-r+1);
1753 
1754     return STAT_OK;
1755 }
1756 
1757 
1758 static Error
read_miff_header(FILE * fin,int * frame,struct ps_spec * spec,int * imageType,int * nframes)1759 read_miff_header(FILE *fin, int *frame, struct ps_spec *spec, int *imageType, int *nframes)
1760 {
1761 
1762     char buff[BUFFSIZE];
1763     char token[128], value[128];
1764     int  found_frames = 0;
1765     int  found_data = 0;
1766     int  status = STAT_OK;
1767     int  tmp;
1768 
1769     for (;;) {
1770 	if (!fgets(buff, BUFFSIZE, fin)) goto error;
1771 	if (strstr(buff, "{")) {
1772 	    for (;;) {
1773 		if (!fgets(buff, BUFFSIZE, fin)) goto error;
1774 		if (strstr(buff, "}"))
1775 		    break;
1776 		if (!found_frames && (1 == sscanf(buff, "nscenes=%d", &tmp))) {
1777 		    found_frames = 1;
1778 		    *nframes = tmp;
1779 		}
1780 		if (!found_data && (1 == sscanf(buff, "data_size=%d", &tmp))) {
1781 		    found_data = 1;
1782 		    spec->data_size = tmp;
1783 		}
1784 	    }
1785 	    continue;
1786 	}
1787 	for (status = get_token(buff, token, value); status == STAT_OK;
1788 			status = get_token(buff, token, value)) {
1789 	    if (!strcmp(token, "class")) {
1790 		if (strcmp(value, "DirectClass")) {
1791 		    DXSetError(ERROR_DATA_INVALID, "MIFF: class=%s is not supported", value);
1792 		    goto error;
1793 		}
1794 	    } else if (!strcmp(token, "columns")) {
1795 		if (1 != sscanf(value, "%d", &spec->image_width)) {
1796 		    DXSetError(ERROR_DATA_INVALID, "MIFF: bad columns value, %s", value);
1797 		    goto error;
1798 		}
1799 	    } else if (!strcmp(token, "compression")) {
1800 		if (strcmp(value, "RunlengthEncoded")) {
1801 		    DXSetError(ERROR_DATA_INVALID, "MIFF: compression=%s is not supported", value);
1802 		    goto error;
1803 		}
1804 	    } else if (!strcmp(token, "rows")) {
1805 		if (1 != sscanf(value, "%d", &spec->image_height)) {
1806 		    DXSetError(ERROR_DATA_INVALID, "MIFF: bad rows value, %s", value);
1807 		    goto error;
1808 		}
1809 	    } else if (!strcmp(token, "scene")) {
1810 		if (1 != sscanf(value, "%d", frame)) {
1811 		    DXSetError(ERROR_DATA_INVALID, "MIFF: bad scene value, %s", value);
1812 		    goto error;
1813 		}
1814 	    }
1815 	}
1816 	if (status == STAT_COMPLETE)
1817 	    break;
1818 	if (status == STAT_ERROR) {
1819 	    DXSetError(ERROR_DATA_INVALID, "MIFF: error parsing line %s", buff);
1820 	    goto error;
1821 	}
1822     }
1823 
1824     return OK;
1825 
1826 error:
1827     return ERROR;
1828 }
1829 
_dxf_ReadImageSizesMIFF(char * name,int startframe,SizeData * data,int * use_numerics,int ext_sel,int * multiples)1830 SizeData * _dxf_ReadImageSizesMIFF(char *name,
1831 				    int startframe,
1832 				    SizeData *data,
1833 				    int *use_numerics,
1834 				    int ext_sel,
1835 				    int *multiples)
1836 {
1837     FILE *fin;
1838     struct ps_spec spec;
1839     int imgtype;
1840     int nframes;
1841 
1842     memset(&spec, 0, sizeof(spec));
1843     if (NULL == (fin = fopen(name, "r")))
1844 	goto error;
1845     if (ERROR == read_miff_header(fin, &startframe, &spec, &imgtype, &nframes))
1846 	goto error;
1847     fclose(fin);
1848     data->height = spec.image_height;
1849     data->width = spec.image_width;
1850     *multiples = ((nframes>0)?1:0);
1851     data->startframe = 0;
1852     data->endframe = nframes-1;
1853     *use_numerics = 0;
1854 
1855     return data;
1856 
1857 error:
1858     return ERROR;
1859 }
1860 
1861 static Error
miff_out_flc(FILE * fout,Pointer pixels,RGBColor * map,int imageType,struct ps_spec * spec)1862 miff_out_flc(FILE *fout, Pointer pixels,
1863         RGBColor *map, int imageType, struct ps_spec *spec)
1864 {
1865    int i, j, P;
1866    ubyte *encbuff, *RGBbuff, *RGBptr;
1867    int encbuff_size, RGBbuff_size;
1868    int byte_count;
1869    ubyte gamma_table[256];
1870 
1871    spec->compress = DO_COMPRESSION;
1872 
1873    _dxf_make_gamma_table(gamma_table, spec->gamma);
1874 
1875    RGBbuff_size = spec->image_width*3;
1876    RGBbuff = DXAllocate(RGBbuff_size);
1877 
1878    /* This is a worst-case row buffer size for no runs */
1879    encbuff_size = RGBbuff_size*2;
1880    /* now add some spare         */
1881    encbuff_size += 100;
1882    encbuff = DXAllocate(encbuff_size);
1883 
1884    if (imageType == FLOAT_COLOR)
1885        {
1886            RGBColor *fpixels = (RGBColor *)pixels;
1887 	   fpixels += spec->image_width*(spec->image_height-1);
1888            for (i=0; i<spec->image_height; i++) {
1889                for (j=0, RGBptr = RGBbuff; j<spec->image_width; j++, fpixels++) {
1890                   float r = fpixels->r * 255;
1891                   float g = fpixels->g * 255;
1892                   float b = fpixels->b * 255;
1893                   *RGBptr++  = gamma_table[CLAMP(r)];
1894                   *RGBptr++  = gamma_table[CLAMP(g)];
1895                   *RGBptr++  = gamma_table[CLAMP(b)];
1896                }
1897 	       byte_count = 0;
1898                build_rle_row(RGBbuff, spec->image_width, 3,
1899                             spec->compress, encbuff, &byte_count, RLE_BINARY, RLE_COUNT_POST, RLE_STUPID);
1900                if (fwrite(encbuff, sizeof(ubyte), byte_count, fout) != byte_count)
1901                    goto error;
1902 	       spec->data_size += byte_count;
1903 	       fpixels -= 2*spec->image_width;
1904 
1905            }
1906        }
1907        else if (imageType == UBYTE_COLOR)
1908        {
1909            RGBByteColor *upixels = (RGBByteColor *)pixels;
1910 	   upixels += spec->image_width*(spec->image_height-1);
1911 
1912            for (i=0; i<spec->image_height; i++) {
1913                for (j=0, RGBptr = RGBbuff; j<spec->image_width; j++, upixels++) {
1914                   *RGBptr++  = gamma_table[upixels->r];
1915                   *RGBptr++  = gamma_table[upixels->g];
1916                   *RGBptr++  = gamma_table[upixels->b];
1917                }
1918 	       byte_count = 0;
1919                build_rle_row(RGBbuff, spec->image_width, 3,
1920                             spec->compress, encbuff, &byte_count, RLE_BINARY, RLE_COUNT_POST, RLE_STUPID);
1921                if (fwrite(encbuff, sizeof(ubyte), byte_count, fout) != byte_count)
1922                    goto error;
1923 	       spec->data_size += byte_count;
1924 	       upixels -= 2*spec->image_width;
1925            }
1926        }
1927        else
1928        {
1929            ubyte *upixels = (ubyte *)pixels;
1930 	   ubyte cmap[256*3];
1931 	   for (i=0, RGBptr = cmap; i<256; i++) {
1932                   float r = map[i].r * 255;
1933                   float g = map[i].g * 255;
1934                   float b = map[i].b * 255;
1935                   *RGBptr++  = gamma_table[CLAMP(r)];
1936                   *RGBptr++  = gamma_table[CLAMP(g)];
1937                   *RGBptr++  = gamma_table[CLAMP(b)];
1938 	   }
1939 
1940 	   if (fwrite(cmap, sizeof(ubyte), 256*3, fout) != 256*3)
1941 		goto error;
1942 
1943 	   spec->data_size += 256*3;
1944 	   upixels += spec->image_width*(spec->image_height-1);
1945            for (i=0; i<spec->image_height; i++) {
1946 	       byte_count = 0;
1947                build_rle_row(upixels, spec->image_width, 1,
1948                             spec->compress, encbuff, &byte_count, RLE_BINARY, RLE_COUNT_POST, RLE_STUPID);
1949                if (fwrite(encbuff, sizeof(ubyte), byte_count, fout) != byte_count)
1950                    goto error;
1951 	       spec->data_size += byte_count;
1952 	       upixels -= spec->image_width;
1953            }
1954        }
1955 
1956    DXFree(RGBbuff);
1957    DXFree(encbuff);
1958    return OK;
1959 error:
1960    DXFree(RGBbuff);
1961    DXFree(encbuff);
1962    DXErrorReturn(ERROR_DATA_INVALID, "Can't write miff pixel data.");
1963 }
1964 
1965 Error
_dxf_write_miff(RWImageArgs * iargs)1966 _dxf_write_miff(RWImageArgs *iargs)
1967 {
1968         Error e;
1969         e = output_miff(iargs);
1970         return e;
1971 }
1972 
1973 static Error
output_miff(RWImageArgs * iargs)1974 output_miff(RWImageArgs *iargs)
1975 {
1976     char     imagefilename[MAX_IMAGE_NAMELEN];
1977     int      firstframe, lastframe, i, series;
1978     int      frames, deleteable = 0;
1979     struct   ps_spec page_spec;
1980     Pointer  pixels;
1981     FILE     *fp = NULL;
1982     Array    colors, color_map;
1983     RGBColor *map = NULL;
1984     int      imageType=0;
1985     Type     type;
1986     int      rank, shape[32];
1987     char     buff[BUFFSIZE];
1988     char     *seqptr;
1989     long     fptr = 0;
1990     int      init_nframes = 0;
1991 
1992     SizeData  image_sizes;  /* Values as found in the image object itself */
1993     Field       img = NULL;
1994 
1995     if (iargs->adasd)
1996         DXErrorGoto(ERROR_NOT_IMPLEMENTED,
1997                 "MIFF format not supported on disk array");
1998 
1999     series = iargs->imgclass == CLASS_SERIES;
2000 
2001     if ( !_dxf_GetImageAttributes ( (Object)iargs->image, &image_sizes ) )
2002         goto error;
2003 
2004     /*
2005      * Always write all frames of a series.
2006      */
2007     frames = (image_sizes.endframe - image_sizes.startframe + 1);
2008     firstframe = image_sizes.startframe;
2009     lastframe = image_sizes.endframe;
2010     page_spec.image_height = image_sizes.height;
2011     page_spec.image_width = image_sizes.width;
2012     page_spec.gamma = 2.0;
2013     if (iargs->format) {
2014         if (!parse_format(iargs->format,&page_spec))
2015             goto error;
2016     }
2017 
2018     /*
2019      * Attempt to open image file and position to start of frame(s).
2020      */
2021     if (iargs->pipe == NULL) {
2022         /*
2023          * Create an appropriate file name.
2024          */
2025         if (!_dxf_BuildImageFileName(imagefilename,MAX_IMAGE_NAMELEN,
2026                         iargs->basename, iargs->imgtyp,iargs->startframe,0))
2027                 goto error;
2028 	/*
2029 	 * Need to open the file if it exists, and find number of scenes present
2030 	 * as specified in the first header.
2031 	 * Then save pointer to this number string for later update.
2032 	*/
2033 	if ((fp=fopen(imagefilename, "r+"))) {
2034 	   for ( ; ; ) {
2035 	       fptr = ftell(fp);
2036 	       if (!fgets(buff, BUFFSIZE, fp)) goto error;
2037 	       if ((seqptr=strstr(buff, NSCENES_STRING))) break;
2038 	   }
2039 	   seqptr += strlen(NSCENES_STRING);
2040 	   if (!sscanf(seqptr,"%d", &init_nframes)) goto error;
2041 	   if (fseek(fp, fptr, SEEK_SET)) goto error;
2042 	   if (fprintf(fp, NSCENES_STRING) < 0) goto error;
2043 	   if (fprintf(fp, "%06d\n", init_nframes+frames) < 0) goto error;
2044 	   if (fseek(fp, 0, SEEK_END)) goto error;
2045 	   fptr = ftell(fp);
2046 	   fclose(fp);
2047 	}
2048 
2049 	if (!fptr)
2050 	{
2051 	    if ( (fp = fopen (imagefilename, "w+" )) == 0 )
2052 		ErrorGotoPlus1 ( ERROR_DATA_INVALID,
2053 			      "Can't open image file (%s)", imagefilename );
2054 	} else {
2055 	    if ( (fp = fopen (imagefilename, "r+" )) == 0 )
2056 		ErrorGotoPlus1 ( ERROR_DATA_INVALID,
2057 			      "Can't open image file (%s)", imagefilename );
2058 	    fseek(fp, fptr, SEEK_SET);
2059 	}
2060 
2061     } else {
2062         strcpy(imagefilename,"stdout");
2063         fp = iargs->pipe;
2064     }
2065 
2066     img = iargs->image;
2067     for (i=firstframe ; i<=lastframe ; i++)
2068     {
2069         if (series) {
2070             if (deleteable) DXDelete((Object)img);
2071             img = _dxf_GetFlatSeriesImage((Series)iargs->image,i,
2072                         page_spec.image_width,page_spec.image_height,
2073                         &deleteable);
2074             if (!img)
2075                 goto error;
2076         }
2077 
2078         colors = (Array)DXGetComponentValue(img, "colors");
2079         if (! colors)
2080         {
2081             DXSetError(ERROR_DATA_INVALID,
2082                 "image does not contain colors component");
2083             goto error;
2084         }
2085 
2086         DXGetArrayInfo(colors, NULL, &type, NULL, &rank, shape);
2087 
2088         if (type == TYPE_FLOAT)
2089         {
2090             if (rank != 1 || shape[0] != 3)
2091             {
2092                 DXSetError(ERROR_DATA_INVALID,
2093                     "floating-point colors component must be 3-vector");
2094                 goto error;
2095             }
2096 
2097             imageType = FLOAT_COLOR;
2098         }
2099         else if (type == TYPE_UBYTE)
2100         {
2101             if (rank == 0 || (rank == 1 && shape[0] == 1))
2102             {
2103                 color_map = (Array)DXGetComponentValue(img, "color map");
2104                 if (! color_map)
2105                 {
2106                     DXSetError(ERROR_DATA_INVALID,
2107                         "single-valued ubyte colors component requires a %s",
2108                         "color map");
2109                     goto error;
2110                 }
2111 
2112                 DXGetArrayInfo(color_map, NULL, &type, NULL, &rank, shape);
2113 
2114                 if (type != TYPE_FLOAT || rank != 1 || shape[0] != 3)
2115                 {
2116                     DXSetError(ERROR_DATA_INVALID,
2117                         "color map must be floating point 3-vectors");
2118                     goto error;
2119                 }
2120 
2121                 map = (RGBColor *)DXGetArrayData(color_map);
2122                 imageType = MAPPED_COLOR;
2123             }
2124             else if (rank != 1 || shape[0] != 3)
2125             {
2126                 DXSetError(ERROR_DATA_INVALID,
2127                     "unsigned byte colors component must be either single %s",
2128                     "valued with a color map or 3-vectors");
2129                 goto error;
2130             }
2131             else
2132                 imageType = UBYTE_COLOR;;
2133         }
2134 
2135         if (!(pixels = DXGetArrayData(colors)))
2136             goto error;
2137 
2138 	/*
2139 	 * Write out the miff header
2140 	 */
2141 	if (!put_miff_header(fp, imagefilename, i+init_nframes, &page_spec, imageType, frames))
2142 	    goto bad_write;
2143 
2144         /*
2145          * Write out the pixel data
2146          */
2147 	page_spec.data_size = 0;
2148         if (!miff_out_flc(fp, pixels, map, imageType, &page_spec))
2149             goto bad_write;
2150 	fptr = ftell(fp);
2151 	if (fseek(fp, page_spec.fptr, SEEK_SET))
2152 	    goto error;
2153 	if (fprintf(fp, "%08d", page_spec.data_size) < 0)
2154 	    goto error;
2155 	if (fseek(fp, fptr, SEEK_SET))
2156 	    goto error;
2157     }
2158 
2159     if (fclose(fp) != 0)
2160         goto bad_write;
2161 
2162     if (deleteable && img) DXDelete((Object)img);
2163 
2164     return OK;
2165 
2166 bad_write:
2167     if ( iargs->pipe == NULL )
2168         DXErrorGoto
2169             ( ERROR_DATA_INVALID,
2170               "Can't write miff file." )
2171     else
2172         DXErrorGoto
2173             ( ERROR_BAD_PARAMETER,
2174               "Can't send image with specified command." );
2175 
2176 error:
2177     if ( fp ) fclose(fp);
2178     if (deleteable && img) DXDelete((Object)img);
2179     return ERROR;
2180 }
2181 
_dxf_InputMIFF(FILE ** fh,int width,int height,char * name,int relframe,int delayed,char * colortype)2182 Field _dxf_InputMIFF (FILE **fh, int width, int height, char *name,
2183                       int relframe, int delayed, char *colortype)
2184 {
2185     int      i;
2186     int      frame, nframes;
2187     struct   ps_spec page_spec;
2188     Pointer  pixels;
2189     int      imageType;
2190     Type     type;
2191     int      rank, shape[32];
2192     Field    image = NULL;
2193     Array    colorsArray;
2194     int      npix = 0;
2195     int      tot_pix;
2196     ubyte    *pixptr;
2197 
2198     struct {
2199 	ubyte rgb[3];
2200 	ubyte count;
2201     }rle_entry;
2202 
2203     if (!*fh)
2204 	if (NULL == (*fh = fopen(name, "r")))
2205 	    goto error;
2206 
2207     read_miff_header(*fh, &frame, &page_spec, &imageType, &nframes);
2208     image = DXMakeImageFormat(width, height, "BYTE");
2209     if (!image)
2210 	goto error;
2211 
2212     tot_pix = width*height;
2213     colorsArray = (Array)DXGetComponentValue(image, "colors");
2214     DXGetArrayInfo(colorsArray, NULL, &type, NULL, &rank, shape);
2215     pixels = DXGetArrayData(colorsArray);
2216     pixptr = (ubyte *)pixels;
2217     pixptr += width*(height-1)*3*sizeof(ubyte);
2218     do {
2219 	if (fread(&rle_entry, sizeof(rle_entry), 1, *fh) < 1)
2220 	    goto error;
2221 	for (i=0; i<rle_entry.count+1; i++) {
2222 	    memcpy(pixptr, rle_entry.rgb, sizeof(rle_entry.rgb));
2223 	    pixptr += 3;
2224 	}
2225 	npix += rle_entry.count+1;
2226 	if (npix % width == 0)
2227 	    pixptr -= 2*width*3*sizeof(ubyte);
2228     } while (npix < tot_pix);
2229 
2230     return image;
2231 
2232 
2233 error:
2234     if (NULL != *fh)
2235 	fclose(*fh);
2236     return ERROR;
2237 }
2238