| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* |
|
2
|
|
|
|
|
|
|
* pdfmake_color_mgmt.c — Color management. |
|
3
|
|
|
|
|
|
|
* |
|
4
|
|
|
|
|
|
|
* §8.6 Color Spaces, §14.11.5 Output Intents |
|
5
|
|
|
|
|
|
|
*/ |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#include "pdfmake_color_mgmt.h" |
|
8
|
|
|
|
|
|
|
#include "pdfmake_page.h" |
|
9
|
|
|
|
|
|
|
#include "pdfmake_filter.h" |
|
10
|
|
|
|
|
|
|
#include |
|
11
|
|
|
|
|
|
|
#include |
|
12
|
|
|
|
|
|
|
#include |
|
13
|
|
|
|
|
|
|
#include |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
/* ── Device color space singletons ─────────────────────── */ |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
static pdfmake_colorspace_t _cs_gray = { |
|
18
|
|
|
|
|
|
|
.family = PDFMAKE_CS_DEVICE_GRAY, |
|
19
|
|
|
|
|
|
|
.components = 1, |
|
20
|
|
|
|
|
|
|
.name = "DeviceGray", |
|
21
|
|
|
|
|
|
|
.obj_num = 0, |
|
22
|
|
|
|
|
|
|
}; |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
static pdfmake_colorspace_t _cs_rgb = { |
|
25
|
|
|
|
|
|
|
.family = PDFMAKE_CS_DEVICE_RGB, |
|
26
|
|
|
|
|
|
|
.components = 3, |
|
27
|
|
|
|
|
|
|
.name = "DeviceRGB", |
|
28
|
|
|
|
|
|
|
.obj_num = 0, |
|
29
|
|
|
|
|
|
|
}; |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
static pdfmake_colorspace_t _cs_cmyk = { |
|
32
|
|
|
|
|
|
|
.family = PDFMAKE_CS_DEVICE_CMYK, |
|
33
|
|
|
|
|
|
|
.components = 4, |
|
34
|
|
|
|
|
|
|
.name = "DeviceCMYK", |
|
35
|
|
|
|
|
|
|
.obj_num = 0, |
|
36
|
|
|
|
|
|
|
}; |
|
37
|
|
|
|
|
|
|
|
|
38
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_device_gray(void) { return &_cs_gray; } |
|
39
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_device_rgb(void) { return &_cs_rgb; } |
|
40
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_device_cmyk(void) { return &_cs_cmyk; } |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
/* ── CIE-based ─────────────────────────────────────────── */ |
|
43
|
|
|
|
|
|
|
|
|
44
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_cal_gray( |
|
45
|
|
|
|
|
|
|
pdfmake_arena_t *arena, const double wp[3], |
|
46
|
|
|
|
|
|
|
const double *bp, double gamma_val) |
|
47
|
|
|
|
|
|
|
{ |
|
48
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *cs = calloc(1, sizeof(*cs)); |
|
49
|
0
|
0
|
|
|
|
|
if (!cs) return NULL; |
|
50
|
|
|
|
|
|
|
(void)arena; |
|
51
|
0
|
|
|
|
|
|
cs->family = PDFMAKE_CS_CAL_GRAY; |
|
52
|
0
|
|
|
|
|
|
cs->components = 1; |
|
53
|
0
|
|
|
|
|
|
memcpy(cs->white_point, wp, 3 * sizeof(double)); |
|
54
|
0
|
0
|
|
|
|
|
if (bp) memcpy(cs->black_point, bp, 3 * sizeof(double)); |
|
55
|
0
|
|
|
|
|
|
cs->gamma[0] = gamma_val; |
|
56
|
0
|
|
|
|
|
|
return cs; |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
7
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_cal_rgb( |
|
60
|
|
|
|
|
|
|
pdfmake_arena_t *arena, const double wp[3], |
|
61
|
|
|
|
|
|
|
const double *bp, const double gamma[3], const double matrix[9]) |
|
62
|
|
|
|
|
|
|
{ |
|
63
|
7
|
|
|
|
|
|
pdfmake_colorspace_t *cs = calloc(1, sizeof(*cs)); |
|
64
|
7
|
50
|
|
|
|
|
if (!cs) return NULL; |
|
65
|
|
|
|
|
|
|
(void)arena; |
|
66
|
7
|
|
|
|
|
|
cs->family = PDFMAKE_CS_CAL_RGB; |
|
67
|
7
|
|
|
|
|
|
cs->components = 3; |
|
68
|
7
|
|
|
|
|
|
memcpy(cs->white_point, wp, 3 * sizeof(double)); |
|
69
|
7
|
50
|
|
|
|
|
if (bp) memcpy(cs->black_point, bp, 3 * sizeof(double)); |
|
70
|
7
|
|
|
|
|
|
memcpy(cs->gamma, gamma, 3 * sizeof(double)); |
|
71
|
7
|
|
|
|
|
|
memcpy(cs->matrix, matrix, 9 * sizeof(double)); |
|
72
|
7
|
|
|
|
|
|
return cs; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_lab( |
|
76
|
|
|
|
|
|
|
pdfmake_arena_t *arena, const double wp[3], |
|
77
|
|
|
|
|
|
|
const double *bp, const double range[4]) |
|
78
|
|
|
|
|
|
|
{ |
|
79
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *cs = calloc(1, sizeof(*cs)); |
|
80
|
0
|
0
|
|
|
|
|
if (!cs) return NULL; |
|
81
|
|
|
|
|
|
|
(void)arena; |
|
82
|
0
|
|
|
|
|
|
cs->family = PDFMAKE_CS_LAB; |
|
83
|
0
|
|
|
|
|
|
cs->components = 3; |
|
84
|
0
|
|
|
|
|
|
memcpy(cs->white_point, wp, 3 * sizeof(double)); |
|
85
|
0
|
0
|
|
|
|
|
if (bp) memcpy(cs->black_point, bp, 3 * sizeof(double)); |
|
86
|
0
|
|
|
|
|
|
memcpy(cs->range, range, 4 * sizeof(double)); |
|
87
|
0
|
|
|
|
|
|
return cs; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
/* ── ICC-based ─────────────────────────────────────────── */ |
|
91
|
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_icc_from_data( |
|
93
|
|
|
|
|
|
|
pdfmake_arena_t *arena, const uint8_t *data, size_t len, int components) |
|
94
|
|
|
|
|
|
|
{ |
|
95
|
|
|
|
|
|
|
pdfmake_colorspace_t *cs; |
|
96
|
0
|
0
|
|
|
|
|
if (!data || len == 0) return NULL; |
|
|
|
0
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
(void)arena; |
|
98
|
0
|
|
|
|
|
|
cs = calloc(1, sizeof(*cs)); |
|
99
|
0
|
0
|
|
|
|
|
if (!cs) return NULL; |
|
100
|
0
|
|
|
|
|
|
cs->family = PDFMAKE_CS_ICC_BASED; |
|
101
|
0
|
|
|
|
|
|
cs->components = components; |
|
102
|
0
|
|
|
|
|
|
cs->icc_data = malloc(len); |
|
103
|
0
|
0
|
|
|
|
|
if (!cs->icc_data) { free(cs); return NULL; } |
|
104
|
0
|
|
|
|
|
|
memcpy(cs->icc_data, data, len); |
|
105
|
0
|
|
|
|
|
|
cs->icc_data_len = len; |
|
106
|
0
|
|
|
|
|
|
switch (components) { |
|
107
|
0
|
|
|
|
|
|
case 1: strncpy(cs->icc_alt, "DeviceGray", sizeof(cs->icc_alt)); break; |
|
108
|
0
|
|
|
|
|
|
case 3: strncpy(cs->icc_alt, "DeviceRGB", sizeof(cs->icc_alt)); break; |
|
109
|
0
|
|
|
|
|
|
case 4: strncpy(cs->icc_alt, "DeviceCMYK", sizeof(cs->icc_alt)); break; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
0
|
|
|
|
|
|
return cs; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_icc_from_path( |
|
115
|
|
|
|
|
|
|
pdfmake_arena_t *arena, const char *path, int components) |
|
116
|
|
|
|
|
|
|
{ |
|
117
|
0
|
|
|
|
|
|
FILE *fp = fopen(path, "rb"); |
|
118
|
|
|
|
|
|
|
long len; |
|
119
|
|
|
|
|
|
|
uint8_t *buf; |
|
120
|
|
|
|
|
|
|
pdfmake_colorspace_t *cs; |
|
121
|
0
|
0
|
|
|
|
|
if (!fp) return NULL; |
|
122
|
0
|
|
|
|
|
|
fseek(fp, 0, SEEK_END); |
|
123
|
0
|
|
|
|
|
|
len = ftell(fp); |
|
124
|
0
|
0
|
|
|
|
|
if (len < 0) { fclose(fp); return NULL; } |
|
125
|
0
|
|
|
|
|
|
rewind(fp); |
|
126
|
0
|
|
|
|
|
|
buf = malloc((size_t)len); |
|
127
|
0
|
0
|
|
|
|
|
if (!buf) { fclose(fp); return NULL; } |
|
128
|
0
|
|
|
|
|
|
fread(buf, 1, (size_t)len, fp); |
|
129
|
0
|
|
|
|
|
|
fclose(fp); |
|
130
|
0
|
|
|
|
|
|
cs = pdfmake_cs_icc_from_data(arena, buf, (size_t)len, components); |
|
131
|
0
|
|
|
|
|
|
free(buf); |
|
132
|
0
|
|
|
|
|
|
return cs; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
/* Minimal sRGB ICC profile (D65 white point, 2.2 gamma). |
|
136
|
|
|
|
|
|
|
* We use CalRGB as a fallback since embedding a real ICC profile |
|
137
|
|
|
|
|
|
|
* would require a 3KB+ binary blob. */ |
|
138
|
7
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_srgb(pdfmake_arena_t *arena) { |
|
139
|
7
|
|
|
|
|
|
double wp[3] = {0.9505, 1.0, 1.089}; |
|
140
|
7
|
|
|
|
|
|
double gamma[3] = {2.2, 2.2, 2.2}; |
|
141
|
7
|
|
|
|
|
|
double matrix[9] = { |
|
142
|
|
|
|
|
|
|
0.4124, 0.2126, 0.0193, |
|
143
|
|
|
|
|
|
|
0.3576, 0.7152, 0.1192, |
|
144
|
|
|
|
|
|
|
0.1805, 0.0722, 0.9505 |
|
145
|
|
|
|
|
|
|
}; |
|
146
|
7
|
|
|
|
|
|
return pdfmake_cs_cal_rgb(arena, wp, NULL, gamma, matrix); |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
/* ── Separation ────────────────────────────────────────── */ |
|
150
|
|
|
|
|
|
|
|
|
151
|
6
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_separation( |
|
152
|
|
|
|
|
|
|
pdfmake_arena_t *arena, const char *spot_name, |
|
153
|
|
|
|
|
|
|
double c, double m, double y, double k) |
|
154
|
|
|
|
|
|
|
{ |
|
155
|
|
|
|
|
|
|
pdfmake_colorspace_t *cs; |
|
156
|
|
|
|
|
|
|
(void)arena; |
|
157
|
6
|
|
|
|
|
|
cs = calloc(1, sizeof(*cs)); |
|
158
|
6
|
50
|
|
|
|
|
if (!cs) return NULL; |
|
159
|
6
|
|
|
|
|
|
cs->family = PDFMAKE_CS_SEPARATION; |
|
160
|
6
|
|
|
|
|
|
cs->components = 1; |
|
161
|
6
|
|
|
|
|
|
strncpy(cs->name, spot_name, sizeof(cs->name) - 1); |
|
162
|
6
|
|
|
|
|
|
cs->tint_cmyk[0] = c; |
|
163
|
6
|
|
|
|
|
|
cs->tint_cmyk[1] = m; |
|
164
|
6
|
|
|
|
|
|
cs->tint_cmyk[2] = y; |
|
165
|
6
|
|
|
|
|
|
cs->tint_cmyk[3] = k; |
|
166
|
6
|
|
|
|
|
|
return cs; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
/* ── Indexed ───────────────────────────────────────────── */ |
|
170
|
|
|
|
|
|
|
|
|
171
|
0
|
|
|
|
|
|
pdfmake_colorspace_t *pdfmake_cs_indexed( |
|
172
|
|
|
|
|
|
|
pdfmake_arena_t *arena, pdfmake_colorspace_t *base, |
|
173
|
|
|
|
|
|
|
int max_index, const uint8_t *palette, size_t palette_len) |
|
174
|
|
|
|
|
|
|
{ |
|
175
|
|
|
|
|
|
|
pdfmake_colorspace_t *cs; |
|
176
|
|
|
|
|
|
|
(void)arena; |
|
177
|
0
|
|
|
|
|
|
cs = calloc(1, sizeof(*cs)); |
|
178
|
0
|
0
|
|
|
|
|
if (!cs) return NULL; |
|
179
|
0
|
|
|
|
|
|
cs->family = PDFMAKE_CS_INDEXED; |
|
180
|
0
|
|
|
|
|
|
cs->components = 1; |
|
181
|
0
|
|
|
|
|
|
cs->base = base; |
|
182
|
0
|
|
|
|
|
|
cs->max_index = max_index; |
|
183
|
0
|
|
|
|
|
|
cs->palette = malloc(palette_len); |
|
184
|
0
|
0
|
|
|
|
|
if (!cs->palette) { free(cs); return NULL; } |
|
185
|
0
|
|
|
|
|
|
memcpy(cs->palette, palette, palette_len); |
|
186
|
0
|
|
|
|
|
|
cs->palette_len = palette_len; |
|
187
|
0
|
|
|
|
|
|
return cs; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
/* ── Writing ───────────────────────────────────────────── */ |
|
191
|
|
|
|
|
|
|
|
|
192
|
7
|
|
|
|
|
|
uint32_t pdfmake_cs_write(pdfmake_colorspace_t *cs, pdfmake_doc_t *doc) { |
|
193
|
|
|
|
|
|
|
pdfmake_arena_t *arena; |
|
194
|
|
|
|
|
|
|
uint32_t k; |
|
195
|
|
|
|
|
|
|
|
|
196
|
7
|
50
|
|
|
|
|
if (!cs || !doc) return 0; |
|
|
|
50
|
|
|
|
|
|
|
197
|
7
|
50
|
|
|
|
|
if (cs->obj_num) return cs->obj_num; |
|
198
|
|
|
|
|
|
|
|
|
199
|
7
|
|
|
|
|
|
arena = pdfmake_doc_arena(doc); |
|
200
|
|
|
|
|
|
|
|
|
201
|
7
|
|
|
|
|
|
switch (cs->family) { |
|
202
|
0
|
|
|
|
|
|
case PDFMAKE_CS_DEVICE_GRAY: |
|
203
|
|
|
|
|
|
|
case PDFMAKE_CS_DEVICE_RGB: |
|
204
|
|
|
|
|
|
|
case PDFMAKE_CS_DEVICE_CMYK: |
|
205
|
|
|
|
|
|
|
/* Device spaces are names, not objects */ |
|
206
|
0
|
|
|
|
|
|
return 0; |
|
207
|
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
case PDFMAKE_CS_CAL_GRAY: { |
|
209
|
0
|
|
|
|
|
|
pdfmake_obj_t arr = pdfmake_array_new(arena); |
|
210
|
|
|
|
|
|
|
pdfmake_obj_t dict; |
|
211
|
|
|
|
|
|
|
pdfmake_obj_t wp; |
|
212
|
|
|
|
|
|
|
int i; |
|
213
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "CalGray")); |
|
214
|
0
|
|
|
|
|
|
dict = pdfmake_dict_new(arena); |
|
215
|
0
|
|
|
|
|
|
wp = pdfmake_array_new(arena); |
|
216
|
0
|
0
|
|
|
|
|
for (i = 0; i < 3; i++) |
|
217
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &wp, pdfmake_real(cs->white_point[i])); |
|
218
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "WhitePoint", 10); |
|
219
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict, k, wp); |
|
220
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Gamma", 5); |
|
221
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict, k, pdfmake_real(cs->gamma[0])); |
|
222
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, dict); |
|
223
|
0
|
|
|
|
|
|
cs->obj_num = pdfmake_doc_add(doc, arr); |
|
224
|
0
|
|
|
|
|
|
return cs->obj_num; |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
|
|
227
|
4
|
|
|
|
|
|
case PDFMAKE_CS_CAL_RGB: { |
|
228
|
4
|
|
|
|
|
|
pdfmake_obj_t arr = pdfmake_array_new(arena); |
|
229
|
|
|
|
|
|
|
pdfmake_obj_t dict; |
|
230
|
|
|
|
|
|
|
pdfmake_obj_t wp; |
|
231
|
|
|
|
|
|
|
pdfmake_obj_t gm; |
|
232
|
|
|
|
|
|
|
pdfmake_obj_t mx; |
|
233
|
|
|
|
|
|
|
int i; |
|
234
|
4
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "CalRGB")); |
|
235
|
4
|
|
|
|
|
|
dict = pdfmake_dict_new(arena); |
|
236
|
4
|
|
|
|
|
|
wp = pdfmake_array_new(arena); |
|
237
|
4
|
|
|
|
|
|
gm = pdfmake_array_new(arena); |
|
238
|
4
|
|
|
|
|
|
mx = pdfmake_array_new(arena); |
|
239
|
16
|
100
|
|
|
|
|
for (i = 0; i < 3; i++) { |
|
240
|
12
|
|
|
|
|
|
pdfmake_array_push(arena, &wp, pdfmake_real(cs->white_point[i])); |
|
241
|
12
|
|
|
|
|
|
pdfmake_array_push(arena, &gm, pdfmake_real(cs->gamma[i])); |
|
242
|
|
|
|
|
|
|
} |
|
243
|
40
|
100
|
|
|
|
|
for (i = 0; i < 9; i++) |
|
244
|
36
|
|
|
|
|
|
pdfmake_array_push(arena, &mx, pdfmake_real(cs->matrix[i])); |
|
245
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "WhitePoint", 10); |
|
246
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict, k, wp); |
|
247
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Gamma", 5); |
|
248
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict, k, gm); |
|
249
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Matrix", 6); |
|
250
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict, k, mx); |
|
251
|
4
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, dict); |
|
252
|
4
|
|
|
|
|
|
cs->obj_num = pdfmake_doc_add(doc, arr); |
|
253
|
4
|
|
|
|
|
|
return cs->obj_num; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
0
|
|
|
|
|
|
case PDFMAKE_CS_LAB: { |
|
257
|
0
|
|
|
|
|
|
pdfmake_obj_t arr = pdfmake_array_new(arena); |
|
258
|
|
|
|
|
|
|
pdfmake_obj_t dict; |
|
259
|
|
|
|
|
|
|
pdfmake_obj_t wp; |
|
260
|
|
|
|
|
|
|
pdfmake_obj_t rng; |
|
261
|
|
|
|
|
|
|
int i; |
|
262
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "Lab")); |
|
263
|
0
|
|
|
|
|
|
dict = pdfmake_dict_new(arena); |
|
264
|
0
|
|
|
|
|
|
wp = pdfmake_array_new(arena); |
|
265
|
0
|
|
|
|
|
|
rng = pdfmake_array_new(arena); |
|
266
|
0
|
0
|
|
|
|
|
for (i = 0; i < 3; i++) |
|
267
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &wp, pdfmake_real(cs->white_point[i])); |
|
268
|
0
|
0
|
|
|
|
|
for (i = 0; i < 4; i++) |
|
269
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &rng, pdfmake_real(cs->range[i])); |
|
270
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "WhitePoint", 10); |
|
271
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict, k, wp); |
|
272
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Range", 5); |
|
273
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict, k, rng); |
|
274
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, dict); |
|
275
|
0
|
|
|
|
|
|
cs->obj_num = pdfmake_doc_add(doc, arr); |
|
276
|
0
|
|
|
|
|
|
return cs->obj_num; |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
case PDFMAKE_CS_ICC_BASED: { |
|
280
|
|
|
|
|
|
|
/* ICC profile as stream */ |
|
281
|
0
|
|
|
|
|
|
pdfmake_obj_t stream = pdfmake_stream_new(arena); |
|
282
|
|
|
|
|
|
|
pdfmake_obj_t dict_obj; |
|
283
|
|
|
|
|
|
|
uint32_t stream_num; |
|
284
|
|
|
|
|
|
|
pdfmake_obj_t arr; |
|
285
|
0
|
|
|
|
|
|
pdfmake_stream_set_data(arena, &stream, cs->icc_data, cs->icc_data_len); |
|
286
|
0
|
|
|
|
|
|
dict_obj.kind = PDFMAKE_DICT; |
|
287
|
0
|
|
|
|
|
|
dict_obj.as.dict = pdfmake_stream_dict(&stream); |
|
288
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "N", 1); |
|
289
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict_obj, k, pdfmake_int(cs->components)); |
|
290
|
0
|
0
|
|
|
|
|
if (cs->icc_alt[0]) { |
|
291
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Alternate", 9); |
|
292
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict_obj, k, pdfmake_name_cstr(arena, cs->icc_alt)); |
|
293
|
|
|
|
|
|
|
} |
|
294
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Length", 6); |
|
295
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &dict_obj, k, pdfmake_int((int64_t)cs->icc_data_len)); |
|
296
|
0
|
|
|
|
|
|
stream_num = pdfmake_doc_add(doc, stream); |
|
297
|
|
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
arr = pdfmake_array_new(arena); |
|
299
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "ICCBased")); |
|
300
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_ref(stream_num, 0)); |
|
301
|
0
|
|
|
|
|
|
cs->obj_num = pdfmake_doc_add(doc, arr); |
|
302
|
0
|
|
|
|
|
|
return cs->obj_num; |
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
|
|
305
|
3
|
|
|
|
|
|
case PDFMAKE_CS_SEPARATION: { |
|
306
|
|
|
|
|
|
|
/* [/Separation /Name /DeviceCMYK tint_fn] */ |
|
307
|
3
|
|
|
|
|
|
pdfmake_obj_t arr = pdfmake_array_new(arena); |
|
308
|
|
|
|
|
|
|
char fn_body[128]; |
|
309
|
|
|
|
|
|
|
pdfmake_obj_t fn_stream; |
|
310
|
|
|
|
|
|
|
pdfmake_obj_t fn_dict_obj; |
|
311
|
|
|
|
|
|
|
pdfmake_obj_t domain; |
|
312
|
|
|
|
|
|
|
pdfmake_obj_t range; |
|
313
|
|
|
|
|
|
|
int i; |
|
314
|
|
|
|
|
|
|
uint32_t fn_num; |
|
315
|
3
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "Separation")); |
|
316
|
3
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, cs->name)); |
|
317
|
3
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "DeviceCMYK")); |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
/* Type 4 PostScript calculator function: { c m y k } scaled by tint */ |
|
320
|
3
|
|
|
|
|
|
snprintf(fn_body, sizeof(fn_body), |
|
321
|
|
|
|
|
|
|
"{ dup %g mul exch dup %g mul exch dup %g mul exch %g mul }", |
|
322
|
|
|
|
|
|
|
cs->tint_cmyk[0], cs->tint_cmyk[1], cs->tint_cmyk[2], cs->tint_cmyk[3]); |
|
323
|
|
|
|
|
|
|
|
|
324
|
3
|
|
|
|
|
|
fn_stream = pdfmake_stream_new(arena); |
|
325
|
3
|
|
|
|
|
|
pdfmake_stream_set_data(arena, &fn_stream, |
|
326
|
|
|
|
|
|
|
(const uint8_t *)fn_body, strlen(fn_body)); |
|
327
|
3
|
|
|
|
|
|
fn_dict_obj.kind = PDFMAKE_DICT; |
|
328
|
3
|
|
|
|
|
|
fn_dict_obj.as.dict = pdfmake_stream_dict(&fn_stream); |
|
329
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "FunctionType", 12); |
|
330
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, &fn_dict_obj, k, pdfmake_int(4)); |
|
331
|
3
|
|
|
|
|
|
domain = pdfmake_array_new(arena); |
|
332
|
3
|
|
|
|
|
|
pdfmake_array_push(arena, &domain, pdfmake_real(0)); |
|
333
|
3
|
|
|
|
|
|
pdfmake_array_push(arena, &domain, pdfmake_real(1)); |
|
334
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Domain", 6); |
|
335
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, &fn_dict_obj, k, domain); |
|
336
|
3
|
|
|
|
|
|
range = pdfmake_array_new(arena); |
|
337
|
15
|
100
|
|
|
|
|
for (i = 0; i < 4; i++) { |
|
338
|
12
|
|
|
|
|
|
pdfmake_array_push(arena, &range, pdfmake_real(0)); |
|
339
|
12
|
|
|
|
|
|
pdfmake_array_push(arena, &range, pdfmake_real(1)); |
|
340
|
|
|
|
|
|
|
} |
|
341
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Range", 5); |
|
342
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, &fn_dict_obj, k, range); |
|
343
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Length", 6); |
|
344
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, &fn_dict_obj, k, pdfmake_int((int64_t)strlen(fn_body))); |
|
345
|
|
|
|
|
|
|
|
|
346
|
3
|
|
|
|
|
|
fn_num = pdfmake_doc_add(doc, fn_stream); |
|
347
|
3
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_ref(fn_num, 0)); |
|
348
|
|
|
|
|
|
|
|
|
349
|
3
|
|
|
|
|
|
cs->obj_num = pdfmake_doc_add(doc, arr); |
|
350
|
3
|
|
|
|
|
|
return cs->obj_num; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
0
|
|
|
|
|
|
case PDFMAKE_CS_INDEXED: { |
|
354
|
0
|
|
|
|
|
|
pdfmake_obj_t arr = pdfmake_array_new(arena); |
|
355
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "Indexed")); |
|
356
|
|
|
|
|
|
|
/* Base color space name */ |
|
357
|
0
|
0
|
|
|
|
|
if (cs->base) { |
|
358
|
0
|
|
|
|
|
|
const char *base_name = "DeviceRGB"; |
|
359
|
0
|
|
|
|
|
|
switch (cs->base->family) { |
|
360
|
0
|
|
|
|
|
|
case PDFMAKE_CS_DEVICE_GRAY: base_name = "DeviceGray"; break; |
|
361
|
0
|
|
|
|
|
|
case PDFMAKE_CS_DEVICE_RGB: base_name = "DeviceRGB"; break; |
|
362
|
0
|
|
|
|
|
|
case PDFMAKE_CS_DEVICE_CMYK: base_name = "DeviceCMYK"; break; |
|
363
|
0
|
|
|
|
|
|
default: break; |
|
364
|
|
|
|
|
|
|
} |
|
365
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, base_name)); |
|
366
|
|
|
|
|
|
|
} else { |
|
367
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_name_cstr(arena, "DeviceRGB")); |
|
368
|
|
|
|
|
|
|
} |
|
369
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, pdfmake_int(cs->max_index)); |
|
370
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &arr, |
|
371
|
0
|
|
|
|
|
|
pdfmake_hexstr(arena, cs->palette, cs->palette_len)); |
|
372
|
0
|
|
|
|
|
|
cs->obj_num = pdfmake_doc_add(doc, arr); |
|
373
|
0
|
|
|
|
|
|
return cs->obj_num; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
0
|
|
|
|
|
|
default: |
|
377
|
0
|
|
|
|
|
|
return 0; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
/* ── Output intent ─────────────────────────────────────── */ |
|
382
|
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_doc_set_output_intent( |
|
384
|
|
|
|
|
|
|
pdfmake_doc_t *doc, |
|
385
|
|
|
|
|
|
|
pdfmake_output_intent_type_t type, |
|
386
|
|
|
|
|
|
|
pdfmake_colorspace_t *dest_profile, |
|
387
|
|
|
|
|
|
|
const char *condition, |
|
388
|
|
|
|
|
|
|
const char *info) |
|
389
|
|
|
|
|
|
|
{ |
|
390
|
|
|
|
|
|
|
pdfmake_arena_t *arena; |
|
391
|
|
|
|
|
|
|
uint32_t k; |
|
392
|
|
|
|
|
|
|
const char *subtype; |
|
393
|
|
|
|
|
|
|
pdfmake_obj_t intent; |
|
394
|
|
|
|
|
|
|
pdfmake_obj_t *catalog; |
|
395
|
|
|
|
|
|
|
pdfmake_obj_t intents_arr; |
|
396
|
|
|
|
|
|
|
|
|
397
|
0
|
0
|
|
|
|
|
if (!doc || !condition) return PDFMAKE_EINVAL; |
|
|
|
0
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
/* Must be called after finalize (catalog exists) */ |
|
399
|
0
|
0
|
|
|
|
|
if (!doc->finalized || doc->root_num == 0) return PDFMAKE_EINVAL; |
|
|
|
0
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
|
arena = pdfmake_doc_arena(doc); |
|
402
|
|
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
|
switch (type) { |
|
404
|
0
|
|
|
|
|
|
case PDFMAKE_INTENT_GTS_PDFX: subtype = "GTS_PDFX"; break; |
|
405
|
0
|
|
|
|
|
|
case PDFMAKE_INTENT_GTS_PDFA: subtype = "GTS_PDFA1"; break; |
|
406
|
0
|
|
|
|
|
|
case PDFMAKE_INTENT_ISO_PDFE: subtype = "ISO_PDFE1"; break; |
|
407
|
0
|
|
|
|
|
|
default: subtype = "GTS_PDFX"; break; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
intent = pdfmake_dict_new(arena); |
|
411
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Type", 4); |
|
412
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &intent, k, pdfmake_name_cstr(arena, "OutputIntent")); |
|
413
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "S", 1); |
|
414
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &intent, k, pdfmake_name_cstr(arena, subtype)); |
|
415
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "OutputConditionIdentifier", 25); |
|
416
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &intent, k, pdfmake_str_cstr(arena, condition)); |
|
417
|
0
|
0
|
|
|
|
|
if (info) { |
|
418
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Info", 4); |
|
419
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &intent, k, pdfmake_str_cstr(arena, info)); |
|
420
|
|
|
|
|
|
|
} |
|
421
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "RegistryName", 12); |
|
422
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &intent, k, pdfmake_str_cstr(arena, "http://www.color.org")); |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
/* Write ICC profile if provided */ |
|
425
|
0
|
0
|
|
|
|
|
if (dest_profile && dest_profile->family == PDFMAKE_CS_ICC_BASED) { |
|
|
|
0
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
uint32_t profile_num = pdfmake_cs_write(dest_profile, doc); |
|
427
|
0
|
0
|
|
|
|
|
if (profile_num > 0) { |
|
428
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "DestOutputProfile", 17); |
|
429
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &intent, k, pdfmake_ref(profile_num, 0)); |
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
} |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
/* /OutputIntents [intent] on catalog */ |
|
434
|
0
|
|
|
|
|
|
catalog = pdfmake_doc_get(doc, doc->root_num); |
|
435
|
0
|
0
|
|
|
|
|
if (!catalog || catalog->kind != PDFMAKE_DICT) return PDFMAKE_EINVAL; |
|
|
|
0
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
|
|
437
|
0
|
|
|
|
|
|
intents_arr = pdfmake_array_new(arena); |
|
438
|
0
|
|
|
|
|
|
pdfmake_array_push(arena, &intents_arr, intent); |
|
439
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "OutputIntents", 13); |
|
440
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, catalog, k, intents_arr); |
|
441
|
|
|
|
|
|
|
|
|
442
|
0
|
|
|
|
|
|
return PDFMAKE_OK; |
|
443
|
|
|
|
|
|
|
} |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
/* ── Basic conversion ──────────────────────────────────── */ |
|
446
|
|
|
|
|
|
|
|
|
447
|
3
|
|
|
|
|
|
void pdfmake_rgb_to_cmyk(double r, double g, double b, |
|
448
|
|
|
|
|
|
|
double *c, double *m, double *y, double *k_out) { |
|
449
|
3
|
|
|
|
|
|
double k_val = 1.0 - fmax(fmax(r, g), b); |
|
450
|
3
|
50
|
|
|
|
|
if (k_val >= 1.0) { |
|
451
|
0
|
|
|
|
|
|
*c = 0; *m = 0; *y = 0; *k_out = 1.0; |
|
452
|
|
|
|
|
|
|
} else { |
|
453
|
3
|
|
|
|
|
|
*c = (1.0 - r - k_val) / (1.0 - k_val); |
|
454
|
3
|
|
|
|
|
|
*m = (1.0 - g - k_val) / (1.0 - k_val); |
|
455
|
3
|
|
|
|
|
|
*y = (1.0 - b - k_val) / (1.0 - k_val); |
|
456
|
3
|
|
|
|
|
|
*k_out = k_val; |
|
457
|
|
|
|
|
|
|
} |
|
458
|
3
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
|
|
460
|
4
|
|
|
|
|
|
void pdfmake_cmyk_to_rgb(double c, double m, double y, double k, |
|
461
|
|
|
|
|
|
|
double *r, double *g, double *b) { |
|
462
|
4
|
|
|
|
|
|
*r = (1.0 - c) * (1.0 - k); |
|
463
|
4
|
|
|
|
|
|
*g = (1.0 - m) * (1.0 - k); |
|
464
|
4
|
|
|
|
|
|
*b = (1.0 - y) * (1.0 - k); |
|
465
|
4
|
|
|
|
|
|
} |
|
466
|
|
|
|
|
|
|
|
|
467
|
0
|
|
|
|
|
|
void pdfmake_gray_to_rgb(double gray, double *r, double *g, double *b) { |
|
468
|
0
|
|
|
|
|
|
*r = *g = *b = gray; |
|
469
|
0
|
|
|
|
|
|
} |
|
470
|
|
|
|
|
|
|
|
|
471
|
5
|
|
|
|
|
|
int pdfmake_hex_to_rgb(const char *hex, double *r, double *g, double *b) { |
|
472
|
|
|
|
|
|
|
unsigned int rv, gv, bv; |
|
473
|
|
|
|
|
|
|
size_t len; |
|
474
|
5
|
50
|
|
|
|
|
if (!hex) return -1; |
|
475
|
5
|
100
|
|
|
|
|
if (*hex == '#') hex++; |
|
476
|
5
|
|
|
|
|
|
len = strlen(hex); |
|
477
|
5
|
50
|
|
|
|
|
if (len == 3) { |
|
478
|
0
|
0
|
|
|
|
|
if (sscanf(hex, "%1x%1x%1x", &rv, &gv, &bv) != 3) return -1; |
|
479
|
0
|
|
|
|
|
|
*r = (rv * 17) / 255.0; |
|
480
|
0
|
|
|
|
|
|
*g = (gv * 17) / 255.0; |
|
481
|
0
|
|
|
|
|
|
*b = (bv * 17) / 255.0; |
|
482
|
5
|
100
|
|
|
|
|
} else if (len == 6) { |
|
483
|
4
|
50
|
|
|
|
|
if (sscanf(hex, "%2x%2x%2x", &rv, &gv, &bv) != 3) return -1; |
|
484
|
4
|
|
|
|
|
|
*r = rv / 255.0; |
|
485
|
4
|
|
|
|
|
|
*g = gv / 255.0; |
|
486
|
4
|
|
|
|
|
|
*b = bv / 255.0; |
|
487
|
|
|
|
|
|
|
} else { |
|
488
|
1
|
|
|
|
|
|
return -1; |
|
489
|
|
|
|
|
|
|
} |
|
490
|
4
|
|
|
|
|
|
return 0; |
|
491
|
|
|
|
|
|
|
} |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
/* ── Cleanup ───────────────────────────────────────────── */ |
|
494
|
|
|
|
|
|
|
|
|
495
|
13
|
|
|
|
|
|
void pdfmake_cs_free(pdfmake_colorspace_t *cs) { |
|
496
|
13
|
50
|
|
|
|
|
if (!cs) return; |
|
497
|
|
|
|
|
|
|
/* Don't free singletons */ |
|
498
|
13
|
50
|
|
|
|
|
if (cs == &_cs_gray || cs == &_cs_rgb || cs == &_cs_cmyk) return; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
499
|
13
|
|
|
|
|
|
free(cs->icc_data); |
|
500
|
13
|
|
|
|
|
|
free(cs->palette); |
|
501
|
13
|
|
|
|
|
|
free(cs); |
|
502
|
|
|
|
|
|
|
} |