1 /*
2 Copyright (c) 2011-2013, Richard Hughes
3 Copyright (c) 2014, Joseph Simon
4
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 MIT Open Source License - http://www.opensource.org/
25
26 */
27
28
29 #include "colormanager.h"
30 #include <cupsfilters/colord.h>
31 //#include <cupsfilters/kmdevices.h>
32
33
34 #define CM_MAX_FILE_LENGTH 1024
35
36
37 /* Private function prototypes */
38 static int _get_colord_printer_cm_status (const char *printer_name);
39 static char *_get_colord_printer_id (const char *printer_name);
40 static int _get_colord_profile (const char *printer_name,
41 char **profile,
42 ppd_file_t *ppd);
43 static char *_get_ppd_icc_fallback (ppd_file_t *ppd,
44 char **qualifier);
45
46
47
48 /* Commonly-used calibration numbers */
49
50 double adobergb_wp[3] = {0.95045471, 1.0, 1.08905029};
51 double sgray_wp[3] = {0.9505, 1, 1.0890};
52 double adobergb_gamma[3] = {2.2, 2.2, 2.2};
53 double sgray_gamma[1] = {2.2};
54 double adobergb_matrix[9] = {0.60974121, 0.20527649, 0.14918518,
55 0.31111145, 0.62567139, 0.06321716,
56 0.01947021, 0.06086731, 0.74456787};
57 double blackpoint_default[3] = {0.0, 0.0, 0.0};
58
59
60
61
62 /*
63 * Public functions
64 */
65
66
67 /* Get printer color management status from the system's color manager */
68 int
cmIsPrinterCmDisabled(const char * printer_name)69 cmIsPrinterCmDisabled(const char *printer_name) /* dest name */
70 {
71
72 int is_cm_off = 0; /* color management status flag */
73
74
75 /* Request color management status from colord */
76 is_cm_off = _get_colord_printer_cm_status(printer_name);
77
78 if (is_cm_off)
79 fprintf(stderr,"DEBUG: Color Manager: Color management disabled by OS.\n");
80
81 return is_cm_off;
82
83 }
84
85
86 /* Get printer ICC profile from the system's color manager */
87 int
cmGetPrinterIccProfile(const char * printer_name,char ** icc_profile,ppd_file_t * ppd)88 cmGetPrinterIccProfile(const char *printer_name, /* Printer name (usually "dest" name) */
89 char **icc_profile, /* ICC Profile Path */
90 ppd_file_t *ppd) /* Optional PPD file for fallback profile */
91 {
92
93 int profile_set = 0; /* 'is profile found' flag */
94
95
96 /* Request a profile from colord */
97 profile_set = _get_colord_profile(printer_name, icc_profile, ppd);
98
99 fprintf(stderr, "DEBUG: Color Manager: ICC Profile: %s\n", *icc_profile ?
100 *icc_profile : "None");
101
102 return profile_set;
103
104 }
105
106
107 /* Find the "cm-calibration" CUPS option */
108 cm_calibration_t
cmGetCupsColorCalibrateMode(cups_option_t * options,int num_options)109 cmGetCupsColorCalibrateMode(cups_option_t *options, /* Options from CUPS */
110 int num_options) /* Options from CUPS */
111 {
112
113 cm_calibration_t status; /* color management status */
114
115
116 /* Find the string in CUPS options and */
117 if (cupsGetOption(CM_CALIBRATION_STRING, num_options, options) != NULL)
118 status = CM_CALIBRATION_ENABLED;
119 else
120 status = CM_CALIBRATION_DISABLED;
121
122 fprintf(stderr, "DEBUG: Color Manager: %s\n", status ?
123 "Calibration Mode/Enabled" : "Calibration Mode/Off");
124
125 return status;
126
127 }
128
129
130 /* Functions to return specific calibration data */
131
132
133 /* Gamma values */
134
cmGammaAdobeRgb(void)135 double *cmGammaAdobeRgb(void)
136 {
137 return adobergb_gamma;
138 }
cmGammaSGray(void)139 double *cmGammaSGray(void)
140 {
141 return sgray_gamma;
142 }
143
144
145 /* Whitepoint values */
146
cmWhitePointAdobeRgb(void)147 double *cmWhitePointAdobeRgb(void)
148 {
149 return adobergb_wp;
150 }
cmWhitePointSGray(void)151 double *cmWhitePointSGray(void)
152 {
153 return sgray_wp;
154 }
155
156
157 /* Adapted primaries matrix */
158
cmMatrixAdobeRgb(void)159 double *cmMatrixAdobeRgb(void)
160 {
161 return adobergb_matrix;
162 }
163
164
165 /* Blackpoint value */
166
cmBlackPointDefault(void)167 double *cmBlackPointDefault(void)
168 {
169 return blackpoint_default;
170 }
171
172
173
174
175 /*
176 * Private functions
177 */
178
179
180 char *
_get_colord_printer_id(const char * printer_name)181 _get_colord_printer_id(const char *printer_name) /* Dest name */
182 {
183
184 if (printer_name == NULL) {
185 fprintf(stderr, "DEBUG: Color Manager: Invalid printer name.\n");
186 return 0;
187 }
188
189 /* Create printer id string for colord */
190 char* printer_id = (char*)malloc(CM_MAX_FILE_LENGTH);
191 snprintf (printer_id, CM_MAX_FILE_LENGTH, "cups-%s", printer_name);
192
193 return printer_id;
194
195 }
196
197
198 int
_get_colord_printer_cm_status(const char * printer_name)199 _get_colord_printer_cm_status(const char *printer_name) /* Dest name */
200 {
201
202 /* If invalid input, we leave color management alone */
203 if (printer_name == NULL) {
204 fprintf(stderr, "DEBUG: Color Manager: Invalid printer name.\n");
205 return 0;
206 } else if (!strcmp(printer_name, "(null)"))
207 return 0;
208
209 int is_printer_cm_disabled = 0; /* color management status flag */
210 char *printer_id = 0; /* colord printer id string */
211
212
213 /* Check if device is inhibited/disabled in colord */
214 printer_id = _get_colord_printer_id(printer_name);
215 is_printer_cm_disabled = colord_get_inhibit_for_device_id (printer_id);
216
217 if (printer_id != NULL)
218 free(printer_id);
219
220 return is_printer_cm_disabled;
221
222 }
223
224 int
_get_colord_profile(const char * printer_name,char ** profile,ppd_file_t * ppd)225 _get_colord_profile(const char *printer_name, /* Dest name */
226 char **profile, /* Requested icc profile path */
227 ppd_file_t *ppd) /* PPD file */
228 {
229
230 if (printer_name == NULL || profile == 0) {
231 fprintf(stderr, "DEBUG: Color Manager: Invalid input - Unable to find profile.\n");
232 return -1;
233 }
234
235 int is_profile_set = 0; /* profile-is-found flag */
236 char **qualifier = NULL; /* color qualifier strings */
237 char *icc_profile = NULL; /* icc profile path */
238 char *printer_id = NULL; /* colord printer id */
239
240
241 /* Get color qualifier triple */
242 qualifier = colord_get_qualifier_for_ppd(ppd);
243
244 if (qualifier != NULL) {
245 printer_id = _get_colord_printer_id(printer_name);
246 /* Get profile from colord using qualifiers */
247 icc_profile = colord_get_profile_for_device_id ((const char *)printer_id,
248 (const char **)qualifier);
249 }
250
251 if (icc_profile)
252 is_profile_set = 1;
253 else if (ppd) {
254 /* Get optional fallback PPD profile */
255 icc_profile = _get_ppd_icc_fallback(ppd, qualifier);
256 if (icc_profile)
257 is_profile_set = 1;
258 }
259
260 /* If a profile is found, we give it to the caller */
261 if (is_profile_set)
262 *profile = strdup(icc_profile);
263 else
264 *profile = 0;
265
266 if (printer_id != NULL)
267 free(printer_id);
268
269 if (qualifier != NULL) {
270 for (int i=0; qualifier[i] != NULL; i++)
271 free(qualifier[i]);
272 free(qualifier);
273 }
274
275 if (icc_profile != NULL)
276 free(icc_profile);
277
278 return is_profile_set;
279
280 }
281
282
283 #ifndef CUPSDATA
284 #define CUPSDATA "/usr/share/cups"
285 #endif
286
287 /* From gstoraster */
288 char *
_get_ppd_icc_fallback(ppd_file_t * ppd,char ** qualifier)289 _get_ppd_icc_fallback (ppd_file_t *ppd, char **qualifier)
290 {
291 char full_path[1024];
292 char *icc_profile = NULL;
293 char qualifer_tmp[1024];
294 const char *profile_key;
295 ppd_attr_t *attr;
296
297 /* get profile attr, falling back to CUPS */
298 profile_key = "APTiogaProfile";
299 attr = ppdFindAttr(ppd, profile_key, NULL);
300 if (attr == NULL) {
301 profile_key = "cupsICCProfile";
302 attr = ppdFindAttr(ppd, profile_key, NULL);
303 }
304
305 /* create a string for a quick comparion */
306 snprintf(qualifer_tmp, sizeof(qualifer_tmp),
307 "%s.%s.%s",
308 qualifier[0],
309 qualifier[1],
310 qualifier[2]);
311
312 /* neither */
313 if (attr == NULL) {
314 fprintf(stderr, "INFO: Color Manager: no profiles specified in PPD\n");
315 goto out;
316 }
317
318 /* try to find a profile that matches the qualifier exactly */
319 for (;attr != NULL; attr = ppdFindNextAttr(ppd, profile_key, NULL)) {
320 fprintf(stderr, "INFO: Color Manager: found profile %s in PPD with qualifier '%s'\n",
321 attr->value, attr->spec);
322
323 /* invalid entry */
324 if (attr->spec == NULL || attr->value == NULL)
325 continue;
326
327 /* expand to a full path if not already specified */
328 if (attr->value[0] != '/')
329 snprintf(full_path, sizeof(full_path),
330 "%s/profiles/%s", CUPSDATA, attr->value);
331 else {
332 strncpy(full_path, attr->value, sizeof(full_path) - 1);
333 if (strlen(attr->value) > 1023)
334 full_path[1023] = '\0';
335 }
336
337 /* check the file exists */
338 if (access(full_path, 0)) {
339 fprintf(stderr, "INFO: Color Manager: found profile %s in PPD that does not exist\n",
340 full_path);
341 continue;
342 }
343
344 /* matches the qualifier */
345 if (strcmp(qualifer_tmp, attr->spec) == 0) {
346 icc_profile = strdup(full_path);
347 goto out;
348 }
349 }
350
351 /* no match */
352 if (attr == NULL) {
353 fprintf(stderr, "INFO: Color Manager: no profiles in PPD for qualifier '%s'\n",
354 qualifer_tmp);
355 goto out;
356 }
357
358 out:
359 return icc_profile;
360 }
361
362