Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}