| 1 | /* Copyright (C) 1992 Aladdin Enterprises. All rights reserved. |
| 2 | Distributed by Free Software Foundation, Inc. |
| 3 | |
| 4 | This file is part of Ghostscript. |
| 5 | |
| 6 | Ghostscript is distributed in the hope that it will be useful, but |
| 7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility |
| 8 | to anyone for the consequences of using it or for whether it serves any |
| 9 | particular purpose or works at all, unless he says so in writing. Refer |
| 10 | to the Ghostscript General Public License for full details. |
| 11 | |
| 12 | Everyone is granted permission to copy, modify and redistribute |
| 13 | Ghostscript, but only under the conditions described in the Ghostscript |
| 14 | General Public License. A copy of this license is supposed to have been |
| 15 | given to you along with Ghostscript so you can know your rights and |
| 16 | responsibilities. It should be in a file named COPYING. Among other |
| 17 | things, the copyright notice and this notice must be preserved on all |
| 18 | copies. */ |
| 19 | |
| 20 | /* gscie.c */ |
| 21 | /* CIE color algorithms for Ghostscript */ |
| 22 | #include "std.h" |
| 23 | #include "gscie.h" |
| 24 | |
| 25 | /* Default values for components. */ |
| 26 | private float |
| 27 | fp_identity(floatp value) |
| 28 | { return (float)value; |
| 29 | } |
| 30 | gs_range3 Range3_default = { {0,1}, {0,1}, {0,1} }; |
| 31 | gs_float_proc3 Decode3_default = { fp_identity, fp_identity, fp_identity }; |
| 32 | gs_matrix3 Matrix3_default = { {1,0,0}, {0,1,0}, {0,0,1} }; |
| 33 | gs_range RangeA_default = {0,1}; |
| 34 | gs_float_proc DecodeA_default = fp_identity; |
| 35 | gs_vector3 MatrixA_default = { 1, 1, 1 }; |
| 36 | gs_vector3 BlackPoint_default = { 0, 0, 0 }; |
| 37 | |
| 38 | /* Apply procedures to a vector. */ |
| 39 | private void |
| 40 | cie_apply3(gs_vector3 *in, gs_float_proc3 *procs, gs_vector3 *out) |
| 41 | { out->u = (*procs->u)(in->u); |
| 42 | out->v = (*procs->v)(in->v); |
| 43 | out->w = (*procs->w)(in->w); |
| 44 | } |
| 45 | |
| 46 | /* Multiply a vector by a matrix. */ |
| 47 | private void |
| 48 | cie_mult3(gs_vector3 *in, register gs_matrix3 *mat, gs_vector3 *out) |
| 49 | { float u = in->u, v = in->v, w = in->w; |
| 50 | out->u = (u * mat->cu.u) + (v * mat->cu.v) + (w * mat->cu.w); |
| 51 | out->v = (u * mat->cv.u) + (v * mat->cv.v) + (w * mat->cv.w); |
| 52 | out->w = (u * mat->cw.u) + (v * mat->cw.v) + (w * mat->cw.w); |
| 53 | } |
| 54 | |
| 55 | /* Invert a matrix. */ |
| 56 | private void |
| 57 | cie_invert3(register gs_matrix3 *in, register gs_matrix3 *out) |
| 58 | { /* This is a brute force algorithm; maybe there are better. */ |
| 59 | /* We label the array elements */ |
| 60 | /* [ A B C ] */ |
| 61 | /* [ D E F ] */ |
| 62 | /* [ G H I ] */ |
| 63 | #define A cu.u |
| 64 | #define B cv.u |
| 65 | #define C cw.u |
| 66 | #define D cu.v |
| 67 | #define E cv.v |
| 68 | #define F cw.v |
| 69 | #define G cu.w |
| 70 | #define H cv.w |
| 71 | #define I cw.w |
| 72 | double AE = in->A * in->E, AF = in->A * in->F, |
| 73 | AH = in->A * in->H, AI = in->A * in->I; |
| 74 | double BD = in->B * in->D, BF = in->B * in->F, |
| 75 | BG = in->B * in->G, BI = in->B * in->I; |
| 76 | double CD = in->C * in->D, CE = in->C * in->E, |
| 77 | CG = in->C * in->G, CH = in->C * in->H; |
| 78 | double DH = in->D * in->H, DI = in->D * in->I; |
| 79 | double EG = in->E * in->G, EI = in->E * in->I; |
| 80 | double FG = in->F * in->G, FH = in->F * in->H; |
| 81 | double coA = EI - FH, coB = FG - DI, coC = DH - EG; |
| 82 | double det = in->A * coA + in->B * coB + in->C * coC; |
| 83 | out->A = coA / det; |
| 84 | out->D = coB / det; |
| 85 | out->G = coC / det; |
| 86 | out->B = (CH - BI) / det; |
| 87 | out->E = (AI - CG) / det; |
| 88 | out->H = (BG - AH) / det; |
| 89 | out->C = (BF - CE) / det; |
| 90 | out->F = (CD - AF) / det; |
| 91 | out->I = (AE - BD) / det; |
| 92 | #undef A |
| 93 | #undef B |
| 94 | #undef C |
| 95 | #undef D |
| 96 | #undef E |
| 97 | #undef F |
| 98 | #undef G |
| 99 | #undef H |
| 100 | #undef I |
| 101 | } |
| 102 | |
| 103 | /* Force values within bounds. */ |
| 104 | #define restrict(v, r)\ |
| 105 | ((v) < (r).rmin ? (r).rmin : (v) > (r).rmax ? (r).rmax : (v)) |
| 106 | private void |
| 107 | cie_restrict3(gs_vector3 *in, gs_range3 *range, gs_vector3 *out) |
| 108 | { float temp; |
| 109 | temp = in->u; out->u = restrict(temp, range->u); |
| 110 | temp = in->v; out->v = restrict(temp, range->v); |
| 111 | temp = in->w; out->w = restrict(temp, range->w); |
| 112 | } |
| 113 | |
| 114 | /* Decode ABC values to XYZ. */ |
| 115 | int |
| 116 | gs_cie_abc_decode1(gs_vector3 *pabc, gs_vector3 *ptabc, gs_cie_abc *pcie) |
| 117 | { cie_restrict3(pabc, &pcie->RangeABC, ptabc); |
| 118 | return 0; |
| 119 | } |
| 120 | /* |
| 121 | * Client: |
| 122 | cie_apply3(ptabc, &pcie->DecodeABC, ptabc); |
| 123 | */ |
| 124 | int |
| 125 | gs_cie_abc_decode2(gs_vector3 *ptabc, gs_vector3 *ptlmn, gs_cie_abc *pcie) |
| 126 | { cie_mult3(ptabc, &pcie->MatrixABC, ptlmn); |
| 127 | cie_restrict3(ptlmn, &pcie->RangeLMN, ptlmn); |
| 128 | return 0; |
| 129 | } |
| 130 | /* |
| 131 | * Client: |
| 132 | cie_apply3(ptlmn, &pcie->DecodeLMN, ptlmn); |
| 133 | */ |
| 134 | int |
| 135 | gs_cie_abc_decode3(gs_vector3 *ptlmn, gs_vector3 *pxyz, gs_cie_abc *pcie) |
| 136 | { cie_mult3(ptlmn, &pcie->MatrixLMN, pxyz); |
| 137 | return 0; |
| 138 | } |
| 139 | |
| 140 | /* Decode an A value to XYZ. */ |
| 141 | int |
| 142 | gs_cie_a_decode1(floatp va, float *pta, gs_cie_a *pcie) |
| 143 | { *pta = restrict(va, pcie->RangeA); |
| 144 | return 0; |
| 145 | } |
| 146 | /* |
| 147 | * Client: |
| 148 | ta = (*pcie->DecodeA)(*pta); |
| 149 | */ |
| 150 | int |
| 151 | gs_cie_a_decode2(floatp ta, gs_vector3 *ptlmn, gs_cie_a *pcie) |
| 152 | { gs_vector3 lmn; |
| 153 | lmn.u = ta * pcie->MatrixA.u; |
| 154 | lmn.v = ta * pcie->MatrixA.v; |
| 155 | lmn.w = ta * pcie->MatrixA.w; |
| 156 | cie_restrict3(&lmn, &pcie->RangeLMN, ptlmn); |
| 157 | return 0; |
| 158 | } |
| 159 | /* |
| 160 | * Client: |
| 161 | cie_apply3(ptlmn, &pcie->DecodeLMN, ptlmn); |
| 162 | */ |
| 163 | /* gs_cie_a_decode3 is the same as gs_cie_abc_decode3. */ |
| 164 | |
| 165 | /* Initialize the computed fields of a CIE color rendering structure. */ |
| 166 | int |
| 167 | gs_cie_render_init(gs_cie_render *pcie) |
| 168 | { cie_invert3(&pcie->MatrixPQR, &pcie->MatrixPQR_inverse); |
| 169 | cie_mult3(&pcie->points.WhitePoint, &pcie->MatrixPQR, &pcie->wdpqr); |
| 170 | cie_mult3(&pcie->points.BlackPoint, &pcie->MatrixPQR, &pcie->bdpqr); |
| 171 | return 0; |
| 172 | } |
| 173 | |
| 174 | /* Render CIE colors */ |
| 175 | int |
| 176 | gs_cie_render_colors1(gs_vector3 *pxyz, gs_cie_wbsd *pwbsd, gs_vector3 *ptpqr, gs_cie_wb *points, gs_cie_render *pcie) |
| 177 | { cie_mult3(pxyz, &pcie->MatrixPQR, ptpqr); |
| 178 | pwbsd->ws.xyz = points->WhitePoint; |
| 179 | cie_mult3(&pwbsd->ws.xyz, &pcie->MatrixPQR, &pwbsd->ws.pqr); |
| 180 | pwbsd->bs.xyz = points->BlackPoint; |
| 181 | cie_mult3(&pwbsd->bs.xyz, &pcie->MatrixPQR, &pwbsd->bs.pqr); |
| 182 | pwbsd->wd.xyz = pcie->points.WhitePoint; |
| 183 | pwbsd->wd.pqr = pcie->wdpqr; |
| 184 | pwbsd->bd.xyz = pcie->points.BlackPoint; |
| 185 | pwbsd->bd.pqr = pcie->bdpqr; |
| 186 | return 0; |
| 187 | } |
| 188 | /* |
| 189 | * Client: |
| 190 | ptpqr->u = (*pcie->TransformPQR.u)(pwbsd, ptpqr->u); |
| 191 | ptpqr->v = (*pcie->TransformPQR.v)(pwbsd, ptpqr->v); |
| 192 | ptpqr->w = (*pcie->TransformPQR.w)(pwbsd, ptpqr->w); |
| 193 | */ |
| 194 | int |
| 195 | gs_cie_render_colors2(gs_vector3 *ptpqr, gs_vector3 *ptlmn, gs_cie_render *pcie) |
| 196 | { gs_vector3 xyzd; |
| 197 | cie_mult3(ptpqr, &pcie->MatrixPQR_inverse, &xyzd); |
| 198 | cie_mult3(&xyzd, &pcie->MatrixLMN, ptlmn); |
| 199 | return 0; |
| 200 | } |
| 201 | /* |
| 202 | /* Client: |
| 203 | cie_apply3(ptlmn, &pcie->EncodeLMN, ptlmn); |
| 204 | */ |
| 205 | int |
| 206 | gs_cir_render_colors3(gs_vector3 *ptlmn, gs_vector3 *ptabc, gs_cie_render *pcie) |
| 207 | { gs_vector3 lmn; |
| 208 | cie_restrict3(ptlmn, &pcie->RangeLMN, &lmn); |
| 209 | cie_mult3(&lmn, &pcie->MatrixABC, ptabc); |
| 210 | return 0; |
| 211 | } |
| 212 | /* |
| 213 | * Client: |
| 214 | cie_apply3(ptabc, &pcie->EncodeABC, ptabc); |
| 215 | */ |
| 216 | int |
| 217 | gs_cie_render_colors4(gs_vector3 *ptabc, float *colors, gs_cie_render *pcie) |
| 218 | { gs_vector3 abc; |
| 219 | cie_restrict3(ptabc, &pcie->RangeABC, &abc); |
| 220 | if ( pcie->RenderTable.table == 0 ) |
| 221 | { /* No further transformation */ |
| 222 | colors[0] = abc.u; |
| 223 | colors[1] = abc.v; |
| 224 | colors[2] = abc.w; |
| 225 | } |
| 226 | else |
| 227 | { /* Use the RenderTable. */ |
| 228 | int m = pcie->RenderTable.m; |
| 229 | #define ri(s,n)\ |
| 230 | (int)((abc.s - pcie->RangeABC.s.rmin) * (pcie->RenderTable.n - 1) /\ |
| 231 | (pcie->RangeABC.s.rmax - pcie->RangeABC.s.rmin) + 0.5) |
| 232 | int ia = ri(u, NA); |
| 233 | int ib = ri(v, NB); |
| 234 | int ic = ri(w, NC); |
| 235 | int j; |
| 236 | byte *pdc = pcie->RenderTable.table[ia] + |
| 237 | m * (ib * pcie->RenderTable.NC + ic); |
| 238 | for ( j = 0; j < m; j++ ) |
| 239 | colors[j] = (*pcie->RenderTable.T[j])(pdc[j] / 255.0); |
| 240 | } |
| 241 | return 0; |
| 242 | } |