Skip to content

Commit d0083b5

Browse files
committed
Overhaul of color management code.
* The pluggable CMS context was premature over-engineering, and could never have worked as implemented. There were plenty of hardcoded dependencies on LCMS2MT, the source file with the LCMS2 functions had several other ICC-related but non-LCMS2 related functions guarded by the same ifdefs. I've made it non-pluggable, but replacable at compile time by isolating the LCMS2 specific functions to color-lcms.c. Everything else should be CMS agnostic. * I've added an LCMS2MT=1 ifdef to allow building with stock LCMS2 as well as Artifex's multi-threaded LCMS2 fork. With the stock LCMS2 trying to access the color conversion engine from multiple threads will throw an exception. * The color conversion functions were taking the half a dozen arguments in a haphazard order. I've changed all of the functions to take their arguments in the same, regularized, order: src_colorspace, src_color, dst_colorspace, dst_color, proof, params. * The color-fast.c file contains unmanaged, fast, color conversions. These are used as fallbacks when the CMS fails to create a link, or when color management is turned off with fz_disable_icc(ctx). * The colorspace struct was a half-opaque hidden in the ../fitz/colorspace-imp.h header that was included by other modules. I can make it simpler and transparent by changing the internals and how the managed/non-managed color converters work. * Indexed and separation colorspaces are now public and well defined in the header. No more PDF specific hacks. The separation tint function evaluation is done by a callback in the colorspace struct. * Converting a pixmap is done directly, not via a special pixmap converter lookup and callback. This is just simpler, and the lookup/callback mechanism is not as useful for converting images since we never did multiple images with the same converter. The lookup and callback is useful for converting multiple color samples at once (such as when converting pixmap samples in the slow fallback case, or shadings) in order to amortize the converter lookup cost. * I've removed the intermediate fz_cal_colorspace struct. We directly create an ICC-backed Cal colorspace from fz_new_cal_xxx_colorspace() instead. TODO: LCMS2 supports Cal colorspaces directly, why don't we use those functions? * The cached ICC links did not take BGR order into account. Fixed. * Passing NULL colorspaces for alpha only drawing. Some functions automatically treated a NULL colorspace as DeviceGray, but other similar functions did not. It was all a bit random and confusing. I've removed all of these hacks. Any code that wants to convert a color should have a colorspace. If you are drawing alpha only, don't bother calling the color conversion code to convert a NULL color. It is better to catch these errors early during development and do things properly than invisibly plaster over them by treating NULL as gray. * Loading embedded ICC profiles and compatibility handling. Most image loaders were doing inconsistent compatibility checking when loading an ICC profile. Now if you pass a colorspace type to the ICC profile, the colorspace constructor will check that the profile matches the expected colorspace. I've cleaned up the image loaders to behave similarly in their ICC profile loading and checking. * Do not save DeviceGray/RGB ICC profiles when writing PNG files. These profiles are completely redundant, since PNG files are already defined by spec to be in the sRGB colorspace. * Store the ICC profile buffer publicly in the fz_colorspace struct, so we don't need awkward callbacks to the CMS to get the profile data back to calling code. This simplifies PNG and PSD writing code. * Pass fz_color_params by value. This is a 4-byte struct. Passing it as a pointer poses two issues: 1) A pointer may be 8 bytes. Bloat. 2) A pointer may be NULL. This adds a lot of unnecessary NULL checks. Also use a global variable for the default color parameters, saving us a function call every time we need the defaults.
1 parent a894a26 commit d0083b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+3983
-4675
lines changed

Makethird

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ ifeq ($(USE_SYSTEM_LIBS),yes)
55
USE_SYSTEM_HARFBUZZ := yes
66
USE_SYSTEM_JBIG2DEC := yes
77
USE_SYSTEM_JPEGXR := no # not available
8-
USE_SYSTEM_LCMS2 := no # need lcms2-art fork
8+
USE_SYSTEM_LCMS2 := no # lcms2mt is strongly preferred
99
USE_SYSTEM_LIBJPEG := yes
1010
USE_SYSTEM_MUJS := no # not available
1111
USE_SYSTEM_OPENJPEG := yes
@@ -206,12 +206,12 @@ endif
206206

207207
ifeq ($(USE_SYSTEM_LCMS2),yes)
208208
THIRD_CFLAGS += $(SYS_LCMS2_CFLAGS)
209-
THIRD_LIBS += $(SYS_LCMS2_CFLAGS)
209+
THIRD_LIBS += $(SYS_LCMS2_LIBS)
210210
else
211211

212212
THIRD_SRC += $(sort $(wildcard thirdparty/lcms2/src/cms*.c))
213213

