15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* vim: set ts=8 sw=8 noexpandtab: */ 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// qcms 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (C) 2009 Mozilla Corporation 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (C) 1998-2007 Marti Maria 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Permission is hereby granted, free of charge, to any person obtaining 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a copy of this software and associated documentation files (the "Software"), 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to deal in the Software without restriction, including without limitation 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the rights to use, copy, modify, merge, publish, distribute, sublicense, 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and/or sell copies of the Software, and to permit persons to whom the Software 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is furnished to do so, subject to the following conditions: 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The above copyright notice and this permission notice shall be included in 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all copies or substantial portions of the Software. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h> 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> //memcpy 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "qcmsint.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chain.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "matrix.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "transform_util.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* for MSVC, GCC, Intel, and Sun compilers */ 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_M_AMD64) || defined(__x86_64__) || defined(__x86_64) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define X86 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* _M_IX86 || __i386__ || __i386 || _M_AMD64 || __x86_64__ || __x86_64 */ 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is just an approximation, I am not handling all the non-linear 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// aspects of the RGB to XYZ process, and assumming that the gamma correction 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// has transitive property in the tranformation chain. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the alghoritm: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - First I build the absolute conversion matrix using 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// primaries in XYZ. This matrix is next inverted 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Then I eval the source white point across this matrix 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// obtaining the coeficients of the transformation 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Then, I apply these coeficients to the original matrix 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct matrix build_RGB_to_XYZ_transfer_matrix(qcms_CIE_xyY white, qcms_CIE_xyYTRIPLE primrs) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix primaries; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix primaries_invert; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix result; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vector white_point; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vector coefs; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double xn, yn; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double xr, yr; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double xg, yg; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double xb, yb; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xn = white.x; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) yn = white.y; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (yn == 0.0) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return matrix_invalid(); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xr = primrs.red.x; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) yr = primrs.red.y; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xg = primrs.green.x; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) yg = primrs.green.y; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xb = primrs.blue.x; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) yb = primrs.blue.y; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[0][0] = xr; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[0][1] = xg; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[0][2] = xb; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[1][0] = yr; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[1][1] = yg; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[1][2] = yb; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[2][0] = 1 - xr - yr; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[2][1] = 1 - xg - yg; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.m[2][2] = 1 - xb - yb; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries.invalid = false; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) white_point.v[0] = xn/yn; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) white_point.v[1] = 1.; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) white_point.v[2] = (1.0-xn-yn)/yn; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primaries_invert = matrix_invert(primaries); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) coefs = matrix_eval(primaries_invert, white_point); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[0][0] = coefs.v[0]*xr; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[0][1] = coefs.v[1]*xg; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[0][2] = coefs.v[2]*xb; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[1][0] = coefs.v[0]*yr; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[1][1] = coefs.v[1]*yg; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[1][2] = coefs.v[2]*yb; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[2][0] = coefs.v[0]*(1.-xr-yr); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[2][1] = coefs.v[1]*(1.-xg-yg); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.m[2][2] = coefs.v[2]*(1.-xb-yb); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.invalid = primaries_invert.invalid; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct CIE_XYZ { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double X; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double Y; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double Z; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* CIE Illuminant D50 */ 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct CIE_XYZ D50_XYZ = { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0.9642, 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1.0000, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0.8249 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* from lcms: xyY2XYZ() 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * corresponds to argyll: icmYxy2XYZ() */ 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct CIE_XYZ xyY2XYZ(qcms_CIE_xyY source) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct CIE_XYZ dest; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest.X = (source.x / source.y) * source.Y; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest.Y = source.Y; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest.Z = ((1 - source.x - source.y) / source.y) * source.Y; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dest; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* from lcms: ComputeChromaticAdaption */ 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Compute chromatic adaption matrix using chad as cone matrix 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct matrix 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)compute_chromatic_adaption(struct CIE_XYZ source_white_point, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct CIE_XYZ dest_white_point, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix chad) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix chad_inv; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vector cone_source_XYZ, cone_source_rgb; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct vector cone_dest_XYZ, cone_dest_rgb; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix cone, tmp; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmp = chad; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chad_inv = matrix_invert(tmp); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_source_XYZ.v[0] = source_white_point.X; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_source_XYZ.v[1] = source_white_point.Y; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_source_XYZ.v[2] = source_white_point.Z; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_dest_XYZ.v[0] = dest_white_point.X; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_dest_XYZ.v[1] = dest_white_point.Y; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_dest_XYZ.v[2] = dest_white_point.Z; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_source_rgb = matrix_eval(chad, cone_source_XYZ); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone_dest_rgb = matrix_eval(chad, cone_dest_XYZ); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[0][0] = cone_dest_rgb.v[0]/cone_source_rgb.v[0]; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[0][1] = 0; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[0][2] = 0; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[1][0] = 0; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[1][1] = cone_dest_rgb.v[1]/cone_source_rgb.v[1]; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[1][2] = 0; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[2][0] = 0; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[2][1] = 0; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.m[2][2] = cone_dest_rgb.v[2]/cone_source_rgb.v[2]; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cone.invalid = false; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Normalize 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return matrix_multiply(chad_inv, matrix_multiply(cone, chad)); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* from lcms: cmsAdaptionMatrix */ 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Bradford is assumed 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct matrix 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined (_MSC_VER) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(push) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Disable double to float truncation warning 4305 */ 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(disable:4305) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix lam_rigg = {{ // Bradford matrix 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 0.8951, 0.2664, -0.1614 }, 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { -0.7502, 1.7135, 0.0367 }, 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 0.0389, -0.0685, 1.0296 } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }}; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined (_MSC_VER) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Restore warnings */ 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(pop) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* from lcms: cmsAdaptMatrixToD50 */ 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct matrix adapt_matrix_to_D50(struct matrix r, qcms_CIE_xyY source_white_pt) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct CIE_XYZ Dn; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix Bradford; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source_white_pt.y == 0.0) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return matrix_invalid(); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Dn = xyY2XYZ(source_white_pt); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bradford = adaption_matrix(Dn, D50_XYZ); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return matrix_multiply(Bradford, r); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix colorants; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) colorants = adapt_matrix_to_D50(colorants, white_point); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colorants.invalid) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* note: there's a transpose type of operation going on here */ 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->redColorant.X = double_to_s15Fixed16Number(colorants.m[0][0]); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->redColorant.Y = double_to_s15Fixed16Number(colorants.m[1][0]); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->redColorant.Z = double_to_s15Fixed16Number(colorants.m[2][0]); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->greenColorant.X = double_to_s15Fixed16Number(colorants.m[0][1]); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->greenColorant.Y = double_to_s15Fixed16Number(colorants.m[1][1]); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->greenColorant.Z = double_to_s15Fixed16Number(colorants.m[2][1]); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2]); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2]); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2]); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float (*mat)[4] = transform->matrix; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i<length; i++) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_r = *src++; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_g = *src++; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_b = *src++; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = transform->input_gamma_table_r[device_r]; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_g = transform->input_gamma_table_g[device_g]; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_b = transform->input_gamma_table_b[device_b]; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_device_r = pow(out_linear_r, transform->out_gamma_r); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_device_g = pow(out_linear_g, transform->out_gamma_g); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_device_b = pow(out_linear_b, transform->out_gamma_b); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(out_device_r*255); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(out_device_g*255); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(out_device_b*255); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_device_r, out_device_g, out_device_b; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device = *src++; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear = transform->input_gamma_table_gray[device]; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(out_device_r*255); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(out_device_g*255); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(out_device_b*255); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Alpha is not corrected. 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A rationale for this is found in Alvy Ray's "Should Alpha Be Nonlinear If 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RGB Is?" Tech Memo 17 (December 14, 1998). 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_device_r, out_device_g, out_device_b; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device = *src++; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char alpha = *src++; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear = transform->input_gamma_table_gray[device]; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(out_device_r*255); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(out_device_g*255); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(out_device_b*255); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[3] = alpha; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 4; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device = *src++; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t gray; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear = transform->input_gamma_table_gray[device]; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* we could round here... */ 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gray = linear * PRECACHE_OUTPUT_MAX; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = transform->output_table_r->data[gray]; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = transform->output_table_g->data[gray]; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = transform->output_table_b->data[gray]; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device = *src++; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char alpha = *src++; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t gray; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear = transform->input_gamma_table_gray[device]; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* we could round here... */ 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gray = linear * PRECACHE_OUTPUT_MAX; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = transform->output_table_r->data[gray]; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = transform->output_table_g->data[gray]; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = transform->output_table_b->data[gray]; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[3] = alpha; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 4; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float (*mat)[4] = transform->matrix; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_r = *src++; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_g = *src++; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_b = *src++; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t r, g, b; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = transform->input_gamma_table_r[device_r]; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_g = transform->input_gamma_table_g[device_g]; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_b = transform->input_gamma_table_b[device_b]; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_r = clamp_float(out_linear_r); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_g = clamp_float(out_linear_g); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_b = clamp_float(out_linear_b); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* we could round here... */ 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) r = out_linear_r * PRECACHE_OUTPUT_MAX; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g = out_linear_g * PRECACHE_OUTPUT_MAX; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b = out_linear_b * PRECACHE_OUTPUT_MAX; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = transform->output_table_r->data[r]; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = transform->output_table_g->data[g]; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = transform->output_table_b->data[b]; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float (*mat)[4] = transform->matrix; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_r = *src++; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_g = *src++; 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_b = *src++; 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char alpha = *src++; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t r, g, b; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = transform->input_gamma_table_r[device_r]; 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_g = transform->input_gamma_table_g[device_g]; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_b = transform->input_gamma_table_b[device_b]; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_r = clamp_float(out_linear_r); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_g = clamp_float(out_linear_g); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_b = clamp_float(out_linear_b); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* we could round here... */ 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) r = out_linear_r * PRECACHE_OUTPUT_MAX; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g = out_linear_g * PRECACHE_OUTPUT_MAX; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b = out_linear_b * PRECACHE_OUTPUT_MAX; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = transform->output_table_r->data[r]; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = transform->output_table_g->data[g]; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = transform->output_table_b->data[b]; 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[3] = alpha; 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 4; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Not used 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int xy_len = 1; 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x_len = transform->grid_size; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = x_len * x_len; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* r_table = transform->r_clut; 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* g_table = transform->g_clut; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* b_table = transform->b_clut; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_r = *src++; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_g = *src++; 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_b = *src++; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = floor(linear_r * (transform->grid_size-1)); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = floor(linear_g * (transform->grid_size-1)); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int z = floor(linear_b * (transform->grid_size-1)); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x_n = ceil(linear_r * (transform->grid_size-1)); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y_n = ceil(linear_g * (transform->grid_size-1)); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int z_n = ceil(linear_b * (transform->grid_size-1)); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float x_d = linear_r * (transform->grid_size-1) - x; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float y_d = linear_g * (transform->grid_size-1) - y; 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float z_d = linear_b * (transform->grid_size-1) - z; 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float r_y1 = lerp(r_x1, r_x2, y_d); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float r_y2 = lerp(r_x3, r_x4, y_d); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float clut_r = lerp(r_y1, r_y2, z_d); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float g_y1 = lerp(g_x1, g_x2, y_d); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float g_y2 = lerp(g_x3, g_x4, y_d); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float clut_g = lerp(g_y1, g_y2, z_d); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float b_y1 = lerp(b_x1, b_x2, y_d); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d); 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float b_y2 = lerp(b_x3, b_x4, y_d); 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float clut_b = lerp(b_y1, b_y2, z_d); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(clut_r*255.0f); 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(clut_g*255.0f); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(clut_b*255.0f); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Using lcms' tetra interpolation algorithm. 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int xy_len = 1; 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x_len = transform->grid_size; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = x_len * x_len; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* r_table = transform->r_clut; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* g_table = transform->g_clut; 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* b_table = transform->b_clut; 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float c0_r, c1_r, c2_r, c3_r; 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float c0_g, c1_g, c2_g, c3_g; 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float c0_b, c1_b, c2_b, c3_b; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float clut_r, clut_g, clut_b; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_r = *src++; 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_g = *src++; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_b = *src++; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_a = *src++; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f; 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = floor(linear_r * (transform->grid_size-1)); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = floor(linear_g * (transform->grid_size-1)); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int z = floor(linear_b * (transform->grid_size-1)); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x_n = ceil(linear_r * (transform->grid_size-1)); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y_n = ceil(linear_g * (transform->grid_size-1)); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int z_n = ceil(linear_b * (transform->grid_size-1)); 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float rx = linear_r * (transform->grid_size-1) - x; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float ry = linear_g * (transform->grid_size-1) - y; 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float rz = linear_b * (transform->grid_size-1) - z; 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c0_r = CLU(r_table, x, y, z); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c0_g = CLU(g_table, x, y, z); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c0_b = CLU(b_table, x, y, z); 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rx >= ry ) { 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ry >= rz) { //rx >= ry && ry >= rz 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y, z) - c0_r; 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z); 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y, z) - c0_g; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z); 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y, z) - c0_b; 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rx >= rz) { //rx >= rz && rz >= ry 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y, z) - c0_r; 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y, z) - c0_g; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y, z) - c0_b; 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { //rz > rx && rx >= ry 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x, y, z_n) - c0_r; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x, y, z_n) - c0_g; 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x, y, z_n) - c0_b; 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rx >= rz) { //ry > rx && rx >= rz 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x, y_n, z) - c0_r; 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x, y_n, z) - c0_g; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z); 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x, y_n, z) - c0_b; 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ry >= rz) { //ry >= rz && rz > rx 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x, y_n, z) - c0_r; 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x, y_n, z) - c0_g; 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x, y_n, z) - c0_b; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z); 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { //rz > ry && ry > rx 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y, z_n); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x, y, z_n) - c0_r; 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y, z_n); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x, y, z_n) - c0_g; 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y, z_n); 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x, y, z_n) - c0_b; 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz; 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(clut_r*255.0f); 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(clut_g*255.0f); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(clut_b*255.0f); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[3] = in_a; 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 4; 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Using lcms' tetra interpolation code. 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int xy_len = 1; 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x_len = transform->grid_size; 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = x_len * x_len; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* r_table = transform->r_clut; 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* g_table = transform->g_clut; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* b_table = transform->b_clut; 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float c0_r, c1_r, c2_r, c3_r; 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float c0_g, c1_g, c2_g, c3_g; 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float c0_b, c1_b, c2_b, c3_b; 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float clut_r, clut_g, clut_b; 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_r = *src++; 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_g = *src++; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char in_b = *src++; 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f; 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = floor(linear_r * (transform->grid_size-1)); 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = floor(linear_g * (transform->grid_size-1)); 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int z = floor(linear_b * (transform->grid_size-1)); 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x_n = ceil(linear_r * (transform->grid_size-1)); 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y_n = ceil(linear_g * (transform->grid_size-1)); 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int z_n = ceil(linear_b * (transform->grid_size-1)); 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float rx = linear_r * (transform->grid_size-1) - x; 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float ry = linear_g * (transform->grid_size-1) - y; 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float rz = linear_b * (transform->grid_size-1) - z; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c0_r = CLU(r_table, x, y, z); 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c0_g = CLU(g_table, x, y, z); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c0_b = CLU(b_table, x, y, z); 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rx >= ry ) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ry >= rz) { //rx >= ry && ry >= rz 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y, z) - c0_r; 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z); 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y, z) - c0_g; 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z); 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y, z) - c0_b; 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rx >= rz) { //rx >= rz && rz >= ry 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y, z) - c0_r; 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z); 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y, z) - c0_g; 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z); 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y, z) - c0_b; 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z); 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { //rz > rx && rx >= ry 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n); 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x, y, z_n) - c0_r; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n); 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x, y, z_n) - c0_g; 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n); 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x, y, z_n) - c0_b; 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rx >= rz) { //ry > rx && rx >= rz 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z); 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x, y_n, z) - c0_r; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z); 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x, y_n, z) - c0_g; 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x, y_n, z) - c0_b; 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ry >= rz) { //ry >= rz && rz > rx 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x, y_n, z) - c0_r; 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z); 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x, y_n, z) - c0_g; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z); 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x, y_n, z) - c0_b; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z); 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { //rz > ry && ry > rx 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y, z_n); 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_r = CLU(r_table, x, y, z_n) - c0_r; 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y, z_n); 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_g = CLU(g_table, x, y, z_n) - c0_g; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c2_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y, z_n); 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c3_b = CLU(b_table, x, y, z_n) - c0_b; 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(clut_r*255.0f); 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(clut_g*255.0f); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(clut_b*255.0f); 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float (*mat)[4] = transform->matrix; 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_r = *src++; 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_g = *src++; 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_b = *src++; 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_device_r, out_device_g, out_device_b; 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = transform->input_gamma_table_r[device_r]; 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_g = transform->input_gamma_table_g[device_g]; 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_b = transform->input_gamma_table_b[device_b]; 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_r = clamp_float(out_linear_r); 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_g = clamp_float(out_linear_g); 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_b = clamp_float(out_linear_b); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_r = lut_interp_linear(out_linear_r, 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_g = lut_interp_linear(out_linear_g, 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_b = lut_interp_linear(out_linear_b, 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(out_device_r*255); 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(out_device_g*255); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(out_device_b*255); 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int i; 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float (*mat)[4] = transform->matrix; 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_r = *src++; 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_g = *src++; 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_b = *src++; 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char alpha = *src++; 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_device_r, out_device_g, out_device_b; 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = transform->input_gamma_table_r[device_r]; 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_g = transform->input_gamma_table_g[device_g]; 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_b = transform->input_gamma_table_b[device_b]; 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_r = clamp_float(out_linear_r); 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_g = clamp_float(out_linear_g); 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_linear_b = clamp_float(out_linear_b); 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_r = lut_interp_linear(out_linear_r, 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_g = lut_interp_linear(out_linear_g, 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_device_b = lut_interp_linear(out_linear_b, 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(out_device_r*255); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(out_device_g*255); 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(out_device_b*255); 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[3] = alpha; 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 4; 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r_out = output_format.r; 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int b_out = output_format.b; 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float (*mat)[4] = transform->matrix; 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < length; i++) { 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_r = *src++; 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_g = *src++; 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char device_b = *src++; 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_r = transform->input_gamma_table_r[device_r]; 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_g = transform->input_gamma_table_g[device_g]; 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float linear_b = transform->input_gamma_table_b[device_b]; 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[r_out] = clamp_u8(out_linear_r*255); 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[1] = clamp_u8(out_linear_g*255); 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest[b_out] = clamp_u8(out_linear_b*255); 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest += 3; 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 862a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)/* 863a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * If users create and destroy objects on different threads, even if the same 864a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * objects aren't used on different threads at the same time, we can still run 865a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * in to trouble with refcounts if they aren't atomic. 866a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * 867a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * This can lead to us prematurely deleting the precache if threads get unlucky 868a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * and write the wrong value to the ref count. 869a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) */ 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct precache_output *precache_reference(struct precache_output *p) 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 872a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) qcms_atomic_increment(p->ref_count); 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct precache_output *precache_create() 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct precache_output *p = malloc(sizeof(struct precache_output)); 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (p) 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->ref_count = 1; 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p; 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void precache_release(struct precache_output *p) 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 886a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (qcms_atomic_decrement(p->ref_count) == 0) { 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(p); 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_POSIX_MEMALIGN 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static qcms_transform *transform_alloc(void) 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform *t; 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!posix_memalign(&t, 16, sizeof(*t))) { 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return t; 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void transform_free(qcms_transform *t) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t); 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static qcms_transform *transform_alloc(void) 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* transform needs to be aligned on a 16byte boundrary */ 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *original_block = calloc(sizeof(qcms_transform) + sizeof(void*) + 16, 1); 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* make room for a pointer to the block returned by calloc */ 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *transform_start = original_block + sizeof(void*); 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* align transform_start */ 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform *transform_aligned = (qcms_transform*)(((uintptr_t)transform_start + 15) & ~0xf); 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* store a pointer to the block returned by calloc so that we can free it later */ 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void **(original_block_ptr) = (void**)transform_aligned; 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!original_block) 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_block_ptr--; 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *original_block_ptr = original_block; 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return transform_aligned; 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void transform_free(qcms_transform *t) 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* get at the pointer to the unaligned block returned by calloc */ 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void **p = (void**)t; 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p--; 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(*p); 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void qcms_transform_release(qcms_transform *t) 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* ensure we only free the gamma tables once even if there are 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * multiple references to the same data */ 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (t->output_table_r) 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(t->output_table_r); 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (t->output_table_g) 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(t->output_table_g); 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (t->output_table_b) 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(t->output_table_b); 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t->input_gamma_table_r); 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (t->input_gamma_table_g != t->input_gamma_table_r) 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t->input_gamma_table_g); 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (t->input_gamma_table_g != t->input_gamma_table_r && 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) t->input_gamma_table_g != t->input_gamma_table_b) 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t->input_gamma_table_b); 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t->input_gamma_table_gray); 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t->output_gamma_lut_r); 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t->output_gamma_lut_g); 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(t->output_gamma_lut_b); 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform_free(t); 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef X86 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Determine if we can build with SSE2 (this was partly copied from jmorecfg.h in 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mozilla/jpeg) 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ------------------------------------------------------------------------- 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_M_IX86) && defined(_MSC_VER) 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define HAS_CPUID 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Get us a CPUID function. Avoid clobbering EBX because sometimes it's the PIC 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) register - I'm not sure if that ever happens on windows, but cpuid isn't 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) on the critical path so we just preserve the register to be safe and to be 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) consistent with the non-windows version. */ 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t a_, b_, c_, d_; 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __asm { 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xchg ebx, esi 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mov eax, fxn 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuid 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mov a_, eax 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mov b_, ebx 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mov c_, ecx 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mov d_, edx 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xchg ebx, esi 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *a = a_; 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *b = b_; 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *c = c_; 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *d = d_; 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif (defined(__GNUC__) || defined(__SUNPRO_C)) && (defined(__i386__) || defined(__i386)) 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define HAS_CPUID 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Get us a CPUID function. We can't use ebx because it's the PIC register on 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) some platforms, so we use ESI instead and save ebx to avoid clobbering it. */ 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t a_, b_, c_, d_; 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __asm__ __volatile__ ("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi;" 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : "=a" (a_), "=S" (b_), "=c" (c_), "=d" (d_) : "a" (fxn)); 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *a = a_; 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *b = b_; 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *c = c_; 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *d = d_; 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -------------------------Runtime SSEx Detection----------------------------- 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* MMX is always supported per 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Gecko v1.9.1 minimum CPU requirements */ 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSE1_EDX_MASK (1UL << 25) 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSE2_EDX_MASK (1UL << 26) 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SSE3_ECX_MASK (1UL << 0) 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int sse_version_available(void) 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* we know at build time that 64-bit CPUs always have SSE2 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this tells the compiler that non-SSE2 branches will never be 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * taken (i.e. OK to optimze away the SSE1 and non-SIMD code */ 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 2; 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(HAS_CPUID) 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int sse_version = -1; 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t a, b, c, d; 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t function = 0x00000001; 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sse_version == -1) { 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sse_version = 0; 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cpuid(function, &a, &b, &c, &d); 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c & SSE3_ECX_MASK) 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sse_version = 3; 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (d & SSE2_EDX_MASK) 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sse_version = 2; 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (d & SSE1_EDX_MASK) 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sse_version = 1; 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sse_version; 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct matrix bradford_matrix = {{ { 0.8951f, 0.2664f,-0.1614f}, 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {-0.7502f, 1.7135f, 0.0367f}, 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 0.0389f,-0.0685f, 1.0296f}}, 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false}; 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const struct matrix bradford_matrix_inv = {{ { 0.9869929f,-0.1470543f, 0.1599627f}, 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 0.4323053f, 0.5183603f, 0.0492912f}, 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {-0.0085287f, 0.0400428f, 0.9684867f}}, 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false}; 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See ICCv4 E.3 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct matrix compute_whitepoint_adaption(float X, float Y, float Z) { 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float p = (0.96422f*bradford_matrix.m[0][0] + 1.000f*bradford_matrix.m[1][0] + 0.82521f*bradford_matrix.m[2][0]) / 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (X*bradford_matrix.m[0][0] + Y*bradford_matrix.m[1][0] + Z*bradford_matrix.m[2][0] ); 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float y = (0.96422f*bradford_matrix.m[0][1] + 1.000f*bradford_matrix.m[1][1] + 0.82521f*bradford_matrix.m[2][1]) / 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (X*bradford_matrix.m[0][1] + Y*bradford_matrix.m[1][1] + Z*bradford_matrix.m[2][1] ); 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float b = (0.96422f*bradford_matrix.m[0][2] + 1.000f*bradford_matrix.m[1][2] + 0.82521f*bradford_matrix.m[2][2]) / 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (X*bradford_matrix.m[0][2] + Y*bradford_matrix.m[1][2] + Z*bradford_matrix.m[2][2] ); 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix white_adaption = {{ {p,0,0}, {0,y,0}, {0,0,b}}, false}; 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return matrix_multiply( bradford_matrix_inv, matrix_multiply(white_adaption, bradford_matrix) ); 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void qcms_profile_precache_output_transform(qcms_profile *profile) 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* we only support precaching on rgb profiles */ 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->color_space != RGB_SIGNATURE) 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (qcms_supports_iccv4) { 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* don't precache since we will use the B2A LUT */ 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->B2A0) 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* don't precache since we will use the mBA LUT */ 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->mBA) 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* don't precache if we do not have the TRC curves */ 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC) 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->output_table_r) { 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->output_table_r = precache_create(); 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->output_table_r && 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !compute_precache(profile->redTRC, profile->output_table_r->data)) { 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(profile->output_table_r); 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->output_table_r = NULL; 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->output_table_g) { 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->output_table_g = precache_create(); 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->output_table_g && 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !compute_precache(profile->greenTRC, profile->output_table_g->data)) { 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(profile->output_table_g); 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->output_table_g = NULL; 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile->output_table_b) { 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->output_table_b = precache_create(); 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile->output_table_b && 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !compute_precache(profile->blueTRC, profile->output_table_b->data)) { 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache_release(profile->output_table_b); 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile->output_table_b = NULL; 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Replace the current transformation with a LUT transformation using a given number of sample points */ 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms_profile *in, qcms_profile *out, 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int samples, qcms_data_type in_type) 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* The range between which 2 consecutive sample points can be used to interpolate */ 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16_t x,y,z; 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t l; 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32_t lutSize = 3 * samples * samples * samples; 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* src = NULL; 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* dest = NULL; 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* lut = NULL; 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src = malloc(lutSize*sizeof(float)); 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dest = malloc(lutSize*sizeof(float)); 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (src && dest) { 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Prepare a list of points we want to sample */ 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l = 0; 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (x = 0; x < samples; x++) { 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (y = 0; y < samples; y++) { 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (z = 0; z < samples; z++) { 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src[l++] = x / (float)(samples-1); 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src[l++] = y / (float)(samples-1); 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src[l++] = z / (float)(samples-1); 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lut = qcms_chain_transform(in, out, src, dest, lutSize); 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lut) { 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->r_clut = &lut[0]; 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->g_clut = &lut[1]; 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->b_clut = &lut[2]; 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->grid_size = samples; 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type == QCMS_DATA_RGBA_8) { 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_tetra_clut_rgba; 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_tetra_clut; 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //XXX: qcms_modular_transform_data may return either the src or dest buffer. If so it must not be free-ed 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (src && lut != src) { 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(src); 1156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 1157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (dest && lut != dest) { 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) free(dest); 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lut == NULL) { 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return transform; 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_MEM_TRANSFORM NULL 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_transform* qcms_transform_create( 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile *in, qcms_data_type in_type, 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_profile *out, qcms_data_type out_type, 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_intent intent) 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool precache = false; 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform *transform = transform_alloc(); 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!transform) { 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (out_type != QCMS_DATA_RGB_8 && 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_type != QCMS_DATA_RGBA_8) { 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0 && "output type"); 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform_free(transform); 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (out->output_table_r && 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out->output_table_g && 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out->output_table_b) { 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) precache = true; 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (qcms_supports_iccv4 && (in->A2B0 || out->B2A0 || in->mAB || out->mAB)) { 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Precache the transformation to a CLUT 33x33x33 in size. 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 33 is used by many profiles and works well in pratice. 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This evenly divides 256 into blocks of 8x8x8. 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO For transforming small data sets of about 200x200 or less 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // precaching should be avoided. 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform *result = qcms_transform_precacheLUT_float(transform, in, out, 33, in_type); 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!result) { 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0 && "precacheLUT failed"); 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform_free(transform); 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (precache) { 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_table_r = precache_reference(out->output_table_r); 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_table_g = precache_reference(out->output_table_g); 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->output_table_b = precache_reference(out->output_table_b); 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!out->redTRC || !out->greenTRC || !out->blueTRC) { 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform_release(transform); 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_TRANSFORM; 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) build_output_lut(out->redTRC, &transform->output_gamma_lut_r, &transform->output_gamma_lut_r_length); 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) build_output_lut(out->greenTRC, &transform->output_gamma_lut_g, &transform->output_gamma_lut_g_length); 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) build_output_lut(out->blueTRC, &transform->output_gamma_lut_b, &transform->output_gamma_lut_b_length); 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!transform->output_gamma_lut_r || !transform->output_gamma_lut_g || !transform->output_gamma_lut_b) { 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform_release(transform); 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_TRANSFORM; 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in->color_space == RGB_SIGNATURE) { 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct matrix in_matrix, out_matrix, result; 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type != QCMS_DATA_RGB_8 && 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_type != QCMS_DATA_RGBA_8){ 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0 && "input type"); 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform_free(transform); 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (precache) { 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(SSE2_ENABLE) && defined(X86) 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sse_version_available() >= 2) { 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type == QCMS_DATA_RGB_8) 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2; 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2; 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(SSE2_ENABLE) && !(defined(_MSC_VER) && defined(_M_AMD64)) 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Microsoft Compiler for x64 doesn't support MMX. 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SSE code uses MMX so that we disable on x64 */ 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sse_version_available() >= 1) { 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type == QCMS_DATA_RGB_8) 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgb_out_lut_sse1; 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgba_out_lut_sse1; 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type == QCMS_DATA_RGB_8) 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgb_out_lut_precache; 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgba_out_lut_precache; 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type == QCMS_DATA_RGB_8) 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgb_out_lut; 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_rgba_out_lut; 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //XXX: avoid duplicating tables if we can 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->input_gamma_table_r = build_input_gamma_table(in->redTRC); 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->input_gamma_table_g = build_input_gamma_table(in->greenTRC); 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->input_gamma_table_b = build_input_gamma_table(in->blueTRC); 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!transform->input_gamma_table_r || !transform->input_gamma_table_g || !transform->input_gamma_table_b) { 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform_release(transform); 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_TRANSFORM; 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* build combined colorant matrix */ 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_matrix = build_colorant_matrix(in); 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_matrix = build_colorant_matrix(out); 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_matrix = matrix_invert(out_matrix); 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (out_matrix.invalid) { 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform_release(transform); 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = matrix_multiply(out_matrix, in_matrix); 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* store the results in column major mode 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this makes doing the multiplication with sse easier */ 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[0][0] = result.m[0][0]; 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[1][0] = result.m[0][1]; 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[2][0] = result.m[0][2]; 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[0][1] = result.m[1][0]; 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[1][1] = result.m[1][1]; 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[2][1] = result.m[1][2]; 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[0][2] = result.m[2][0]; 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[1][2] = result.m[2][1]; 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->matrix[2][2] = result.m[2][2]; 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (in->color_space == GRAY_SIGNATURE) { 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type != QCMS_DATA_GRAY_8 && 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in_type != QCMS_DATA_GRAYA_8){ 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0 && "input type"); 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform_free(transform); 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->input_gamma_table_gray = build_input_gamma_table(in->grayTRC); 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!transform->input_gamma_table_gray) { 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_transform_release(transform); 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NO_MEM_TRANSFORM; 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (precache) { 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type == QCMS_DATA_GRAY_8) { 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_gray_out_precache; 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_graya_out_precache; 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (in_type == QCMS_DATA_GRAY_8) { 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_gray_out_lut; 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn = qcms_transform_data_graya_out_lut; 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0 && "unexpected colorspace"); 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform_free(transform); 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return transform; 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on unused 13362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the presence 13372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * of the attribute but is currently only supported by clang */ 13382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__has_attribute) 13392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__) 1340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#elif defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) && !defined(__arm__) && !defined(__mips__) 13412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define HAS_FORCE_ALIGN_ARG_POINTER 1 13422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 13432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define HAS_FORCE_ALIGN_ARG_POINTER 0 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 13452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 13462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if HAS_FORCE_ALIGN_ARG_POINTER 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */ 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__attribute__((__force_align_arg_pointer__)) 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length) 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const struct _qcms_format_type output_rgbx = { 0, 2 }; 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn(transform, src, dest, length, output_rgbx); 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type) 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const struct _qcms_format_type output_rgbx = { 0, 2 }; 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const struct _qcms_format_type output_bgrx = { 2, 0 }; 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPUT_BGRX ? output_bgrx : output_rgbx); 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)qcms_bool qcms_supports_iccv4; 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void qcms_enable_iccv4() 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qcms_supports_iccv4 = true; 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1370