/src/ghostpdl/pcl/pcl/pcmtx3.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* pcmtx3.c - 3 x 3 matrix utilities for PCL device independent color spaces */ |
18 | | #include "string_.h" |
19 | | #include "math_.h" |
20 | | #include "gx.h" |
21 | | #include "gstypes.h" |
22 | | #include "pcommand.h" |
23 | | #include "pcmtx3.h" |
24 | | |
25 | | /* |
26 | | * Calculate the co-factor for the (i, j) component of a 3 x 3 matrix, |
27 | | * including the sign. Note that i and j range from 0 to 2. |
28 | | * |
29 | | * The cofactor of the (i, j) entry in an n-dimensional matrix is the |
30 | | * determinant of the (n - 1) dimensional matrix formed by dropping the |
31 | | * ith row and jth column of the given matrix, multiplied by -1 if |
32 | | * (i + j) is odd. |
33 | | */ |
34 | | static double |
35 | | calc_cofactor(int i, int j, const pcl_mtx3_t * pmtx) |
36 | 0 | { |
37 | 0 | int i1 = (i == 0 ? 1 : 0); |
38 | 0 | int i2 = (i == 2 ? 1 : 2); |
39 | 0 | int j1 = (j == 0 ? 1 : 0); |
40 | 0 | int j2 = (j == 2 ? 1 : 2); |
41 | 0 | double cf = pmtx->a[3 * i1 + j1] * pmtx->a[3 * i2 + j2] |
42 | 0 | - pmtx->a[3 * i1 + j2] * pmtx->a[3 * i2 + j1]; |
43 | |
|
44 | 0 | return (((i + j) & 0x1) != 0) ? -cf : cf; |
45 | 0 | } |
46 | | |
47 | | /* |
48 | | * Form the "cofactor matrix" corresponding to the given matrix. |
49 | | * |
50 | | * For this routine, pinmtx and poutmtx must be different. |
51 | | */ |
52 | | static void |
53 | | make_cofactor_mtx(const pcl_mtx3_t * pinmtx, pcl_mtx3_t * poutmtx) |
54 | 0 | { |
55 | 0 | int i; |
56 | |
|
57 | 0 | for (i = 0; i < 3; i++) { |
58 | 0 | int j; |
59 | |
|
60 | 0 | for (j = 0; j < 3; j++) |
61 | 0 | poutmtx->a[3 * i + j] = calc_cofactor(i, j, pinmtx); |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | /* |
66 | | * Add and subtract 3 dimensional vectors. These are not currently needed, |
67 | | * but are included for completeness. No inner-product is provided because |
68 | | * color spaces do not, in general, have geometric or even metric properties |
69 | | * (the CID L*a*b* space is an exception, and then only approximately). |
70 | | * |
71 | | * Any of the three pointer operands may be the same. |
72 | | */ |
73 | | void |
74 | | pcl_vec3_add(const pcl_vec3_t * pivec1, |
75 | | const pcl_vec3_t * pivec2, pcl_vec3_t * poutvec) |
76 | 0 | { |
77 | 0 | poutvec->vc.v1 = pivec1->vc.v1 + pivec2->vc.v1; |
78 | 0 | poutvec->vc.v2 = pivec1->vc.v2 + pivec2->vc.v2; |
79 | 0 | poutvec->vc.v3 = pivec1->vc.v3 + pivec2->vc.v3; |
80 | 0 | } |
81 | | |
82 | | void |
83 | | pcl_vec3_sub(const pcl_vec3_t * pivec1, |
84 | | const pcl_vec3_t * pivec2, pcl_vec3_t * poutvec) |
85 | 0 | { |
86 | 0 | poutvec->vc.v1 = pivec1->vc.v1 - pivec2->vc.v1; |
87 | 0 | poutvec->vc.v2 = pivec1->vc.v2 - pivec2->vc.v2; |
88 | 0 | poutvec->vc.v3 = pivec1->vc.v3 - pivec2->vc.v3; |
89 | 0 | } |
90 | | |
91 | | /* |
92 | | * Apply a matrix to a color component vector. Note that vectors are inter- |
93 | | * preted as row vectors, and matrices are specified in a row-first order. |
94 | | * |
95 | | * The code will properly handle the case pinvec == poutvec. |
96 | | */ |
97 | | void |
98 | | pcl_vec3_xform(const pcl_vec3_t * pinvec, |
99 | | pcl_vec3_t * poutvec, const pcl_mtx3_t * pmtx) |
100 | 0 | { |
101 | 0 | pcl_vec3_t tmp_vec; |
102 | 0 | int i; |
103 | |
|
104 | 0 | for (i = 0; i < 3; i++) |
105 | 0 | tmp_vec.va[i] = pinvec->vc.v1 * pmtx->a[i] |
106 | 0 | + pinvec->vc.v2 * pmtx->a[i + 3] |
107 | 0 | + pinvec->vc.v3 * pmtx->a[i + 6]; |
108 | 0 | poutvec->vc = tmp_vec.vc; |
109 | 0 | } |
110 | | |
111 | | /* |
112 | | * Invert a 3 x 3 matrix. |
113 | | * |
114 | | * This will properly handle the case of pinmtx == poutmtx. |
115 | | * |
116 | | * Returns 0 on success, e_Range if the matrix provided is singular. |
117 | | */ |
118 | | int |
119 | | pcl_mtx3_invert(const pcl_mtx3_t * pinmtx, pcl_mtx3_t * poutmtx) |
120 | 0 | { |
121 | 0 | pcl_mtx3_t cf_mtx; |
122 | 0 | double det; |
123 | 0 | int i; |
124 | |
|
125 | 0 | make_cofactor_mtx(pinmtx, &cf_mtx); |
126 | 0 | det = pinmtx->c.a11 * cf_mtx.c.a11 |
127 | 0 | + pinmtx->c.a12 * cf_mtx.c.a12 + pinmtx->c.a13 * cf_mtx.c.a13; |
128 | 0 | if (det == 0.0) |
129 | 0 | return e_Range; |
130 | 0 | for (i = 0; i < 3; i++) { |
131 | 0 | int j; |
132 | |
|
133 | 0 | for (j = 0; j < 3; j++) |
134 | 0 | poutmtx->a[3 * i + j] = cf_mtx.a[3 * j + i] / det; |
135 | 0 | } |
136 | |
|
137 | 0 | return 0; |
138 | 0 | } |
139 | | |
140 | | /* |
141 | | * Add, subtract, and multiply two 3 x 3 matrices. These are not currently |
142 | | * needed, but are included for completenese. |
143 | | * |
144 | | * In all cases, any of the three pointers provided may be identical. |
145 | | */ |
146 | | void |
147 | | pcl_mtx3_add(const pcl_mtx3_t * pinmtx1, |
148 | | const pcl_mtx3_t * pinmtx2, pcl_mtx3_t * poutmtx) |
149 | 0 | { |
150 | 0 | int i; |
151 | |
|
152 | 0 | for (i = 0; i < 9; i++) |
153 | 0 | poutmtx->a[i] = pinmtx1->a[i] + pinmtx2->a[i]; |
154 | 0 | } |
155 | | |
156 | | void |
157 | | pcl_mtx3_sub(const pcl_mtx3_t * pinmtx1, |
158 | | const pcl_mtx3_t * pinmtx2, pcl_mtx3_t * poutmtx) |
159 | 0 | { |
160 | 0 | int i; |
161 | |
|
162 | 0 | for (i = 0; i < 9; i++) |
163 | 0 | poutmtx->a[i] = pinmtx1->a[i] - pinmtx2->a[i]; |
164 | 0 | } |
165 | | |
166 | | void |
167 | | pcl_mtx3_mul(const pcl_mtx3_t * pinmtx1, |
168 | | const pcl_mtx3_t * pinmtx2, pcl_mtx3_t * poutmtx) |
169 | 0 | { |
170 | 0 | pcl_mtx3_t tmp_mtx; |
171 | 0 | int i; |
172 | |
|
173 | 0 | for (i = 0; i < 3; i++) { |
174 | 0 | int j; |
175 | |
|
176 | 0 | for (j = 0; j < 3; j++) { |
177 | 0 | int k; |
178 | 0 | double val = 0.0; |
179 | |
|
180 | 0 | for (k = 0; k < 3; k++) |
181 | 0 | val += pinmtx1->a[3 * i + k] * pinmtx2->a[3 * k + j]; |
182 | 0 | tmp_mtx.a[3 * i + j] = val; |
183 | 0 | } |
184 | 0 | } |
185 | 0 | *poutmtx = tmp_mtx; |
186 | 0 | } |
187 | | |
188 | | /* |
189 | | * Convert a pcl_mtx3_t structure to and from a gs_matrix3 struct. Identity |
190 | | * transformations are rare in PCL, so no attempt is made to identify them. |
191 | | * |
192 | | * Note that the conversion transposes the matrix in interpretation, though |
193 | | * physically entries remain in the same order. This is due to the use of |
194 | | * a "column vector" interpretation of color components in the graphic library. |
195 | | */ |
196 | | void |
197 | | pcl_mtx3_convert_to_gs(const pcl_mtx3_t * pinmtx, gs_matrix3 * pgsmtx) |
198 | 0 | { |
199 | 0 | pgsmtx->cu.u = pinmtx->c.a11; |
200 | 0 | pgsmtx->cu.v = pinmtx->c.a12; |
201 | 0 | pgsmtx->cu.w = pinmtx->c.a13; |
202 | 0 | pgsmtx->cv.u = pinmtx->c.a21; |
203 | 0 | pgsmtx->cv.v = pinmtx->c.a22; |
204 | 0 | pgsmtx->cv.w = pinmtx->c.a23; |
205 | 0 | pgsmtx->cw.u = pinmtx->c.a31; |
206 | 0 | pgsmtx->cw.v = pinmtx->c.a32; |
207 | 0 | pgsmtx->cw.w = pinmtx->c.a33; |
208 | 0 | pgsmtx->is_identity = false; |
209 | 0 | } |
210 | | |
211 | | void |
212 | | pcl_mtx3_convert_from_gs(pcl_mtx3_t * poutmtx, const gs_matrix3 * pgsmtx) |
213 | 0 | { |
214 | 0 | if (pgsmtx->is_identity) { |
215 | 0 | memset(poutmtx, 0, sizeof(pcl_mtx3_t)); |
216 | 0 | poutmtx->c.a11 = 1.0; |
217 | 0 | poutmtx->c.a22 = 1.0; |
218 | 0 | poutmtx->c.a22 = 1.0; |
219 | 0 | } else { |
220 | 0 | poutmtx->c.a11 = pgsmtx->cu.u; |
221 | 0 | poutmtx->c.a12 = pgsmtx->cu.v; |
222 | 0 | poutmtx->c.a13 = pgsmtx->cu.w; |
223 | 0 | poutmtx->c.a21 = pgsmtx->cv.u; |
224 | 0 | poutmtx->c.a22 = pgsmtx->cv.v; |
225 | 0 | poutmtx->c.a23 = pgsmtx->cw.v; |
226 | 0 | poutmtx->c.a31 = pgsmtx->cw.u; |
227 | 0 | poutmtx->c.a32 = pgsmtx->cw.v; |
228 | 0 | poutmtx->c.a33 = pgsmtx->cw.w; |
229 | 0 | } |
230 | 0 | } |