Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/tools/ippeveps.c
1090 views
1
/*
2
* Generic Adobe PostScript printer command for ippeveprinter/CUPS.
3
*
4
* Copyright © 2021-2022 by OpenPrinting.
5
* Copyright © 2019 by Apple Inc.
6
*
7
* Licensed under Apache License v2.0. See the file "LICENSE" for more
8
* information.
9
*/
10
11
/*
12
* Include necessary headers...
13
*/
14
15
#include "ippevecommon.h"
16
#if !CUPS_LITE
17
# include <cups/ppd-private.h>
18
#endif /* !CUPS_LITE */
19
#include <limits.h>
20
#include <sys/wait.h>
21
22
#ifdef __APPLE__
23
# define PDFTOPS CUPS_SERVERBIN "/filter/cgpdftops"
24
#else
25
# define PDFTOPS CUPS_SERVERBIN "/filter/pdftops"
26
#endif /* __APPLE__ */
27
28
29
/*
30
* Local globals...
31
*/
32
33
#if !CUPS_LITE
34
static ppd_file_t *ppd = NULL; /* PPD file data */
35
static _ppd_cache_t *ppd_cache = NULL;
36
/* IPP to PPD cache data */
37
#endif /* !CUPS_LITE */
38
39
40
/*
41
* Local functions...
42
*/
43
44
static void ascii85(const unsigned char *data, int length, int eod);
45
static void dsc_header(int num_pages);
46
static void dsc_page(int page);
47
static void dsc_trailer(int num_pages);
48
static int get_options(cups_option_t **options);
49
static int jpeg_to_ps(const char *filename, int copies);
50
static int pdf_to_ps(const char *filename, int copies, int num_options, cups_option_t *options);
51
static int ps_to_ps(const char *filename, int copies);
52
static int raster_to_ps(const char *filename);
53
54
55
/*
56
* 'main()' - Main entry for PostScript printer command.
57
*/
58
59
int /* O - Exit status */
60
main(int argc, /* I - Number of command-line arguments */
61
char *argv[]) /* I - Command-line arguments */
62
{
63
const char *content_type, /* Content type to print */
64
*ipp_copies; /* IPP_COPIES value */
65
int copies; /* Number of copies */
66
int num_options; /* Number of options */
67
cups_option_t *options; /* Options */
68
69
70
/*
71
* Get print options...
72
*/
73
74
num_options = get_options(&options);
75
if ((ipp_copies = getenv("IPP_COPIES")) != NULL)
76
{
77
if ((copies = atoi(ipp_copies)) < 1)
78
copies = 1;
79
}
80
else
81
copies = 1;
82
83
/*
84
* Print it...
85
*/
86
87
if (argc > 2)
88
{
89
fputs("ERROR: Too many arguments supplied, aborting.\n", stderr);
90
return (1);
91
}
92
else if ((content_type = getenv("CONTENT_TYPE")) == NULL)
93
{
94
fputs("ERROR: CONTENT_TYPE environment variable not set, aborting.\n", stderr);
95
return (1);
96
}
97
else if (!strcasecmp(content_type, "application/pdf"))
98
{
99
return (pdf_to_ps(argv[1], copies, num_options, options));
100
}
101
else if (!strcasecmp(content_type, "application/postscript"))
102
{
103
return (ps_to_ps(argv[1], copies));
104
}
105
else if (!strcasecmp(content_type, "image/jpeg"))
106
{
107
return (jpeg_to_ps(argv[1], copies));
108
}
109
else if (!strcasecmp(content_type, "image/pwg-raster") || !strcasecmp(content_type, "image/urf"))
110
{
111
return (raster_to_ps(argv[1]));
112
}
113
else
114
{
115
fprintf(stderr, "ERROR: CONTENT_TYPE %s not supported.\n", content_type);
116
return (1);
117
}
118
}
119
120
121
/*
122
* 'ascii85()' - Write binary data using a Base85 encoding...
123
*/
124
125
static void
126
ascii85(const unsigned char *data, /* I - Data to write */
127
int length, /* I - Number of bytes to write */
128
int eod) /* I - 1 if this is the end, 0 otherwise */
129
{
130
unsigned b = 0; /* Current 32-bit word */
131
unsigned char c[5]; /* Base-85 encoded characters */
132
static int col = 0; /* Column */
133
static unsigned char leftdata[4]; /* Leftover data at the end */
134
static int leftcount = 0; /* Size of leftover data */
135
136
137
length += leftcount;
138
139
while (length > 3)
140
{
141
switch (leftcount)
142
{
143
case 0 :
144
b = (unsigned)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
145
break;
146
case 1 :
147
b = (unsigned)((leftdata[0] << 24) | (data[0] << 16) | (data[1] << 8) | data[2]);
148
break;
149
case 2 :
150
b = (unsigned)((leftdata[0] << 24) | (leftdata[1] << 16) | (data[0] << 8) | data[1]);
151
break;
152
case 3 :
153
b = (unsigned)((leftdata[0] << 24) | (leftdata[1] << 16) | (leftdata[2] << 8) | data[0]);
154
break;
155
}
156
157
if (col >= 76)
158
{
159
col = 0;
160
putchar('\n');
161
}
162
163
if (b == 0)
164
{
165
putchar('z');
166
col ++;
167
}
168
else
169
{
170
c[4] = (unsigned char) ((b % 85) + '!');
171
b /= 85;
172
c[3] = (unsigned char) ((b % 85) + '!');
173
b /= 85;
174
c[2] = (unsigned char) ((b % 85) + '!');
175
b /= 85;
176
c[1] = (unsigned char) ((b % 85) + '!');
177
b /= 85;
178
c[0] = (unsigned char)(b + '!');
179
180
fwrite(c, 1, 5, stdout);
181
col += 5;
182
}
183
184
data += 4 - leftcount;
185
length -= 4 - leftcount;
186
leftcount = 0;
187
}
188
189
if (length > 0)
190
{
191
// Copy any remainder into the leftdata array...
192
if (length > leftcount)
193
memcpy(leftdata + leftcount, data, (size_t)(length - leftcount));
194
195
memset(leftdata + length, 0, (size_t)(4 - length));
196
197
leftcount = length;
198
}
199
200
if (eod)
201
{
202
// Do the end-of-data dance...
203
if (col >= 76)
204
{
205
col = 0;
206
putchar('\n');
207
}
208
209
if (leftcount > 0)
210
{
211
// Write the remaining bytes as needed...
212
b = (unsigned)((leftdata[0] << 24) | (leftdata[1] << 16) | (leftdata[2] << 8) | leftdata[3]);
213
214
c[4] = (unsigned char) ((b % 85) + '!');
215
b /= 85;
216
c[3] = (unsigned char) ((b % 85) + '!');
217
b /= 85;
218
c[2] = (unsigned char) ((b % 85) + '!');
219
b /= 85;
220
c[1] = (unsigned char) ((b % 85) + '!');
221
b /= 85;
222
c[0] = (unsigned char)(b + '!');
223
224
fwrite(c, (size_t)(leftcount + 1), 1, stdout);
225
226
leftcount = 0;
227
}
228
229
puts("~>");
230
col = 0;
231
}
232
}
233
234
235
/*
236
* 'dsc_header()' - Write out a standard Document Structuring Conventions
237
* PostScript header.
238
*/
239
240
static void
241
dsc_header(int num_pages) /* I - Number of pages or 0 if not known */
242
{
243
const char *job_name = getenv("IPP_JOB_NAME");
244
/* job-name value */
245
246
247
#if !CUPS_LITE
248
const char *job_id = getenv("IPP_JOB_ID");
249
/* job-id value */
250
251
ppdEmitJCL(ppd, stdout, job_id ? atoi(job_id) : 0, cupsUser(), job_name ? job_name : "Unknown");
252
#endif /* !CUPS_LITE */
253
254
puts("%!PS-Adobe-3.0");
255
puts("%%LanguageLevel: 2");
256
printf("%%%%Creator: ippeveps/%d.%d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, CUPS_VERSION_PATCH);
257
if (job_name)
258
{
259
fputs("%%Title: ", stdout);
260
while (*job_name)
261
{
262
if (*job_name >= 0x20 && *job_name < 0x7f)
263
putchar(*job_name);
264
else
265
putchar('?');
266
267
job_name ++;
268
}
269
putchar('\n');
270
}
271
if (num_pages > 0)
272
printf("%%%%Pages: %d\n", num_pages);
273
else
274
puts("%%Pages: (atend)");
275
puts("%%EndComments");
276
277
#if !CUPS_LITE
278
if (ppd)
279
{
280
puts("%%BeginProlog");
281
if (ppd->patches)
282
{
283
puts("%%BeginFeature: *JobPatchFile 1");
284
puts(ppd->patches);
285
puts("%%EndFeature");
286
}
287
ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
288
puts("%%EndProlog");
289
290
puts("%%BeginSetup");
291
ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
292
ppdEmit(ppd, stdout, PPD_ORDER_ANY);
293
puts("%%EndSetup");
294
}
295
#endif /* !CUPS_LITE */
296
}
297
298
299
/*
300
* 'dsc_page()' - Mark the start of a page.
301
*/
302
303
static void
304
dsc_page(int page) /* I - Page number (1-based) */
305
{
306
printf("%%%%Page: (%d) %d\n", page, page);
307
308
fprintf(stderr, "ATTR: job-impressions-completed=%d\n", page);
309
310
#if !CUPS_LITE
311
if (ppd)
312
{
313
puts("%%BeginPageSetup");
314
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
315
puts("%%EndPageSetup");
316
}
317
#endif /* !CUPS_LITE */
318
}
319
320
321
/*
322
* 'dsc_trailer()' - Mark the end of the document.
323
*/
324
325
static void
326
dsc_trailer(int num_pages) /* I - Number of pages */
327
{
328
if (num_pages > 0)
329
{
330
puts("%%Trailer");
331
printf("%%%%Pages: %d\n", num_pages);
332
puts("%%EOF");
333
}
334
335
#if !CUPS_LITE
336
if (ppd && ppd->jcl_end)
337
ppdEmitJCLEnd(ppd, stdout);
338
else
339
#endif /* !CUPS_LITE */
340
putchar(0x04);
341
}
342
343
344
/*
345
* 'get_options()' - Get the PPD options corresponding to the IPP Job Template
346
* attributes.
347
*/
348
349
static int /* O - Number of options */
350
get_options(cups_option_t **options) /* O - Options */
351
{
352
int num_options = 0; /* Number of options */
353
const char *value; /* Option value */
354
pwg_media_t *media = NULL; /* Media mapping */
355
int num_media_col = 0; /* Number of media-col values */
356
cups_option_t *media_col = NULL; /* media-col values */
357
#if !CUPS_LITE
358
const char *choice; /* PPD choice */
359
#endif /* !CUPS_LITE */
360
361
362
/*
363
* No options to start...
364
*/
365
366
*options = NULL;
367
368
/*
369
* Media...
370
*/
371
372
if ((value = getenv("IPP_MEDIA")) == NULL)
373
if ((value = getenv("IPP_MEDIA_COL")) == NULL)
374
if ((value = getenv("IPP_MEDIA_DEFAULT")) == NULL)
375
value = getenv("IPP_MEDIA_COL_DEFAULT");
376
377
if (value)
378
{
379
if (*value == '{')
380
{
381
/*
382
* media-col value...
383
*/
384
385
num_media_col = cupsParseOptions(value, 0, &media_col);
386
}
387
else
388
{
389
/*
390
* media value - map to media-col.media-size-name...
391
*/
392
393
num_media_col = cupsAddOption("media-size-name", value, 0, &media_col);
394
}
395
}
396
397
if ((value = cupsGetOption("media-size-name", num_media_col, media_col)) != NULL)
398
{
399
media = pwgMediaForPWG(value);
400
}
401
else if ((value = cupsGetOption("media-size", num_media_col, media_col)) != NULL)
402
{
403
int num_media_size; /* Number of media-size values */
404
cups_option_t *media_size; /* media-size values */
405
const char *x_dimension, /* x-dimension value */
406
*y_dimension; /* y-dimension value */
407
408
num_media_size = cupsParseOptions(value, 0, &media_size);
409
410
if ((x_dimension = cupsGetOption("x-dimension", num_media_size, media_size)) != NULL && (y_dimension = cupsGetOption("y-dimension", num_media_size, media_size)) != NULL)
411
media = pwgMediaForSize(atoi(x_dimension), atoi(y_dimension));
412
413
cupsFreeOptions(num_media_size, media_size);
414
}
415
416
if (media)
417
num_options = cupsAddOption("PageSize", media->ppd, num_options, options);
418
419
#if !CUPS_LITE
420
/*
421
* Load PPD file and the corresponding IPP <-> PPD cache data...
422
*/
423
424
if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL && (ppd_cache = _ppdCacheCreateWithPPD(ppd)) != NULL)
425
{
426
/* TODO: Fix me - values are names, not numbers... Also need to support finishings-col */
427
if ((value = getenv("IPP_FINISHINGS")) == NULL)
428
value = getenv("IPP_FINISHINGS_DEFAULT");
429
430
if (value)
431
{
432
char *ptr; /* Pointer into value */
433
long fin; /* Current value */
434
435
for (fin = strtol(value, &ptr, 10); fin > 0; fin = strtol(ptr + 1, &ptr, 10))
436
{
437
num_options = _ppdCacheGetFinishingOptions(ppd_cache, NULL, (ipp_finishings_t)fin, num_options, options);
438
439
if (*ptr != ',')
440
break;
441
}
442
}
443
444
if ((value = cupsGetOption("media-source", num_media_col, media_col)) != NULL)
445
{
446
if ((choice = _ppdCacheGetInputSlot(ppd_cache, NULL, value)) != NULL)
447
num_options = cupsAddOption("InputSlot", choice, num_options, options);
448
}
449
450
if ((value = cupsGetOption("media-type", num_media_col, media_col)) != NULL)
451
{
452
if ((choice = _ppdCacheGetMediaType(ppd_cache, NULL, value)) != NULL)
453
num_options = cupsAddOption("MediaType", choice, num_options, options);
454
}
455
456
if ((value = getenv("IPP_OUTPUT_BIN")) == NULL)
457
value = getenv("IPP_OUTPUT_BIN_DEFAULT");
458
459
if (value)
460
{
461
if ((choice = _ppdCacheGetOutputBin(ppd_cache, value)) != NULL)
462
num_options = cupsAddOption("OutputBin", choice, num_options, options);
463
}
464
465
if ((value = getenv("IPP_SIDES")) == NULL)
466
value = getenv("IPP_SIDES_DEFAULT");
467
468
if (value && ppd_cache->sides_option)
469
{
470
if (!strcmp(value, "one-sided") && ppd_cache->sides_1sided)
471
num_options = cupsAddOption(ppd_cache->sides_option, ppd_cache->sides_1sided, num_options, options);
472
else if (!strcmp(value, "two-sided-long-edge") && ppd_cache->sides_2sided_long)
473
num_options = cupsAddOption(ppd_cache->sides_option, ppd_cache->sides_2sided_long, num_options, options);
474
else if (!strcmp(value, "two-sided-short-edge") && ppd_cache->sides_2sided_short)
475
num_options = cupsAddOption(ppd_cache->sides_option, ppd_cache->sides_2sided_short, num_options, options);
476
}
477
478
if ((value = getenv("IPP_PRINT_QUALITY")) == NULL)
479
value = getenv("IPP_PRINT_QUALITY_DEFAULT");
480
481
if (value)
482
{
483
int i; /* Looping var */
484
int pq; /* Print quality (0-2) */
485
int pcm = 1; /* Print color model (0 = mono, 1 = color) */
486
int num_presets; /* Number of presets */
487
cups_option_t *presets; /* Presets */
488
489
if (!strcmp(value, "draft"))
490
pq = 0;
491
else if (!strcmp(value, "high"))
492
pq = 2;
493
else
494
pq = 1;
495
496
if ((value = getenv("IPP_PRINT_COLOR_MODE")) == NULL)
497
value = getenv("IPP_PRINT_COLOR_MODE_DEFAULT");
498
499
if (value && !strcmp(value, "monochrome"))
500
pcm = 0;
501
502
num_presets = ppd_cache->num_presets[pcm][pq];
503
presets = ppd_cache->presets[pcm][pq];
504
505
for (i = 0; i < num_presets; i ++)
506
num_options = cupsAddOption(presets[i].name, presets[i].value, num_options, options);
507
}
508
509
/*
510
* Mark the PPD with the options...
511
*/
512
513
ppdMarkDefaults(ppd);
514
cupsMarkOptions(ppd, num_options, *options);
515
}
516
#endif /* !CUPS_LITE */
517
518
cupsFreeOptions(num_media_col, media_col);
519
520
return (num_options);
521
}
522
523
524
/*
525
* 'jpeg_to_ps()' - Convert a JPEG file to PostScript.
526
*/
527
528
static int /* O - Exit status */
529
jpeg_to_ps(const char *filename, /* I - Filename */
530
int copies) /* I - Number of copies */
531
{
532
int fd; /* JPEG file descriptor */
533
int copy; /* Current copy */
534
int width = 0, /* Width */
535
height = 0, /* Height */
536
depth = 0; /* Number of colors */
537
ssize_t length; /* Length of marker */
538
unsigned char buffer[65536], /* Copy buffer */
539
*bufptr, /* Pointer info buffer */
540
*bufend; /* End of buffer */
541
ssize_t bytes; /* Bytes in buffer */
542
const char *decode; /* Decode array */
543
float page_left, /* Left margin */
544
page_top, /* Top margin */
545
page_width, /* Page width in points */
546
page_height, /* Page height in points */
547
x_factor, /* X image scaling factor */
548
y_factor, /* Y image scaling factor */
549
page_scaling; /* Image scaling factor */
550
#if !CUPS_LITE
551
ppd_size_t *page_size; /* Current page size */
552
#endif /* !CUPS_LITE */
553
554
555
/*
556
* Open the input file...
557
*/
558
559
if (filename)
560
{
561
if ((fd = open(filename, O_RDONLY)) < 0)
562
{
563
fprintf(stderr, "ERROR: Unable to open \"%s\": %s\n", filename, strerror(errno));
564
return (1);
565
}
566
}
567
else
568
{
569
fd = 0;
570
copies = 1;
571
}
572
573
/*
574
* Read the JPEG dimensions...
575
*/
576
577
bytes = read(fd, buffer, sizeof(buffer));
578
579
if (bytes < 3 || memcmp(buffer, "\377\330\377", 3))
580
{
581
fputs("ERROR: Not a JPEG image.\n", stderr);
582
583
if (fd > 0)
584
close(fd);
585
586
return (1);
587
}
588
589
for (bufptr = buffer + 2, bufend = buffer + bytes; bufptr < bufend;)
590
{
591
/*
592
* Scan the file for a SOFn marker, then we can get the dimensions...
593
*/
594
595
if (*bufptr == 0xff)
596
{
597
bufptr ++;
598
599
if (bufptr >= bufend)
600
{
601
/*
602
* If we are at the end of the current buffer, re-fill and continue...
603
*/
604
605
if ((bytes = read(fd, buffer, sizeof(buffer))) <= 0)
606
break;
607
608
bufptr = buffer;
609
bufend = buffer + bytes;
610
}
611
612
if (*bufptr == 0xff)
613
continue;
614
615
if ((bufptr + 16) >= bufend)
616
{
617
/*
618
* Read more of the marker...
619
*/
620
621
bytes = bufend - bufptr;
622
623
memmove(buffer, bufptr, (size_t)bytes);
624
bufptr = buffer;
625
bufend = buffer + bytes;
626
627
if ((bytes = read(fd, bufend, sizeof(buffer) - (size_t)bytes)) <= 0)
628
break;
629
630
bufend += bytes;
631
}
632
633
length = (ssize_t)((bufptr[1] << 8) | bufptr[2]);
634
635
if ((*bufptr >= 0xc0 && *bufptr <= 0xc3) || (*bufptr >= 0xc5 && *bufptr <= 0xc7) || (*bufptr >= 0xc9 && *bufptr <= 0xcb) || (*bufptr >= 0xcd && *bufptr <= 0xcf))
636
{
637
/*
638
* SOFn marker, look for dimensions...
639
*/
640
641
width = (bufptr[6] << 8) | bufptr[7];
642
height = (bufptr[4] << 8) | bufptr[5];
643
depth = bufptr[8];
644
break;
645
}
646
647
/*
648
* Skip past this marker...
649
*/
650
651
bufptr ++;
652
bytes = bufend - bufptr;
653
654
while (length >= bytes)
655
{
656
length -= bytes;
657
658
if ((bytes = read(fd, buffer, sizeof(buffer))) <= 0)
659
break;
660
661
bufptr = buffer;
662
bufend = buffer + bytes;
663
}
664
665
if (length > bytes)
666
break;
667
668
bufptr += length;
669
}
670
}
671
672
fprintf(stderr, "DEBUG: JPEG dimensions are %dx%dx%d\n", width, height, depth);
673
674
if (width <= 0 || height <= 0 || depth <= 0)
675
{
676
fputs("ERROR: No valid image data in JPEG file.\n", stderr);
677
678
if (fd > 0)
679
close(fd);
680
681
return (1);
682
}
683
684
fputs("ATTR: job-impressions=1\n", stderr);
685
686
/*
687
* Figure out the dimensions/scaling of the final image...
688
*/
689
690
#if CUPS_LITE
691
page_left = 18.0f;
692
page_top = 756.0f;
693
page_width = 576.0f;
694
page_height = 720.0f;
695
696
#else
697
if ((page_size = ppdPageSize(ppd, NULL)) != NULL)
698
{
699
page_left = page_size->left;
700
page_top = page_size->top;
701
page_width = page_size->right - page_left;
702
page_height = page_top - page_size->bottom;
703
}
704
else
705
{
706
page_left = 18.0f;
707
page_top = 756.0f;
708
page_width = 576.0f;
709
page_height = 720.0f;
710
}
711
#endif /* CUPS_LITE */
712
713
fprintf(stderr, "DEBUG: page_left=%.2f, page_top=%.2f, page_width=%.2f, page_height=%.2f\n", page_left, page_top, page_width, page_height);
714
715
/* TODO: Support orientation/rotation, different print-scaling modes */
716
x_factor = page_width / width;
717
y_factor = page_height / height;
718
719
if (x_factor > y_factor && (height * x_factor) <= page_height)
720
page_scaling = x_factor;
721
else
722
page_scaling = y_factor;
723
724
fprintf(stderr, "DEBUG: Scaled dimensions are %.2fx%.2f\n", width * page_scaling, height * page_scaling);
725
726
/*
727
* Write pages...
728
*/
729
730
dsc_header(copies);
731
732
for (copy = 1; copy <= copies; copy ++)
733
{
734
dsc_page(copy);
735
736
if (depth == 1)
737
{
738
puts("/DeviceGray setcolorspace");
739
decode = "0 1";
740
}
741
else if (depth == 3)
742
{
743
puts("/DeviceRGB setcolorspace");
744
decode = "0 1 0 1 0 1";
745
}
746
else
747
{
748
puts("/DeviceCMYK setcolorspace");
749
decode = "0 1 0 1 0 1 0 1";
750
}
751
752
printf("gsave %.3f %.3f translate %.3f %.3f scale\n", page_left + 0.5f * (page_width - width * page_scaling), page_top - 0.5f * (page_height - height * page_scaling), page_scaling, page_scaling);
753
printf("<</ImageType 1/Width %d/Height %d/BitsPerComponent 8/ImageMatrix[1 0 0 -1 0 1]/Decode[%s]/DataSource currentfile/ASCII85Decode filter/DCTDecode filter/Interpolate true>>image\n", width, height, decode);
754
755
if (fd > 0)
756
lseek(fd, 0, SEEK_SET);
757
758
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
759
ascii85(buffer, (int)bytes, 0);
760
761
ascii85(buffer, 0, 1);
762
763
puts("grestore showpage");
764
}
765
766
dsc_trailer(0);
767
768
return (0);
769
}
770
771
772
/*
773
* 'pdf_to_ps()' - Convert a PDF file to PostScript.
774
*/
775
776
static int /* O - Exit status */
777
pdf_to_ps(const char *filename, /* I - Filename */
778
int copies, /* I - Number of copies */
779
int num_options, /* I - Number of options */
780
cups_option_t *options) /* I - options */
781
{
782
int status; /* Exit status */
783
char tempfile[1024]; /* Temporary file */
784
int tempfd; /* Temporary file descriptor */
785
int pid; /* Process ID */
786
const char *pdf_argv[8]; /* Command-line arguments */
787
char pdf_options[1024]; /* Options */
788
const char *value; /* Option value */
789
const char *job_id, /* job-id value */
790
*job_name; /* job-name value */
791
792
793
/*
794
* Create a temporary file for the PostScript version...
795
*/
796
797
if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
798
{
799
fprintf(stderr, "ERROR: Unable to create temporary file: %s\n", strerror(errno));
800
return (1);
801
}
802
803
/*
804
* Run cgpdftops or pdftops in the filter directory...
805
*/
806
807
if ((value = cupsGetOption("PageSize", num_options, options)) != NULL)
808
snprintf(pdf_options, sizeof(pdf_options), "PageSize=%s", value);
809
else
810
pdf_options[0] = '\0';
811
812
if ((job_id = getenv("IPP_JOB_ID")) == NULL)
813
job_id = "42";
814
if ((job_name = getenv("IPP_JOB_NAME")) == NULL)
815
job_name = "untitled";
816
817
pdf_argv[0] = "printer";
818
pdf_argv[1] = job_id;
819
pdf_argv[2] = cupsUser();
820
pdf_argv[3] = job_name;
821
pdf_argv[4] = "1";
822
pdf_argv[5] = pdf_options;
823
pdf_argv[6] = filename;
824
pdf_argv[7] = NULL;
825
826
if ((pid = fork()) == 0)
827
{
828
/*
829
* Child comes here...
830
*/
831
832
close(1);
833
dup2(tempfd, 1);
834
close(tempfd);
835
836
execv(PDFTOPS, (char * const *)pdf_argv);
837
exit(errno);
838
}
839
else if (pid < 0)
840
{
841
/*
842
* Unable to fork process...
843
*/
844
845
perror("ERROR: Unable to start PDF filter");
846
847
close(tempfd);
848
unlink(tempfile);
849
850
return (1);
851
}
852
else
853
{
854
/*
855
* Wait for the filter to complete...
856
*/
857
858
close(tempfd);
859
860
# ifdef HAVE_WAITPID
861
while (waitpid(pid, &status, 0) < 0);
862
# else
863
while (wait(&status) < 0);
864
# endif /* HAVE_WAITPID */
865
866
if (status)
867
{
868
if (WIFEXITED(status))
869
fprintf(stderr, "ERROR: " PDFTOPS " exited with status %d.\n", WEXITSTATUS(status));
870
else
871
fprintf(stderr, "ERROR: " PDFTOPS " terminated with signal %d.\n", WTERMSIG(status));
872
873
unlink(tempfile);
874
return (1);
875
}
876
}
877
878
/*
879
* Copy the PostScript output from the command...
880
*/
881
882
status = ps_to_ps(tempfile, copies);
883
884
unlink(tempfile);
885
886
return (status);
887
}
888
889
890
/*
891
* 'ps_to_ps()' - Copy PostScript to the standard output.
892
*/
893
894
static int /* O - Exit status */
895
ps_to_ps(const char *filename, /* I - Filename */
896
int copies) /* I - Number of copies */
897
{
898
FILE *fp; /* File to read from */
899
int copy, /* Current copy */
900
page, /* Current page number */
901
num_pages = 0, /* Total number of pages */
902
first_page, /* First page */
903
last_page; /* Last page */
904
const char *page_ranges; /* page-ranges option */
905
long first_pos; /* Offset for first page */
906
char line[1024]; /* Line from file */
907
908
909
/*
910
* Open the print file...
911
*/
912
913
if (filename)
914
{
915
if ((fp = fopen(filename, "rb")) == NULL)
916
{
917
fprintf(stderr, "ERROR: Unable to open \"%s\": %s\n", filename, strerror(errno));
918
return (1);
919
}
920
}
921
else
922
{
923
copies = 1;
924
fp = stdin;
925
}
926
927
/*
928
* Check page ranges...
929
*/
930
931
if ((page_ranges = getenv("IPP_PAGE_RANGES")) != NULL)
932
{
933
if (sscanf(page_ranges, "%d-%d", &first_page, &last_page) != 2)
934
{
935
first_page = 1;
936
last_page = INT_MAX;
937
}
938
}
939
else
940
{
941
first_page = 1;
942
last_page = INT_MAX;
943
}
944
945
/*
946
* Write the PostScript header for the document...
947
*/
948
949
dsc_header(0);
950
951
first_pos = 0;
952
953
while (fgets(line, sizeof(line), fp))
954
{
955
if (!strncmp(line, "%%Page:", 7))
956
break;
957
958
if ((first_pos = ftell(fp)) < 0)
959
{
960
perror("DEBUG: ftell failed");
961
first_pos = 0;
962
}
963
964
if (line[0] != '%')
965
fputs(line, stdout);
966
}
967
968
if (!strncmp(line, "%%Page:", 7))
969
{
970
for (copy = 0; copy < copies; copy ++)
971
{
972
int copy_page = 0; /* Do we copy the page data? */
973
974
if (fp != stdin)
975
{
976
if (fseek(fp, first_pos, SEEK_SET) < 0)
977
{
978
perror("ERROR: Unable to seek within PostScript file");
979
break;
980
}
981
}
982
983
page = 0;
984
while (fgets(line, sizeof(line), fp))
985
{
986
if (!strncmp(line, "%%Page:", 7))
987
{
988
page ++;
989
copy_page = page >= first_page && page <= last_page;
990
991
if (copy_page)
992
{
993
num_pages ++;
994
dsc_page(num_pages);
995
}
996
}
997
else if (copy_page)
998
fputs(line, stdout);
999
}
1000
}
1001
}
1002
1003
dsc_trailer(num_pages);
1004
1005
fprintf(stderr, "ATTR: job-impressions=%d\n", num_pages / copies);
1006
1007
if (fp != stdin)
1008
fclose(fp);
1009
1010
return (0);
1011
}
1012
1013
1014
/*
1015
* 'raster_to_ps()' - Convert PWG Raster/Apple Raster to PostScript.
1016
*
1017
* The current implementation locally-decodes the raster data and then writes
1018
* whole, non-blank lines as 1-line high images with base-85 encoding, resulting
1019
* in between 10 and 20 times larger output. An alternate implementation (if it
1020
* is deemed necessary) would be to implement a PostScript decode procedure that
1021
* handles the modified packbits decompression so that we just have the base-85
1022
* encoding overhead (25%). Furthermore, Level 3 PostScript printers also
1023
* support Flate compression.
1024
*
1025
* That said, the most efficient path with the highest quality is for Clients
1026
* to supply PDF files and us to use the existing PDF to PostScript conversion
1027
* filters.
1028
*/
1029
1030
static int /* O - Exit status */
1031
raster_to_ps(const char *filename) /* I - Filename */
1032
{
1033
int fd; /* Input file */
1034
cups_raster_t *ras; /* Raster stream */
1035
cups_page_header2_t header; /* Page header */
1036
int page = 0; /* Current page */
1037
unsigned y; /* Current line */
1038
unsigned char *line; /* Line buffer */
1039
unsigned char white; /* White color */
1040
const char *decode; /* Image decode array */
1041
1042
1043
/*
1044
* Open the input file...
1045
*/
1046
1047
if (filename)
1048
{
1049
if ((fd = open(filename, O_RDONLY)) < 0)
1050
{
1051
fprintf(stderr, "ERROR: Unable to open \"%s\": %s\n", filename, strerror(errno));
1052
return (1);
1053
}
1054
}
1055
else
1056
{
1057
fd = 0;
1058
}
1059
1060
/*
1061
* Open the raster stream and send pages...
1062
*/
1063
1064
if ((ras = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL)
1065
{
1066
fputs("ERROR: Unable to read raster data, aborting.\n", stderr);
1067
return (1);
1068
}
1069
1070
dsc_header(0);
1071
1072
while (cupsRasterReadHeader2(ras, &header))
1073
{
1074
page ++;
1075
1076
fprintf(stderr, "DEBUG: Page %d: %ux%ux%u\n", page, header.cupsWidth, header.cupsHeight, header.cupsBitsPerPixel);
1077
1078
if (header.cupsColorSpace != CUPS_CSPACE_W && header.cupsColorSpace != CUPS_CSPACE_SW && header.cupsColorSpace != CUPS_CSPACE_K && header.cupsColorSpace != CUPS_CSPACE_RGB && header.cupsColorSpace != CUPS_CSPACE_SRGB)
1079
{
1080
fputs("ERROR: Unsupported color space, aborting.\n", stderr);
1081
break;
1082
}
1083
else if (header.cupsBitsPerColor != 1 && header.cupsBitsPerColor != 8)
1084
{
1085
fputs("ERROR: Unsupported bit depth, aborting.\n", stderr);
1086
break;
1087
}
1088
1089
line = malloc(header.cupsBytesPerLine);
1090
1091
dsc_page(page);
1092
1093
puts("gsave");
1094
printf("%.6f %.6f scale\n", 72.0f / header.HWResolution[0], 72.0f / header.HWResolution[1]);
1095
1096
switch (header.cupsColorSpace)
1097
{
1098
case CUPS_CSPACE_W :
1099
case CUPS_CSPACE_SW :
1100
decode = "0 1";
1101
puts("/DeviceGray setcolorspace");
1102
white = 255;
1103
break;
1104
1105
case CUPS_CSPACE_K :
1106
decode = "0 1";
1107
puts("/DeviceGray setcolorspace");
1108
white = 0;
1109
break;
1110
1111
default :
1112
decode = "0 1 0 1 0 1";
1113
puts("/DeviceRGB setcolorspace");
1114
white = 255;
1115
break;
1116
}
1117
1118
printf("gsave /L{grestore gsave 0 exch translate <</ImageType 1/Width %u/Height 1/BitsPerComponent %u/ImageMatrix[1 0 0 -1 0 1]/DataSource currentfile/ASCII85Decode filter/Decode[%s]>>image}bind def\n", header.cupsWidth, header.cupsBitsPerColor, decode);
1119
1120
for (y = header.cupsHeight; y > 0; y --)
1121
{
1122
if (cupsRasterReadPixels(ras, line, header.cupsBytesPerLine))
1123
{
1124
if (line[0] != white || memcmp(line, line + 1, header.cupsBytesPerLine - 1))
1125
{
1126
printf("%d L\n", y - 1);
1127
ascii85(line, (int)header.cupsBytesPerLine, 1);
1128
}
1129
}
1130
else
1131
break;
1132
}
1133
1134
fprintf(stderr, "DEBUG: y=%u at end...\n", y);
1135
1136
puts("grestore grestore");
1137
puts("showpage");
1138
1139
free(line);
1140
}
1141
1142
cupsRasterClose(ras);
1143
1144
dsc_trailer(page);
1145
1146
fprintf(stderr, "ATTR: job-impressions=%d\n", page);
1147
1148
return (0);
1149
}
1150
1151
1152
1153