~ubuntu-branches/ubuntu/saucy/argyll/saucy

« back to all changes in this revision

Viewing changes to render/thscreen.c

  • Committer: Package Import Robot
  • Author(s): Christian Marillat
  • Date: 2012-04-25 07:46:07 UTC
  • mfrom: (1.2.2) (13.1.15 sid)
  • Revision ID: package-import@ubuntu.com-20120425074607-yjqadetw8kum9skc
Tags: 1.4.0-4
Should Build-Depends on libusb-dev (Closes: #670329).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * render2d
 
4
 *
 
5
 * Threshold screen pixel processing object.
 
6
 * (Simplified from DPS code)
 
7
 *
 
8
 * Author:  Graeme W. Gill
 
9
 * Date:    8/9/2005
 
10
 * Version: 1.00
 
11
 *
 
12
 * Copyright 2005, 2012 Graeme W. Gill
 
13
 * All rights reserved.
 
14
 * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
 
15
 * see the License.txt file for licencing details.
 
16
 *
 
17
 */
 
18
 
 
19
#include <stdio.h>
 
20
#include <stdlib.h>
 
21
#include <stdarg.h>
 
22
#include <fcntl.h>
 
23
#include <string.h>
 
24
#include <math.h>
 
25
#include "aconfig.h"
 
26
#include "numlib.h"
 
27
//#include "icc.h"
 
28
#include "sort.h"
 
29
//#include "xcolorants.h"
 
30
#include "thscreen.h"
 
31
 
 
32
/* Configuration: */
 
33
#undef DEBUG
 
34
 
 
35
/* ----------------------------------------------------------- */
 
36
 
 
37
#ifdef DEBUG
 
38
# define DBG(text) printf text ; fflush(stdout);
 
39
#else
 
40
# define DBG(text) 
 
41
#endif
 
42
 
 
43
/* ----------------------------------------------------------- */
 
44
/* Setup a set of screens */
 
45
/* Screen data is used that best matches the requested parameters. */
 
46
 
 
47
#include "screens.h"    /* Pre-generated screen patterns */
 
48
 
 
49
/* Screen a single color plane */
 
50
void screen_thscreens(                  /* Pointer to dither function */
 
51
        thscreens *t,                   /* Screening object pointer */
 
52
        int width, int height,  /* Width and height to screen in pixels */
 
53
        int xoff, int yoff,             /* Offset into screening pattern */
 
54
        unsigned char *in,              /* Input pixel buffer */
 
55
        unsigned long ipitch,   /* Increment between input lines */
 
56
        unsigned char *out,             /* Output pixel buffer */
 
57
        unsigned long opitch    /* Increment between output lines */
 
58
) {
 
59
        int i;
 
60
        for (i = 0; i < t->np; i++)
 
61
                t->sc[i]->screen(t->sc[i], width, height, xoff, yoff, in + 2 * i, t->np, ipitch,
 
62
                                                                      out + i, t->np, opitch);
 
63
}
 
64
 
 
65
/* Delete a thscreens */
 
66
void del_thscreens(thscreens *t) {
 
67
        int i;
 
68
 
 
69
        for (i = 0; i < t->np; i++)
 
70
                t->sc[i]->del(t->sc[i]);
 
71
        free(t->sc);
 
72
        free(t);
 
73
}
 
74
 
 
75
/* Create a new thscreens object matching the parameters */
 
76
thscreens *new_thscreens(
 
77
        int exact,                              /* Return only exact matches */
 
78
        int nplanes,                    /* Number of planes to screen */
 
79
        double asp,                             /* Target aspect ratio (== dpiX/dpiY) */
 
80
        int size,                               /* Target size */
 
81
        sc_iencoding ie,                /* Input encoding - must be scie_16 */
 
82
        int oebpc,                              /* Output encoding bits per component - must be 8 */
 
83
        int oelev,                              /* Output encoding levels. Must be <= 2 ^ oebpc */
 
84
        int *oevalues,                  /* Optional output encoding values for each level */
 
85
                                                        /* Must be oelev entries. Default is 0 .. oelev-1 */
 
86
        sc_oorder oo,                   /* Output bit ordering */
 
87
        double overlap,                 /* Overlap between levels, 0 - 1.0 */
 
88
        void   **cntx,                  /* List of contexts for lookup table callback */
 
89
        double (**lutfunc)(void *cntx, double in)       /* List of callback function, NULL if none */
 
90
) {
 
91
        thscreens *t;
 
92
        int i, bi = -1;
 
93
        double bamatch;         /* Best aspect match */
 
94
        int bsize = 100000;     /* Best size match */
 
95
        int swap = 0;           /* width and height will need swapping */
 
96
        
 
97
        DBG(("thscreens: new called with:\n"));
 
98
        DBG((" nplanes = 0x%x\n",nplanes));
 
99
        DBG((" asp = %f\n",asp));
 
100
        DBG((" ie = %d\n",ie));
 
101
        DBG((" oebpc = %d\n",oebpc));
 
102
        DBG((" oelev = %d\n",oelev));
 
103
        DBG((" oo = %d\n",oo));
 
104
        DBG((" overlap = %f\n",overlap));
 
105
 
 
106
        if (asp < 1.0) {        /* All screens[] have asp >= 1.0 */
 
107
                asp = 1.0/asp;
 
108
                swap = 1;
 
109
                DBG(("thscreens: aspect swap needed\n"));
 
110
        }
 
111
 
 
112
        if ((t = (thscreens *)calloc(1, sizeof(thscreens))) == NULL) {
 
113
                DBG(("thscreens: malloc of thscreens failed\n"));
 
114
                return NULL;
 
115
        }
 
116
 
 
117
        t->np = nplanes;        /* Number of planes */
 
118
 
 
119
        DBG(("thscreens no planes = %d\n",t->np));
 
120
 
 
121
        t->screen = screen_thscreens;
 
122
        t->del = del_thscreens;
 
123
 
 
124
        if ((t->sc = malloc(sizeof(thscreen *) * t->np)) == NULL) {
 
125
                free(t);
 
126
                DBG(("thscreens: malloc of thscreens->sc[] failed\n"));
 
127
                return NULL;
 
128
        }
 
129
 
 
130
        DBG(("thscreens: searching amongst %d screens, exact = %d\n",NO_SCREENS,exact));
 
131
 
 
132
        DBG(("thscreens: looking for non-exact match\n"));
 
133
 
 
134
        /* Synthesise a set of screens from what's there */
 
135
        /* (Don't bother with matching the colorspace) */
 
136
        for (i = 0;i < NO_SCREENS; i++) {
 
137
                double thamatch;        /* This aspect match */
 
138
                int thsize;                     /* This size match */
 
139
 
 
140
                thamatch = asp/screens[i].asp;
 
141
                if (thamatch < 1.0)
 
142
                        thamatch = 1.0/thamatch;
 
143
 
 
144
                if (bi < 0 || (thamatch < bamatch)) {   /* No best or new best */
 
145
                        bamatch = thamatch;
 
146
                        bi = i;
 
147
                        DBG(("thscreens: new best with aspmatch %f\n",bamatch));
 
148
                        continue;                                               /* On to next */
 
149
                }
 
150
                if (thamatch > bamatch)                         /* Worse aspect match */
 
151
                        continue;
 
152
                /* Same on aspect ratio. Check size */
 
153
                thsize = size - screens[i].size;
 
154
                if (thsize < 0)
 
155
                        thsize = -thsize;
 
156
                if (thsize < bsize) {                           /* New better size match */
 
157
                        bsize = thsize;
 
158
                        bi = i;
 
159
                        DBG(("thscreens: new best with size %d\n",bsize));
 
160
                }
 
161
        }
 
162
 
 
163
        if (bi < 0)                     /* Strange */
 
164
                return NULL;
 
165
 
 
166
        /* Create each screening object from one defined screen. */
 
167
        /* Use the 0'th plane screen */
 
168
        /* Stagger the screens with a round of 9 offset */
 
169
        for (i = 0; i < t->np; i++) {
 
170
                int xoff = ((i % 3) * screens[bi].width)/3;
 
171
                int yoff = (((i/3) % 3) * screens[bi].height)/3;
 
172
                void   *cx = NULL;
 
173
                double (*lf)(void *cntx, double in) = 0;
 
174
                if (cntx != NULL)
 
175
                        cx = cntx[i];
 
176
                if (lutfunc != NULL)
 
177
                        lf = lutfunc[i];
 
178
 
 
179
                DBG(("thscreens: creating plane %d/%d thscreen, offset %d %d\n",i,t->np,xoff,yoff));
 
180
                if ((t->sc[i] = new_thscreen(screens[bi].width, screens[bi].height, xoff, yoff,
 
181
                                          screens[bi].asp, swap, screens[bi].list[0],
 
182
                                          ie, oebpc, oelev, oevalues, oo, overlap,
 
183
                                          cx, lf)) == NULL) {
 
184
                        for (--i; i >= 0; i--)
 
185
                                t->sc[i]->del(t->sc[i]);
 
186
                        free(t->sc);
 
187
                        free(t);
 
188
                        DBG(("thscreens: new_thscreen() failed\n"));
 
189
                        return NULL;
 
190
                }
 
191
        }
 
192
        DBG(("thscreens: returning nonexact match\n"));
 
193
        return t;
 
194
}
 
195
 
 
196
/* ----------------------------------------------------------- */
 
197
/* The kernel screening routin */
 
198
 
 
199
void thscreen16_8(
 
200
        struct _thscreen *t,    /* Screening object pointer */
 
201
        int width, int height,  /* Width and height to screen in pixels */
 
202
        int xoff, int yoff,             /* Offset into screening pattern (must be +ve) */
 
203
        unsigned char *_in,             /* Input pixel buffer */
 
204
        unsigned long ipinc,    /* Increment between input pixels */
 
205
        unsigned long ipitch,   /* Increment between input lines */
 
206
        unsigned char *out,             /* Output pixel buffer */
 
207
        unsigned long opinc,    /* Increment between output pixels */
 
208
        unsigned long opitch    /* Increment between output lines */
 
209
) {
 
210
        unsigned short *in = (unsigned short *)_in;     /* Pointer to input pixel sized values */
 
211
        int *lut = t->lut;                      /* Copy of 8 or 16 -> 16 bit lookup table */
 
212
        unsigned char **oth, **eth; /* Current lines start, origin and end in screening table. */
 
213
        int thtsize;                            /* Overall size of threshold table */
 
214
        unsigned char **eeth;           /* Very end of threshold table */
 
215
        unsigned short *ein = in + height * ipitch;     /* Vertical end pixel marker */
 
216
        unsigned short *ein1;                           /* Horizontal end pixel markers */
 
217
 
 
218
        {
 
219
                unsigned char **sth;                            /* Start point of line intable */
 
220
                sth = t->thp + (yoff % t->sheight) * t->twidth;
 
221
                oth = sth + (xoff % t->swidth);         /* Orgin of pattern to start from */
 
222
                eth = sth + t->swidth;                          /* Ending point to wrap back */
 
223
                thtsize = t->twidth * t->theight;
 
224
                eeth = t->thp + thtsize;                        /* very end of table */
 
225
        }
 
226
 
 
227
        ein1 = in + ipinc * width;
 
228
        
 
229
        /* For each line: */
 
230
        for (; in < ein; in += ipitch, ein1 += ipitch, out += opitch) {
 
231
                unsigned char **th = oth;       /* Threshold table origin */
 
232
                unsigned short *ip = in;        /* Horizontal input pointer */
 
233
                unsigned char *op = out;        /* Horizontal output pointer */
 
234
 
 
235
                /* Do pixels one output byte at a time */
 
236
                for (; ip < ein1; ip += ipinc, op += opinc) {
 
237
                        int tt = lut[*ip];
 
238
                        *op = (unsigned char)th[0][tt];
 
239
                        if (++th >= eth)
 
240
                                th -= t->swidth;
 
241
                }
 
242
 
 
243
                /* Advance screen table pointers with vertical wrap */
 
244
                oth += t->twidth;
 
245
                eth += t->twidth;
 
246
                if (eth > eeth) {
 
247
                        oth -= thtsize;
 
248
                        eth -= thtsize; 
 
249
                } 
 
250
        }
 
251
}
 
252
 
 
253
/* ----------------------------------------------------------- */
 
254
 
 
255
/* We're done with the screening object */
 
256
static void th_del(
 
257
        thscreen *t
 
258
) {
 
259
        if (t->lut != NULL)
 
260
                free(t->lut);
 
261
        if (t->thp != NULL)
 
262
                free(t->thp);
 
263
        free(t);
 
264
}
 
265
 
 
266
/* Create a new thscreen object */
 
267
/* Return NULL on error */
 
268
thscreen *new_thscreen(
 
269
        int width,                                      /* width in pixels of screen */
 
270
        int height,                                     /* Height in pixels of screen */
 
271
        int xoff, int yoff,                     /* Pattern offsets into width & height */
 
272
        double asp,                                     /* Aspect ratio of screen (== dpiX/dpiY) */
 
273
        int swap,                                       /* Swap X & Y to invert aspect ratio  & swap width/height */
 
274
        ccoord *thli,                           /* Pointer to list of threshold coordinates */
 
275
        sc_iencoding ie,                        /* Input encoding - must be scie_16 */
 
276
        int oebpc,                                      /* Output encoding bits per component - must be 8 */
 
277
        int oelev,                                      /* Output encoding levels. Must be <= 2 ^ oebpc */
 
278
        int *oevalues,                          /* Optional output encoding values for each level */
 
279
                                                                /* Must be oelev entries. Default is 0 .. oelev-1 */
 
280
        sc_oorder oo,                           /* Output bit ordering */
 
281
        double olap,                            /* Overlap between levels, 0 - 1.0 */
 
282
        void   *cntx,                           /* Context for LUT table callback */
 
283
        double (*lutfunc)(void *cntx, double in)        /* Callback function, NULL if none */
 
284
) {
 
285
        thscreen *t;            /* Object being created */
 
286
        int npix;                       /* Total pixels in screen */
 
287
        double mrang;           /* threshold modulation range */ 
 
288
        double **fthr;          /* Floating point threshold array */
 
289
        int i, j;
 
290
 
 
291
        DBG(("new_thscreen() called, oebpc = %d\n",oebpc));
 
292
        DBG(("new_thscreen() called, oelev = %d\n",oelev));
 
293
 
 
294
        /* Sanity check overlap */
 
295
        if (olap < 0.0)
 
296
                olap = 0.0;
 
297
        else if (olap > 1.0)
 
298
                olap = 1.0;
 
299
 
 
300
        /* Sanity check parameters */
 
301
        if (ie != scie_16) { 
 
302
                DBG(("new_thscreen() ie %d != scie_16\n",ie));
 
303
                return NULL;
 
304
        }
 
305
        if (oebpc != 8) { 
 
306
                DBG(("new_thscreen() oebpc %d != 8\n",oebpc));
 
307
                return NULL;
 
308
        }
 
309
 
 
310
        if (oelev < 2 || oelev > (1 << oebpc)) { 
 
311
                DBG(("new_thscreen() oelev %d > 2^%d = %d\n",oelev,1 << oebpc,oebpc));
 
312
                return NULL;
 
313
        }
 
314
 
 
315
        if ((t = (thscreen *)calloc(1, sizeof(thscreen))) == NULL) {
 
316
                DBG(("new_thscreen() calloc failed\n"));
 
317
                return NULL;
 
318
        }
 
319
 
 
320
        /* Instantiation parameters */
 
321
        t->ie = ie;
 
322
        t->oebpc = oebpc;
 
323
        t->oelev = oelev;
 
324
        if (oevalues != NULL) {
 
325
                for (i = 0; i < t->oelev; i++) {
 
326
                        if (oevalues[i] >= (1 << t->oebpc)) {
 
327
                                DBG(("new_thscreen() oevalues[%d] value %d can't fit in %d bits\n",i,oevalues[i],t->oebpc));
 
328
                                free(t);
 
329
                                return NULL;
 
330
                        }
 
331
                        t->oevalues[i] = oevalues[i];
 
332
                }
 
333
        } else {
 
334
                for (i = 0; i < t->oelev; i++)
 
335
                        t->oevalues[i] = i;
 
336
        }
 
337
 
 
338
        t->oo = oo;
 
339
        t->overlap;
 
340
 
 
341
        /* Create a suitable LUT from the given function */
 
342
        /* Input is either 8 or 16 bits, output is always 16 bits */
 
343
        DBG(("new_thscreen() about to create LUT\n"));
 
344
        if ((t->lut = (int *)malloc(sizeof(int) * 65536)) == NULL) {
 
345
                free(t);
 
346
                DBG(("new_thscreen() malloc of 16 bit LUT failed\n"));
 
347
                return NULL;
 
348
        }
 
349
        for (i = 0; i < 65536; i++) {
 
350
                if (lutfunc != NULL) {
 
351
                        double v = i/65535.0;
 
352
                        v = lutfunc(cntx, v);
 
353
                        t->lut[i] = (int)(v * 65535.0 + 0.5);
 
354
                } else
 
355
                        t->lut[i] = i;
 
356
        }
 
357
 
 
358
        /* Screen definition parameters */
 
359
        if (swap) {
 
360
                t->asp = 1.0/asp;
 
361
                t->swidth = height;
 
362
                t->sheight = width;
 
363
        } else {
 
364
                t->asp = asp;
 
365
                t->swidth = width;
 
366
                t->sheight = height;
 
367
        }
 
368
        DBG(("new_thscreen() target width %d, height %d, asp %f\n",t->swidth,t->sheight,t->asp));
 
369
        DBG(("new_thscreen() given width %d, height %d, asp %f\n",width,height,asp));
 
370
 
 
371
        npix = t->swidth * t->sheight;  /* Total pixels */
 
372
                                                        /* Allow for read of a words worth of pixels from within screen: */
 
373
        DBG(("new_thscreen() tot pix %d, lev %d, bpp %d\n",npix,t->oelev,t->oebpc));
 
374
 
 
375
        t->twidth = t->swidth + (8/t->oebpc) -1;
 
376
        t->theight = t->sheight;
 
377
 
 
378
        DBG(("new_thscreen() th table size = %d x %d\n",t->twidth,t->theight));
 
379
        DBG(("new_thscreen() about to turn screen list into float threshold matrix\n"));
 
380
 
 
381
        /* Convert the list of screen cells into a floating point threshold array */
 
382
        fthr = dmatrix(0, t->sheight-1, 0, t->swidth-1);        /* Temporary matrix */
 
383
        if (swap) {
 
384
                double tt = xoff;       /* Swap offsets to align with orientation */
 
385
                xoff = yoff;
 
386
                yoff = tt;
 
387
                for (i = 0; i < npix; i++)
 
388
                        fthr[thli[i].x][thli[i].y] = (double)(i/(npix - 1.0));
 
389
        } else {
 
390
                for (i = 0; i < npix; i++)
 
391
                        fthr[thli[i].y][thli[i].x] = (double)(i/(npix - 1.0));
 
392
        }
 
393
 
 
394
        /* The range that the screen has to modulate */
 
395
        /* over to cross all the thresholds evenly. */
 
396
        mrang = 65535.0/(t->oelev - 1.0); 
 
397
        DBG(("new_thscreen() raw modulation rande = %f\n",mrang));
 
398
 
 
399
        /* Modify the modulation range to accomodate any level overlap */
 
400
        if (olap > 0.0 && t->oelev > 2) {
 
401
                mrang = ((t->oelev - 2.0) * olap * mrang + 65535.0)/(t->oelev - 1.0);
 
402
                DBG(("new_thscreen() modulation adjusted for overlap = %f\n",mrang));
 
403
        }
 
404
 
 
405
        /* Init the threshold table. It holds the quantized, encoded output */
 
406
        /* values, allowing an input value offset by the screen to be */
 
407
        /* thresholded directly into the output value. We allow a guard band at */
 
408
        /* each end for the effects of the screen modulating the input value. */
 
409
 
 
410
        DBG(("new_thscreen() about to init threshold table\n"));
 
411
        t->tht = &t->_tht[32768];       /* base allows for -ve & +ve range */
 
412
        for (i = -32768; i < (2 * 65536) + 32768; i++) {
 
413
                if (i < mrang) {                                /* Lower guard band */
 
414
                        t->tht[i] = t->oevalues[0];
 
415
                } else if (i >= 65535) {                /* Upper guard band */
 
416
                        t->tht[i] = t->oevalues[t->oelev-1];
 
417
                } else {                                                /* Middle range */
 
418
                        t->tht[i] = t->oevalues[1 + (int)((t->oelev - 2.0) * (i - mrang)/(65535.0 - mrang))];
 
419
                }
 
420
        }
 
421
 
 
422
        /* Allocate the 2D table of pointers into the */
 
423
        /* threshold table that encodes the screen offset. */
 
424
        if ((t->thp = (unsigned char **)malloc(sizeof(unsigned char *)
 
425
                                               * t->twidth * t->theight)) == NULL) {
 
426
                free_dmatrix(fthr, 0, t->sheight-1, 0, t->swidth-1);
 
427
                free(t->lut);
 
428
                free(t);
 
429
                DBG(("new_thscreen() malloc of threshold pointer matrix failed\n"));
 
430
                return NULL;
 
431
        }
 
432
 
 
433
        /* Setup the threshold pointer array to point into the apropriate */
 
434
        /* point into the threshold array itself. This implicitly adds */
 
435
        /* the screen pattern offset value to the input before thresholding it. */
 
436
        /* The input screen offsets are applied at this point too. */
 
437
        DBG(("new_thscreen() about to init threshold pointer table\n"));
 
438
        for (i = 0; i < t->twidth; i++) {
 
439
                for (j = 0; j < t->theight; j++) {
 
440
                        double sov = fthr[(j+yoff) % t->sheight][(i+xoff) % t->swidth];
 
441
                        int    tho = (int)((mrang - 1.0) * (1.0 - sov) + 0.5);
 
442
                        t->thp[j * t->twidth + i] = &t->tht[tho];
 
443
                }
 
444
        }
 
445
        free_dmatrix(fthr, 0, t->sheight-1, 0, t->swidth-1);
 
446
 
 
447
        DBG(("new_thscreen() about to setup method pointers\n"));
 
448
 
 
449
        /* Methods */
 
450
        t->screen = thscreen16_8;
 
451
        t->del = th_del;
 
452
 
 
453
        DBG(("new_thscreen() done\n"));
 
454
        return t;
 
455
}
 
456
 
 
457
 
 
458
 
 
459
 
 
460
 
 
461
 
 
462
 
 
463
 
 
464
 
 
465
 
 
466
 
 
467
 
 
468
 
 
469
 
 
470
 
 
471
 
 
472
 
 
473
 
 
474