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
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>
14 #include <prefs/printergfx.h>
15 #include <prefs/printertxt.h>
16 #include <exec/rawfmt.h>
18 #include <proto/exec.h>
19 #include <proto/graphics.h>
21 /* Support binary compatability with AOS */
23 #undef RAWFMTFUNC_STRING
24 #define RAWFMTFUNC_STRING (VOID (*)())"\x16\xC0\x4E\x75"
27 static LONG
sk_Init(struct PrinterData
*pd
);
28 static VOID
sk_Expunge(VOID
);
29 static LONG
sk_Open(union printerIO
*ior
);
30 static VOID
sk_Close(union printerIO
*ior
);
32 static LONG
sk_Render(SIPTR ct
, LONG x
, LONG y
, LONG status
);
33 static LONG
sk_ConvFunc(UBYTE
*buf
, UBYTE c
, LONG crlf_flag
);
34 static LONG
sk_DoPreferences(union printerIO
*ior
, LONG command
);
35 static VOID
sk_CallErrHook(union printerIO
*ior
, struct Hook
*hook
);
36 static LONG
sk_DoSpecial(UWORD
*command
, UBYTE output_buffer
[],
37 BYTE
*current_line_position
,
38 BYTE
*current_line_spacing
,
39 BYTE
*crlf_flag
, UBYTE params
[]);
41 static CONST_STRPTR PED_Commands
[] = {
42 "\377", /* 0 aRIS (reset) */
43 "\377\377", /* 1 aRIN (initialize) */
44 "\377", /* 2 aIND (linefeed) */
45 "\377", /* 3 aNEL (CR/LF) */
46 "\377", /* 4 aRI (reverse LF) */
47 "\377", /* 5 aSGR0 (Courier) */
48 "\377", /* 6 aSGR3 (italics) */
49 "\377", /* 7 aSGR23 (no italics) */
50 "\377", /* 8 aSGR4 (underline) */
51 "\377", /* 9 aSGR24 (no underline) */
52 "\377", /* 10 aSGR1 (boldface) */
53 "\377", /* 11 aSGR21 (no boldface) */
54 "\377", /* 12 aSFC (set text color) */
55 "\377", /* 13 aSBC (set background color) */
56 "\377", /* 14 aSHORP0 (normal pitch) */
57 "\377", /* 15 aSHORP2 (elite) */
58 "\377", /* 16 aSHORP1 (no elite) */
59 "\377", /* 17 aSHORP4 (condensed) */
60 "\377", /* 18 aSHORP3 (no condensed) */
61 "\377", /* 19 aSHORP6 (enlarge) */
62 "\377", /* 20 aSHORT5 (no enlarge) */
63 "\377", /* 21 aDEN6 (shadow) */
64 "\377", /* 22 aDEN5 (no shadow) */
65 "\377", /* 23 aDEN4 (double strike) */
66 "\377", /* 24 aDEN3 (no double strike) */
67 "\377", /* 25 aDEN2 (NLQ) */
68 "\377", /* 26 aDEN1 (no NLQ) */
69 "\377", /* 27 aSUS2 (superscript) */
70 "\377", /* 28 aSUS1 (no superscript) */
71 "\377", /* 29 aSUS4 (subscript) */
72 "\377", /* 30 aSUS3 (no subscript) */
73 "\377", /* 31 aSUS0 (normal) */
74 "\377", /* 32 aPLU (partial line up) */
75 "\377", /* 33 aPLD (partial line down) */
76 "\377", /* 34 aFNT0 (Courier) */
77 "\377", /* 35 aFNT1 (Helvetica) */
78 "\377", /* 36 aFNT2 (Font 2) */
79 "\377", /* 37 aFNT3 (Font 3) */
80 "\377", /* 38 aFNT4 (Font 4) */
81 "\377", /* 39 aFNT5 (Font 5) */
82 "\377", /* 40 aFNT6 (Font 6) */
83 "\377", /* 41 aFNT7 (Font 7) */
84 "\377", /* 42 aFNT8 (Font 8) */
85 "\377", /* 43 aFNT9 (Font 9) */
86 "\377", /* 44 aFNT10 (Font 10) */
87 "\377", /* 45 aPROP2 (proportional) */
88 "\377", /* 46 aPROP1 (no proportional) */
89 "\377", /* 47 aPROP0 (default proportion) */
90 "\377", /* 48 aTSS (set proportional offset) */
91 "\377", /* 49 aJFY5 (left justify) */
92 "\377", /* 50 aJFY7 (right justify) */
93 "\377", /* 51 aJFY6 (full justify) */
94 "\377", /* 52 aJFY0 (no justify) */
95 "\377", /* 53 aJFY3 (letter space) */
96 "\377", /* 54 aJFY1 (word fill) */
97 "\377", /* 55 aVERP0 (1/8" line spacing) */
98 "\377", /* 56 aVERP1 (1/6" line spacing) */
99 "\377", /* 57 aSLPP (form length) */
100 "\377", /* 58 aPERF (skip n perfs) */
101 "\377", /* 59 aPERF0 (no skip perfs) */
102 "\377", /* 60 aLMS (left margin) */
103 "\377", /* 61 aRMS (right margin) */
104 "\377", /* 62 aTMS (top margin) */
105 "\377", /* 63 aBMS (bot margin) */
106 "\377", /* 64 aSTBM (top & bottom margin) */
107 "\377", /* 65 aSLRM (left & right margin) */
108 "\377", /* 66 aCAM (no margins) */
109 "\377", /* 67 aHTS (horizontal tabs) */
110 "\377", /* 68 aVTS (vertical tabs) */
111 "\377", /* 69 aTBC0 (clear horizontal tab) */
112 "\377", /* 70 aTBC3 (clear all horiz. tabs) */
113 "\377", /* 71 aTBC1 (clear vertical tab) */
114 "\377", /* 72 aTBC4 (clear all vertical tabs) */
115 "\377", /* 73 aTBCALL (clear all tabs) */
116 "\377", /* 74 aTBSALL (default tabs) */
117 "\377", /* 75 aEXTEND (extended chars) */
118 "\377", /* 76 aRAW (next N chars are literal) */
121 static CONST_STRPTR cmdTable
[] = {
201 static CONST_STRPTR PED_8BitChars
[] = {
301 static struct TagItem PED_TagList
[] = {
302 { PRTA_8BitGuns
, TRUE
}, /* 0 */
303 { PRTA_MixBWColor
, TRUE
}, /* 1 */
304 { PRTA_LeftBorder
, 0 }, /* 2 */
305 { PRTA_TopBorder
, 0 }, /* 3 */
306 // { PRTA_ConvertSource, TRUE }, /* 4 */
307 { PRTA_ColorCorrection
, TRUE
}, /* 5 */
311 AROS_PRINTER_TAG(PED
, 44, 0,
312 .ped_PrinterName
= "Skeleton",
314 .ped_Expunge
= sk_Expunge
,
316 .ped_Close
= sk_Close
,
318 /* Settings for a 'graphics only' printer */
319 .ped_PrinterClass
= PPC_COLORGFX
| PPCF_EXTENDED
,
320 .ped_MaxColumns
= 0, /* Set during render */
321 .ped_ColorClass
= PCC_YMCB
| PCC_MULTI_PASS
,
322 .ped_NumCharSets
= 2,
323 .ped_NumRows
= 1, /* minimum pixels/row in gfx mode */
324 .ped_MaxXDots
= 0, /* Set during render */
325 .ped_MaxYDots
= 0, /* Set during render */
326 .ped_XDotsInch
= 0, /* Set during render */
327 .ped_YDotsInch
= 0, /* Set during render */
328 .ped_Commands
= (STRPTR
*)PED_Commands
, /* No ANSI commands */
329 .ped_DoSpecial
= sk_DoSpecial
,
330 .ped_Render
= sk_Render
,
331 .ped_TimeoutSecs
= 1000, /* For print-to-file timeouts */
332 .ped_8BitChars
= (STRPTR
*)PED_8BitChars
,
334 .ped_ConvFunc
= sk_ConvFunc
,
335 .ped_TagList
= &PED_TagList
[0],
336 .ped_DoPreferences
= sk_DoPreferences
,
337 .ped_CallErrHook
= sk_CallErrHook
,
340 struct PrinterData
*PD
;
341 static CONST_STRPTR sk_PaperSize
;
342 static LONG sk_PrintBufLen
;
343 static LONG sk_SpacingLPI
;
344 static LONG sk_FontCPI
;
346 static LONG
sk_Init(struct PrinterData
*pd
)
348 D(bug("sk_Init: pd=%p\n", pd
));
353 static VOID
sk_Expunge(VOID
)
355 D(bug("sk_Expunge\n"));
365 .buff
= &sk_PState
.buff_a
[0]
368 #define PFLUSH() do { \
369 PD->pd_PWrite(sk_PState.buff, sk_PState.len); \
370 if (sk_PState.buff == &sk_PState.buff_a[0]) \
371 sk_PState.buff = &sk_PState.buff_b[0]; \
373 sk_PState.buff = &sk_PState.buff_a[0]; \
378 static AROS_UFH2(void, sk_PPutC
,
379 AROS_UFHA(UBYTE
, c
, D0
),
380 AROS_UFHA(APTR
, dummy
, A3
))
384 /* Ignore the trailing 0 that RawDoFmt() tacks on the end */
388 sk_PState
.buff
[sk_PState
.len
++]=c
;
389 if (sk_PState
.len
>= 16)
395 #define sk_PWrite(fmt, ...) \
397 IPTR args[] = { AROS_PP_VARIADIC_CAST2IPTR(__VA_ARGS__) }; \
398 RawDoFmt(fmt, args, (VOID_FUNC)sk_PPutC, NULL); \
402 #define sk_VWrite(buf, fmt, ...) \
404 IPTR args[] = { AROS_PP_VARIADIC_CAST2IPTR(__VA_ARGS__) }; \
405 RawDoFmt(fmt, args, RAWFMTFUNC_STRING, buf); \
408 static LONG
sk_Open(union printerIO
*ior
)
410 D(bug("sk_Open: ior=%p\n", ior
));
415 static VOID
sk_Close(union printerIO
*ior
)
417 D(bug("sk_Close: ior=%p\n", ior
));
420 static LONG
sk_RenderInit(struct IODRPReq
*io
, LONG width
, LONG height
)
422 D(bug("sk_RenderInit: Dump raster %ldx%ld pixels, io_RastPort=%p\n", width
, height
, io
->io_RastPort
));
423 D(bug("\t@%ldx%ld (%ldx%ld) => @%ldx%ld\n",
424 io
->io_SrcX
, io
->io_SrcY
, io
->io_SrcWidth
,
425 io
->io_SrcHeight
, io
->io_DestCols
, io
->io_DestRows
));
426 LONG alignOffsetX
= 0;
427 LONG alignOffsetY
= 0;
430 sk_PrintBufLen
= width
;
431 PD
->pd_PrintBuf
= AllocMem(sk_PrintBufLen
* 6, MEMF_ANY
);
432 if (PD
->pd_PrintBuf
== NULL
)
433 return PDERR_BUFFERMEMORY
;
435 if (PD
->pd_Preferences
.PrintFlags
& PGFF_CENTER_IMAGE
) {
436 alignOffsetX
= (PED
->ped_MaxXDots
- width
) / 2;
437 alignOffsetY
= (PED
->ped_MaxYDots
- height
) / 2;
440 sk_PWrite("[IMAGE]\n");
445 static LONG
sk_RenderTransfer(struct PrtInfo
*pi
, LONG color
, LONG y
)
447 UBYTE
*ptr
= PD
->pd_PrintBuf
;
448 union colorEntry
*src
= pi
->pi_ColorInt
;
451 D(bug("\tSource=%p\n", src
));
453 sk_PWrite("[Image %ld] ", y
);
454 for (x
= 0; x
< pi
->pi_width
; x
++, src
++, ptr
++) {
455 *ptr
= " ..ccooCCOO@@##"[(src
->colorByte
[PCMBLACK
] >> 4) & 0xf];
461 static LONG
sk_RenderFlush(LONG rows
)
463 PD
->pd_PWrite(PD
->pd_PrintBuf
, sk_PrintBufLen
);
464 PD
->pd_PWrite("\n", 1);
468 static LONG
sk_RenderClear(void)
470 memset(PD
->pd_PrintBuf
, ' ', sk_PrintBufLen
);
474 static LONG
sk_RenderPreInit(struct IODRPReq
*io
, LONG flags
)
480 switch (flags
& SPECIAL_DENSITYMASK
) {
481 case SPECIAL_DENSITY1
:
485 case SPECIAL_DENSITY2
:
489 case SPECIAL_DENSITY3
:
493 case SPECIAL_DENSITY4
:
497 case SPECIAL_DENSITY5
:
501 case SPECIAL_DENSITY6
:
505 case SPECIAL_DENSITY7
:
514 switch (PD
->pd_Preferences
.PrintPitch
) {
515 case PP_ELITE
: sk_FontCPI
= 120; break;
516 case PP_FINE
: sk_FontCPI
= 171; break;
517 case PP_PICA
: sk_FontCPI
= 100; break;
519 return PDERR_BADDIMENSION
;
522 switch (PD
->pd_Preferences
.PrintSpacing
) {
523 case PS_SIX_LPI
: sk_SpacingLPI
= 6; break;
524 case PS_EIGHT_LPI
: sk_SpacingLPI
= 8; break;
526 return PDERR_BADDIMENSION
;
529 switch (PD
->pd_Preferences
.PaperSize
) {
530 /* PaperSize (in units of 0.0001 meters) */
531 case US_LETTER
: sk_PaperSize
= "Letter"; break; /* 8.5"x11" */
532 case US_LEGAL
: sk_PaperSize
= "Legal"; break; /* 8.5"x14" */
533 case N_TRACTOR
: sk_PaperSize
= "80-Col"; break; /* 9.5"x11" */
534 case W_TRACTOR
: sk_PaperSize
= "132-Col"; break; /* 14.86"x11" */
536 case EURO_A0
: sk_PaperSize
= "A0"; break; /* A0: 841 x 1189 */
537 case EURO_A1
: sk_PaperSize
= "A1"; break; /* A1: 594 x 841 */
538 case EURO_A2
: sk_PaperSize
= "A2"; break; /* A2: 420 x 594 */
539 case EURO_A3
: sk_PaperSize
= "A3"; break; /* A3: 297 x 420 */
540 case EURO_A4
: sk_PaperSize
= "A4"; break; /* A4: 210 x 297 */
541 case EURO_A5
: sk_PaperSize
= "A5"; break; /* A5: 148 x 210 */
542 case EURO_A6
: sk_PaperSize
= "A6"; break; /* A6: 105 x 148 */
543 case EURO_A7
: sk_PaperSize
= "A7"; break; /* A7: 74 x 105 */
544 case EURO_A8
: sk_PaperSize
= "A8"; break; /* A8: 52 x 74 */
545 case CUSTOM
: sk_PaperSize
= "Custom"; break;
546 default: return PDERR_BADDIMENSION
;
549 /* Set up for the page size */
550 switch (PD
->pd_Preferences
.PaperSize
) {
551 /* PaperSize (in units of 0.0001 meters) */
552 case US_LETTER
: width
= 2159; height
= 2794; break; /* 8.5"x11" */
553 case US_LEGAL
: width
= 2159; height
= 3556; break; /* 8.5"x14" */
554 case N_TRACTOR
: width
= 2413; height
= 2794; break; /* 9.5"x11" */
555 case W_TRACTOR
: width
= 3774; height
= 2794; break; /* 14.86"x11" */
557 case EURO_A0
: width
= 8410; height
= 11890; break; /* A0: 841 x 1189 */
558 case EURO_A1
: width
= 5940; height
= 8410; break; /* A1: 594 x 841 */
559 case EURO_A2
: width
= 4200; height
= 5940; break; /* A2: 420 x 594 */
560 case EURO_A3
: width
= 2970; height
= 4200; break; /* A3: 297 x 420 */
561 case EURO_A4
: width
= 2100; height
= 2970; break; /* A4: 210 x 297 */
562 case EURO_A5
: width
= 1480; height
= 2100; break; /* A5: 148 x 210 */
563 case EURO_A6
: width
= 1050; height
= 1480; break; /* A6: 105 x 148 */
564 case EURO_A7
: width
= 740; height
= 1050; break; /* A7: 74 x 105 */
565 case EURO_A8
: width
= 520; height
= 740; break; /* A8: 52 x 74 */
566 case CUSTOM
: width
= PD
->pd_Preferences
.PrintMaxWidth
* 254 / 10;
567 height
= PD
->pd_Preferences
.PrintMaxHeight
* 254 / 10;
569 default: return PDERR_CANCEL
;
572 PED
->ped_MaxColumns
= width
* sk_FontCPI
/ 2540;
573 PED
->ped_XDotsInch
= dpiX
;
574 PED
->ped_YDotsInch
= dpiY
;
575 PED
->ped_MaxXDots
= width
* dpiX
/ 254;
576 PED
->ped_MaxYDots
= height
* dpiY
/ 254;
577 D(bug("MaxColumns=%d, dpiX=%d, dpiY=%d, MaxXDots=%d, MaxYDots=%d (%d x %d in)\n",
578 PED
->ped_MaxColumns
, PED
->ped_XDotsInch
, PED
->ped_YDotsInch
,
579 PED
->ped_MaxXDots
, PED
->ped_MaxYDots
,
580 PED
->ped_MaxXDots
/ dpiX
, PED
->ped_MaxYDots
/ dpiY
));
585 static LONG
sk_RenderClose(SIPTR error
, ULONG flags
)
587 if (error
!= PDERR_CANCEL
) {
589 if (!(flags
& SPECIAL_NOFORMFEED
))
593 sk_PWrite("[Close]\n");
598 static LONG
sk_RenderNextColor(void)
603 /* If Tag PRTA_ConvertSource is set, this function is called instead
604 * of the printer.device built-in to convert.
606 * The size of each entry is either sizeof(union colorEntry), or
607 * Tag PRTA_ColorSize (if set)
609 * The conversion is done in-place.
611 static LONG
sk_RenderConvert(APTR row
, LONG entries
, LONG is_pixels
)
616 /* If Tag PRTA_ColorCorrection is set, this function is called instead
617 * of the printer.device built-in to correct printer-space colors.
619 * The size of each entry is either sizeof(union colorEntry), or
620 * Tag PRTA_ColorSize (if set)
622 * The conversion is done in-place.
624 static LONG
sk_RenderCorrect(APTR row
, LONG entries
, LONG is_pixels
)
629 static LONG
sk_Render(SIPTR ct
, LONG x
, LONG y
, LONG status
)
631 LONG err
= PDERR_NOERR
;
635 D(bug("PRS_INIT: IODRPReq=%p, width=%d, height=%d\n", ct
, x
, y
));
636 err
= sk_RenderInit((struct IODRPReq
*)ct
, x
, y
);
639 D(bug("PRS_TRANSFER: PrtInfo=%p, color=%d, row=%d\n", ct
, x
, y
));
640 err
= sk_RenderTransfer((struct PrtInfo
*)ct
, x
, y
);
643 D(bug("PRS_FLUSH: ct=%p, x=%d, rows=%d\n", ct
, x
, y
));
644 err
= sk_RenderFlush(y
);
647 D(bug("PRS_CLEAR: ct=%p, x=%d, y=%d\n", ct
, x
, y
));
648 err
= sk_RenderClear();
651 D(bug("PRS_CLOSE: error=%d, io_Special=0x%0x, y=%d\n", ct
, x
, y
));
652 err
= sk_RenderClose(ct
, x
);
655 D(bug("PRS_PREINIT: IODRPReq=%p, io_Special=0x%0x, y=%d\n", ct
, x
, y
));
656 err
= sk_RenderPreInit((struct IODRPReq
*)ct
, x
);
659 D(bug("PRS_NEXTCOLOR: ct=%p, x=0x%0x, y=%d\n", ct
, x
, y
));
660 err
= sk_RenderNextColor();
663 D(bug("PRS_UNKNOWN: ct=%p, x=0x%0x, y=%d\n", ct
, x
, y
));
667 D(bug("PRS_CONVERT: row=%p, entries=%d, type=%s\n", ct
, x
, y
? "pixels" : "union colorEntry"));
668 err
= sk_RenderConvert((APTR
)ct
, x
, y
);
671 D(bug("PRS_CORRECT: row=%p, entries=%d, type=%s\n", ct
, x
, y
? "pixels" : "union colorEntry"));
672 err
= sk_RenderCorrect((APTR
)ct
, x
, y
);
675 D(bug("PRS_xxxx(%d): ct=%p, x=0x%0x, y=%d\n", status
, ct
, x
, y
));
683 * > 0 = processed, add N chars
684 * 0 = not handled by DoSpecial
685 * -1 = Unsupported command
686 * -2 = Processed, but no additional chars in the buffer
688 static LONG
sk_DoSpecial(UWORD
*command
, UBYTE output_buffer
[],
689 BYTE
*current_line_position
,
690 BYTE
*current_line_spacing
,
691 BYTE
*crlf_flag
, UBYTE params
[])
693 D(bug("sk_DoSpecial: command=0x%04x, output_buffer=%p, current_line_position=%d, current_line_spacing=%d, crlf_flag=%d, params=%s\n",
694 *command
, output_buffer
, *current_line_position
, *current_line_spacing
, *crlf_flag
, params
));
696 sk_VWrite(output_buffer
, "[%s %ld,%ld,%ld,%ld]", cmdTable
[*command
], params
[0], params
[1], params
[2], params
[3]);
698 return strlen(output_buffer
);
701 static LONG
sk_ConvFunc(UBYTE
*buf
, UBYTE c
, LONG crlf_flag
)
703 D(bug("sk_ConvFunc: %p '%c' %d\n", buf
, c
, crlf_flag
));
705 /* NOTE: For compatability with AOS 3.x, do
706 * not attempt to convert ESC or \377
707 * characters if you want DoSpecial() to work.
709 if (c
== 0x1b || c
== 0xff)
712 /* As a demo, we're going to UPPERCASE all characters,
713 * and put a '\' in front of the modified character.
715 if (c
>= 'a' && c
<= 'z') {
724 static LONG
sk_DoPreferences(union printerIO
*ior
, LONG command
)
726 D(bug("sk_DoPreferences: ior=%p, command=%d\n"));
730 static VOID
sk_CallErrHook(union printerIO
*ior
, struct Hook
*hook
)
732 D(bug("sk_CallErrHook: ior=%p, hook=%p\n", ior
, hook
));