1
0
mirror of https://github.com/deadw00d/AROS.git synced 2025-12-06 05:00:25 +00:00
Files
AROS-v0/workbench/devs/printer/gfx.c
Matthias Rustler 6b5a534ce3 workbench: detabbed
2021-05-02 13:55:14 +02:00

675 lines
21 KiB
C

/*
* Copyright (C) 2012, The AROS Development Team. All rights reserved.
* Author: Jason S. McMullan <jason.mcmullan@gmail.com>
*
* Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
*
* Code related to Gfx printing
*/
#include <string.h>
#include <aros/debug.h>
#include <aros/printertag.h>
#include <proto/exec.h>
#include <proto/arossupport.h>
#include <proto/graphics.h>
#include <proto/cybergraphics.h>
#include <cybergraphx/cybergraphics.h>
#include <devices/prtgfx.h>
#include <SDI/SDI_hook.h>
#include "printer_intern.h"
struct driverInfo {
struct PrtInfo pi;
struct PrinterData *di_PrinterData;
BOOL di_8BitGuns;
BOOL di_ConvertSource;
BOOL di_FloydDithering;
BOOL di_AntiAlias;
BOOL di_ColorCorrection;
BOOL di_NewColor;
BOOL di_NoScaling;
LONG di_ColorSize;
LONG di_NumRows;
};
typedef LONG (*renderFunc )(SIPTR ct, LONG x, LONG y, LONG status);
#define RENDER(ct, x, y, status) ({ \
D(bug("\tRENDER(%d): ct=%p x=%d y=%d\n", status, (APTR)ct, x, y)); \
((renderFunc)pi->pi_render)((SIPTR)(ct), (LONG)(x), (LONG)(y), (LONG)(status)); })
static void pg_ConvertSource(struct driverInfo *di, UBYTE *pdata, LONG width)
{
struct PrinterData *pd = di->di_PrinterData;
struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
LONG x;
if (di->di_ColorSize < sizeof(union colorEntry)) {
D(bug("\tdi->di_ColorSize<sizeof(union colorEntry)\n"));
return;
}
for (x = 0; x < width; x++, pdata += di->di_ColorSize) {
union colorEntry *ce = (APTR) pdata;
UBYTE r, g, b, w;
r = ce->colorByte[PCMRED];
g = ce->colorByte[PCMGREEN];
b = ce->colorByte[PCMBLUE];
/* Find largest white*/
w = (r > g) ? r : g;
w = (b > w) ? b : w;
if ((ped->ped_ColorClass & PCC_4COLOR)) {
r = ~((w - r) * 255 / w);
g = ~((w - g) * 255 / w);
b = ~((w - b) * 255 / w);
}
if (!(ped->ped_ColorClass & PCC_ADDITIVE)) {
r = ~r;
g = ~g;
b = ~b;
w = ~w;
}
if (!di->di_8BitGuns) {
r >>= 4;
g >>= 4;
b >>= 4;
w >>= 4;
}
ce->colorByte[PCMRED] = r;
ce->colorByte[PCMGREEN] = g;
ce->colorByte[PCMBLUE] = b;
ce->colorByte[PCMWHITE] = w;
}
}
static void pg_ColorCorrection(struct driverInfo *di, UBYTE *pdata, LONG width)
{
/*Nothing to do here*/
}
static void pg_FloydDithering(struct driverInfo *di, UBYTE *pdata, LONG width)
{
/* Nothing done here for now.
*
* In theory, we should do Ordered and Floyd-Steinberg dithering here.
*/
}
ULONG zrgbof(struct ColorMap *cm, ULONG index)
{
UWORD hibits;
/* For invalid entries, print white, not black
*/
if (index >= cm->Count)
return 0x00ffffff;
hibits = cm->ColorTable[index];
ULONG red8 = (hibits & 0x0f00) >> 4;
ULONG green8 = (hibits & 0x00f0);
ULONG blue8 = (hibits & 0x000f) << 4;
if (cm->Type > COLORMAP_TYPE_V1_2) {
UWORD lobits = cm->LowColorBits[index];
red8 |= (lobits & 0x0f00) >> 8;
green8 |= (lobits & 0x00f0) >> 4;
blue8 |= (lobits & 0x000f);
}
return (red8 << 16) | (green8 << 8) | blue8;
}
/* TurboPrint emulation helper hooks - convert from
* native formats to 0RGB32 longwords
*/
DISPATCHER(TPSlice)
{
struct DRPSourceMsg *drp = (struct DRPSourceMsg *)msg;
struct IODRPReq *io = (struct IODRPReq *)obj;
struct BitMap *tpbm = io->io_RastPort->BitMap;
UBYTE *src = tpbm->Planes[0];
ULONG *buf = drp->buf;
UWORD bpr = tpbm->BytesPerRow;
struct ColorMap *cm = io->io_ColorMap;
struct TPExtIODRP *tp = (struct TPExtIODRP *)io->io_Modes;
int w, h;
int bpp;
switch (tp->Mode) {
case TPFMT_Chunky8:
if (cm == NULL)
return 0;
bpp = 1;
break;
case TPFMT_RGB15:
case TPFMT_BGR15:
case TPFMT_RGB16:
case TPFMT_BGR16:
bpp = 2;
break;
case TPFMT_RGB24:
case TPFMT_BGR24:
bpp = 3;
break;
default:
return 0;
}
src += (bpr * drp->y);
for (h = 0; h < drp->height; h++, src += bpr) {
UBYTE *sref = src + drp->x * bpp;
for (w = 0; w < drp->width; w++ ) {
ULONG zrgb;
UWORD rgb15, rgb16;
switch (tp->Mode) {
case TPFMT_Chunky8:
zrgb = zrgbof(cm, *(sref++));
break;
case TPFMT_RGB15:
rgb15 = (*(sref++)) << 8;
rgb15 |= *(sref++);
goto rgb15;
case TPFMT_BGR15:
rgb15 = *(sref++);
rgb15 |= (*(sref++)) << 8;
rgb15:
zrgb = ((((rgb15 >> 10) & 0x1f)<<3) << 16) |
((((rgb15 >> 5) & 0x1f)<<3) << 8) |
((((rgb15 >> 0) & 0x1f)<<3) << 0);
break;
case TPFMT_RGB16:
rgb16 = (*(sref++)) << 8;
rgb16 |= *(sref++);
goto rgb16;
case TPFMT_BGR16:
rgb16 = *(sref++);
rgb16 |= (*(sref++)) << 8;
rgb16:
zrgb = ((((rgb16 >> 11) & 0x1f)<<3) << 16) |
((((rgb16 >> 5) & 0x3f)<<2) << 8) |
((((rgb16 >> 0) & 0x1f)<<3) << 0);
break;
case TPFMT_RGB24:
zrgb = (*(sref++) << 16);
zrgb |= (*(sref++) << 8);
zrgb |= (*(sref++) << 0);
break;
case TPFMT_BGR24:
zrgb = (*(sref++) << 0);
zrgb |= (*(sref++) << 8);
zrgb |= (*(sref++) << 16);
break;
default:
zrgb = 0x00ffffff;
break;
}
*(buf++) = zrgb;
}
}
return (buf - drp->buf);
}
MakeStaticHook(TPHook, TPSlice);
LONG Printer_Gfx_DumpRPort(struct IODRPReq *io, struct TagItem *tags)
{
struct PrinterData *pd = (struct PrinterData *)io->io_Device;
struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED;
struct PrinterGfxPrefs *gfx = &pd->pd_PUnit->pu_Prefs.pp_Gfx;
struct Hook *srcHook = NULL;
struct TagItem *tag;
struct BitMap *bm;
LONG aspectXsrc = 1, aspectYsrc = 1;
LONG aspectXdst = 1, aspectYdst = 1;
LONG scaleXsrc, scaleXdst;
LONG scaleYsrc, scaleYdst;
LONG prnMarginLeft, prnMarginRight;
LONG prnMarginTop, prnMarginBottom;
LONG prnX, prnY;
LONG prnW, prnH;
LONG err;
struct driverInfo di = {
.di_PrinterData = pd,
.di_ColorSize = sizeof(union colorEntry),
};
struct PrtInfo *pi = &di.pi;
UBYTE const dmatrix[] = {
1, 9, 3, 11,
13, 5, 15, 7,
4, 12, 2, 10,
16, 8, 14, 6,
};
D(bug("%s: io=%p, tags=%p\n", __func__, io, tags));
pi->pi_render = (APTR)ped->ped_Render;
if (!(ped->ped_PrinterClass & 1) || pi->pi_render == NULL) {
/* Not graphics. */
D(bug("\tNot a graphics printer (class = 0x%x)\n", ped->ped_PrinterClass));
return PDERR_NOTGRAPHICS;
}
/* Set up density and printer dimensions */
err = RENDER(io, io->io_Special, 0, PRS_PREINIT);
if (err < 0)
return err;
/* Get the source's aspect ratio */
if (io->io_Command == PRD_TPEXTDUMPRPORT) {
struct TPExtIODRP *tp = (APTR)io->io_Modes;
if (tp == NULL)
return PDERR_NOTGRAPHICS;
aspectXsrc = tp->PixAspX;
aspectYsrc = tp->PixAspY;
bug("tp->Mode = 0x%04x\n", tp->Mode);
switch (tp->Mode) {
case TPFMT_Chunky8:
case TPFMT_BGR15:
case TPFMT_BGR16:
case TPFMT_BGR24:
case TPFMT_RGB15:
case TPFMT_RGB16:
case TPFMT_RGB24:
srcHook = &TPHook;
break;
case TPFMT_CyberGraphX:
case TPFMT_BitPlanes:
case TPFMT_HAM:
case TPFMT_EHB:
srcHook = NULL; /* AROS BitMap object - we can handle this */
break;
default:
return PDERR_NOTGRAPHICS;
}
} else if (io->io_Modes != INVALID_ID) {
struct DisplayInfo dpyinfo;
if (GetDisplayInfoData(NULL, (APTR)&dpyinfo, sizeof(dpyinfo), DTAG_DISP, io->io_Modes)) {
aspectXsrc = dpyinfo.Resolution.x;
aspectYsrc = dpyinfo.Resolution.y;
}
}
/* Get the printer's aspect ratio */
aspectXdst = ped->ped_XDotsInch;
aspectYdst = ped->ped_YDotsInch;
while ((tag = LibNextTagItem(&tags))) {
switch (tag->ti_Tag) {
case DRPA_SourceHook:
srcHook = (struct Hook *)tag->ti_Data;
break;
case DRPA_AspectX:
aspectXsrc = tag->ti_Data;
break;
case DRPA_AspectY:
aspectYsrc = tag->ti_Data;
break;
default:
break;
}
}
if ((pd->pd_SegmentData->ps_Version >= 44) &&
(ped->ped_PrinterClass & PPCF_EXTENDED)) {
tags = ped->ped_TagList;
while ((tag = LibNextTagItem(&tags))) {
switch (tag->ti_Tag) {
case PRTA_8BitGuns:
di.di_8BitGuns = (BOOL)tag->ti_Data;
break;
case PRTA_ConvertSource:
di.di_ConvertSource = (BOOL)tag->ti_Data;
break;
case PRTA_FloydDithering:
di.di_FloydDithering = (BOOL)tag->ti_Data;
break;
case PRTA_AntiAlias:
di.di_AntiAlias = (BOOL)tag->ti_Data;
break;
case PRTA_ColorCorrection:
di.di_ColorCorrection = (BOOL)tag->ti_Data;
break;
case PRTA_NoIO:
/* Handled in driver.c */
break;
case PRTA_NewColor:
di.di_NewColor = (BOOL)tag->ti_Data;
break;
case PRTA_ColorSize:
di.di_ColorSize = (ULONG)tag->ti_Data;
break;
case PRTA_NoScaling:
di.di_NoScaling = (BOOL)tag->ti_Data;
break;
case PRTA_DitherNames:
case PRTA_ShadingNames:
case PRTA_ColorCorrect:
case PRTA_DensityInfo:
/* Handled in :Prefs/Printer */
break;
case PRTA_LeftBorder:
case PRTA_TopBorder:
case PRTA_MixBWColor:
case PRTA_Preferences:
/* Advice for applications */
break;
default:
break;
}
}
}
if (di.di_NewColor) {
di.di_ConvertSource = TRUE;
di.di_FloydDithering = TRUE;
di.di_AntiAlias = TRUE;
di.di_ColorCorrection = TRUE;
}
if (di.di_NoScaling) {
di.di_FloydDithering = TRUE;
di.di_AntiAlias = TRUE;
}
if (di.di_8BitGuns) {
di.di_FloydDithering = TRUE;
}
if (di.di_ColorSize < 3) {
D(bug("\tPRTA_ColorSize was %d - illegal!\n", di.di_ColorSize));
return PDERR_BADDIMENSION;
}
if (di.di_ColorSize < sizeof(union colorEntry) && !di.di_ConvertSource
&& !di.di_ColorCorrection) {
D(bug("\tPRTA_ColorSize of %d is illegal without PRTA_ConvertSource and PRTA_ColorCorrection!\n", di.di_ColorSize));
return PDERR_BADDIMENSION;
}
prnMarginLeft = gfx->pg_PrintXOffset;
prnMarginRight = 0;
prnMarginTop = gfx->pg_PrintYOffset;
prnMarginBottom = 0;
prnX = 0;
prnY = 0;
prnW = io->io_DestCols ? io->io_DestCols : io->io_SrcWidth;
prnH = io->io_DestRows ? io->io_DestRows : io->io_SrcHeight;
di.di_NumRows = ped->ped_NumRows; /* Rows/Stripe */
if (io->io_Special == 0) {
/* From the OS 3.9 autodocs for printer.device... */
if (prnW == 0 && prnH > 0) {
prnW = (ped->ped_MaxXDots - (prnMarginLeft + prnMarginRight));
} else if (prnW == 0 && prnH == 0) {
prnW = (ped->ped_MaxXDots - (prnMarginLeft + prnMarginRight));
prnH = prnW * aspectYsrc / aspectXsrc;
} else if (prnW > 0 && prnH == 0) {
prnH = prnW * aspectYsrc / aspectXsrc;
} else if (prnW < 0 && prnH > 0) {
prnW = io->io_SrcWidth * (-prnW) / prnH;
prnH = prnW * aspectYsrc / aspectXsrc;
}
}
if (io->io_Special & SPECIAL_MILCOLS) {
prnW = io->io_DestCols * ped->ped_XDotsInch / 1000;
}
if (io->io_Special & SPECIAL_MILROWS) {
prnH = io->io_DestRows * ped->ped_YDotsInch / 1000;
}
/* The following math relies on the fact that at
* ped_Max?Dots is limited to 65535 pixels:
* At even 1200dpi, 65535 pixels is over 100 inches!
*/
if (io->io_Special & SPECIAL_FRACCOLS) {
prnW = (ped->ped_MaxXDots * (io->io_DestCols >> 16)) >> 16;
}
if (io->io_Special & SPECIAL_FRACROWS) {
prnH = (ped->ped_MaxYDots * (io->io_DestRows >> 16)) >> 16;
}
/* Full page width (minus the margins) */
if (io->io_Special & SPECIAL_FULLCOLS) {
prnW = ped->ped_MaxXDots - (prnMarginLeft + prnMarginRight);
}
if (io->io_Special & SPECIAL_FULLROWS) {
prnH = ped->ped_MaxYDots - (prnMarginTop + prnMarginBottom);
}
if (io->io_Special & SPECIAL_ASPECT) {
prnH = prnH * aspectYdst / aspectXdst;
}
/* Autoshrink to maximum page size */
if (prnW > (ped->ped_MaxXDots - (prnMarginLeft + prnMarginRight ))) {
LONG delta = prnW - (ped->ped_MaxXDots - (prnMarginLeft + prnMarginRight ));
prnH = prnH - delta * prnH / prnW;
prnW = prnW - delta;
}
if (prnH > (ped->ped_MaxYDots - (prnMarginTop + prnMarginBottom ))) {
LONG delta = prnH - (ped->ped_MaxYDots - (prnMarginTop + prnMarginBottom ));
prnW = prnW - delta * prnW / prnH;
prnH = prnH - delta;
}
/* Centering */
if (io->io_Special & SPECIAL_CENTER) {
prnX = prnMarginLeft + (ped->ped_MaxXDots - (prnMarginLeft + prnMarginRight ) - prnW) / 2;
prnY = prnMarginTop + (ped->ped_MaxYDots - (prnMarginTop + prnMarginBottom) - prnH) / 2;
} else {
prnX = prnMarginLeft;
prnY = prnMarginTop;
}
D(bug("\tAspect: %dx%d %d:%d => %dx%d %d:%d\n",
io->io_SrcWidth, io->io_SrcHeight,
aspectXsrc, aspectYsrc,
prnW, prnH,
aspectXdst, aspectYdst));
/* Scaling calculations. */
scaleXsrc = io->io_SrcWidth;
scaleYsrc = io->io_SrcHeight;
scaleXdst = prnW;
scaleYdst = prnH;
while (scaleXsrc > 168383 || scaleXdst > 168383) {
scaleXsrc >>= 1;
scaleXdst >>= 1;
if (scaleXsrc == 0 || scaleXdst == 0) {
D(bug("\tCan't scale X from %dx%d to %dx%d\n", io->io_SrcWidth, io->io_SrcHeight, prnW, prnH));
return PDERR_BADDIMENSION;
}
}
while (scaleYsrc > 168383 || scaleYdst > 168383) {
scaleYsrc >>= 1;
scaleYdst >>= 1;
if (scaleYsrc == 0 || scaleYdst == 0) {
D(bug("\tCan't scale Y from %dx%d to %dx%d\n", io->io_SrcWidth, io->io_SrcHeight, prnW, prnH));
return PDERR_BADDIMENSION;
}
}
prnW = ScalerDiv(io->io_SrcWidth, scaleXdst, scaleXsrc);
prnH = ScalerDiv(io->io_SrcHeight, scaleYdst, scaleYsrc);
D(bug("\tScaling %dx%d (%d:%d) => %dx%d (%d:%d)\n",
io->io_SrcWidth, io->io_SrcHeight, scaleXsrc, scaleYsrc,
prnW, prnH, scaleXdst, scaleYdst));
io->io_DestCols = prnW;
io->io_DestRows = prnH;
/* If nothing to print, we're done! */
if (io->io_Special & SPECIAL_NOPRINT) {
D(bug("\tOh, SPECIAL_NOPRINT. Done.\n"));
return 0;
}
/* Set up the PrtInfo structure */
pi->pi_rp = io->io_RastPort;
pi->pi_ScaleX = NULL; /* New di.di_s should *not* be using this */
pi->pi_dmatrix = (UBYTE *) dmatrix;
pi->pi_width = prnW;
pi->pi_height = prnH;
pi->pi_xpos = prnX;
pi->pi_threshold = pd->pd_Preferences.PrintThreshold;
pi->pi_special = io->io_Special;
pi->pi_SourceHook = srcHook;
/* Initialize page for printing */
if (0 == (err = RENDER(io, prnW, prnH, PRS_INIT))) {
APTR pdata;
struct BitMap *src_bm = NULL;
if (di.di_NoScaling) {
prnW = io->io_SrcWidth;
prnH = io->io_SrcHeight;
scaleXsrc = scaleXdst = 1;
scaleYsrc = scaleYdst = 1;
}
/* Allocate a row for 24-bit RGB color information */
if (srcHook) {
APTR pdata;
struct RastPort src_rp;
InitRastPort(&src_rp);
/* In case we fail.. */
err = PDERR_INTERNALMEMORY;
if ((pdata = AllocMem(io->io_SrcWidth * 4, MEMF_PUBLIC))) {
if ((src_bm = AllocBitMap(io->io_SrcWidth, io->io_SrcHeight, 24, BMF_SPECIALFMT | SHIFT_PIXFMT(PIXFMT_RGB24) , io->io_RastPort->BitMap))) {
struct DRPSourceMsg msg;
LONG row;
src_rp.BitMap = src_bm;
msg.x = io->io_SrcX;
msg.y = io->io_SrcY;
msg.width = io->io_SrcWidth;
msg.buf = (APTR)pdata;
for (row = 0; row < io->io_SrcHeight; row++, msg.y++) {
/* Collect the next source row */
msg.height = 1;
CallHookA(srcHook, io, &msg);
/* Transfer to source bitmap */
WritePixelArray(pdata, 0, 0, io->io_SrcWidth * 4, &src_rp, 0, row, io->io_SrcWidth, 1, RECTFMT_0RGB32);
}
} else {
D(bug("\tCan't allocate bitmap to hold srcHook data (%d x %d)\n", io->io_SrcWidth, io->io_SrcHeight));
}
FreeMem(pdata, io->io_SrcWidth * 4);
} else {
D(bug("\tCan't allocate a %dx4 row to hold srcHook data\n", io->io_SrcWidth));
}
} else {
src_bm = io->io_RastPort->BitMap;
}
if (src_bm) {
struct RastPort rp;
InitRastPort(&rp);
if ((pdata = AllocMem(prnW * di.di_ColorSize, MEMF_PUBLIC))) {
pi->pi_ColorInt = pdata;
pi->pi_ColorIntSize = prnW * di.di_ColorSize;
if ((bm = AllocBitMap(prnW, prnH, src_bm->Depth, 0, src_bm))) {
/* Render it ourselves */
struct BitScaleArgs bsa = {
.bsa_SrcBitMap = src_bm,
.bsa_SrcX = io->io_SrcX,
.bsa_SrcY = io->io_SrcY,
.bsa_SrcWidth = io->io_SrcWidth,
.bsa_SrcHeight = io->io_SrcHeight,
.bsa_XSrcFactor = scaleXsrc,
.bsa_XDestFactor = scaleXdst,
.bsa_YSrcFactor = scaleYsrc,
.bsa_YDestFactor = scaleYdst,
.bsa_DestBitMap = bm,
};
LONG row;
LONG rleft = prnH;
BitMapScale(&bsa);
rp.BitMap = bm;
/* If we make a temporary source bitmap, we no longer need it.
*/
if (srcHook && src_bm) {
FreeBitMap(src_bm);
}
for (row = 0; row < prnH; rleft -= di.di_NumRows) {
LONG rows = (rleft > di.di_NumRows) ? di.di_NumRows : rleft;
int i;
for (i =0; i < rows; i++, row++) {
ReadPixelArray(pdata, 0, 0, prnW * di.di_ColorSize,
&rp, 0, row, prnW, 1,
di.di_ColorSize == 3 ?
RECTFMT_BGR24 :
RECTFMT_BGR032);
/* Convert from RGB to printer color space */
if (di.di_ConvertSource)
RENDER(pdata, prnW, 1, PRS_CONVERT);
else
pg_ConvertSource(&di, pdata, prnW);
/* Apply printer color space corrections */
if (di.di_ColorCorrection)
RENDER(pdata, prnW, 1, PRS_CORRECT);
else
pg_ColorCorrection(&di, pdata, prnW);
if (!di.di_FloydDithering)
pg_FloydDithering(&di, pdata, prnW);
RENDER(pi, 0, prnY + row, PRS_TRANSFER);
}
RENDER(0, 0, rows, PRS_FLUSH);
}
FreeBitMap(bm);
} else {
D(bug("\tCan't allocate a %dx%d bitmap for the scaled data\n", prnW, prnH));
}
FreeMem(pdata, prnW * di.di_ColorSize);
} else {
D(bug("\tCan't allocate a %d x %d byte transfer row\n", prnW, di.di_ColorSize));
}
} else {
D(bug("\tCan't find nor synthesize a source bitmap\n"));
}
RENDER((SIPTR)err, io->io_Special, 0, PRS_CLOSE);
}
return err;
}