Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gxdcconv.c
Line
Count
Source (jump to first uncovered line)
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
/* Conversion between device color spaces for Ghostscript */
18
#include "gx.h"
19
#include "gsdcolor.h"   /* for gxcmap.h */
20
#include "gxdcconv.h"   /* interface */
21
#include "gxdevice.h"   /* for gxcmap.h */
22
#include "gxcmap.h"
23
#include "gxfarith.h"
24
#include "gxlum.h"
25
#include "gxgstate.h"
26
#include "gsstate.h"            /* for gs_currentcpsimode */
27
28
/*
29
 * The CMYK to RGB algorithms specified by Adobe are, e.g.,
30
 *      R = 1.0 - min(1.0, C + K)
31
 *      C = max(0.0, min(1.0, 1 - R - UCR))
32
 * We got better results on displays with
33
 *      R = (1.0 - C) * (1.0 - K)
34
 *      C = max(0.0, min(1.0, 1 - R / (1 - UCR)))
35
 * For PLRM compatibility, we use the Adobe algorithms by default,
36
 * but what Adobe says and what they do are two different things.
37
 * Testing on CPSI shows that they use the 'better' algorithm.
38
 */
39
40
/* ------ Color space conversion ------ */
41
42
/* Only 4 of the 6 conversions are implemented here; */
43
/* the other 2 (Gray to RGB/CMYK) are trivial. */
44
45
/* Convert RGB to Gray. */
46
frac
47
color_rgb_to_gray(frac r, frac g, frac b, const gs_gstate * pgs)
48
25.8k
{
49
25.8k
    return (r * (unsigned long)lum_red_weight +
50
25.8k
            g * (unsigned long)lum_green_weight +
51
25.8k
            b * (unsigned long)lum_blue_weight +
52
25.8k
            (lum_all_weights / 2))
53
25.8k
        / lum_all_weights;
54
25.8k
}
55
56
/* Convert RGB to CMYK. */
57
/* Note that this involves black generation and undercolor removal. */
58
void
59
color_rgb_to_cmyk(frac r, frac g, frac b, const gs_gstate * pgs,
60
                  frac cmyk[4], gs_memory_t *mem)
61
0
{
62
0
    frac c = frac_1 - r, m = frac_1 - g, y = frac_1 - b;
63
0
    frac k = (c < m ? min(c, y) : min(m, y));
64
65
    /*
66
     * The default UCR and BG functions are pretty arbitrary,
67
     * but they must agree with the ones in gs_init.ps.
68
     */
69
0
    frac bg =
70
0
        (pgs == NULL ? k : pgs->black_generation == NULL ? frac_0 :
71
0
         gx_map_color_frac(pgs, k, black_generation));
72
0
    signed_frac ucr =
73
0
        (pgs == NULL ? k : pgs->undercolor_removal == NULL ? frac_0 :
74
0
         gx_map_color_frac(pgs, k, undercolor_removal));
75
76
0
    if (ucr == frac_1)
77
0
        cmyk[0] = cmyk[1] = cmyk[2] = 0;
78
0
    else if (ucr == frac_0)
79
0
        cmyk[0] = c, cmyk[1] = m, cmyk[2] = y;
80
0
    else {
81
0
        if (!gs_currentcpsimode(mem)) {
82
            /* C = max(0.0, min(1.0, 1 - R - UCR)), etc. */
83
0
            signed_frac not_ucr = (ucr < 0 ? frac_1 + ucr : frac_1);
84
85
0
            cmyk[0] = (c < ucr ? frac_0 : c > not_ucr ? frac_1 : c - ucr);
86
0
            cmyk[1] = (m < ucr ? frac_0 : m > not_ucr ? frac_1 : m - ucr);
87
0
            cmyk[2] = (y < ucr ? frac_0 : y > not_ucr ? frac_1 : y - ucr);
88
0
        } else {
89
            /* Adobe CPSI method */
90
            /* C = max(0.0, min(1.0, 1 - R / (1 - UCR))), etc. */
91
0
            float denom = frac2float(frac_1 - ucr);   /* unscaled */
92
0
            float v;
93
94
0
            v = (float)frac_1 - r / denom; /* unscaled */
95
0
            cmyk[0] =
96
0
                (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
97
0
            v = (float)frac_1 - g / denom; /* unscaled */
98
0
            cmyk[1] =
99
0
                (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
100
0
            v = (float)frac_1 - b / denom; /* unscaled */
101
0
            cmyk[2] =
102
0
                (is_fneg(v) ? frac_0 : v >= (float)frac_1 ? frac_1 : (frac) v);
103
0
        }
104
0
    }
105
0
    cmyk[3] = bg;
106
0
    if_debug7m('c', mem, "[c]RGB 0x%x,0x%x,0x%x -> CMYK 0x%x,0x%x,0x%x,0x%x\n",
107
0
               r, g, b, cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
108
0
}
109
110
/* Convert CMYK to Gray. */
111
frac
112
color_cmyk_to_gray(frac c, frac m, frac y, frac k, const gs_gstate * pgs)
113
3.40k
{
114
3.40k
    frac not_gray = color_rgb_to_gray(c, m, y, pgs);
115
116
3.40k
    return (not_gray > frac_1 - k ?  /* gray + k > 1.0 */
117
3.40k
            frac_0 : frac_1 - (not_gray + k));
118
3.40k
}
119
120
/* Convert CMYK to RGB. */
121
void
122
color_cmyk_to_rgb(frac c, frac m, frac y, frac k, const gs_gstate * pgs,
123
                  frac rgb[3], gs_memory_t *mem)
124
868
{
125
868
    switch (k) {
126
434
        case frac_0:
127
434
            rgb[0] = frac_1 - c;
128
434
            rgb[1] = frac_1 - m;
129
434
            rgb[2] = frac_1 - y;
130
434
            break;
131
44
        case frac_1:
132
44
            rgb[0] = rgb[1] = rgb[2] = frac_0;
133
44
            break;
134
390
        default:
135
390
            if (!gs_currentcpsimode(mem)) {
136
                /* R = 1.0 - min(1.0, C + K), etc. */
137
390
                frac not_k = frac_1 - k;
138
139
390
                rgb[0] = (c > not_k ? frac_0 : not_k - c);
140
390
                rgb[1] = (m > not_k ? frac_0 : not_k - m);
141
390
                rgb[2] = (y > not_k ? frac_0 : not_k - y);
142
390
            } else {
143
                /* R = (1.0 - C) * (1.0 - K), etc. */
144
0
                ulong not_k = frac_1 - k;
145
146
                /* Compute not_k * (frac_1 - v) / frac_1 efficiently. */
147
0
                ulong prod;
148
149
0
#define deduct_black(v)\
150
0
  (prod = (frac_1 - (v)) * not_k, frac_1_quo(prod))
151
0
                rgb[0] = deduct_black(c);
152
0
                rgb[1] = deduct_black(m);
153
0
                rgb[2] = deduct_black(y);
154
0
#undef deduct_black
155
0
            }
156
868
    }
157
868
    if_debug7m('c', mem, "[c]CMYK 0x%x,0x%x,0x%x,0x%x -> RGB 0x%x,0x%x,0x%x\n",
158
868
               c, m, y, k, rgb[0], rgb[1], rgb[2]);
159
868
}