summaryrefslogtreecommitdiff
path: root/support/jpeg2ps/jpeg2ps.c
blob: c25f1f312dd626b0a858bbf32620b20d9dd73fbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
/* --------------------------------------------------------------------
 * jpeg2ps: convert JPEG files to compressed PostScript Level 2 EPS
 *
 * (C) 1994-1999 Thomas Merz 
 *
 * ------------------------------------------------------------------*/

#define VERSION		"V1.8"

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

#ifndef DOS
#include <unistd.h>
#endif

#ifdef DOS
#include <dos.h>
#include <io.h>
#include <fcntl.h>
#endif

/* try to identify Mac compilers */
#if __POWERPC__ || __CFM68K__ || __MC68K_
#define MAC
#endif

#ifdef MAC
#include "Main.h"		/* Required for DropUNIX */
#endif

#include "psimage.h"

#if (defined(DOS) || defined (MAC))
#define READMODE  "rb"           /* read JPEG files in binary mode */
#define WRITEMODE "wb"           /* write (some) PS files in binary mode */
#else
#define READMODE  "r"
#define WRITEMODE "w"           /* write (some) PS files in binary mode */
#endif

int Margin     	= 20;           /* safety margin */
BOOL quiet	= FALSE;	/* suppress informational messages */
BOOL autorotate = FALSE;	/* disable automatic rotation */

extern BOOL	AnalyzeJPEG P1(imagedata *, image);
extern int	ASCII85Encode P2(FILE *, in, FILE *, out);
extern void     ASCIIHexEncode P2(FILE *, in, FILE *, out);

#ifndef MAC
extern char *optarg;
extern int optind;
#endif

#ifdef DOS
extern int      getopt P3(int, nargc, char **, nargv, char *, ostr);
#endif

#define BUFFERSIZE 1024
static char buffer[BUFFERSIZE];
static char *ColorSpaceNames[] = {"", "Gray", "", "RGB", "CMYK" };

/* Array of known page sizes including name, width, and height */

typedef struct { const char *name; int width; int height; } PageSize_s;

PageSize_s PageSizes[] = {
    {"a0",	2380, 3368},
    {"a1",	1684, 2380},
    {"a2",	1190, 1684},
    {"a3",	842, 1190},
    {"a4",	595, 842},
    {"a5",	421, 595},
    {"a6",	297, 421},
    {"b5",	501, 709},
    {"letter",	612, 792},
    {"legal",	612, 1008},
    {"ledger",	1224, 792},
    {"p11x17",	792, 1224}
};

#define PAGESIZELIST	(sizeof(PageSizes)/sizeof(PageSizes[0]))

#ifdef A4
int PageWidth  = 595;           /* page width A4 */
int PageHeight = 842;           /* page height A4 */
#else
int PageWidth  = 612;           /* page width letter */
int PageHeight = 792;           /* page height letter */
#endif

