diff options
Diffstat (limited to 'lib/colord/cd-context-lcms.c')
-rw-r--r-- | lib/colord/cd-context-lcms.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/lib/colord/cd-context-lcms.c b/lib/colord/cd-context-lcms.c new file mode 100644 index 0000000..85d5574 --- /dev/null +++ b/lib/colord/cd-context-lcms.c @@ -0,0 +1,239 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2014 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/** + * SECTION:cd-context-lcms + * @short_description: Functionality to save per-thread context data for LCMS2 + */ + +#include "config.h" + +#include <lcms2.h> +#include <lcms2_plugin.h> + +#include "cd-context-lcms.h" +#include "cd-icc.h" /* for the error codes */ + +/*< private >*/ +#define LCMS_CURVE_PLUGIN_TYPE_REC709 1024 + +/** + * cd_context_lcms_get_error: + **/ +static GError ** +cd_context_lcms_get_error (gpointer ctx) +{ + GError **error_ctx; +#ifdef HAVE_LCMS_CREATE_CONTEXT + error_ctx = cmsGetContextUserData (ctx); +#else + error_ctx = (GError **) ctx; +#endif + return error_ctx; +} + +/** + * cd_context_lcms2_error_cb: + **/ +static void +cd_context_lcms2_error_cb (cmsContext context_id, + cmsUInt32Number code, + const gchar *message) +{ + gint error_code; + GError **error_ctx; + + /* nothing set, must be pre-2.6 */ + if (context_id == NULL) { + g_warning ("Error handler called with no context: %s", message); + return; + } + + /* there's already one error pending */ + error_ctx = cd_context_lcms_get_error (context_id); + if (*error_ctx != NULL) { + g_prefix_error (error_ctx, "%s & ", message); + return; + } + + /* convert the first cmsERROR in into a CdIccError */ + switch (code) { + case cmsERROR_CORRUPTION_DETECTED: + error_code = CD_ICC_ERROR_CORRUPTION_DETECTED; + break; + case cmsERROR_FILE: + case cmsERROR_READ: + case cmsERROR_SEEK: + error_code = CD_ICC_ERROR_FAILED_TO_OPEN; + break; + case cmsERROR_WRITE: + error_code = CD_ICC_ERROR_FAILED_TO_SAVE; + break; + case cmsERROR_COLORSPACE_CHECK: + error_code = CD_ICC_ERROR_INVALID_COLORSPACE; + break; + case cmsERROR_BAD_SIGNATURE: + error_code = CD_ICC_ERROR_FAILED_TO_PARSE; + break; + case cmsERROR_ALREADY_DEFINED: + case cmsERROR_INTERNAL: + case cmsERROR_NOT_SUITABLE: + case cmsERROR_NULL: + case cmsERROR_RANGE: + case cmsERROR_UNDEFINED: + case cmsERROR_UNKNOWN_EXTENSION: + error_code = CD_ICC_ERROR_INTERNAL; + break; + default: + g_warning ("LCMS2 error code not recognised; please report"); + error_code = CD_ICC_ERROR_INTERNAL; + } + error_ctx = cd_context_lcms_get_error (context_id); + g_set_error_literal (error_ctx, CD_ICC_ERROR, error_code, message); +} + +/** + * cd_context_lcms_plugins_cb: + **/ +static double +cd_context_lcms_plugins_cb (int type, const double params[], double x) +{ + gdouble val = 0.f; + + switch (type) { + case -LCMS_CURVE_PLUGIN_TYPE_REC709: + if (x < params[4]) + val = x * params[3]; + else + val = params[1] * pow (x, (1.f / params[0])) + params[2]; + break; + case LCMS_CURVE_PLUGIN_TYPE_REC709: + if (x <= (params[3] * params[4])) + val = x / params[3]; + else + val = pow (((x + params[2]) / params[1]), params[0]); + break; + } + return val; +} + +cmsPluginParametricCurves cd_icc_lcms_plugins = { + { cmsPluginMagicNumber, /* 'acpp' */ + 2000, /* minimum version */ + cmsPluginParametricCurveSig, /* type */ + NULL }, /* no more plugins */ + 1, /* number functions */ + {LCMS_CURVE_PLUGIN_TYPE_REC709}, /* function types */ + {5}, /* parameter count */ + cd_context_lcms_plugins_cb /* evaluator */ +}; + +/** + * cd_context_lcms_new: + * + * Return value: (transfer full): A new LCMS context + **/ +gpointer +cd_context_lcms_new (void) +{ + cmsContext ctx; + GError **error_ctx; + error_ctx = g_new0 (GError *, 1); +#ifdef HAVE_LCMS_CREATE_CONTEXT + ctx = cmsCreateContext (NULL, error_ctx); + cmsSetLogErrorHandlerTHR (ctx, cd_context_lcms2_error_cb); + cmsPluginTHR (ctx, &cd_icc_lcms_plugins); +#else + ctx = (cmsContext) error_ctx; + cmsSetLogErrorHandler (cd_context_lcms2_error_cb); + /* we've disabled this as it's unreliable without a context */ + if(0) cmsPlugin (&cd_icc_lcms_plugins); +#endif + return ctx; +} + +/** + * _cd_context_lcms_pre26_start: + **/ +void +_cd_context_lcms_pre26_start (void) +{ +#ifndef HAVE_LCMS_CREATE_CONTEXT + cmsSetLogErrorHandler (cd_context_lcms2_error_cb); +#endif +} + +/** + * _cd_context_lcms_pre26_stop: + **/ +void +_cd_context_lcms_pre26_stop (void) +{ +#ifndef HAVE_LCMS_CREATE_CONTEXT + cmsSetLogErrorHandler (NULL); +#endif +} + +/** + * cd_context_lcms_free: + **/ +void +cd_context_lcms_free (gpointer ctx) +{ + GError **error_ctx; + +#ifdef HAVE_LCMS_CREATE_CONTEXT + error_ctx = cmsGetContextUserData (ctx); +#else + error_ctx = (GError **) ctx; +#endif + g_clear_error (error_ctx); + +#ifdef HAVE_LCMS_CREATE_CONTEXT + cmsUnregisterPluginsTHR (ctx); + cmsDeleteContext (ctx); +#endif +} + +/** + * cd_context_lcms_error_clear: + **/ +void +cd_context_lcms_error_clear (gpointer ctx) +{ + g_clear_error (cd_context_lcms_get_error (ctx)); +} + +/** + * cd_context_lcms_error_check: + **/ +gboolean +cd_context_lcms_error_check (gpointer ctx, GError **error) +{ + GError **error_ctx; + error_ctx = cd_context_lcms_get_error (ctx); + if (*error_ctx == NULL) + return TRUE; + g_propagate_error (error, *error_ctx); + *error_ctx = NULL; + return FALSE; +} |