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