1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2014 Richard Hughes <richard@hughsie.com>
4 *
5 * Licensed under the GNU Lesser General Public License Version 2.1
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22
23 /**
24 * SECTION:cd-context-lcms
25 * @short_description: Functionality to save per-thread context data for LCMS2
26 */
27
28 #include "config.h"
29
30 #include <lcms2.h>
31 #include <lcms2_plugin.h>
32
33 #include "cd-context-lcms.h"
34 #include "cd-icc.h" /* for the error codes */
35
36 /*< private >*/
37 #define LCMS_CURVE_PLUGIN_TYPE_REC709 1024
38
39 /**
40 * cd_context_lcms_get_error:
41 **/
42 static GError **
cd_context_lcms_get_error(gpointer ctx)43 cd_context_lcms_get_error (gpointer ctx)
44 {
45 return cmsGetContextUserData (ctx);
46 }
47
48 /**
49 * cd_context_lcms2_error_cb:
50 **/
51 static void
cd_context_lcms2_error_cb(cmsContext context_id,cmsUInt32Number code,const gchar * message)52 cd_context_lcms2_error_cb (cmsContext context_id,
53 cmsUInt32Number code,
54 const gchar *message)
55 {
56 gint error_code;
57 GError **error_ctx;
58
59 /* nothing set, must be pre-2.6 */
60 if (context_id == NULL) {
61 g_warning ("Error handler called with no context: %s", message);
62 return;
63 }
64
65 /* there's already one error pending */
66 error_ctx = cd_context_lcms_get_error (context_id);
67 if (*error_ctx != NULL) {
68 g_prefix_error (error_ctx, "%s & ", message);
69 return;
70 }
71
72 /* convert the first cmsERROR in into a CdIccError */
73 switch (code) {
74 case cmsERROR_CORRUPTION_DETECTED:
75 error_code = CD_ICC_ERROR_CORRUPTION_DETECTED;
76 break;
77 case cmsERROR_FILE:
78 case cmsERROR_READ:
79 case cmsERROR_SEEK:
80 error_code = CD_ICC_ERROR_FAILED_TO_OPEN;
81 break;
82 case cmsERROR_WRITE:
83 error_code = CD_ICC_ERROR_FAILED_TO_SAVE;
84 break;
85 case cmsERROR_COLORSPACE_CHECK:
86 error_code = CD_ICC_ERROR_INVALID_COLORSPACE;
87 break;
88 case cmsERROR_BAD_SIGNATURE:
89 error_code = CD_ICC_ERROR_FAILED_TO_PARSE;
90 break;
91 case cmsERROR_ALREADY_DEFINED:
92 case cmsERROR_INTERNAL:
93 case cmsERROR_NOT_SUITABLE:
94 case cmsERROR_NULL:
95 case cmsERROR_RANGE:
96 case cmsERROR_UNDEFINED:
97 case cmsERROR_UNKNOWN_EXTENSION:
98 error_code = CD_ICC_ERROR_INTERNAL;
99 break;
100 default:
101 g_warning ("LCMS2 error code not recognised; please report");
102 error_code = CD_ICC_ERROR_INTERNAL;
103 }
104 error_ctx = cd_context_lcms_get_error (context_id);
105 g_set_error_literal (error_ctx, CD_ICC_ERROR, error_code, message);
106 }
107
108 /**
109 * cd_context_lcms_plugins_cb:
110 **/
111 static double
cd_context_lcms_plugins_cb(int type,const double params[],double x)112 cd_context_lcms_plugins_cb (int type, const double params[], double x)
113 {
114 gdouble val = 0.f;
115
116 switch (type) {
117 case -LCMS_CURVE_PLUGIN_TYPE_REC709:
118 if (x < params[4])
119 val = x * params[3];
120 else
121 val = params[1] * pow (x, (1.f / params[0])) + params[2];
122 break;
123 case LCMS_CURVE_PLUGIN_TYPE_REC709:
124 if (x <= (params[3] * params[4]))
125 val = x / params[3];
126 else
127 val = pow (((x + params[2]) / params[1]), params[0]);
128 break;
129 }
130 return val;
131 }
132
133 cmsPluginParametricCurves cd_icc_lcms_plugins = {
134 { cmsPluginMagicNumber, /* 'acpp' */
135 2000, /* minimum version */
136 cmsPluginParametricCurveSig, /* type */
137 NULL }, /* no more plugins */
138 1, /* number functions */
139 {LCMS_CURVE_PLUGIN_TYPE_REC709}, /* function types */
140 {5}, /* parameter count */
141 cd_context_lcms_plugins_cb /* evaluator */
142 };
143
144 /**
145 * cd_context_lcms_new:
146 *
147 * Return value: (transfer full): A new LCMS context
148 **/
149 gpointer
cd_context_lcms_new(void)150 cd_context_lcms_new (void)
151 {
152 cmsContext ctx;
153 GError **error_ctx;
154 error_ctx = g_new0 (GError *, 1);
155 ctx = cmsCreateContext (NULL, error_ctx);
156 cmsSetLogErrorHandlerTHR (ctx, cd_context_lcms2_error_cb);
157 cmsPluginTHR (ctx, &cd_icc_lcms_plugins);
158 return ctx;
159 }
160
161 /**
162 * cd_context_lcms_free:
163 **/
164 void
cd_context_lcms_free(gpointer ctx)165 cd_context_lcms_free (gpointer ctx)
166 {
167 GError **error_ctx;
168
169 error_ctx = cmsGetContextUserData (ctx);
170 g_clear_error (error_ctx);
171 g_free (error_ctx);
172
173 cmsUnregisterPluginsTHR (ctx);
174 cmsDeleteContext (ctx);
175 }
176
177 /**
178 * cd_context_lcms_error_clear:
179 **/
180 void
cd_context_lcms_error_clear(gpointer ctx)181 cd_context_lcms_error_clear (gpointer ctx)
182 {
183 g_clear_error (cd_context_lcms_get_error (ctx));
184 }
185
186 /**
187 * cd_context_lcms_error_check:
188 **/
189 gboolean
cd_context_lcms_error_check(gpointer ctx,GError ** error)190 cd_context_lcms_error_check (gpointer ctx, GError **error)
191 {
192 GError **error_ctx;
193 error_ctx = cd_context_lcms_get_error (ctx);
194 if (*error_ctx == NULL)
195 return TRUE;
196 g_propagate_error (error, *error_ctx);
197 *error_ctx = NULL;
198 return FALSE;
199 }
200