1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gxicolor.c 8677 2008-04-29 06:34:17Z mvrhel $ */
15
/* Color image rendering */
40
byte v[GS_IMAGE_MAX_COLOR_COMPONENTS];
41
#define BYTES_PER_BITS32 4
42
#define BITS32_PER_COLOR_SAMPLES\
43
((GS_IMAGE_MAX_COLOR_COMPONENTS + BYTES_PER_BITS32 - 1) / BYTES_PER_BITS32)
44
bits32 all[BITS32_PER_COLOR_SAMPLES]; /* for fast comparison */
47
/* ------ Strategy procedure ------ */
49
/* Check the prototype. */
50
iclass_proc(gs_image_class_4_color);
52
static irender_proc(image_render_color);
54
gs_image_class_4_color(gx_image_enum * penum)
56
if (penum->use_mask_color) {
58
* Scale the mask colors to match the scaling of each sample to
59
* a full byte, and set up the quick-filter parameters.
62
color_samples mask, test;
63
bool exact = penum->spp <= BYTES_PER_BITS32;
65
memset(&mask, 0, sizeof(mask));
66
memset(&test, 0, sizeof(test));
67
for (i = 0; i < penum->spp; ++i) {
71
gx_image_scale_mask_colors(penum, i);
72
v0 = (byte)penum->mask_color.values[2 * i];
73
v1 = (byte)penum->mask_color.values[2 * i + 1];
74
while ((v0 & match) != (v1 & match))
77
test.v[i] = v0 & match;
78
exact &= (v0 == match && (v1 | match) == 0xff);
80
penum->mask_color.mask = mask.all[0];
81
penum->mask_color.test = test.all[0];
82
penum->mask_color.exact = exact;
84
penum->mask_color.mask = 0;
85
penum->mask_color.test = ~0;
87
return &image_render_color;
90
/* ------ Rendering procedures ------ */
92
/* Test whether a color is transparent. */
94
mask_color_matches(const byte *v, const gx_image_enum *penum,
99
for (i = num_components * 2, v += num_components - 1; (i -= 2) >= 0; --v)
100
if (*v < penum->mask_color.values[i] ||
101
*v > penum->mask_color.values[i + 1]
107
/* Render a color image with 8 or fewer bits per sample. */
109
image_render_color(gx_image_enum *penum_orig, const byte *buffer, int data_x,
110
uint w, int h, gx_device * dev)
112
const gx_image_enum *const penum = penum_orig; /* const within proc */
113
gx_image_clue *const clues = penum_orig->clues; /* not const */
114
const gs_imager_state *pis = penum->pis;
115
gs_logical_operation_t lop = penum->log_op;
116
gx_dda_fixed_point pnext;
117
image_posture posture = penum->posture;
119
fixed pdyx, pdyy; /* edge of parallelogram */
121
const gs_color_space *pcs = penum->pcs;
122
cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
123
cs_proc_remap_concrete_color((*remap_concrete_color)) =
124
pcs->type->remap_concrete_color;
126
bool device_color = penum->device_color;
127
const gx_color_map_procs *cmap_procs = gx_get_cmap_procs(pis, dev);
128
bits32 mask = penum->mask_color.mask;
129
bits32 test = penum->mask_color.test;
130
gx_image_clue *pic = &clues[0];
131
#define pdevc (&pic->dev_color)
132
gx_image_clue *pic_next = &clues[1];
133
#define pdevc_next (&pic_next->dev_color)
134
gx_image_clue empty_clue;
135
gx_image_clue clue_temp;
136
int spp = penum->spp;
137
const byte *psrc_initial = buffer + data_x * spp;
138
const byte *psrc = psrc_initial;
139
const byte *rsrc = psrc + spp; /* psrc + spp at start of run */
140
fixed xrun; /* x ditto */
141
fixed yrun; /* y ditto */
142
int irun; /* int x/rrun */
143
color_samples run; /* run value */
144
color_samples next; /* next sample value */
145
const byte *bufend = psrc + w;
146
bool use_cache = spp * penum->bps <= 12;
147
int code = 0, mcode = 0;
148
gs_cie_icc * picc_info; /*used for detecting if image source color space is CIELAB. */
152
pnext = penum->dda.pixel0;
153
xrun = xprev = dda_current(pnext.x);
154
yrun = yprev = dda_current(pnext.y);
155
pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
156
pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
159
vci = penum->yci, vdi = penum->hci;
160
irun = fixed2int_var_rounded(xrun);
162
case image_landscape:
163
default: /* we don't handle skew -- treat as landscape */
164
vci = penum->xci, vdi = penum->wci;
165
irun = fixed2int_var_rounded(yrun);
169
if_debug5('b', "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
170
penum->y, data_x, w, fixed2float(xprev), fixed2float(yprev));
171
memset(&run, 0, sizeof(run));
172
memset(&next, 0, sizeof(next));
173
/* Ensure that we don't get any false dev_color_eq hits. */
175
set_nonclient_dev_color(&empty_clue.dev_color, gx_no_color_index);
178
cs_full_init_color(&cc, pcs);
179
run.v[0] = ~psrc[0]; /* force remap */
180
while (psrc < bufend) {
183
#define CLUE_HASH3(penum, next)\
184
&clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4)) & 255];
185
#define CLUE_HASH4(penum, next)\
186
&clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4) +\
187
(next.v[3] << 6)) & 255]
189
if (spp == 4) { /* may be CMYK or RGBA */
195
map4: if (posture != image_skewed && next.all[0] == run.all[0])
198
pic_next = CLUE_HASH4(penum, next);
199
if (pic_next->key == next.all[0])
202
* If we are really unlucky, pic_next == pic,
203
* so mapping this color would clobber the one
204
* we're about to use for filling the run.
206
if (pic_next == pic) {
210
pic_next->key = next.all[0];
212
/* Check for transparent color. */
213
if ((next.all[0] & mask) == test &&
214
(penum->mask_color.exact ||
215
mask_color_matches(next.v, penum, 4))
217
color_set_null(pdevc_next);
225
* We do not have support for DeviceN color and alpha.
227
cmap_procs->map_rgb_alpha
228
(byte2frac(next.v[0]), byte2frac(next.v[1]),
229
byte2frac(next.v[2]), byte2frac(next.v[3]),
230
pdevc_next, pis, dev,
231
gs_color_select_source);
235
* We can call the remap concrete_color for the colorspace
236
* directly since device_color is only true if the colorspace
239
frac_color[0] = byte2frac(next.v[0]);
240
frac_color[1] = byte2frac(next.v[1]);
241
frac_color[2] = byte2frac(next.v[2]);
242
frac_color[3] = byte2frac(next.v[3]);
243
remap_concrete_color(frac_color, pcs, pdevc_next, pis,
244
dev, gs_color_select_source);
247
decode_sample(next.v[3], cc, 3);
248
if_debug1('B', "[B]cc[3]=%g\n", cc.paint.values[3]);
249
do3: if(spp == 3 && pcs->type->index == gs_color_space_index_CIEICC)
251
/* It is 3 channel with an ICC profile.
252
We need to check if it is an LAB image */
254
picc_info = pcs->params.icc.picc_info;
256
if( picc_info->plu->e_inSpace == icSigLabData )
259
/* It is a CIELAB image. For now, put in true CIELAB float values rather than normalized 0 to 1 floats */
260
/* concretization will handle the proper conversion this way */
262
decode_sample(next.v[0], cc, 0);
263
cc.paint.values[0]*=100.0;
264
decode_sample(next.v[1], cc, 1);
265
cc.paint.values[1] = 255.0*cc.paint.values[1] - 128.0;
266
decode_sample(next.v[2], cc, 2);
267
cc.paint.values[2] = 255.0*cc.paint.values[2] - 128.0;
273
decode_sample(next.v[0], cc, 0);
274
decode_sample(next.v[1], cc, 1);
275
decode_sample(next.v[2], cc, 2);
283
decode_sample(next.v[0], cc, 0);
284
decode_sample(next.v[1], cc, 1);
285
decode_sample(next.v[2], cc, 2);
289
if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
290
cc.paint.values[0], cc.paint.values[1],
293
} else if (spp == 3) { /* may be RGB, but could be LAB image file with ICC profile... */
298
if (posture != image_skewed && next.all[0] == run.all[0])
301
pic_next = CLUE_HASH3(penum, next);
302
if (pic_next->key == next.all[0])
304
/* See above re the following check. */
305
if (pic_next == pic) {
309
pic_next->key = next.all[0];
311
/* Check for transparent color. */
312
if ((next.all[0] & mask) == test &&
313
(penum->mask_color.exact ||
314
mask_color_matches(next.v, penum, 3))
316
color_set_null(pdevc_next);
323
* We can call the remap concrete_color for the colorspace
324
* directly since device_color is only true if the colorspace
327
frac_color[0] = byte2frac(next.v[0]);
328
frac_color[1] = byte2frac(next.v[1]);
329
frac_color[2] = byte2frac(next.v[2]);
330
remap_concrete_color(frac_color, pcs, pdevc_next, pis,
331
dev, gs_color_select_source);
336
} else if (penum->alpha) {
337
if (spp == 2) { /* might be Gray + alpha */
338
next.v[2] = next.v[1] = next.v[0] = psrc[0];
342
} else if (spp == 5) { /* might be CMYK + alpha */
343
/* Convert CMYK to RGB. */
346
color_cmyk_to_rgb(byte2frac(psrc[0]), byte2frac(psrc[1]),
347
byte2frac(psrc[2]), byte2frac(psrc[3]),
350
* It seems silly to do all this converting between
351
* fracs and bytes, but that's what the current
354
next.v[0] = frac2byte(rgb[0]);
355
next.v[1] = frac2byte(rgb[1]);
356
next.v[2] = frac2byte(rgb[2]);
361
} else { /* DeviceN */
364
use_cache = false; /* should do in initialization */
365
if (posture != image_skewed && !memcmp(psrc, run.v, spp)) {
369
memcpy(next.v, psrc, spp);
371
if ((next.all[0] & mask) == test &&
372
(penum->mask_color.exact ||
373
mask_color_matches(next.v, penum, spp))
375
color_set_null(pdevc_next);
378
for (i = 0; i < spp; ++i)
379
decode_sample(next.v[i], cc, i);
381
if (gs_debug_c('B')) {
382
dprintf2("[B]cc[0..%d]=%g", spp - 1,
384
for (i = 1; i < spp; ++i)
385
dprintf1(",%g", cc.paint.values[i]);
390
mcode = remap_color(&cc, pcs, pdevc_next, pis, dev,
391
gs_color_select_source);
394
mapped: if (pic == pic_next)
396
f: if (sizeof(pdevc_next->colors.binary.color[0]) <= sizeof(ulong))
397
if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> 0x%lx,0x%lx,0x%lx\n",
398
next.v[0], next.v[1], next.v[2], next.v[3],
399
(ulong)pdevc_next->colors.binary.color[0],
400
(ulong)pdevc_next->colors.binary.color[1],
401
(ulong) pdevc_next->type);
403
if_debug9('B', "[B]0x%x,0x%x,0x%x,0x%x -> 0x%08lx%08lx,0x%08lx%08lx,0x%lx\n",
404
next.v[0], next.v[1], next.v[2], next.v[3],
405
(ulong)(pdevc_next->colors.binary.color[0] >>
406
8 * (sizeof(pdevc_next->colors.binary.color[0]) - sizeof(ulong))),
407
(ulong)pdevc_next->colors.binary.color[0],
408
(ulong)(pdevc_next->colors.binary.color[1] >>
409
8 * (sizeof(pdevc_next->colors.binary.color[1]) - sizeof(ulong))),
410
(ulong)pdevc_next->colors.binary.color[1],
411
(ulong) pdevc_next->type);
412
/* NB: printf above fails to account for sizeof gx_color_index 4 or 8 bytes */
414
/* Even though the supplied colors don't match, */
415
/* the device colors might. */
416
if (posture != image_skewed && dev_color_eq(*pdevc, *pdevc_next))
418
fill: /* Fill the region between */
419
/* xrun/irun and xprev */
421
* Note; This section is nearly a copy of a simlar section below
422
* for processing the last image pixel in the loop. This would have been
423
* made into a subroutine except for complications about the number of
424
* variables that would have been needed to be passed to the routine.
430
int wi = (irun = fixed2int_var_rounded(xprev)) - xi;
435
code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi,
439
case image_landscape:
440
{ /* 90 degree rotated rectangle */
442
int hi = (irun = fixed2int_var_rounded(yprev)) - yi;
447
code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi,
452
{ /* Parallelogram */
453
code = (*dev_proc(dev, fill_parallelogram))
454
(dev, xrun, yrun, xprev - xrun, yprev - yrun, pdyx, pdyy,
463
if ((code = mcode) < 0) {
464
/* Invalidate any partially built cache entry. */
466
pic_next->key = ~next.all[0];
472
gx_image_clue *ptemp = pic;
478
inc: xprev = dda_current(pnext.x);
479
yprev = dda_current(pnext.y); /* harmless if no skew */
481
/* Fill the last run. */
483
* Note; This section is nearly a copy of a simlar section above
484
* for processing an image pixel in the loop. This would have been
485
* made into a subroutine except for complications about the number
486
* variables that would have been needed to be passed to the routine.
492
int wi = (irun = fixed2int_var_rounded(xprev)) - xi;
497
code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi,
501
case image_landscape:
502
{ /* 90 degree rotated rectangle */
504
int hi = (irun = fixed2int_var_rounded(yprev)) - yi;
509
code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi,
514
{ /* Parallelogram */
515
code = (*dev_proc(dev, fill_parallelogram))
516
(dev, xrun, yrun, xprev - xrun, yprev - yrun, pdyx, pdyy,
520
return (code < 0 ? code : 1);
521
/* Save position if error, in case we resume. */
523
penum_orig->used.x = (rsrc - spp - psrc_initial) / spp;
524
penum_orig->used.y = 0;