/* * Copyright (C) 2012, The AROS Development Team. All rights reserved. * Author: Jason S. McMullan * * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1 * * Code related to Gfx printing */ #include #include #include #include #include #include #include #include #include #include #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_ColorSizedi_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; }