/** Function: oyNamedColor_GetColor
 *  @memberof oyNamedColor_s
 *  @brief   convert a named color to a standard color space
 *
 *  @since Oyranos: version 0.1.8
 *  @date  23 december 2007 (API 0.1.8)
 */
int          oyNamedColor_GetColor   ( oyNamedColor_s    * color,
                                       oyProfile_s       * profile,
                                       oyPointer           buf,
                                       oyDATATYPE_e        buf_type,
                                       uint32_t            flags,
                                       oyOptions_s       * options )
{
  int error = !color || !profile || !buf;
  oyNamedColor_s_ * s = (oyNamedColor_s_*) color;
  oyProfile_s * p_in = 0;

  if(!error)
    p_in = s->profile_;

  /* XYZ has priority */
  if(error <= 0 &&
     s->XYZ_[0] != -1 && s->XYZ_[1] != -1 && s->XYZ_[2] != -1)
  {
    p_in = oyProfile_FromStd ( oyEDITING_XYZ, flags, NULL );
    if(!profile)
      return 1;
 
    error = oyColorConvert_( p_in, profile,
                              s->XYZ_, buf,
                              oyDOUBLE, buf_type, options, 1);

    oyProfile_Release ( &p_in );

  } else if(error <= 0)
    error = oyColorConvert_( p_in, profile,
                              s->channels_, buf,
                              oyDOUBLE, buf_type, options, 1);

  return error;
}
예제 #2
0
bool ColorContext::getDeviceProfile(oyConfig_s *device)
{
    kDebug() << device;

    oyProfile_Release(&m_dstProfile);

    oyOptions_s *options = 0;
    oyOptions_SetFromText(&options, "//"OY_TYPE_STD"/config/command", "list", OY_CREATE_NEW);
    oyOptions_SetFromText(&options,
        "//"OY_TYPE_STD"/config/icc_profile.x_color_region_target",
        "yes", OY_CREATE_NEW );
    int error = oyDeviceGetProfile(device, options, &m_dstProfile);
    oyOptions_Release(&options);

    if (m_dstProfile) {
        /* check that no sRGB is delivered */
        if (error) {
            oyProfile_s *dummyProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0);
            if (oyProfile_Equal(dummyProfile, m_dstProfile)) {
                kWarning() << "Output" << m_outputName << "ignoring fallback, error" << error;
                oyProfile_Release(&m_dstProfile);
                error = 1;
            } else
                error = 0;
            oyProfile_Release(&dummyProfile);
        }
    } else {
        kWarning() << "Output" << m_outputName << ": no ICC profile found, error" << error;
        error = 1;
    }

    return error == 0;
}
예제 #3
0
void ColorContext::setup(const QString &name)
{
    kDebug();
    if (!Display::getInstance()->colorDesktopActivated())
        return;

    m_srcProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0);
    m_outputName = name;
    if (!m_srcProfile)
        kWarning() << "Output" << name << "no sRGB source profile";

    setupColorLookupTable(Display::getInstance()->isAdvancedIccDisplay());
}
/** Function: oyNamedColor_GetColorStd
 *  @memberof oyNamedColor_s
 *  @brief   convert a named color to a standard color space
 *
 *  @since Oyranos: version 0.1.8
 *  @date  23 december 2007 (API 0.1.8)
 */
int      oyNamedColor_GetColorStd    ( oyNamedColor_s    * color,
                                       oyPROFILE_e         color_space,
                                       oyPointer           buf,
                                       oyDATATYPE_e        buf_type,
                                       uint32_t            flags,
                                       oyOptions_s       * options )
{                        
  int ret = 0;
  oyProfile_s * profile;
  oyNamedColor_s_ * s = (oyNamedColor_s_*) color;

  if(!color)
    return 1;

  /* abreviate */
  if(buf_type == oyDOUBLE &&
     s->XYZ_[0] != -1 && s->XYZ_[1] != -1 && s->XYZ_[2] != -1)
  {
    if(color_space == oyEDITING_LAB)
    {
      oyXYZ2Lab( s->XYZ_, (double*)buf );
      return 0;
    }

    if(color_space == oyEDITING_XYZ)
    {
      oyCopyColor( s->XYZ_, (double*)buf, 1, 0, 0 );
      return 0;
    }
  }

  profile = oyProfile_FromStd ( color_space, flags, NULL );
  if(!profile)
    return 1;

  ret = oyNamedColor_GetColor ( color, profile, buf, buf_type, 0, options );
  oyProfile_Release ( &profile );

  return ret;
}
예제 #5
0
/** @brief  create_profile.white_point_adjust.bradford
 *
 *  The profile will be generated in many different shades, which will explode
 *  conversion cache.
 */
