From 094535c010320967639e8e86f974d878e80baa72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Fri, 1 May 2015 16:13:57 +0200 Subject: Imported Upstream version 1.7.0 --- render/thscreen.c | 328 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 278 insertions(+), 50 deletions(-) (limited to 'render/thscreen.c') diff --git a/render/thscreen.c b/render/thscreen.c index c0a5548..8523e38 100644 --- a/render/thscreen.c +++ b/render/thscreen.c @@ -2,7 +2,7 @@ /* * render2d * - * Threshold screen pixel processing object. + * Threshold or Error diffusion screen pixel processing object. * (Simplified from DPS code) * * Author: Graeme W. Gill @@ -32,6 +32,8 @@ /* Configuration: */ #undef DEBUG +#undef CHECK_EXPECTED_ED_LEVELS /* Output expected quantized levels for checkking */ + /* ----------------------------------------------------------- */ #ifdef DEBUG @@ -46,29 +48,190 @@ #include "screens.h" /* Pre-generated screen patterns */ -/* Screen a single color plane */ -void screen_thscreens( /* Pointer to dither function */ +/* Threshold screen lines of multiplane pixels */ +void screen_thscreens( thscreens *t, /* Screening object pointer */ int width, int height, /* Width and height to screen in pixels */ int xoff, int yoff, /* Offset into screening pattern */ - unsigned char *in, /* Input pixel buffer */ - unsigned long ipitch, /* Increment between input lines */ unsigned char *out, /* Output pixel buffer */ - unsigned long opitch /* Increment between output lines */ + unsigned long opitch, /* Increment between output lines in components */ + unsigned char *in, /* Input pixel buffer */ + unsigned long ipitch /* Increment between input lines in components */ ) { int i; for (i = 0; i < t->np; i++) - t->sc[i]->screen(t->sc[i], width, height, xoff, yoff, in + 2 * i, t->np, ipitch, - out + i, t->np, opitch); + t->sc[i]->screen(t->sc[i], width, height, xoff, yoff, + out + i, t->np, opitch, + in + 2 * i, t->np, ipitch); +} + +/* Error diffusion screen lines of multiplane pixels */ +void screen_edscreens( + thscreens *t, /* Screening object pointer */ + int width, int height, /* Width and height to screen in pixels */ + int xoff, int yoff, /* Offset into screening pattern, [xoff + width < mxwidth] */ + unsigned char *out, /* Output pixel buffer */ + unsigned long opitch, /* Increment between output lines in components */ + unsigned char *_in, /* Input pixel buffer */ + unsigned long ipitch /* Increment between input lines in components */ +) { + unsigned short *in = (unsigned short *)_in; /* Pointer to input pixel sized values */ + unsigned short *ein = in + height * ipitch; /* Vertical end pixel marker */ + unsigned short *ein1; /* Horizontal end pixel markers */ + int xo, yo; /* Threshold screen offset */ + int x, j; + + /* Limit width to mxwidth */ + if ((xoff + width) > t->mxwidth) { + width = t->mxwidth - xoff; + if (width < 0) + return; + } + + /* If not sequential, clear error buffer */ + if (yoff != (t->lastyoff+1)) { + for (x = -1; x <= t->mxwidth; x++) { + for (j = 0; j < t->np; j++) + t->ebuf[j][x] = 0.0; + } + } + + /* Clear "next to right" error */ + for (j = 0; j < t->np; j++) { + t->ebuf[j][-2] = 0.0; + } + + t->lastyoff = yoff; + + /* For each line: */ + for (; in < ein; in += ipitch, ein1 += ipitch, out += opitch, yoff++) { + unsigned short *ip; /* Horizontal input pointer */ + unsigned char *op; /* Horizontal output pointer */ + int xinc, pinc; + + /* Do in serpentine order */ + if (yoff & 1) { + xinc = -1; + x = xoff + width-1; /* x is index into error buffer */ + pinc = -t->np; + ein1 = in + pinc; + ip = in + t->np * (width-1); + op = out + t->np * (width-1); + } else { + xinc = 1; + x = xoff; + pinc = t->np; + ein1 = in + t->np * width; + ip = in; + op = out; + } + + /* For each pixel */ + for (; ip != ein1; ip += pinc, op += pinc, x += xinc) { + double ov[THMXCH2D], tv[THMXCH2D], ev[THMXCH2D]; + + /* For each plane */ + for (j = 0; j < t->np; j++) { + tv[j] = t->luts[j][ip[j]] / 65535.0; /* 0.0 - 1.0 value */ + + /* Value + accumulated error */ + ov[j] = tv[j] = tv[j] + t->ebuf[j][x]; + + /* Limit */ + if (ov[j] > 1.0) + ov[j] = 1.0; + else if (ov[j] < 0.0) + ov[j] = 0.0; + + /* Output encode */ + op[j] = t->oevalues[(int)(ov[j] * (t->oelev-1.0) + 0.5)]; + } + +#ifdef CHECK_EXPECTED_ED_LEVELS +#pragma message("######### render/thscreen.c CHECK_EXPECTED_ED_LEVELS defined ! ##") + // Put expected values in output to check levels + t->quant(t->qcntx, ev, ov); + for (j = 0; j < t->np; j++) + op[j] = t->oevalues[(int)(ev[j] * (t->oelev-1.0) + 0.5)]; +#endif + + /* Quantize to values that it actually will be */ + if (t->quant != NULL) + t->quant(t->qcntx, ov, ov); + else { + for (j = 0; j < t->np; j++) + ov[j] = floor(ov[j] * (t->oelev-1) + 0.5)/(t->oelev-1.0); + } + + /* Compute the error to the target */ + for (j = 0; j < t->np; j++) { + + /* Error to target */ + ev[j] = tv[j] - ov[j]; + } + + /* Distribute the error */ + for (j = 0; j < t->np; j++) { +#ifdef NEVER + /* Classic error diffusion */ + t->ebuf[j][x-xinc] += 0.1875 * ev[j]; /* Lower left */ + t->ebuf[j][x] = t->ebuf[j][-2] + 0.3125 * ev[j]; /* Lower */ + t->ebuf[j][-2] = 0.0625 * ev[j]; /* Lower right */ + t->ebuf[j][x+xinc] += 0.4375 * ev[j]; /* Right */ +#else + /* Using random placement error distribution */ + double rav; + int ii; + t->so->next(t->so, &rav); /* For some order */ + rav *= 4.0; + rav += d_rand(0.0, 2.5); /* For some randomness */ + ii = (int)(rav); + if (ii > 3) + ii -= 4; + t->ebuf[j][x] = t->ebuf[j][-2]; + t->ebuf[j][-2] = 0.0; + switch (ii) { + case 0: + t->ebuf[j][x-xinc] += ev[j]; /* Lower left */ + break; + case 1: + t->ebuf[j][x] += ev[j]; /* Lower */ + break; + case 2: + t->ebuf[j][-2] += ev[j]; /* Lower right */ + break; + case 3: + t->ebuf[j][x+xinc] += ev[j]; /* Right */ + break; + } +#endif + } + } + } } /* Delete a thscreens */ void del_thscreens(thscreens *t) { int i; - for (i = 0; i < t->np; i++) - t->sc[i]->del(t->sc[i]); - free(t->sc); + if (t->sc != NULL) { + for (i = 0; i < t->np; i++) { + if (t->sc[i] != NULL) + t->sc[i]->del(t->sc[i]); + } + free(t->sc); + } + if (t->ebuf != NULL) { + free_fmatrix(t->ebuf, 0, t->np-1, -2, t->mxwidth); + } + + if (t->luts != NULL) { + free_imatrix(t->luts, 0, t->np-1, 0, 65535); + } + + if (t->so != NULL) + t->so->del(t->so); + free(t); } @@ -77,7 +240,7 @@ thscreens *new_thscreens( int exact, /* Return only exact matches */ int nplanes, /* Number of planes to screen */ double asp, /* Target aspect ratio (== dpiX/dpiY) */ - int size, /* Target size */ + int size, /* Target screen size */ sc_iencoding ie, /* Input encoding - must be scie_16 */ int oebpc, /* Output encoding bits per component - must be 8 */ int oelev, /* Output encoding levels. Must be <= 2 ^ oebpc */ @@ -85,8 +248,12 @@ thscreens *new_thscreens( /* Must be oelev entries. Default is 0 .. oelev-1 */ sc_oorder oo, /* Output bit ordering */ double overlap, /* Overlap between levels, 0 - 1.0 */ + int mxwidth, /* max width in pixels of raster to be screened */ void **cntx, /* List of contexts for lookup table callback */ - double (**lutfunc)(void *cntx, double in) /* List of callback function, NULL if none */ + double (**lutfunc)(void *cntx, double in), /* List of callback functions, NULL if none */ + int edif, /* nz if using error diffusion */ + void (*quant)(void *qcntx, double *out, double *in), /* optional quantization func. for edif */ + void *qcntx ) { thscreens *t; int i, bi = -1; @@ -115,18 +282,40 @@ thscreens *new_thscreens( } t->np = nplanes; /* Number of planes */ + t->edif = edif; /* Error diffusion */ + t->quant = quant; /* Optional quantization function */ + t->qcntx = qcntx; - DBG(("thscreens no planes = %d\n",t->np)); + t->mxwidth = mxwidth; + t->lastyoff = -1; - t->screen = screen_thscreens; - t->del = del_thscreens; + /* Allocate and initialise a next line error buffer. */ + /* we allow 2 extra locations for pixels to the left and right of the current one: */ + /* [-1] for the one to the below left when we are at x = 0, */ + /* [-2] for the one below right, before we use [x] */ + if (t->edif) + t->ebuf = fmatrixz(0, t->np-1, -2, t->mxwidth); - if ((t->sc = malloc(sizeof(thscreen *) * t->np)) == NULL) { - free(t); - DBG(("thscreens: malloc of thscreens->sc[] failed\n")); - return NULL; + t->oebpc = oebpc; + t->oelev = oelev; + if (oevalues != NULL) { + for (i = 0; i < t->oelev; i++) { + if (oevalues[i] >= (1 << t->oebpc)) { + DBG(("new_thscreens() oevalues[%d] value %d can't fit in %d bits\n",i,oevalues[i],t->oebpc)); + free(t); + return NULL; + } + t->oevalues[i] = oevalues[i]; + } + } else { + for (i = 0; i < t->oelev; i++) + t->oevalues[i] = i; } + DBG(("thscreens no planes = %d\n",t->np)); + + t->del = del_thscreens; + DBG(("thscreens: searching amongst %d screens, exact = %d\n",NO_SCREENS,exact)); DBG(("thscreens: looking for non-exact match\n")); @@ -163,57 +352,96 @@ thscreens *new_thscreens( if (bi < 0) /* Strange */ return NULL; - /* Create each screening object from one defined screen. */ - /* Use the 0'th plane screen */ - /* Stagger the screens with a round of 9 offset */ - for (i = 0; i < t->np; i++) { - int xoff = ((i % 3) * screens[bi].width)/3; - int yoff = (((i/3) % 3) * screens[bi].height)/3; - void *cx = NULL; - double (*lf)(void *cntx, double in) = 0; - if (cntx != NULL) - cx = cntx[i]; - if (lutfunc != NULL) - lf = lutfunc[i]; - - DBG(("thscreens: creating plane %d/%d thscreen, offset %d %d\n",i,t->np,xoff,yoff)); - if ((t->sc[i] = new_thscreen(screens[bi].width, screens[bi].height, xoff, yoff, - screens[bi].asp, swap, screens[bi].list[0], - ie, oebpc, oelev, oevalues, oo, overlap, - cx, lf)) == NULL) { - for (--i; i >= 0; i--) - t->sc[i]->del(t->sc[i]); - free(t->sc); + if (t->edif) { + int j; + int npix; + + t->screen = screen_edscreens; + + t->luts = imatrix(0, t->np-1, 0, 65535); + + /* Create a suitable LUT from the given function */ + /* Input is either 8 or 16 bits, output is always 16 bits */ + for (j = 0; j < t->np; j++) { + for (i = 0; i < 65536; i++) { + if (lutfunc != NULL && lutfunc[j] != NULL) { + double v = i/65535.0; + v = lutfunc[j](cntx[j], v); + t->luts[j][i] = (int)(v * 65535.0 + 0.5); + } else + t->luts[j][i] = i; + } + } + + if ((t->so = new_sobol(1)) == NULL) { + DBG(("thscreens: new_sobol() failed\n")); + return NULL; + } + + + } else { + + t->screen = screen_thscreens; + + if ((t->sc = malloc(sizeof(thscreen *) * t->np)) == NULL) { free(t); - DBG(("thscreens: new_thscreen() failed\n")); + DBG(("thscreens: malloc of thscreens->sc[] failed\n")); return NULL; } + + /* Create each screening object from one defined screen. */ + /* Use the 0'th plane screen */ + /* Stagger the screens with a round of 9 offset */ + for (i = 0; i < t->np; i++) { + int xoff = ((i % 3) * screens[bi].width)/3; + int yoff = (((i/3) % 3) * screens[bi].height)/3; + void *cx = NULL; + double (*lf)(void *cntx, double in) = 0; + if (cntx != NULL) + cx = cntx[i]; + if (lutfunc != NULL) + lf = lutfunc[i]; + + DBG(("thscreens: creating plane %d/%d thscreen, offset %d %d\n",i,t->np,xoff,yoff)); + if ((t->sc[i] = new_thscreen(screens[bi].width, screens[bi].height, xoff, yoff, + screens[bi].asp, swap, screens[bi].list[0], + ie, oebpc, oelev, oevalues, oo, overlap, + cx, lf)) == NULL) { + for (--i; i >= 0; i--) + t->sc[i]->del(t->sc[i]); + free(t->sc); + free(t); + DBG(("thscreens: new_thscreen() failed\n")); + return NULL; + } + } } DBG(("thscreens: returning nonexact match\n")); + return t; } /* ----------------------------------------------------------- */ -/* The kernel screening routin */ +/* The kernel stocastic screening routine */ void thscreen16_8( struct _thscreen *t, /* Screening object pointer */ int width, int height, /* Width and height to screen in pixels */ int xoff, int yoff, /* Offset into screening pattern (must be +ve) */ - unsigned char *_in, /* Input pixel buffer */ - unsigned long ipinc, /* Increment between input pixels */ - unsigned long ipitch, /* Increment between input lines */ unsigned char *out, /* Output pixel buffer */ - unsigned long opinc, /* Increment between output pixels */ - unsigned long opitch /* Increment between output lines */ + unsigned long opinc, /* Increment between output pixels in components */ + unsigned long opitch, /* Increment between output lines in components */ + unsigned char *_in, /* Input pixel buffer */ + unsigned long ipinc, /* Increment between input pixels in components */ + unsigned long ipitch /* Increment between input lines in components */ ) { unsigned short *in = (unsigned short *)_in; /* Pointer to input pixel sized values */ int *lut = t->lut; /* Copy of 8 or 16 -> 16 bit lookup table */ + unsigned short *ein = in + height * ipitch; /* Vertical end pixel marker */ + unsigned short *ein1; /* Horizontal end pixel markers */ unsigned char **oth, **eth; /* Current lines start, origin and end in screening table. */ int thtsize; /* Overall size of threshold table */ unsigned char **eeth; /* Very end of threshold table */ - unsigned short *ein = in + height * ipitch; /* Vertical end pixel marker */ - unsigned short *ein1; /* Horizontal end pixel markers */ { unsigned char **sth; /* Start point of line intable */ -- cgit v1.2.3