Warning, file /office/calligra/libs/pigment/KoColorConversionSystem_p.h 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 #ifndef KOCOLORCONVERSIONSYSTEM_P_H 0021 #define KOCOLORCONVERSIONSYSTEM_P_H 0022 0023 #include "DebugPigment.h" 0024 #include "KoColorSpaceRegistry.h" 0025 #include "KoColorModelStandardIds.h" 0026 #include "KoColorConversionTransformationFactory.h" 0027 #include "KoColorSpaceEngine.h" 0028 0029 #include <QList> 0030 0031 struct KoColorConversionSystem::Node { 0032 0033 Node() 0034 : isHdr(false) 0035 , isInitialized(false) 0036 , referenceDepth(0) 0037 , isGray(false) 0038 , crossingCost(1) 0039 , colorSpaceFactory(0) 0040 , isEngine(false) 0041 , engine(0) {} 0042 0043 void init(const KoColorSpaceFactory* _colorSpaceFactory) { 0044 dbgPigment << "Initialise " << modelId << " " << depthId << " " << profileName; 0045 0046 if (isInitialized) { 0047 dbgPigment << "Re-initializing node. Old factory" << colorSpaceFactory << "new factory" << _colorSpaceFactory; 0048 } 0049 isInitialized = true; 0050 0051 if (_colorSpaceFactory) { 0052 isHdr = _colorSpaceFactory->isHdr(); 0053 colorSpaceFactory = _colorSpaceFactory; 0054 referenceDepth = _colorSpaceFactory->referenceDepth(); 0055 isGray = (_colorSpaceFactory->colorModelId() == GrayAColorModelID 0056 || _colorSpaceFactory->colorModelId() == GrayColorModelID); 0057 } 0058 } 0059 0060 void init(const KoColorSpaceEngine* _engine) { 0061 Q_ASSERT(!isInitialized); 0062 isEngine = true; 0063 isInitialized = true; 0064 isHdr = true; 0065 engine = _engine; 0066 } 0067 0068 QString id() const { 0069 return modelId + " " + depthId + " " + profileName; 0070 } 0071 0072 QString modelId; 0073 QString depthId; 0074 QString profileName; 0075 bool isHdr; 0076 bool isInitialized; 0077 int referenceDepth; 0078 QList<Vertex*> outputVertexes; 0079 bool isGray; 0080 int crossingCost; 0081 const KoColorSpaceFactory* colorSpaceFactory; 0082 bool isEngine; 0083 const KoColorSpaceEngine* engine; 0084 }; 0085 Q_DECLARE_TYPEINFO(KoColorConversionSystem::Node, Q_MOVABLE_TYPE); 0086 0087 struct KoColorConversionSystem::Vertex { 0088 0089 Vertex(Node* _srcNode, Node* _dstNode) 0090 : srcNode(_srcNode) 0091 , dstNode(_dstNode) 0092 , factoryFromSrc(0) 0093 , factoryFromDst(0) { 0094 } 0095 0096 ~Vertex() { 0097 if (factoryFromSrc == factoryFromDst) { 0098 delete factoryFromSrc; 0099 } else { 0100 delete factoryFromSrc; 0101 delete factoryFromDst; 0102 } 0103 } 0104 0105 void setFactoryFromSrc(KoColorConversionTransformationFactory* factory) { 0106 factoryFromSrc = factory; 0107 initParameter(factoryFromSrc); 0108 } 0109 0110 void setFactoryFromDst(KoColorConversionTransformationFactory* factory) { 0111 factoryFromDst = factory; 0112 if (!factoryFromSrc) initParameter(factoryFromDst); 0113 } 0114 0115 void initParameter(KoColorConversionTransformationFactory* transfo) { 0116 conserveColorInformation = transfo->conserveColorInformation(); 0117 conserveDynamicRange = transfo->conserveDynamicRange(); 0118 } 0119 0120 KoColorConversionTransformationFactory* factory() { 0121 if (factoryFromSrc) return factoryFromSrc; 0122 return factoryFromDst; 0123 } 0124 0125 Node* srcNode; 0126 Node* dstNode; 0127 0128 bool conserveColorInformation; 0129 bool conserveDynamicRange; 0130 0131 private: 0132 0133 KoColorConversionTransformationFactory* factoryFromSrc; // Factory provided by the destination node 0134 KoColorConversionTransformationFactory* factoryFromDst; // Factory provided by the destination node 0135 0136 }; 0137 0138 struct KoColorConversionSystem::NodeKey { 0139 0140 NodeKey(const QString &_modelId, const QString &_depthId, const QString &_profileName) 0141 : modelId(_modelId) 0142 , depthId(_depthId) 0143 , profileName(_profileName) {} 0144 0145 bool operator==(const KoColorConversionSystem::NodeKey& rhs) const { 0146 return modelId == rhs.modelId && depthId == rhs.depthId && profileName == rhs.profileName; 0147 } 0148 0149 QString modelId; 0150 QString depthId; 0151 QString profileName; 0152 }; 0153 Q_DECLARE_TYPEINFO(KoColorConversionSystem::NodeKey, Q_MOVABLE_TYPE); 0154 0155 struct KoColorConversionSystem::Path { 0156 0157 Path() 0158 : respectColorCorrectness(true) 0159 , referenceDepth(0) 0160 , keepDynamicRange(true) 0161 , isGood(false) 0162 , cost(0) {} 0163 0164 Node* startNode() { 0165 return (vertexes.first())->srcNode; 0166 } 0167 0168 bool operator==(const Path &other) const { 0169 return other.vertexes == vertexes; 0170 } 0171 0172 0173 const Node* startNode() const { 0174 return (vertexes.first())->srcNode; 0175 } 0176 0177 Node* endNode() { 0178 return (vertexes.last())->dstNode; 0179 } 0180 0181 const Node* endNode() const { 0182 return (vertexes.last())->dstNode; 0183 } 0184 0185 bool isEmpty() const { 0186 return vertexes.isEmpty(); 0187 } 0188 0189 void appendVertex(Vertex* v) { 0190 if (vertexes.empty()) { 0191 referenceDepth = v->srcNode->referenceDepth; 0192 } 0193 vertexes.append(v); 0194 if (!v->conserveColorInformation) respectColorCorrectness = false; 0195 if (!v->conserveDynamicRange) keepDynamicRange = false; 0196 referenceDepth = qMin(referenceDepth, v->dstNode->referenceDepth); 0197 cost += v->dstNode->crossingCost; 0198 } 0199 0200 // Compress path to hide the Engine node and correctly select the factory 0201 typedef QPair<Node*, const KoColorConversionTransformationAbstractFactory* > node2factory; 0202 QList< node2factory > compressedPath() const { 0203 QList< node2factory > nodes; 0204 nodes.push_back(node2factory(vertexes.first()->srcNode , vertexes.first()->factory())); 0205 const KoColorConversionTransformationAbstractFactory* previousFactory = 0; 0206 foreach(Vertex* vertex, vertexes) { // Unless the node is the icc node, add it to the path 0207 Node* n = vertex->dstNode; 0208 if (n->isEngine) { 0209 previousFactory = n->engine; 0210 } else { 0211 nodes.push_back( 0212 node2factory(n, 0213 previousFactory ? previousFactory : vertex->factory())); 0214 previousFactory = 0; 0215 } 0216 } 0217 return nodes; 0218 } 0219 0220 int length() const { 0221 return vertexes.size(); 0222 } 0223 0224 bool contains(Node* n) const { 0225 foreach(Vertex* v, vertexes) { 0226 if (v->srcNode == n || v->dstNode == n) { 0227 return true; 0228 } 0229 } 0230 return false; 0231 } 0232 0233 QList<Vertex*> vertexes; 0234 bool respectColorCorrectness; 0235 int referenceDepth; 0236 bool keepDynamicRange; 0237 bool isGood; 0238 int cost; 0239 }; 0240 Q_DECLARE_TYPEINFO(KoColorConversionSystem::Path, Q_MOVABLE_TYPE); 0241 0242 typedef QHash<KoColorConversionSystem::Node*, KoColorConversionSystem::Path > Node2PathHash; 0243 0244 0245 uint qHash(const KoColorConversionSystem::NodeKey &key) 0246 { 0247 return qHash(key.modelId) + qHash(key.depthId); 0248 } 0249 0250 struct Q_DECL_HIDDEN KoColorConversionSystem::Private { 0251 0252 QHash<NodeKey, Node*> graph; 0253 QList<Vertex*> vertexes; 0254 Node* alphaNode; 0255 }; 0256 0257 #define CHECK_ONE_AND_NOT_THE_OTHER(name) \ 0258 if(path1. name && !path2. name) \ 0259 { \ 0260 return true; \ 0261 } \ 0262 if(!path1. name && path2. name) \ 0263 { \ 0264 return false; \ 0265 } 0266 0267 struct PathQualityChecker { 0268 0269 PathQualityChecker(int _referenceDepth, bool _ignoreHdr, bool _ignoreColorCorrectness) 0270 : referenceDepth(_referenceDepth) 0271 , ignoreHdr(_ignoreHdr) 0272 , ignoreColorCorrectness(_ignoreColorCorrectness) 0273 {} 0274 0275 /// @return true if the path maximize all the criteria (except length) 0276 inline bool isGoodPath(const KoColorConversionSystem::Path & path) const { 0277 0278 return (path.respectColorCorrectness || ignoreColorCorrectness) && 0279 (path.referenceDepth >= referenceDepth) && 0280 (path.keepDynamicRange || ignoreHdr); 0281 } 0282 0283 /** 0284 * Compare two paths. 0285 */ 0286 inline bool lessWorseThan(const KoColorConversionSystem::Path &path1, const KoColorConversionSystem::Path &path2) const { 0287 // There is no point in comparing two paths which doesn't start from the same node or doesn't end at the same node 0288 if (!ignoreHdr) { 0289 CHECK_ONE_AND_NOT_THE_OTHER(keepDynamicRange) 0290 } 0291 if (!ignoreColorCorrectness) { 0292 CHECK_ONE_AND_NOT_THE_OTHER(respectColorCorrectness) 0293 } 0294 if (path1.referenceDepth == path2.referenceDepth) { 0295 return path1.cost < path2.cost; // if they have the same cost, well anyway you have to choose one, and there is no point in keeping one and not the other 0296 } 0297 return path1.referenceDepth > path2.referenceDepth; 0298 } 0299 int referenceDepth; 0300 bool ignoreHdr; 0301 bool ignoreColorCorrectness; 0302 }; 0303 0304 #undef CHECK_ONE_AND_NOT_THE_OTHER 0305 0306 #endif