int      oyProfileAddWhitePointEffect( oyProfile_s       * monitor_profile,
                                       oyOptions_s      ** module_options )
{
  oyProfile_s * wtpt = NULL;
  double        src_XYZ[3] = {0.0, 0.0, 0.0}, dst_XYZ[3] = {0.0, 0.0, 0.0},
                scale = 1.0;
  int error = oyProfile_GetWhitePoint( monitor_profile, src_XYZ );
  int32_t display_white_point = oyGetBehaviour( oyBEHAVIOUR_DISPLAY_WHITE_POINT );
  oyOptions_s * result_opts = NULL, * opts = NULL;
  const char * desc = NULL;

  if(*module_options)
  {
    const char * value = oyOptions_FindString( *module_options, "display_white_point", 0 );
    if(value)
    {
      int c = atoi( value );
      if(c >= 0)
        display_white_point = c;
    }
  }

  if(!display_white_point)
    return 0;

  if(!error)
    error = oyGetDisplayWhitePoint( display_white_point, dst_XYZ );
  if(isnan(dst_XYZ[0]))
    error = 1;
  if(error)
  {
    oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                   "automatic display_white_point: not readable", OY_DBG_ARGS_);
    return error;
  }

  desc = oyProfile_GetText( monitor_profile, oyNAME_DESCRIPTION );

  error = oyOptions_SetFromString( &opts, "//" OY_TYPE_STD "/src_name", desc, OY_CREATE_NEW );
  if(error)
    return error;
  DBG_S_( oyPrintTime() );
  {
    int current = -1, choices = 0;
    const char ** choices_string_list = NULL;
    uint32_t flags = 0;
#ifdef HAVE_LOCALE_H
    char * old_loc = strdup(setlocale(LC_ALL,NULL));
    setlocale(LC_ALL,"C");
#endif
    error = oyOptionChoicesGet2( oyWIDGET_DISPLAY_WHITE_POINT, flags,
                                 oyNAME_NAME, &choices,
                                 &choices_string_list, &current );
    if(error > 0)
      oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                   "oyOptionChoicesGet2 failed %d", OY_DBG_ARGS_,
                   error);
#ifdef HAVE_LOCALE_H
    setlocale(LC_ALL,old_loc);
    if(old_loc) { free(old_loc); } old_loc = NULL;