static void 
JPEGtoPS P2(imagedata *, JPEG, FILE *, PSfile) {
  int llx, lly, urx, ury;        /* Bounding box coordinates */
  size_t n;
  float scale, sx, sy;           /* scale factors            */
  time_t t;
  int i;

  /* read image parameters and fill JPEG struct*/
  if (!AnalyzeJPEG(JPEG)) {
    fprintf(stderr, "Error: '%s' is not a proper JPEG file!\n", JPEG->filename);
    return;
  }

  if (!quiet)
      fprintf(stderr, "Note on file '%s': %dx%d pixel, %d color component%s\n",
	JPEG->filename, JPEG->width, JPEG->height, JPEG->components,
	(JPEG->components == 1 ? "" : "s"));

  /* "Use resolution from file" was requested, but we couldn't find any */
  if (JPEG->dpi == DPI_USE_FILE && !quiet) { 
    fprintf(stderr,
    	"Note: no resolution values found in JPEG file - using standard scaling.\n");
    JPEG->dpi = DPI_IGNORE;
  }

  if (JPEG->dpi == DPI_IGNORE) {
    if (JPEG->width > JPEG->height && autorotate) {	/* switch to landscape if needed */
      JPEG->landscape = TRUE;
      if (!quiet)
	  fprintf(stderr, 
	    "Note: image width exceeds height - producing landscape output!\n");
    }
    if (!JPEG->landscape) {       /* calculate scaling factors */
      sx = (float) (PageWidth - 2*Margin) / JPEG->width;
      sy = (float) (PageHeight - 2*Margin) / JPEG->height;
    }else {
      sx = (float) (PageHeight - 2*Margin) / JPEG->width;
      sy = (float) (PageWidth - 2*Margin) / JPEG->height;
    }
    scale = min(sx, sy);	/* We use at least one edge of the page */
  } else {
    if (!quiet)
	fprintf(stderr, "Note: Using resolution %d dpi.\n", (int) JPEG->dpi);
    scale = 72 / JPEG->dpi;     /* use given image resolution */
  }

  if (JPEG->landscape) {
    /* landscape: move to (urx, lly) */
    urx = PageWidth - Margin;
    lly = Margin;
    ury = (int) (Margin + scale*JPEG->width + 0.9);    /* ceiling */
    llx = (int) (urx - scale * JPEG->height);          /* floor  */
  }else {
    /* portrait: move to (llx, lly) */
    llx = lly = Margin;
    urx = (int) (llx + scale * JPEG->width + 0.9);     /* ceiling */
    ury = (int) (lly + scale * JPEG->height + 0.9);    /* ceiling */
  }

  time(&t);

  /* produce EPS header comments */
  fprintf(PSfile, "%%!PS-Adobe-3.0 EPSF-3.0\n");
  fprintf(PSfile, "%%%%Creator: jpeg2ps %s by Thomas Merz\n", VERSION);
  fprintf(PSfile, "%%%%Title: %s\n", JPEG->filename);
  fprintf(PSfile, "%%%%CreationDate: %s", ctime(&t));
  fprintf(PSfile, "%%%%BoundingBox: %d %d %d %d\n", 
                   llx, lly, urx, ury);
  fprintf(PSfile, "%%%%DocumentData: %s\n", 
                  JPEG->mode == BINARY ? "Binary" : "Clean7Bit");
  fprintf(PSfile, "%%%%LanguageLevel: 2\n");
  fprintf(PSfile, "%%%%EndComments\n");
  fprintf(PSfile, "%%%%BeginProlog\n");
  fprintf(PSfile, "%%%%EndProlog\n");
  fprintf(PSfile, "%%%%Page: 1 1\n");

  fprintf(PSfile, "/languagelevel where {pop languagelevel 2 lt}");
  fprintf(PSfile, "{true} ifelse {\n");
  fprintf(PSfile, "  (JPEG file '%s' needs PostScript Level 2!",
                  JPEG->filename);
  fprintf(PSfile, "\\n) dup print flush\n");
  fprintf(PSfile, "  /Helvetica findfont 20 scalefont setfont ");
  fprintf(PSfile, "100 100 moveto show showpage stop\n");
  fprintf(PSfile, "} if\n");

  fprintf(PSfile, "save\n");
  fprintf(PSfile, "/RawData currentfile ");

  if (JPEG->mode == ASCIIHEX)            /* hex representation... */
    fprintf(PSfile, "/ASCIIHexDecode filter ");
  else if (JPEG->mode == ASCII85)        /* ...or ASCII85         */
    fprintf(PSfile, "/ASCII85Decode filter ");
  /* else binary mode: don't use any additional filter! */

  fprintf(PSfile, "def\n");

  fprintf(PSfile, "/Data RawData << ");
  fprintf(PSfile, ">> /DCTDecode filter def\n");

  /* translate to lower left corner of image */
  fprintf(PSfile, "%d %d translate\n", (JPEG->landscape ? 
                   PageWidth - Margin : Margin), Margin);

  if (JPEG->landscape)                 /* rotation for landscape */
    fprintf(PSfile, "90 rotate\n");
      
  fprintf(PSfile, "%.2f %.2f scale\n", /* scaling */
                   JPEG->width * scale, JPEG->height * scale);
  fprintf(PSfile, "/Device%s setcolorspace\n", 
                  ColorSpaceNames[JPEG->components]);
  fprintf(PSfile, "{ << /ImageType 1\n");
  fprintf(PSfile, "     /Width %d\n", JPEG->width);
  fprintf(PSfile, "     /Height %d\n", JPEG->height);
  fprintf(PSfile, "     /ImageMatrix [ %d 0 0 %d 0 %d ]\n",
                  JPEG->width, -JPEG->height, JPEG->height);
  fprintf(PSfile, "     /DataSource Data\n");
  fprintf(PSfile, "     /BitsPerComponent %d\n", 
                  JPEG->bits_per_component);

  /* workaround for color-inverted CMYK files produced by Adobe Photoshop:
   * compensate for the color inversion in the PostScript code
   */
  if (JPEG->adobe && JPEG->components == 4) {
    if (!quiet)
	fprintf(stderr, "Note: Adobe-conforming CMYK file - applying workaround for color inversion.\n");
    fprintf(PSfile, "     /Decode [1 0 1 0 1 0 1 0]\n");
  }else {
    fprintf(PSfile, "     /Decode [0 1");
    for (i = 1; i < JPEG->components; i++) 
      fprintf(PSfile," 0 1");
    fprintf(PSfile, "]\n");
  }

  fprintf(PSfile, "  >> image\n");
  fprintf(PSfile, "  Data closefile\n");
  fprintf(PSfile, "  RawData flushfile\n");
  fprintf(PSfile, "  showpage\n");
  fprintf(PSfile, "  restore\n");
  fprintf(PSfile, "} exec");

  /* seek to start position of JPEG data */
  fseek(JPEG->fp, JPEG->startpos, SEEK_SET);

  switch (JPEG->mode) {
  case BINARY:
    /* important: ONE blank and NO newline */
    fprintf(PSfile, " ");
#ifdef DOS
    fflush(PSfile);         	  /* up to now we have CR/NL mapping */
    setmode(fileno(PSfile), O_BINARY);    /* continue in binary mode */
#endif
    /* copy data without change */
    while ((n = fread(buffer, 1, sizeof(buffer), JPEG->fp)) != 0)
      fwrite(buffer, 1, n, PSfile);
#ifdef DOS
    fflush(PSfile);                  	/* binary yet */
    setmode(fileno(PSfile), O_TEXT);    /* text mode */
#endif
    break;

  case ASCII85:
    fprintf(PSfile, "\n");

    /* ASCII85 representation of image data */
    if (ASCII85Encode(JPEG->fp, PSfile)) {
      fprintf(stderr, "Error: internal problems with ASCII85Encode!\n");
      exit(1);
    }
    break;

  case ASCIIHEX:
    /* hex representation of image data (useful for buggy dvips) */
    ASCIIHexEncode(JPEG->fp, PSfile);
    break;
  }
  fprintf(PSfile, "\n%%%%EOF\n");
}

