root/platform/cups/rpdl/trunk/rastertorpdl.c @ 36567

Revision 36567, 16.0 kB (checked in by dayflower, 3 years ago)

初期インポート

Line 
1/*
2   This software is distributed in the hope that it will be useful, but
3   WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
4   to anyone for the consequences of using it or for whether it serves any
5   particular purpose or works at all, unless he says so in writing.  Refer
6   to the GNU General Public License for full details.
7
8   Everyone is granted permission to copy, modify and redistribute
9   this software, but only under the conditions described in the GNU
10   General Public License.  A copy of this license is supposed to have been
11   given to you along with this software so you can know your rights and
12   responsibilities.  It should be in a file named COPYING.  Among other
13   things, the copyright notice and this notice must be preserved on all
14   copies.
15 */
16/*
17   ESC sequences in RPDL are copied from Ricoh RPDL driver for Ghostscript.
18   That implementation was released under GPL, and covered with
19   copyright (C) 1999, 2000 Norihito Ohmori.
20 */
21#include <cups/cups.h>
22#include <cups/i18n.h>
23#include <cups/raster.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <signal.h>
29#include <errno.h>
30
31int g_canceled = 0;
32
33static void
34cancel_job(int sig)
35{
36    g_canceled = 1;
37}
38
39static void
40rpdl_init(FILE *out, ppd_file_t *ppd)
41{
42    fputs(
43        "\033\022!@R00\033 "        /* enter RPDL mode */
44        "\0334"                     /* leave graphic mode */
45        "\033\032I"                 /* printer reset */
46        "\033\022YP,2 "             /* select RPDL mode */
47        , out);
48}
49
50static int
51rpdl_set_custom_paper_size(FILE *out, int width, int height /* in pt */)
52{
53    int w, h;
54
55    if (width < height) {
56        w = width;
57        h = height;
58    }
59    else {
60        w = height;
61        h = width;
62    }
63
64    fprintf(out, "\033\022?5%d,%d\033 ",
65            (int) (w * 25.4 / 72.0),
66            (int) (h * 25.4 / 72.0));
67
68    return 1;
69}
70
71struct paper_name_map_t {
72    const char *name;
73    const char *code[2];
74};
75
76static int
77rpdl_set_paper_size_by_name(FILE *out, const char *name)
78{
79    struct paper_name_map_t *pmap;
80    static struct paper_name_map_t paper_name_map[] = {
81        { "A1", { "A1R", "A1" } },
82        { "A2", { "A2R", "A2" } },
83        { "A3", { "A3R", "A3" } },
84        { "A4", { "A4R", "A4" } },
85        { "A5", { "A5R", "A5" } },
86        { "A6", { "A6R", "A6" } },
87
88        { "B4", { "B4R", "B4" } },
89        { "B5", { "B5R", "B5" } },
90        { "B6", { "B6R", "B6" } },
91
92        { "Letter",    { "LTR", "LT" } },    /* Letter */
93        { "Legal",     { "LGR", "LG" } },    /* Legal */
94        { "Statement", { "HLR", "HLT" } },   /* Half Letter / Statement */
95        { "Ledger",    { "DLR", "DLT" } },   /* Ledger / Double Letter */
96
97        { NULL, { NULL, NULL } },
98    };
99
100    for (pmap = paper_name_map; pmap->name; pmap ++) {
101        if (! strcasecmp(pmap->name, name)) {
102            int i;
103
104            for (i = 0; i < 2; i ++) {
105                if (pmap->code[i])
106                    fprintf(out, "\033\02251@%s\033 ", pmap->code[i]);
107            }
108
109            return 1;
110        }
111    }
112
113    return 0;
114}
115
116struct paper_size_map_t {
117    short int width;
118    short int height;
119    const char *name;
120};
121
122static int
123rpdl_set_paper_size_by_size(FILE *out, int width, int height /* in pt */)
124{
125    int w, h;
126    struct paper_size_map_t *pmap;
127    static struct paper_size_map_t paper_size_map[] = {
128        { 1684, 2384, "A1" },
129        { 1191, 1684, "A2" },
130        {  842, 1191, "A3" },
131        {  595,  842, "A4" },
132        {  420,  595, "A5" },
133        {  297,  420, "A6" },
134
135        {  729, 1032, "B4" },
136        {  516,  729, "B5" },
137        {  363,  516, "B6" },
138
139        {  612,  792, "Letter"    },
140        {  612, 1008, "Legal"     },
141        {  396,  612, "Statement" },
142        {  792, 1224, "Ledger"    },
143
144        { -1, -1, NULL },
145    };
146
147    if (width < height) {
148        w = width;
149        h = height;
150    }
151    else {
152        w = height;
153        h = width;
154    }
155
156    for (pmap = paper_size_map; pmap->width > 0; pmap ++) {
157        if (w == pmap->width && h == pmap->height) {
158            return rpdl_set_paper_size_by_name(out, pmap->name);
159        }
160    }
161
162    return 0;
163}
164
165static int
166rpdl_set_paper_size(FILE *out, ppd_file_t *ppd, cups_page_header2_t *header)
167{
168    int r;
169
170    r = 0;
171    if (*(header->cupsPageSizeName)) {
172        r = rpdl_set_paper_size_by_name(out, header->cupsPageSizeName);
173        if (r)
174            return r;
175    }
176
177    r = rpdl_set_paper_size_by_size(out, header->PageSize[0],
178                                          header->PageSize[1]);
179    if (r)
180        return r;
181
182    return rpdl_set_custom_paper_size(out, header->PageSize[0],
183                                           header->PageSize[1]);
184}
185
186static void
187rpdl_set_paper_type(FILE *out, int paper_type)
188{
189    fprintf(out, "\033\022?6T,%d\033 ", paper_type);
190}
191
192static int
193rpdl_set_tray(FILE *out, ppd_file_t *ppd, cups_page_header2_t *header)
194{
195    switch (header->MediaPosition) {
196    case 0:     /* auto */
197        fputs("\033\022Z2 ", out);
198        break;
199    case 1:     /* manual tray */
200        fputs("\033\022Z1 "
201              "\033\031M", out);
202        break;
203    default:    /* tray N */
204        fputs("\033\022Z1 ", out);
205        fprintf(out, "\033\031%d", header->MediaPosition);
206    }
207
208    return 0;
209}
210
211static int
212rpdl_set_paper_tray(FILE *out, ppd_file_t *ppd, cups_page_header2_t *header)
213{
214    int r;
215
216    switch (header->MediaPosition) {
217    case 0:     /* auto */
218        /* paper type can not be specified */
219        break;
220    case 1:     /* manual tray */
221        rpdl_set_paper_type(out, 0);
222        break;
223    default:    /* tray N */
224        /* always 15 */
225        rpdl_set_paper_type(out, 15);
226    }
227
228    r = rpdl_set_tray(out, ppd, header);
229
230    if (header->MediaPosition == 0 /* auto */) {
231        r = rpdl_set_paper_size(out, ppd, header);
232    }
233
234    return 0;
235}
236
237static int
238rpdl_setup_page(FILE *out, ppd_file_t *ppd, cups_page_header2_t *header)
239{
240    if (header->cupsBitsPerColor != 1) {
241        fputs("ERROR: BPC is not 1!\n", stderr);
242        return -1;
243    }
244
245    if (header->cupsColorSpace != CUPS_CSPACE_K) {
246        fputs("ERROR: Color Space is not K!\n", stderr);
247        return -1;
248    }
249
250    if (header->Duplex) {
251        fputs("\033\022YA06,2 ", out);      /* duplex: on */
252
253        if (header->Tumble) {
254            fputs("\033\022YA03,1 ", out);  /* top binding */
255        }
256        else {
257            fputs("\033\022YA03,2 ", out);  /* left binding */
258        }
259            /* right binding is 3 */
260    }
261    else {
262        fputs("\033\022YA06,1 ", out);      /* duplex: off */
263    }
264
265    switch (header->HWResolution[0] /* dpi */) {
266    case 1200:
267        fputs(
268            "\033\022YA04,4 "               /* engine           */
269            "\033\022YW,4 "                 /* graphics unit    */
270            "\033\022YI,9 "                 /* unknown unit     */
271            "\033\022#5 "                   /* cartecian unit   */
272            "\033\022Q6 "                   /* spacing unit     */
273            , out);
274        break;
275    case 600:
276        fputs(
277            "\033\022YA04,3 "               /* engine           */
278            "\033\022YW,3 "                 /* graphics unit    */
279            "\033\022YI,8 "                 /* unknown unit     */
280            "\033\022#4 "                   /* cartecian unit   */
281            "\033\022Q5 "                   /* spacing unit     */
282            , out);
283        break;
284    case 400:
285    default:
286        fputs(
287            "\033\022YA04,1 "               /* engine           */
288            "\033\022YW,1 "                 /* graphics unit    */
289            "\033\022YI,7 "                 /* unknown unit     */
290            "\033\022#2 "                   /* cartecian unit   */
291            "\033\022Q4 "                   /* spacing unit     */
292            , out);
293    }
294
295    switch (header->cupsInteger[1]) {
296    case 2:
297        fputs("\033\022YA02,1 ", out);      /* strong toner save */
298        break;
299    case 1:
300        fputs("\033\022YA02,3 ", out);      /* light toner save */
301        break;
302    default:
303        if (header->cupsInteger[0]) {
304            fputs("\033\022YA02,2 ", out);  /* smoothing on */
305        }
306        else {
307            fputs("\033\022YA02,4 ", out);  /* smoothing off */
308        }
309    }
310
311    fputs(
312        "\033\022YQ,2 "                     /* page length - maximum */
313        "\033\022YB,2 "                     /* printable area - maximum */
314        "\033\022YK,1 "                     /* left margin - 0 mm */
315        "\033\022YL,1 "                     /* top margin  - 0 mm */
316        "\033\022YM,1 "                     /* zoom - 100% */
317        , out);       
318
319    rpdl_set_paper_tray(out, ppd, header);
320
321    if (header->PageSize[0] > header->PageSize[1]) {
322        fputs("\033\022D2 ", out);          /* landscape */
323    }
324    else {
325        fputs("\033\022D1 ", out);          /* portrait */
326    }
327
328    /* number of copies */
329    fprintf(out, "\033\022N%d ", header->NumCopies);
330
331    return 0;
332}
333
334static int
335rpdl_finish(FILE *out, ppd_file_t *ppd, cups_page_header2_t *header)
336{
337    if (header->Duplex) {
338        if (header->Tumble) {   /* in case of top binding */
339            fputs("\033\022YA03,2 ", out);  /* reset to left binding */
340        }
341
342        fputs("\033\022YA06,1 ", out);      /* duplex: off */
343    }
344
345    if (header->MediaPosition != 0 /* auto */) {
346        fputs("\033\022Z2 ", out);          /* tray auto */
347        rpdl_set_paper_size_by_name(out, "A4");
348    }
349
350    return 0;
351}
352
353static int
354runlength_line2(const unsigned char *source, int cb_source,
355                unsigned char *buffer, size_t cb_buffer)
356{
357    const unsigned char *ps, *es;
358    unsigned char *pb, *eb;
359    int c = -1;
360
361    ps = source;
362    es = source + cb_source;
363    pb = buffer;
364    eb = buffer + cb_buffer;
365    while (ps < es) {
366        unsigned char nc;
367        int run;
368
369        if (pb >= eb)
370            return -1;
371
372        nc = *pb ++ = *ps ++;
373
374        if (nc != c) {
375            c = nc;
376            continue;
377        }
378
379        /* begin run */
380        run = 0;
381        while (ps < es && run < 255) {
382            if (*ps != c)
383                break;
384
385            ps ++;
386            run ++;
387        }
388
389        if (pb >= eb)
390            return -1;
391
392        *pb ++ = run;
393        c = -1;
394    }
395
396    return pb - buffer;
397}
398
399static void
400trim_line(const unsigned char *source, int cb_source,
401          int *offset, int *length)
402{
403    const unsigned char *sp, *ep;
404
405    ep = source + cb_source;
406    for (sp = source; sp < ep; sp ++)
407        if (*sp != 0)
408            break;
409
410    for (           ; ep > sp; ep --)
411        if (*(ep - 1) != 0)
412            break;
413
414    *offset = sp - source;
415    *length = ep - sp;
416}
417
418static int
419rpdl_render_line(FILE *out, const unsigned char *line_buf, int cb_line,
420                 int x, int y, int use_compression, int use_trim,
421                 unsigned char *comp_buf, int cb_cbuf)
422{
423    int cb_cdat;
424    int of_trim, cb_trim;
425
426    if (use_trim) {
427        trim_line(line_buf, cb_line, &of_trim, &cb_trim);
428    }
429    else {
430        cb_trim = cb_line;
431        of_trim = 0;
432    }
433
434    if (cb_trim == 0)
435        return 0;
436
437    if (use_compression) {
438        cb_cdat = runlength_line2(line_buf + of_trim, cb_trim, comp_buf,
439                                  cb_cbuf);
440        if (cb_cdat < 0)
441            return -1;
442
443        if (cb_cdat == 0)
444            return 0;
445    }
446
447    if (! use_compression || cb_cdat >= cb_trim) {
448        /* non-effective compression => raw */
449        fprintf(out, "\033\022G3,%d,%d,,,%d,%d@",
450                cb_trim * 8, 1, (x + of_trim * 8) * 1, y * 1);
451
452        fwrite(line_buf + of_trim, 1, cb_trim, out);
453    }
454    else {
455        /* effective compression */
456        fprintf(out, "\033\022G3,%d,%d,,4,%d,%d,%d@",
457                cb_trim * 8, 1, (x + of_trim * 8) * 1, y * 1,
458                cb_cdat);
459
460        fwrite(comp_buf, 1, cb_cdat, out);
461    }
462
463    return 1;
464}
465
466#if 0   /* example */
467static int
468rpdl_render_image(FILE *out, const unsigned char *ptr, int width, int height,
469                  int ox, int oy, int use_compression, int use_trim)
470{
471    int cb_line, cb_cbuf;
472    unsigned char *comp_buf;
473    int y;
474
475    cb_line = (width + 7) / 8;
476
477    cb_cbuf = (cb_line * 3 + 1) / 2;
478    comp_buf = malloc(cb_cbuf);
479    if (! comp_buf)
480        return -1;
481
482    for (y = 0; y < height; y ++) {
483        int r;
484
485        r = rpdl_render_line(out, ptr, cb_line, ox, oy + y, use_compression,
486                             use_trim, comp_buf, cb_cbuf);
487
488        if (r < 0) {
489            fputs("ERROR: buffer is small.\n", stderr);
490            return -1;
491        }
492
493        ptr += cb_line;
494    }
495
496    free(comp_buf);
497
498    return 0;
499}
500#endif
501
502int
503main(int argc, char *argv[])
504{
505    int num_options;
506    cups_option_t *options;
507    FILE *out;
508    int fd;
509    cups_raster_t *ras;
510    ppd_file_t *ppd;
511    cups_page_header2_t header;
512    int page, y;
513    int inited;
514#if ! defined(HAVE_SIGSET) && defined(HAVE_SIGACTION)
515    struct sigaction action;
516#endif
517
518    setbuf(stderr, NULL);
519
520    if (argc < 6 || argc > 7) {
521        _cupsLangPrintf(stderr,
522                        _("Usage: %s job-id user title copies options\n"),
523                        argv[0]);
524
525        return 1;
526    }
527
528    num_options = cupsParseOptions(argv[5], 0, &options);
529
530    ppd = ppdOpenFile(getenv("PPD"));
531
532    if (! ppd) {
533        _cupsLangPuts(stderr, _("ERROR: Unable to open PPD file!\n"));
534        return 1;
535    }
536
537    ppdMarkDefaults(ppd);
538    cupsMarkOptions(ppd, num_options, options);
539
540    if (argc >= 7) {
541        fd = open(argv[6], O_RDONLY);
542        if (fd < 0) {
543            _cupsLangPrintf(stderr,
544                            _("ERROR: Unable to open raster file - %s\n"),
545                            strerror(errno));
546
547            return 1;
548        }
549    }
550    else
551        fd = 0;
552
553    ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
554
555    out = stdout;
556
557    g_canceled = 0;
558
559#if defined(HAVE_SIGSET)
560    sigset(SIGTERM, cancel_job);
561#elif defined(HAVE_SIGACTION)
562    memset(&action, 0, sizeof(action));
563    sigemptyset(&action.sa_mask);
564    action.sa_handler = cancel_job;
565    sigaction(SIGTERM, &action, NULL);
566#else
567    signal(SIGTERM, cancel_job);
568#endif
569
570    rpdl_init(out, ppd);
571
572    inited = 0;
573    page   = 0;
574    while (cupsRasterReadHeader2(ras, &header)) {
575        unsigned char *plane;
576        unsigned char *comp_buf;
577        int cb_cbuf;
578
579        if (g_canceled) break;
580
581        page ++;
582        fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);
583        _cupsLangPrintf(stderr, _("INFO: Starting page %d...\n"), page);
584
585        if (! inited) {
586            rpdl_setup_page(out, ppd, &header);
587
588            inited = 1;
589        }
590
591        plane = malloc(header.cupsBytesPerLine);
592        if (! plane) {
593            g_canceled = 1;
594            break;
595        }
596
597        cb_cbuf = (header.cupsBytesPerLine * 3 + 1) / 2;
598        comp_buf = malloc(cb_cbuf);
599        if (! comp_buf) {
600            if (plane)
601                free(plane);
602
603            g_canceled = 1;
604            break;
605        }
606
607        for (y = 0; y < header.cupsHeight; y ++) {
608            if (g_canceled) break;
609
610            if (cupsRasterReadPixels(ras, plane,
611                                     header.cupsBytesPerLine) < 1) {
612                break;
613            }
614
615            rpdl_render_line(out, plane, header.cupsBytesPerLine, 0, y,
616                             1, 1, comp_buf, cb_cbuf);
617        }
618
619        if (comp_buf)
620            free(comp_buf);
621
622        if (plane)
623            free(plane);
624
625        _cupsLangPrintf(stderr, _("INFO: Finished page %d...\n"), page);
626
627        fputs("\014", out);     /* Form Feed */
628    }
629
630    if (! g_canceled && header.Duplex && page % 2 == 1) {
631        fputs("\014", out);     /* Form Feed */
632    }
633
634    if (inited)
635        rpdl_finish(out, ppd, &header);
636
637    if (ppd)
638        ppdClose(ppd);
639
640    cupsRasterClose(ras);
641
642    if (fd)
643        close(fd);
644
645    if (out != stdout)
646        fclose(out);
647
648    cupsFreeOptions(num_options, options);
649
650    if (page == 0) {
651        _cupsLangPuts(stderr, _("ERROR: No pages found!\n"));
652
653        return 1;
654    }
655    else {
656        _cupsLangPuts(stderr, _("INFO: Ready to print.\n"));
657
658        return 0;
659    }
660}
661
662/* vi: set expandtab ts=4 sw=4 sts=0 : */
Note: See TracBrowser for help on using the browser.