#endif
    if(current > 0 && current < choices && choices_string_list)
    {
      if(current == 1) /* automatic */
      {
        double temperature = oyGetTemperature(-1);
        char k[12];
        sprintf(k, "%dK", (int)temperature);
        oyOptions_SetFromString( &opts, "//" OY_TYPE_STD "/illu_name", k, OY_CREATE_NEW );
        if(temperature <= 0.1)
          oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                   "automatic display_white_point: [%g %g %g] %s", OY_DBG_ARGS_,
                   dst_XYZ[0], dst_XYZ[1], dst_XYZ[2], k);
      }
      else
        oyOptions_SetFromString( &opts, "//" OY_TYPE_STD "/illu_name", choices_string_list[current], OY_CREATE_NEW );
      if(oy_debug)
        oyMessageFunc_p( oyMSG_DBG,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                   "illu_name: %s", OY_DBG_ARGS_,
                   oyOptions_FindString( opts, "illu_name", 0) );
    }
    oyOptionChoicesFree( oyWIDGET_DISPLAY_WHITE_POINT, &choices_string_list, choices );
  }

  if(oy_debug)
    oyMessageFunc_p( oyMSG_WARN, NULL, OY_DBG_FORMAT_
                   "src_name: %s -> illu_name: %s",
                   OY_DBG_ARGS_, oyOptions_FindString(opts, "src_name", 0), oyOptions_FindString(opts, "illu_name", 0) );
  oyOptions_SetFromDouble( &opts, "//" OY_TYPE_STD "/src_iccXYZ", src_XYZ[0], 0, OY_CREATE_NEW );
  oyOptions_SetFromDouble( &opts, "//" OY_TYPE_STD "/src_iccXYZ", src_XYZ[1], 1, OY_CREATE_NEW );
  oyOptions_SetFromDouble( &opts, "//" OY_TYPE_STD "/src_iccXYZ", src_XYZ[2], 2, OY_CREATE_NEW );
  oyOptions_SetFromDouble( &opts, "//" OY_TYPE_STD "/illu_iccXYZ", dst_XYZ[0], 0, OY_CREATE_NEW );
  oyOptions_SetFromDouble( &opts, "//" OY_TYPE_STD "/illu_iccXYZ", dst_XYZ[1], 1, OY_CREATE_NEW );
  oyOptions_SetFromDouble( &opts, "//" OY_TYPE_STD "/illu_iccXYZ", dst_XYZ[2], 2, OY_CREATE_NEW );
  /* cache the display white point abstract profile */
  error = oyOptions_Handle( "//" OY_TYPE_STD "/create_profile.white_point_adjust.bradford",
                            opts,             "create_profile.white_point_adjust.bradford.file_name",
                            &result_opts );
  DBG_S_( oyPrintTime() );
  if(error > 0)
    oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                   "oyOptions_Handle(white_point_adjust.bradford.file_name) failed %d", OY_DBG_ARGS_,
                   error);

  /* write cache profile for slightly better speed and useful for debugging */
  if(error == 0)
  {
    const char * file_name = oyOptions_FindString( result_opts, "file_name", 0 );
    char * cache_path = oyGetInstallPath( oyPATH_CACHE, oySCOPE_USER, oyAllocateFunc_ ), *t;
    if(strstr( cache_path, "device_link") != NULL)
    {
      t = strstr( cache_path, "device_link");
      t[0] = '\000';
      oyStringAddPrintf( &cache_path, 0,0, "white_point_adjust/%s.icc", file_name );
    }

    if(oyIsFile_(cache_path))
    {
      if(oy_debug)
        oyMessageFunc_p( oyMSG_DBG,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                     "found file_name: %s -> %s\n", OY_DBG_ARGS_, file_name, cache_path );
      wtpt = oyProfile_FromFile( cache_path, 0,0 );
      DBG_S_( oyPrintTime() );
    }
  }

  if(!error && wtpt)
  {
    oyOptions_MoveInStruct( module_options,
                          OY_STD "/icc_color/display.icc_profile.abstract.white_point.automatic.oy-monitor",
                          (oyStruct_s**) &wtpt, OY_CREATE_NEW );
    oyOptions_Release( &result_opts );
    oyOptions_Release( &opts );

    return error;
  }

  if(!error && !wtpt)
  {
    /* detect scaling factor
     * - convert monitor device RGB to XYZ,
     * - apply white point adaption matrix,
     * - convert back to monitor device RGB and
     * - again to XYZ to detect clipping and
     * - use that information for scaling inside the white point effect profile */
    oyProfile_s * xyz_profile = oyProfile_FromStd( oyASSUMED_XYZ, 0, 0 );
    float rgb[9] = {1,0,0, 0,1,0, 0,0,1},
          xyz[9] = {0,0,0, 0,0,0, 0,0,0};
    oyDATATYPE_e buf_type = oyFLOAT;
    oyConversion_s * cc_moni2xyz = oyConversion_CreateBasicPixelsFromBuffers(
                              monitor_profile, rgb, oyDataType_m(buf_type),
                              xyz_profile, xyz, oyDataType_m(buf_type),
                              0, 3 );
    oyConversion_s * cc_xyz2moni = oyConversion_CreateBasicPixelsFromBuffers(
                              xyz_profile, xyz, oyDataType_m(buf_type),
                              monitor_profile, rgb, oyDataType_m(buf_type),
                              0, 3 );
    oyMAT3 wtpt_adapt;
    oyCIEXYZ srcWtpt = {src_XYZ[0], src_XYZ[1], src_XYZ[2]},
             dstIllu = {dst_XYZ[0], dst_XYZ[1], dst_XYZ[2]};
    error = !oyAdaptationMatrix( &wtpt_adapt, NULL, &srcWtpt, &dstIllu );
    int i,j;
    for(j = 0; j < 100; ++j)
    {
      oyConversion_RunPixels( cc_moni2xyz, 0 );
      if(oy_debug)
        oyMessageFunc_p( oyMSG_DBG,(oyStruct_s*)cc_moni2xyz, OY_DBG_FORMAT_
                   "rgb->xyz:\nR[%g %g %g] G[%g %g %g] B[%g %g %g]",
                   OY_DBG_ARGS_, xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5], xyz[6], xyz[7], xyz[8]);
      oyVEC3 rXYZ, srcXYZ[3] = { {{xyz[0], xyz[1], xyz[2]}}, {{xyz[3], xyz[4], xyz[5]}}, {{xyz[6], xyz[7], xyz[8]}} };
      oyMAT3 wtpt_adapt_scaled,
             scale_mat = {{ {{scale,0,0}}, {{0,scale,0}}, {{0,0,scale}} }};
      oyMAT3per( &wtpt_adapt_scaled, &wtpt_adapt, &scale_mat );
      oyMAT3eval( &rXYZ, &wtpt_adapt_scaled, &srcXYZ[0] ); for(i = 0; i < 3; ++i) xyz[0+i] = rXYZ.n[i];
      oyMAT3eval( &rXYZ, &wtpt_adapt_scaled, &srcXYZ[1] ); for(i = 0; i < 3; ++i) xyz[3+i] = rXYZ.n[i];
      oyMAT3eval( &rXYZ, &wtpt_adapt_scaled, &srcXYZ[2] ); for(i = 0; i < 3; ++i) xyz[6+i] = rXYZ.n[i];
      if(oy_debug)
        oyMessageFunc_p( oyMSG_DBG,(oyStruct_s*)cc_moni2xyz, OY_DBG_FORMAT_
                   "srcWtpt->Illu:\nR[%g %g %g] G[%g %g %g] B[%g %g %g]", OY_DBG_ARGS_,
          xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5], xyz[6], xyz[7], xyz[8]);
      oyConversion_RunPixels( cc_xyz2moni, 0 );
      if(oy_debug)
        oyMessageFunc_p( oyMSG_WARN,(oyStruct_s*)cc_moni2xyz, OY_DBG_FORMAT_
                   "xyz->rgb:\nR[%g %g %g] G[%g %g %g] B[%g %g %g] %g",
                   OY_DBG_ARGS_, rgb[0], rgb[1], rgb[2], rgb[3], rgb[4], rgb[5], rgb[6], rgb[7], rgb[8], scale);
      if(rgb[0+0] < 0.99 && rgb[3+1] < 0.99 && rgb[6+2] < 0.99)
      {
        if(scale < 1.00) scale += 0.01;
        break;
      }
      scale -= 0.01;
    }
  }

  oyMessageFunc_p( /*error ?*/ oyMSG_WARN/*:oyMSG_DBG*/,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                   "%s display_white_point: %d [%g %g %g] -> [%g %g %g] * %g %d", OY_DBG_ARGS_,
          desc, display_white_point,
          src_XYZ[0], src_XYZ[1], src_XYZ[2], dst_XYZ[0], dst_XYZ[1], dst_XYZ[2], scale, error);
  if(error > 0)
    return error;

  /* write cache profile for slightly better speed and useful for debugging */
  if(error == 0)
  {
    const char * file_name = oyOptions_FindString( result_opts, "file_name", 0 );
    char * cache_path = oyGetInstallPath( oyPATH_CACHE, oySCOPE_USER, oyAllocateFunc_ ), *t;
    if(strstr( cache_path, "device_link") != NULL)
    {
      t = strstr( cache_path, "device_link");
      t[0] = '\000';
      oyStringAddPrintf( &cache_path, 0,0, "white_point_adjust/%s.icc", file_name );
    }

    {
      error = oyOptions_SetFromDouble( &opts, "//" OY_TYPE_STD "/scale", scale, 0, OY_CREATE_NEW );
      if(oy_debug)
        oyMessageFunc_p( oyMSG_DBG,(oyStruct_s*)monitor_profile, OY_DBG_FORMAT_
                     "creating file_name: %s -> %s\n", OY_DBG_ARGS_, file_name, cache_path );
      error = oyOptions_Handle( "//" OY_TYPE_STD "/create_profile.white_point_adjust.bradford",
                            opts,             "create_profile.white_point_adjust.bradford",
                            &result_opts );
      wtpt = (oyProfile_s*) oyOptions_GetType( result_opts, -1, "icc_profile",
                                           oyOBJECT_PROFILE_S );
      error = !wtpt;
      if(!error)
        oyProfile_ToFile_( (oyProfile_s_*) wtpt, cache_path );
      DBG_S_( oyPrintTime() );
    }
  }

  error = !wtpt;
  if(error == 0)
    oyOptions_MoveInStruct( module_options,
                          OY_STD "/icc_color/display.icc_profile.abstract.white_point.automatic.oy-monitor",
                          (oyStruct_s**) &wtpt, OY_CREATE_NEW );
  oyOptions_Release( &result_opts );
  oyOptions_Release( &opts );

  return error;
}
/** Function: oyNamedColor_SetColorStd
 *  @memberof oyNamedColor_s
 *  @brief   set color channels
 *
 *
 *  @param[in]     color               Oyranos color struct pointer
 *  @param[in]     color_space         Oyranos standard color space
 *  @param[in]     channels            pointer to channel data
 *  @param[in]     channels_type       data type
 *  @param[in]     flags               reserved for future use
 *  @param[in]     options             for filter node creation
 *  @return                            error
 *
 *  @since Oyranos: version 0.1.8
 *  @date  23 december 2007 (API 0.1.8)
 */
