~ubuntu-branches/ubuntu/breezy/gimp/breezy

« back to all changes in this revision

Viewing changes to plug-ins/common/postscript.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-10-04 19:04:46 UTC
  • Revision ID: james.westby@ubuntu.com-20051004190446-ukh32kwk56s4sjhu
Tags: upstream-2.2.8
ImportĀ upstreamĀ versionĀ 2.2.8

Show diffs side-by-side

added added

removed removed

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