214-
THIRD_CFLAGS += -Ithirdparty/lcms2/include
214+
THIRD_CFLAGS += -Ithirdparty/lcms2/include -DHAVE_LCMS2MT=1
215215

216216
$(OUT)/thirdparty/lcms2/%.o: thirdparty/lcms2/%.c
217217
$(CC_CMD) -Ithirdparty/lcms2/include

include/mupdf/fitz.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ extern "C" {
3131

3232
/* Resources */
3333
#include "mupdf/fitz/store.h"
34-
#include "mupdf/fitz/colorspace.h"
34+
#include "mupdf/fitz/color.h"
3535
#include "mupdf/fitz/pixmap.h"
3636
#include "mupdf/fitz/glyph.h"
3737
#include "mupdf/fitz/bitmap.h"
@@ -41,7 +41,6 @@ extern "C" {
4141
#include "mupdf/fitz/path.h"
4242
#include "mupdf/fitz/text.h"
4343
#include "mupdf/fitz/separation.h"
44-
#include "mupdf/fitz/color-management.h"
4544

4645
#include "mupdf/fitz/device.h"
4746
#include "mupdf/fitz/display-list.h"

include/mupdf/fitz/color-management.h

Lines changed: 0 additions & 92 deletions
This file was deleted.

include/mupdf/fitz/color.h

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
#ifndef MUPDF_FITZ_COLOR_H
2+
#define MUPDF_FITZ_COLOR_H
3+
4+
#include "mupdf/fitz/system.h"
5+
#include "mupdf/fitz/context.h"
6+
#include "mupdf/fitz/store.h"
7+
8+
typedef struct fz_colorspace_s fz_colorspace;
9+
typedef struct fz_pixmap_s fz_pixmap;
10+
11+
#if FZ_ENABLE_ICC
12+
13+
typedef struct fz_icc_instance_s fz_icc_instance;
14+
typedef struct fz_icc_profile_s fz_icc_profile;
15+
typedef struct fz_icc_link_s fz_icc_link;
16+
17+
#endif
18+
19+
/* Color handling parameters: rendering intent, overprint, etc. */
20+
21+
enum
22+
{
23+
/* Same order as needed by lcms */
24+
FZ_RI_PERCEPTUAL,
25+
FZ_RI_RELATIVE_COLORIMETRIC,
26+
FZ_RI_SATURATION,
27+
FZ_RI_ABSOLUTE_COLORIMETRIC,
28+
};
29+
30+
typedef struct fz_color_params_s fz_color_params;
31+
struct fz_color_params_s
32+
{
33+
uint8_t ri; /* rendering intent */
34+
uint8_t bp; /* black point compensation */
35+
uint8_t op; /* overprinting */
36+
uint8_t opm; /* overprint mode */
37+
};
38+
39+
extern const fz_color_params fz_default_color_params;
40+
41+
int fz_lookup_rendering_intent(const char *name);
42+
const char *fz_rendering_intent_name(int ri);
43+
44+
enum { FZ_MAX_COLORS = 32 };
45+
46+
enum fz_colorspace_type
47+
{
48+
FZ_COLORSPACE_NONE,
49+
FZ_COLORSPACE_GRAY,
50+
FZ_COLORSPACE_RGB,
51+
FZ_COLORSPACE_BGR,
52+
FZ_COLORSPACE_CMYK,
53+
FZ_COLORSPACE_LAB,
54+
FZ_COLORSPACE_INDEXED,
55+
FZ_COLORSPACE_SEPARATION,
56+
};
57+
58+
enum
59+
{
60+
FZ_COLORSPACE_IS_DEVICE = 1,
61+
FZ_COLORSPACE_IS_ICC = 2,
62+
FZ_COLORSPACE_IS_CAL = 4,
63+
FZ_COLORSPACE_HAS_CMYK = 8,
64+
FZ_COLORSPACE_HAS_SPOTS = 16,
65+
FZ_COLORSPACE_HAS_CMYK_AND_SPOTS = 8|16,
66+
};
67+
68+
struct fz_colorspace_s
69+
{
70+
fz_key_storable key_storable;
71+
enum fz_colorspace_type type;
72+
int flags;
73+
int n;
74+
char *name;
75+
union {
76+
#if FZ_ENABLE_ICC
77+
struct {
78+
fz_buffer *buffer;
79+
unsigned char md5[16];
80+
fz_icc_profile *profile;
81+
} icc;
82+
#endif
83+
struct {
84+
fz_colorspace *base;
85+
int high;
86+
unsigned char *lookup;
87+
} indexed;
88+
struct {
89+
fz_colorspace *base;
90+
void (*eval)(fz_context *ctx, void *tint, const float *s, int sn, float *d, int dn);
91+
void (*drop)(fz_context *ctx, void *tint);
92+
void *tint;
93+
char *colorant[FZ_MAX_COLORS];
94+
} separation;
95+
} u;
96+
};
97+
98+
fz_colorspace *fz_new_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, int n, const char *name);
99+
fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace);
100+
void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace);
101+
void fz_drop_colorspace_imp(fz_context *ctx, fz_storable *cs_);
102+
void fz_drop_colorspace_store_key(fz_context *ctx, fz_colorspace *cs);
103+
fz_colorspace *fz_keep_colorspace_store_key(fz_context *ctx, fz_colorspace *cs);
104+
105+
fz_colorspace *fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup);
106+
fz_colorspace *fz_new_icc_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, const char *name, fz_buffer *buf);
107+
fz_colorspace *fz_new_cal_gray_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma);
108+
fz_colorspace *fz_new_cal_rgb_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma[3], float matrix[9]);
109+
110+
fz_buffer *fz_new_icc_data_from_cal(fz_context *ctx, float wp[3], float bp[3], float gamma[3], float matrix[9], int n);
111+
112+
enum fz_colorspace_type fz_colorspace_type(fz_context *ctx, fz_colorspace *cs);
113+
const char *fz_colorspace_name(fz_context *ctx, fz_colorspace *cs);
114+
int fz_colorspace_n(fz_context *ctx, fz_colorspace *cs);
115+
116+
int fz_colorspace_is_subtractive(fz_context *ctx, fz_colorspace *cs);
117+
int fz_colorspace_device_n_has_only_cmyk(fz_context *ctx, fz_colorspace *cs);
118+
int fz_colorspace_device_n_has_cmyk(fz_context *ctx, fz_colorspace *cs);
119+
int fz_colorspace_is_gray(fz_context *ctx, fz_colorspace *cs);
120+
int fz_colorspace_is_rgb(fz_context *ctx, fz_colorspace *cs);
121+
int fz_colorspace_is_cmyk(fz_context *ctx, fz_colorspace *cs);
122+
int fz_colorspace_is_lab(fz_context *ctx, fz_colorspace *cs);
123+
int fz_colorspace_is_indexed(fz_context *ctx, fz_colorspace *cs);
124+
int fz_colorspace_is_device_n(fz_context *ctx, fz_colorspace *cs);
125+
int fz_colorspace_is_device(fz_context *ctx, fz_colorspace *cs);
126+
int fz_colorspace_is_device_gray(fz_context *ctx, fz_colorspace *cs);
127+
int fz_colorspace_is_device_cmyk(fz_context *ctx, fz_colorspace *cs);
128+
int fz_colorspace_is_lab_icc(fz_context *ctx, fz_colorspace *cs);
129+
130+
fz_colorspace *fz_device_gray(fz_context *ctx);
131+
fz_colorspace *fz_device_rgb(fz_context *ctx);
132+
fz_colorspace *fz_device_bgr(fz_context *ctx);
133+
fz_colorspace *fz_device_cmyk(fz_context *ctx);
134+
fz_colorspace *fz_device_lab(fz_context *ctx);
135+
136+
void fz_colorspace_name_process_colorants(fz_context *ctx, fz_colorspace *cs);
137+
void fz_colorspace_name_colorant(fz_context *ctx, fz_colorspace *cs, int n, const char *name);
138+
const char *fz_colorspace_colorant(fz_context *ctx, fz_colorspace *cs, int n);
139+
140+
/* Color conversion */
141+
142+
typedef struct fz_color_converter_s fz_color_converter;
143+
typedef void (fz_color_convert_fn)(fz_context *ctx, fz_color_converter *cc, const float *src, float *dst);
144+
struct fz_color_converter_s
145+
{
146+
fz_color_convert_fn *convert;
147+
fz_color_convert_fn *convert_via;
148+
fz_colorspace *ds;
149+
fz_colorspace *ss;
150+
fz_colorspace *ss_via;
151+
void *opaque;
152+
#if FZ_ENABLE_ICC
153+
fz_icc_link *link;
154+
#endif
155+
};
156+
157+
fz_color_convert_fn *fz_lookup_fast_color_converter(fz_context *ctx, fz_colorspace *ss, fz_colorspace *ds);
158+
void fz_find_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_colorspace *is, fz_color_params params);
159+
void fz_drop_color_converter(fz_context *ctx, fz_color_converter *cc);
160+
void fz_init_cached_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_colorspace *is, fz_color_params params);
161+
void fz_fin_cached_color_converter(fz_context *ctx, fz_color_converter *cc);
162+
163+
void fz_clamp_color(fz_context *ctx, fz_colorspace *cs, const float *in, float *out);
164+
void fz_convert_color(fz_context *ctx, fz_colorspace *ss, const float *sv, fz_colorspace *ds, float *dv, fz_colorspace *is, fz_color_params params);
165+
166+
/* Default (fallback) colorspace handling */
167+
168+
typedef struct fz_default_colorspaces_s fz_default_colorspaces;
169+
struct fz_default_colorspaces_s
170+
{
171+
int refs;
172+
fz_colorspace *gray;
173+
fz_colorspace *rgb;
174+
fz_colorspace *cmyk;
175+
fz_colorspace *oi;
176+
};
177+
178+
fz_default_colorspaces *fz_new_default_colorspaces(fz_context *ctx);
179+
fz_default_colorspaces* fz_keep_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs);
180+
void fz_drop_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs);
181+
fz_default_colorspaces *fz_clone_default_colorspaces(fz_context *ctx, fz_default_colorspaces *base);
182+
183+
fz_colorspace *fz_default_gray(fz_context *ctx, const fz_default_colorspaces *default_cs);
184+
fz_colorspace *fz_default_rgb(fz_context *ctx, const fz_default_colorspaces *default_cs);
185+
fz_colorspace *fz_default_cmyk(fz_context *ctx, const fz_default_colorspaces *default_cs);
186+
fz_colorspace *fz_default_output_intent(fz_context *ctx, const fz_default_colorspaces *default_cs);
187+
188+
void fz_set_default_gray(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs);
189+
void fz_set_default_rgb(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs);
190+
void fz_set_default_cmyk(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs);
191+
void fz_set_default_output_intent(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs);
192+
193+
/*
194+
Color convert a pixmap. The passing of default_cs is needed due to the base cs of the image possibly
195+
needing to be treated as being in one of the page default color spaces.
196+
*/
197+
void fz_convert_pixmap_samples(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst, fz_colorspace *prf, const fz_default_colorspaces *default_cs, fz_color_params color_params, int copy_spots);
198+
void fz_fast_any_to_alpha(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst, int copy_spots);
199+
void fz_convert_fast_pixmap_samples(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst, int copy_spots);
200+
void fz_convert_slow_pixmap_samples(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst, fz_colorspace *prf, fz_color_params params, int copy_spots);
201+
202+
/* Color management engine */
203+
204+
#if FZ_ENABLE_ICC
205+
206+
void fz_new_icc_context(fz_context *ctx);
207+
void fz_drop_icc_context(fz_context *ctx);
208+
fz_icc_profile *fz_new_icc_profile(fz_context *ctx, unsigned char *data, size_t size);
209+
void fz_drop_icc_profile(fz_context *ctx, fz_icc_profile *profile);
210+
void fz_icc_profile_name(fz_context *ctx, fz_icc_profile *profile, char *name, size_t size);
211+
int fz_icc_profile_components(fz_context *ctx, fz_icc_profile *profile);
212+
fz_icc_link *fz_new_icc_link(fz_context *ctx,
213+
fz_colorspace *src, int src_extras,
214+
fz_colorspace *dst, int dst_extras,
215+
fz_colorspace *prf,
216+
fz_color_params color_params,
217+
int format,
218+
int copy_spots);
219+
void fz_drop_icc_link_imp(fz_context *ctx, fz_storable *link);
220+
void fz_drop_icc_link(fz_context *ctx, fz_icc_link *link);
221+
fz_icc_link *fz_find_icc_link(fz_context *ctx,
222+
fz_colorspace *src, int src_extras,
223+
fz_colorspace *dst, int dst_extras,
224+
fz_colorspace *prf,
225+
fz_color_params color_params,
226+
int format,
227+
int copy_spots);
228+
void fz_icc_transform_color(fz_context *ctx, fz_color_converter *cc, const float *src, float *dst);
229+
void fz_icc_transform_pixmap(fz_context *ctx, fz_icc_link *link, fz_pixmap *src, fz_pixmap *dst, int copy_spots);
230+
231+
#endif
232+
233+
struct fz_colorspace_context_s
234+
{
235+
int ctx_refs;
236+
fz_colorspace *gray, *rgb, *bgr, *cmyk, *lab;
237+
#if FZ_ENABLE_ICC
238+
void *icc_instance;
239+
#endif
240+
};
241+
242+
#endif

0 commit comments

Comments
 (0)