File indexing completed on 2024-04-14 04:16:23
0001 /******************************************************************** 0002 KolorServer - color server based on the X Color Management Specification 0003 This file is part of the KDE project. 0004 0005 Copyright (C) 2012 Casian Andrei <skeletk13@gmail.com> 0006 0007 Redistribution and use in source and binary forms, with or without 0008 modification, are permitted provided that the following conditions 0009 are met: 0010 0011 1. Redistributions of source code must retain the above copyright 0012 notice, this list of conditions and the following disclaimer. 0013 2. Redistributions in binary form must reproduce the above copyright 0014 notice, this list of conditions and the following disclaimer in the 0015 documentation and/or other materials provided with the distribution. 0016 0017 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0018 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0019 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0020 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0021 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0022 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0023 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0024 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0025 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0026 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0027 *********************************************************************/ 0028 0029 #include <KDebug> 0030 0031 #include "color-context.h" 0032 0033 #include "display.h" 0034 0035 #include <oyranos_devices.h> 0036 #include <oyConversion_s.h> 0037 0038 namespace KolorServer 0039 { 0040 0041 /* 0042 * Color Context 0043 */ 0044 0045 ColorContext::ColorContext() 0046 : m_srcProfile(NULL) 0047 , m_dstProfile(NULL) 0048 { 0049 buildDummyClut(m_clut); 0050 /* select profiles matching actual capabilities */ 0051 icc_profile_flags = oyICCProfileSelectionFlagsFromOptions( OY_CMM_STD, "//" OY_TYPE_STD "/icc_color", NULL, 0 ); 0052 } 0053 0054 ColorContext::~ColorContext() 0055 { 0056 // Release profiles 0057 if (m_srcProfile) 0058 oyProfile_Release(&m_srcProfile); 0059 if (m_dstProfile) 0060 oyProfile_Release(&m_dstProfile); 0061 } 0062 0063 oyProfile_s *ColorContext::sourceProfile() 0064 { 0065 return m_srcProfile; 0066 } 0067 0068 oyProfile_s *ColorContext::destinationProfile() 0069 { 0070 return m_dstProfile; 0071 } 0072 0073 void ColorContext::setDestinationProfile(oyProfile_s *profile) 0074 { 0075 oyProfile_Release(&m_dstProfile); 0076 m_dstProfile = profile; 0077 } 0078 0079 const QString& ColorContext::outputName() 0080 { 0081 return m_outputName; 0082 } 0083 0084 const Clut& ColorContext::colorLookupTable() const 0085 { 0086 return m_clut; 0087 } 0088 0089 void ColorContext::setupColorLookupTable(bool advanced) 0090 { 0091 kDebug() << m_outputName; 0092 0093 oyProfile_s *dummyProfile = 0; 0094 oyOptions_s *options = 0; 0095 0096 if (!m_dstProfile) 0097 m_dstProfile = dummyProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0); 0098 0099 /* skip dummyProfile to dummyProfile conversion */ 0100 if (!m_srcProfile && dummyProfile) { 0101 if (dummyProfile) 0102 oyProfile_Release(&dummyProfile); 0103 return; 0104 } 0105 0106 if (!m_srcProfile) { 0107 m_srcProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0); 0108 if (!m_srcProfile) { 0109 kError() << "Output" << m_outputName << ":" << "no assumed dummyProfile source profile"; 0110 kWarning() << "Output" << m_outputName << "using dummy clut"; 0111 buildDummyClut(m_clut); 0112 return; 0113 } 0114 } 0115 0116 int error = 0; 0117 int flags = 0; 0118 0119 // Optionally set advanced options from Oyranos 0120 if (advanced) 0121 flags = oyOPTIONATTRIBUTE_ADVANCED; 0122 0123 // Allocate memory for clut data 0124 m_clut.resize(CLUT_ELEMENT_COUNT); 0125 0126 kDebug() << "Color conversion for" << m_outputName << "flags" << flags << (advanced ? "advanced" : ""); 0127 oyImage_s *imageIn = oyImage_Create( 0128 LUT_GRID_POINTS, 0129 LUT_GRID_POINTS * LUT_GRID_POINTS, 0130 m_clut.data(), 0131 OY_TYPE_123_16, 0132 m_srcProfile, 0133 0); 0134 oyImage_s *imageOut = oyImage_Create( 0135 LUT_GRID_POINTS, 0136 LUT_GRID_POINTS * LUT_GRID_POINTS, 0137 m_clut.data(), 0138 OY_TYPE_123_16, 0139 m_dstProfile, 0140 0); 0141 0142 oyConversion_s *conversion = oyConversion_CreateBasicPixels(imageIn, imageOut, options, 0); 0143 if (!conversion) { 0144 kWarning() << "No conversion created for" << m_outputName; 0145 if (dummyProfile) 0146 oyProfile_Release(&dummyProfile); 0147 return; 0148 } 0149 oyOptions_Release(&options); 0150 0151 error = oyOptions_SetFromText(&options, "//"OY_TYPE_STD"/config/display_mode", "1", OY_CREATE_NEW); 0152 if (error) { 0153 kWarning() << "Oy options error:" << error; 0154 if (dummyProfile) 0155 oyProfile_Release(&dummyProfile); 0156 return; 0157 } 0158 error = oyConversion_Correct(conversion, "//"OY_TYPE_STD"/icc_color", flags, options); 0159 if (error > 0) { 0160 kWarning() << "Failed to correct conversion for" << m_outputName << "flags" << flags; 0161 if (dummyProfile) 0162 oyProfile_Release(&dummyProfile); 0163 return; 0164 } 0165 0166 oyFilterGraph_s *conversionGraph = oyConversion_GetGraph(conversion); 0167 oyFilterNode_s *iccNode = oyFilterGraph_GetNode(conversionGraph, -1, "///icc", 0); 0168 0169 // See what to search for in the cache 0170 QByteArray entryText; 0171 const char *t = oyFilterNode_GetText(iccNode, oyNAME_NAME); 0172 if (t) 0173 entryText = t; 0174 0175 oyStructList_s *cache = Display::getInstance()->cache(); 0176 oyHash_s *entry = oyStructList_GetHash(cache, 0, entryText.constData()); 0177 oyArray2d_s *oyClut = (oyArray2d_s*) oyHash_GetPointer(entry, oyOBJECT_ARRAY2D_S); 0178 char ** array2d = (char**)oyArray2d_GetData( oyClut ); 0179 0180 oyFilterNode_Release(&iccNode); 0181 oyFilterGraph_Release(&conversionGraph); 0182 0183 if (oyClut) { 0184 // Found in cache 0185 kDebug() << "clut" << oyClut << "obtained from cache using entry" << entryText; 0186 memcpy(m_clut.data(), array2d[0], CLUT_DATA_SIZE); 0187 } else { 0188 kDebug() << "clut not found in cache using entry" << entryText << ", doing conversion"; 0189 0190 // Create dummy / identity clut data for conversion input 0191 buildDummyClut(m_clut); 0192 0193 // Do conversion 0194 error = oyConversion_RunPixels(conversion, 0); 0195 if (error) { 0196 kWarning() << "Output" << m_outputName << "Error" << error << "in conversion run pixels"; 0197 if (dummyProfile) 0198 oyProfile_Release(&dummyProfile); 0199 return; 0200 } 0201 0202 // Save to cache 0203 oyClut = oyArray2d_Create( 0204 NULL, 0205 LUT_GRID_POINTS * 3, 0206 LUT_GRID_POINTS * LUT_GRID_POINTS, 0207 oyUINT16, 0208 NULL); 0209 array2d = (char**)oyArray2d_GetData( oyClut ); 0210 memcpy(array2d[0], m_clut.data(), CLUT_DATA_SIZE); 0211 oyHash_SetPointer(entry, (oyStruct_s*) oyClut); 0212 } 0213 0214 oyOptions_Release(&options); 0215 oyImage_Release(&imageIn); 0216 oyImage_Release(&imageOut); 0217 oyConversion_Release(&conversion); 0218 0219 if (!m_dstProfile) 0220 kDebug() << "Output" << m_outputName << "no profile"; 0221 } 0222 0223 void ColorContext::setup(const QString &name) 0224 { 0225 kDebug(); 0226 if (!Display::getInstance()->colorDesktopActivated()) 0227 return; 0228 0229 m_srcProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0); 0230 m_outputName = name; 0231 if (!m_srcProfile) 0232 kWarning() << "Output" << name << "no sRGB source profile"; 0233 0234 setupColorLookupTable(Display::getInstance()->isAdvancedIccDisplay()); 0235 } 0236 0237 bool ColorContext::getDeviceProfile(oyConfig_s *device) 0238 { 0239 kDebug() << device; 0240 0241 oyProfile_Release(&m_dstProfile); 0242 0243 oyOptions_s *options = 0; 0244 oyOptions_SetFromText(&options, "//"OY_TYPE_STD"/config/command", "list", OY_CREATE_NEW); 0245 oyOptions_SetFromText(&options, 0246 "//"OY_TYPE_STD"/config/icc_profile.x_color_region_target", 0247 "yes", OY_CREATE_NEW ); 0248 int error = oyDeviceGetProfile(device, options, &m_dstProfile); 0249 oyOptions_Release(&options); 0250 0251 if (m_dstProfile) { 0252 /* check that no sRGB is delivered */ 0253 if (error) { 0254 oyProfile_s *dummyProfile = oyProfile_FromStd(oyASSUMED_WEB, icc_profile_flags, 0); 0255 if (oyProfile_Equal(dummyProfile, m_dstProfile)) { 0256 kWarning() << "Output" << m_outputName << "ignoring fallback, error" << error; 0257 oyProfile_Release(&m_dstProfile); 0258 error = 1; 0259 } else 0260 error = 0; 0261 oyProfile_Release(&dummyProfile); 0262 } 0263 } else { 0264 kWarning() << "Output" << m_outputName << ": no ICC profile found, error" << error; 0265 error = 1; 0266 } 0267 0268 return error == 0; 0269 } 0270 0271 } // KolorServer namespace