revert between 56095 -> 55830 in arch
[AROS.git] / workbench / printers / postscript / postscript.c
blobc85042092295e945a5694df81b2055e77b234222
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 #define DEBUG 0
9 #include <aros/debug.h>
10 #include <aros/printertag.h>
12 #include <clib/alib_protos.h>
13 #include <devices/printer.h>
14 #include <devices/prtgfx.h>
15 #include <prefs/printergfx.h>
16 #include <prefs/printertxt.h>
17 #include <exec/rawfmt.h>
19 #include <proto/exec.h>
20 #include <proto/graphics.h>
22 #define PS_NOSCALING TRUE /* Do all scaling in PostScript, not in printer.device */
23 #define PS_RGB TRUE /* RGB or CMYK printing */
26 /* Support binary compatability with AOS */
27 #ifdef __mc68000
28 #undef RAWFMTFUNC_STRING
29 #define RAWFMTFUNC_STRING (VOID (*)())"\x16\xC0\x4E\x75"
30 #endif
32 static LONG ps_Init(struct PrinterData *pd);
33 static VOID ps_Expunge(VOID);
34 static LONG ps_Open(union printerIO *ior);
35 static VOID ps_Close(union printerIO *ior);
37 static LONG ps_Render(SIPTR ct, LONG x, LONG y, LONG status);
38 static LONG ps_ConvFunc(UBYTE *buf, UBYTE c, LONG crlf_flag);
39 static LONG ps_DoPreferences(union printerIO *ior, LONG command);
40 static VOID ps_CallErrHook(union printerIO *ior, struct Hook *hook);
41 static LONG ps_DoSpecial(UWORD *command, UBYTE output_buffer[],
42 BYTE *current_line_position,
43 BYTE *current_line_spacing,
44 BYTE *crlf_flag, UBYTE params[]);
46 static CONST_STRPTR PED_Commands[] = {
47 "\377", /* 0 aRIS (reset) */
48 "\377\377", /* 1 aRIN (initialize) */
49 ") aSHOW aIND (", /* 2 aIND (linefeed) */
50 ") aSHOW aNEL (", /* 3 aNEL (CR/LF) */
51 "\377", /* 4 aRI (reverse LF) */
52 ") aSHOW aSGR0 (", /* 5 aSGR0 (Courier) */
53 ") aSHOW aSGR3 (", /* 6 aSGR3 (italics) */
54 ") aSHOW aSGR23 (", /* 7 aSGR23 (no italics) */
55 ") aSHOW aSGR4 (", /* 8 aSGR4 (underline) */
56 ") aSHOW aSGR24 (", /* 9 aSGR24 (no underline) */
57 ") aSHOW aSGR1 (", /* 10 aSGR1 (boldface) */
58 ") aSHOW aSGR22 (", /* 11 aSGR22 (no boldface) */
59 "\377", /* 12 aSFC (set text color) */
60 "\377", /* 13 aSBC (set background color) */
61 ") aSHOW aSHORP0 (", /* 14 aSHORP0 (normal pitch) */
62 ") aSHOW aSHORP2 (", /* 15 aSHORP2 (elite) */
63 ") aSHOW aSHORP1 (", /* 16 aSHORP1 (no elite) */
64 ") aSHOW aSHORP4 (", /* 17 aSHORP4 (condensed) */
65 ") aSHOW aSHORP3 (", /* 18 aSHORP3 (no condensed) */
66 ") aSHOW aSHORP6 (", /* 19 aSHORP6 (enlarge) */
67 ") aSHOW aSHORP5 (", /* 20 aSHORT5 (no enlarge) */
68 ") aSHOW aDEN6 (", /* 21 aDEN6 (shadow) */
69 ") aSHOW aDEN5 (", /* 22 aDEN5 (no shadow) */
70 ") aSHOW aDEN4 (", /* 23 aDEN4 (double strike) */
71 ") aSHOW aDEN3 (", /* 24 aDEN3 (no double strike) */
72 ") aSHOW aDEN2 (", /* 25 aDEN2 (NLQ) */
73 ") aSHOW aDEN1 (", /* 26 aDEN1 (no NLQ) */
74 ") aSHOW aSUS2 (", /* 27 aSUS2 (superscript) */
75 ") aSHOW aSUS1 (", /* 28 aSUS1 (no superscript) */
76 ") aSHOW aSUS4 (", /* 29 aSUS4 (subscript) */
77 ") aSHOW aSUS3 (", /* 30 aSUS3 (no subscript) */
78 ") aSHOW aSUS0 (", /* 31 aSUS0 (normal) */
79 ") aSHOW aPLU (", /* 32 aPLU (partial line up) */
80 ") aSHOW aPLD (", /* 33 aPLD (partial line down) */
81 ") aSHOW aFNT0 (", /* 34 aFNT0 (Courier) */
82 ") aSHOW aFNT1 (", /* 35 aFNT1 (Helvetica) */
83 ") aSHOW aFNT2 (", /* 36 aFNT2 (Font 2) */
84 ") aSHOW aFNT3 (", /* 37 aFNT3 (Font 3) */
85 ") aSHOW aFNT4 (", /* 38 aFNT4 (Font 4) */
86 ") aSHOW aFNT5 (", /* 39 aFNT5 (Font 5) */
87 ") aSHOW aFNT6 (", /* 40 aFNT6 (Font 6) */
88 ") aSHOW aFNT7 (", /* 41 aFNT7 (Font 7) */
89 ") aSHOW aFNT8 (", /* 42 aFNT8 (Font 8) */
90 ") aSHOW aFNT9 (", /* 43 aFNT9 (Font 9) */
91 ") aSHOW aFNT10 (", /* 44 aFNT10 (Font 10) */
92 ") aSHOW aPROP2 (", /* 45 aPROP2 (proportional) */
93 ") aSHOW aPROP1 (", /* 46 aPROP1 (no proportional) */
94 ") aSHOW aPROP0 (", /* 47 aPROP0 (default proportion) */
95 "\377", /* 48 aTSS (set proportional offset) */
96 ") aSHOW aJFY5 (", /* 49 aJFY5 (left justify) */
97 ") aSHOW aJFY7 (", /* 50 aJFY7 (right justify) */
98 ") aSHOW aJFY6 (", /* 51 aJFY6 (full justify) */
99 ") aSHOW aJFY0 (", /* 52 aJFY0 (no justify) */
100 ") aSHOW aJFY3 (", /* 53 aJFY3 (letter space) */
101 ") aSHOW aJFY1 (", /* 54 aJFY1 (word fill) */
102 ") aSHOW aVERP0 (", /* 55 aVERP0 (1/8" line spacing) */
103 ") aSHOW aVERP1 (", /* 56 aVERP1 (1/6" line spacing) */
104 "\377", /* 57 aSLPP (form length) */
105 "\377", /* 58 aPERF (skip n perfs) */
106 "\377", /* 59 aPERF0 (no skip perfs) */
107 "\377", /* 60 aLMS (left margin) */
108 "\377", /* 61 aRMS (right margin) */
109 "\377", /* 62 aTMS (top margin) */
110 "\377", /* 63 aBMS (bot margin) */
111 "\377", /* 64 aSTBM (top & bottom margin) */
112 "\377", /* 65 aSLRM (left & right margin) */
113 "\377", /* 66 aCAM (no margins) */
114 "\377", /* 67 aHTS (horizontal tabs) */
115 "\377", /* 68 aVTS (vertical tabs) */
116 "\377", /* 69 aTBC0 (clear horizontal tab) */
117 "\377", /* 70 aTBC3 (clear all horiz. tabs) */
118 "\377", /* 71 aTBC1 (clear vertical tab) */
119 "\377", /* 72 aTBC4 (clear all vertical tabs) */
120 "\377", /* 73 aTBCALL (clear all tabs) */
121 "\377", /* 74 aTBSALL (default tabs) */
122 "\377", /* 75 aEXTEND (extended chars) */
123 "\377", /* 76 aRAW (next N chars are literal) */
126 static CONST_STRPTR PED_8BitChars[] = {
128 " ", /* SPC (160) */
129 "?", /* ! */
130 "?", /* c */
131 "?", /* £ */
132 "?", /* o */
133 "?", /* Y */
134 "|",
135 "?", /* S */
136 "?",
137 "?", /* Copyright */
138 "?", /* a */
139 "?", /* < */
140 "?", /* - */
141 "?", /* SHY */
142 "?", /* R */
143 "?", /* - */
144 "?", /* o (176) */
145 "?", /* +- */
146 "?", /* 2 */
147 "?", /* 3 */
148 "?",
149 "?", /* u */
150 "?", /* P */
151 "?", /* . */
152 "?", /* , */
153 "?", /* 1 */
154 "?", /* o */
155 "?", /* > */
156 "?", /* 1/4 */
157 "?", /* 1/2 */
158 "?", /* 3/4 */
159 "?", /* ? */
160 "?", /* A' (192) */
161 "?", /* A' */
162 "?", /* A^ */
163 "?", /* A~ */
164 "?", /* A: */
165 "?", /* Ao */
166 "?", /* AE */
167 "?", /* C */
168 "?", /* E' */
169 "?", /* E' */
170 "?", /* E^ */
171 "?", /* E: */
172 "?", /* I' */
173 "?", /* I' */
174 "?", /* I^ */
175 "?", /* I: */
176 "?", /* D- (208) */
177 "?", /* N~ */
178 "?", /* O' */
179 "?", /* O' */
180 "?", /* O^ */
181 "?", /* O~ */
182 "?", /* O: */
183 "?", /* x */
184 "?", /* 0 */
185 "?", /* U' */
186 "?", /* U' */
187 "?", /* U^ */
188 "?", /* U: */
189 "?", /* Y' */
190 "?", /* p */
191 "?", /* B */
192 "?", /* a' (224) */
193 "?", /* a' */
194 "?", /* a^ */
195 "?", /* a~ */
196 "?", /* a: */
197 "?", /* ao */
198 "?", /* ae */
199 "?", /* c */
200 "?", /* e' */
201 "?", /* e' */
202 "?", /* e^ */
203 "?", /* e: */
204 "?", /* i' */
205 "?", /* i' */
206 "?", /* i^ */
207 "?", /* i: */
208 "?", /* o (240) */
209 "?", /* n~ */
210 "?", /* o' */
211 "?", /* o' */
212 "?", /* o^ */
213 "?", /* o~ */
214 "?", /* o: */
215 "?", /* / */
216 "?", /* 0 */
217 "?", /* u' */
218 "?", /* u' */
219 "?", /* u^ */
220 "?", /* u: */
221 "?", /* y' */
222 "?", /* p */
223 "?", /* y: */
226 static struct TagItem PED_TagList[] = {
227 { PRTA_8BitGuns, TRUE }, /* 0 */
228 { PRTA_FloydDithering, TRUE }, /* 1 */
229 { PRTA_MixBWColor, TRUE }, /* 2 */
230 { PRTA_LeftBorder, 0 }, /* 3 */
231 { PRTA_TopBorder, 0 }, /* 4 */
232 { PRTA_NoScaling, PS_NOSCALING },
233 { TAG_END }
236 AROS_PRINTER_TAG(PED, 44, 0,
237 .ped_PrinterName = "PostScript",
238 .ped_Init = ps_Init,
239 .ped_Expunge = ps_Expunge,
240 .ped_Open = ps_Open,
241 .ped_Close = ps_Close,
243 /* Settings for a 'graphics only' printer */
244 .ped_PrinterClass = PPC_COLORGFX | PPCF_EXTENDED,
245 .ped_MaxColumns = 0, /* Set during render */
246 .ped_ColorClass = (PS_RGB ? PCC_BGR : PCC_YMCB),
247 .ped_NumCharSets = 2,
248 .ped_NumRows = 1, /* minimum pixels/row in gfx mode */
249 .ped_MaxXDots = 0, /* Set during render */
250 .ped_MaxYDots = 0, /* Set during render */
251 .ped_XDotsInch = 0, /* Set during render */
252 .ped_YDotsInch = 0, /* Set during render */
253 .ped_Commands = (STRPTR *)PED_Commands, /* No ANSI commands */
254 .ped_DoSpecial = ps_DoSpecial,
255 .ped_Render = ps_Render,
256 .ped_TimeoutSecs = 1000, /* For print-to-file timeouts */
257 .ped_8BitChars = (STRPTR *)PED_8BitChars,
258 .ped_PrintMode = 1,
259 .ped_ConvFunc = ps_ConvFunc,
260 .ped_TagList = &PED_TagList[0],
261 .ped_DoPreferences = ps_DoPreferences,
262 .ped_CallErrHook = ps_CallErrHook,
265 struct PrinterData *PD;
266 static LONG ps_PageID;
267 static BOOL ps_HeaderSent;
268 static CONST_STRPTR ps_PaperSize;
269 static LONG ps_PrintBufLen;
270 static LONG ps_SpacingLPI;
271 static LONG ps_FontCPI;
272 static UWORD ps_PrintShade;
274 struct ExecBase *SysBase;
276 static LONG ps_Init(struct PrinterData *pd)
278 SysBase = pd->pd_Device.dd_ExecBase;
280 D(bug("ps_Init: pd=%p\n", pd));
281 PD = pd;
282 return 0;
285 static VOID ps_Expunge(VOID)
287 D(bug("ps_Expunge\n"));
288 PD = NULL;
291 static struct {
292 char buff_a[16];
293 char buff_b[16];
294 char *buff;
295 int len;
296 } ps_PState = {
297 .buff = &ps_PState.buff_a[0]
300 #define PFLUSH() do { \
301 PD->pd_PWrite(ps_PState.buff, ps_PState.len); \
302 if (ps_PState.buff == &ps_PState.buff_a[0]) \
303 ps_PState.buff = &ps_PState.buff_b[0]; \
304 else \
305 ps_PState.buff = &ps_PState.buff_a[0]; \
306 ps_PState.len = 0; \
307 } while (0)
310 static AROS_UFH2(void, ps_PPutC,
311 AROS_UFHA(UBYTE, c, D0),
312 AROS_UFHA(APTR, dummy, A3))
314 AROS_USERFUNC_INIT
316 /* Ignore the trailing 0 that RawDoFmt() tacks on the end */
317 if (c == 0)
318 return;
320 ps_PState.buff[ps_PState.len++]=c;
321 if (ps_PState.len >= 16)
322 PFLUSH();
324 AROS_USERFUNC_EXIT
327 static inline void ps_PWrite(const char *fmt, ...)
329 AROS_SLOWSTACKFORMAT_PRE(fmt);
330 RawDoFmt(fmt, AROS_SLOWSTACKFORMAT_ARG(fmt), (VOID_FUNC)ps_PPutC, NULL);
331 AROS_SLOWSTACKFORMAT_POST(fmt);
332 PFLUSH();
335 #ifdef __mc68000
336 #define STRING_FUNC (VOID (*)())"\x16\xC0\x4E\x75"
337 #else
338 #define STRING_FUNC RAWFMTFUNC_STRING
339 #endif
341 static inline void ps_VWrite(char *buf, const char *fmt, ...)
343 AROS_SLOWSTACKFORMAT_PRE(fmt);
344 RawDoFmt(fmt, AROS_SLOWSTACKFORMAT_ARG(fmt), STRING_FUNC, buf);
345 AROS_SLOWSTACKFORMAT_POST(fmt);
348 CONST TEXT ps_PageHeader[] =
349 "%s\n" /* Optional formfeed */
350 "%%%%Page: %ld %ld\n"
351 "%%%%BeginPageSetup\n"
352 "%%%%PageOrientation: %s\n"
353 "%%%%PageMedia: %s\n"
354 "%%%%PageBoundingBox: %ld %ld %ld %ld\n"
355 "%%%%EndPageSetup\n"
356 "aFB (\\\n"
359 static void ps_VSendPage(char *buff, BOOL formfeed)
361 ps_VWrite(buff, ps_PageHeader, formfeed ? ") aSHOW aFF" : "",
362 ps_PageID, ps_PageID,
363 /* Aspect */
364 PD->pd_Preferences.PrintAspect ? "Landscape" : "Portrait",
365 /* Media */
366 ps_PaperSize,
367 /* BoundingBox */
368 0, 0,
369 PED->ped_MaxXDots * 72 / PED->ped_XDotsInch,
370 PED->ped_MaxYDots * 72 / PED->ped_YDotsInch
373 ps_PageID++;
376 static void ps_SendPage(BOOL formfeed)
378 ps_PWrite(ps_PageHeader, formfeed ? ") aSHOW aFF" : "",
379 ps_PageID, ps_PageID,
380 /* Aspect */
381 PD->pd_Preferences.PrintAspect ? "Landscape" : "Portrait",
382 /* Media */
383 ps_PaperSize,
384 /* BoundingBox */
385 0, 0,
386 PED->ped_MaxXDots * 72 / PED->ped_XDotsInch,
387 PED->ped_MaxYDots * 72 / PED->ped_YDotsInch
390 ps_PageID++;
393 static void ps_SendHeader(void)
395 const TEXT header[] =
396 "%%!PS-Adobe-2.0\n"
397 "%%%%Creator: AROS PostScript %ld.%ld (printer.device)\n"
398 "%%%%BoundingBox: %ld %ld %ld %ld\n"
399 "%%%%DocumentData: Clean7Bit\n"
400 "%%%%LanguageLevel: 2\n"
401 "%%%%DocumentMedia: %s %ld %ld 0 () ()\n"
402 "%%%%EndComments\n"
403 "%%%%BeginProlog\n"
404 /* (ypixels * 72 / ydpi) - (72 / 4) [1/4 inch] */
405 "/Page_Top %ld 72 mul %ld div 72 4 div sub def\n"
406 /* 12 * left-margin-chars */
407 "/Page_Left 12 %ld mul def\n"
408 "/aFB { gsave Font_CPI setFont Page_Left Page_Top moveto } bind def\n"
409 "/aFF { grestore showpage } bind def\n"
410 "/aImageBW {\n"
411 " /aImage_H exch def /aImage_W exch def\n"
412 " aImage_W aImage_H 1\n"
413 " [ aImage_W 0 0 aImage_H neg 0 aImage_H ]\n"
414 " { currentfile aImage_W 7 add 8 div cvi string readhexstring pop} bind\n"
415 " image\n"
416 "} bind def\n"
417 "/aImageGreyscale {\n"
418 " /aImage_H exch def /aImage_W exch def\n"
419 " aImage_W aImage_H 8\n"
420 " [ aImage_W 0 0 aImage_H neg 0 aImage_H ]\n"
421 " { currentfile aImage_W string readhexstring pop} bind\n"
422 " image\n"
423 "} bind def\n"
424 "/aImageColorRGB {\n"
425 " /aImage_H exch def /aImage_W exch def\n"
426 " aImage_W aImage_H 8\n"
427 " [ aImage_W 0 0 aImage_H neg 0 aImage_H ]\n"
428 " { currentfile aImage_W 3 mul string readhexstring pop} bind %% RGB\n"
429 " false 3 colorimage %% Single-pass \n"
430 "} bind def\n"
431 "/aImageColorCMYK {\n"
432 " /aImage_H exch def /aImage_W exch def\n"
433 " aImage_W aImage_H 8\n"
434 " [ aImage_W 0 0 aImage_H -1 mul 0 aImage_H ]\n"
435 " { currentfile aImage_W 4 mul string readhexstring pop} bind %% CMYK\n"
436 " false 4 colorimage %%\n"
437 "} bind def\n"
438 "\n"
439 "/setFont { Font_Name findfont 1200 Font_CPI div scalefont setfont } bind def\n"
440 "/Spacing { 72 Spacing_LPI div } bind def\n"
441 "/Font_Name { \n"
442 " Font_P {\n"
443 " Font_I { \n"
444 " Font_B { /Helvetica-BoldOblique } { /Courier-Oblique } ifelse\n"
445 " } { \n"
446 " Font_B { /Helvetica-Bold } { /Courier } ifelse\n"
447 " } ifelse\n"
448 " } {\n"
449 " Font_I { \n"
450 " Font_B { /Courier-BoldOblique } { /Courier-Oblique } ifelse\n"
451 " } { \n"
452 " Font_B { /Courier-Bold } { /Courier } ifelse\n"
453 " } ifelse\n"
454 " } ifelse\n"
455 " } bind def\n"
456 "/Font_CPIDefault %ld def\n"
457 "/Spacing_LPIDefault %ld def\n"
458 "/Font_CPI Font_CPIDefault def\n"
459 "/Font_P false def\n"
460 "/Font_U false def\n"
461 "/Font_B false def\n"
462 "/Font_I false def\n"
463 "/Font_Bg [ 1 1 1 ] def\n"
464 "/Font_Fg [ 0 0 0 ] def\n"
465 "/Spacing_LPI Spacing_LPIDefault def\n"
466 "/aSHOW { \n"
467 " gsave Font_Bg aload pop setrgbcolor \n"
468 " 0 -2 rmoveto dup stringwidth pop dup 0 rlineto\n"
469 " 0 Spacing 2 sub rlineto neg 0 rlineto closepath fill\n"
470 " grestore\n"
471 " Font_U { gsave 0 -2 rmoveto dup stringwidth rlineto 0.3 setlinewidth stroke grestore } if\n"
472 " Font_Fg aload pop setrgbcolor\n"
473 " show } bind def\n"
474 "%% Commands\n"
475 "/aNEL { currentpoint exch pop Page_Left exch Spacing sub dup 0 lt { pop pop aFF aFB } { moveto } ifelse } bind def\n"
476 "/aIND { currentpoint exch pop Page_Left exch moveto } bind def\n"
477 "/aSGR0 { /Font_Fg [ 0 0 0 ] def /Font_Bg [ 1 1 1 ] def /Font_U false def /Font_B false def /Font_I false def Font_CPI setFont } bind def\n"
478 "/aSGR3 { /Font_I true def setFont } bind def\n"
479 "/aSGR23 { /Font_I false def setFont } bind def\n"
480 "/aSGR4 { /Font_U true def setFont } bind def\n"
481 "/aSGR24 { /Font_U false def setFont } bind def\n"
482 "/aSGR1 { /Font_B true def setFont } bind def\n"
483 "/aSGR22 { /Font_B false def setFont } bind def\n"
484 "/aColor { [ [ 0 0 0 ] [ 1 0 0 ] [ 0 1 0] [ 1 1 0] [ 0 0 1] [ 0.3 0.3 0.3] [0 1 1] [0.7 0.7 0.7] [ 0 0 0 ] [ 0 0 0 ] ] exch get } bind def\n"
485 "/aSFC { aColor /Font_Fg exch def } bind def\n"
486 "/aSBC { aColor /Font_Bg exch def } bind def\n"
487 "/aSHORP0 { /Font_CPI Font_CPIDefault def setFont } bind def\n"
488 "/aSHORP1 { /Font_CPI Font_CPIDefault def setFont } bind def\n"
489 "/aSHORP2 { /Font_CPI 120 def setFont } bind def\n"
490 "/aSHORP3 { /Font_CPI Font_CPIDefault def setFont } bind def\n"
491 "/aSHORP4 { /Font_CPI 171 def setFont } bind def\n"
492 "/aSHORP5 { /Font_CPI Font_CPIDefault def setFont } bind def\n"
493 "/aSHORP6 { /Font_CPI 100 def setFont } bind def\n"
494 "/aDEN6 { } bind def\n"
495 "/aDEN5 { } bind def\n"
496 "/aDEN4 { } bind def\n"
497 "/aDEN3 { } bind def\n"
498 "/aDEN2 { } bind def\n"
499 "/aDEN1 { } bind def\n"
500 "/aSUS2 { } bind def\n"
501 "/aSUS1 { } bind def\n"
502 "/aSUS4 { } bind def\n"
503 "/aSUS3 { } bind def\n"
504 "/aSUS0 { } bind def\n"
505 "/aPLU { } bind def\n"
506 "/aPLD { } bind def\n"
507 "/aFNT0 { } bind def\n"
508 "/aFNT1 { } bind def\n"
509 "/aFNT2 { } bind def\n"
510 "/aFNT3 { } bind def\n"
511 "/aFNT4 { } bind def\n"
512 "/aFNT5 { } bind def\n"
513 "/aFNT6 { } bind def\n"
514 "/aFNT7 { } bind def\n"
515 "/aFNT8 { } bind def\n"
516 "/aFNT9 { } bind def\n"
517 "/aFNT10 { } bind def\n"
518 "/aPROP2 { /Font_P true def } bind def\n"
519 "/aPROP1 { /Font_P false def } bind def\n"
520 "/aPROP0 { /Font_P false def } bind def\n"
521 "/aJFY5 { } bind def\n"
522 "/aJFY7 { } bind def\n"
523 "/aJFY6 { } bind def\n"
524 "/aJFY0 { } bind def\n"
525 "/aJFY3 { } bind def\n"
526 "/aJFY1 { } bind def\n"
527 "/aVERP0 { /Spacing_LPI 8 def } bind def\n"
528 "/aVERP1 { /Spacing_LPI 6 def } bind def\n"
529 "%%%%EndProlog\n"
532 if (!ps_HeaderSent) {
533 ps_PWrite(header,
534 __pmh.pmh_Version,
535 __pmh.pmh_Revision,
536 /* BoundingBox */
537 0, 0,
538 PED->ped_MaxXDots * 72 / PED->ped_XDotsInch,
539 PED->ped_MaxYDots * 72 / PED->ped_YDotsInch,
540 /* DocumentMedia */
541 ps_PaperSize,
542 PED->ped_MaxXDots * 72 / PED->ped_XDotsInch,
543 PED->ped_MaxYDots * 72 / PED->ped_YDotsInch,
544 /* Margin - assuming average font width is 1/2 its height*/
545 PED->ped_MaxYDots, PED->ped_YDotsInch,
546 PD->pd_Preferences.PrintLeftMargin,
547 ps_FontCPI,
548 ps_SpacingLPI);
550 ps_PageID = 1;
551 ps_HeaderSent = TRUE;
552 ps_SendPage(FALSE);
556 static LONG ps_Open(union printerIO *ior)
558 D(bug("ps_Open: ior=%p\n", ior));
560 ps_HeaderSent = FALSE;
562 return 0;
565 static VOID ps_Close(union printerIO *ior)
567 if (ps_HeaderSent) {
568 ps_PWrite(") aSHOW aFF\n"
569 "%%%%Trailer\n"
570 "%%%%EOF\n");
572 D(bug("ps_Close: ior=%p\n", ior));
575 VOID color_get(struct ColorMap *cm,
576 UBYTE *r,
577 UBYTE *g,
578 UBYTE *b,
579 ULONG index)
581 UWORD hibits = ((UWORD *)cm->ColorTable)[index];
583 ULONG red8 = (hibits & 0x0f00) >> 4;
584 ULONG green8 = (hibits & 0x00f0);
585 ULONG blue8 = (hibits & 0x000f) << 4;
587 if (cm->Type > COLORMAP_TYPE_V1_2) {
588 UWORD lobits = ((UWORD *)cm->LowColorBits)[index];
590 red8 |= (lobits & 0x0f00) >> 8;
591 green8 |= (lobits & 0x00f0) >> 4;
592 blue8 |= (lobits & 0x000f);
595 *r = red8;
596 *g = green8;
597 *b = blue8;
600 static LONG ps_RenderInit(struct IODRPReq *io, LONG width, LONG height)
602 D(bug("ps_RenderInit: Dump raster %ldx%ld pixels, io_RastPort=%p\n", width, height, io->io_RastPort));
603 D(bug("\t@%ldx%ld (%ldx%ld) => @%ldx%ld\n",
604 io->io_SrcX, io->io_SrcY, io->io_SrcWidth,
605 io->io_SrcHeight, io->io_DestCols, io->io_DestRows));
606 LONG alignOffsetX;
607 LONG alignOffsetY;
608 LONG x, y;
610 ps_SendHeader();
612 ps_PrintShade = PD->pd_Preferences.PrintShade;
613 ps_PrintBufLen = PS_NOSCALING ? io->io_SrcWidth : width;
614 PD->pd_PrintBuf = AllocMem(ps_PrintBufLen * 8 + 1, MEMF_ANY);
615 if (PD->pd_PrintBuf == NULL)
616 return PDERR_BUFFERMEMORY;
618 if (PD->pd_Preferences.PrintFlags & PGFF_CENTER_IMAGE) {
619 alignOffsetX = (PED->ped_MaxXDots - width) / 2;
620 alignOffsetY = (PED->ped_MaxYDots - height) / 2;
621 } else {
622 alignOffsetX = 0;
623 alignOffsetY = PED->ped_MaxYDots - height;
626 /* Leave text printing mode */
627 ps_PWrite(") aSHOW grestore gsave\n");
629 /* Move grapics location to (in dots):
630 * x = alignOffsetX
631 * (dots)
632 * y = alignOffsetY
634 x = alignOffsetX;
635 y = alignOffsetY;
637 /* Move text location to (in points):
638 * textx = PageLeft
639 * texty = y * 72 / dpiY - Spacing
641 ps_PWrite("Page_Left %ld 72 mul %ld div Spacing sub moveto\n",
642 y, PED->ped_YDotsInch);
644 /* Save the graphics context - we don't want the scaling & translation
645 * when we return to text context later
647 ps_PWrite("gsave\n");
648 ps_PWrite("%ld %ld div %ld %ld div translate\n",
649 x * 72, PED->ped_XDotsInch,
650 y * 72, PED->ped_YDotsInch);
651 ps_PWrite("%ld %ld div %ld %ld div scale\n", width * 72, PED->ped_XDotsInch, height * 72, PED->ped_YDotsInch);
653 if (PS_NOSCALING) {
654 width = io->io_SrcWidth;
655 height = io->io_SrcHeight;
658 ps_PWrite("%ld %ld ", width, height);
660 switch (ps_PrintShade) {
661 case SHADE_BW:
662 ps_PWrite("aImageBW\n");
663 break;
664 case SHADE_GREYSCALE:
665 ps_PWrite("aImageGreyscale\n");
666 break;
667 case SHADE_COLOR:
668 if (PS_RGB) {
669 ps_PWrite("aImageColorRGB\n");
670 } else {
671 ps_PWrite("aImageColorCMYK\n");
673 break;
676 return PDERR_NOERR;
679 static UBYTE tohex(UBYTE val)
681 val &= 0xf;
682 return (val < 10) ? ('0' + val) : ('a' + val - 10);
685 static LONG ps_RenderTransfer(struct PrtInfo *pi, LONG cindex, LONG y)
687 UBYTE *ptr = PD->pd_PrintBuf;
688 union colorEntry *src = pi->pi_ColorInt;
689 int x;
690 int const rgb[3] = { PCMRED, PCMGREEN, PCMBLUE };
691 int const cmyk[4] = { PCMCYAN, PCMMAGENTA, PCMYELLOW, PCMBLACK };
692 UBYTE color = 0;
693 UBYTE threshold = (PD->pd_Preferences.PrintThreshold & 0xf) * 0x11;
695 for (x = 0; x < ps_PrintBufLen; x++, src++) {
696 int i;
698 switch (ps_PrintShade) {
699 case SHADE_BW:
700 color <<= 1;
701 if (PS_RGB)
702 color |= (src->colorByte[PCMWHITE] >= threshold) ? 1 : 0;
703 else
704 color |= ((255 - src->colorByte[PCMBLACK]) >= threshold) ? 1 : 0;
705 if ((x & 7)==7) {
706 *(ptr++) = tohex(color>>4);
707 *(ptr++) = tohex(color>>0);
709 break;
710 case SHADE_GREYSCALE:
711 if (PS_RGB)
712 color = src->colorByte[PCMWHITE];
713 else
714 color = 255 - src->colorByte[PCMBLACK];
715 *(ptr++) = tohex(color>>4);
716 *(ptr++) = tohex(color>>0);
717 break;
718 case SHADE_COLOR:
719 if (PS_RGB) {
720 /* Single-pass RGB */
721 for (i = 0; i < 3; i++) {
722 color = src->colorByte[rgb[i]];
723 *(ptr++) = tohex(color>>4);
724 *(ptr++) = tohex(color>>0);
726 } else {
727 /* CMYK */
728 for (i = 0; i < 4; i++) {
729 color = src->colorByte[cmyk[i]];
730 *(ptr++) = tohex(color>>4);
731 *(ptr++) = tohex(color>>0);
734 break;
737 if (ps_PrintShade == SHADE_BW && ((x & 7) != 0)) {
738 for (; (x & 7) != 0; x++) {
739 color <<= 1;
741 *(ptr++) = tohex(color>>4);
742 *(ptr++) = tohex(color>>0);
745 *(ptr++) = '\n';
747 return PDERR_NOERR;
750 static LONG ps_RenderFlush(LONG rows)
752 int len = 0;
754 switch (ps_PrintShade) {
755 case SHADE_BW:
756 len = (ps_PrintBufLen + 7) / 8;
757 break;
758 case SHADE_GREYSCALE:
759 len = ps_PrintBufLen;
760 break;
761 case SHADE_COLOR:
762 if (PS_RGB)
763 len = ps_PrintBufLen * 3;
764 else
765 len = ps_PrintBufLen * 4;
766 break;
769 PD->pd_PWrite(PD->pd_PrintBuf, len * 2 + 1);
770 PD->pd_PBothReady();
771 return PDERR_NOERR;
774 static LONG ps_RenderClear(void)
776 memset(PD->pd_PrintBuf, '0', ps_PrintBufLen * 8);
777 return PDERR_NOERR;
780 static LONG ps_RenderPreInit(struct IODRPReq *io, LONG flags)
782 ULONG dpiX, dpiY;
783 ULONG width, height;
785 /* Select DPI */
786 switch (flags & SPECIAL_DENSITYMASK) {
787 case SPECIAL_DENSITY1:
788 dpiX = 72;
789 dpiY = 72;
790 break;
791 case SPECIAL_DENSITY2:
792 dpiX = 100;
793 dpiY = 100;
794 break;
795 case SPECIAL_DENSITY3:
796 dpiX = 120;
797 dpiY = 120;
798 break;
799 case SPECIAL_DENSITY4:
800 dpiX = 150;
801 dpiY = 150;
802 break;
803 case SPECIAL_DENSITY5:
804 dpiX = 300;
805 dpiY = 300;
806 break;
807 case SPECIAL_DENSITY6:
808 dpiX = 600;
809 dpiY = 600;
810 break;
811 case SPECIAL_DENSITY7:
812 dpiX = 1200;
813 dpiY = 1200;
814 break;
815 default:
816 dpiX = 72;
817 dpiY = 72;
820 switch (PD->pd_Preferences.PrintPitch) {
821 case PP_ELITE: ps_FontCPI = 120; break;
822 case PP_FINE: ps_FontCPI = 171; break;
823 case PP_PICA: ps_FontCPI = 100; break;
824 default:
825 return PDERR_BADDIMENSION;
828 switch (PD->pd_Preferences.PrintSpacing) {
829 case PS_SIX_LPI: ps_SpacingLPI = 6; break;
830 case PS_EIGHT_LPI: ps_SpacingLPI = 8; break;
831 default:
832 return PDERR_BADDIMENSION;
835 switch (PD->pd_Preferences.PaperSize) {
836 /* PaperSize (in units of 0.0001 meters) */
837 case US_LETTER: ps_PaperSize = "Letter"; break; /* 8.5"x11" */
838 case US_LEGAL: ps_PaperSize = "Legal"; break; /* 8.5"x14" */
839 case N_TRACTOR: ps_PaperSize = "80-Col"; break; /* 9.5"x11" */
840 case W_TRACTOR: ps_PaperSize = "132-Col"; break; /* 14.86"x11" */
841 /* European sizes */
842 case EURO_A0: ps_PaperSize = "A0"; break; /* A0: 841 x 1189 */
843 case EURO_A1: ps_PaperSize = "A1"; break; /* A1: 594 x 841 */
844 case EURO_A2: ps_PaperSize = "A2"; break; /* A2: 420 x 594 */
845 case EURO_A3: ps_PaperSize = "A3"; break; /* A3: 297 x 420 */
846 case EURO_A4: ps_PaperSize = "A4"; break; /* A4: 210 x 297 */
847 case EURO_A5: ps_PaperSize = "A5"; break; /* A5: 148 x 210 */
848 case EURO_A6: ps_PaperSize = "A6"; break; /* A6: 105 x 148 */
849 case EURO_A7: ps_PaperSize = "A7"; break; /* A7: 74 x 105 */
850 case EURO_A8: ps_PaperSize = "A8"; break; /* A8: 52 x 74 */
851 case CUSTOM: ps_PaperSize = "Custom"; break;
852 default: return PDERR_BADDIMENSION;
855 /* Set up for the page size */
856 switch (PD->pd_Preferences.PaperSize) {
857 /* PaperSize (in units of 0.0001 meters) */
858 case US_LETTER: width = 2159; height = 2794; break; /* 8.5"x11" */
859 case US_LEGAL: width = 2159; height = 3556; break; /* 8.5"x14" */
860 case N_TRACTOR: width = 2413; height = 2794; break; /* 9.5"x11" */
861 case W_TRACTOR: width = 3774; height = 2794; break; /* 14.86"x11" */
862 /* European sizes */
863 case EURO_A0: width = 8410; height = 11890; break; /* A0: 841 x 1189 */
864 case EURO_A1: width = 5940; height = 8410; break; /* A1: 594 x 841 */
865 case EURO_A2: width = 4200; height = 5940; break; /* A2: 420 x 594 */
866 case EURO_A3: width = 2970; height = 4200; break; /* A3: 297 x 420 */
867 case EURO_A4: width = 2100; height = 2970; break; /* A4: 210 x 297 */
868 case EURO_A5: width = 1480; height = 2100; break; /* A5: 148 x 210 */
869 case EURO_A6: width = 1050; height = 1480; break; /* A6: 105 x 148 */
870 case EURO_A7: width = 740; height = 1050; break; /* A7: 74 x 105 */
871 case EURO_A8: width = 520; height = 740; break; /* A8: 52 x 74 */
872 case CUSTOM: width = PD->pd_Preferences.PrintMaxWidth * 254 / 10;
873 height = PD->pd_Preferences.PrintMaxHeight * 254 / 10;
874 break;
875 default: return PDERR_CANCEL;
878 PED->ped_MaxColumns = width * ps_FontCPI / 2540;
879 PED->ped_XDotsInch = dpiX;
880 PED->ped_YDotsInch = dpiY;
881 PED->ped_MaxXDots = width * dpiX / 254;
882 PED->ped_MaxYDots = height * dpiY / 254;
883 D(bug("MaxColumns=%d, dpiX=%d, dpiY=%d, MaxXDots=%d, MaxYDots=%d (%d x %d in)\n",
884 PED->ped_MaxColumns, PED->ped_XDotsInch, PED->ped_YDotsInch,
885 PED->ped_MaxXDots, PED->ped_MaxYDots,
886 PED->ped_MaxXDots / dpiX, PED->ped_MaxYDots / dpiY));
888 return PDERR_NOERR;
891 static LONG ps_RenderClose(SIPTR error, ULONG flags)
893 if (ps_PrintBufLen) {
894 /* Restore to text context - the text location
895 * has already been moved to after the raster
897 ps_PWrite("grestore (\n");
898 FreeMem(PD->pd_PrintBuf, ps_PrintBufLen * 8 + 1);
899 PD->pd_PrintBuf=NULL;
900 ps_PrintBufLen=0;
903 /* Send formfeed */
904 if (!(flags & SPECIAL_NOFORMFEED))
905 ps_SendPage(TRUE);
907 return PDERR_NOERR;
911 static LONG ps_Render(SIPTR ct, LONG x, LONG y, LONG status)
913 LONG err = PDERR_NOERR;
915 switch (status) {
916 case PRS_INIT:
917 D(bug("PRS_INIT: ct=%p, x=%d, y=%d\n", ct, x, y));
918 err = ps_RenderInit((struct IODRPReq *)ct, x, y);
919 break;
920 case PRS_TRANSFER:
921 D(bug("PRS_TRANSFER: ct=%p, x=%d, y=%d\n", ct, x, y));
922 err = ps_RenderTransfer((struct PrtInfo *)ct, x, y);
923 break;
924 case PRS_FLUSH:
925 D(bug("PRS_FLUSH: ct=%p, x=%d, y=%d\n", ct, x, y));
926 err = ps_RenderFlush(y);
927 break;
928 case PRS_CLEAR:
929 D(bug("PRS_CLEAR: ct=%p, x=%d, y=%d\n", ct, x, y));
930 err = ps_RenderClear();
931 break;
932 case PRS_CLOSE:
933 D(bug("PRS_CLOSE: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
934 err = ps_RenderClose(ct, x);
935 break;
936 case PRS_PREINIT:
937 D(bug("PRS_PREINIT: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
938 err = ps_RenderPreInit((struct IODRPReq *)ct, x);
939 break;
940 case PRS_CONVERT:
941 D(bug("PRS_CONVERT: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
942 err = PDERR_NOERR;
943 break;
944 case PRS_CORRECT:
945 D(bug("PRS_CORRECT: ct=%p, x=0x%0x, y=%d\n", ct, x, y));
946 err = PDERR_NOERR;
947 break;
948 default:
949 D(bug("PRS_xxxx(%d): ct=%p, x=0x%0x, y=%d\n", status, ct, x, y));
950 err = PDERR_CANCEL;
951 break;
954 return err;
957 /* Text output:
958 * > 0 = processed, add N chars
959 * 0 = not handled by DoSpecial
960 * -1 = Unsupported command
961 * -2 = Processed, but no additional chars in the buffer
963 static LONG ps_DoSpecial(UWORD *command, UBYTE output_buffer[],
964 BYTE *current_line_position,
965 BYTE *current_line_spacing,
966 BYTE *crlf_flag, UBYTE params[])
968 LONG ret;
969 D(bug("ps_DoSpecial: command=0x%04x, output_buffer=%p, current_line_position=%d, current_line_spacing=%d, crlf_flag=%d, params=%s\n",
970 *command, output_buffer, *current_line_position, *current_line_spacing, *crlf_flag, params));
972 switch (*command) {
973 case aRIN:
974 ps_SendHeader();
975 ret = -2;
976 break;
977 case aRIS:
978 PD->pd_PWaitEnabled = '\375';
979 ret = -2;
980 break;
981 case aSFC:
982 ps_VWrite(output_buffer, ") aSHOW %ld aSFC (\n", params[0] % 10);
983 ret = strlen(output_buffer);
984 break;
985 case aSBC:
986 ps_VWrite(output_buffer, ") aSHOW %ld aSBC (\n", params[0] % 10);
987 ret = strlen(output_buffer);
988 break;
989 default:
990 ret = -1;
991 break;
994 return ret;
997 static LONG ps_ConvFunc(UBYTE *buf, UBYTE c, LONG crlf_flag)
999 D(bug("ps_ConvFunc: %p '%c' %d\n", buf, c, crlf_flag));
1001 if (c == '\014') { /* Formfeed */
1002 ps_VSendPage(buf, TRUE);
1003 return strlen(buf);
1006 if (c < 0x1f || c > 0x7f)
1007 return -1;
1009 if (c == '(' || c == ')' || c== '\\') {
1010 *(buf++) = '\\';
1011 *(buf++) = c;
1012 *(buf++) = 0;
1013 return 2;
1016 if (c >= ' ' && c < 127) {
1017 *(buf++) = c;
1018 *(buf++) = 0;
1019 return 1;
1022 *(buf++) = '\\';
1023 *(buf++) = ((c >> 6) & 7) + '0';
1024 *(buf++) = ((c >> 3) & 7) + '0';
1025 *(buf++) = ((c >> 0) & 7) + '0';
1026 *(buf++) = 0;
1027 return 4;
1030 static LONG ps_DoPreferences(union printerIO *ior, LONG command)
1032 D(bug("ps_DoPreferences: ior=%p, command=%d\n"));
1033 return 0;
1036 static VOID ps_CallErrHook(union printerIO *ior, struct Hook *hook)
1038 D(bug("ps_CallErrHook: ior=%p, hook=%p\n", ior, hook));