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
7 * Code related to Gfx printing
12 #include <aros/debug.h>
13 #include <aros/printertag.h>
15 #include <proto/exec.h>
16 #include <proto/arossupport.h>
17 #include <proto/graphics.h>
18 #include <proto/cybergraphics.h>
20 #include <cybergraphx/cybergraphics.h>
22 #include <devices/prtgfx.h>
24 #include <SDI/SDI_hook.h>
26 #include "printer_intern.h"
30 struct PrinterData
*di_PrinterData
;
32 BOOL di_ConvertSource
;
33 BOOL di_FloydDithering
;
35 BOOL di_ColorCorrection
;
42 typedef LONG (*renderFunc
)(SIPTR ct
, LONG x
, LONG y
, LONG status
);
44 #define RENDER(ct, x, y, status) ({ \
45 D(bug("\tRENDER(%d): ct=%p x=%d y=%d\n", status, (APTR)ct, x, y)); \
46 ((renderFunc)pi->pi_render)((SIPTR)(ct), (LONG)(x), (LONG)(y), (LONG)(status)); })
48 static void pg_ConvertSource(struct driverInfo
*di
, UBYTE
*pdata
, LONG width
)
50 struct PrinterData
*pd
= di
->di_PrinterData
;
51 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
54 if (di
->di_ColorSize
< sizeof(union colorEntry
)) {
55 D(bug("\tdi->di_ColorSize<sizeof(union colorEntry)\n"));
59 for (x
= 0; x
< width
; x
++, pdata
+= di
->di_ColorSize
) {
60 union colorEntry
*ce
= (APTR
) pdata
;
63 r
= ce
->colorByte
[PCMRED
];
64 g
= ce
->colorByte
[PCMGREEN
];
65 b
= ce
->colorByte
[PCMBLUE
];
67 /* Find largest white*/
71 if ((ped
->ped_ColorClass
& PCC_4COLOR
)) {
72 r
= ~((w
- r
) * 255 / w
);
73 g
= ~((w
- g
) * 255 / w
);
74 b
= ~((w
- b
) * 255 / w
);
77 if (!(ped
->ped_ColorClass
& PCC_ADDITIVE
)) {
84 if (!di
->di_8BitGuns
) {
91 ce
->colorByte
[PCMRED
] = r
;
92 ce
->colorByte
[PCMGREEN
] = g
;
93 ce
->colorByte
[PCMBLUE
] = b
;
94 ce
->colorByte
[PCMWHITE
] = w
;
99 static void pg_ColorCorrection(struct driverInfo
*di
, UBYTE
*pdata
, LONG width
)
101 /*Nothing to do here*/
104 static void pg_FloydDithering(struct driverInfo
*di
, UBYTE
*pdata
, LONG width
)
106 /* Nothing done here for now.
108 * In theory, we should do Ordered and Floyd-Steinberg dithering here.
112 ULONG
zrgbof(struct ColorMap
*cm
, ULONG index
)
116 /* For invalid entries, print white, not black
118 if (index
>= cm
->Count
)
121 hibits
= cm
->ColorTable
[index
];
123 ULONG red8
= (hibits
& 0x0f00) >> 4;
124 ULONG green8
= (hibits
& 0x00f0);
125 ULONG blue8
= (hibits
& 0x000f) << 4;
127 if (cm
->Type
> COLORMAP_TYPE_V1_2
) {
128 UWORD lobits
= cm
->LowColorBits
[index
];
130 red8
|= (lobits
& 0x0f00) >> 8;
131 green8
|= (lobits
& 0x00f0) >> 4;
132 blue8
|= (lobits
& 0x000f);
135 return (red8
<< 16) | (green8
<< 8) | blue8
;
138 /* TurboPrint emulation helper hooks - convert from
139 * native formats to 0RGB32 longwords
143 struct DRPSourceMsg
*drp
= (struct DRPSourceMsg
*)msg
;
144 struct IODRPReq
*io
= (struct IODRPReq
*)obj
;
145 struct BitMap
*tpbm
= io
->io_RastPort
->BitMap
;
146 UBYTE
*src
= tpbm
->Planes
[0];
147 ULONG
*buf
= drp
->buf
;
148 UWORD bpr
= tpbm
->BytesPerRow
;
149 struct ColorMap
*cm
= io
->io_ColorMap
;
150 struct TPExtIODRP
*tp
= (struct TPExtIODRP
*)io
->io_Modes
;
174 src
+= (bpr
* drp
->y
);
175 for (h
= 0; h
< drp
->height
; h
++, src
+= bpr
) {
176 UBYTE
*sref
= src
+ drp
->x
* bpp
;
177 for (w
= 0; w
< drp
->width
; w
++ ) {
183 zrgb
= zrgbof(cm
, *(sref
++));
186 rgb15
= (*(sref
++)) << 8;
191 rgb15
|= (*(sref
++)) << 8;
193 zrgb
= ((((rgb15
>> 10) & 0x1f)<<3) << 16) |
194 ((((rgb15
>> 5) & 0x1f)<<3) << 8) |
195 ((((rgb15
>> 0) & 0x1f)<<3) << 0);
198 rgb16
= (*(sref
++)) << 8;
203 rgb16
|= (*(sref
++)) << 8;
205 zrgb
= ((((rgb16
>> 11) & 0x1f)<<3) << 16) |
206 ((((rgb16
>> 5) & 0x3f)<<2) << 8) |
207 ((((rgb16
>> 0) & 0x1f)<<3) << 0);
210 zrgb
= (*(sref
++) << 16);
211 zrgb
|= (*(sref
++) << 8);
212 zrgb
|= (*(sref
++) << 0);
215 zrgb
= (*(sref
++) << 0);
216 zrgb
|= (*(sref
++) << 8);
217 zrgb
|= (*(sref
++) << 16);
228 return (buf
- drp
->buf
);
231 MakeStaticHook(TPHook
, TPSlice
);
233 LONG
Printer_Gfx_DumpRPort(struct IODRPReq
*io
, struct TagItem
*tags
)
235 struct PrinterData
*pd
= (struct PrinterData
*)io
->io_Device
;
236 struct PrinterExtendedData
*ped
= &pd
->pd_SegmentData
->ps_PED
;
237 struct PrinterGfxPrefs
*gfx
= &pd
->pd_PUnit
->pu_Prefs
.pp_Gfx
;
238 struct Hook
*srcHook
= NULL
;
241 LONG aspectXsrc
= 1, aspectYsrc
= 1;
242 LONG aspectXdst
= 1, aspectYdst
= 1;
243 LONG scaleXsrc
, scaleXdst
;
244 LONG scaleYsrc
, scaleYdst
;
245 LONG prnMarginLeft
, prnMarginRight
;
246 LONG prnMarginTop
, prnMarginBottom
;
250 struct driverInfo di
= {
251 .di_PrinterData
= pd
,
252 .di_ColorSize
= sizeof(union colorEntry
),
254 struct PrtInfo
*pi
= &di
.pi
;
255 UBYTE
const dmatrix
[] = {
262 D(bug("%s: io=%p, tags=%p\n", __func__
, io
, tags
));
264 pi
->pi_render
= (APTR
)ped
->ped_Render
;
265 if (!(ped
->ped_PrinterClass
& 1) || pi
->pi_render
== NULL
) {
267 D(bug("\tNot a graphics printer (class = 0x%x)\n", ped
->ped_PrinterClass
));
268 return PDERR_NOTGRAPHICS
;
271 /* Set up density and printer dimensions */
272 err
= RENDER(io
, io
->io_Special
, 0, PRS_PREINIT
);
276 /* Get the source's aspect ratio */
277 if (io
->io_Command
== PRD_TPEXTDUMPRPORT
) {
278 struct TPExtIODRP
*tp
= (APTR
)io
->io_Modes
;
280 return PDERR_NOTGRAPHICS
;
281 aspectXsrc
= tp
->PixAspX
;
282 aspectYsrc
= tp
->PixAspY
;
283 bug("tp->Mode = 0x%04x\n", tp
->Mode
);
294 case TPFMT_CyberGraphX
:
295 case TPFMT_BitPlanes
:
298 srcHook
= NULL
; /* AROS BitMap object - we can handle this */
301 return PDERR_NOTGRAPHICS
;
303 } else if (io
->io_Modes
!= INVALID_ID
) {
304 struct DisplayInfo dpyinfo
;
306 if (GetDisplayInfoData(NULL
, (APTR
)&dpyinfo
, sizeof(dpyinfo
), DTAG_DISP
, io
->io_Modes
)) {
307 aspectXsrc
= dpyinfo
.Resolution
.x
;
308 aspectYsrc
= dpyinfo
.Resolution
.y
;
312 /* Get the printer's aspect ratio */
313 aspectXdst
= ped
->ped_XDotsInch
;
314 aspectYdst
= ped
->ped_YDotsInch
;
316 while ((tag
= LibNextTagItem(&tags
))) {
317 switch (tag
->ti_Tag
) {
318 case DRPA_SourceHook
:
319 srcHook
= (struct Hook
*)tag
->ti_Data
;
322 aspectXsrc
= tag
->ti_Data
;
325 aspectYsrc
= tag
->ti_Data
;
332 if ((pd
->pd_SegmentData
->ps_Version
>= 44) &&
333 (ped
->ped_PrinterClass
& PPCF_EXTENDED
)) {
334 tags
= ped
->ped_TagList
;
335 while ((tag
= LibNextTagItem(&tags
))) {
336 switch (tag
->ti_Tag
) {
338 di
.di_8BitGuns
= (BOOL
)tag
->ti_Data
;
340 case PRTA_ConvertSource
:
341 di
.di_ConvertSource
= (BOOL
)tag
->ti_Data
;
343 case PRTA_FloydDithering
:
344 di
.di_FloydDithering
= (BOOL
)tag
->ti_Data
;
347 di
.di_AntiAlias
= (BOOL
)tag
->ti_Data
;
349 case PRTA_ColorCorrection
:
350 di
.di_ColorCorrection
= (BOOL
)tag
->ti_Data
;
353 /* Handled in driver.c */
356 di
.di_NewColor
= (BOOL
)tag
->ti_Data
;
359 di
.di_ColorSize
= (ULONG
)tag
->ti_Data
;
362 di
.di_NoScaling
= (BOOL
)tag
->ti_Data
;
364 case PRTA_DitherNames
:
365 case PRTA_ShadingNames
:
366 case PRTA_ColorCorrect
:
367 case PRTA_DensityInfo
:
368 /* Handled in :Prefs/Printer */
370 case PRTA_LeftBorder
:
372 case PRTA_MixBWColor
:
373 case PRTA_Preferences
:
374 /* Advice for applications */
382 if (di
.di_NewColor
) {
383 di
.di_ConvertSource
= TRUE
;
384 di
.di_FloydDithering
= TRUE
;
385 di
.di_AntiAlias
= TRUE
;
386 di
.di_ColorCorrection
= TRUE
;
389 if (di
.di_NoScaling
) {
390 di
.di_FloydDithering
= TRUE
;
391 di
.di_AntiAlias
= TRUE
;
394 if (di
.di_8BitGuns
) {
395 di
.di_FloydDithering
= TRUE
;
398 if (di
.di_ColorSize
< 3) {
399 D(bug("\tPRTA_ColorSize was %d - illegal!\n", di
.di_ColorSize
));
400 return PDERR_BADDIMENSION
;
403 if (di
.di_ColorSize
< sizeof(union colorEntry
) && !di
.di_ConvertSource
404 && !di
.di_ColorCorrection
) {
405 D(bug("\tPRTA_ColorSize of %d is illegal without PRTA_ConvertSource and PRTA_ColorCorrection!\n", di
.di_ColorSize
));
406 return PDERR_BADDIMENSION
;
409 prnMarginLeft
= gfx
->pg_PrintXOffset
;
411 prnMarginTop
= gfx
->pg_PrintYOffset
;
416 prnW
= io
->io_DestCols
? io
->io_DestCols
: io
->io_SrcWidth
;
417 prnH
= io
->io_DestRows
? io
->io_DestRows
: io
->io_SrcHeight
;
419 di
.di_NumRows
= ped
->ped_NumRows
; /* Rows/Stripe */
421 if (io
->io_Special
== 0) {
422 /* From the OS 3.9 autodocs for printer.device... */
423 if (prnW
== 0 && prnH
> 0) {
424 prnW
= (ped
->ped_MaxXDots
- (prnMarginLeft
+ prnMarginRight
));
425 } else if (prnW
== 0 && prnH
== 0) {
426 prnW
= (ped
->ped_MaxXDots
- (prnMarginLeft
+ prnMarginRight
));
427 prnH
= prnW
* aspectYsrc
/ aspectXsrc
;
428 } else if (prnW
> 0 && prnH
== 0) {
429 prnH
= prnW
* aspectYsrc
/ aspectXsrc
;
430 } else if (prnW
< 0 && prnH
> 0) {
431 prnW
= io
->io_SrcWidth
* (-prnW
) / prnH
;
432 prnH
= prnW
* aspectYsrc
/ aspectXsrc
;
436 if (io
->io_Special
& SPECIAL_MILCOLS
) {
437 prnW
= io
->io_DestCols
* ped
->ped_XDotsInch
/ 1000;
439 if (io
->io_Special
& SPECIAL_MILROWS
) {
440 prnH
= io
->io_DestRows
* ped
->ped_YDotsInch
/ 1000;
442 /* The following math relies on the fact that at
443 * ped_Max?Dots is limited to 65535 pixels:
444 * At even 1200dpi, 65535 pixels is over 100 inches!
446 if (io
->io_Special
& SPECIAL_FRACCOLS
) {
447 prnW
= (ped
->ped_MaxXDots
* (io
->io_DestCols
>> 16)) >> 16;
449 if (io
->io_Special
& SPECIAL_FRACROWS
) {
450 prnH
= (ped
->ped_MaxYDots
* (io
->io_DestRows
>> 16)) >> 16;
452 /* Full page width (minus the margins) */
453 if (io
->io_Special
& SPECIAL_FULLCOLS
) {
454 prnW
= ped
->ped_MaxXDots
- (prnMarginLeft
+ prnMarginRight
);
456 if (io
->io_Special
& SPECIAL_FULLROWS
) {
457 prnH
= ped
->ped_MaxYDots
- (prnMarginTop
+ prnMarginBottom
);
459 if (io
->io_Special
& SPECIAL_ASPECT
) {
460 prnH
= prnH
* aspectYdst
/ aspectXdst
;
463 /* Autoshrink to maximum page size */
464 if (prnW
> (ped
->ped_MaxXDots
- (prnMarginLeft
+ prnMarginRight
))) {
465 LONG delta
= prnW
- (ped
->ped_MaxXDots
- (prnMarginLeft
+ prnMarginRight
));
466 prnH
= prnH
- delta
* prnH
/ prnW
;
470 if (prnH
> (ped
->ped_MaxYDots
- (prnMarginTop
+ prnMarginBottom
))) {
471 LONG delta
= prnH
- (ped
->ped_MaxYDots
- (prnMarginTop
+ prnMarginBottom
));
472 prnW
= prnW
- delta
* prnW
/ prnH
;
477 if (io
->io_Special
& SPECIAL_CENTER
) {
478 prnX
= prnMarginLeft
+ (ped
->ped_MaxXDots
- (prnMarginLeft
+ prnMarginRight
) - prnW
) / 2;
479 prnY
= prnMarginTop
+ (ped
->ped_MaxYDots
- (prnMarginTop
+ prnMarginBottom
) - prnH
) / 2;
481 prnX
= prnMarginLeft
;
485 D(bug("\tAspect: %dx%d %d:%d => %dx%d %d:%d\n",
486 io
->io_SrcWidth
, io
->io_SrcHeight
,
487 aspectXsrc
, aspectYsrc
,
489 aspectXdst
, aspectYdst
));
491 /* Scaling calculations. */
492 scaleXsrc
= io
->io_SrcWidth
;
493 scaleYsrc
= io
->io_SrcHeight
;
497 while (scaleXsrc
> 168383 || scaleXdst
> 168383) {
500 if (scaleXsrc
== 0 || scaleXdst
== 0) {
501 D(bug("\tCan't scale X from %dx%d to %dx%d\n", io
->io_SrcWidth
, io
->io_SrcHeight
, prnW
, prnH
));
502 return PDERR_BADDIMENSION
;
506 while (scaleYsrc
> 168383 || scaleYdst
> 168383) {
509 if (scaleYsrc
== 0 || scaleYdst
== 0) {
510 D(bug("\tCan't scale Y from %dx%d to %dx%d\n", io
->io_SrcWidth
, io
->io_SrcHeight
, prnW
, prnH
));
511 return PDERR_BADDIMENSION
;
516 prnW
= ScalerDiv(io
->io_SrcWidth
, scaleXdst
, scaleXsrc
);
517 prnH
= ScalerDiv(io
->io_SrcHeight
, scaleYdst
, scaleYsrc
);
519 D(bug("\tScaling %dx%d (%d:%d) => %dx%d (%d:%d)\n",
520 io
->io_SrcWidth
, io
->io_SrcHeight
, scaleXsrc
, scaleYsrc
,
521 prnW
, prnH
, scaleXdst
, scaleYdst
));
523 io
->io_DestCols
= prnW
;
524 io
->io_DestRows
= prnH
;
527 /* If nothing to print, we're done! */
528 if (io
->io_Special
& SPECIAL_NOPRINT
) {
529 D(bug("\tOh, SPECIAL_NOPRINT. Done.\n"));
533 /* Set up the PrtInfo structure */
534 pi
->pi_rp
= io
->io_RastPort
;
535 pi
->pi_ScaleX
= NULL
; /* New di.di_s should *not* be using this */
536 pi
->pi_dmatrix
= (UBYTE
*) dmatrix
;
538 pi
->pi_height
= prnH
;
540 pi
->pi_threshold
= pd
->pd_Preferences
.PrintThreshold
;
541 pi
->pi_special
= io
->io_Special
;
542 pi
->pi_SourceHook
= srcHook
;
544 /* Initialize page for printing */
545 if (0 == (err
= RENDER(io
, prnW
, prnH
, PRS_INIT
))) {
547 struct BitMap
*src_bm
= NULL
;
549 if (di
.di_NoScaling
) {
550 prnW
= io
->io_SrcWidth
;
551 prnH
= io
->io_SrcHeight
;
552 scaleXsrc
= scaleXdst
= 1;
553 scaleYsrc
= scaleYdst
= 1;
556 /* Allocate a row for 24-bit RGB color information */
559 struct RastPort src_rp
;
560 InitRastPort(&src_rp
);
562 /* In case we fail.. */
563 err
= PDERR_INTERNALMEMORY
;
564 if ((pdata
= AllocMem(io
->io_SrcWidth
* 4, MEMF_PUBLIC
))) {
565 if ((src_bm
= AllocBitMap(io
->io_SrcWidth
, io
->io_SrcHeight
, 24, BMF_SPECIALFMT
| SHIFT_PIXFMT(PIXFMT_RGB24
) , io
->io_RastPort
->BitMap
))) {
566 struct DRPSourceMsg msg
;
569 src_rp
.BitMap
= src_bm
;
573 msg
.width
= io
->io_SrcWidth
;
574 msg
.buf
= (APTR
)pdata
;
576 for (row
= 0; row
< io
->io_SrcHeight
; row
++, msg
.y
++) {
577 /* Collect the next source row */
579 CallHookA(srcHook
, io
, &msg
);
580 /* Transfer to source bitmap */
581 WritePixelArray(pdata
, 0, 0, io
->io_SrcWidth
* 4, &src_rp
, 0, row
, io
->io_SrcWidth
, 1, RECTFMT_0RGB32
);
584 D(bug("\tCan't allocate bitmap to hold srcHook data (%d x %d)\n", io
->io_SrcWidth
, io
->io_SrcHeight
));
586 FreeMem(pdata
, io
->io_SrcWidth
* 4);
588 D(bug("\tCan't allocate a %dx4 row to hold srcHook data\n", io
->io_SrcWidth
));
591 src_bm
= io
->io_RastPort
->BitMap
;
597 if ((pdata
= AllocMem(prnW
* di
.di_ColorSize
, MEMF_PUBLIC
))) {
598 pi
->pi_ColorInt
= pdata
;
599 pi
->pi_ColorIntSize
= prnW
* di
.di_ColorSize
;
601 if ((bm
= AllocBitMap(prnW
, prnH
, src_bm
->Depth
, 0, src_bm
))) {
602 /* Render it ourselves */
603 struct BitScaleArgs bsa
= {
604 .bsa_SrcBitMap
= src_bm
,
605 .bsa_SrcX
= io
->io_SrcX
,
606 .bsa_SrcY
= io
->io_SrcY
,
607 .bsa_SrcWidth
= io
->io_SrcWidth
,
608 .bsa_SrcHeight
= io
->io_SrcHeight
,
609 .bsa_XSrcFactor
= scaleXsrc
,
610 .bsa_XDestFactor
= scaleXdst
,
611 .bsa_YSrcFactor
= scaleYsrc
,
612 .bsa_YDestFactor
= scaleYdst
,
613 .bsa_DestBitMap
= bm
,
621 /* If we make a temporary source bitmap, we no longer need it.
623 if (srcHook
&& src_bm
) {
627 for (row
= 0; row
< prnH
; rleft
-= di
.di_NumRows
) {
628 LONG rows
= (rleft
> di
.di_NumRows
) ? di
.di_NumRows
: rleft
;
630 for (i
=0; i
< rows
; i
++, row
++) {
631 ReadPixelArray(pdata
, 0, 0, prnW
* di
.di_ColorSize
,
632 &rp
, 0, row
, prnW
, 1,
633 di
.di_ColorSize
== 3 ?
637 /* Convert from RGB to printer color space */
638 if (di
.di_ConvertSource
)
639 RENDER(pdata
, prnW
, 1, PRS_CONVERT
);
641 pg_ConvertSource(&di
, pdata
, prnW
);
643 /* Apply printer color space corrections */
644 if (di
.di_ColorCorrection
)
645 RENDER(pdata
, prnW
, 1, PRS_CORRECT
);
647 pg_ColorCorrection(&di
, pdata
, prnW
);
649 if (!di
.di_FloydDithering
)
650 pg_FloydDithering(&di
, pdata
, prnW
);
652 RENDER(pi
, 0, prnY
+ row
, PRS_TRANSFER
);
654 RENDER(0, 0, rows
, PRS_FLUSH
);
658 D(bug("\tCan't allocate a %dx%d bitmap for the scaled data\n", prnW
, prnH
));
660 FreeMem(pdata
, prnW
* di
.di_ColorSize
);
662 D(bug("\tCan't allocate a %d x %d byte transfer row\n", prnW
, di
.di_ColorSize
));
665 D(bug("\tCan't find nor synthesize a source bitmap\n"));
668 RENDER((SIPTR
)err
, io
->io_Special
, 0, PRS_CLOSE
);