/* Shared function between the single and buffer conversions */ static void gsicc_nocm_transform_general(gx_device *dev, gsicc_link_t *icclink, void *inputcolor, void *outputcolor, int num_bytes_in, int num_bytes_out) { /* Input data is either single byte or 2 byte color values. The color mapping procs work on frac values so we have to sandwich the transformation between to and from frac conversions. We are only doing at most 4 source colors here */ nocm_link_t *link = (nocm_link_t*) icclink->link_handle; byte num_in = link->num_in; byte num_out = link->num_out; frac frac_in[4]; frac frac_out[GX_DEVICE_COLOR_MAX_COMPONENTS]; int k; if (num_bytes_in == 2) { unsigned short *data = (unsigned short *) inputcolor; for (k = 0; k < num_in; k++) { frac_in[k] = ushort2frac(data[k]); } } else { byte *data = (byte *) inputcolor; for (k = 0; k < num_in; k++) { frac_in[k] = byte2frac(data[k]); } } /* Use the device procedure */ switch (num_in) { case 1: (link->cm_procs.map_gray)(dev, frac_in[0], frac_out); break; case 3: (link->cm_procs.map_rgb)(dev, link->pis, frac_in[0], frac_in[1], frac_in[2], frac_out); break; case 4: (link->cm_procs.map_cmyk)(dev, frac_in[0], frac_in[1], frac_in[2], frac_in[3], frac_out); break; default: break; } if (num_bytes_out == 2) { unsigned short *data = (unsigned short *) outputcolor; for (k = 0; k < num_out; k++) { data[k] = frac2ushort(frac_out[k]); } } else { byte *data = (byte *) outputcolor; for (k = 0; k < num_out; k++) { data[k] = frac2byte(frac_out[k]); } } return; }
/* Shared function between the single and buffer conversions. This is where we do the actual replacement. For now, we make the replacement a negative to show the effect of what using color replacement. We also use the device procs to map to the device value. */ static void gsicc_rcm_transform_general(gx_device *dev, gsicc_link_t *icclink, void *inputcolor, void *outputcolor, int num_bytes_in, int num_bytes_out) { /* Input data is either single byte or 2 byte color values. */ rcm_link_t *link = (rcm_link_t*) icclink->link_handle; byte num_in = link->num_in; byte num_out = link->num_out; frac frac_in[4]; frac frac_out[GX_DEVICE_COLOR_MAX_COMPONENTS]; int k; /* Make the negative for the demo.... */ if (num_bytes_in == 2) { unsigned short *data = (unsigned short *) inputcolor; for (k = 0; k < num_in; k++) { frac_in[k] = frac_1 - ushort2frac(data[k]); } } else { byte *data = (byte *) inputcolor; for (k = 0; k < num_in; k++) { frac_in[k] = frac_1 - byte2frac(data[k]); } } /* Use the device procedure */ switch (num_in) { case 1: (link->cm_procs.map_gray)(dev, frac_in[0], frac_out); break; case 3: (link->cm_procs.map_rgb)(dev, NULL, frac_in[0], frac_in[1], frac_in[2], frac_out); break; case 4: (link->cm_procs.map_cmyk)(dev, frac_in[0], frac_in[1], frac_in[2], frac_in[3], frac_out); break; default: break; } if (num_bytes_out == 2) { unsigned short *data = (unsigned short *) outputcolor; for (k = 0; k < num_out; k++) { data[k] = frac2ushort(frac_out[k]); } } else { byte *data = (byte *) outputcolor; for (k = 0; k < num_out; k++) { data[k] = frac2byte(frac_out[k]); } } return; }
/* * Define an implementation that simply picks the nearest value without * any interpolation. */ void gx_color_interpolate_nearest(const fixed * pi, const gx_color_lookup_table * pclt, frac * pv) { const int *pdim = pclt->dims; int m = pclt->m; const gs_const_string *table = pclt->table; if (pclt->n > 3) { table += fixed2int_var_rounded(pi[0]) * pdim[1]; ++pi, ++pdim; } { int ic = fixed2int_var_rounded(pi[2]); int ib = fixed2int_var_rounded(pi[1]); int ia = fixed2int_var_rounded(pi[0]); const byte *p = pclt->table[ia].data + (ib * pdim[2] + ic) * m; int j; for (j = 0; j < m; ++j, ++p) pv[j] = byte2frac(*p); } }
/* * Define an implementation that uses trilinear interpolation. */ static void interpolate_accum(const fixed * pi, const gx_color_lookup_table * pclt, frac * pv, fixed factor) { const int *pdim = pclt->dims; int m = pclt->m; if (pclt->n > 3) { /* Do two 3-D interpolations, interpolating between them. */ gx_color_lookup_table clt3; int ix = fixed2int_var(pi[0]); fixed fx = fixed_fraction(pi[0]); clt3.n = 3; clt3.dims[0] = pdim[1]; /* needed only for range checking */ clt3.dims[1] = pdim[2]; clt3.dims[2] = pdim[3]; clt3.m = m; clt3.table = pclt->table + ix * pdim[1]; interpolate_accum(pi + 1, &clt3, pv, fixed_1); if (ix == pdim[0] - 1) return; clt3.table += pdim[1]; interpolate_accum(pi + 1, &clt3, pv, fx); } else { int ic = fixed2int_var(pi[2]); fixed fc = fixed_fraction(pi[2]); uint dc1 = (ic == pdim[2] - 1 ? 0 : m); int ib = fixed2int_var(pi[1]); fixed fb = fixed_fraction(pi[1]); uint db1 = (ib == pdim[1] - 1 ? 0 : pdim[2] * m); uint dbc = (ib * pdim[2] + ic) * m; uint dbc1 = db1 + dc1; int ia = fixed2int_var(pi[0]); fixed fa = fixed_fraction(pi[0]); const byte *pa0 = pclt->table[ia].data + dbc; const byte *pa1 = (ia == pdim[0] - 1 ? pa0 : pclt->table[ia + 1].data + dbc); int j; /* The values to be interpolated are */ /* pa{0,1}[{0,db1,dc1,dbc1}]. */ for (j = 0; j < m; ++j, ++pa0, ++pa1) { frac v000 = byte2frac(pa0[0]); frac v001 = byte2frac(pa0[dc1]); frac v010 = byte2frac(pa0[db1]); frac v011 = byte2frac(pa0[dbc1]); frac v100 = byte2frac(pa1[0]); frac v101 = byte2frac(pa1[dc1]); frac v110 = byte2frac(pa1[db1]); frac v111 = byte2frac(pa1[dbc1]); frac rv; frac v00 = v000 + (frac) arith_rshift((long)fc * (v001 - v000), _fixed_shift); frac v01 = v010 + (frac) arith_rshift((long)fc * (v011 - v010), _fixed_shift); frac v10 = v100 + (frac) arith_rshift((long)fc * (v101 - v100), _fixed_shift); frac v11 = v110 + (frac) arith_rshift((long)fc * (v111 - v110), _fixed_shift); frac v0 = v00 + (frac) arith_rshift((long)fb * (v01 - v00), _fixed_shift); frac v1 = v10 + (frac) arith_rshift((long)fb * (v11 - v10), _fixed_shift); rv = v0 + (frac) arith_rshift((long)fa * (v1 - v0), _fixed_shift); if (factor == fixed_1) pv[j] = rv; else pv[j] += (frac) arith_rshift((long)factor * (rv - pv[j]), _fixed_shift); } } }
/* this procedure is exported for the benefit of gsicc.c */ int gx_cie_real_remap_finish(cie_cached_vector3 vec3, frac * pconc, const gs_imager_state * pis, const gs_color_space *pcs) { const gs_cie_render *pcrd = pis->cie_render; const gx_cie_joint_caches *pjc = pis->cie_joint_caches; const gs_const_string *table = pcrd->RenderTable.lookup.table; int tabc[3]; /* indices for final EncodeABC lookup */ /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */ if (!pjc->skipDecodeLMN) cie_lookup_map3(&vec3 /* LMN => PQR */, &pjc->DecodeLMN, "Decode/MatrixLMN+MatrixPQR"); /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */ if (!pjc->skipPQR) cie_lookup_map3(&vec3 /* PQR => LMN */, &pjc->TransformPQR, "Transform/Matrix'PQR+MatrixLMN"); /* Apply EncodeLMN and MatrixABC(encode). */ if (!pjc->skipEncodeLMN) cie_lookup_map3(&vec3 /* LMN => ABC */, &pcrd->caches.EncodeLMN, "EncodeLMN+MatrixABC"); /* MatrixABCEncode includes the scaling of the EncodeABC */ /* cache index. */ #define SET_TABC(i, t)\ BEGIN\ tabc[i] = cie_cached2int(vec3 /*ABC*/.t - pcrd->EncodeABC_base[i],\ _cie_interpolate_bits);\ if ((uint)tabc[i] > (gx_cie_cache_size - 1) << _cie_interpolate_bits)\ tabc[i] = (tabc[i] < 0 ? 0 :\ (gx_cie_cache_size - 1) << _cie_interpolate_bits);\ END SET_TABC(0, u); SET_TABC(1, v); SET_TABC(2, w); #undef SET_TABC if (table == 0) { /* * No further transformation. * The final mapping step includes both restriction to * the range [0..1] and conversion to fracs. */ #define EABC(i)\ cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.fracs.values, tabc[i]) pconc[0] = EABC(0); pconc[1] = EABC(1); pconc[2] = EABC(2); #undef EABC return 3; } else { /* * Use the RenderTable. */ int m = pcrd->RenderTable.lookup.m; #define RT_LOOKUP(j, i) pcrd->caches.RenderTableT[j].fracs.values[i] #ifdef CIE_RENDER_TABLE_INTERPOLATE /* * The final mapping step includes restriction to the * ranges [0..dims[c]] as ints with interpolation bits. */ fixed rfix[3]; const int s = _fixed_shift - _cie_interpolate_bits; #define EABC(i)\ cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.ints.values, tabc[i]) #define FABC(i, s)\ ((s) > 0) ? (EABC(i) << (s)) : (EABC(i) >> -(s)) rfix[0] = FABC(0, s); rfix[1] = FABC(1, s); rfix[2] = FABC(2, s); #undef FABC #undef EABC if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n", cie_cached2float(vec3.u), cie_cached2float(vec3.v), cie_cached2float(vec3.w), fixed2float(rfix[0]), fixed2float(rfix[1]), fixed2float(rfix[2])); gx_color_interpolate_linear(rfix, &pcrd->RenderTable.lookup, pconc); if_debug3('c', "[c] interpolated => %g,%g,%g\n", frac2float(pconc[0]), frac2float(pconc[1]), frac2float(pconc[2])); if (!pcrd->caches.RenderTableT_is_identity) { /* Map the interpolated values. */ #define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size) pconc[0] = RT_LOOKUP(0, frac2cache_index(pconc[0])); pconc[1] = RT_LOOKUP(1, frac2cache_index(pconc[1])); pconc[2] = RT_LOOKUP(2, frac2cache_index(pconc[2])); if (m > 3) pconc[3] = RT_LOOKUP(3, frac2cache_index(pconc[3])); #undef frac2cache_index } #else /* !CIE_RENDER_TABLE_INTERPOLATE */ /* * The final mapping step includes restriction to the ranges * [0..dims[c]], plus scaling of the indices in the strings. */ #define RI(i)\ pcrd->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits] int ia = RI(0); int ib = RI(1); /* pre-multiplied by m * NC */ int ic = RI(2); /* pre-multiplied by m */ const byte *prtc = table[ia].data + ib + ic; /* (*pcrd->RenderTable.T)(prtc, m, pcrd, pconc); */ if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n", cie_cached2float(vec3.u), cie_cached2float(vec3.v), cie_cached2float(vec3.w), ia, ib, ic); if (pcrd->caches.RenderTableT_is_identity) { pconc[0] = byte2frac(prtc[0]); pconc[1] = byte2frac(prtc[1]); pconc[2] = byte2frac(prtc[2]); if (m > 3) pconc[3] = byte2frac(prtc[3]); } else { #if gx_cie_log2_cache_size == 8 # define byte2cache_index(b) (b) #else # if gx_cie_log2_cache_size > 8 # define byte2cache_index(b)\ ( ((b) << (gx_cie_log2_cache_size - 8)) +\ ((b) >> (16 - gx_cie_log2_cache_size)) ) # else /* < 8 */ # define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size)) # endif #endif pconc[0] = RT_LOOKUP(0, byte2cache_index(prtc[0])); pconc[1] = RT_LOOKUP(1, byte2cache_index(prtc[1])); pconc[2] = RT_LOOKUP(2, byte2cache_index(prtc[2])); if (m > 3) pconc[3] = RT_LOOKUP(3, byte2cache_index(prtc[3])); #undef byte2cache_index } #endif /* !CIE_RENDER_TABLE_INTERPOLATE */ #undef RI #undef RT_LOOKUP return m; } }