printer: Move some files around, in preparation for more types of printer drivers
[AROS.git] / workbench / printers / postscript / postscript.c
blobaf0adf260ad81b29c5ac26abb6a2e9034ad64c05
1 /*
2 * Copyright (C) 2012, The AROS Development Team. All rights reserved.
3 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
5 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
6 */
8 #include <aros/debug.h>
9 #include <aros/printertag.h>
11 #include <clib/alib_protos.h>
12 #include <devices/printer.h>
13 #include <devices/prtgfx.h>
15 #include <proto/graphics.h>
17 static struct Library *GfxBase;
19 static LONG ps_Init(struct PrinterData *pd);
20 static VOID ps_Expunge(VOID);
21 static LONG ps_Open(union printerIO *ior);
22 static VOID ps_Close(union printerIO *ior);
24 static LONG ps_Render(SIPTR ct, LONG x, LONG y, LONG status);
25 static LONG ps_ConvFunc(UBYTE *buf, UBYTE c, LONG crlf_flag);
26 static LONG ps_DoPreferences(union printerIO *ior, LONG command);
27 static VOID ps_CallErrHook(union printerIO *ior, struct Hook *hook);
28 static LONG ps_DoSpecial(UWORD *command, UBYTE output_buffer[],
29 BYTE *current_line_position,
30 BYTE *current_line_spacing,
31 BYTE *crlf_flag, UBYTE params[]);
33 static struct TagItem PED_TagList[] = {
34 { PRTA_8BitGuns, TRUE }, /* 0 */
35 { PRTA_NewColor, TRUE }, /* 1 */
36 { PRTA_ColorSize, 3 }, /* 2 */
37 { PRTA_NoScaling, TRUE }, /* 3 */
38 { PRTA_MixBWColor, FALSE }, /* 4 */
39 { PRTA_LeftBorder, 0 }, /* 5 */
40 { PRTA_TopBorder, 0 }, /* 6 */
41 { TAG_END }
44 static CONST_STRPTR PED_Commands[] = {
45 "\377", /* 0 aRIS (reset) */
46 "", /* 1 aRIN (initialize) */
47 "\n", /* 2 aIND (linefeed) */
48 "\r\n", /* 3 aNEL (CR/LF) */
49 "\377", /* 4 aRI (reverse LF) */
50 "\377", /* 5 aSGR0 (Courier) */
51 "\377", /* 6 aSGR3 (italics) */
52 "\377", /* 7 aSGR23 (no italics) */
53 "\377", /* 8 aSGR4 (underline) */
54 "\377", /* 9 aSGR24 (no underline) */
55 "\377", /* 10 aSGR1 (boldface) */
56 "\377", /* 11 aSGR21 (no boldface) */
57 "\377", /* 12 aSFC (set text color) */
58 "\377", /* 13 aSBC (set background color) */
59 "\377", /* 14 aSHORP0 (normal pitch) */
60 "\377", /* 15 aSHORP2 (elite) */
61 "\377", /* 16 aSHORP1 (no elite) */
62 "\377", /* 17 aSHORP4 (condensed) */
63 "\377", /* 18 aSHORP3 (no condensed) */
64 "\377", /* 19 aSHORP6 (enlarge) */
65 "\377", /* 20 aSHORT5 (no enlarge) */
66 "\377", /* 21 aDEN6 (shadow) */
67 "\377", /* 22 aDEN5 (no shadow) */
68 "\377", /* 23 aDEN4 (double strike) */
69 "\377", /* 24 aDEN3 (no double strike) */
70 "\377", /* 25 aDEN2 (NLQ) */
71 "\377", /* 26 aDEN1 (no NLQ) */
72 "\377", /* 27 aSUS2 (superscript) */
73 "\377", /* 28 aSUS1 (no superscript) */
74 "\377", /* 29 aSUS4 (subscript) */
75 "\377", /* 30 aSUS3 (no subscript) */
76 "\377", /* 31 aSUS0 (normal) */
77 "\377", /* 32 aPLU (partial line up) */
78 "\377", /* 33 aPLD (partial line down) */
79 "\377", /* 34 aFNT0 (Courier) */
80 "\377", /* 35 aFNT1 (Helvetica) */
81 "\377", /* 36 aFNT2 (Font 2) */
82 "\377", /* 37 aFNT3 (Font 3) */
83 "\377", /* 38 aFNT4 (Font 4) */
84 "\377", /* 39 aFNT5 (Font 5) */
85 "\377", /* 40 aFNT6 (Font 6) */
86 "\377", /* 41 aFNT7 (Font 7) */
87 "\377", /* 42 aFNT8 (Font 8) */
88 "\377", /* 43 aFNT9 (Font 9) */
89 "\377", /* 44 aFNT10 (Font 10) */
90 "\377", /* 45 aPROP2 (proportional) */
91 "\377", /* 46 aPROP1 (no proportional) */
92 "\377", /* 47 aPROP0 (default proportion) */
93 "\377", /* 48 aTSS (set proportional offset) */
94 "\377", /* 49 aJFY5 (left justify) */
95 "\377", /* 50 aJFY7 (right justify) */
96 "\377", /* 51 aJFY6 (full justify) */
97 "\377", /* 52 aJFY0 (no justify) */
98 "\377", /* 53 aJFY3 (letter space) */
99 "\377", /* 54 aJFY1 (word fill) */
100 "\377", /* 55 aVERP0 (1/8" line spacing) */
101 "\377", /* 56 aVERP1 (1/6" line spacing) */
102 "\377", /* 57 aSLPP (form length) */
103 "\377", /* 58 aPERF (skip n perfs) */
104 "\377", /* 59 aPERF0 (no skip perfs) */
105 "\377", /* 60 aLMS (left margin) */
106 "\377", /* 61 aRMS (right margin) */
107 "\377", /* 62 aTMS (top margin) */
108 "\377", /* 63 aBMS (bot margin) */
109 "\377", /* 64 aSTBM (top & bottom margin) */
110 "\377", /* 65 aSLRM (left & right margin) */
111 "\377", /* 66 aCAM (no margins) */
112 "\377", /* 67 aHTS (horizontal tabs) */
113 "\377", /* 68 aVTS (vertical tabs) */
114 "\377", /* 69 aTBC0 (clear horizontal tab) */
115 "\377", /* 70 aTBC3 (clear all horiz. tabs) */
116 "\377", /* 71 aTBC1 (clear vertical tab) */
117 "\377", /* 72 aTBC4 (clear all vertical tabs) */
118 "\377", /* 73 aTBCALL (clear all tabs) */
119 "\377", /* 74 aTBSALL (default tabs) */
120 "\377", /* 75 aEXTEND (extended chars) */
121 "\377", /* 76 aRAW (next N chars are literal) */
124 static CONST_STRPTR PED_8BitChars[] = {
126 " ", /* SPC (160) */
127 "?", /* ! */
128 "?", /* c */
129 "?", /* £ */
130 "?", /* o */
131 "?", /* Y */
132 "|",
133 "?", /* S */
134 "?",
135 "?", /* Copyright */
136 "?", /* a */
137 "?", /* < */
138 "?", /* - */
139 "?", /* SHY */
140 "?", /* R */
141 "?", /* - */
142 "?", /* o (176) */
143 "?", /* +- */
144 "?", /* 2 */
145 "?", /* 3 */
146 "?",
147 "?", /* u */
148 "?", /* P */
149 "?", /* . */
150 "?", /* , */
151 "?", /* 1 */
152 "?", /* o */
153 "?", /* > */
154 "?", /* 1/4 */
155 "?", /* 1/2 */
156 "?", /* 3/4 */
157 "?", /* ? */
158 "?", /* A' (192) */
159 "?", /* A' */
160 "?", /* A^ */
161 "?", /* A~ */
162 "?", /* A: */
163 "?", /* Ao */
164 "?", /* AE */
165 "?", /* C */
166 "?", /* E' */
167 "?", /* E' */
168 "?", /* E^ */
169 "?", /* E: */
170 "?", /* I' */
171 "?", /* I' */
172 "?", /* I^ */
173 "?", /* I: */
174 "?", /* D- (208) */
175 "?", /* N~ */
176 "?", /* O' */
177 "?", /* O' */
178 "?", /* O^ */
179 "?", /* O~ */
180 "?", /* O: */
181 "?", /* x */
182 "?", /* 0 */
183 "?", /* U' */
184 "?", /* U' */
185 "?", /* U^ */
186 "?", /* U: */
187 "?", /* Y' */
188 "?", /* p */
189 "?", /* B */
190 "?", /* a' (224) */
191 "?", /* a' */
192 "?", /* a^ */
193 "?", /* a~ */
194 "?", /* a: */
195 "?", /* ao */
196 "?", /* ae */
197 "?", /* c */
198 "?", /* e' */
199 "?", /* e' */
200 "?", /* e^ */
201 "?", /* e: */
202 "?", /* i' */
203 "?", /* i' */
204 "?", /* i^ */
205 "?", /* i: */
206 "?", /* o (240) */
207 "?", /* n~ */
208 "?", /* o' */
209 "?", /* o' */
210 "?", /* o^ */
211 "?", /* o~ */
212 "?", /* o: */
213 "?", /* / */
214 "?", /* 0 */
215 "?", /* u' */
216 "?", /* u' */
217 "?", /* u^ */
218 "?", /* u: */
219 "?", /* y' */
220 "?", /* p */
221 "?", /* y: */
224 AROS_PRINTER_TAG(PED, 44, 0,
225 .ped_PrinterName = "PostScript",
226 .ped_Init = ps_Init,
227 .ped_Expunge = ps_Expunge,
228 .ped_Open = ps_Open,
229 .ped_Close = ps_Close,
231 /* Settings for a 'graphics only' printer */
232 .ped_PrinterClass = PPC_COLORGFX | PPCF_EXTENDED,
233 .ped_MaxColumns = 0, /* Set during render */
234 .ped_ColorClass = PCC_BGR,
235 .ped_NumCharSets = 2,
236 .ped_NumRows = 1,
237 .ped_MaxXDots = 0, /* Set during render */
238 .ped_MaxYDots = 0, /* Set during render */
239 .ped_XDotsInch = 0, /* Set during render */
240 .ped_YDotsInch = 0, /* Set during render */
241 .ped_Commands = (STRPTR *)PED_Commands, /* No ANSI commands */
242 .ped_DoSpecial = ps_DoSpecial,
243 .ped_Render = ps_Render,
244 .ped_TimeoutSecs = 1000, /* For print-to-file timeouts */
245 .ped_8BitChars = (STRPTR *)PED_8BitChars,
246 .ped_PrintMode = 1,
247 .ped_ConvFunc = ps_ConvFunc,
248 .ped_TagList = &PED_TagList[0],
249 .ped_DoPreferences = ps_DoPreferences,
250 .ped_CallErrHook = ps_CallErrHook,
253 struct PrinterData *PD;
255 static LONG ps_Init(struct PrinterData *pd)
257 D(bug("ps_Init: pd=%p\n", pd));
258 PD = pd;
259 GfxBase = OpenLibrary("graphics.library", 0);
260 return 0;
263 static VOID ps_Expunge(VOID)
265 D(bug("ps_Expunge\n"));
266 PD = NULL;
267 CloseLibrary(GfxBase);
270 static void PWrite(const char *format, ...)
272 va_list args;
273 char state = 0;
274 int len = 0;
275 LONG lval = 0;
276 static char buff_a[16];
277 static char buff_b[16];
278 static char *buff = &buff_a[0];
280 #define PFLUSH() do { \
281 PD->pd_PWrite(buff, len); \
282 if (buff == &buff_a[0]) \
283 buff = &buff_b[0]; \
284 else \
285 buff = &buff_a[0]; \
286 len = 0; \
287 } while (0)
289 #define PUTC(c) do { \
290 buff[len++]=c; \
291 if (len >= 16) PFLUSH(); \
292 } while (0)
294 va_start(args, format);
296 for (; *format; format++) {
297 switch (state) {
298 case 0:
299 if (*format == '%') {
300 state = '%';
301 } else {
302 PUTC(*format);
304 break;
305 case '%':
306 switch (*format) {
307 case 'd':
308 lval = va_arg(args, LONG);
309 if (lval == 0)
310 PUTC('0');
311 else {
312 BYTE out[10];
313 int olen = 0;
314 if (lval < 0) {
315 PUTC('-');
316 lval = -lval;
318 do {
319 out[olen++] = lval % 10;
320 lval /= 10;
321 } while (lval > 0);
322 while (olen--) {
323 PUTC(out[olen] + '0');
326 break;
327 case '%':
328 PUTC('%');
329 break;
330 default:
331 PUTC('?');
332 break;
334 state = 0;
335 break;
336 default:
337 state = 0;
338 break;
342 va_end(args);
344 PFLUSH();
347 static BOOL ps_HeaderSent;
349 static void ps_SendHeader(void)
351 const TEXT header[] =
352 "%%!PS-Adobe-2.0\n"
353 "/Courier findfont 12 scalefont setfont\n"
354 "5 %d moveto gsave\n"
355 "(\\\n";
357 if (!ps_HeaderSent) {
358 PWrite(header, PED->ped_MaxYDots * 72 / PED->ped_YDotsInch - 36);
359 ps_HeaderSent = TRUE;
364 static LONG ps_Open(union printerIO *ior)
366 D(bug("ps_Open: ior=%p\n", ior));
368 ps_HeaderSent = FALSE;
370 return 0;
373 static VOID ps_Close(union printerIO *ior)
375 if (ps_HeaderSent)
376 PWrite(") show showpage grestore\n");
377 D(bug("ps_Close: ior=%p\n", ior));
380 VOID color_get(struct ColorMap *cm,
381 UBYTE *r,
382 UBYTE *g,
383 UBYTE *b,
384 ULONG index)
386 UWORD hibits = ((UWORD *)cm->ColorTable)[index];
388 ULONG red8 = (hibits & 0x0f00) >> 4;
389 ULONG green8 = (hibits & 0x00f0);
390 ULONG blue8 = (hibits & 0x000f) << 4;
392 if (cm->Type > COLORMAP_TYPE_V1_2) {
393 UWORD lobits = ((UWORD *)cm->LowColorBits)[index];
395 red8 |= (lobits & 0x0f00) >> 8;
396 green8 |= (lobits & 0x00f0) >> 4;
397 blue8 |= (lobits & 0x000f);
400 *r = red8;
401 *g = green8;
402 *b = blue8;
405 static LONG ps_PrintBufLen;
407 static LONG ps_RenderInit(struct IODRPReq *io, LONG x, LONG y)
409 D(bug("ps_RenderInit: Dump raster %dx%d pixels, io_RastPort=%p\n", x, y, io->io_RastPort));
410 D(bug("\t@%dx%d (%dx%d) => @%dx%d\n",
411 io->io_SrcX, io->io_SrcY, io->io_SrcWidth,
412 io->io_SrcHeight, io->io_DestCols, io->io_DestRows));
414 ps_SendHeader();
416 ps_PrintBufLen = io->io_SrcWidth;
417 PD->pd_PrintBuf = AllocMem(ps_PrintBufLen * 6, MEMF_ANY);
418 if (PD->pd_PrintBuf == NULL)
419 return PDERR_BUFFERMEMORY;
421 /* Write a postscript colorimage */
422 PWrite(") show grestore gsave\n");
423 PWrite("%d %d translate\n", PD->pd_Preferences.PrintXOffset * PED->ped_XDotsInch / 10 +
424 (PED->ped_MaxXDots - x) / 2,
425 (PED->ped_MaxYDots - y) / 2);
426 PWrite("%d %d scale\n", x, y);
427 PWrite("%d %d 8 [%d 0 0 %d 0 %d]\n",
428 io->io_SrcWidth, io->io_SrcHeight,
429 io->io_SrcWidth, -io->io_SrcHeight, io->io_SrcHeight);
430 PWrite("{<\n");
432 return PDERR_NOERR;
435 static UBYTE tohex(UBYTE val)
437 val &= 0xf;
438 return (val < 10) ? ('0' + val) : ('a' + val - 10);
441 static LONG ps_RenderTransfer(struct PrtInfo *pi, LONG x, LONG y)
443 UBYTE *ptr = PD->pd_PrintBuf;
444 UBYTE *src = (UBYTE *)pi->pi_ColorInt;
445 ptr += (2 * x);
447 for (x = 0; x < ps_PrintBufLen; x++, src += 3, ptr += 6) {
448 int i;
449 for (i = 0; i < 3; i++) {
450 ptr[i*2+0] = tohex(src[2-i]>>4);
451 ptr[i*2+1] = tohex(src[2-i]>>0);
455 return PDERR_NOERR;
458 static LONG ps_RenderFlush(LONG rows)
460 PD->pd_PWrite(PD->pd_PrintBuf, ps_PrintBufLen * 6);
461 PD->pd_PWrite("\n", 1);
462 return PDERR_NOERR;
465 static LONG ps_RenderClear(void)
467 memset(PD->pd_PrintBuf, '0', ps_PrintBufLen * 6);
468 return PDERR_NOERR;
471 static LONG ps_RenderPreInit(struct IODRPReq *io, LONG flags)
473 ULONG dpiX = 0, dpiY = 0;
474 ULONG width, height;
476 /* Select DPI */
477 switch (flags & SPECIAL_DENSITYMASK) {
478 case SPECIAL_DENSITY1:
479 dpiX = 72;
480 dpiY = 72;
481 break;
482 case SPECIAL_DENSITY2:
483 dpiX = 100;
484 dpiY = 100;
485 break;
486 case SPECIAL_DENSITY3:
487 dpiX = 120;
488 dpiY = 120;
489 break;
490 case SPECIAL_DENSITY4:
491 dpiX = 150;
492 dpiY = 150;
493 break;
494 case SPECIAL_DENSITY5:
495 dpiX = 300;
496 dpiY = 300;
497 break;
498 case SPECIAL_DENSITY6:
499 dpiX = 600;
500 dpiY = 600;
501 break;
502 case SPECIAL_DENSITY7:
503 dpiX = 1200;
504 dpiY = 1200;
505 break;
508 /* Set up for the page size */
509 switch (PD->pd_Preferences.PaperSize) {
510 /* PaperSize (in um) */
511 case US_LETTER: width = 2159; height = 2794; break; /* 8.5"x11" */
512 case US_LEGAL: width = 2159; height = 3556; break; /* 8.5"x14" */
513 case N_TRACTOR: width = 2413; height = 2794; break; /* 9.5"x11" */
514 case W_TRACTOR: width = 3774; height = 2794; break; /* 14.86"x11" */
515 /* European sizes */
516 case EURO_A0: width = 8410; height = 11890; break; /* A0: 841 x 1189 */
517 case EURO_A1: width = 5940; height = 8410; break; /* A1: 594 x 841 */
518 case EURO_A2: width = 4200; height = 5940; break; /* A2: 420 x 594 */
519 case EURO_A3: width = 2970; height = 4200; break; /* A3: 297 x 420 */
520 case EURO_A4: width = 2100; height = 2970; break; /* A4: 210 x 297 */
521 case EURO_A5: width = 1480; height = 2100; break; /* A5: 148 x 210 */
522 case EURO_A6: width = 1050; height = 1480; break; /* A6: 105 x 148 */
523 case EURO_A7: width = 740; height = 1050; break; /* A7: 74 x 105 */
524 case EURO_A8: width = 520; height = 740; break; /* A8: 52 x 74 */
525 case CUSTOM: width = PD->pd_Preferences.PrintMaxWidth * 254 / 10;
526 height = PD->pd_Preferences.PrintMaxHeight * 254 / 10;
527 break;
528 default: return PDERR_CANCEL;
531 PED->ped_MaxColumns = width * 10 / 254;
532 PED->ped_XDotsInch = dpiX;
533 PED->ped_YDotsInch = dpiY;
534 PED->ped_MaxXDots = width * dpiX / 254;
535 PED->ped_MaxYDots = height * dpiY / 254;
537 return PDERR_NOERR;
540 static LONG ps_RenderClose(struct IODRPReq *io, ULONG flags)
542 if (ps_PrintBufLen) {
543 PWrite(">}\nfalse 3 colorimage\n");
544 PWrite("grestore (\n");
545 FreeMem(PD->pd_PrintBuf, ps_PrintBufLen * 6);
546 PD->pd_PrintBuf=NULL;
547 ps_PrintBufLen=0;
550 return PDERR_NOERR;
554 static LONG ps_Render(SIPTR ct, LONG x, LONG y, LONG status)
556 LONG err = PDERR_NOERR;
558 switch (status) {
559 case PRS_INIT:
560 D(bug("PRS_INIT: ct=%p, x=%d, y=%d\n", ct, x, y));
561 err = ps_RenderInit((struct IODRPReq *)ct, x, y);
562 break;
563 case PRS_TRANSFER:
564 D(bug("PRS_TRANSFER: ct=%p, x=%d, y=%d\n", ct, x, y));
565 err = ps_RenderTransfer((struct PrtInfo *)ct, x, y);
566 break;
567 case PRS_FLUSH:
568 D(bug("PRS_FLUSH: ct=%p, x=%d, y=%d\n", ct, x, y));
569 err = ps_RenderFlush(y);
570 break;
571 case PRS_CLEAR:
572 D(bug("PRS_CLEAR: ct=%p, x=%d, y=%d\n", ct, x, y));
573 err = ps_RenderClear();
574 break;
575 case PRS_CLOSE:
576 D(bug("PRS_CLOSE: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
577 err = ps_RenderClose((struct IODRPReq *)ct, x);
578 break;
579 case PRS_PREINIT:
580 D(bug("PRS_PREINIT: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
581 err = ps_RenderPreInit((struct IODRPReq *)ct, x);
582 break;
583 case PRS_CONVERT:
584 D(bug("PRS_CONVERT: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
585 err = PDERR_NOERR;
586 break;
587 case PRS_CORRECT:
588 D(bug("PRS_CORRECT: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
589 err = PDERR_NOERR;
590 break;
591 default:
592 D(bug("PRS_xxxx(%d): ct=%p, x=0x%0x, y=%d\n", status, ct, x, y));
593 err = PDERR_CANCEL;
594 break;
597 return err;
600 /* Text output */
601 static LONG ps_DoSpecial(UWORD *command, UBYTE output_buffer[],
602 BYTE *current_line_position,
603 BYTE *current_line_spacing,
604 BYTE *crlf_flag, UBYTE params[])
606 D(bug("ps_DoSpecial: command=0x%04x, output_buffer=%p, current_line_position=%d, current_line_spacing=%d, crlf_flag=%d, params=%s\n",
607 *command, output_buffer, *current_line_position, *current_line_spacing, *crlf_flag, params));
609 if (*command == aRIN) {
610 ps_SendHeader();
613 if (*command == aRIS) {
614 PD->pd_PWaitEnabled = '\375';
617 if (*command == aIND) {
618 strcpy(output_buffer, "\\\n) show\n"
619 /* Get current point => x=5, y=currentline */
620 "currentpoint exch pop 5 exch moveto\n"
621 "(\\\n");
622 return strlen(output_buffer);
625 if (*command == aNEL) {
626 strcpy(output_buffer, "\\\n) show\n"
627 /* Get current point => x=5, y=currentline-11 */
628 "currentpoint exch pop 5 exch 11 sub moveto\n"
629 "(\\\n");
630 return strlen(output_buffer);
634 return -1;
637 static LONG ps_ConvFunc(UBYTE *buf, UBYTE c, LONG crlf_flag)
639 D(bug("ps_ConvFunc: %p '%c' %d\n", buf, c, crlf_flag));
641 if (c < 0x1f || c > 0x7f)
642 return -1;
644 if (c == '(' || c == ')') {
645 *(buf++) = '\\';
646 *(buf++) = c;
647 *(buf++) = 0;
648 return 2;
651 if (c >= ' ' && c < 127) {
652 *(buf++) = c;
653 *(buf++) = 0;
654 return 1;
657 *(buf++) = '\\';
658 *(buf++) = ((c >> 6) & 7) + '0';
659 *(buf++) = ((c >> 3) & 7) + '0';
660 *(buf++) = ((c >> 0) & 7) + '0';
661 *(buf++) = 0;
662 return 4;
665 static LONG ps_DoPreferences(union printerIO *ior, LONG command)
667 D(bug("ps_DoPreferences: ior=%p, command=%d\n"));
668 return 0;
671 static VOID ps_CallErrHook(union printerIO *ior, struct Hook *hook)
673 D(bug("ps_CallErrHook: ior=%p, hook=%p\n", ior, hook));