store the pre-alphacomposit hook and allow it to be queried.
[AROS.git] / workbench / devs / printer / gfx.c
blobb98e75551f1d9f173c3cc92d8dde4e33d4e065ec
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
7 * Code related to Gfx printing
8 */
10 #include <string.h>
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"
28 struct driverInfo {
29 struct PrtInfo pi;
30 struct PrinterData *di_PrinterData;
31 BOOL di_8BitGuns;
32 BOOL di_ConvertSource;
33 BOOL di_FloydDithering;
34 BOOL di_AntiAlias;
35 BOOL di_ColorCorrection;
36 BOOL di_NewColor;
37 BOOL di_NoScaling;
38 LONG di_ColorSize;
39 LONG di_NumRows;
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;
52 LONG x;
54 if (di->di_ColorSize < sizeof(union colorEntry)) {
55 D(bug("\tdi->di_ColorSize<sizeof(union colorEntry)\n"));
56 return;
59 for (x = 0; x < width; x++, pdata += di->di_ColorSize) {
60 union colorEntry *ce = (APTR) pdata;
61 UBYTE r, g, b, w;
63 r = ce->colorByte[PCMRED];
64 g = ce->colorByte[PCMGREEN];
65 b = ce->colorByte[PCMBLUE];
67 /* Find largest white*/
68 w = (r > g) ? r : g;
69 w = (b > w) ? b : w;
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)) {
78 r = ~r;
79 g = ~g;
80 b = ~b;
81 w = ~w;
84 if (!di->di_8BitGuns) {
85 r >>= 4;
86 g >>= 4;
87 b >>= 4;
88 w >>= 4;
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)
114 UWORD hibits;
116 /* For invalid entries, print white, not black
118 if (index >= cm->Count)
119 return 0x00ffffff;
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
141 DISPATCHER(TPSlice)
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;
151 int w, h;
152 int bpp;
154 switch (tp->Mode) {
155 case TPFMT_Chunky8:
156 if (cm == NULL)
157 return 0;
158 bpp = 1;
159 break;
160 case TPFMT_RGB15:
161 case TPFMT_BGR15:
162 case TPFMT_RGB16:
163 case TPFMT_BGR16:
164 bpp = 2;
165 break;
166 case TPFMT_RGB24:
167 case TPFMT_BGR24:
168 bpp = 3;
169 break;
170 default:
171 return 0;
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++ ) {
178 ULONG zrgb;
179 UWORD rgb15, rgb16;
181 switch (tp->Mode) {
182 case TPFMT_Chunky8:
183 zrgb = zrgbof(cm, *(sref++));
184 break;
185 case TPFMT_RGB15:
186 rgb15 = (*(sref++)) << 8;
187 rgb15 |= *(sref++);
188 goto rgb15;
189 case TPFMT_BGR15:
190 rgb15 = *(sref++);
191 rgb15 |= (*(sref++)) << 8;
192 rgb15:
193 zrgb = ((((rgb15 >> 10) & 0x1f)<<3) << 16) |
194 ((((rgb15 >> 5) & 0x1f)<<3) << 8) |
195 ((((rgb15 >> 0) & 0x1f)<<3) << 0);
196 break;
197 case TPFMT_RGB16:
198 rgb16 = (*(sref++)) << 8;
199 rgb16 |= *(sref++);
200 goto rgb16;
201 case TPFMT_BGR16:
202 rgb16 = *(sref++);
203 rgb16 |= (*(sref++)) << 8;
204 rgb16:
205 zrgb = ((((rgb16 >> 11) & 0x1f)<<3) << 16) |
206 ((((rgb16 >> 5) & 0x3f)<<2) << 8) |
207 ((((rgb16 >> 0) & 0x1f)<<3) << 0);
208 break;
209 case TPFMT_RGB24:
210 zrgb = (*(sref++) << 16);
211 zrgb |= (*(sref++) << 8);
212 zrgb |= (*(sref++) << 0);
213 break;
214 case TPFMT_BGR24:
215 zrgb = (*(sref++) << 0);
216 zrgb |= (*(sref++) << 8);
217 zrgb |= (*(sref++) << 16);
218 break;
219 default:
220 zrgb = 0x00ffffff;
221 break;
224 *(buf++) = zrgb;
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;
239 struct TagItem *tag;
240 struct BitMap *bm;
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;
247 LONG prnX, prnY;
248 LONG prnW, prnH;
249 LONG err;
250 struct driverInfo di = {
251 .di_PrinterData = pd,
252 .di_ColorSize = sizeof(union colorEntry),
254 struct PrtInfo *pi = &di.pi;
255 UBYTE const dmatrix[] = {
256 1, 9, 3, 11,
257 13, 5, 15, 7,
258 4, 12, 2, 10,
259 16, 8, 14, 6,
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) {
266 /* Not graphics. */
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);
273 if (err < 0)
274 return err;
276 /* Get the source's aspect ratio */
277 if (io->io_Command == PRD_TPEXTDUMPRPORT) {
278 struct TPExtIODRP *tp = (APTR)io->io_Modes;
279 if (tp == NULL)
280 return PDERR_NOTGRAPHICS;
281 aspectXsrc = tp->PixAspX;
282 aspectYsrc = tp->PixAspY;
283 bug("tp->Mode = 0x%04x\n", tp->Mode);
284 switch (tp->Mode) {
285 case TPFMT_Chunky8:
286 case TPFMT_BGR15:
287 case TPFMT_BGR16:
288 case TPFMT_BGR24:
289 case TPFMT_RGB15:
290 case TPFMT_RGB16:
291 case TPFMT_RGB24:
292 srcHook = &TPHook;
293 break;
294 case TPFMT_CyberGraphX:
295 case TPFMT_BitPlanes:
296 case TPFMT_HAM:
297 case TPFMT_EHB:
298 srcHook = NULL; /* AROS BitMap object - we can handle this */
299 break;
300 default:
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;
320 break;
321 case DRPA_AspectX:
322 aspectXsrc = tag->ti_Data;
323 break;
324 case DRPA_AspectY:
325 aspectYsrc = tag->ti_Data;
326 break;
327 default:
328 break;
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) {
337 case PRTA_8BitGuns:
338 di.di_8BitGuns = (BOOL)tag->ti_Data;
339 break;
340 case PRTA_ConvertSource:
341 di.di_ConvertSource = (BOOL)tag->ti_Data;
342 break;
343 case PRTA_FloydDithering:
344 di.di_FloydDithering = (BOOL)tag->ti_Data;
345 break;
346 case PRTA_AntiAlias:
347 di.di_AntiAlias = (BOOL)tag->ti_Data;
348 break;
349 case PRTA_ColorCorrection:
350 di.di_ColorCorrection = (BOOL)tag->ti_Data;
351 break;
352 case PRTA_NoIO:
353 /* Handled in driver.c */
354 break;
355 case PRTA_NewColor:
356 di.di_NewColor = (BOOL)tag->ti_Data;
357 break;
358 case PRTA_ColorSize:
359 di.di_ColorSize = (ULONG)tag->ti_Data;
360 break;
361 case PRTA_NoScaling:
362 di.di_NoScaling = (BOOL)tag->ti_Data;
363 break;
364 case PRTA_DitherNames:
365 case PRTA_ShadingNames:
366 case PRTA_ColorCorrect:
367 case PRTA_DensityInfo:
368 /* Handled in :Prefs/Printer */
369 break;
370 case PRTA_LeftBorder:
371 case PRTA_TopBorder:
372 case PRTA_MixBWColor:
373 case PRTA_Preferences:
374 /* Advice for applications */
375 break;
376 default:
377 break;
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;
410 prnMarginRight = 0;
411 prnMarginTop = gfx->pg_PrintYOffset;
412 prnMarginBottom = 0;
414 prnX = 0;
415 prnY = 0;
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;
467 prnW = prnW - delta;
470 if (prnH > (ped->ped_MaxYDots - (prnMarginTop + prnMarginBottom ))) {
471 LONG delta = prnH - (ped->ped_MaxYDots - (prnMarginTop + prnMarginBottom ));
472 prnW = prnW - delta * prnW / prnH;
473 prnH = prnH - delta;
476 /* Centering */
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;
480 } else {
481 prnX = prnMarginLeft;
482 prnY = prnMarginTop;
485 D(bug("\tAspect: %dx%d %d:%d => %dx%d %d:%d\n",
486 io->io_SrcWidth, io->io_SrcHeight,
487 aspectXsrc, aspectYsrc,
488 prnW, prnH,
489 aspectXdst, aspectYdst));
491 /* Scaling calculations. */
492 scaleXsrc = io->io_SrcWidth;
493 scaleYsrc = io->io_SrcHeight;
494 scaleXdst = prnW;
495 scaleYdst = prnH;
497 while (scaleXsrc > 168383 || scaleXdst > 168383) {
498 scaleXsrc >>= 1;
499 scaleXdst >>= 1;
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) {
507 scaleYsrc >>= 1;
508 scaleYdst >>= 1;
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"));
530 return 0;
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;
537 pi->pi_width = prnW;
538 pi->pi_height = prnH;
539 pi->pi_xpos = prnX;
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))) {
546 APTR pdata;
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 */
557 if (srcHook) {
558 APTR pdata;
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;
567 LONG row;
569 src_rp.BitMap = src_bm;
571 msg.x = io->io_SrcX;
572 msg.y = io->io_SrcY;
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 */
578 msg.height = 1;
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);
583 } else {
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);
587 } else {
588 D(bug("\tCan't allocate a %dx4 row to hold srcHook data\n", io->io_SrcWidth));
590 } else {
591 src_bm = io->io_RastPort->BitMap;
594 if (src_bm) {
595 struct RastPort rp;
596 InitRastPort(&rp);
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,
615 LONG row;
616 LONG rleft = prnH;
618 BitMapScale(&bsa);
619 rp.BitMap = bm;
621 /* If we make a temporary source bitmap, we no longer need it.
623 if (srcHook && src_bm) {
624 FreeBitMap(src_bm);
627 for (row = 0; row < prnH; rleft -= di.di_NumRows) {
628 LONG rows = (rleft > di.di_NumRows) ? di.di_NumRows : rleft;
629 int i;
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 ?
634 RECTFMT_BGR24 :
635 RECTFMT_BGR032);
637 /* Convert from RGB to printer color space */
638 if (di.di_ConvertSource)
639 RENDER(pdata, prnW, 1, PRS_CONVERT);
640 else
641 pg_ConvertSource(&di, pdata, prnW);
643 /* Apply printer color space corrections */
644 if (di.di_ColorCorrection)
645 RENDER(pdata, prnW, 1, PRS_CORRECT);
646 else
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);
656 FreeBitMap(bm);
657 } else {
658 D(bug("\tCan't allocate a %dx%d bitmap for the scaled data\n", prnW, prnH));
660 FreeMem(pdata, prnW * di.di_ColorSize);
661 } else {
662 D(bug("\tCan't allocate a %d x %d byte transfer row\n", prnW, di.di_ColorSize));
664 } else {
665 D(bug("\tCan't find nor synthesize a source bitmap\n"));
668 RENDER((SIPTR)err, io->io_Special, 0, PRS_CLOSE);
671 return err;