Commit | Line | Data |
---|---|---|
e964bf85 WJ |
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 | } |