int               oyNamedColor_SetColorStd ( oyNamedColor_s * color,
                                       oyPROFILE_e         color_space,
                                       oyPointer           channels,
                                       oyDATATYPE_e        channels_type,
                                       uint32_t            flags,
                                       oyOptions_s       * options )
{
  oyNamedColor_s_ * s = (oyNamedColor_s_*) color;
  int error = !s || !color_space || !channels;
  oyProfile_s * p_in = 0;
  oyProfile_s * p_out = 0;

  /* abreviate */
  if(error <= 0 && channels_type == oyDOUBLE)
  {
    if     (color_space == oyEDITING_LAB)
    {
      oyLab2XYZ( (double*)channels, s->XYZ_ );
      return error;

    }
    else if(color_space == oyEDITING_XYZ)
    {
      oyCopyColor( (double*)channels, s->XYZ_, 1, 0, 0 );
      return error;
    }
  }

  if(error <= 0)
  {
    p_in = oyProfile_FromStd ( color_space, flags, NULL );
    error = !p_in;
  }

  /* reset and allocate */
  if(error <= 0)
  {
    int n = oyProfile_GetChannelsCount( p_in );

    oyDeAlloc_f deallocateFunc = s->oy_->deallocateFunc_;

    if(n > oyProfile_GetChannelsCount( s->profile_ ))
    {
      if(s->channels_)
        deallocateFunc(s->channels_); s->channels_ = 0;

      s->channels_ = s->oy_->allocateFunc_( n * sizeof(double) );
    }

    error = !memset( s->channels_, 0, sizeof(double) * n );

    s->XYZ_[0] = s->XYZ_[1] = s->XYZ_[2] = -1;

    if(deallocateFunc && s->blob_)
      deallocateFunc( s->blob_ ); s->blob_ = 0; s->blob_len_ = 0;
  }

  /* convert */
  if(error <= 0)
  {
    p_out = s->profile_;
    error = oyColorConvert_( p_in, p_out,
                              channels, s->channels_,
                              channels_type , oyDOUBLE, options, 1 );
    p_out = 0;
  }

  if(error <= 0)                               
  {  
    p_out = oyProfile_FromStd( oyEDITING_XYZ, flags, 0 );
    error = oyColorConvert_( p_in, p_out,
                              channels, s->XYZ_,
                              channels_type , oyDOUBLE, options, 1 );
    oyProfile_Release ( &p_out );
  }

  return error;
}
예제 #7
0
void ColorContext::setupColorLookupTable(bool advanced)
{
    kDebug() << m_outputName;

    oyProfile_s *dummyProfile = 0;
    oyOptions_s *options = 0;

    if (!m_dstProfile)
        m_dstProfile = dummyProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0);

    /* skip dummyProfile to dummyProfile conversion */
    if (!m_srcProfile && dummyProfile) {
        if (dummyProfile)
            oyProfile_Release(&dummyProfile);
        return;
    }

    if (!m_srcProfile) {
        m_srcProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0);
        if (!m_srcProfile) {
            kError() << "Output" << m_outputName << ":" << "no assumed dummyProfile source profile";
            kWarning() << "Output" << m_outputName << "using dummy clut";
            buildDummyClut(m_clut);
            return;
        }
    }

    int error = 0;
    int flags = 0;

    // Optionally set advanced options from Oyranos
    if (advanced)
        flags = oyOPTIONATTRIBUTE_ADVANCED;

    // Allocate memory for clut data
    m_clut.resize(CLUT_ELEMENT_COUNT);

    kDebug() << "Color conversion for" << m_outputName << "flags" << flags << (advanced ? "advanced" : "");
    oyImage_s *imageIn = oyImage_Create(
        LUT_GRID_POINTS,
        LUT_GRID_POINTS * LUT_GRID_POINTS,
        m_clut.data(),
        OY_TYPE_123_16,
        m_srcProfile,
        0);
    oyImage_s *imageOut = oyImage_Create(
        LUT_GRID_POINTS,
        LUT_GRID_POINTS * LUT_GRID_POINTS,
        m_clut.data(),
        OY_TYPE_123_16,
        m_dstProfile,
        0);

    oyConversion_s *conversion = oyConversion_CreateBasicPixels(imageIn, imageOut, options, 0);
    if (!conversion) {
        kWarning() << "No conversion created for" << m_outputName;
        if (dummyProfile)
            oyProfile_Release(&dummyProfile);
        return;
    }
    oyOptions_Release(&options);

    error = oyOptions_SetFromText(&options, "//"OY_TYPE_STD"/config/display_mode", "1", OY_CREATE_NEW);
    if (error) {
        kWarning() << "Oy options error:" << error;
        if (dummyProfile)
            oyProfile_Release(&dummyProfile);
        return;
    }
    error = oyConversion_Correct(conversion, "//"OY_TYPE_STD"/icc", flags, options);
    if (error) {
        kWarning() << "Failed to correct conversion for" << m_outputName << "flags" << flags;
        if (dummyProfile)
            oyProfile_Release(&dummyProfile);
        return;
    }

    oyFilterGraph_s *conversionGraph = oyConversion_GetGraph(conversion);
    oyFilterNode_s *iccNode = oyFilterGraph_GetNode(conversionGraph, -1, "///icc", 0);

    // See what to search for in the cache
    QByteArray entryText;
    const char *t = oyFilterNode_GetText(iccNode, oyNAME_NAME);
    if (t)
        entryText = t;

    oyStructList_s *cache = Display::getInstance()->cache();
    oyHash_s *entry = oyStructList_GetHash(cache, 0, entryText.constData());
    oyArray2d_s *oyClut = (oyArray2d_s*) oyHash_GetPointer(entry, oyOBJECT_ARRAY2D_S);
    char ** array2d = (char**)oyArray2d_GetData( oyClut );

    oyFilterNode_Release(&iccNode);
    oyFilterGraph_Release(&conversionGraph);

    if (oyClut) {
        // Found in cache
        kDebug() << "clut" << oyClut << "obtained from cache using entry" << entryText;
        memcpy(m_clut.data(), array2d[0], CLUT_DATA_SIZE);
    } else {
        kDebug() << "clut not found in cache using entry" << entryText << ", doing conversion";

        // Create dummy / identity clut data for conversion input
        buildDummyClut(m_clut);

        // Do conversion
        error = oyConversion_RunPixels(conversion, 0);
        if (error) {
            kWarning() << "Output" << m_outputName << "Error" << error << "in conversion run pixels";
            if (dummyProfile)
                oyProfile_Release(&dummyProfile);
            return;
        }

        // Save to cache
        oyClut = oyArray2d_Create(
            NULL,
            LUT_GRID_POINTS * 3,
            LUT_GRID_POINTS * LUT_GRID_POINTS,
            oyUINT16,
            NULL);
        array2d = (char**)oyArray2d_GetData( oyClut );
        memcpy(array2d[0], m_clut.data(), CLUT_DATA_SIZE);
        oyHash_SetPointer(entry, (oyStruct_s*) oyClut);
    }

    oyOptions_Release(&options);
    oyImage_Release(&imageIn);
    oyImage_Release(&imageOut);
    oyConversion_Release(&conversion);

    if (!m_dstProfile)
        kDebug() << "Output" << m_outputName << "no profile";
}