Warning, file /office/calligra/libs/pigment/KoColorConversionSystem.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * Copyright (c) 2007-2008 Cyrille Berger <cberger@cberger.net> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KoColorConversionSystem.h" 0021 #include "KoColorConversionSystem_p.h" 0022 0023 #include <QHash> 0024 #include <QString> 0025 0026 #include "KoColorConversionAlphaTransformation.h" 0027 #include "KoColorConversionTransformation.h" 0028 #include "KoColorProfile.h" 0029 #include "KoColorSpace.h" 0030 #include "KoCopyColorConversionTransformation.h" 0031 #include "KoMultipleColorConversionTransformation.h" 0032 0033 0034 KoColorConversionSystem::KoColorConversionSystem() : d(new Private) 0035 { 0036 // Create the Alpha 8bit 0037 d->alphaNode = new Node; 0038 d->alphaNode->modelId = AlphaColorModelID.id(); 0039 d->alphaNode->depthId = Integer8BitsColorDepthID.id(); 0040 d->alphaNode->crossingCost = 1000000; 0041 d->alphaNode->isInitialized = true; 0042 d->alphaNode->isGray = true; // <- FIXME: it's a little bit hacky as alpha doesn't really have color information 0043 d->graph.insert(NodeKey(d->alphaNode->modelId, d->alphaNode->depthId, "default"), d->alphaNode); 0044 0045 Vertex* v = createVertex(d->alphaNode, d->alphaNode); 0046 v->setFactoryFromSrc(new KoCopyColorConversionTransformationFactory(AlphaColorModelID.id(), Integer8BitsColorDepthID.id(), "default")); 0047 } 0048 0049 KoColorConversionSystem::~KoColorConversionSystem() 0050 { 0051 qDeleteAll(d->graph); 0052 qDeleteAll(d->vertexes); 0053 delete d; 0054 } 0055 0056 void KoColorConversionSystem::connectToEngine(Node* _node, Node* _engine) 0057 { 0058 Vertex* v1 = createVertex(_node, _engine); 0059 Vertex* v2 = createVertex(_engine, _node); 0060 v1->conserveColorInformation = !_node->isGray; 0061 v2->conserveColorInformation = !_node->isGray; 0062 v1->conserveDynamicRange = _engine->isHdr; 0063 v2->conserveDynamicRange = _engine->isHdr; 0064 } 0065 0066 KoColorConversionSystem::Node* KoColorConversionSystem::insertEngine(const KoColorSpaceEngine* engine) 0067 { 0068 NodeKey key(engine->id(), engine->id(), engine->id()); 0069 Node* n = new Node; 0070 n->modelId = engine->id(); 0071 n->depthId = engine->id(); 0072 n->profileName = engine->id(); 0073 n->referenceDepth = 64; // engine don't have reference depth, 0074 d->graph.insert(key, n); 0075 n->init(engine); 0076 return n; 0077 } 0078 0079 0080 void KoColorConversionSystem::insertColorSpace(const KoColorSpaceFactory* csf) 0081 { 0082 dbgPigment << "Inserting color space " << csf->name() << " (" << csf->id() << ") Model: " << csf->colorModelId() << " Depth: " << csf->colorDepthId() << " into the CCS"; 0083 const QList<const KoColorProfile*> profiles = KoColorSpaceRegistry::instance()->profilesFor(csf); 0084 QString modelId = csf->colorModelId().id(); 0085 QString depthId = csf->colorDepthId().id(); 0086 if (profiles.isEmpty()) { // There is no profile for this CS, create a node without profile name if the color engine isn't icc-based 0087 if (csf->colorSpaceEngine() != "icc") { 0088 Node* n = nodeFor(modelId, depthId, "default"); 0089 n->init(csf); 0090 } 0091 else { 0092 dbgPigment << "Cannot add node for " << csf->name() << ", since there are no profiles available"; 0093 } 0094 } else { 0095 // Initialise the nodes 0096 foreach(const KoColorProfile* profile, profiles) { 0097 Node* n = nodeFor(modelId, depthId, profile->name()); 0098 n->init(csf); 0099 if (!csf->colorSpaceEngine().isEmpty()) { 0100 KoColorSpaceEngine* engine = KoColorSpaceEngineRegistry::instance()->get(csf->colorSpaceEngine()); 0101 Q_ASSERT(engine); 0102 NodeKey engineKey(engine->id(), engine->id(), engine->id()); 0103 Node* engineNode = 0; 0104 QHash<NodeKey, Node*>::ConstIterator it = d->graph.constFind(engineKey); 0105 if (it != d->graph.constEnd()) { 0106 engineNode = it.value(); 0107 } else { 0108 engineNode = insertEngine(engine); 0109 } 0110 connectToEngine(n, engineNode); 0111 } 0112 } 0113 } 0114 // Construct a link for "custom" transformation 0115 const QList<KoColorConversionTransformationFactory*> cctfs = csf->colorConversionLinks(); 0116 foreach(KoColorConversionTransformationFactory* cctf, cctfs) { 0117 Node* srcNode = nodeFor(cctf->srcColorModelId(), cctf->srcColorDepthId(), cctf->srcProfile()); 0118 Q_ASSERT(srcNode); 0119 Node* dstNode = nodeFor(cctf->dstColorModelId(), cctf->dstColorDepthId(), cctf->dstProfile()); 0120 Q_ASSERT(dstNode); 0121 // Check if the two nodes are already connected 0122 Vertex* v = vertexBetween(srcNode, dstNode); 0123 // If the vertex doesn't already exist, then create it 0124 if (!v) { 0125 v = createVertex(srcNode, dstNode); 0126 } 0127 Q_ASSERT(v); // we should have one now 0128 if (dstNode->modelId == modelId && dstNode->depthId == depthId) { 0129 v->setFactoryFromDst(cctf); 0130 } 0131 if (srcNode->modelId == modelId && srcNode->depthId == depthId) { 0132 v->setFactoryFromSrc(cctf); 0133 } 0134 } 0135 } 0136 0137 void KoColorConversionSystem::insertColorProfile(const KoColorProfile* _profile) 0138 { 0139 dbgPigmentCCS << _profile->name(); 0140 const QList< const KoColorSpaceFactory* >& factories = KoColorSpaceRegistry::instance()->colorSpacesFor(_profile); 0141 foreach(const KoColorSpaceFactory* factory, factories) { 0142 QString modelId = factory->colorModelId().id(); 0143 QString depthId = factory->colorDepthId().id(); 0144 Node* n = nodeFor(modelId, depthId, _profile->name()); 0145 n->init(factory); 0146 if (!factory->colorSpaceEngine().isEmpty()) { 0147 KoColorSpaceEngine* engine = KoColorSpaceEngineRegistry::instance()->get(factory->colorSpaceEngine()); 0148 Q_ASSERT(engine); 0149 Node* engineNode = d->graph[ NodeKey(engine->id(), engine->id(), engine->id())]; 0150 Q_ASSERT(engineNode); 0151 connectToEngine(n, engineNode); 0152 } 0153 const QList<KoColorConversionTransformationFactory*> cctfs = factory->colorConversionLinks(); 0154 foreach(KoColorConversionTransformationFactory* cctf, cctfs) { 0155 Node* srcNode = nodeFor(cctf->srcColorModelId(), cctf->srcColorDepthId(), cctf->srcProfile()); 0156 Q_ASSERT(srcNode); 0157 Node* dstNode = nodeFor(cctf->dstColorModelId(), cctf->dstColorDepthId(), cctf->dstProfile()); 0158 Q_ASSERT(dstNode); 0159 if (srcNode == n || dstNode == n) { 0160 // Check if the two nodes are already connected 0161 Vertex* v = vertexBetween(srcNode, dstNode); 0162 // If the vertex doesn't already exist, then create it 0163 if (!v) { 0164 v = createVertex(srcNode, dstNode); 0165 } 0166 Q_ASSERT(v); // we should have one now 0167 if (dstNode->modelId == modelId && dstNode->depthId == depthId) { 0168 v->setFactoryFromDst(cctf); 0169 } 0170 if (srcNode->modelId == modelId && srcNode->depthId == depthId) { 0171 v->setFactoryFromSrc(cctf); 0172 } 0173 } 0174 } 0175 } 0176 } 0177 0178 const KoColorSpace* KoColorConversionSystem::defaultColorSpaceForNode(const Node* node) const 0179 { 0180 return KoColorSpaceRegistry::instance()->colorSpace(node->modelId, node->depthId, node->profileName); 0181 } 0182 0183 KoColorConversionSystem::Node* KoColorConversionSystem::createNode(const QString& _modelId, const QString& _depthId, const QString& _profileName) 0184 { 0185 Node* n = new Node; 0186 n->modelId = _modelId; 0187 n->depthId = _depthId; 0188 n->profileName = _profileName; 0189 d->graph.insert(NodeKey(_modelId, _depthId, _profileName), n); 0190 Q_ASSERT(vertexBetween(d->alphaNode, n) == 0); // The two color spaces should not be connected yet 0191 Vertex* vFromAlpha = createVertex(d->alphaNode, n); 0192 vFromAlpha->setFactoryFromSrc(new KoColorConversionFromAlphaTransformationFactory(_modelId, _depthId, _profileName)); 0193 Q_ASSERT(vertexBetween(n, d->alphaNode) == 0); // The two color spaces should not be connected yet 0194 Vertex* vToAlpha = createVertex(n, d->alphaNode); 0195 vToAlpha->setFactoryFromDst(new KoColorConversionToAlphaTransformationFactory(_modelId, _depthId, _profileName)); 0196 return n; 0197 } 0198 0199 const KoColorConversionSystem::Node* KoColorConversionSystem::nodeFor(const KoColorSpace* _colorSpace) const 0200 { 0201 const KoColorProfile* profile = _colorSpace->profile(); 0202 return nodeFor(_colorSpace->colorModelId().id(), _colorSpace->colorDepthId().id(), 0203 profile ? profile->name() : "default"); 0204 } 0205 0206 const KoColorConversionSystem::Node* KoColorConversionSystem::nodeFor(const QString& _colorModelId, const QString& _colorDepthId, const QString& _profileName) const 0207 { 0208 //dbgPigmentCCS << "Look for node: " << _colorModelId << " " << _colorDepthId << " " << _profileName; 0209 return nodeFor(NodeKey(_colorModelId, _colorDepthId, _profileName)); 0210 } 0211 0212 const KoColorConversionSystem::Node* KoColorConversionSystem::nodeFor(const NodeKey& key) const 0213 { 0214 //dbgPigmentCCS << "Look for node: " << key.modelId << " " << key.depthId << " " << key.profileName << " " << d->graph.value(key); 0215 return d->graph.value(key); 0216 } 0217 0218 KoColorConversionSystem::Node* KoColorConversionSystem::nodeFor(const QString& _colorModelId, const QString& _colorDepthId, const QString& _profileName) 0219 { 0220 return nodeFor(NodeKey(_colorModelId, _colorDepthId, _profileName)); 0221 } 0222 0223 KoColorConversionSystem::Node* KoColorConversionSystem::nodeFor(const KoColorConversionSystem::NodeKey& key) 0224 { 0225 QHash<NodeKey, Node*>::ConstIterator it = d->graph.constFind(key); 0226 if (it != d->graph.constEnd()) { 0227 return it.value(); 0228 } else { 0229 return createNode(key.modelId, key.depthId, key.profileName); 0230 } 0231 } 0232 0233 QList<KoColorConversionSystem::Node*> KoColorConversionSystem::nodesFor(const QString& _modelId, const QString& _depthId) 0234 { 0235 QList<Node*> nodes; 0236 foreach(Node* node, d->graph) { 0237 if (node->modelId == _modelId && node->depthId == _depthId) { 0238 nodes << node; 0239 } 0240 } 0241 return nodes; 0242 } 0243 0244 KoColorConversionTransformation* KoColorConversionSystem::createColorConverter(const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const 0245 { 0246 if (*srcColorSpace == *dstColorSpace) { 0247 return new KoCopyColorConversionTransformation(srcColorSpace); 0248 } 0249 Q_ASSERT(srcColorSpace); 0250 Q_ASSERT(dstColorSpace); 0251 dbgPigmentCCS << srcColorSpace->id() << (srcColorSpace->profile() ? srcColorSpace->profile()->name() : "default"); 0252 dbgPigmentCCS << dstColorSpace->id() << (dstColorSpace->profile() ? dstColorSpace->profile()->name() : "default"); 0253 Path path = findBestPath( 0254 nodeFor(srcColorSpace), 0255 nodeFor(dstColorSpace)); 0256 Q_ASSERT(path.length() > 0); 0257 KoColorConversionTransformation* transfo = createTransformationFromPath(path, srcColorSpace, dstColorSpace, renderingIntent, conversionFlags); 0258 Q_ASSERT(*transfo->srcColorSpace() == *srcColorSpace); 0259 Q_ASSERT(*transfo->dstColorSpace() == *dstColorSpace); 0260 Q_ASSERT(transfo); 0261 return transfo; 0262 } 0263 0264 void KoColorConversionSystem::createColorConverters(const KoColorSpace* colorSpace, const QList< QPair<KoID, KoID> >& possibilities, KoColorConversionTransformation*& fromCS, KoColorConversionTransformation*& toCS) const 0265 { 0266 // TODO This function currently only select the best conversion only based on the transformation 0267 // from colorSpace to one of the color spaces in the list, but not the other way around 0268 // it might be worth to look also the return path. 0269 const Node* csNode = nodeFor(colorSpace); 0270 PathQualityChecker pQC(csNode->referenceDepth, !csNode->isHdr, !csNode->isGray); 0271 // Look for a color conversion 0272 Path bestPath; 0273 typedef QPair<KoID, KoID> KoID2KoID; 0274 foreach(const KoID2KoID & possibility, possibilities) { 0275 const KoColorSpaceFactory* csf = KoColorSpaceRegistry::instance()->colorSpaceFactory(KoColorSpaceRegistry::instance()->colorSpaceId(possibility.first.id(), possibility.second.id())); 0276 if (csf) { 0277 Path path = findBestPath(csNode, nodeFor(csf->colorModelId().id(), csf->colorDepthId().id(), csf->defaultProfile())); 0278 Q_ASSERT(path.length() > 0); 0279 path.isGood = pQC.isGoodPath(path); 0280 0281 if (bestPath.isEmpty()) { 0282 bestPath = path; 0283 } else if ((!bestPath.isGood && path.isGood) || pQC.lessWorseThan(path, bestPath)) { 0284 bestPath = path; 0285 } 0286 } 0287 } 0288 Q_ASSERT(!bestPath.isEmpty()); 0289 const KoColorSpace* endColorSpace = defaultColorSpaceForNode(bestPath.endNode()); 0290 fromCS = createTransformationFromPath(bestPath, colorSpace, endColorSpace, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); 0291 Path returnPath = findBestPath(bestPath.endNode(), csNode); 0292 Q_ASSERT(!returnPath.isEmpty()); 0293 toCS = createTransformationFromPath(returnPath, endColorSpace, colorSpace, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); 0294 Q_ASSERT(*toCS->dstColorSpace() == *fromCS->srcColorSpace()); 0295 Q_ASSERT(*fromCS->dstColorSpace() == *toCS->srcColorSpace()); 0296 } 0297 0298 KoColorConversionTransformation* KoColorConversionSystem::createTransformationFromPath(const Path &path, const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const 0299 { 0300 Q_ASSERT(srcColorSpace->colorModelId().id() == path.startNode()->modelId); 0301 Q_ASSERT(srcColorSpace->colorDepthId().id() == path.startNode()->depthId); 0302 Q_ASSERT(dstColorSpace->colorModelId().id() == path.endNode()->modelId); 0303 Q_ASSERT(dstColorSpace->colorDepthId().id() == path.endNode()->depthId); 0304 0305 KoColorConversionTransformation* transfo; 0306 0307 const QList< Path::node2factory > pathOfNode = path.compressedPath(); 0308 0309 if (pathOfNode.size() == 2) { // Direct connection 0310 transfo = pathOfNode[1].second->createColorTransformation(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags); 0311 } 0312 else { 0313 0314 KoMultipleColorConversionTransformation* mccTransfo = new KoMultipleColorConversionTransformation(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags); 0315 0316 transfo = mccTransfo; 0317 0318 // Get the first intermediary color space 0319 dbgPigmentCCS << pathOfNode[ 0 ].first->id() << " to " << pathOfNode[ 1 ].first->id(); 0320 0321 const KoColorSpace* intermCS = 0322 defaultColorSpaceForNode(pathOfNode[1].first); 0323 0324 mccTransfo->appendTransfo(pathOfNode[1].second->createColorTransformation(srcColorSpace, intermCS, renderingIntent, conversionFlags)); 0325 0326 for (int i = 2; i < pathOfNode.size() - 1; i++) { 0327 dbgPigmentCCS << pathOfNode[ i - 1 ].first->id() << " to " << pathOfNode[ i ].first->id(); 0328 const KoColorSpace* intermCS2 = defaultColorSpaceForNode(pathOfNode[i].first); 0329 Q_ASSERT(intermCS2); 0330 mccTransfo->appendTransfo(pathOfNode[i].second->createColorTransformation(intermCS, intermCS2, renderingIntent, conversionFlags)); 0331 intermCS = intermCS2; 0332 } 0333 0334 dbgPigmentCCS << pathOfNode[ pathOfNode.size() - 2 ].first->id() << " to " << pathOfNode[ pathOfNode.size() - 1 ].first->id(); 0335 mccTransfo->appendTransfo(pathOfNode.last().second->createColorTransformation(intermCS, dstColorSpace, renderingIntent, conversionFlags)); 0336 } 0337 return transfo; 0338 } 0339 0340 0341 KoColorConversionSystem::Vertex* KoColorConversionSystem::vertexBetween(KoColorConversionSystem::Node* srcNode, KoColorConversionSystem::Node* dstNode) 0342 { 0343 foreach(Vertex* oV, srcNode->outputVertexes) { 0344 if (oV->dstNode == dstNode) { 0345 return oV; 0346 } 0347 } 0348 return 0; 0349 } 0350 0351 KoColorConversionSystem::Vertex* KoColorConversionSystem::createVertex(Node* srcNode, Node* dstNode) 0352 { 0353 Vertex* v = new Vertex(srcNode, dstNode); 0354 srcNode->outputVertexes.append(v); 0355 d->vertexes.append(v); 0356 return v; 0357 } 0358 0359 // -- Graph visualization functions -- 0360 0361 QString KoColorConversionSystem::vertexToDot(KoColorConversionSystem::Vertex* v, const QString &options) const 0362 { 0363 return QString(" \"%1\" -> \"%2\" %3\n").arg(v->srcNode->id(), v->dstNode->id(), options); 0364 } 0365 0366 QString KoColorConversionSystem::toDot() const 0367 { 0368 QString dot = "digraph CCS {\n"; 0369 foreach(Vertex* oV, d->vertexes) { 0370 dot += vertexToDot(oV, "default") ; 0371 } 0372 dot += "}\n"; 0373 return dot; 0374 } 0375 0376 bool KoColorConversionSystem::existsPath(const QString& srcModelId, const QString& srcDepthId, const QString& srcProfileName, const QString& dstModelId, const QString& dstDepthId, const QString& dstProfileName) const 0377 { 0378 //dbgPigmentCCS << "srcModelId = " << srcModelId << " srcDepthId = " << srcDepthId << " srcProfileName = " << srcProfileName << " dstModelId = " << dstModelId << " dstDepthId = " << dstDepthId << " dstProfileName = " << dstProfileName; 0379 const Node* srcNode = nodeFor(srcModelId, srcDepthId, srcProfileName); 0380 const Node* dstNode = nodeFor(dstModelId, dstDepthId, dstProfileName); 0381 if (srcNode == dstNode) return true; 0382 if (!srcNode) return false; 0383 if (!dstNode) return false; 0384 Path path = findBestPath(srcNode, dstNode); 0385 bool exist = !path.isEmpty(); 0386 return exist; 0387 } 0388 0389 bool KoColorConversionSystem::existsGoodPath(const QString& srcModelId, const QString& srcDepthId, const QString& srcProfileName, const QString& dstModelId, const QString& dstDepthId, const QString& dstProfileName) const 0390 { 0391 const Node* srcNode = nodeFor(srcModelId, srcDepthId, srcProfileName); 0392 const Node* dstNode = nodeFor(dstModelId, dstDepthId, dstProfileName); 0393 if (srcNode == dstNode) return true; 0394 if (!srcNode) return false; 0395 if (!dstNode) return false; 0396 Path path = findBestPath(srcNode, dstNode); 0397 bool existAndGood = path.isGood; 0398 return existAndGood; 0399 } 0400 0401 0402 QString KoColorConversionSystem::bestPathToDot(const QString& srcKey, const QString& dstKey) const 0403 { 0404 const Node* srcNode = 0; 0405 const Node* dstNode = 0; 0406 foreach(Node* node, d->graph) { 0407 if (node->id() == srcKey) { 0408 srcNode = node; 0409 } 0410 if (node->id() == dstKey) { 0411 dstNode = node; 0412 } 0413 } 0414 Path p = findBestPath(srcNode, dstNode); 0415 Q_ASSERT(!p.isEmpty()); 0416 QString dot = "digraph CCS {\n" + 0417 QString(" \"%1\" [color=red]\n").arg(srcNode->id()) + 0418 QString(" \"%1\" [color=red]\n").arg(dstNode->id()); 0419 foreach(Vertex* oV, d->vertexes) { 0420 QString options; 0421 if (p.vertexes.contains(oV)) { 0422 options = "[color=red]"; 0423 } 0424 dot += vertexToDot(oV, options) ; 0425 } 0426 dot += "}\n"; 0427 return dot; 0428 } 0429 0430 inline KoColorConversionSystem::Path KoColorConversionSystem::findBestPathImpl2(const KoColorConversionSystem::Node* srcNode, const KoColorConversionSystem::Node* dstNode, bool ignoreHdr, bool ignoreColorCorrectness) const 0431 { 0432 PathQualityChecker pQC(qMin(srcNode->referenceDepth, dstNode->referenceDepth), ignoreHdr, ignoreColorCorrectness); 0433 Node2PathHash node2path; // current best path to reach a given node 0434 QList<Path> possiblePaths; // list of all paths 0435 // Generate the initial list of paths 0436 foreach(Vertex* v, srcNode->outputVertexes) { 0437 if (v->dstNode->isInitialized) { 0438 Path p; 0439 p.appendVertex(v); 0440 Node* endNode = v->dstNode; 0441 if (endNode == dstNode) { 0442 Q_ASSERT(pQC.isGoodPath(p)); // <- it's a direct link, it has to be a good path 0443 p.isGood = true; 0444 return p; 0445 } else { 0446 Q_ASSERT(!node2path.contains(endNode)); // That would be a total fuck up if there are two vertexes between two nodes 0447 node2path.insert(endNode, p); 0448 possiblePaths.append(p); 0449 } 0450 } 0451 } 0452 0453 Path currentBestPath; 0454 // Continue while there are any possibilities remaining 0455 while (possiblePaths.size() > 0) { 0456 0457 // Loop through all paths and explore one step further 0458 const QList<Path> currentPaths = possiblePaths; 0459 for (const Path &p : currentPaths) { 0460 const Node* endNode = p.endNode(); 0461 for (Vertex* v : endNode->outputVertexes) { 0462 if (v->dstNode->isInitialized && !p.contains(v->dstNode)) { 0463 Path newP = p; // Candidate 0464 newP.appendVertex(v); 0465 Node* newEndNode = v->dstNode; 0466 if (newEndNode == dstNode) { 0467 if (pQC.isGoodPath(newP)) { // Victory 0468 newP.isGood = true; 0469 return newP; 0470 } else if (pQC.lessWorseThan(newP, currentBestPath)) { 0471 Q_ASSERT(newP.startNode()->id() == currentBestPath.startNode()->id()); 0472 Q_ASSERT(newP.endNode()->id() == currentBestPath.endNode()->id()); 0473 // Can we do better than dumping memory values??? 0474 // warnPigment << pQC.lessWorseThan(newP, currentBestPath) << " " << newP << " " << currentBestPath; 0475 currentBestPath = newP; 0476 } 0477 } else { 0478 // This is an incomplete path. Check if there's a better way to get to its endpoint. 0479 Node2PathHash::Iterator it = node2path.find(newEndNode); 0480 if (it != node2path.end()) { 0481 Path &p2 = it.value(); 0482 if (pQC.lessWorseThan(newP, p2)) { 0483 p2 = newP; 0484 possiblePaths.append(newP); 0485 } 0486 } else { 0487 node2path.insert(newEndNode, newP); 0488 possiblePaths.append(newP); 0489 } 0490 } 0491 } 0492 } 0493 possiblePaths.removeAll(p); // Remove from list of remaining paths 0494 } 0495 } 0496 if (!currentBestPath.isEmpty()) { 0497 warnPigment << "No good path from " << srcNode->id() << " to " << dstNode->id() << " found : length = " << currentBestPath.length() << " cost = " << currentBestPath.cost << " referenceDepth = " << currentBestPath.referenceDepth << " respectColorCorrectness = " << currentBestPath.respectColorCorrectness << " isGood = " << currentBestPath.isGood ; 0498 return currentBestPath; 0499 } 0500 errorPigment << "No path from " << srcNode->id() << " to " << dstNode->id() << " found not "; 0501 return currentBestPath; 0502 } 0503 0504 inline KoColorConversionSystem::Path KoColorConversionSystem::findBestPathImpl(const KoColorConversionSystem::Node* srcNode, const KoColorConversionSystem::Node* dstNode, bool ignoreHdr) const 0505 { 0506 Q_ASSERT(srcNode); 0507 Q_ASSERT(dstNode); 0508 return findBestPathImpl2(srcNode, dstNode, ignoreHdr, (srcNode->isGray || dstNode->isGray)); 0509 } 0510 0511 KoColorConversionSystem::Path KoColorConversionSystem::findBestPath(const KoColorConversionSystem::Node* srcNode, const KoColorConversionSystem::Node* dstNode) const 0512 { 0513 Q_ASSERT(srcNode); 0514 Q_ASSERT(dstNode); 0515 //dbgPigmentCCS << "Find best path between " << srcNode->id() << " and " << dstNode->id(); 0516 if (srcNode->isHdr && dstNode->isHdr) { 0517 return findBestPathImpl(srcNode, dstNode, false); 0518 } else { 0519 return findBestPathImpl(srcNode, dstNode, true); 0520 } 0521 }