1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  * PostScript file plugin
4  * PostScript writing and GhostScript interfacing code
5  * Copyright (C) 1997-98 Peter Kirchgessner
6  * (email: peter@kirchgessner.net, WWW: http://www.kirchgessner.net)
7  *
8  * Added controls for TextAlphaBits and GraphicsAlphaBits
9  *   George White <aa056@chebucto.ns.ca>
10  *
11  * Added Ascii85 encoding
12  *   Austin Donnelly <austin@gimp.org>
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
26  *
27  */
28 
29 /* Event history:
30  * V 0.90, PK, 28-Mar-97: Creation.
31  * V 0.91, PK, 03-Apr-97: Clip everything outside BoundingBox.
32  *             24-Apr-97: Multi page read support.
33  * V 1.00, PK, 30-Apr-97: PDF support.
34  * V 1.01, PK, 05-Oct-97: Parse rc-file.
35  * V 1.02, GW, 09-Oct-97: Antialiasing support.
36  *         PK, 11-Oct-97: No progress bars when running non-interactive.
37  *                        New procedure file_ps_load_setargs to set
38  *                        load-arguments non-interactively.
39  *                        If GS_OPTIONS are not set, use at least "-dSAFER"
40  * V 1.03, nn, 20-Dec-97: Initialize some variables
41  * V 1.04, PK, 20-Dec-97: Add Encapsulated PostScript output and preview
42  * V 1.05, PK, 21-Sep-98: Write b/w-images (indexed) using image-operator
43  * V 1.06, PK, 22-Dec-98: Fix problem with writing color PS files.
44  *                        Ghostview may hang when displaying the files.
45  * V 1.07, PK, 14-Sep-99: Add resolution to image
46  * V 1.08, PK, 16-Jan-2000: Add PostScript-Level 2 by Austin Donnelly
47  * V 1.09, PK, 15-Feb-2000: Force showpage on EPS-files
48  *                          Add "RunLength" compression
49  *                          Fix problem with "Level 2" toggle
50  * V 1.10, PK, 15-Mar-2000: For load EPSF, allow negative Bounding Box Values
51  *                          Save PS: don't start lines of image data with %%
52  *                          to prevent problems with stupid PostScript
53  *                          analyzer programs (Stanislav Brabec)
54  *                          Add BeginData/EndData comments
55  *                          Save PS: Set default rotation to 0
56  * V 1.11, PK, 20-Aug-2000: Fix problem with BoundingBox recognition
57  *                          for Mac files.
58  *                          Fix problem with loop when reading not all
59  *                          images of a multi page file.
60  *         PK, 31-Aug-2000: Load PS: Add checks for space in filename.
61  * V 1.12  PK, 19-Jun-2001: Fix problem with command line switch --
62  *                          (reported by Ferenc Wagner)
63  * V 1.13  PK, 07-Apr-2002: Fix problem with DOS binary EPS files
64  * V 1.14  PK, 14-May-2002: Workaround EPS files of Adb. Ill. 8.0
65  * V 1.15  PK, 04-Oct-2002: Be more accurate with using BoundingBox
66  * V 1.16  PK, 22-Jan-2004: Don't use popen(), use g_spawn_async_with_pipes()
67  *                          or g_spawn_sync().
68  * V 1.17  PK, 19-Sep-2004: Fix problem with interpretation of bounding box
69  */
70 
71 #include "config.h"
72 
73 #include <errno.h>
74 #include <string.h>
75 #include <time.h>
76 
77 #include <sys/types.h>
78 
79 #ifdef HAVE_UNISTD_H
80 #include <unistd.h>
81 #endif
82 
83 #include <glib/gstdio.h>
84 
85 #include <libgimp/gimp.h>
86 #include <libgimp/gimpui.h>
87 
88 #include "libgimp/stdplugins-intl.h"
89 
90 #include <ghostscript/ierrors.h>
91 #include <ghostscript/iapi.h>
92 #include <ghostscript/gdevdsp.h>
93 
94 #define VERSIO 1.17
95 static const gchar dversio[] = "v1.17  19-Sep-2004";
96 
97 #define LOAD_PS_PROC         "file-ps-load"
98 #define LOAD_EPS_PROC        "file-eps-load"
99 #define LOAD_PS_SETARGS_PROC "file-ps-load-setargs"
100 #define LOAD_PS_THUMB_PROC   "file-ps-load-thumb"
101 #define SAVE_PS_PROC         "file-ps-save"
102 #define SAVE_EPS_PROC        "file-eps-save"
103 #define PLUG_IN_BINARY       "file-ps"
104 #define PLUG_IN_ROLE         "gimp-file-ps"
105 
106 
107 #define STR_LENGTH     64
108 #define MIN_RESOLUTION 5
109 #define MAX_RESOLUTION 8192
110 
111 /* Load info */
112 typedef struct
113 {
114   guint     resolution;        /* resolution (dpi) at which to run ghostscript */
115   guint     width, height;     /* desired size (ghostscript may ignore this) */
116   gboolean  use_bbox;          /* 0: use width/height, 1: try to use BoundingBox */
117   gchar     pages[STR_LENGTH]; /* Pages to load (eg.: 1,3,5-7) */
118   gint      pnm_type;          /* 4: pbm, 5: pgm, 6: ppm, 7: automatic */
119   gint      textalpha;         /* antialiasing: 1,2, or 4 TextAlphaBits */
120   gint      graphicsalpha;     /* antialiasing: 1,2, or 4 GraphicsAlphaBits */
121 } PSLoadVals;
122 
123 static PSLoadVals plvals =
124 {
125   100,         /* 100 dpi                        */
126   826, 1170,   /* default width/height (A4)      */
127   TRUE,        /* try to use BoundingBox         */
128   "1",         /* pages to load                  */
129   6,           /* use ppm (color)               */
130   1,           /* don't use text antialiasing     */
131   1            /* don't use graphics antialiasing */
132 };
133 
134 /* Widgets for width and height of PostScript image to
135 *  be loaded, so that they can be updated when desired resolution is
136 *  changed
137 */
138 static GtkWidget *ps_width_spinbutton;
139 static GtkWidget *ps_height_spinbutton;
140 
141 /* Save info  */
142 typedef struct
143 {
144   gdouble    width, height;      /* Size of image */
145   gdouble    x_offset, y_offset; /* Offset to image on page */
146   gboolean   unit_mm;            /* Unit of measure (0: inch, 1: mm) */
147   gboolean   keep_ratio;         /* Keep aspect ratio */
148   gint       rotate;             /* Rotation (0, 90, 180, 270) */
149   gint       level;              /* PostScript Level */
150   gboolean   eps;                /* Encapsulated PostScript flag */
151   gboolean   preview;            /* Preview Flag */
152   gint       preview_size;       /* Preview size */
153 } PSSaveVals;
154 
155 static PSSaveVals psvals =
156 {
157   287.0, 200.0,   /* Image size (A4) */
158   5.0, 5.0,       /* Offset */
159   TRUE,           /* Unit is mm */
160   TRUE,           /* Keep edge ratio */
161   0,              /* Rotate */
162   2,              /* PostScript Level */
163   FALSE,          /* Encapsulated PostScript flag */
164   FALSE,          /* Preview flag */
165   256             /* Preview size */
166 };
167 
168 static const char hex[] = "0123456789abcdef";
169 
170 
171 /* Declare some local functions.
172  */
173 static void      query            (void);
174 static void      run              (const gchar       *name,
175                                    gint               nparams,
176                                    const GimpParam   *param,
177                                    gint              *nreturn_vals,
178                                    GimpParam        **return_vals);
179 
180 static gint32    load_image       (const gchar       *filename,
181                                    GError           **error);
182 static gboolean  save_image       (GFile             *file,
183                                    gint32             image_ID,
184                                    gint32             drawable_ID,
185                                    GError           **error);
186 
187 static gboolean  save_ps_header   (GOutputStream     *output,
188                                    GFile             *file,
189                                    GError           **error);
190 static gboolean  save_ps_setup    (GOutputStream     *output,
191                                    gint32             drawable_ID,
192                                    gint               width,
193                                    gint               height,
194                                    gint               bpp,
195                                    GError           **error);
196 static gboolean  save_ps_trailer  (GOutputStream     *output,
197                                    GError           **error);
198 
199 static gboolean  save_ps_preview  (GOutputStream     *output,
200                                    gint32             drawable_ID,
201                                    GError           **error);
202 
203 static gboolean  save_gray        (GOutputStream     *output,
204                                    gint32             image_ID,
205                                    gint32             drawable_ID,
206                                    GError           **error);
207 static gboolean  save_bw          (GOutputStream     *output,
208                                    gint32             image_ID,
209                                    gint32             drawable_ID,
210                                    GError           **error);
211 static gboolean  save_index       (GOutputStream     *output,
212                                    gint32             image_ID,
213                                    gint32             drawable_ID,
214                                    GError           **error);
215 static gboolean  save_rgb         (GOutputStream     *output,
216                                    gint32             image_ID,
217                                    gint32             drawable_ID,
218                                    GError           **error);
219 
220 static gboolean  print            (GOutputStream     *output,
221                                    GError           **error,
222                                    const gchar       *format,
223                                    ...) G_GNUC_PRINTF (3, 4);
224 
225 static gint32    create_new_image (const gchar       *filename,
226                                    guint              pagenum,
227                                    guint              width,
228                                    guint              height,
229                                    GimpImageBaseType  type,
230                                    gint32            *layer_ID);
231 
232 static void      check_load_vals  (void);
233 static void      check_save_vals  (void);
234 
235 static gint      page_in_list     (gchar             *list,
236                                    guint              pagenum);
237 
238 static gint      get_bbox         (const gchar       *filename,
239                                    gint              *x0,
240                                    gint              *y0,
241                                    gint              *x1,
242                                    gint              *y1);
243 
244 static FILE    * ps_open         (const gchar       *filename,
245                                   const PSLoadVals  *loadopt,
246                                   gint              *llx,
247                                   gint              *lly,
248                                   gint              *urx,
249                                   gint              *ury,
250                                   gboolean          *is_epsf);
251 
252 static void      ps_close         (FILE              *ifp);
253 
254 static gboolean  skip_ps          (FILE              *ifp);
255 
256 static gint32    load_ps          (const gchar       *filename,
257                                    guint              pagenum,
258                                    FILE              *ifp,
259                                    gint               llx,
260                                    gint               lly,
261                                    gint               urx,
262                                    gint               ury);
263 
264 static void      dither_grey      (const guchar      *grey,
265                                    guchar            *bw,
266                                    gint               npix,
267                                    gint               linecount);
268 
269 
270 /* Dialog-handling */
271 
272 static gint32    count_ps_pages             (const gchar *filename);
273 static gboolean  load_dialog                (const gchar *filename);
274 static void      load_pages_entry_callback  (GtkWidget   *widget,
275                                              gpointer     data);
276 
277 static gboolean  resolution_change_callback (GtkAdjustment *adjustment,
278                                              gpointer   data);
279 
280 typedef struct
281 {
282   GtkAdjustment *adjustment[4];
283   gint           level;
284 } SaveDialogVals;
285 
286 static gboolean  save_dialog              (void);
287 static void      save_unit_toggle_update  (GtkWidget *widget,
288                                            gpointer   data);
289 
290 const GimpPlugInInfo PLUG_IN_INFO =
291 {
292   NULL,  /* init_proc  */
293   NULL,  /* quit_proc  */
294   query, /* query_proc */
295   run,   /* run_proc   */
296 };
297 
298 
299 /* The run mode */
300 static GimpRunMode l_run_mode;
301 
302 static void compress_packbits (int            nin,
303                                unsigned char *src,
304                                int           *nout,
305                                unsigned char *dst);
306 
307 
308 static guint32  ascii85_buf       = 0;
309 static gint     ascii85_len       = 0;
310 static gint     ascii85_linewidth = 0;
311 
312 static GimpPageSelectorTarget ps_pagemode = GIMP_PAGE_SELECTOR_TARGET_LAYERS;
313 
314 static void
ascii85_init(void)315 ascii85_init (void)
316 {
317   ascii85_len       = 0;
318   ascii85_linewidth = 0;
319 }
320 
321 static gboolean
ascii85_flush(GOutputStream * output,GError ** error)322 ascii85_flush (GOutputStream  *output,
323                GError        **error)
324 {
325   gchar    c[5];
326   gint     i;
327   gboolean zero_case = (ascii85_buf == 0);
328   GString  *string   = g_string_new (NULL);
329 
330   static gint max_linewidth = 75;
331 
332   for (i = 4; i >= 0; i--)
333     {
334       c[i] = (ascii85_buf % 85) + '!';
335       ascii85_buf /= 85;
336     }
337 
338   /* check for special case: "!!!!!" becomes "z", but only if not
339    * at end of data. */
340   if (zero_case && (ascii85_len == 4))
341     {
342       if (ascii85_linewidth >= max_linewidth)
343         {
344           g_string_append_c (string, '\n');
345 
346           ascii85_linewidth = 0;
347         }
348 
349       g_string_append_c (string, 'z');
350 
351       ascii85_linewidth++;
352     }
353   else
354     {
355       for (i = 0; i < ascii85_len + 1; i++)
356         {
357           if ((ascii85_linewidth >= max_linewidth) && (c[i] != '%'))
358             {
359               g_string_append_c (string, '\n');
360 
361               ascii85_linewidth = 0;
362             }
363 
364           g_string_append_c (string, c[i]);
365 
366           ascii85_linewidth++;
367         }
368     }
369 
370   ascii85_len = 0;
371   ascii85_buf = 0;
372 
373   if (string->len > 0 &&
374       ! g_output_stream_write_all (output,
375                                    string->str, string->len, NULL,
376                                    NULL, error))
377     {
378       g_string_free (string, TRUE);
379 
380       return FALSE;
381     }
382 
383   g_string_free (string, TRUE);
384 
385   return TRUE;
386 }
387 
388 static inline gboolean
ascii85_out(GOutputStream * output,guchar byte,GError ** error)389 ascii85_out (GOutputStream  *output,
390              guchar          byte,
391              GError        **error)
392 {
393   if (ascii85_len == 4)
394     if (! ascii85_flush (output, error))
395       return FALSE;
396 
397   ascii85_buf <<= 8;
398   ascii85_buf |= byte;
399   ascii85_len++;
400 
401   return TRUE;
402 }
403 
404 static gboolean
ascii85_nout(GOutputStream * output,gint n,guchar * uptr,GError ** error)405 ascii85_nout (GOutputStream  *output,
406               gint            n,
407               guchar         *uptr,
408               GError        **error)
409 {
410   while (n-- > 0)
411     {
412       if (! ascii85_out (output, *uptr, error))
413         return FALSE;
414 
415       uptr++;
416     }
417 
418   return TRUE;
419 }
420 
421 static gboolean
ascii85_done(GOutputStream * output,GError ** error)422 ascii85_done (GOutputStream  *output,
423               GError        **error)
424 {
425   if (ascii85_len)
426     {
427       /* zero any unfilled buffer portion, then flush */
428       ascii85_buf <<= (8 * (4 - ascii85_len));
429 
430       if (! ascii85_flush (output, error))
431         return FALSE;
432     }
433 
434   if (! print (output, error, "~>\n"))
435     return FALSE;
436 
437   return TRUE;
438 }
439 
440 
441 static void
compress_packbits(int nin,unsigned char * src,int * nout,unsigned char * dst)442 compress_packbits (int nin,
443                    unsigned char *src,
444                    int *nout,
445                    unsigned char *dst)
446 
447 {
448  unsigned char c;
449  int nrepeat, nliteral;
450  unsigned char *run_start;
451  unsigned char *start_dst = dst;
452  unsigned char *last_literal = NULL;
453 
454  for (;;)
455  {
456    if (nin <= 0) break;
457 
458    run_start = src;
459    c = *run_start;
460 
461    /* Search repeat bytes */
462    if ((nin > 1) && (c == src[1]))
463    {
464      nrepeat = 1;
465      nin -= 2;
466      src += 2;
467      while ((nin > 0) && (c == *src))
468      {
469        nrepeat++;
470        src++;
471        nin--;
472        if (nrepeat == 127) break; /* Maximum repeat */
473      }
474 
475      /* Add two-byte repeat to last literal run ? */
476      if (   (nrepeat == 1)
477          && (last_literal != NULL) && (((*last_literal)+1)+2 <= 128))
478      {
479        *last_literal += 2;
480        *(dst++) = c;
481        *(dst++) = c;
482        continue;
483      }
484 
485      /* Add repeat run */
486      *(dst++) = (unsigned char)((-nrepeat) & 0xff);
487      *(dst++) = c;
488      last_literal = NULL;
489      continue;
490    }
491    /* Search literal bytes */
492    nliteral = 1;
493    nin--;
494    src++;
495 
496    for (;;)
497    {
498      if (nin <= 0) break;
499 
500      if ((nin >= 2) && (src[0] == src[1])) /* A two byte repeat ? */
501        break;
502 
503      nliteral++;
504      nin--;
505      src++;
506      if (nliteral == 128) break; /* Maximum literal run */
507    }
508 
509    /* Could be added to last literal run ? */
510    if ((last_literal != NULL) && (((*last_literal)+1)+nliteral <= 128))
511    {
512      *last_literal += nliteral;
513    }
514    else
515    {
516      last_literal = dst;
517      *(dst++) = (unsigned char)(nliteral-1);
518    }
519    while (nliteral-- > 0) *(dst++) = *(run_start++);
520  }
521  *nout = dst - start_dst;
522 }
523 
524 
525 typedef struct
526 {
527   goffset eol;
528   goffset begin_data;
529 } PS_DATA_POS;
530 
531 static PS_DATA_POS ps_data_pos = { 0, 0 };
532 
533 static gboolean
ps_begin_data(GOutputStream * output,GError ** error)534 ps_begin_data (GOutputStream  *output,
535                GError        **error)
536 {
537   /*                                 %%BeginData: 123456789012 ASCII Bytes */
538   if (! print (output, error, "%s", "%%BeginData:                         "))
539     return FALSE;
540 
541   ps_data_pos.eol = g_seekable_tell (G_SEEKABLE (output));
542 
543   if (! print (output, error, "\n"))
544     return FALSE;
545 
546   ps_data_pos.begin_data = g_seekable_tell (G_SEEKABLE (output));
547 
548   return TRUE;
549 }
550 
551 static gboolean
ps_end_data(GOutputStream * output,GError ** error)552 ps_end_data (GOutputStream  *output,
553              GError        **error)
554 {
555   goffset end_data;
556   gchar   s[64];
557 
558   if ((ps_data_pos.begin_data > 0) && (ps_data_pos.eol > 0))
559     {
560       end_data = g_seekable_tell (G_SEEKABLE (output));
561 
562       if (end_data > 0)
563         {
564           g_snprintf (s, sizeof (s),
565                       "%"G_GOFFSET_FORMAT" ASCII Bytes", end_data - ps_data_pos.begin_data);
566 
567           if (! g_seekable_seek (G_SEEKABLE (output),
568                                  ps_data_pos.eol - strlen (s), G_SEEK_SET,
569                                  NULL, error))
570             return FALSE;
571 
572           if (! print (output, error, "%s", s))
573             return FALSE;
574 
575           if (! g_seekable_seek (G_SEEKABLE (output),
576                                  end_data, G_SEEK_SET,
577                                  NULL, error))
578             return FALSE;
579         }
580     }
581 
582   if (! print (output, error, "%s\n", "%%EndData"))
583     return FALSE;
584 
585   return TRUE;
586 }
587 
588 
MAIN()589 MAIN ()
590 
591 static void
592 query (void)
593 {
594   static const GimpParamDef load_args[] =
595   {
596     { GIMP_PDB_INT32,  "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
597     { GIMP_PDB_STRING, "filename",     "The name of the file to load" },
598     { GIMP_PDB_STRING, "raw-filename", "The name of the file to load" }
599   };
600   static const GimpParamDef load_return_vals[] =
601   {
602     { GIMP_PDB_IMAGE, "image", "Output image" }
603   };
604 
605   static const GimpParamDef set_load_args[] =
606   {
607     { GIMP_PDB_INT32,  "resolution", "Resolution to interpret image (dpi)"     },
608     { GIMP_PDB_INT32,  "width",      "Desired width"                           },
609     { GIMP_PDB_INT32,  "height",     "Desired height"                          },
610     { GIMP_PDB_INT32,  "check-bbox", "0: Use width/height, 1: Use BoundingBox" },
611     { GIMP_PDB_STRING, "pages",      "Pages to load (e.g.: 1,3,5-7)"           },
612     { GIMP_PDB_INT32,  "coloring",   "4: b/w, 5: grey, 6: color image, 7: automatic" },
613     { GIMP_PDB_INT32,  "text-alpha-bits",    "1, 2, or 4" },
614     { GIMP_PDB_INT32,  "graphic-alpha-bits", "1, 2, or 4" }
615   };
616 
617   static const GimpParamDef thumb_args[] =
618   {
619     { GIMP_PDB_STRING, "filename",     "The name of the file to load"  },
620     { GIMP_PDB_INT32,  "thumb-size",   "Preferred thumbnail size"      }
621   };
622   static const GimpParamDef thumb_return_vals[] =
623   {
624     { GIMP_PDB_IMAGE, "image",         "Output image" }
625   };
626 
627   static const GimpParamDef save_args[] =
628   {
629     { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
630     { GIMP_PDB_IMAGE,    "image",        "Input image" },
631     { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to export" },
632     { GIMP_PDB_STRING,   "filename",     "The name of the file to export the image in" },
633     { GIMP_PDB_STRING,   "raw-filename", "The name of the file to export the image in" },
634     { GIMP_PDB_FLOAT,    "width",        "Width of the image in PostScript file (0: use input image size)" },
635     { GIMP_PDB_FLOAT,    "height",       "Height of image in PostScript file (0: use input image size)" },
636     { GIMP_PDB_FLOAT,    "x-offset",     "X-offset to image from lower left corner" },
637     { GIMP_PDB_FLOAT,    "y-offset",     "Y-offset to image from lower left corner" },
638     { GIMP_PDB_INT32,    "unit",         "Unit for width/height/offset. 0: inches, 1: millimeters" },
639     { GIMP_PDB_INT32,    "keep-ratio",   "0: use width/height, 1: keep aspect ratio" },
640     { GIMP_PDB_INT32,    "rotation",     "0, 90, 180, 270" },
641     { GIMP_PDB_INT32,    "eps-flag",     "0: PostScript, 1: Encapsulated PostScript" },
642     { GIMP_PDB_INT32,    "preview",      "0: no preview, >0: max. size of preview" },
643     { GIMP_PDB_INT32,    "level",        "1: PostScript Level 1, 2: PostScript Level 2" }
644   };
645 
646   gimp_install_procedure (LOAD_PS_PROC,
647                           "load PostScript documents",
648                           "load PostScript documents",
649                           "Peter Kirchgessner <peter@kirchgessner.net>",
650                           "Peter Kirchgessner",
651                           dversio,
652                           N_("PostScript document"),
653                           NULL,
654                           GIMP_PLUGIN,
655                           G_N_ELEMENTS (load_args),
656                           G_N_ELEMENTS (load_return_vals),
657                           load_args, load_return_vals);
658 
659   gimp_register_file_handler_mime (LOAD_PS_PROC, "application/postscript");
660   gimp_register_magic_load_handler (LOAD_PS_PROC,
661                                     "ps",
662                                     "",
663                                     "0,string,%!,0,long,0xc5d0d3c6");
664 
665   gimp_install_procedure (LOAD_EPS_PROC,
666                           "load Encapsulated PostScript images",
667                           "load Encapsulated PostScript images",
668                           "Peter Kirchgessner <peter@kirchgessner.net>",
669                           "Peter Kirchgessner",
670                           dversio,
671                           N_("Encapsulated PostScript image"),
672                           NULL,
673                           GIMP_PLUGIN,
674                           G_N_ELEMENTS (load_args),
675                           G_N_ELEMENTS (load_return_vals),
676                           load_args, load_return_vals);
677 
678   gimp_register_file_handler_mime (LOAD_EPS_PROC, "image/x-eps");
679   gimp_register_magic_load_handler (LOAD_EPS_PROC,
680                                     "eps",
681                                     "",
682                                     "0,string,%!,0,long,0xc5d0d3c6");
683 
684   gimp_install_procedure (LOAD_PS_SETARGS_PROC,
685                           "set additional parameters for procedure file-ps-load",
686                           "set additional parameters for procedure file-ps-load",
687                           "Peter Kirchgessner <peter@kirchgessner.net>",
688                           "Peter Kirchgessner",
689                           dversio,
690                           NULL,
691                           NULL,
692                           GIMP_PLUGIN,
693                           G_N_ELEMENTS (set_load_args), 0,
694                           set_load_args, NULL);
695 
696   gimp_install_procedure (LOAD_PS_THUMB_PROC,
697                           "Loads a small preview from a PostScript or PDF document",
698                           "",
699                           "Peter Kirchgessner <peter@kirchgessner.net>",
700                           "Peter Kirchgessner",
701                           dversio,
702                           NULL,
703                           NULL,
704                           GIMP_PLUGIN,
705                           G_N_ELEMENTS (thumb_args),
706                           G_N_ELEMENTS (thumb_return_vals),
707                           thumb_args, thumb_return_vals);
708 
709   gimp_register_thumbnail_loader (LOAD_PS_PROC,  LOAD_PS_THUMB_PROC);
710   gimp_register_thumbnail_loader (LOAD_EPS_PROC, LOAD_PS_THUMB_PROC);
711 
712   gimp_install_procedure (SAVE_PS_PROC,
713                           "export image as PostScript document",
714                           "PostScript exporting handles all image types except "
715                           "those with alpha channels.",
716                           "Peter Kirchgessner <peter@kirchgessner.net>",
717                           "Peter Kirchgessner",
718                           dversio,
719                           N_("PostScript document"),
720                           "RGB, GRAY, INDEXED",
721                           GIMP_PLUGIN,
722                           G_N_ELEMENTS (save_args), 0,
723                           save_args, NULL);
724 
725   gimp_register_file_handler_mime (SAVE_PS_PROC, "application/postscript");
726   gimp_register_file_handler_uri (SAVE_PS_PROC);
727   gimp_register_save_handler (SAVE_PS_PROC, "ps", "");
728 
729   gimp_install_procedure (SAVE_EPS_PROC,
730                           "export image as Encapsulated PostScript image",
731                           "PostScript exporting handles all image types except "
732                           "those with alpha channels.",
733                           "Peter Kirchgessner <peter@kirchgessner.net>",
734                           "Peter Kirchgessner",
735                           dversio,
736                           N_("Encapsulated PostScript image"),
737                           "RGB, GRAY, INDEXED",
738                           GIMP_PLUGIN,
739                           G_N_ELEMENTS (save_args), 0,
740                           save_args, NULL);
741 
742   gimp_register_file_handler_mime (SAVE_EPS_PROC, "application/x-eps");
743   gimp_register_file_handler_uri (SAVE_EPS_PROC);
744   gimp_register_save_handler (SAVE_EPS_PROC, "eps", "");
745 }
746 
747 static void
ps_set_save_size(PSSaveVals * vals,gint32 image_ID)748 ps_set_save_size (PSSaveVals *vals,
749                   gint32      image_ID)
750 {
751   gdouble  xres, yres, factor, iw, ih;
752   guint    width, height;
753   GimpUnit unit;
754 
755   gimp_image_get_resolution (image_ID, &xres, &yres);
756 
757   if ((xres < 1e-5) || (yres < 1e-5))
758     xres = yres = 72.0;
759 
760   /* Calculate size of image in inches */
761   width  = gimp_image_width (image_ID);
762   height = gimp_image_height (image_ID);
763   iw = width  / xres;
764   ih = height / yres;
765 
766   unit = gimp_image_get_unit (image_ID);
767   factor = gimp_unit_get_factor (unit);
768 
769   if (factor == 0.0254 ||
770       factor == 0.254 ||
771       factor == 2.54 ||
772       factor == 25.4)
773     {
774       vals->unit_mm = TRUE;
775     }
776 
777   if (vals->unit_mm)
778     {
779       iw *= 25.4;
780       ih *= 25.4;
781     }
782 
783   vals->width  = iw;
784   vals->height = ih;
785 }
786 
787 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)788 run (const gchar      *name,
789      gint              nparams,
790      const GimpParam  *param,
791      gint             *nreturn_vals,
792      GimpParam       **return_vals)
793 {
794   static GimpParam   values[2];
795   GimpRunMode        run_mode;
796   GimpPDBStatusType  status        = GIMP_PDB_SUCCESS;
797   gint32             image_ID      = -1;
798   gint32             drawable_ID   = -1;
799   gint32             orig_image_ID = -1;
800   GimpExportReturn   export        = GIMP_EXPORT_CANCEL;
801   GError            *error         = NULL;
802 
803   l_run_mode = run_mode = param[0].data.d_int32;
804 
805   INIT_I18N ();
806   gegl_init (NULL, NULL);
807 
808   *nreturn_vals = 1;
809   *return_vals  = values;
810 
811   values[0].type          = GIMP_PDB_STATUS;
812   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
813 
814   if (strcmp (name, LOAD_PS_PROC)  == 0 ||
815       strcmp (name, LOAD_EPS_PROC) == 0)
816     {
817       switch (run_mode)
818         {
819         case GIMP_RUN_INTERACTIVE:
820           /*  Possibly retrieve data  */
821           gimp_get_data (LOAD_PS_PROC, &plvals);
822 
823           if (! load_dialog (param[1].data.d_string))
824             status = GIMP_PDB_CANCEL;
825           break;
826 
827         case GIMP_RUN_NONINTERACTIVE:
828           /*  Make sure all the arguments are there!  */
829           if (nparams != 3)
830             status = GIMP_PDB_CALLING_ERROR;
831           else    /* Get additional interpretation arguments */
832             gimp_get_data (LOAD_PS_PROC, &plvals);
833           break;
834 
835         case GIMP_RUN_WITH_LAST_VALS:
836           /* Possibly retrieve data */
837           gimp_get_data (LOAD_PS_PROC, &plvals);
838           break;
839 
840         default:
841           break;
842         }
843 
844       if (status == GIMP_PDB_SUCCESS)
845         {
846           check_load_vals ();
847           image_ID = load_image (param[1].data.d_string, &error);
848 
849           if (image_ID != -1)
850             {
851               *nreturn_vals = 2;
852               values[1].type         = GIMP_PDB_IMAGE;
853               values[1].data.d_image = image_ID;
854             }
855           else
856             {
857               status = GIMP_PDB_EXECUTION_ERROR;
858             }
859         }
860 
861       /*  Store plvals data  */
862       if (status == GIMP_PDB_SUCCESS)
863         gimp_set_data (LOAD_PS_PROC, &plvals, sizeof (PSLoadVals));
864     }
865   else if (strcmp (name, LOAD_PS_THUMB_PROC) == 0)
866     {
867       if (nparams < 2)
868         {
869           status = GIMP_PDB_CALLING_ERROR;
870         }
871       else
872         {
873           gint size = param[1].data.d_int32;
874 
875           /*  We should look for an embedded preview but for now we
876            *  just load the document at a small resolution and the
877            *  first page only.
878            */
879 
880           plvals.resolution = size / 4;
881           plvals.width      = size;
882           plvals.height     = size;
883           strncpy (plvals.pages, "1", sizeof (plvals.pages) - 1);
884 
885           check_load_vals ();
886           image_ID = load_image (param[0].data.d_string, &error);
887 
888           if (image_ID != -1)
889             {
890               *nreturn_vals = 2;
891               values[1].type         = GIMP_PDB_IMAGE;
892               values[1].data.d_image = image_ID;
893             }
894           else
895             {
896               status = GIMP_PDB_EXECUTION_ERROR;
897             }
898         }
899     }
900   else if (strcmp (name, SAVE_PS_PROC)  == 0 ||
901            strcmp (name, SAVE_EPS_PROC) == 0)
902     {
903       psvals.eps = strcmp (name, SAVE_PS_PROC);
904 
905       image_ID    = orig_image_ID = param[1].data.d_int32;
906       drawable_ID = param[2].data.d_int32;
907 
908       /* eventually export the image */
909       switch (run_mode)
910         {
911         case GIMP_RUN_INTERACTIVE:
912         case GIMP_RUN_WITH_LAST_VALS:
913           gimp_ui_init (PLUG_IN_BINARY, FALSE);
914 
915           export = gimp_export_image (&image_ID, &drawable_ID,
916                                       psvals.eps ? "EPS" : "PostScript",
917                                       GIMP_EXPORT_CAN_HANDLE_RGB  |
918                                       GIMP_EXPORT_CAN_HANDLE_GRAY |
919                                       GIMP_EXPORT_CAN_HANDLE_INDEXED);
920 
921           if (export == GIMP_EXPORT_CANCEL)
922             {
923               values[0].data.d_status = GIMP_PDB_CANCEL;
924               return;
925             }
926           break;
927         default:
928           break;
929         }
930 
931       switch (run_mode)
932         {
933         case GIMP_RUN_INTERACTIVE:
934           /*  Possibly retrieve data  */
935           gimp_get_data (name, &psvals);
936 
937           ps_set_save_size (&psvals, orig_image_ID);
938 
939           /*  First acquire information with a dialog  */
940           if (! save_dialog ())
941             status = GIMP_PDB_CANCEL;
942           break;
943 
944         case GIMP_RUN_NONINTERACTIVE:
945           /*  Make sure all the arguments are there!  */
946           if (nparams != 15)
947             {
948               status = GIMP_PDB_CALLING_ERROR;
949             }
950           else
951             {
952               psvals.width        = param[5].data.d_float;
953               psvals.height       = param[6].data.d_float;
954               psvals.x_offset     = param[7].data.d_float;
955               psvals.y_offset     = param[8].data.d_float;
956               psvals.unit_mm      = (param[9].data.d_int32 != 0);
957               psvals.keep_ratio   = (param[10].data.d_int32 != 0);
958               psvals.rotate       = param[11].data.d_int32;
959               psvals.eps          = (param[12].data.d_int32 != 0);
960               psvals.preview      = (param[13].data.d_int32 != 0);
961               psvals.preview_size = param[13].data.d_int32;
962               psvals.level        = param[14].data.d_int32;
963             }
964           break;
965 
966         case GIMP_RUN_WITH_LAST_VALS:
967           /*  Possibly retrieve data  */
968           gimp_get_data (name, &psvals);
969           break;
970 
971         default:
972           break;
973         }
974 
975       if (status == GIMP_PDB_SUCCESS)
976         {
977           if ((psvals.width == 0.0) || (psvals.height == 0.0))
978             ps_set_save_size (&psvals, orig_image_ID);
979 
980           check_save_vals ();
981 
982           if (save_image (g_file_new_for_uri (param[3].data.d_string),
983                           image_ID, drawable_ID,
984                           &error))
985             {
986               /*  Store psvals data  */
987               gimp_set_data (name, &psvals, sizeof (PSSaveVals));
988             }
989           else
990             {
991               status = GIMP_PDB_EXECUTION_ERROR;
992             }
993         }
994 
995       if (export == GIMP_EXPORT_EXPORT)
996         gimp_image_delete (image_ID);
997     }
998   else if (strcmp (name, LOAD_PS_SETARGS_PROC) == 0)
999     {
1000       /*  Make sure all the arguments are there!  */
1001       if (nparams != 8)
1002         {
1003           status = GIMP_PDB_CALLING_ERROR;
1004         }
1005       else
1006         {
1007           plvals.resolution = param[0].data.d_int32;
1008           plvals.width      = param[1].data.d_int32;
1009           plvals.height     = param[2].data.d_int32;
1010           plvals.use_bbox   = param[3].data.d_int32;
1011           if (param[4].data.d_string != NULL)
1012             strncpy (plvals.pages, param[4].data.d_string,
1013                      sizeof (plvals.pages));
1014           else
1015             plvals.pages[0] = '\0';
1016           plvals.pages[sizeof (plvals.pages) - 1] = '\0';
1017           plvals.pnm_type      = param[5].data.d_int32;
1018           plvals.textalpha     = param[6].data.d_int32;
1019           plvals.graphicsalpha = param[7].data.d_int32;
1020           check_load_vals ();
1021 
1022           gimp_set_data (LOAD_PS_PROC, &plvals, sizeof (PSLoadVals));
1023         }
1024     }
1025   else
1026     {
1027       status = GIMP_PDB_CALLING_ERROR;
1028     }
1029 
1030   if (status != GIMP_PDB_SUCCESS && error)
1031     {
1032       *nreturn_vals = 2;
1033       values[1].type          = GIMP_PDB_STRING;
1034       values[1].data.d_string = error->message;
1035     }
1036 
1037   values[0].data.d_status = status;
1038 }
1039 
1040 
1041 static gint32
load_image(const gchar * filename,GError ** error)1042 load_image (const gchar  *filename,
1043             GError      **error)
1044 {
1045   gint32    image_ID = 0;
1046   gint32   *image_list, *nl;
1047   guint     page_count;
1048   FILE     *ifp;
1049   gchar    *temp;
1050   gint      llx, lly, urx, ury;
1051   gint      k, n_images, max_images, max_pagenum;
1052   gboolean  is_epsf;
1053 
1054 #ifdef PS_DEBUG
1055   g_print ("load_image:\n resolution = %d\n", plvals.resolution);
1056   g_print (" %dx%d pixels\n", plvals.width, plvals.height);
1057   g_print (" BoundingBox: %d\n", plvals.use_bbox);
1058   g_print (" Coloring: %d\n", plvals.pnm_type);
1059   g_print (" TextAlphaBits: %d\n", plvals.textalpha);
1060   g_print (" GraphicsAlphaBits: %d\n", plvals.graphicsalpha);
1061 #endif
1062 
1063   gimp_progress_init_printf (_("Opening '%s'"),
1064                              gimp_filename_to_utf8 (filename));
1065 
1066   /* Try to see if PostScript file is available */
1067   ifp = g_fopen (filename, "r");
1068   if (ifp == NULL)
1069     {
1070       g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
1071                    _("Could not open '%s' for reading: %s"),
1072                    gimp_filename_to_utf8 (filename), g_strerror (errno));
1073       return -1;
1074     }
1075   fclose (ifp);
1076 
1077   ifp = ps_open (filename, &plvals, &llx, &lly, &urx, &ury, &is_epsf);
1078   if (!ifp)
1079     {
1080       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR,
1081                    _("Could not interpret PostScript file '%s'"),
1082                    gimp_filename_to_utf8 (filename));
1083       return -1;
1084     }
1085 
1086   image_list = g_new (gint32, 10);
1087   n_images = 0;
1088   max_images = 10;
1089 
1090   max_pagenum = 9999;  /* Try to get the maximum pagenumber to read */
1091   if (is_epsf)
1092     max_pagenum = 1;
1093 
1094   if (!page_in_list (plvals.pages, max_pagenum)) /* Is there a limit in list ? */
1095     {
1096       max_pagenum = -1;
1097       for (temp = plvals.pages; *temp != '\0'; temp++)
1098         {
1099           if ((*temp < '0') || (*temp > '9'))
1100             continue; /* Search next digit */
1101           sscanf (temp, "%d", &k);
1102           if (k > max_pagenum)
1103             max_pagenum = k;
1104           while ((*temp >= '0') && (*temp <= '9'))
1105             temp++;
1106           temp--;
1107         }
1108 
1109       if (max_pagenum < 1)
1110         max_pagenum = 9999;
1111     }
1112 
1113   /* Load all images */
1114   for (page_count = 1; page_count <= max_pagenum; page_count++)
1115     {
1116       if (page_in_list (plvals.pages, page_count))
1117         {
1118           image_ID = load_ps (filename, page_count, ifp, llx, lly, urx, ury);
1119           if (image_ID == -1)
1120             break;
1121 
1122           gimp_image_set_resolution (image_ID,
1123                                      (gdouble) plvals.resolution,
1124                                      (gdouble) plvals.resolution);
1125 
1126           if (n_images == max_images)
1127             {
1128               nl = (gint32 *) g_realloc (image_list,
1129                                          (max_images+10)*sizeof (gint32));
1130               if (nl == NULL) break;
1131               image_list = nl;
1132               max_images += 10;
1133             }
1134           image_list[n_images++] = image_ID;
1135         }
1136       else  /* Skip an image */
1137         {
1138           image_ID = -1;
1139           if (! skip_ps (ifp))
1140             break;
1141         }
1142     }
1143 
1144   ps_close (ifp);
1145 
1146   if (ps_pagemode == GIMP_PAGE_SELECTOR_TARGET_LAYERS)
1147     {
1148       for (k = 0; k < n_images; k++)
1149         {
1150           gchar *name;
1151 
1152           if (k == 0)
1153             {
1154               image_ID = image_list[0];
1155 
1156               name = g_strdup_printf (_("%s-pages"), filename);
1157               gimp_image_set_filename (image_ID, name);
1158               g_free (name);
1159             }
1160           else
1161             {
1162               gint32 current_layer;
1163               gint32 tmp_ID;
1164 
1165               tmp_ID = gimp_image_get_active_drawable (image_list[k]);
1166 
1167               name = gimp_item_get_name (tmp_ID);
1168 
1169               current_layer = gimp_layer_new_from_drawable (tmp_ID, image_ID);
1170               gimp_item_set_name (current_layer, name);
1171               gimp_image_insert_layer (image_ID, current_layer, -1, -1);
1172               gimp_image_delete (image_list[k]);
1173 
1174               g_free (name);
1175             }
1176         }
1177 
1178       gimp_image_undo_enable (image_ID);
1179     }
1180   else
1181     {
1182       /* Display images in reverse order.
1183        * The last will be displayed by GIMP itself
1184        */
1185       for (k = n_images - 1; k >= 0; k--)
1186         {
1187           gimp_image_undo_enable (image_list[k]);
1188           gimp_image_clean_all (image_list[k]);
1189 
1190           if (l_run_mode != GIMP_RUN_NONINTERACTIVE && k > 0)
1191             gimp_display_new (image_list[k]);
1192         }
1193 
1194       image_ID = (n_images > 0) ? image_list[0] : -1;
1195     }
1196 
1197   g_free (image_list);
1198 
1199   return image_ID;
1200 }
1201 
1202 
1203 static gboolean
save_image(GFile * file,gint32 image_ID,gint32 drawable_ID,GError ** error)1204 save_image (GFile   *file,
1205             gint32   image_ID,
1206             gint32   drawable_ID,
1207             GError **error)
1208 {
1209   GOutputStream *output;
1210   GCancellable  *cancellable;
1211   GimpImageType  drawable_type;
1212 
1213   drawable_type = gimp_drawable_type (drawable_ID);
1214 
1215   /*  Make sure we're not exporting an image with an alpha channel  */
1216   if (gimp_drawable_has_alpha (drawable_ID))
1217     {
1218       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
1219                    _("PostScript export cannot handle images with alpha channels"));
1220       return FALSE;
1221     }
1222 
1223   switch (drawable_type)
1224     {
1225     case GIMP_INDEXED_IMAGE:
1226     case GIMP_GRAY_IMAGE:
1227     case GIMP_RGB_IMAGE:
1228       break;
1229 
1230     default:
1231       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
1232                    _("Cannot operate on unknown image types."));
1233       return FALSE;
1234       break;
1235     }
1236 
1237   gimp_progress_init_printf (_("Exporting '%s'"),
1238                              gimp_file_get_utf8_name (file));
1239 
1240   output = G_OUTPUT_STREAM (g_file_replace (file,
1241                                             NULL, FALSE, G_FILE_CREATE_NONE,
1242                                             NULL, error));
1243   if (output)
1244     {
1245       GOutputStream *buffered;
1246 
1247       buffered = g_buffered_output_stream_new (output);
1248       g_object_unref (output);
1249 
1250       output = buffered;
1251     }
1252   else
1253     {
1254       return FALSE;
1255     }
1256 
1257   if (! save_ps_header (output, file, error))
1258     goto fail;
1259 
1260   switch (drawable_type)
1261     {
1262     case GIMP_INDEXED_IMAGE:
1263       if (! save_index (output, image_ID, drawable_ID, error))
1264         goto fail;
1265       break;
1266 
1267     case GIMP_GRAY_IMAGE:
1268       if (! save_gray (output, image_ID, drawable_ID, error))
1269         goto fail;
1270       break;
1271 
1272     case GIMP_RGB_IMAGE:
1273       if (! save_rgb (output, image_ID, drawable_ID, error))
1274         goto fail;
1275       break;
1276 
1277     default:
1278       g_return_val_if_reached (FALSE);
1279     }
1280 
1281   if (! save_ps_trailer (output, error))
1282     goto fail;
1283 
1284   if (! g_output_stream_close (output, NULL, error))
1285     goto fail;
1286 
1287   g_object_unref (output);
1288 
1289   return TRUE;
1290 
1291  fail:
1292 
1293   cancellable = g_cancellable_new ();
1294   g_cancellable_cancel (cancellable);
1295   g_output_stream_close (output, cancellable, NULL);
1296 
1297   g_object_unref (output);
1298   g_object_unref (cancellable);
1299 
1300   return FALSE;
1301 }
1302 
1303 
1304 /* Check (and correct) the load values plvals */
1305 static void
check_load_vals(void)1306 check_load_vals (void)
1307 {
1308   if (plvals.resolution < MIN_RESOLUTION)
1309     plvals.resolution = MIN_RESOLUTION;
1310   else if (plvals.resolution > MAX_RESOLUTION)
1311     plvals.resolution = MAX_RESOLUTION;
1312 
1313   if (plvals.width < 2)
1314     plvals.width = 2;
1315   if (plvals.height < 2)
1316     plvals.height = 2;
1317   plvals.use_bbox = (plvals.use_bbox != 0);
1318   if (plvals.pages[0] == '\0')
1319     strncpy (plvals.pages, "1-99", sizeof (plvals.pages) - 1);
1320   if ((plvals.pnm_type < 4) || (plvals.pnm_type > 7))
1321     plvals.pnm_type = 6;
1322   if (   (plvals.textalpha != 1) && (plvals.textalpha != 2)
1323       && (plvals.textalpha != 4))
1324     plvals.textalpha = 1;
1325   if (   (plvals.graphicsalpha != 1) && (plvals.graphicsalpha != 2)
1326       && (plvals.graphicsalpha != 4))
1327     plvals.graphicsalpha = 1;
1328 }
1329 
1330 
1331 /* Check (and correct) the save values psvals */
1332 static void
check_save_vals(void)1333 check_save_vals (void)
1334 {
1335   int i;
1336 
1337   i = psvals.rotate;
1338   if ((i != 0) && (i != 90) && (i != 180) && (i != 270))
1339     psvals.rotate = 90;
1340   if (psvals.preview_size <= 0)
1341     psvals.preview = FALSE;
1342 }
1343 
1344 
1345 /* Check if a page is in a given list */
1346 static gint
page_in_list(gchar * list,guint page_num)1347 page_in_list (gchar *list,
1348               guint  page_num)
1349 {
1350   char tmplist[STR_LENGTH], *c0, *c1;
1351   int state, start_num, end_num;
1352 #define READ_STARTNUM  0
1353 #define READ_ENDNUM    1
1354 #define CHK_LIST(a,b,c) {int low=(a),high=(b),swp; \
1355   if ((low>0) && (high>0)) { \
1356   if (low>high) {swp=low; low=high; high=swp;} \
1357   if ((low<=(c))&&(high>=(c))) return (1); } }
1358 
1359   if ((list == NULL) || (*list == '\0'))
1360     return 1;
1361 
1362   strncpy (tmplist, list, STR_LENGTH);
1363   tmplist[STR_LENGTH-1] = '\0';
1364 
1365   c0 = c1 = tmplist;
1366   while (*c1)    /* Remove all whitespace and break on unsupported characters */
1367     {
1368       if ((*c1 >= '0') && (*c1 <= '9'))
1369         {
1370           *(c0++) = *c1;
1371         }
1372       else if ((*c1 == '-') || (*c1 == ','))
1373         { /* Try to remove double occurrences of these characters */
1374           if (c0 == tmplist)
1375             {
1376               *(c0++) = *c1;
1377             }
1378           else
1379             {
1380               if (*(c0-1) != *c1)
1381                 *(c0++) = *c1;
1382             }
1383         }
1384       else
1385         break;
1386 
1387       c1++;
1388     }
1389 
1390   if (c0 == tmplist)
1391     return 1;
1392 
1393   *c0 = '\0';
1394 
1395   /* Now we have a comma separated list like 1-4-1,-3,1- */
1396 
1397   start_num = end_num = -1;
1398   state = READ_STARTNUM;
1399   for (c0 = tmplist; *c0 != '\0'; c0++)
1400     {
1401       switch (state)
1402         {
1403         case READ_STARTNUM:
1404           if (*c0 == ',')
1405             {
1406               if ((start_num > 0) && (start_num == (int)page_num))
1407                 return -1;
1408               start_num = -1;
1409             }
1410           else if (*c0 == '-')
1411             {
1412               if (start_num < 0) start_num = 1;
1413               state = READ_ENDNUM;
1414             }
1415           else /* '0' - '9' */
1416             {
1417               if (start_num < 0) start_num = 0;
1418               start_num *= 10;
1419               start_num += *c0 - '0';
1420             }
1421           break;
1422 
1423         case READ_ENDNUM:
1424           if (*c0 == ',')
1425             {
1426               if (end_num < 0) end_num = 9999;
1427               CHK_LIST (start_num, end_num, (int)page_num);
1428               start_num = end_num = -1;
1429               state = READ_STARTNUM;
1430             }
1431           else if (*c0 == '-')
1432             {
1433               CHK_LIST (start_num, end_num, (int)page_num);
1434               start_num = end_num;
1435               end_num = -1;
1436             }
1437           else /* '0' - '9' */
1438             {
1439               if (end_num < 0) end_num = 0;
1440               end_num *= 10;
1441               end_num += *c0 - '0';
1442             }
1443           break;
1444         }
1445     }
1446   if (state == READ_STARTNUM)
1447     {
1448       if (start_num > 0)
1449         return (start_num == (int) page_num);
1450     }
1451   else
1452     {
1453       if (end_num < 0) end_num = 9999;
1454       CHK_LIST (start_num, end_num, (int)page_num);
1455     }
1456 
1457   return 0;
1458 #undef CHK_LIST
1459 }
1460 
1461 
1462 /* A function like fgets, but treats single CR-character as line break. */
1463 /* As a line break the newline-character is returned. */
psfgets(char * s,int size,FILE * stream)1464 static char *psfgets (char *s, int size, FILE *stream)
1465 
1466 {
1467   int c;
1468   char *sptr = s;
1469 
1470   if (size <= 0)
1471     return NULL;
1472 
1473   if (size == 1)
1474     {
1475       *s = '\0';
1476       return NULL;
1477     }
1478 
1479   c = getc (stream);
1480   if (c == EOF)
1481     return NULL;
1482 
1483   for (;;)
1484     {
1485       /* At this point we have space in sptr for at least two characters */
1486       if (c == '\n')    /* Got end of line (UNIX line end) ? */
1487         {
1488           *(sptr++) = '\n';
1489           break;
1490         }
1491       else if (c == '\r')  /* Got a carriage return. Check next character */
1492         {
1493           c = getc (stream);
1494           if ((c == EOF) || (c == '\n')) /* EOF or DOS line end ? */
1495             {
1496               *(sptr++) = '\n';  /* Return UNIX line end */
1497               break;
1498             }
1499           else  /* Single carriage return. Return UNIX line end. */
1500             {
1501               ungetc (c, stream);  /* Save the extra character */
1502               *(sptr++) = '\n';
1503               break;
1504             }
1505         }
1506       else   /* no line end character */
1507         {
1508           *(sptr++) = (char)c;
1509           size--;
1510         }
1511       if (size == 1)
1512         break;  /* Only space for the nul-character ? */
1513 
1514       c = getc (stream);
1515       if (c == EOF)
1516         break;
1517     }
1518 
1519   *sptr = '\0';
1520 
1521   return s;
1522 }
1523 
1524 
1525 /* Get the BoundingBox of a PostScript file. On success, 0 is returned. */
1526 /* On failure, -1 is returned. */
1527 static gint
get_bbox(const gchar * filename,gint * x0,gint * y0,gint * x1,gint * y1)1528 get_bbox (const gchar *filename,
1529           gint        *x0,
1530           gint        *y0,
1531           gint        *x1,
1532           gint        *y1)
1533 {
1534   char line[1024], *src;
1535   FILE *ifp;
1536   int retval = -1;
1537 
1538   ifp = g_fopen (filename, "rb");
1539   if (ifp == NULL)
1540     return -1;
1541 
1542   for (;;)
1543     {
1544       if (psfgets (line, sizeof (line)-1, ifp) == NULL) break;
1545       if ((line[0] != '%') || (line[1] != '%')) continue;
1546       src = &(line[2]);
1547       while ((*src == ' ') || (*src == '\t')) src++;
1548       if (strncmp (src, "BoundingBox", 11) != 0) continue;
1549       src += 11;
1550       while ((*src == ' ') || (*src == '\t') || (*src == ':')) src++;
1551       if (strncmp (src, "(atend)", 7) == 0) continue;
1552       if (sscanf (src, "%d%d%d%d", x0, y0, x1, y1) == 4)
1553         retval = 0;
1554       break;
1555     }
1556   fclose (ifp);
1557 
1558   return retval;
1559 }
1560 
1561 static gchar *pnmfile;
1562 
1563 /* Open the PostScript file. On failure, NULL is returned. */
1564 /* The filepointer returned will give a PNM-file generated */
1565 /* by the PostScript-interpreter. */
1566 static FILE *
ps_open(const gchar * filename,const PSLoadVals * loadopt,gint * llx,gint * lly,gint * urx,gint * ury,gboolean * is_epsf)1567 ps_open (const gchar      *filename,
1568          const PSLoadVals *loadopt,
1569          gint             *llx,
1570          gint             *lly,
1571          gint             *urx,
1572          gint             *ury,
1573          gboolean         *is_epsf)
1574 {
1575   const gchar  *driver;
1576   GPtrArray    *cmdA;
1577   gchar       **pcmdA;
1578   FILE         *fd_popen = NULL;
1579   FILE         *eps_file;
1580   gint          width, height;
1581   gint          resolution;
1582   gint          x0, y0, x1, y1;
1583   gint          offx = 0;
1584   gint          offy = 0;
1585   gboolean      is_pdf;
1586   gboolean      maybe_epsf = FALSE;
1587   int           code;
1588   void         *instance = NULL;
1589 
1590   resolution = loadopt->resolution;
1591   *llx = *lly = 0;
1592   width = loadopt->width;
1593   height = loadopt->height;
1594   *urx = width - 1;
1595   *ury = height - 1;
1596 
1597   /* Check if the file is a PDF. For PDF, we can't set geometry */
1598   is_pdf = FALSE;
1599 
1600   /* Check if it is a EPS-file */
1601   *is_epsf = FALSE;
1602 
1603   eps_file = g_fopen (filename, "rb");
1604 
1605   if (eps_file != NULL)
1606     {
1607       gchar hdr[512];
1608 
1609       fread (hdr, 1, sizeof(hdr), eps_file);
1610       is_pdf = (strncmp (hdr, "%PDF", 4) == 0);
1611 
1612       if (!is_pdf)  /* Check for EPSF */
1613         {
1614           char *adobe, *epsf;
1615           int ds = 0;
1616           static unsigned char doseps[5] = { 0xc5, 0xd0, 0xd3, 0xc6, 0 };
1617 
1618           hdr[sizeof(hdr)-1] = '\0';
1619           adobe = strstr (hdr, "PS-Adobe-");
1620           epsf = strstr (hdr, "EPSF-");
1621 
1622           if ((adobe != NULL) && (epsf != NULL))
1623             ds = epsf - adobe;
1624 
1625           *is_epsf = ((ds >= 11) && (ds <= 15));
1626 
1627           /* Illustrator uses negative values in BoundingBox without marking */
1628           /* files as EPSF. Try to handle that. */
1629           maybe_epsf =
1630             (strstr (hdr, "%%Creator: Adobe Illustrator(R) 8.0") != 0);
1631 
1632           /* Check DOS EPS binary file */
1633           if ((!*is_epsf) && (strncmp (hdr, (char *)doseps, 4) == 0))
1634             *is_epsf = 1;
1635         }
1636 
1637       fclose (eps_file);
1638     }
1639 
1640   if ((!is_pdf) && (loadopt->use_bbox))    /* Try the BoundingBox ? */
1641     {
1642       if (get_bbox (filename, &x0, &y0, &x1, &y1) == 0)
1643         {
1644           if (maybe_epsf && ((x0 < 0) || (y0 < 0)))
1645             *is_epsf = 1;
1646 
1647           if (*is_epsf)  /* Handle negative BoundingBox for EPSF */
1648             {
1649               offx = -x0; x1 += offx; x0 += offx;
1650               offy = -y0; y1 += offy; y0 += offy;
1651             }
1652           if ((x0 >= 0) && (y0 >= 0) && (x1 > x0) && (y1 > y0))
1653             {
1654                *llx = (int)((x0/72.0) * resolution + 0.0001);
1655                *lly = (int)((y0/72.0) * resolution + 0.0001);
1656                /* Use upper bbox values as image size */
1657                width = (int)((x1/72.0) * resolution + 0.5);
1658                height = (int)((y1/72.0) * resolution + 0.5);
1659                /* Pixel coordinates must be one less */
1660                *urx = width - 1;
1661                *ury = height - 1;
1662                if (*urx < *llx) *urx = *llx;
1663                if (*ury < *lly) *ury = *lly;
1664             }
1665         }
1666     }
1667 
1668   switch (loadopt->pnm_type)
1669     {
1670     case 4:
1671       driver = "pbmraw";
1672       break;
1673     case 5:
1674       driver = "pgmraw";
1675       break;
1676     case 7:
1677       driver = "pnmraw";
1678       break;
1679     default:
1680       driver = "ppmraw";
1681       break;
1682     }
1683 
1684   /* For instance, the Win32 port of ghostscript doesn't work correctly when
1685    * using standard output as output file.
1686    * Thus, use a real output file.
1687    */
1688   pnmfile = gimp_temp_name ("pnm");
1689 
1690   /* Build command array */
1691   cmdA = g_ptr_array_new ();
1692 
1693   g_ptr_array_add (cmdA, g_strdup (g_get_prgname ()));
1694   g_ptr_array_add (cmdA, g_strdup_printf ("-sDEVICE=%s", driver));
1695   g_ptr_array_add (cmdA, g_strdup_printf ("-r%d", resolution));
1696 
1697   if (is_pdf)
1698     {
1699       /* Acrobat Reader honors CropBox over MediaBox, so let's match that
1700        * behavior.
1701        */
1702       g_ptr_array_add (cmdA, g_strdup ("-dUseCropBox"));
1703     }
1704   else
1705     {
1706       /* For PDF, we can't set geometry */
1707       g_ptr_array_add (cmdA, g_strdup_printf ("-g%dx%d", width, height));
1708     }
1709 
1710   /* Antialiasing not available for PBM-device */
1711   if ((loadopt->pnm_type != 4) && (loadopt->textalpha != 1))
1712     g_ptr_array_add (cmdA, g_strdup_printf ("-dTextAlphaBits=%d",
1713                                             loadopt->textalpha));
1714   if ((loadopt->pnm_type != 4) && (loadopt->graphicsalpha != 1))
1715     g_ptr_array_add (cmdA, g_strdup_printf ("-dGraphicsAlphaBits=%d",
1716                                             loadopt->graphicsalpha));
1717   g_ptr_array_add (cmdA, g_strdup ("-q"));
1718   g_ptr_array_add (cmdA, g_strdup ("-dBATCH"));
1719   g_ptr_array_add (cmdA, g_strdup ("-dNOPAUSE"));
1720 
1721   /* If no additional options specified, use at least -dSAFER */
1722   if (g_getenv ("GS_OPTIONS") == NULL)
1723     g_ptr_array_add (cmdA, g_strdup ("-dSAFER"));
1724 
1725   /* Output file name */
1726   g_ptr_array_add (cmdA, g_strdup_printf ("-sOutputFile=%s", pnmfile));
1727 
1728   /* Offset command for gs to get image part with negative x/y-coord. */
1729   if ((offx != 0) || (offy != 0))
1730     {
1731       g_ptr_array_add (cmdA, g_strdup ("-c"));
1732       g_ptr_array_add (cmdA, g_strdup_printf ("%d", offx));
1733       g_ptr_array_add (cmdA, g_strdup_printf ("%d", offy));
1734       g_ptr_array_add (cmdA, g_strdup ("translate"));
1735     }
1736 
1737   /* input file name */
1738   g_ptr_array_add (cmdA, g_strdup ("-f"));
1739   g_ptr_array_add (cmdA, g_strdup (filename));
1740 
1741   if (*is_epsf)
1742     {
1743       g_ptr_array_add (cmdA, g_strdup ("-c"));
1744       g_ptr_array_add (cmdA, g_strdup ("showpage"));
1745     }
1746 
1747   g_ptr_array_add (cmdA, g_strdup ("-c"));
1748   g_ptr_array_add (cmdA, g_strdup ("quit"));
1749   g_ptr_array_add (cmdA, NULL);
1750 
1751   pcmdA = (gchar **) cmdA->pdata;
1752 
1753 #ifdef PS_DEBUG
1754   {
1755     gchar **p = pcmdA;
1756     g_print ("Passing args (argc=%d):\n", cmdA->len - 1);
1757 
1758     while (*p)
1759       {
1760         g_print ("%s\n", *p);
1761         p++;
1762       }
1763   }
1764 #endif
1765 
1766   code = gsapi_new_instance (&instance, NULL);
1767   if (code == 0) {
1768     code = gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_UTF8);
1769     code = gsapi_init_with_args (instance, cmdA->len - 1, pcmdA);
1770     code = gsapi_exit (instance);
1771     gsapi_delete_instance (instance);
1772   }
1773 
1774   /* Don't care about exit status of ghostscript. */
1775   /* Just try to read what it wrote. */
1776 
1777   fd_popen = g_fopen (pnmfile, "rb");
1778 
1779   g_ptr_array_free (cmdA, FALSE);
1780   g_strfreev (pcmdA);
1781 
1782   return fd_popen;
1783 }
1784 
1785 
1786 /* Close the PNM-File of the PostScript interpreter */
1787 static void
ps_close(FILE * ifp)1788 ps_close (FILE *ifp)
1789 {
1790  /* If a real outputfile was used, close the file and remove it. */
1791   fclose (ifp);
1792   g_unlink (pnmfile);
1793 }
1794 
1795 
1796 /* Read the header of a raw PNM-file and return type (4-6) or -1 on failure */
1797 static gint
read_pnmraw_type(FILE * ifp,gint * width,gint * height,gint * maxval)1798 read_pnmraw_type (FILE *ifp,
1799                   gint *width,
1800                   gint *height,
1801                   gint *maxval)
1802 {
1803   int frst, scnd, thrd;
1804   gint  pnmtype;
1805   gchar line[1024];
1806 
1807   /* GhostScript may write some informational messages infront of the header. */
1808   /* We are just looking at a Px\n in the input stream. */
1809   frst = getc (ifp);
1810   scnd = getc (ifp);
1811   thrd = getc (ifp);
1812   for (;;)
1813     {
1814       if (thrd == EOF) return -1;
1815 #ifdef G_OS_WIN32
1816       if (thrd == '\r') thrd = getc (ifp);
1817 #endif
1818       if ((thrd == '\n') && (frst == 'P') && (scnd >= '1') && (scnd <= '6'))
1819         break;
1820       frst = scnd;
1821       scnd = thrd;
1822       thrd = getc (ifp);
1823     }
1824   pnmtype = scnd - '0';
1825   /* We don't use the ASCII-versions */
1826   if ((pnmtype >= 1) && (pnmtype <= 3))
1827     return -1;
1828 
1829   /* Read width/height */
1830   for (;;)
1831     {
1832       if (fgets (line, sizeof (line)-1, ifp) == NULL)
1833         return -1;
1834       if (line[0] != '#')
1835         break;
1836     }
1837   if (sscanf (line, "%d%d", width, height) != 2)
1838     return -1;
1839 
1840   *maxval = 255;
1841 
1842   if (pnmtype != 4)  /* Read maxval */
1843     {
1844       for (;;)
1845         {
1846           if (fgets (line, sizeof (line)-1, ifp) == NULL)
1847             return -1;
1848           if (line[0] != '#')
1849             break;
1850         }
1851       if (sscanf (line, "%d", maxval) != 1)
1852         return -1;
1853     }
1854 
1855   return pnmtype;
1856 }
1857 
1858 
1859 /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
1860 static gint32
create_new_image(const gchar * filename,guint pagenum,guint width,guint height,GimpImageBaseType type,gint32 * layer_ID)1861 create_new_image (const gchar        *filename,
1862                   guint               pagenum,
1863                   guint               width,
1864                   guint               height,
1865                   GimpImageBaseType   type,
1866                   gint32             *layer_ID)
1867 {
1868   gint32         image_ID;
1869   GimpImageType  gdtype;
1870   gchar         *tmp;
1871 
1872   switch (type)
1873     {
1874     case GIMP_GRAY:
1875       gdtype = GIMP_GRAY_IMAGE;
1876       break;
1877     case GIMP_INDEXED:
1878       gdtype = GIMP_INDEXED_IMAGE;
1879       break;
1880     case GIMP_RGB:
1881     default:
1882       gdtype = GIMP_RGB_IMAGE;
1883     }
1884 
1885   image_ID = gimp_image_new_with_precision (width, height, type,
1886                                             GIMP_PRECISION_U8_GAMMA);
1887   gimp_image_undo_disable (image_ID);
1888 
1889   tmp = g_strdup_printf ("%s-%d", filename, pagenum);
1890   gimp_image_set_filename (image_ID, tmp);
1891   g_free (tmp);
1892 
1893   tmp = g_strdup_printf (_("Page %d"), pagenum);
1894   *layer_ID = gimp_layer_new (image_ID, tmp, width, height,
1895                               gdtype,
1896                               100,
1897                               gimp_image_get_default_new_layer_mode (image_ID));
1898   g_free (tmp);
1899 
1900   gimp_image_insert_layer (image_ID, *layer_ID, -1, 0);
1901 
1902   return image_ID;
1903 }
1904 
1905 
1906 /* Skip PNM image generated from PostScript file. */
1907 /* Return TRUE on success, FALSE otherwise.       */
1908 static gboolean
skip_ps(FILE * ifp)1909 skip_ps (FILE *ifp)
1910 {
1911   guchar  buf[8192];
1912   gsize   len;
1913   gint    pnmtype, width, height, maxval, bpl;
1914 
1915   pnmtype = read_pnmraw_type (ifp, &width, &height, &maxval);
1916 
1917   if (pnmtype == 4)    /* Portable bitmap */
1918     bpl = (width + 7) / 8;
1919   else if (pnmtype == 5)
1920     bpl = width;
1921   else if (pnmtype == 6)
1922     bpl = width * 3;
1923   else
1924     return FALSE;
1925 
1926   len = bpl * height;
1927   while (len)
1928     {
1929       gsize  bytes = fread (buf, 1, MIN (len, sizeof (buf)), ifp);
1930 
1931       if (bytes < MIN (len, sizeof (buf)))
1932         return FALSE;
1933 
1934       len -= bytes;
1935     }
1936 
1937   return TRUE;
1938 }
1939 
1940 
1941 /* Load PNM image generated from PostScript file */
1942 static gint32
load_ps(const gchar * filename,guint pagenum,FILE * ifp,gint llx,gint lly,gint urx,gint ury)1943 load_ps (const gchar *filename,
1944          guint        pagenum,
1945          FILE        *ifp,
1946          gint         llx,
1947          gint         lly,
1948          gint         urx,
1949          gint         ury)
1950 {
1951   guchar *dest;
1952   guchar *data, *bitline = NULL, *byteline = NULL, *byteptr, *temp;
1953   guchar bit2byte[256*8];
1954   int width, height, tile_height, scan_lines, total_scan_lines;
1955   int image_width, image_height;
1956   int skip_left, skip_bottom;
1957   int i, j, pnmtype, maxval, bpp, nread;
1958   GimpImageBaseType imagetype;
1959   gint32 layer_ID, image_ID;
1960   GeglBuffer *buffer = NULL;
1961   int err = 0, e;
1962 
1963   pnmtype = read_pnmraw_type (ifp, &width, &height, &maxval);
1964 
1965   if ((width == urx+1) && (height == ury+1))  /* gs respected BoundingBox ? */
1966     {
1967       skip_left = llx;    skip_bottom = lly;
1968       image_width = width - skip_left;
1969       image_height = height - skip_bottom;
1970     }
1971   else
1972     {
1973       skip_left = skip_bottom = 0;
1974       image_width = width;
1975       image_height = height;
1976     }
1977   if (pnmtype == 4)   /* Portable Bitmap */
1978     {
1979       imagetype = GIMP_INDEXED;
1980       nread = (width+7)/8;
1981       bpp = 1;
1982       bitline = g_new (guchar, nread);
1983       byteline = g_new (guchar, nread * 8);
1984 
1985       /* Get an array for mapping 8 bits in a byte to 8 bytes */
1986       temp = bit2byte;
1987       for (j = 0; j < 256; j++)
1988         for (i = 7; i >= 0; i--)
1989           *(temp++) = ((j & (1 << i)) != 0);
1990     }
1991   else if (pnmtype == 5)  /* Portable Greymap */
1992     {
1993       imagetype = GIMP_GRAY;
1994       nread = width;
1995       bpp = 1;
1996       byteline = g_new (guchar, nread);
1997     }
1998   else if (pnmtype == 6)  /* Portable Pixmap */
1999     {
2000       imagetype = GIMP_RGB;
2001       nread = width * 3;
2002       bpp = 3;
2003       byteline = g_new (guchar, nread);
2004     }
2005   else
2006     return -1;
2007 
2008   image_ID = create_new_image (filename, pagenum,
2009                                image_width, image_height, imagetype,
2010                                &layer_ID);
2011   buffer = gimp_drawable_get_buffer (layer_ID);
2012 
2013   tile_height = gimp_tile_height ();
2014   data = g_malloc (tile_height * image_width * bpp);
2015 
2016   dest = data;
2017   total_scan_lines = scan_lines = 0;
2018 
2019   if (pnmtype == 4)   /* Read bitimage ? Must be mapped to indexed */
2020     {
2021       const guchar BWColorMap[2*3] = { 255, 255, 255, 0, 0, 0 };
2022 
2023       gimp_image_set_colormap (image_ID, BWColorMap, 2);
2024 
2025       for (i = 0; i < height; i++)
2026         {
2027           e = (fread (bitline, 1, nread, ifp) != nread);
2028           if (total_scan_lines >= image_height)
2029             continue;
2030           err |= e;
2031           if (err)
2032             break;
2033 
2034           j = width;   /* Map 1 byte of bitimage to 8 bytes of indexed image */
2035           temp = bitline;
2036           byteptr = byteline;
2037           while (j >= 8)
2038             {
2039               memcpy (byteptr, bit2byte + *(temp++)*8, 8);
2040               byteptr += 8;
2041               j -= 8;
2042             }
2043           if (j > 0)
2044             memcpy (byteptr, bit2byte + *temp*8, j);
2045 
2046           memcpy (dest, byteline+skip_left, image_width);
2047           dest += image_width;
2048           scan_lines++;
2049           total_scan_lines++;
2050 
2051           if ((scan_lines == tile_height) || ((i + 1) == image_height))
2052             {
2053               gegl_buffer_set (buffer,
2054                                GEGL_RECTANGLE (0, i-scan_lines+1,
2055                                                image_width, scan_lines),
2056                                0,
2057                                NULL,
2058                                data,
2059                                GEGL_AUTO_ROWSTRIDE);
2060               scan_lines = 0;
2061               dest = data;
2062             }
2063 
2064           if ((i % 20) == 0)
2065             gimp_progress_update ((gdouble) (i + 1) / (gdouble) image_height);
2066 
2067           if (err)
2068             break;
2069         }
2070     }
2071   else   /* Read gray/rgb-image */
2072     {
2073       for (i = 0; i < height; i++)
2074         {
2075           e = (fread (byteline, bpp, width, ifp) != width);
2076           if (total_scan_lines >= image_height)
2077             continue;
2078           err |= e;
2079           if (err)
2080             break;
2081 
2082           memcpy (dest, byteline+skip_left*bpp, image_width*bpp);
2083           dest += image_width*bpp;
2084           scan_lines++;
2085           total_scan_lines++;
2086 
2087           if ((scan_lines == tile_height) || ((i + 1) == image_height))
2088             {
2089               gegl_buffer_set (buffer,
2090                                GEGL_RECTANGLE (0, i-scan_lines+1,
2091                                                image_width, scan_lines),
2092                                0,
2093                                NULL,
2094                                data,
2095                                GEGL_AUTO_ROWSTRIDE);
2096               scan_lines = 0;
2097               dest = data;
2098             }
2099 
2100           if ((i % 20) == 0)
2101             gimp_progress_update ((gdouble) (i + 1) / (gdouble) image_height);
2102 
2103           if (err)
2104             break;
2105         }
2106     }
2107   gimp_progress_update (1.0);
2108 
2109   g_free (data);
2110   g_free (byteline);
2111   g_free (bitline);
2112 
2113   if (err)
2114     g_message ("EOF encountered on reading");
2115 
2116   g_object_unref (buffer);
2117 
2118   return (err ? -1 : image_ID);
2119 }
2120 
2121 
2122 /* Write out the PostScript file header */
2123 static gboolean
save_ps_header(GOutputStream * output,GFile * file,GError ** error)2124 save_ps_header (GOutputStream  *output,
2125                 GFile          *file,
2126                 GError        **error)
2127 {
2128   gchar  *basename = g_path_get_basename (gimp_file_get_utf8_name (file));
2129   time_t  cutime   = time (NULL);
2130 
2131   if (! print (output, error,
2132                "%%!PS-Adobe-3.0%s\n", psvals.eps ? " EPSF-3.0" : ""))
2133     goto fail;
2134 
2135   if (! print (output, error,
2136                "%%%%Creator: GIMP PostScript file plug-in V %4.2f "
2137                "by Peter Kirchgessner\n", VERSIO))
2138     goto fail;
2139 
2140   if (! print (output, error,
2141                "%%%%Title: %s\n"
2142                "%%%%CreationDate: %s"
2143                "%%%%DocumentData: Clean7Bit\n",
2144                basename, ctime (&cutime)))
2145     goto fail;
2146 
2147   if (psvals.eps || (psvals.level > 1))
2148     if (! print (output, error,"%%%%LanguageLevel: 2\n"))
2149       goto fail;
2150 
2151   if (! print (output, error, "%%%%Pages: 1\n"))
2152     goto fail;
2153 
2154   g_free (basename);
2155 
2156   return TRUE;
2157 
2158  fail:
2159 
2160   g_free (basename);
2161 
2162   return FALSE;
2163 }
2164 
2165 
2166 /* Write out transformation for image */
2167 static gboolean
save_ps_setup(GOutputStream * output,gint32 drawable_ID,gint width,gint height,gint bpp,GError ** error)2168 save_ps_setup (GOutputStream  *output,
2169                gint32          drawable_ID,
2170                gint            width,
2171                gint            height,
2172                gint            bpp,
2173                GError        **error)
2174 {
2175   gdouble x_offset, y_offset, x_size, y_size;
2176   gdouble urx, ury;
2177   gdouble width_inch, height_inch;
2178   gdouble f1, f2, dx, dy;
2179   gint    xtrans, ytrans;
2180   gint    i_urx, i_ury;
2181   gchar   tmpbuf1[G_ASCII_DTOSTR_BUF_SIZE];
2182   gchar   tmpbuf2[G_ASCII_DTOSTR_BUF_SIZE];
2183 
2184   /* initialize */
2185 
2186   dx = 0.0;
2187   dy = 0.0;
2188 
2189   x_offset    = psvals.x_offset;
2190   y_offset    = psvals.y_offset;
2191   width_inch  = fabs (psvals.width);
2192   height_inch = fabs (psvals.height);
2193 
2194   if (psvals.unit_mm)
2195     {
2196       x_offset /= 25.4; y_offset /= 25.4;
2197       width_inch /= 25.4; height_inch /= 25.4;
2198     }
2199 
2200   if (psvals.keep_ratio)   /* Proportions to keep ? */
2201     {                        /* Fit the image into the allowed size */
2202       f1 = width_inch / width;
2203       f2 = height_inch / height;
2204       if (f1 < f2)
2205         height_inch = width_inch * (gdouble) height / (gdouble) width;
2206       else
2207         width_inch = fabs (height_inch) * (gdouble) width / (gdouble) height;
2208     }
2209 
2210   if ((psvals.rotate == 0) || (psvals.rotate == 180))
2211     {
2212       x_size = width_inch;
2213       y_size = height_inch;
2214     }
2215   else
2216     {
2217       y_size = width_inch;
2218       x_size = height_inch;
2219     }
2220 
2221   /* Round up upper right corner only for non-integer values */
2222   urx = (x_offset + x_size) * 72.0;
2223   ury = (y_offset + y_size) * 72.0;
2224   i_urx = (gint) urx;
2225   i_ury = (gint) ury;
2226   if (urx != (gdouble) i_urx) i_urx++;  /* Check for non-integer value */
2227   if (ury != (gdouble) i_ury) i_ury++;
2228 
2229   if (! print (output, error,
2230                "%%%%BoundingBox: %d %d %d %d\n"
2231                "%%%%EndComments\n",
2232                (gint) (x_offset * 72.0), (gint) (y_offset * 72.0), i_urx, i_ury))
2233     return FALSE;
2234 
2235   if (psvals.preview && (psvals.preview_size > 0))
2236     {
2237       if (! save_ps_preview (output, drawable_ID, error))
2238         return FALSE;
2239     }
2240 
2241   if (! print (output, error,
2242                "%%%%BeginProlog\n"
2243                "%% Use own dictionary to avoid conflicts\n"
2244                "10 dict begin\n"
2245                "%%%%EndProlog\n"
2246                "%%%%Page: 1 1\n"
2247                "%% Translate for offset\n"
2248                "%s %s translate\n",
2249                g_ascii_dtostr (tmpbuf1, sizeof (tmpbuf1), x_offset * 72.0),
2250                g_ascii_dtostr (tmpbuf2, sizeof (tmpbuf2), y_offset * 72.0)))
2251     return FALSE;
2252 
2253   /* Calculate translation to startpoint of first scanline */
2254   switch (psvals.rotate)
2255     {
2256     case   0: dx = 0.0; dy = y_size * 72.0;
2257       break;
2258     case  90: dx = dy = 0.0;
2259       break;
2260     case 180: dx = x_size * 72.0; dy = 0.0;
2261       break;
2262     case 270: dx = x_size * 72.0; dy = y_size * 72.0;
2263       break;
2264     }
2265 
2266   if ((dx != 0.0) || (dy != 0.0))
2267     {
2268       if (! print (output, error,
2269                    "%% Translate to begin of first scanline\n"
2270                    "%s %s translate\n",
2271                    g_ascii_dtostr (tmpbuf1, sizeof (tmpbuf1), dx),
2272                    g_ascii_dtostr (tmpbuf2, sizeof (tmpbuf2), dy)))
2273         return FALSE;
2274     }
2275 
2276   if (psvals.rotate)
2277     if (! print (output, error, "%d rotate\n", (gint) psvals.rotate))
2278       return FALSE;
2279 
2280   if (! print (output, error,
2281                "%s %s scale\n",
2282                g_ascii_dtostr (tmpbuf1, sizeof (tmpbuf1),  72.0 * width_inch),
2283                g_ascii_dtostr (tmpbuf2, sizeof (tmpbuf2), -72.0 * height_inch)))
2284     return FALSE;
2285 
2286   /* Write the PostScript procedures to read the image */
2287   if (psvals.level <= 1)
2288     {
2289       if (! print (output, error,
2290                    "%% Variable to keep one line of raster data\n"))
2291         return FALSE;
2292 
2293       if (bpp == 1)
2294         {
2295           if (! print (output, error,
2296                        "/scanline %d string def\n", (width + 7) / 8))
2297             return FALSE;
2298         }
2299       else
2300         {
2301           if (! print (output, error,
2302                        "/scanline %d %d mul string def\n", width, bpp / 8))
2303             return FALSE;
2304         }
2305     }
2306 
2307   if (! print (output, error,
2308                "%% Image geometry\n%d %d %d\n"
2309                "%% Transformation matrix\n",
2310                width, height, (bpp == 1) ? 1 : 8))
2311     return FALSE;
2312 
2313   xtrans = ytrans = 0;
2314   if (psvals.width  < 0.0) { width  = -width;  xtrans = -width;  }
2315   if (psvals.height < 0.0) { height = -height; ytrans = -height; }
2316 
2317   if (! print (output, error,
2318                "[ %d 0 0 %d %d %d ]\n", width, height, xtrans, ytrans))
2319     return FALSE;
2320 
2321   return TRUE;
2322 }
2323 
2324 static gboolean
save_ps_trailer(GOutputStream * output,GError ** error)2325 save_ps_trailer (GOutputStream  *output,
2326                  GError        **error)
2327 {
2328   return print (output, error,
2329                 "%%%%Trailer\n"
2330                 "end\n%%%%EOF\n");
2331 }
2332 
2333 /* Do a Floyd-Steinberg dithering on a grayscale scanline. */
2334 /* linecount must keep the counter for the actual scanline (0, 1, 2, ...). */
2335 /* If linecount is less than zero, all used memory is freed. */
2336 
2337 static void
dither_grey(const guchar * grey,guchar * bw,gint npix,gint linecount)2338 dither_grey (const guchar *grey,
2339              guchar       *bw,
2340              gint          npix,
2341              gint          linecount)
2342 {
2343   static gboolean  do_init_arrays = TRUE;
2344   static gint     *fs_error = NULL;
2345   static gint      limit[1278];
2346   static gint      east_error[256];
2347   static gint      seast_error[256];
2348   static gint      south_error[256];
2349   static gint      swest_error[256];
2350 
2351   const guchar *greyptr;
2352   guchar       *bwptr, mask;
2353   gint         *fse;
2354   gint          x, greyval, fse_inline;
2355 
2356   if (linecount <= 0)
2357     {
2358       g_free (fs_error);
2359 
2360       if (linecount < 0)
2361         return;
2362 
2363       fs_error = g_new0 (gint, npix + 2);
2364 
2365       /* Initialize some arrays that speed up dithering */
2366       if (do_init_arrays)
2367         {
2368           gint i;
2369 
2370           do_init_arrays = FALSE;
2371 
2372           for (i = 0, x = -511; x <= 766; i++, x++)
2373             limit[i] = (x < 0) ? 0 : ((x > 255) ? 255 : x);
2374 
2375           for (greyval = 0; greyval < 256; greyval++)
2376             {
2377               east_error[greyval] = (greyval < 128) ?
2378                 ((greyval * 79) >> 8) : (((greyval - 255) * 79) >> 8);
2379               seast_error[greyval] = (greyval < 128) ?
2380                 ((greyval * 34) >> 8) : (((greyval - 255) * 34) >> 8);
2381               south_error[greyval] = (greyval < 128) ?
2382                 ((greyval * 56) >> 8) : (((greyval - 255) * 56) >> 8);
2383               swest_error[greyval] = (greyval < 128) ?
2384                 ((greyval * 12) >> 8) : (((greyval - 255) * 12) >> 8);
2385             }
2386         }
2387     }
2388 
2389   g_return_if_fail (fs_error != NULL);
2390 
2391   memset (bw, 0, (npix + 7) / 8); /* Initialize with white */
2392 
2393   greyptr = grey;
2394   bwptr = bw;
2395   mask = 0x80;
2396 
2397   fse_inline = fs_error[1];
2398 
2399   for (x = 0, fse = fs_error + 1; x < npix; x++, fse++)
2400     {
2401       greyval =
2402         limit[*(greyptr++) + fse_inline + 512];  /* 0 <= greyval <= 255 */
2403 
2404       if (greyval < 128)
2405         *bwptr |= mask;  /* Set a black pixel */
2406 
2407       /* Error distribution */
2408       fse_inline = east_error[greyval] + fse[1];
2409       fse[1] = seast_error[greyval];
2410       fse[0] += south_error[greyval];
2411       fse[-1] += swest_error[greyval];
2412 
2413       mask >>= 1;   /* Get mask for next b/w-pixel */
2414 
2415       if (!mask)
2416         {
2417           mask = 0x80;
2418           bwptr++;
2419         }
2420     }
2421 }
2422 
2423 /* Write a device independent screen preview */
2424 static gboolean
save_ps_preview(GOutputStream * output,gint32 drawable_ID,GError ** error)2425 save_ps_preview (GOutputStream  *output,
2426                  gint32          drawable_ID,
2427                  GError        **error)
2428 {
2429   GimpImageType  drawable_type;
2430   GeglBuffer    *buffer = NULL;
2431   const Babl    *format;
2432   gint           bpp;
2433   guchar        *bwptr, *greyptr;
2434   gint           width, height, x, y, nbsl, out_count;
2435   gint           nchar_pl = 72, src_y;
2436   gdouble        f1, f2;
2437   guchar        *grey, *bw, *src_row, *src_ptr;
2438   guchar        *cmap;
2439   gint           ncols, cind;
2440 
2441   if (psvals.preview_size <= 0)
2442     return TRUE;
2443 
2444   buffer = gimp_drawable_get_buffer (drawable_ID);
2445   cmap = NULL;
2446 
2447   drawable_type = gimp_drawable_type (drawable_ID);
2448   switch (drawable_type)
2449     {
2450     case GIMP_GRAY_IMAGE:
2451       format = babl_format ("Y' u8");
2452       break;
2453 
2454     case GIMP_INDEXED_IMAGE:
2455       cmap = gimp_image_get_colormap (gimp_item_get_image (drawable_ID),
2456                                       &ncols);
2457       format = gimp_drawable_get_format (drawable_ID);
2458       break;
2459 
2460     case GIMP_RGB_IMAGE:
2461     default:
2462       format = babl_format ("R'G'B' u8");
2463       break;
2464     }
2465 
2466   bpp = babl_format_get_bytes_per_pixel (format);
2467 
2468   width = gegl_buffer_get_width (buffer);
2469   height = gegl_buffer_get_height (buffer);
2470 
2471   /* Calculate size of preview */
2472   if ((width > psvals.preview_size) ||
2473       (height > psvals.preview_size))
2474     {
2475       f1 = (gdouble) psvals.preview_size / (gdouble) width;
2476       f2 = (gdouble) psvals.preview_size / (gdouble) height;
2477 
2478       if (f1 < f2)
2479         {
2480           width = psvals.preview_size;
2481           height *= f1;
2482           if (height <= 0)
2483             height = 1;
2484         }
2485       else
2486         {
2487           height = psvals.preview_size;
2488           width *= f1;
2489           if (width <= 0)
2490             width = 1;
2491         }
2492     }
2493 
2494   nbsl = (width + 7) / 8;  /* Number of bytes per scanline in bitmap */
2495 
2496   grey    = g_new (guchar, width);
2497   bw      = g_new (guchar, nbsl);
2498   src_row = g_new (guchar, gegl_buffer_get_width (buffer) * bpp);
2499 
2500   if (! print (output, error,
2501                "%%%%BeginPreview: %d %d 1 %d\n",
2502                width, height,
2503                ((nbsl * 2 + nchar_pl - 1) / nchar_pl) * height))
2504     goto fail;
2505 
2506   for (y = 0; y < height; y++)
2507     {
2508       /* Get a scanline from the input image and scale it to the desired
2509          width */
2510       src_y = (y * gegl_buffer_get_height (buffer)) / height;
2511       gegl_buffer_get (buffer,
2512                        GEGL_RECTANGLE (0, src_y,
2513                                        gegl_buffer_get_width (buffer), 1),
2514                        1.0, format, src_row,
2515                        GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
2516 
2517       greyptr = grey;
2518       if (bpp == 3)   /* RGB-image */
2519         {
2520           for (x = 0; x < width; x++)
2521             {                       /* Convert to grey */
2522               src_ptr = src_row + ((x * gegl_buffer_get_width (buffer)) / width) * 3;
2523               *(greyptr++) = (3*src_ptr[0] + 6*src_ptr[1] + src_ptr[2]) / 10;
2524             }
2525         }
2526       else if (cmap)    /* Indexed image */
2527         {
2528           for (x = 0; x < width; x++)
2529             {
2530               src_ptr = src_row + ((x * gegl_buffer_get_width (buffer)) / width);
2531               cind = *src_ptr;   /* Get color index and convert to grey */
2532               src_ptr = (cind >= ncols) ? cmap : (cmap + 3*cind);
2533               *(greyptr++) = (3*src_ptr[0] + 6*src_ptr[1] + src_ptr[2]) / 10;
2534             }
2535         }
2536       else             /* Grey image */
2537         {
2538           for (x = 0; x < width; x++)
2539             *(greyptr++) = *(src_row + ((x * gegl_buffer_get_width (buffer)) / width));
2540         }
2541 
2542       /* Now we have a grayscale line for the desired width. */
2543       /* Dither it to b/w */
2544       dither_grey (grey, bw, width, y);
2545 
2546       /* Write out the b/w line */
2547       out_count = 0;
2548       bwptr = bw;
2549       for (x = 0; x < nbsl; x++)
2550         {
2551           if (out_count == 0)
2552             if (! print (output, error, "%% "))
2553               goto fail;
2554 
2555           if (! print (output, error, "%02x", *(bwptr++)))
2556             goto fail;
2557 
2558           out_count += 2;
2559           if (out_count >= nchar_pl)
2560             {
2561               if (! print (output, error, "\n"))
2562                 goto fail;
2563 
2564               out_count = 0;
2565             }
2566         }
2567 
2568       if (! print (output, error, "\n"))
2569         goto fail;
2570 
2571       if ((y % 20) == 0)
2572         gimp_progress_update ((gdouble) y / (gdouble) height);
2573     }
2574 
2575   gimp_progress_update (1.0);
2576 
2577   if (! print (output, error, "%%%%EndPreview\n"))
2578     goto fail;
2579 
2580   dither_grey (grey, bw, width, -1);
2581   g_free (src_row);
2582   g_free (bw);
2583   g_free (grey);
2584 
2585   g_object_unref (buffer);
2586 
2587   return TRUE;
2588 
2589  fail:
2590 
2591   g_free (src_row);
2592   g_free (bw);
2593   g_free (grey);
2594 
2595   g_object_unref (buffer);
2596 
2597   return FALSE;
2598 }
2599 
2600 static gboolean
save_gray(GOutputStream * output,gint32 image_ID,gint32 drawable_ID,GError ** error)2601 save_gray (GOutputStream  *output,
2602            gint32          image_ID,
2603            gint32          drawable_ID,
2604            GError        **error)
2605 {
2606   GeglBuffer *buffer = NULL;
2607   const Babl *format;
2608   gint        bpp;
2609   gint        height, width, i, j;
2610   gint        tile_height;
2611   guchar     *data;
2612   guchar     *src;
2613   guchar     *packb = NULL;
2614   gboolean    level2 = (psvals.level > 1);
2615 
2616   buffer = gimp_drawable_get_buffer (drawable_ID);
2617   format = babl_format ("Y' u8");
2618   bpp    = babl_format_get_bytes_per_pixel (format);
2619   width  = gegl_buffer_get_width (buffer);
2620   height = gegl_buffer_get_height (buffer);
2621 
2622   tile_height = gimp_tile_height ();
2623 
2624   /* allocate a buffer for retrieving information from the pixel region  */
2625   src = data = (guchar *) g_malloc (tile_height * width * bpp);
2626 
2627   /* Set up transformation in PostScript */
2628   if (! save_ps_setup (output, drawable_ID, width, height, 1 * 8, error))
2629     goto fail;
2630 
2631   /* Write read image procedure */
2632   if (! level2)
2633     {
2634       if (! print (output, error,
2635                    "{ currentfile scanline readhexstring pop }\n"))
2636         goto fail;
2637     }
2638   else
2639     {
2640       if (! print (output, error,
2641                    "currentfile /ASCII85Decode filter /RunLengthDecode filter\n"))
2642         goto fail;
2643 
2644       ascii85_init ();
2645 
2646       /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
2647       packb = (guchar *) g_malloc ((width * 105) / 100 + 2);
2648     }
2649 
2650   if (! ps_begin_data (output, error))
2651     goto fail;
2652 
2653   if (! print (output, error, "image\n"))
2654     goto fail;
2655 
2656 #define GET_GRAY_TILE(begin) \
2657   { gint scan_lines;                                                    \
2658     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
2659     gegl_buffer_get (buffer, GEGL_RECTANGLE (0, i, width, scan_lines),  \
2660                      1.0, format, begin,                                \
2661                      GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);             \
2662     src = begin; }
2663 
2664   for (i = 0; i < height; i++)
2665     {
2666       if ((i % tile_height) == 0)
2667         GET_GRAY_TILE (data); /* Get more data */
2668 
2669       if (! level2)
2670         {
2671           for (j = 0; j < width; j++)
2672             {
2673               if (! print (output, error, "%c", hex[(*src) >> 4]))
2674                 goto fail;
2675 
2676               if (! print (output, error, "%c", hex[(*(src++)) & 0x0f]))
2677                 goto fail;
2678 
2679               if (((j + 1) % 39) == 0)
2680                 if (! print (output, error, "\n"))
2681                   goto fail;
2682            }
2683 
2684           if (! print (output, error, "\n"))
2685             goto fail;
2686         }
2687       else
2688         {
2689           gint nout;
2690 
2691           compress_packbits (width, src, &nout, packb);
2692 
2693           if (! ascii85_nout (output, nout, packb, error))
2694             goto fail;
2695 
2696           src += width;
2697         }
2698 
2699       if ((i % 20) == 0)
2700         gimp_progress_update ((gdouble) i / (gdouble) height);
2701     }
2702 
2703   gimp_progress_update (1.0);
2704 
2705   if (level2)
2706     {
2707       /* Write EOD of RunLengthDecode filter */
2708       if (! ascii85_out (output, 128, error))
2709         goto fail;
2710 
2711       if (! ascii85_done (output, error))
2712         goto fail;
2713     }
2714 
2715   if (! ps_end_data (output, error))
2716     return FALSE;
2717 
2718   if (! print (output, error, "showpage\n"))
2719     goto fail;
2720 
2721   g_free (data);
2722   g_free (packb);
2723 
2724   g_object_unref (buffer);
2725 
2726   return TRUE;
2727 
2728  fail:
2729 
2730   g_free (data);
2731   g_free (packb);
2732 
2733   g_object_unref (buffer);
2734 
2735   return FALSE;
2736 
2737 #undef GET_GRAY_TILE
2738 }
2739 
2740 static gboolean
save_bw(GOutputStream * output,gint32 image_ID,gint32 drawable_ID,GError ** error)2741 save_bw (GOutputStream  *output,
2742          gint32          image_ID,
2743          gint32          drawable_ID,
2744          GError        **error)
2745 {
2746   GeglBuffer *buffer = NULL;
2747   const Babl *format;
2748   gint        bpp;
2749   gint        height, width, i, j;
2750   gint        ncols, nbsl, nwrite;
2751   gint        tile_height;
2752   guchar     *cmap, *ct;
2753   guchar     *data, *src;
2754   guchar     *packb = NULL;
2755   guchar     *scanline, *dst, mask;
2756   guchar     *hex_scanline;
2757   gboolean    level2 = (psvals.level > 1);
2758 
2759   cmap = gimp_image_get_colormap (image_ID, &ncols);
2760 
2761   buffer = gimp_drawable_get_buffer (drawable_ID);
2762   format = gimp_drawable_get_format (drawable_ID);
2763   bpp    = babl_format_get_bytes_per_pixel (format);
2764   width  = gegl_buffer_get_width (buffer);
2765   height = gegl_buffer_get_height (buffer);
2766 
2767   tile_height = gimp_tile_height ();
2768 
2769   /* allocate a buffer for retrieving information from the pixel region  */
2770   src = data = g_new (guchar, tile_height * width * bpp);
2771 
2772   nbsl = (width + 7) / 8;
2773 
2774   scanline     = g_new (guchar, nbsl + 1);
2775   hex_scanline = g_new (guchar, (nbsl + 1) * 2);
2776 
2777   /* Set up transformation in PostScript */
2778   if (! save_ps_setup (output, drawable_ID, width, height, 1, error))
2779     goto fail;
2780 
2781   /* Write read image procedure */
2782   if (! level2)
2783     {
2784       if (! print (output, error,
2785                    "{ currentfile scanline readhexstring pop }\n"))
2786         goto fail;
2787     }
2788   else
2789     {
2790       if (! print (output, error,
2791                    "currentfile /ASCII85Decode filter /RunLengthDecode filter\n"))
2792         goto fail;
2793 
2794       ascii85_init ();
2795 
2796       /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
2797       packb = g_new (guchar, ((nbsl+1) * 105) / 100 + 2);
2798     }
2799 
2800   if (! ps_begin_data (output, error))
2801     goto fail;
2802 
2803   if (! print (output, error, "image\n"))
2804     goto fail;
2805 
2806 #define GET_BW_TILE(begin) \
2807   { gint scan_lines;                                                    \
2808     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
2809     gegl_buffer_get (buffer, GEGL_RECTANGLE (0, i, width, scan_lines),  \
2810                      1.0, format, begin,                                \
2811                      GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);             \
2812     src = begin; }
2813 
2814   for (i = 0; i < height; i++)
2815     {
2816       if ((i % tile_height) == 0)
2817         GET_BW_TILE (data); /* Get more data */
2818 
2819       dst = scanline;
2820       memset (dst, 0, nbsl);
2821       mask = 0x80;
2822 
2823       /* Build a bitmap for a scanline */
2824       for (j = 0; j < width; j++)
2825         {
2826           ct = cmap + *(src++)*3;
2827           if (ct[0] || ct[1] || ct[2])
2828             *dst |= mask;
2829 
2830           if (mask == 0x01)
2831             {
2832               mask = 0x80; dst++;
2833             }
2834           else
2835             {
2836               mask >>= 1;
2837             }
2838         }
2839 
2840       if (! level2)
2841         {
2842           /* Convert to hexstring */
2843           for (j = 0; j < nbsl; j++)
2844             {
2845               hex_scanline[j * 2]     = (guchar) hex[scanline[j] >> 4];
2846               hex_scanline[j * 2 + 1] = (guchar) hex[scanline[j] & 0x0f];
2847             }
2848 
2849           /* Write out hexstring */
2850           j = nbsl * 2;
2851           dst = hex_scanline;
2852 
2853           while (j > 0)
2854             {
2855               nwrite = (j > 78) ? 78 : j;
2856 
2857               if (! g_output_stream_write_all (output,
2858                                                dst, nwrite, NULL,
2859                                                NULL, error))
2860                 goto fail;
2861 
2862               if (! print (output, error, "\n"))
2863                 goto fail;
2864 
2865               j -= nwrite;
2866               dst += nwrite;
2867             }
2868         }
2869       else
2870         {
2871           gint nout;
2872 
2873           compress_packbits (nbsl, scanline, &nout, packb);
2874 
2875           if (! ascii85_nout (output, nout, packb, error))
2876             goto fail;
2877         }
2878 
2879       if ((i % 20) == 0)
2880         gimp_progress_update ((gdouble) i / (gdouble) height);
2881     }
2882 
2883   gimp_progress_update (1.0);
2884 
2885   if (level2)
2886     {
2887       /* Write EOD of RunLengthDecode filter */
2888       if (! ascii85_out (output, 128, error))
2889         goto fail;
2890 
2891       if (! ascii85_done (output, error))
2892         goto fail;
2893     }
2894 
2895   if (! ps_end_data (output, error))
2896     goto fail;
2897 
2898   if (! print (output, error, "showpage\n"))
2899     goto fail;
2900 
2901   g_free (hex_scanline);
2902   g_free (scanline);
2903   g_free (data);
2904   g_free (packb);
2905 
2906   g_object_unref (buffer);
2907 
2908   return TRUE;
2909 
2910  fail:
2911 
2912   g_free (hex_scanline);
2913   g_free (scanline);
2914   g_free (data);
2915   g_free (packb);
2916 
2917   g_object_unref (buffer);
2918 
2919   return FALSE;
2920 
2921 #undef GET_BW_TILE
2922 }
2923 
2924 static gboolean
save_index(GOutputStream * output,gint32 image_ID,gint32 drawable_ID,GError ** error)2925 save_index (GOutputStream  *output,
2926             gint32          image_ID,
2927             gint32          drawable_ID,
2928             GError        **error)
2929 {
2930   GeglBuffer *buffer = NULL;
2931   const Babl *format;
2932   gint        bpp;
2933   gint        height, width, i, j;
2934   gint        ncols, bw;
2935   gint        tile_height;
2936   guchar     *cmap, *cmap_start;
2937   guchar     *data, *src;
2938   guchar     *packb = NULL;
2939   guchar     *plane = NULL;
2940   gchar       coltab[256 * 6], *ct;
2941   gboolean    level2 = (psvals.level > 1);
2942 
2943   cmap = cmap_start = gimp_image_get_colormap (image_ID, &ncols);
2944 
2945   ct = coltab;
2946   bw = 1;
2947   for (j = 0; j < 256; j++)
2948     {
2949       if (j >= ncols)
2950         {
2951           memset (ct, 0, 6);
2952           ct += 6;
2953         }
2954       else
2955         {
2956           bw &= ((cmap[0] == 0)   && (cmap[1] == 0)   && (cmap[2] == 0)) ||
2957                 ((cmap[0] == 255) && (cmap[1] == 255) && (cmap[2] == 255));
2958 
2959           *(ct++) = (guchar) hex[(*cmap) >> 4];
2960           *(ct++) = (guchar) hex[(*(cmap++)) & 0x0f];
2961           *(ct++) = (guchar) hex[(*cmap) >> 4];
2962           *(ct++) = (guchar) hex[(*(cmap++)) & 0x0f];
2963           *(ct++) = (guchar) hex[(*cmap) >> 4];
2964           *(ct++) = (guchar) hex[(*(cmap++)) & 0x0f];
2965         }
2966     }
2967 
2968   if (bw)
2969     return save_bw (output, image_ID, drawable_ID, error);
2970 
2971   buffer = gimp_drawable_get_buffer (drawable_ID);
2972   format = gimp_drawable_get_format (drawable_ID);
2973   bpp    = babl_format_get_bytes_per_pixel (format);
2974   width  = gegl_buffer_get_width (buffer);
2975   height = gegl_buffer_get_height (buffer);
2976 
2977   tile_height = gimp_tile_height ();
2978 
2979   /* allocate a buffer for retrieving information from the pixel region  */
2980   src = data = (guchar *) g_malloc (tile_height * width * bpp);
2981 
2982   /* Set up transformation in PostScript */
2983   if (! save_ps_setup (output, drawable_ID, width, height, 3 * 8, error))
2984     goto fail;
2985 
2986   /* Write read image procedure */
2987   if (! level2)
2988     {
2989       if (! print (output, error,
2990                    "{ currentfile scanline readhexstring pop } false 3\n"))
2991         goto fail;
2992     }
2993   else
2994     {
2995       if (! print (output, error,
2996                    "%% Strings to hold RGB-samples per scanline\n"
2997                    "/rstr %d string def\n"
2998                    "/gstr %d string def\n"
2999                    "/bstr %d string def\n",
3000                    width, width, width))
3001         goto fail;
3002 
3003       if (! print (output, error,
3004                    "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
3005  rstr readstring pop}\n"
3006                    "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
3007  gstr readstring pop}\n"
3008                    "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
3009  bstr readstring pop}\n"
3010                    "true 3\n"))
3011         goto fail;
3012 
3013       /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
3014       packb = (guchar *) g_malloc ((width * 105) / 100 + 2);
3015       plane = (guchar *) g_malloc (width);
3016     }
3017 
3018   if (! ps_begin_data (output, error))
3019     goto fail;
3020 
3021   if (! print (output, error, "colorimage\n"))
3022     goto fail;
3023 
3024 #define GET_INDEX_TILE(begin) \
3025   { gint scan_lines;                                                    \
3026     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
3027     gegl_buffer_get (buffer, GEGL_RECTANGLE (0, i, width, scan_lines),  \
3028                      1.0, format, begin,                                \
3029                      GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);             \
3030     src = begin; }
3031 
3032   for (i = 0; i < height; i++)
3033     {
3034       if ((i % tile_height) == 0)
3035         GET_INDEX_TILE (data); /* Get more data */
3036 
3037       if (! level2)
3038         {
3039           for (j = 0; j < width; j++)
3040             {
3041               if (! g_output_stream_write_all (output,
3042                                                coltab + (*(src++)) * 6, 6, NULL,
3043                                                NULL, error))
3044                 goto fail;
3045 
3046               if (((j + 1) % 13) == 0)
3047                 if (! print (output, error, "\n"))
3048                   goto fail;
3049             }
3050 
3051           if (! print (output, error, "\n"))
3052             goto fail;
3053         }
3054       else
3055         {
3056           gint rgb;
3057 
3058           for (rgb = 0; rgb < 3; rgb++)
3059             {
3060               guchar *src_ptr   = src;
3061               guchar *plane_ptr = plane;
3062               gint    nout;
3063 
3064               for (j = 0; j < width; j++)
3065                 *(plane_ptr++) = cmap_start[3 * *(src_ptr++) + rgb];
3066 
3067               compress_packbits (width, plane, &nout, packb);
3068 
3069               ascii85_init ();
3070 
3071               if (! ascii85_nout (output, nout, packb, error))
3072                 goto fail;
3073 
3074               /* Write EOD of RunLengthDecode filter */
3075               if (! ascii85_out (output, 128, error))
3076                 goto fail;
3077 
3078               if (! ascii85_done (output, error))
3079                 goto fail;
3080             }
3081 
3082           src += width;
3083         }
3084 
3085       if ((i % 20) == 0)
3086         gimp_progress_update ((gdouble) i / (gdouble) height);
3087     }
3088 
3089   gimp_progress_update (1.0);
3090 
3091   if (! ps_end_data (output, error))
3092     goto fail;
3093 
3094   if (! print (output, error, "showpage\n"))
3095     goto fail;
3096 
3097   g_free (data);
3098   g_free (packb);
3099   g_free (plane);
3100 
3101   g_object_unref (buffer);
3102 
3103   return TRUE;
3104 
3105  fail:
3106 
3107   g_free (data);
3108   g_free (packb);
3109   g_free (plane);
3110 
3111   g_object_unref (buffer);
3112 
3113   return FALSE;
3114 
3115 #undef GET_INDEX_TILE
3116 }
3117 
3118 static gboolean
save_rgb(GOutputStream * output,gint32 image_ID,gint32 drawable_ID,GError ** error)3119 save_rgb (GOutputStream  *output,
3120           gint32          image_ID,
3121           gint32          drawable_ID,
3122           GError        **error)
3123 {
3124   GeglBuffer *buffer = NULL;
3125   const Babl *format;
3126   gint        bpp;
3127   gint        height, width, tile_height;
3128   gint        i, j;
3129   guchar     *data, *src;
3130   guchar     *packb = NULL;
3131   guchar     *plane = NULL;
3132   gboolean    level2 = (psvals.level > 1);
3133 
3134   buffer = gimp_drawable_get_buffer (drawable_ID);
3135   format = babl_format ("R'G'B' u8");
3136   bpp    = babl_format_get_bytes_per_pixel (format);
3137   width  = gegl_buffer_get_width (buffer);
3138   height = gegl_buffer_get_height (buffer);
3139 
3140   tile_height = gimp_tile_height ();
3141 
3142   /* allocate a buffer for retrieving information from the pixel region  */
3143   src = data = g_new (guchar, tile_height * width * bpp);
3144 
3145   /* Set up transformation in PostScript */
3146   if (! save_ps_setup (output, drawable_ID, width, height, 3 * 8, error))
3147     goto fail;
3148 
3149   /* Write read image procedure */
3150   if (! level2)
3151     {
3152       if (! print (output, error,
3153                    "{ currentfile scanline readhexstring pop } false 3\n"))
3154         goto fail;
3155     }
3156   else
3157     {
3158       if (! print (output, error,
3159                    "%% Strings to hold RGB-samples per scanline\n"
3160                    "/rstr %d string def\n"
3161                    "/gstr %d string def\n"
3162                    "/bstr %d string def\n",
3163                    width, width, width))
3164         goto fail;
3165 
3166       if (! print (output, error,
3167                    "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
3168  rstr readstring pop}\n"
3169                    "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
3170  gstr readstring pop}\n"
3171                    "{currentfile /ASCII85Decode filter /RunLengthDecode filter\
3172  bstr readstring pop}\n"
3173                    "true 3\n"))
3174         goto fail;
3175 
3176       /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
3177       packb = g_new (guchar, (width * 105) / 100 + 2);
3178       plane = g_new (guchar, width);
3179     }
3180 
3181   if (! ps_begin_data (output, error))
3182     goto fail;
3183 
3184   if (! print (output, error, "colorimage\n"))
3185     goto fail;
3186 
3187 #define GET_RGB_TILE(begin) \
3188   { gint scan_lines;                                                    \
3189     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
3190     gegl_buffer_get (buffer, GEGL_RECTANGLE (0, i, width, scan_lines),  \
3191                      1.0, format, begin,                                \
3192                      GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);             \
3193     src = begin; }
3194 
3195   for (i = 0; i < height; i++)
3196     {
3197       if ((i % tile_height) == 0)
3198         GET_RGB_TILE (data); /* Get more data */
3199 
3200       if (! level2)
3201         {
3202           for (j = 0; j < width; j++)
3203             {
3204               if (! print (output, error, "%c",
3205                            hex[(*src) >> 4]))        /* Red */
3206                 goto fail;
3207 
3208               if (! print (output, error, "%c",
3209                            hex[(*(src++)) & 0x0f]))
3210                 goto fail;
3211 
3212               if (! print (output, error, "%c",
3213                            hex[(*src) >> 4]))        /* Green */
3214                 goto fail;
3215 
3216               if (! print (output, error, "%c",
3217                            hex[(*(src++)) & 0x0f]))
3218                 goto fail;
3219 
3220               if (! print (output, error, "%c",
3221                            hex[(*src) >> 4]))        /* Blue */
3222                 goto fail;
3223 
3224               if (! print (output, error, "%c",
3225                            hex[(*(src++)) & 0x0f]))
3226                 goto fail;
3227 
3228               if (((j+1) % 13) == 0)
3229                 if (! print (output, error, "\n"))
3230                   goto fail;
3231             }
3232 
3233           if (! print (output, error, "\n"))
3234             goto fail;
3235         }
3236       else
3237         {
3238           gint rgb;
3239 
3240           for (rgb = 0; rgb < 3; rgb++)
3241             {
3242               guchar *src_ptr   = src + rgb;
3243               guchar *plane_ptr = plane;
3244               gint    nout;
3245 
3246               for (j = 0; j < width; j++)
3247                 {
3248                   *(plane_ptr++) = *src_ptr;
3249                   src_ptr += 3;
3250                 }
3251 
3252               compress_packbits (width, plane, &nout, packb);
3253 
3254               ascii85_init ();
3255 
3256               if (! ascii85_nout (output, nout, packb, error))
3257                 goto fail;
3258 
3259               /* Write EOD of RunLengthDecode filter */
3260               if (! ascii85_out (output, 128, error))
3261                 goto fail;
3262 
3263               if (! ascii85_done (output, error))
3264                 goto fail;
3265             }
3266 
3267           src += 3 * width;
3268         }
3269 
3270       if ((i % 20) == 0)
3271         gimp_progress_update ((gdouble) i / (gdouble) height);
3272     }
3273 
3274   gimp_progress_update (1.0);
3275 
3276   if (! ps_end_data (output, error))
3277     goto fail;
3278 
3279   if (! print (output, error, "showpage\n"))
3280     goto fail;
3281 
3282   g_free (data);
3283   g_free (packb);
3284   g_free (plane);
3285 
3286   g_object_unref (buffer);
3287 
3288   return TRUE;
3289 
3290  fail:
3291 
3292   g_free (data);
3293   g_free (packb);
3294   g_free (plane);
3295 
3296   g_object_unref (buffer);
3297 
3298   return FALSE;
3299 
3300 #undef GET_RGB_TILE
3301 }
3302 
3303 static gboolean
print(GOutputStream * output,GError ** error,const gchar * format,...)3304 print (GOutputStream  *output,
3305        GError        **error,
3306        const gchar    *format,
3307        ...)
3308 {
3309   va_list  args;
3310   gboolean success;
3311 
3312   va_start (args, format);
3313   success = g_output_stream_vprintf (output, NULL, NULL,
3314                                      error, format, args);
3315   va_end (args);
3316 
3317   return success;
3318 }
3319 
3320 /*  Load interface functions  */
3321 
3322 static gint32
count_ps_pages(const gchar * filename)3323 count_ps_pages (const gchar *filename)
3324 {
3325   FILE   *psfile;
3326   gchar  *extension;
3327   gchar   buf[1024];
3328   gint32  num_pages      = 0;
3329   gint32  showpage_count = 0;
3330 
3331   extension = strrchr (filename, '.');
3332   if (extension)
3333     {
3334       extension = g_ascii_strdown (extension + 1, -1);
3335 
3336       if (strcmp (extension, "eps") == 0)
3337         {
3338           g_free (extension);
3339           return 1;
3340         }
3341 
3342       g_free (extension);
3343     }
3344 
3345   psfile = g_fopen (filename, "r");
3346 
3347   if (psfile == NULL)
3348     {
3349       g_message (_("Could not open '%s' for reading: %s"),
3350                  gimp_filename_to_utf8 (filename), g_strerror (errno));
3351       return 0;
3352     }
3353 
3354   while (num_pages == 0 && !feof (psfile))
3355     {
3356       fgets (buf, sizeof (buf), psfile);
3357 
3358       if (strncmp (buf + 2, "Pages:", 6) == 0)
3359         sscanf (buf + strlen ("%%Pages:"), "%d", &num_pages);
3360       else if (strncmp (buf, "showpage", 8) == 0)
3361         showpage_count++;
3362     }
3363 
3364   if (feof (psfile) && num_pages < 1 && showpage_count > 0)
3365     num_pages = showpage_count;
3366 
3367   fclose (psfile);
3368 
3369   return num_pages;
3370 }
3371 
3372 static gboolean
load_dialog(const gchar * filename)3373 load_dialog (const gchar *filename)
3374 {
3375   GtkWidget     *dialog;
3376   GtkWidget     *main_vbox;
3377   GtkWidget     *hbox;
3378   GtkWidget     *frame;
3379   GtkWidget     *vbox;
3380   GtkWidget     *table;
3381   GtkWidget     *spinbutton;
3382   GtkAdjustment *adj;
3383   GtkWidget     *entry    = NULL;
3384   GtkWidget     *target   = NULL;
3385   GtkWidget     *toggle;
3386   GtkWidget     *selector = NULL;
3387   gint32         page_count;
3388   gchar         *range    = NULL;
3389   gboolean       run;
3390 
3391   page_count = count_ps_pages (filename);
3392 
3393   gimp_ui_init (PLUG_IN_BINARY, FALSE);
3394 
3395   dialog = gimp_dialog_new (_("Import from PostScript"), PLUG_IN_ROLE,
3396                             NULL, 0,
3397                             gimp_standard_help_func, LOAD_PS_PROC,
3398 
3399                             _("_Cancel"), GTK_RESPONSE_CANCEL,
3400                             _("_Import"), GTK_RESPONSE_OK,
3401 
3402                             NULL);
3403 
3404   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
3405                                            GTK_RESPONSE_OK,
3406                                            GTK_RESPONSE_CANCEL,
3407                                            -1);
3408 
3409   gimp_window_set_transient (GTK_WINDOW (dialog));
3410 
3411   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
3412   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
3413   gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
3414                       main_vbox, TRUE, TRUE, 0);
3415   gtk_widget_show (main_vbox);
3416 
3417   if (page_count > 1)
3418     {
3419       selector = gimp_page_selector_new ();
3420       gtk_box_pack_start (GTK_BOX (main_vbox), selector, TRUE, TRUE, 0);
3421       gimp_page_selector_set_n_pages (GIMP_PAGE_SELECTOR (selector),
3422                                       page_count);
3423       gimp_page_selector_set_target (GIMP_PAGE_SELECTOR (selector),
3424                                      ps_pagemode);
3425 
3426       gtk_widget_show (selector);
3427 
3428       g_signal_connect_swapped (selector, "activate",
3429                                 G_CALLBACK (gtk_window_activate_default),
3430                                 dialog);
3431     }
3432 
3433   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
3434   gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
3435   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
3436   gtk_widget_show (hbox);
3437 
3438   /* Rendering */
3439   frame = gimp_frame_new (_("Rendering"));
3440   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
3441 
3442   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
3443   gtk_container_add (GTK_CONTAINER (frame), vbox);
3444 
3445   /* Resolution/Width/Height/Pages labels */
3446   table = gtk_table_new (4, 2, FALSE);
3447   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
3448   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
3449   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
3450   gtk_widget_show (table);
3451 
3452   adj = (GtkAdjustment *) gtk_adjustment_new (plvals.resolution,
3453                                               MIN_RESOLUTION, MAX_RESOLUTION,
3454                                               1, 10, 0);
3455   spinbutton = gimp_spin_button_new (adj, 1.0, 0);
3456   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3457   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
3458                              _("Resolution:"), 0.0, 0.5,
3459                              spinbutton, 1, FALSE);
3460 
3461   g_signal_connect (adj, "value-changed",
3462                     G_CALLBACK (resolution_change_callback),
3463                     &plvals.resolution);
3464   g_signal_connect (adj, "value-changed",
3465                     G_CALLBACK (gimp_int_adjustment_update),
3466                     &plvals.resolution);
3467 
3468   adj = (GtkAdjustment *) gtk_adjustment_new (plvals.width,
3469                                               1, GIMP_MAX_IMAGE_SIZE,
3470                                               1, 10, 0);
3471   ps_width_spinbutton = gimp_spin_button_new (adj, 1.0, 0);
3472   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3473   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
3474                              _("_Width:"), 0.0, 0.5,
3475                              ps_width_spinbutton, 1, FALSE);
3476 
3477   g_signal_connect (adj, "value-changed",
3478                     G_CALLBACK (gimp_int_adjustment_update),
3479                     &plvals.width);
3480 
3481   adj = (GtkAdjustment *) gtk_adjustment_new (plvals.height,
3482                                               1, GIMP_MAX_IMAGE_SIZE,
3483                                               1, 10, 0);
3484   ps_height_spinbutton = gimp_spin_button_new (adj, 1.0, 0);
3485   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3486   gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
3487                              _("_Height:"), 0.0, 0.5,
3488                              ps_height_spinbutton, 1, FALSE);
3489 
3490   g_signal_connect (adj, "value-changed",
3491                     G_CALLBACK (gimp_int_adjustment_update),
3492                     &plvals.height);
3493 
3494   if (page_count == 0)
3495     {
3496       entry = gtk_entry_new ();
3497       gtk_widget_set_size_request (entry, 80, -1);
3498       gtk_entry_set_text (GTK_ENTRY (entry), plvals.pages);
3499       gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
3500                                  _("Pages:"), 0.0, 0.5,
3501                                  entry, 1, FALSE);
3502 
3503       g_signal_connect (entry, "changed",
3504                         G_CALLBACK (load_pages_entry_callback),
3505                         NULL);
3506       gimp_help_set_help_data (GTK_WIDGET (entry),
3507                                _("Pages to load (e.g.: 1-4 or 1,3,5-7)"), NULL);
3508 
3509       target = gtk_combo_box_text_new ();
3510       gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (target),
3511                                       GIMP_PAGE_SELECTOR_TARGET_LAYERS,
3512                                       _("Layers"));
3513       gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (target),
3514                                       GIMP_PAGE_SELECTOR_TARGET_IMAGES,
3515                                       _("Images"));
3516       gtk_combo_box_set_active (GTK_COMBO_BOX (target), (int) ps_pagemode);
3517       gimp_table_attach_aligned (GTK_TABLE (table), 0, 4,
3518                                  _("Open as"), 0.0, 0.5,
3519                                  target, 1, FALSE);
3520     }
3521 
3522   toggle = gtk_check_button_new_with_label (_("Try Bounding Box"));
3523   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
3524   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), plvals.use_bbox);
3525   gtk_widget_show (toggle);
3526 
3527   g_signal_connect (toggle, "toggled",
3528                     G_CALLBACK (gimp_toggle_button_update),
3529                     &plvals.use_bbox);
3530 
3531   gtk_widget_show (vbox);
3532   gtk_widget_show (frame);
3533 
3534   /* Coloring */
3535   frame = gimp_int_radio_group_new (TRUE, _("Coloring"),
3536                                     G_CALLBACK (gimp_radio_button_update),
3537                                     &plvals.pnm_type, plvals.pnm_type,
3538 
3539                                     _("B/W"),       4, NULL,
3540                                     _("Gray"),      5, NULL,
3541                                     _("Color"),     6, NULL,
3542                                     _("Automatic"), 7, NULL,
3543 
3544                                     NULL);
3545   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
3546   gtk_widget_show (frame);
3547 
3548   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
3549   gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
3550   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
3551   gtk_widget_show (hbox);
3552 
3553   frame = gimp_int_radio_group_new (TRUE, _("Text antialiasing"),
3554                                     G_CALLBACK (gimp_radio_button_update),
3555                                     &plvals.textalpha, plvals.textalpha,
3556 
3557                                     C_("antialiasing", "None"), 1, NULL,
3558                                     _("Weak"),                  2, NULL,
3559                                     _("Strong"),                4, NULL,
3560 
3561                                     NULL);
3562   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
3563   gtk_widget_show (frame);
3564 
3565   frame = gimp_int_radio_group_new (TRUE, _("Graphic antialiasing"),
3566                                     G_CALLBACK (gimp_radio_button_update),
3567                                     &plvals.graphicsalpha, plvals.graphicsalpha,
3568 
3569                                     C_("antialiasing", "None"), 1, NULL,
3570                                     _("Weak"),                  2, NULL,
3571                                     _("Strong"),                4, NULL,
3572 
3573                                     NULL);
3574   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
3575   gtk_widget_show (frame);
3576 
3577   gtk_widget_show (dialog);
3578 
3579   run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
3580 
3581   if (selector)
3582     {
3583       range = gimp_page_selector_get_selected_range (GIMP_PAGE_SELECTOR (selector));
3584 
3585       if (strlen (range) < 1)
3586         {
3587           gimp_page_selector_select_all (GIMP_PAGE_SELECTOR (selector));
3588           range = gimp_page_selector_get_selected_range (GIMP_PAGE_SELECTOR (selector));
3589         }
3590 
3591       strncpy (plvals.pages, range, sizeof (plvals.pages));
3592       plvals.pages[strlen (range)] = '\0';
3593 
3594       ps_pagemode = gimp_page_selector_get_target (GIMP_PAGE_SELECTOR (selector));
3595     }
3596   else if (page_count == 0)
3597     {
3598       ps_pagemode = gtk_combo_box_get_active (GTK_COMBO_BOX (target));
3599     }
3600   else
3601     {
3602       strncpy (plvals.pages, "1", 1);
3603       plvals.pages[1] = '\0';
3604       ps_pagemode = GIMP_PAGE_SELECTOR_TARGET_IMAGES;
3605     }
3606 
3607   gtk_widget_destroy (dialog);
3608 
3609   return run;
3610 }
3611 
3612 static void
load_pages_entry_callback(GtkWidget * widget,gpointer data)3613 load_pages_entry_callback (GtkWidget *widget,
3614                            gpointer   data)
3615 {
3616   gsize nelem = sizeof (plvals.pages);
3617 
3618   strncpy (plvals.pages, gtk_entry_get_text (GTK_ENTRY (widget)), nelem);
3619   plvals.pages[nelem-1] = '\0';
3620 }
3621 
3622 
3623 /*  Save interface functions  */
3624 
3625 static gboolean
save_dialog(void)3626 save_dialog (void)
3627 {
3628   SaveDialogVals *vals;
3629   GtkWidget      *dialog;
3630   GtkWidget      *toggle;
3631   GtkWidget      *frame, *uframe;
3632   GtkWidget      *hbox, *vbox;
3633   GtkWidget      *main_vbox[2];
3634   GtkWidget      *table;
3635   GtkWidget      *spinbutton;
3636   GtkAdjustment  *adj;
3637   gint            j;
3638   gboolean        run;
3639 
3640   vals = g_new (SaveDialogVals, 1);
3641   vals->level = (psvals.level > 1);
3642 
3643   dialog = gimp_export_dialog_new (_("PostScript"), PLUG_IN_BINARY, SAVE_PS_PROC);
3644 
3645   /* Main hbox */
3646   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
3647   gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
3648   gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
3649                       hbox, FALSE, FALSE, 0);
3650   main_vbox[0] = main_vbox[1] = NULL;
3651 
3652   for (j = 0; j < G_N_ELEMENTS (main_vbox); j++)
3653     {
3654       main_vbox[j] = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
3655       gtk_box_pack_start (GTK_BOX (hbox), main_vbox[j], FALSE, TRUE, 0);
3656       gtk_widget_show (main_vbox[j]);
3657     }
3658 
3659   /* Image Size */
3660   frame = gimp_frame_new (_("Image Size"));
3661   gtk_box_pack_start (GTK_BOX (main_vbox[0]), frame, FALSE, TRUE, 0);
3662 
3663   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
3664   gtk_container_add (GTK_CONTAINER (frame), vbox);
3665 
3666   /* Width/Height/X-/Y-offset labels */
3667   table = gtk_table_new (4, 2, FALSE);
3668   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
3669   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
3670   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
3671   gtk_widget_show (table);
3672 
3673   vals->adjustment[0] = (GtkAdjustment *)
3674     gtk_adjustment_new (psvals.width,
3675                         1e-5, GIMP_MAX_IMAGE_SIZE, 1, 10, 0);
3676   spinbutton = gimp_spin_button_new (vals->adjustment[0], 1.0, 2);
3677   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3678   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
3679                              _("_Width:"), 0.0, 0.5,
3680                              spinbutton, 1, FALSE);
3681   g_signal_connect (vals->adjustment[0], "value-changed",
3682                     G_CALLBACK (gimp_double_adjustment_update),
3683                     &psvals.width);
3684 
3685   vals->adjustment[1] = (GtkAdjustment *)
3686     gtk_adjustment_new (psvals.height,
3687                         1e-5, GIMP_MAX_IMAGE_SIZE, 1, 10, 0);
3688   spinbutton = gimp_spin_button_new (vals->adjustment[1], 1.0, 2);
3689   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3690   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
3691                              _("_Height:"), 0.0, 0.5,
3692                              spinbutton, 1, FALSE);
3693   g_signal_connect (vals->adjustment[1], "value-changed",
3694                     G_CALLBACK (gimp_double_adjustment_update),
3695                     &psvals.height);
3696 
3697   vals->adjustment[2] = (GtkAdjustment *)
3698     gtk_adjustment_new (psvals.x_offset,
3699                         0.0, GIMP_MAX_IMAGE_SIZE, 1, 10, 0);
3700   spinbutton = gimp_spin_button_new (vals->adjustment[2], 1.0, 2);
3701   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3702   gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
3703                              _("_X offset:"), 0.0, 0.5,
3704                              spinbutton, 1, FALSE);
3705   g_signal_connect (vals->adjustment[2], "value-changed",
3706                     G_CALLBACK (gimp_double_adjustment_update),
3707                     &psvals.x_offset);
3708 
3709   vals->adjustment[3] = (GtkAdjustment *)
3710     gtk_adjustment_new (psvals.y_offset,
3711                         0.0, GIMP_MAX_IMAGE_SIZE, 1, 10, 0);
3712   spinbutton = gimp_spin_button_new (vals->adjustment[3], 1.0, 2);
3713   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3714   gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
3715                              _("_Y offset:"), 0.0, 0.5,
3716                              spinbutton, 1, FALSE);
3717   g_signal_connect (vals->adjustment[3], "value-changed",
3718                     G_CALLBACK (gimp_double_adjustment_update),
3719                     &psvals.y_offset);
3720 
3721   toggle = gtk_check_button_new_with_mnemonic (_("_Keep aspect ratio"));
3722   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
3723   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), psvals.keep_ratio);
3724   gtk_widget_show (toggle);
3725 
3726   gimp_help_set_help_data (toggle,
3727                            _("When toggled, the resulting image will be "
3728                              "scaled to fit into the given size without "
3729                              "changing the aspect ratio."),
3730                            "#keep_aspect_ratio"),
3731 
3732   g_signal_connect (toggle, "toggled",
3733                     G_CALLBACK (gimp_toggle_button_update),
3734                     &psvals.keep_ratio);
3735 
3736   /* Unit */
3737   uframe = gimp_int_radio_group_new (TRUE, _("Unit"),
3738                                      G_CALLBACK (save_unit_toggle_update),
3739                                      vals, psvals.unit_mm,
3740 
3741                                      _("_Inch"),       FALSE, NULL,
3742                                      _("_Millimeter"), TRUE,  NULL,
3743 
3744                                      NULL);
3745 
3746   gtk_box_pack_start (GTK_BOX (main_vbox[0]), uframe, TRUE, TRUE, 0);
3747   gtk_widget_show (uframe);
3748 
3749   gtk_widget_show (vbox);
3750   gtk_widget_show (frame);
3751 
3752   /* Rotation */
3753   frame = gimp_int_radio_group_new (TRUE, _("Rotation"),
3754                                     G_CALLBACK (gimp_radio_button_update),
3755                                     &psvals.rotate, psvals.rotate,
3756 
3757                                     "_0",   0,   NULL,
3758                                     "_90",  90,  NULL,
3759                                     "_180", 180, NULL,
3760                                     "_270", 270, NULL,
3761 
3762                                     NULL);
3763 
3764   gtk_box_pack_start (GTK_BOX (main_vbox[1]), frame, TRUE, TRUE, 0);
3765   gtk_widget_show (frame);
3766 
3767   /* Format */
3768   frame = gimp_frame_new (_("Output"));
3769   gtk_box_pack_start (GTK_BOX (main_vbox[1]), frame, TRUE, TRUE, 0);
3770 
3771   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
3772   gtk_container_add (GTK_CONTAINER (frame), vbox);
3773 
3774   toggle = gtk_check_button_new_with_mnemonic (_("_PostScript level 2"));
3775   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
3776   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), vals->level);
3777   gtk_widget_show (toggle);
3778 
3779   g_signal_connect (toggle, "toggled",
3780                     G_CALLBACK (gimp_toggle_button_update),
3781                     &vals->level);
3782 
3783   toggle = gtk_check_button_new_with_mnemonic (_("_Encapsulated PostScript"));
3784   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
3785   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), psvals.eps);
3786   gtk_widget_show (toggle);
3787 
3788   g_signal_connect (toggle, "toggled",
3789                     G_CALLBACK (gimp_toggle_button_update),
3790                     &psvals.eps);
3791 
3792   toggle = gtk_check_button_new_with_mnemonic (_("P_review"));
3793   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
3794   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), psvals.preview);
3795   gtk_widget_show (toggle);
3796 
3797   g_signal_connect (toggle, "toggled",
3798                     G_CALLBACK (gimp_toggle_button_update),
3799                     &psvals.preview);
3800 
3801   /* Preview size label/entry */
3802   table = gtk_table_new (1, 2, FALSE);
3803   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
3804   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
3805   gtk_widget_show (table);
3806 
3807   g_object_bind_property (toggle, "active",
3808                           table,  "sensitive",
3809                           G_BINDING_SYNC_CREATE);
3810 
3811   adj = (GtkAdjustment *) gtk_adjustment_new (psvals.preview_size,
3812                                               0, 1024, 1, 10, 0);
3813   spinbutton = gimp_spin_button_new (adj, 1.0, 0);
3814   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
3815   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
3816                              _("Preview _size:"), 1.0, 0.5,
3817                              spinbutton, 1, FALSE);
3818   gtk_widget_show (spinbutton);
3819 
3820   g_signal_connect (adj, "value-changed",
3821                     G_CALLBACK (gimp_int_adjustment_update),
3822                     &psvals.preview_size);
3823 
3824   gtk_widget_show (vbox);
3825   gtk_widget_show (frame);
3826 
3827   gtk_widget_show (hbox);
3828   gtk_widget_show (dialog);
3829 
3830   run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
3831 
3832   gtk_widget_destroy (dialog);
3833 
3834   psvals.level = (vals->level) ? 2 : 1;
3835 
3836   g_free (vals);
3837 
3838   return run;
3839 }
3840 
3841 static void
save_unit_toggle_update(GtkWidget * widget,gpointer data)3842 save_unit_toggle_update (GtkWidget *widget,
3843                          gpointer   data)
3844 {
3845   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
3846     {
3847       SaveDialogVals *vals = (SaveDialogVals *) data;
3848       gdouble         factor;
3849       gdouble         value;
3850       gint            unit_mm;
3851       gint            i;
3852 
3853       unit_mm = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
3854                                                     "gimp-item-data"));
3855 
3856       psvals.unit_mm = unit_mm;
3857 
3858       if (unit_mm)
3859         factor = 25.4;
3860       else
3861         factor = 1.0 / 25.4;
3862 
3863       for (i = 0; i < 4; i++)
3864         {
3865           value = gtk_adjustment_get_value (vals->adjustment[i]) * factor;
3866 
3867           gtk_adjustment_set_value (vals->adjustment[i], value);
3868         }
3869     }
3870 }
3871 
3872 static gboolean
resolution_change_callback(GtkAdjustment * adjustment,gpointer data)3873 resolution_change_callback (GtkAdjustment *adjustment,
3874                             gpointer       data)
3875 {
3876   guint   *old_resolution = (guint *) data;
3877   gdouble  ratio;
3878 
3879   if (*old_resolution)
3880     ratio = (gdouble) gtk_adjustment_get_value (adjustment) / *old_resolution;
3881   else
3882     ratio = 1.0;
3883 
3884   gtk_spin_button_set_value (GTK_SPIN_BUTTON (ps_width_spinbutton),
3885                              gtk_spin_button_get_value (GTK_SPIN_BUTTON (ps_width_spinbutton)) * ratio);
3886 
3887   gtk_spin_button_set_value (GTK_SPIN_BUTTON (ps_height_spinbutton),
3888                              gtk_spin_button_get_value (GTK_SPIN_BUTTON (ps_height_spinbutton)) * ratio);
3889 
3890   return TRUE;
3891 
3892 }
3893