LCOV - code coverage report
Current view: directory - gfx/qcms - transform.c (source / functions) Found Hit Coverage
Test: app.info Lines: 635 0 0.0 %
Date: 2012-06-02 Functions: 30 0 0.0 %

       1                 : /* vim: set ts=8 sw=8 noexpandtab: */
       2                 : //  qcms
       3                 : //  Copyright (C) 2009 Mozilla Corporation
       4                 : //  Copyright (C) 1998-2007 Marti Maria
       5                 : //
       6                 : // Permission is hereby granted, free of charge, to any person obtaining 
       7                 : // a copy of this software and associated documentation files (the "Software"), 
       8                 : // to deal in the Software without restriction, including without limitation 
       9                 : // the rights to use, copy, modify, merge, publish, distribute, sublicense, 
      10                 : // and/or sell copies of the Software, and to permit persons to whom the Software 
      11                 : // is furnished to do so, subject to the following conditions:
      12                 : //
      13                 : // The above copyright notice and this permission notice shall be included in 
      14                 : // all copies or substantial portions of the Software.
      15                 : //
      16                 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
      17                 : // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
      18                 : // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
      19                 : // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
      20                 : // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
      21                 : // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
      22                 : // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      23                 : 
      24                 : #include <stdlib.h>
      25                 : #include <math.h>
      26                 : #include <assert.h>
      27                 : #include <string.h> //memcpy
      28                 : #include "qcmsint.h"
      29                 : #include "chain.h"
      30                 : #include "matrix.h"
      31                 : #include "transform_util.h"
      32                 : 
      33                 : /* for MSVC, GCC, Intel, and Sun compilers */
      34                 : #if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_M_AMD64) || defined(__x86_64__) || defined(__x86_64)
      35                 : #define X86
      36                 : #endif /* _M_IX86 || __i386__ || __i386 || _M_AMD64 || __x86_64__ || __x86_64 */
      37                 : 
      38                 : // Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
      39                 : // This is just an approximation, I am not handling all the non-linear
      40                 : // aspects of the RGB to XYZ process, and assumming that the gamma correction
      41                 : // has transitive property in the tranformation chain.
      42                 : //
      43                 : // the alghoritm:
      44                 : //
      45                 : //            - First I build the absolute conversion matrix using
      46                 : //              primaries in XYZ. This matrix is next inverted
      47                 : //            - Then I eval the source white point across this matrix
      48                 : //              obtaining the coeficients of the transformation
      49                 : //            - Then, I apply these coeficients to the original matrix
      50               0 : static struct matrix build_RGB_to_XYZ_transfer_matrix(qcms_CIE_xyY white, qcms_CIE_xyYTRIPLE primrs)
      51                 : {
      52                 :         struct matrix primaries;
      53                 :         struct matrix primaries_invert;
      54                 :         struct matrix result;
      55                 :         struct vector white_point;
      56                 :         struct vector coefs;
      57                 : 
      58                 :         double xn, yn;
      59                 :         double xr, yr;
      60                 :         double xg, yg;
      61                 :         double xb, yb;
      62                 : 
      63               0 :         xn = white.x;
      64               0 :         yn = white.y;
      65                 : 
      66               0 :         if (yn == 0.0)
      67               0 :                 return matrix_invalid();
      68                 : 
      69               0 :         xr = primrs.red.x;
      70               0 :         yr = primrs.red.y;
      71               0 :         xg = primrs.green.x;
      72               0 :         yg = primrs.green.y;
      73               0 :         xb = primrs.blue.x;
      74               0 :         yb = primrs.blue.y;
      75                 : 
      76               0 :         primaries.m[0][0] = xr;
      77               0 :         primaries.m[0][1] = xg;
      78               0 :         primaries.m[0][2] = xb;
      79                 : 
      80               0 :         primaries.m[1][0] = yr;
      81               0 :         primaries.m[1][1] = yg;
      82               0 :         primaries.m[1][2] = yb;
      83                 : 
      84               0 :         primaries.m[2][0] = 1 - xr - yr;
      85               0 :         primaries.m[2][1] = 1 - xg - yg;
      86               0 :         primaries.m[2][2] = 1 - xb - yb;
      87               0 :         primaries.invalid = false;
      88                 : 
      89               0 :         white_point.v[0] = xn/yn;
      90               0 :         white_point.v[1] = 1.;
      91               0 :         white_point.v[2] = (1.0-xn-yn)/yn;
      92                 : 
      93               0 :         primaries_invert = matrix_invert(primaries);
      94                 : 
      95               0 :         coefs = matrix_eval(primaries_invert, white_point);
      96                 : 
      97               0 :         result.m[0][0] = coefs.v[0]*xr;
      98               0 :         result.m[0][1] = coefs.v[1]*xg;
      99               0 :         result.m[0][2] = coefs.v[2]*xb;
     100                 : 
     101               0 :         result.m[1][0] = coefs.v[0]*yr;
     102               0 :         result.m[1][1] = coefs.v[1]*yg;
     103               0 :         result.m[1][2] = coefs.v[2]*yb;
     104                 : 
     105               0 :         result.m[2][0] = coefs.v[0]*(1.-xr-yr);
     106               0 :         result.m[2][1] = coefs.v[1]*(1.-xg-yg);
     107               0 :         result.m[2][2] = coefs.v[2]*(1.-xb-yb);
     108               0 :         result.invalid = primaries_invert.invalid;
     109                 : 
     110               0 :         return result;
     111                 : }
     112                 : 
     113                 : struct CIE_XYZ {
     114                 :         double X;
     115                 :         double Y;
     116                 :         double Z;
     117                 : };
     118                 : 
     119                 : /* CIE Illuminant D50 */
     120                 : static const struct CIE_XYZ D50_XYZ = {
     121                 :         0.9642,
     122                 :         1.0000,
     123                 :         0.8249
     124                 : };
     125                 : 
     126                 : /* from lcms: xyY2XYZ()
     127                 :  * corresponds to argyll: icmYxy2XYZ() */
     128               0 : static struct CIE_XYZ xyY2XYZ(qcms_CIE_xyY source)
     129                 : {
     130                 :         struct CIE_XYZ dest;
     131               0 :         dest.X = (source.x / source.y) * source.Y;
     132               0 :         dest.Y = source.Y;
     133               0 :         dest.Z = ((1 - source.x - source.y) / source.y) * source.Y;
     134               0 :         return dest;
     135                 : }
     136                 : 
     137                 : /* from lcms: ComputeChromaticAdaption */
     138                 : // Compute chromatic adaption matrix using chad as cone matrix
     139                 : static struct matrix
     140               0 : compute_chromatic_adaption(struct CIE_XYZ source_white_point,
     141                 :                            struct CIE_XYZ dest_white_point,
     142                 :                            struct matrix chad)
     143                 : {
     144                 :         struct matrix chad_inv;
     145                 :         struct vector cone_source_XYZ, cone_source_rgb;
     146                 :         struct vector cone_dest_XYZ, cone_dest_rgb;
     147                 :         struct matrix cone, tmp;
     148                 : 
     149               0 :         tmp = chad;
     150               0 :         chad_inv = matrix_invert(tmp);
     151                 : 
     152               0 :         cone_source_XYZ.v[0] = source_white_point.X;
     153               0 :         cone_source_XYZ.v[1] = source_white_point.Y;
     154               0 :         cone_source_XYZ.v[2] = source_white_point.Z;
     155                 : 
     156               0 :         cone_dest_XYZ.v[0] = dest_white_point.X;
     157               0 :         cone_dest_XYZ.v[1] = dest_white_point.Y;
     158               0 :         cone_dest_XYZ.v[2] = dest_white_point.Z;
     159                 : 
     160               0 :         cone_source_rgb = matrix_eval(chad, cone_source_XYZ);
     161               0 :         cone_dest_rgb   = matrix_eval(chad, cone_dest_XYZ);
     162                 : 
     163               0 :         cone.m[0][0] = cone_dest_rgb.v[0]/cone_source_rgb.v[0];
     164               0 :         cone.m[0][1] = 0;
     165               0 :         cone.m[0][2] = 0;
     166               0 :         cone.m[1][0] = 0;
     167               0 :         cone.m[1][1] = cone_dest_rgb.v[1]/cone_source_rgb.v[1];
     168               0 :         cone.m[1][2] = 0;
     169               0 :         cone.m[2][0] = 0;
     170               0 :         cone.m[2][1] = 0;
     171               0 :         cone.m[2][2] = cone_dest_rgb.v[2]/cone_source_rgb.v[2];
     172               0 :         cone.invalid = false;
     173                 : 
     174                 :         // Normalize
     175               0 :         return matrix_multiply(chad_inv, matrix_multiply(cone, chad));
     176                 : }
     177                 : 
     178                 : /* from lcms: cmsAdaptionMatrix */
     179                 : // Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll
     180                 : // Bradford is assumed
     181                 : static struct matrix
     182               0 : adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination)
     183                 : {
     184               0 :         struct matrix lam_rigg = {{ // Bradford matrix
     185                 :                                  {  0.8951,  0.2664, -0.1614 },
     186                 :                                  { -0.7502,  1.7135,  0.0367 },
     187                 :                                  {  0.0389, -0.0685,  1.0296 }
     188                 :                                  }};
     189               0 :         return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg);
     190                 : }
     191                 : 
     192                 : /* from lcms: cmsAdaptMatrixToD50 */
     193               0 : static struct matrix adapt_matrix_to_D50(struct matrix r, qcms_CIE_xyY source_white_pt)
     194                 : {
     195                 :         struct CIE_XYZ Dn;
     196                 :         struct matrix Bradford;
     197                 : 
     198               0 :         if (source_white_pt.y == 0.0)
     199               0 :                 return matrix_invalid();
     200                 : 
     201               0 :         Dn = xyY2XYZ(source_white_pt);
     202                 : 
     203               0 :         Bradford = adaption_matrix(Dn, D50_XYZ);
     204               0 :         return matrix_multiply(Bradford, r);
     205                 : }
     206                 : 
     207               0 : qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries)
     208                 : {
     209                 :         struct matrix colorants;
     210               0 :         colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries);
     211               0 :         colorants = adapt_matrix_to_D50(colorants, white_point);
     212                 : 
     213               0 :         if (colorants.invalid)
     214               0 :                 return false;
     215                 : 
     216                 :         /* note: there's a transpose type of operation going on here */
     217               0 :         profile->redColorant.X = double_to_s15Fixed16Number(colorants.m[0][0]);
     218               0 :         profile->redColorant.Y = double_to_s15Fixed16Number(colorants.m[1][0]);
     219               0 :         profile->redColorant.Z = double_to_s15Fixed16Number(colorants.m[2][0]);
     220                 : 
     221               0 :         profile->greenColorant.X = double_to_s15Fixed16Number(colorants.m[0][1]);
     222               0 :         profile->greenColorant.Y = double_to_s15Fixed16Number(colorants.m[1][1]);
     223               0 :         profile->greenColorant.Z = double_to_s15Fixed16Number(colorants.m[2][1]);
     224                 : 
     225               0 :         profile->blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2]);
     226               0 :         profile->blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2]);
     227               0 :         profile->blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2]);
     228                 : 
     229               0 :         return true;
     230                 : }
     231                 : 
     232                 : #if 0
     233                 : static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     234                 : {
     235                 :         int i;
     236                 :         float (*mat)[4] = transform->matrix;
     237                 :         for (i=0; i<length; i++) {
     238                 :                 unsigned char device_r = *src++;
     239                 :                 unsigned char device_g = *src++;
     240                 :                 unsigned char device_b = *src++;
     241                 : 
     242                 :                 float linear_r = transform->input_gamma_table_r[device_r];
     243                 :                 float linear_g = transform->input_gamma_table_g[device_g];
     244                 :                 float linear_b = transform->input_gamma_table_b[device_b];
     245                 : 
     246                 :                 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
     247                 :                 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
     248                 :                 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
     249                 : 
     250                 :                 float out_device_r = pow(out_linear_r, transform->out_gamma_r);
     251                 :                 float out_device_g = pow(out_linear_g, transform->out_gamma_g);
     252                 :                 float out_device_b = pow(out_linear_b, transform->out_gamma_b);
     253                 : 
     254                 :                 *dest++ = clamp_u8(255*out_device_r);
     255                 :                 *dest++ = clamp_u8(255*out_device_g);
     256                 :                 *dest++ = clamp_u8(255*out_device_b);
     257                 :         }
     258                 : }
     259                 : #endif
     260                 : 
     261               0 : static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     262                 : {
     263                 :         unsigned int i;
     264               0 :         for (i = 0; i < length; i++) {
     265                 :                 float out_device_r, out_device_g, out_device_b;
     266               0 :                 unsigned char device = *src++;
     267                 : 
     268               0 :                 float linear = transform->input_gamma_table_gray[device];
     269                 : 
     270               0 :                 out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
     271               0 :                 out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
     272               0 :                 out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
     273                 : 
     274               0 :                 *dest++ = clamp_u8(out_device_r*255);
     275               0 :                 *dest++ = clamp_u8(out_device_g*255);
     276               0 :                 *dest++ = clamp_u8(out_device_b*255);
     277                 :         }
     278               0 : }
     279                 : 
     280                 : /* Alpha is not corrected.
     281                 :    A rationale for this is found in Alvy Ray's "Should Alpha Be Nonlinear If
     282                 :    RGB Is?" Tech Memo 17 (December 14, 1998).
     283                 :         See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
     284                 : */
     285                 : 
     286               0 : static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     287                 : {
     288                 :         unsigned int i;
     289               0 :         for (i = 0; i < length; i++) {
     290                 :                 float out_device_r, out_device_g, out_device_b;
     291               0 :                 unsigned char device = *src++;
     292               0 :                 unsigned char alpha = *src++;
     293                 : 
     294               0 :                 float linear = transform->input_gamma_table_gray[device];
     295                 : 
     296               0 :                 out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
     297               0 :                 out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
     298               0 :                 out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
     299                 : 
     300               0 :                 *dest++ = clamp_u8(out_device_r*255);
     301               0 :                 *dest++ = clamp_u8(out_device_g*255);
     302               0 :                 *dest++ = clamp_u8(out_device_b*255);
     303               0 :                 *dest++ = alpha;
     304                 :         }
     305               0 : }
     306                 : 
     307                 : 
     308               0 : static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     309                 : {
     310                 :         unsigned int i;
     311               0 :         for (i = 0; i < length; i++) {
     312               0 :                 unsigned char device = *src++;
     313                 :                 uint16_t gray;
     314                 : 
     315               0 :                 float linear = transform->input_gamma_table_gray[device];
     316                 : 
     317                 :                 /* we could round here... */
     318               0 :                 gray = linear * PRECACHE_OUTPUT_MAX;
     319                 : 
     320               0 :                 *dest++ = transform->output_table_r->data[gray];
     321               0 :                 *dest++ = transform->output_table_g->data[gray];
     322               0 :                 *dest++ = transform->output_table_b->data[gray];
     323                 :         }
     324               0 : }
     325                 : 
     326               0 : static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     327                 : {
     328                 :         unsigned int i;
     329               0 :         for (i = 0; i < length; i++) {
     330               0 :                 unsigned char device = *src++;
     331               0 :                 unsigned char alpha = *src++;
     332                 :                 uint16_t gray;
     333                 : 
     334               0 :                 float linear = transform->input_gamma_table_gray[device];
     335                 : 
     336                 :                 /* we could round here... */
     337               0 :                 gray = linear * PRECACHE_OUTPUT_MAX;
     338                 : 
     339               0 :                 *dest++ = transform->output_table_r->data[gray];
     340               0 :                 *dest++ = transform->output_table_g->data[gray];
     341               0 :                 *dest++ = transform->output_table_b->data[gray];
     342               0 :                 *dest++ = alpha;
     343                 :         }
     344               0 : }
     345                 : 
     346               0 : static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     347                 : {
     348                 :         unsigned int i;
     349               0 :         float (*mat)[4] = transform->matrix;
     350               0 :         for (i = 0; i < length; i++) {
     351               0 :                 unsigned char device_r = *src++;
     352               0 :                 unsigned char device_g = *src++;
     353               0 :                 unsigned char device_b = *src++;
     354                 :                 uint16_t r, g, b;
     355                 : 
     356               0 :                 float linear_r = transform->input_gamma_table_r[device_r];
     357               0 :                 float linear_g = transform->input_gamma_table_g[device_g];
     358               0 :                 float linear_b = transform->input_gamma_table_b[device_b];
     359                 : 
     360               0 :                 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
     361               0 :                 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
     362               0 :                 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
     363                 : 
     364               0 :                 out_linear_r = clamp_float(out_linear_r);
     365               0 :                 out_linear_g = clamp_float(out_linear_g);
     366               0 :                 out_linear_b = clamp_float(out_linear_b);
     367                 : 
     368                 :                 /* we could round here... */
     369               0 :                 r = out_linear_r * PRECACHE_OUTPUT_MAX;
     370               0 :                 g = out_linear_g * PRECACHE_OUTPUT_MAX;
     371               0 :                 b = out_linear_b * PRECACHE_OUTPUT_MAX;
     372                 : 
     373               0 :                 *dest++ = transform->output_table_r->data[r];
     374               0 :                 *dest++ = transform->output_table_g->data[g];
     375               0 :                 *dest++ = transform->output_table_b->data[b];
     376                 :         }
     377               0 : }
     378                 : 
     379               0 : static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     380                 : {
     381                 :         unsigned int i;
     382               0 :         float (*mat)[4] = transform->matrix;
     383               0 :         for (i = 0; i < length; i++) {
     384               0 :                 unsigned char device_r = *src++;
     385               0 :                 unsigned char device_g = *src++;
     386               0 :                 unsigned char device_b = *src++;
     387               0 :                 unsigned char alpha = *src++;
     388                 :                 uint16_t r, g, b;
     389                 : 
     390               0 :                 float linear_r = transform->input_gamma_table_r[device_r];
     391               0 :                 float linear_g = transform->input_gamma_table_g[device_g];
     392               0 :                 float linear_b = transform->input_gamma_table_b[device_b];
     393                 : 
     394               0 :                 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
     395               0 :                 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
     396               0 :                 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
     397                 : 
     398               0 :                 out_linear_r = clamp_float(out_linear_r);
     399               0 :                 out_linear_g = clamp_float(out_linear_g);
     400               0 :                 out_linear_b = clamp_float(out_linear_b);
     401                 : 
     402                 :                 /* we could round here... */
     403               0 :                 r = out_linear_r * PRECACHE_OUTPUT_MAX;
     404               0 :                 g = out_linear_g * PRECACHE_OUTPUT_MAX;
     405               0 :                 b = out_linear_b * PRECACHE_OUTPUT_MAX;
     406                 : 
     407               0 :                 *dest++ = transform->output_table_r->data[r];
     408               0 :                 *dest++ = transform->output_table_g->data[g];
     409               0 :                 *dest++ = transform->output_table_b->data[b];
     410               0 :                 *dest++ = alpha;
     411                 :         }
     412               0 : }
     413                 : 
     414                 : // Not used
     415                 : /* 
     416                 : static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
     417                 :         unsigned int i;
     418                 :         int xy_len = 1;
     419                 :         int x_len = transform->grid_size;
     420                 :         int len = x_len * x_len;
     421                 :         float* r_table = transform->r_clut;
     422                 :         float* g_table = transform->g_clut;
     423                 :         float* b_table = transform->b_clut;
     424                 :   
     425                 :         for (i = 0; i < length; i++) {
     426                 :                 unsigned char in_r = *src++;
     427                 :                 unsigned char in_g = *src++;
     428                 :                 unsigned char in_b = *src++;
     429                 :                 float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f;
     430                 : 
     431                 :                 int x = floor(linear_r * (transform->grid_size-1));
     432                 :                 int y = floor(linear_g * (transform->grid_size-1));
     433                 :                 int z = floor(linear_b * (transform->grid_size-1));
     434                 :                 int x_n = ceil(linear_r * (transform->grid_size-1));
     435                 :                 int y_n = ceil(linear_g * (transform->grid_size-1));
     436                 :                 int z_n = ceil(linear_b * (transform->grid_size-1));
     437                 :                 float x_d = linear_r * (transform->grid_size-1) - x; 
     438                 :                 float y_d = linear_g * (transform->grid_size-1) - y;
     439                 :                 float z_d = linear_b * (transform->grid_size-1) - z; 
     440                 : 
     441                 :                 float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d);
     442                 :                 float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
     443                 :                 float r_y1 = lerp(r_x1, r_x2, y_d);
     444                 :                 float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
     445                 :                 float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d);
     446                 :                 float r_y2 = lerp(r_x3, r_x4, y_d);
     447                 :                 float clut_r = lerp(r_y1, r_y2, z_d);
     448                 : 
     449                 :                 float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d);
     450                 :                 float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
     451                 :                 float g_y1 = lerp(g_x1, g_x2, y_d);
     452                 :                 float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
     453                 :                 float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d);
     454                 :                 float g_y2 = lerp(g_x3, g_x4, y_d);
     455                 :                 float clut_g = lerp(g_y1, g_y2, z_d);
     456                 : 
     457                 :                 float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d);
     458                 :                 float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
     459                 :                 float b_y1 = lerp(b_x1, b_x2, y_d);
     460                 :                 float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
     461                 :                 float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d);
     462                 :                 float b_y2 = lerp(b_x3, b_x4, y_d);
     463                 :                 float clut_b = lerp(b_y1, b_y2, z_d);
     464                 : 
     465                 :                 *dest++ = clamp_u8(clut_r*255.0f);
     466                 :                 *dest++ = clamp_u8(clut_g*255.0f);
     467                 :                 *dest++ = clamp_u8(clut_b*255.0f);
     468                 :         }       
     469                 : }
     470                 : */
     471                 : 
     472                 : // Using lcms' tetra interpolation algorithm.
     473               0 : static void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
     474                 :         unsigned int i;
     475               0 :         int xy_len = 1;
     476               0 :         int x_len = transform->grid_size;
     477               0 :         int len = x_len * x_len;
     478               0 :         float* r_table = transform->r_clut;
     479               0 :         float* g_table = transform->g_clut;
     480               0 :         float* b_table = transform->b_clut;
     481                 :         float c0_r, c1_r, c2_r, c3_r;
     482                 :         float c0_g, c1_g, c2_g, c3_g;
     483                 :         float c0_b, c1_b, c2_b, c3_b;
     484                 :         float clut_r, clut_g, clut_b;
     485               0 :         for (i = 0; i < length; i++) {
     486               0 :                 unsigned char in_r = *src++;
     487               0 :                 unsigned char in_g = *src++;
     488               0 :                 unsigned char in_b = *src++;
     489               0 :                 unsigned char in_a = *src++;
     490               0 :                 float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f;
     491                 : 
     492               0 :                 int x = floor(linear_r * (transform->grid_size-1));
     493               0 :                 int y = floor(linear_g * (transform->grid_size-1));
     494               0 :                 int z = floor(linear_b * (transform->grid_size-1));
     495               0 :                 int x_n = ceil(linear_r * (transform->grid_size-1));
     496               0 :                 int y_n = ceil(linear_g * (transform->grid_size-1));
     497               0 :                 int z_n = ceil(linear_b * (transform->grid_size-1));
     498               0 :                 float rx = linear_r * (transform->grid_size-1) - x; 
     499               0 :                 float ry = linear_g * (transform->grid_size-1) - y;
     500               0 :                 float rz = linear_b * (transform->grid_size-1) - z; 
     501                 : 
     502               0 :                 c0_r = CLU(r_table, x, y, z);
     503               0 :                 c0_g = CLU(g_table, x, y, z);
     504               0 :                 c0_b = CLU(b_table, x, y, z);
     505                 : 
     506               0 :                 if( rx >= ry ) {
     507               0 :                         if (ry >= rz) { //rx >= ry && ry >= rz
     508               0 :                                 c1_r = CLU(r_table, x_n, y, z) - c0_r;
     509               0 :                                 c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
     510               0 :                                 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
     511               0 :                                 c1_g = CLU(g_table, x_n, y, z) - c0_g;
     512               0 :                                 c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
     513               0 :                                 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
     514               0 :                                 c1_b = CLU(b_table, x_n, y, z) - c0_b;
     515               0 :                                 c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
     516               0 :                                 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
     517                 :                         } else { 
     518               0 :                                 if (rx >= rz) { //rx >= rz && rz >= ry
     519               0 :                                         c1_r = CLU(r_table, x_n, y, z) - c0_r;
     520               0 :                                         c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
     521               0 :                                         c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z);
     522               0 :                                         c1_g = CLU(g_table, x_n, y, z) - c0_g;
     523               0 :                                         c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
     524               0 :                                         c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z);
     525               0 :                                         c1_b = CLU(b_table, x_n, y, z) - c0_b;
     526               0 :                                         c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
     527               0 :                                         c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z);
     528                 :                                 } else { //rz > rx && rx >= ry
     529               0 :                                         c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n);
     530               0 :                                         c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
     531               0 :                                         c3_r = CLU(r_table, x, y, z_n) - c0_r;
     532               0 :                                         c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n);
     533               0 :                                         c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
     534               0 :                                         c3_g = CLU(g_table, x, y, z_n) - c0_g;
     535               0 :                                         c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n);
     536               0 :                                         c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
     537               0 :                                         c3_b = CLU(b_table, x, y, z_n) - c0_b;
     538                 :                                 }
     539                 :                         }
     540                 :                 } else {
     541               0 :                         if (rx >= rz) { //ry > rx && rx >= rz
     542               0 :                                 c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
     543               0 :                                 c2_r = CLU(r_table, x, y_n, z) - c0_r;
     544               0 :                                 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
     545               0 :                                 c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
     546               0 :                                 c2_g = CLU(g_table, x, y_n, z) - c0_g;
     547               0 :                                 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
     548               0 :                                 c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
     549               0 :                                 c2_b = CLU(b_table, x, y_n, z) - c0_b;
     550               0 :                                 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
     551                 :                         } else {
     552               0 :                                 if (ry >= rz) { //ry >= rz && rz > rx 
     553               0 :                                         c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
     554               0 :                                         c2_r = CLU(r_table, x, y_n, z) - c0_r;
     555               0 :                                         c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z);
     556               0 :                                         c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
     557               0 :                                         c2_g = CLU(g_table, x, y_n, z) - c0_g;
     558               0 :                                         c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z);
     559               0 :                                         c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
     560               0 :                                         c2_b = CLU(b_table, x, y_n, z) - c0_b;
     561               0 :                                         c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z);
     562                 :                                 } else { //rz > ry && ry > rx
     563               0 :                                         c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
     564               0 :                                         c2_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y, z_n);
     565               0 :                                         c3_r = CLU(r_table, x, y, z_n) - c0_r;
     566               0 :                                         c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
     567               0 :                                         c2_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y, z_n);
     568               0 :                                         c3_g = CLU(g_table, x, y, z_n) - c0_g;
     569               0 :                                         c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
     570               0 :                                         c2_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y, z_n);
     571               0 :                                         c3_b = CLU(b_table, x, y, z_n) - c0_b;
     572                 :                                 }
     573                 :                         }
     574                 :                 }
     575                 :                                 
     576               0 :                 clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
     577               0 :                 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
     578               0 :                 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
     579                 : 
     580               0 :                 *dest++ = clamp_u8(clut_r*255.0f);
     581               0 :                 *dest++ = clamp_u8(clut_g*255.0f);
     582               0 :                 *dest++ = clamp_u8(clut_b*255.0f);
     583               0 :                 *dest++ = in_a;
     584                 :         }       
     585               0 : }
     586                 : 
     587                 : // Using lcms' tetra interpolation code.
     588               0 : static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) {
     589                 :         unsigned int i;
     590               0 :         int xy_len = 1;
     591               0 :         int x_len = transform->grid_size;
     592               0 :         int len = x_len * x_len;
     593               0 :         float* r_table = transform->r_clut;
     594               0 :         float* g_table = transform->g_clut;
     595               0 :         float* b_table = transform->b_clut;
     596                 :         float c0_r, c1_r, c2_r, c3_r;
     597                 :         float c0_g, c1_g, c2_g, c3_g;
     598                 :         float c0_b, c1_b, c2_b, c3_b;
     599                 :         float clut_r, clut_g, clut_b;
     600               0 :         for (i = 0; i < length; i++) {
     601               0 :                 unsigned char in_r = *src++;
     602               0 :                 unsigned char in_g = *src++;
     603               0 :                 unsigned char in_b = *src++;
     604               0 :                 float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f;
     605                 : 
     606               0 :                 int x = floor(linear_r * (transform->grid_size-1));
     607               0 :                 int y = floor(linear_g * (transform->grid_size-1));
     608               0 :                 int z = floor(linear_b * (transform->grid_size-1));
     609               0 :                 int x_n = ceil(linear_r * (transform->grid_size-1));
     610               0 :                 int y_n = ceil(linear_g * (transform->grid_size-1));
     611               0 :                 int z_n = ceil(linear_b * (transform->grid_size-1));
     612               0 :                 float rx = linear_r * (transform->grid_size-1) - x; 
     613               0 :                 float ry = linear_g * (transform->grid_size-1) - y;
     614               0 :                 float rz = linear_b * (transform->grid_size-1) - z; 
     615                 : 
     616               0 :                 c0_r = CLU(r_table, x, y, z);
     617               0 :                 c0_g = CLU(g_table, x, y, z);
     618               0 :                 c0_b = CLU(b_table, x, y, z);
     619                 : 
     620               0 :                 if( rx >= ry ) {
     621               0 :                         if (ry >= rz) { //rx >= ry && ry >= rz
     622               0 :                                 c1_r = CLU(r_table, x_n, y, z) - c0_r;
     623               0 :                                 c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
     624               0 :                                 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
     625               0 :                                 c1_g = CLU(g_table, x_n, y, z) - c0_g;
     626               0 :                                 c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
     627               0 :                                 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
     628               0 :                                 c1_b = CLU(b_table, x_n, y, z) - c0_b;
     629               0 :                                 c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
     630               0 :                                 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
     631                 :                         } else { 
     632               0 :                                 if (rx >= rz) { //rx >= rz && rz >= ry
     633               0 :                                         c1_r = CLU(r_table, x_n, y, z) - c0_r;
     634               0 :                                         c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
     635               0 :                                         c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z);
     636               0 :                                         c1_g = CLU(g_table, x_n, y, z) - c0_g;
     637               0 :                                         c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
     638               0 :                                         c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z);
     639               0 :                                         c1_b = CLU(b_table, x_n, y, z) - c0_b;
     640               0 :                                         c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
     641               0 :                                         c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z);
     642                 :                                 } else { //rz > rx && rx >= ry
     643               0 :                                         c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n);
     644               0 :                                         c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n);
     645               0 :                                         c3_r = CLU(r_table, x, y, z_n) - c0_r;
     646               0 :                                         c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n);
     647               0 :                                         c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n);
     648               0 :                                         c3_g = CLU(g_table, x, y, z_n) - c0_g;
     649               0 :                                         c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n);
     650               0 :                                         c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n);
     651               0 :                                         c3_b = CLU(b_table, x, y, z_n) - c0_b;
     652                 :                                 }
     653                 :                         }
     654                 :                 } else {
     655               0 :                         if (rx >= rz) { //ry > rx && rx >= rz
     656               0 :                                 c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
     657               0 :                                 c2_r = CLU(r_table, x, y_n, z) - c0_r;
     658               0 :                                 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z);
     659               0 :                                 c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
     660               0 :                                 c2_g = CLU(g_table, x, y_n, z) - c0_g;
     661               0 :                                 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z);
     662               0 :                                 c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
     663               0 :                                 c2_b = CLU(b_table, x, y_n, z) - c0_b;
     664               0 :                                 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z);
     665                 :                         } else {
     666               0 :                                 if (ry >= rz) { //ry >= rz && rz > rx 
     667               0 :                                         c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
     668               0 :                                         c2_r = CLU(r_table, x, y_n, z) - c0_r;
     669               0 :                                         c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z);
     670               0 :                                         c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
     671               0 :                                         c2_g = CLU(g_table, x, y_n, z) - c0_g;
     672               0 :                                         c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z);
     673               0 :                                         c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
     674               0 :                                         c2_b = CLU(b_table, x, y_n, z) - c0_b;
     675               0 :                                         c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z);
     676                 :                                 } else { //rz > ry && ry > rx
     677               0 :                                         c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n);
     678               0 :                                         c2_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y, z_n);
     679               0 :                                         c3_r = CLU(r_table, x, y, z_n) - c0_r;
     680               0 :                                         c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n);
     681               0 :                                         c2_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y, z_n);
     682               0 :                                         c3_g = CLU(g_table, x, y, z_n) - c0_g;
     683               0 :                                         c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n);
     684               0 :                                         c2_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y, z_n);
     685               0 :                                         c3_b = CLU(b_table, x, y, z_n) - c0_b;
     686                 :                                 }
     687                 :                         }
     688                 :                 }
     689                 :                                 
     690               0 :                 clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
     691               0 :                 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
     692               0 :                 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
     693                 : 
     694               0 :                 *dest++ = clamp_u8(clut_r*255.0f);
     695               0 :                 *dest++ = clamp_u8(clut_g*255.0f);
     696               0 :                 *dest++ = clamp_u8(clut_b*255.0f);
     697                 :         }       
     698               0 : }
     699                 : 
     700               0 : static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     701                 : {
     702                 :         unsigned int i;
     703               0 :         float (*mat)[4] = transform->matrix;
     704               0 :         for (i = 0; i < length; i++) {
     705               0 :                 unsigned char device_r = *src++;
     706               0 :                 unsigned char device_g = *src++;
     707               0 :                 unsigned char device_b = *src++;
     708                 :                 float out_device_r, out_device_g, out_device_b;
     709                 : 
     710               0 :                 float linear_r = transform->input_gamma_table_r[device_r];
     711               0 :                 float linear_g = transform->input_gamma_table_g[device_g];
     712               0 :                 float linear_b = transform->input_gamma_table_b[device_b];
     713                 : 
     714               0 :                 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
     715               0 :                 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
     716               0 :                 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
     717                 : 
     718               0 :                 out_linear_r = clamp_float(out_linear_r);
     719               0 :                 out_linear_g = clamp_float(out_linear_g);
     720               0 :                 out_linear_b = clamp_float(out_linear_b);
     721                 : 
     722               0 :                 out_device_r = lut_interp_linear(out_linear_r, 
     723               0 :                                 transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
     724               0 :                 out_device_g = lut_interp_linear(out_linear_g, 
     725               0 :                                 transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
     726               0 :                 out_device_b = lut_interp_linear(out_linear_b, 
     727               0 :                                 transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
     728                 : 
     729               0 :                 *dest++ = clamp_u8(out_device_r*255);
     730               0 :                 *dest++ = clamp_u8(out_device_g*255);
     731               0 :                 *dest++ = clamp_u8(out_device_b*255);
     732                 :         }
     733               0 : }
     734                 : 
     735               0 : static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     736                 : {
     737                 :         unsigned int i;
     738               0 :         float (*mat)[4] = transform->matrix;
     739               0 :         for (i = 0; i < length; i++) {
     740               0 :                 unsigned char device_r = *src++;
     741               0 :                 unsigned char device_g = *src++;
     742               0 :                 unsigned char device_b = *src++;
     743               0 :                 unsigned char alpha = *src++;
     744                 :                 float out_device_r, out_device_g, out_device_b;
     745                 : 
     746               0 :                 float linear_r = transform->input_gamma_table_r[device_r];
     747               0 :                 float linear_g = transform->input_gamma_table_g[device_g];
     748               0 :                 float linear_b = transform->input_gamma_table_b[device_b];
     749                 : 
     750               0 :                 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
     751               0 :                 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
     752               0 :                 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
     753                 : 
     754               0 :                 out_linear_r = clamp_float(out_linear_r);
     755               0 :                 out_linear_g = clamp_float(out_linear_g);
     756               0 :                 out_linear_b = clamp_float(out_linear_b);
     757                 : 
     758               0 :                 out_device_r = lut_interp_linear(out_linear_r, 
     759               0 :                                 transform->output_gamma_lut_r, transform->output_gamma_lut_r_length);
     760               0 :                 out_device_g = lut_interp_linear(out_linear_g, 
     761               0 :                                 transform->output_gamma_lut_g, transform->output_gamma_lut_g_length);
     762               0 :                 out_device_b = lut_interp_linear(out_linear_b, 
     763               0 :                                 transform->output_gamma_lut_b, transform->output_gamma_lut_b_length);
     764                 : 
     765               0 :                 *dest++ = clamp_u8(out_device_r*255);
     766               0 :                 *dest++ = clamp_u8(out_device_g*255);
     767               0 :                 *dest++ = clamp_u8(out_device_b*255);
     768               0 :                 *dest++ = alpha;
     769                 :         }
     770               0 : }
     771                 : 
     772                 : #if 0
     773                 : static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
     774                 : {
     775                 :         int i;
     776                 :         float (*mat)[4] = transform->matrix;
     777                 :         for (i = 0; i < length; i++) {
     778                 :                 unsigned char device_r = *src++;
     779                 :                 unsigned char device_g = *src++;
     780                 :                 unsigned char device_b = *src++;
     781                 : 
     782                 :                 float linear_r = transform->input_gamma_table_r[device_r];
     783                 :                 float linear_g = transform->input_gamma_table_g[device_g];
     784                 :                 float linear_b = transform->input_gamma_table_b[device_b];
     785                 : 
     786                 :                 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b;
     787                 :                 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b;
     788                 :                 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b;
     789                 : 
     790                 :                 *dest++ = clamp_u8(out_linear_r*255);
     791                 :                 *dest++ = clamp_u8(out_linear_g*255);
     792                 :                 *dest++ = clamp_u8(out_linear_b*255);
     793                 :         }
     794                 : }
     795                 : #endif
     796                 : 
     797               0 : static struct precache_output *precache_reference(struct precache_output *p)
     798                 : {
     799               0 :         p->ref_count++;
     800               0 :         return p;
     801                 : }
     802                 : 
     803               0 : static struct precache_output *precache_create()
     804                 : {
     805               0 :         struct precache_output *p = malloc(sizeof(struct precache_output));
     806               0 :         if (p)
     807               0 :                 p->ref_count = 1;
     808               0 :         return p;
     809                 : }
     810                 : 
     811               0 : void precache_release(struct precache_output *p)
     812                 : {
     813               0 :         if (--p->ref_count == 0) {
     814               0 :                 free(p);
     815                 :         }
     816               0 : }
     817                 : 
     818                 : #ifdef HAS_POSIX_MEMALIGN
     819                 : static qcms_transform *transform_alloc(void)
     820                 : {
     821                 :         qcms_transform *t;
     822                 :         if (!posix_memalign(&t, 16, sizeof(*t))) {
     823                 :                 return t;
     824                 :         } else {
     825                 :                 return NULL;
     826                 :         }
     827                 : }
     828                 : static void transform_free(qcms_transform *t)
     829                 : {
     830                 :         free(t);
     831                 : }
     832                 : #else
     833               0 : static qcms_transform *transform_alloc(void)
     834                 : {
     835                 :         /* transform needs to be aligned on a 16byte boundrary */
     836               0 :         char *original_block = calloc(sizeof(qcms_transform) + sizeof(void*) + 16, 1);
     837                 :         /* make room for a pointer to the block returned by calloc */
     838               0 :         void *transform_start = original_block + sizeof(void*);
     839                 :         /* align transform_start */
     840               0 :         qcms_transform *transform_aligned = (qcms_transform*)(((uintptr_t)transform_start + 15) & ~0xf);
     841                 : 
     842                 :         /* store a pointer to the block returned by calloc so that we can free it later */
     843               0 :         void **(original_block_ptr) = (void**)transform_aligned;
     844               0 :         if (!original_block)
     845               0 :                 return NULL;
     846               0 :         original_block_ptr--;
     847               0 :         *original_block_ptr = original_block;
     848                 : 
     849               0 :         return transform_aligned;
     850                 : }
     851               0 : static void transform_free(qcms_transform *t)
     852                 : {
     853                 :         /* get at the pointer to the unaligned block returned by calloc */
     854               0 :         void **p = (void**)t;
     855               0 :         p--;
     856               0 :         free(*p);
     857               0 : }
     858                 : #endif
     859                 : 
     860               0 : void qcms_transform_release(qcms_transform *t)
     861                 : {
     862                 :         /* ensure we only free the gamma tables once even if there are
     863                 :          * multiple references to the same data */
     864                 : 
     865               0 :         if (t->output_table_r)
     866               0 :                 precache_release(t->output_table_r);
     867               0 :         if (t->output_table_g)
     868               0 :                 precache_release(t->output_table_g);
     869               0 :         if (t->output_table_b)
     870               0 :                 precache_release(t->output_table_b);
     871                 : 
     872               0 :         free(t->input_gamma_table_r);
     873               0 :         if (t->input_gamma_table_g != t->input_gamma_table_r)
     874               0 :                 free(t->input_gamma_table_g);
     875               0 :         if (t->input_gamma_table_g != t->input_gamma_table_r &&
     876               0 :             t->input_gamma_table_g != t->input_gamma_table_b)
     877               0 :                 free(t->input_gamma_table_b);
     878                 : 
     879               0 :         free(t->input_gamma_table_gray);
     880                 : 
     881               0 :         free(t->output_gamma_lut_r);
     882               0 :         free(t->output_gamma_lut_g);
     883               0 :         free(t->output_gamma_lut_b);
     884                 : 
     885               0 :         transform_free(t);
     886               0 : }
     887                 : 
     888                 : #ifdef X86
     889                 : // Determine if we can build with SSE2 (this was partly copied from jmorecfg.h in
     890                 : // mozilla/jpeg)
     891                 :  // -------------------------------------------------------------------------
     892                 : #if defined(_M_IX86) && defined(_MSC_VER)
     893                 : #define HAS_CPUID
     894                 : /* Get us a CPUID function. Avoid clobbering EBX because sometimes it's the PIC
     895                 :    register - I'm not sure if that ever happens on windows, but cpuid isn't
     896                 :    on the critical path so we just preserve the register to be safe and to be
     897                 :    consistent with the non-windows version. */
     898                 : static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
     899                 :        uint32_t a_, b_, c_, d_;
     900                 :        __asm {
     901                 :               xchg   ebx, esi
     902                 :               mov    eax, fxn
     903                 :               cpuid
     904                 :               mov    a_, eax
     905                 :               mov    b_, ebx
     906                 :               mov    c_, ecx
     907                 :               mov    d_, edx
     908                 :               xchg   ebx, esi
     909                 :        }
     910                 :        *a = a_;
     911                 :        *b = b_;
     912                 :        *c = c_;
     913                 :        *d = d_;
     914                 : }
     915                 : #elif (defined(__GNUC__) || defined(__SUNPRO_C)) && (defined(__i386__) || defined(__i386))
     916                 : #define HAS_CPUID
     917                 : /* Get us a CPUID function. We can't use ebx because it's the PIC register on
     918                 :    some platforms, so we use ESI instead and save ebx to avoid clobbering it. */
     919               0 : static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
     920                 : 
     921                 :         uint32_t a_, b_, c_, d_;
     922               0 :        __asm__ __volatile__ ("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi;" 
     923                 :                              : "=a" (a_), "=S" (b_), "=c" (c_), "=d" (d_) : "a" (fxn));
     924               0 :            *a = a_;
     925               0 :            *b = b_;
     926               0 :            *c = c_;
     927               0 :            *d = d_;
     928               0 : }
     929                 : #endif
     930                 : 
     931                 : // -------------------------Runtime SSEx Detection-----------------------------
     932                 : 
     933                 : /* MMX is always supported per
     934                 :  *  Gecko v1.9.1 minimum CPU requirements */
     935                 : #define SSE1_EDX_MASK (1UL << 25)
     936                 : #define SSE2_EDX_MASK (1UL << 26)
     937                 : #define SSE3_ECX_MASK (1UL <<  0)
     938                 : 
     939               0 : static int sse_version_available(void)
     940                 : {
     941                 : #if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
     942                 :         /* we know at build time that 64-bit CPUs always have SSE2
     943                 :          * this tells the compiler that non-SSE2 branches will never be
     944                 :          * taken (i.e. OK to optimze away the SSE1 and non-SIMD code */
     945                 :         return 2;
     946                 : #elif defined(HAS_CPUID)
     947                 :         static int sse_version = -1;
     948                 :         uint32_t a, b, c, d;
     949               0 :         uint32_t function = 0x00000001;
     950                 : 
     951               0 :         if (sse_version == -1) {
     952               0 :                 sse_version = 0;
     953               0 :                 cpuid(function, &a, &b, &c, &d);
     954               0 :                 if (c & SSE3_ECX_MASK)
     955               0 :                         sse_version = 3;
     956               0 :                 else if (d & SSE2_EDX_MASK)
     957               0 :                         sse_version = 2;
     958               0 :                 else if (d & SSE1_EDX_MASK)
     959               0 :                         sse_version = 1;
     960                 :         }
     961                 : 
     962               0 :         return sse_version;
     963                 : #else
     964                 :         return 0;
     965                 : #endif
     966                 : }
     967                 : #endif
     968                 : 
     969                 : static const struct matrix bradford_matrix = {{ { 0.8951f, 0.2664f,-0.1614f},
     970                 :                                                 {-0.7502f, 1.7135f, 0.0367f},
     971                 :                                                 { 0.0389f,-0.0685f, 1.0296f}}, 
     972                 :                                                 false};
     973                 : 
     974                 : static const struct matrix bradford_matrix_inv = {{ { 0.9869929f,-0.1470543f, 0.1599627f},
     975                 :                                                     { 0.4323053f, 0.5183603f, 0.0492912f},
     976                 :                                                     {-0.0085287f, 0.0400428f, 0.9684867f}}, 
     977                 :                                                     false};
     978                 : 
     979                 : // See ICCv4 E.3
     980               0 : struct matrix compute_whitepoint_adaption(float X, float Y, float Z) {
     981               0 :         float p = (0.96422f*bradford_matrix.m[0][0] + 1.000f*bradford_matrix.m[1][0] + 0.82521f*bradford_matrix.m[2][0]) /
     982               0 :                   (X*bradford_matrix.m[0][0]      + Y*bradford_matrix.m[1][0]      + Z*bradford_matrix.m[2][0]     );
     983               0 :         float y = (0.96422f*bradford_matrix.m[0][1] + 1.000f*bradford_matrix.m[1][1] + 0.82521f*bradford_matrix.m[2][1]) /
     984               0 :                   (X*bradford_matrix.m[0][1]      + Y*bradford_matrix.m[1][1]      + Z*bradford_matrix.m[2][1]     );
     985               0 :         float b = (0.96422f*bradford_matrix.m[0][2] + 1.000f*bradford_matrix.m[1][2] + 0.82521f*bradford_matrix.m[2][2]) /
     986               0 :                   (X*bradford_matrix.m[0][2]      + Y*bradford_matrix.m[1][2]      + Z*bradford_matrix.m[2][2]     );
     987               0 :         struct matrix white_adaption = {{ {p,0,0}, {0,y,0}, {0,0,b}}, false};
     988               0 :         return matrix_multiply( bradford_matrix_inv, matrix_multiply(white_adaption, bradford_matrix) );
     989                 : }
     990                 : 
     991               0 : void qcms_profile_precache_output_transform(qcms_profile *profile)
     992                 : {
     993                 :         /* we only support precaching on rgb profiles */
     994               0 :         if (profile->color_space != RGB_SIGNATURE)
     995               0 :                 return;
     996                 : 
     997                 :         /* don't precache since we will use the B2A LUT */
     998               0 :         if (profile->B2A0)
     999               0 :                 return;
    1000                 : 
    1001                 :         /* don't precache since we will use the mBA LUT */
    1002               0 :         if (profile->mBA)
    1003               0 :                 return;
    1004                 : 
    1005                 :         /* don't precache if we do not have the TRC curves */
    1006               0 :         if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC)
    1007               0 :                 return;
    1008                 : 
    1009               0 :         if (!profile->output_table_r) {
    1010               0 :                 profile->output_table_r = precache_create();
    1011               0 :                 if (profile->output_table_r &&
    1012               0 :                                 !compute_precache(profile->redTRC, profile->output_table_r->data)) {
    1013               0 :                         precache_release(profile->output_table_r);
    1014               0 :                         profile->output_table_r = NULL;
    1015                 :                 }
    1016                 :         }
    1017               0 :         if (!profile->output_table_g) {
    1018               0 :                 profile->output_table_g = precache_create();
    1019               0 :                 if (profile->output_table_g &&
    1020               0 :                                 !compute_precache(profile->greenTRC, profile->output_table_g->data)) {
    1021               0 :                         precache_release(profile->output_table_g);
    1022               0 :                         profile->output_table_g = NULL;
    1023                 :                 }
    1024                 :         }
    1025               0 :         if (!profile->output_table_b) {
    1026               0 :                 profile->output_table_b = precache_create();
    1027               0 :                 if (profile->output_table_b &&
    1028               0 :                                 !compute_precache(profile->blueTRC, profile->output_table_b->data)) {
    1029               0 :                         precache_release(profile->output_table_b);
    1030               0 :                         profile->output_table_b = NULL;
    1031                 :                 }
    1032                 :         }
    1033                 : }
    1034                 : 
    1035                 : /* Replace the current transformation with a LUT transformation using a given number of sample points */
    1036               0 : qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms_profile *in, qcms_profile *out, 
    1037                 :                                                  int samples, qcms_data_type in_type)
    1038                 : {
    1039                 :         /* The range between which 2 consecutive sample points can be used to interpolate */
    1040                 :         uint16_t x,y,z;
    1041                 :         uint32_t l;
    1042               0 :         uint32_t lutSize = 3 * samples * samples * samples;
    1043               0 :         float* src = NULL;
    1044               0 :         float* dest = NULL;
    1045               0 :         float* lut = NULL;
    1046                 : 
    1047               0 :         src = malloc(lutSize*sizeof(float));
    1048               0 :         dest = malloc(lutSize*sizeof(float));
    1049                 : 
    1050               0 :         if (src && dest) {
    1051                 :                 /* Prepare a list of points we want to sample */
    1052               0 :                 l = 0;
    1053               0 :                 for (x = 0; x < samples; x++) {
    1054               0 :                         for (y = 0; y < samples; y++) {
    1055               0 :                                 for (z = 0; z < samples; z++) {
    1056               0 :                                         src[l++] = x / (float)(samples-1);
    1057               0 :                                         src[l++] = y / (float)(samples-1);
    1058               0 :                                         src[l++] = z / (float)(samples-1);
    1059                 :                                 }
    1060                 :                         }
    1061                 :                 }
    1062                 : 
    1063               0 :                 lut = qcms_chain_transform(in, out, src, dest, lutSize);
    1064               0 :                 if (lut) {
    1065               0 :                         transform->r_clut = &lut[0];
    1066               0 :                         transform->g_clut = &lut[1];
    1067               0 :                         transform->b_clut = &lut[2];
    1068               0 :                         transform->grid_size = samples;
    1069               0 :                         if (in_type == QCMS_DATA_RGBA_8) {
    1070               0 :                                 transform->transform_fn = qcms_transform_data_tetra_clut_rgba;
    1071                 :                         } else {
    1072               0 :                                 transform->transform_fn = qcms_transform_data_tetra_clut;
    1073                 :                         }
    1074                 :                 }
    1075                 :         }
    1076                 : 
    1077                 : 
    1078                 :         //XXX: qcms_modular_transform_data may return either the src or dest buffer. If so it must not be free-ed
    1079               0 :         if (src && lut != src) {
    1080               0 :                 free(src);
    1081                 :         }
    1082               0 :         if (dest && lut != dest) {
    1083               0 :                 free(dest);
    1084                 :         }
    1085                 : 
    1086               0 :         if (lut == NULL) {
    1087               0 :                 return NULL;
    1088                 :         }
    1089               0 :         return transform;
    1090                 : }
    1091                 : 
    1092                 : #define NO_MEM_TRANSFORM NULL
    1093                 : 
    1094               0 : qcms_transform* qcms_transform_create(
    1095                 :                 qcms_profile *in, qcms_data_type in_type,
    1096                 :                 qcms_profile *out, qcms_data_type out_type,
    1097                 :                 qcms_intent intent)
    1098                 : {
    1099               0 :         bool precache = false;
    1100                 : 
    1101               0 :         qcms_transform *transform = transform_alloc();
    1102               0 :         if (!transform) {
    1103               0 :                 return NULL;
    1104                 :         }
    1105               0 :         if (out_type != QCMS_DATA_RGB_8 &&
    1106                 :                 out_type != QCMS_DATA_RGBA_8) {
    1107               0 :             assert(0 && "output type");
    1108                 :             transform_free(transform);
    1109                 :             return NULL;
    1110                 :         }
    1111                 : 
    1112               0 :         if (out->output_table_r &&
    1113               0 :                         out->output_table_g &&
    1114               0 :                         out->output_table_b) {
    1115               0 :                 precache = true;
    1116                 :         }
    1117                 : 
    1118               0 :         if (qcms_supports_iccv4 && (in->A2B0 || out->B2A0 || in->mAB || out->mAB)) {
    1119                 :                 // Precache the transformation to a CLUT 33x33x33 in size.
    1120                 :                 // 33 is used by many profiles and works well in pratice. 
    1121                 :                 // This evenly divides 256 into blocks of 8x8x8.
    1122                 :                 // TODO For transforming small data sets of about 200x200 or less
    1123                 :                 // precaching should be avoided.
    1124               0 :                 qcms_transform *result = qcms_transform_precacheLUT_float(transform, in, out, 33, in_type);
    1125               0 :                 if (!result) {
    1126               0 :                         assert(0 && "precacheLUT failed");
    1127                 :                         transform_free(transform);
    1128                 :                         return NULL;
    1129                 :                 }
    1130               0 :                 return result;
    1131                 :         }
    1132                 : 
    1133               0 :         if (precache) {
    1134               0 :                 transform->output_table_r = precache_reference(out->output_table_r);
    1135               0 :                 transform->output_table_g = precache_reference(out->output_table_g);
    1136               0 :                 transform->output_table_b = precache_reference(out->output_table_b);
    1137                 :         } else {
    1138               0 :                 if (!out->redTRC || !out->greenTRC || !out->blueTRC) {
    1139               0 :                         qcms_transform_release(transform);
    1140               0 :                         return NO_MEM_TRANSFORM;
    1141                 :                 }
    1142               0 :                 build_output_lut(out->redTRC, &transform->output_gamma_lut_r, &transform->output_gamma_lut_r_length);
    1143               0 :                 build_output_lut(out->greenTRC, &transform->output_gamma_lut_g, &transform->output_gamma_lut_g_length);
    1144               0 :                 build_output_lut(out->blueTRC, &transform->output_gamma_lut_b, &transform->output_gamma_lut_b_length);
    1145               0 :                 if (!transform->output_gamma_lut_r || !transform->output_gamma_lut_g || !transform->output_gamma_lut_b) {
    1146               0 :                         qcms_transform_release(transform);
    1147               0 :                         return NO_MEM_TRANSFORM;
    1148                 :                 }
    1149                 :         }
    1150                 : 
    1151               0 :         if (in->color_space == RGB_SIGNATURE) {
    1152                 :                 struct matrix in_matrix, out_matrix, result;
    1153                 : 
    1154               0 :                 if (in_type != QCMS_DATA_RGB_8 &&
    1155                 :                     in_type != QCMS_DATA_RGBA_8){
    1156               0 :                         assert(0 && "input type");
    1157                 :                         transform_free(transform);
    1158                 :                         return NULL;
    1159                 :                 }
    1160               0 :                 if (precache) {
    1161                 : #ifdef X86
    1162               0 :                     if (sse_version_available() >= 2) {
    1163               0 :                             if (in_type == QCMS_DATA_RGB_8)
    1164               0 :                                     transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2;
    1165                 :                             else
    1166               0 :                                     transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2;
    1167                 : 
    1168                 : #if !(defined(_MSC_VER) && defined(_M_AMD64))
    1169                 :                     /* Microsoft Compiler for x64 doesn't support MMX.
    1170                 :                      * SSE code uses MMX so that we disable on x64 */
    1171                 :                     } else
    1172               0 :                     if (sse_version_available() >= 1) {
    1173               0 :                             if (in_type == QCMS_DATA_RGB_8)
    1174               0 :                                     transform->transform_fn = qcms_transform_data_rgb_out_lut_sse1;
    1175                 :                             else
    1176               0 :                                     transform->transform_fn = qcms_transform_data_rgba_out_lut_sse1;
    1177                 : #endif
    1178                 :                     } else
    1179                 : #endif
    1180                 :                         {
    1181               0 :                                 if (in_type == QCMS_DATA_RGB_8)
    1182               0 :                                         transform->transform_fn = qcms_transform_data_rgb_out_lut_precache;
    1183                 :                                 else
    1184               0 :                                         transform->transform_fn = qcms_transform_data_rgba_out_lut_precache;
    1185                 :                         }
    1186                 :                 } else {
    1187               0 :                         if (in_type == QCMS_DATA_RGB_8)
    1188               0 :                                 transform->transform_fn = qcms_transform_data_rgb_out_lut;
    1189                 :                         else
    1190               0 :                                 transform->transform_fn = qcms_transform_data_rgba_out_lut;
    1191                 :                 }
    1192                 : 
    1193                 :                 //XXX: avoid duplicating tables if we can
    1194               0 :                 transform->input_gamma_table_r = build_input_gamma_table(in->redTRC);
    1195               0 :                 transform->input_gamma_table_g = build_input_gamma_table(in->greenTRC);
    1196               0 :                 transform->input_gamma_table_b = build_input_gamma_table(in->blueTRC);
    1197               0 :                 if (!transform->input_gamma_table_r || !transform->input_gamma_table_g || !transform->input_gamma_table_b) {
    1198               0 :                         qcms_transform_release(transform);
    1199               0 :                         return NO_MEM_TRANSFORM;
    1200                 :                 }
    1201                 : 
    1202                 : 
    1203                 :                 /* build combined colorant matrix */
    1204               0 :                 in_matrix = build_colorant_matrix(in);
    1205               0 :                 out_matrix = build_colorant_matrix(out);
    1206               0 :                 out_matrix = matrix_invert(out_matrix);
    1207               0 :                 if (out_matrix.invalid) {
    1208               0 :                         qcms_transform_release(transform);
    1209               0 :                         return NULL;
    1210                 :                 }
    1211               0 :                 result = matrix_multiply(out_matrix, in_matrix);
    1212                 : 
    1213                 :                 /* store the results in column major mode
    1214                 :                  * this makes doing the multiplication with sse easier */
    1215               0 :                 transform->matrix[0][0] = result.m[0][0];
    1216               0 :                 transform->matrix[1][0] = result.m[0][1];
    1217               0 :                 transform->matrix[2][0] = result.m[0][2];
    1218               0 :                 transform->matrix[0][1] = result.m[1][0];
    1219               0 :                 transform->matrix[1][1] = result.m[1][1];
    1220               0 :                 transform->matrix[2][1] = result.m[1][2];
    1221               0 :                 transform->matrix[0][2] = result.m[2][0];
    1222               0 :                 transform->matrix[1][2] = result.m[2][1];
    1223               0 :                 transform->matrix[2][2] = result.m[2][2];
    1224                 : 
    1225               0 :         } else if (in->color_space == GRAY_SIGNATURE) {
    1226               0 :                 if (in_type != QCMS_DATA_GRAY_8 &&
    1227                 :                                 in_type != QCMS_DATA_GRAYA_8){
    1228               0 :                         assert(0 && "input type");
    1229                 :                         transform_free(transform);
    1230                 :                         return NULL;
    1231                 :                 }
    1232                 : 
    1233               0 :                 transform->input_gamma_table_gray = build_input_gamma_table(in->grayTRC);
    1234               0 :                 if (!transform->input_gamma_table_gray) {
    1235               0 :                         qcms_transform_release(transform);
    1236               0 :                         return NO_MEM_TRANSFORM;
    1237                 :                 }
    1238                 : 
    1239               0 :                 if (precache) {
    1240               0 :                         if (in_type == QCMS_DATA_GRAY_8) {
    1241               0 :                                 transform->transform_fn = qcms_transform_data_gray_out_precache;
    1242                 :                         } else {
    1243               0 :                                 transform->transform_fn = qcms_transform_data_graya_out_precache;
    1244                 :                         }
    1245                 :                 } else {
    1246               0 :                         if (in_type == QCMS_DATA_GRAY_8) {
    1247               0 :                                 transform->transform_fn = qcms_transform_data_gray_out_lut;
    1248                 :                         } else {
    1249               0 :                                 transform->transform_fn = qcms_transform_data_graya_out_lut;
    1250                 :                         }
    1251                 :                 }
    1252                 :         } else {
    1253               0 :                 assert(0 && "unexpected colorspace");
    1254                 :                 transform_free(transform);
    1255                 :                 return NULL;
    1256                 :         }
    1257               0 :         return transform;
    1258                 : }
    1259                 : 
    1260                 : #if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
    1261                 : /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
    1262                 : __attribute__((__force_align_arg_pointer__))
    1263                 : #endif
    1264               0 : void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length)
    1265                 : {
    1266               0 :         transform->transform_fn(transform, src, dest, length);
    1267               0 : }
    1268                 : 
    1269                 : qcms_bool qcms_supports_iccv4;
    1270               0 : void qcms_enable_iccv4()
    1271                 : {
    1272               0 :         qcms_supports_iccv4 = true;
    1273               0 : }

Generated by: LCOV version 1.7