static
void usage P0(void) {
  fprintf(stderr, "jpeg2ps %s: convert JPEG files to PostScript Level 2.\n",
		   VERSION);
  fprintf(stderr, "(C) Thomas Merz 1994-1999\n\n");
  fprintf(stderr, "usage: jpeg2ps [options] jpegfile > epsfile\n");
  fprintf(stderr, "-a        auto rotate: produce landscape output if width > height\n");
  fprintf(stderr, "-b        binary mode: output 8 bit data (default: 7 bit with ASCII85)\n");
  fprintf(stderr, "-h        hex mode: output 7 bit data in ASCIIHex encoding\n");
  fprintf(stderr, "-o <name> output file name\n");
  fprintf(stderr, "-p <size> page size name. Known names are:\n");
  fprintf(stderr, "          a0, a1, a2, a3, a4, a5, a6, b5, letter, legal, ledger, p11x17\n");
  fprintf(stderr, "-q        quiet mode: suppress all informational messages\n");
  fprintf(stderr, "-r <dpi>  resolution value (dots per inch)\n");
  fprintf(stderr, "          0 means use value given in file, if any (disables autorotate)\n");
  exit(1);
}

int
main P2(int, argc, char **, argv) {
  imagedata image;
  FILE *outfile;

#ifdef MAC
  int i, bufLength;
  char *cp, outfilename[512];
#else
  int opt, pagesizeindex = -1;
#endif

  image.filename = NULL;
  image.mode     = ASCII85;
  image.startpos = 0L;
  image.landscape= FALSE;
  image.dpi      = DPI_IGNORE;
  image.adobe    = FALSE;

  outfile = stdout;

 if (argc == 1)
    usage();

#ifndef MAC
  while ((opt = getopt(argc, argv, "abho:p:qr:")) != -1)
    switch (opt) {
      case 'a':
          autorotate = TRUE;
          break;
      case 'b':
	  image.mode = BINARY;
	  break;
      case 'h':
	  image.mode = ASCIIHEX;
	  break;
      case 'o':
	  outfile = fopen(optarg, "w");
	  if (outfile == NULL) {
	    fprintf(stderr, "Error: cannot open output file %s.\n", optarg);
	    exit(-2);
	  } 
	  break;
      case 'p':
	  for(pagesizeindex=0; pagesizeindex < PAGESIZELIST; pagesizeindex++)
	    if (!strcmp((const char *) optarg, PageSizes[pagesizeindex].name)) {
		PageHeight = PageSizes[pagesizeindex].height;
		PageWidth = PageSizes[pagesizeindex].width;
		break;
	    }
	  if (pagesizeindex == PAGESIZELIST) {	/* page size name not found */
		fprintf(stderr, "Error: Unknown page size %s.\n", optarg);
		exit(-3);
	  }
	  break;
      case 'q':
          quiet = TRUE;
	  break;
      case 'r':
	  image.dpi = (float) atof(optarg);
	  if (image.dpi < 0) {
	    fprintf(stderr, "Error: bad resolution value %f !\n", image.dpi);
	    exit(1);
	  }
	  break;
      case '?':
	  usage();
    }

  if (pagesizeindex != -1 && ! quiet)	/* page size user option given */
      fprintf(stderr, "Note: Using %s page size.\n",
		    PageSizes[pagesizeindex].name);

  if (optind == argc)	/* filename missing */
    usage();
  else
    image.filename = argv[optind];

  if (!image.filename)
    usage();

  if ((image.fp = fopen(image.filename, READMODE)) == NULL) {
    fprintf(stderr, "Error: couldn't read JPEG file '%s'!\n", 
      image.filename),
    exit(1);
  }

  JPEGtoPS(&image, outfile);      /* convert JPEG data */
  fclose(image.fp);
  fclose(outfile);

#else /* MAC */

 for (i = 1; i < argc; i++) {
    image.filename = argv[i];

    strcpy(outfilename, image.filename);
    bufLength = strlen(outfilename);
    cp = outfilename;
    if (bufLength > 3)
    {
	cp += (bufLength - 4);
	/* strip .jpg from terminating string */
	if (strcmp(cp, ".jpg") == 0 || strcmp(cp, ".JPG") == 0) 
	    outfilename[bufLength - 4] = '\0'; 		
    }
    
    strcat(outfilename, ".eps");

     if ((image.fp = fopen(image.filename, READMODE)) == NULL) {
	fprintf(stderr, "Error: couldn't read JPEG file '%s'!\n", 
	image.filename),
	exit(1);
     }

    outfile = fopen(outfilename, WRITEMODE);

    JPEGtoPS(&image, outfile);      /* convert JPEG data */

    fclose(image.fp);
    fclose(outfile);
  }

#endif	/* not MAC */

  return 0;
}