Commit 659f9c41 authored by Cyrille Berger's avatar Cyrille Berger

* add the possibility to extend colors spaces with new KoColorTransformation...

* add the possibility to extend colors spaces with new KoColorTransformation (first 2.1 todo finished :/), as those color transformation aren't necesseraly available use the CCS to create a fallback transformation

svn path=/trunk/koffice/; revision=734963
parent e57e0d49
......@@ -30,6 +30,8 @@ set(pigmentcms_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/KoColorSpace.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorSpaceMaths.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorSpaceRegistry.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorTransformationFactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorTransformationFactoryRegistry.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoCompositeOp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoCopyColorConversionTransformation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoFallBackColorTransformation.cpp
......
This diff is collapsed.
......@@ -22,9 +22,11 @@
class KoColorSpace;
class KoColorSpaceFactory;
class KoID;
#include "KoColorConversionTransformation.h"
#include <QList>
#include <QPair>
#include <pigment_export.h>
......@@ -59,6 +61,25 @@ class PIGMENTCMS_EXPORT KoColorConversionSystem {
* the best possible path between the two color space.
*/
KoColorConversionTransformation* createColorConverter(const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::IntentPerceptual) const;
/**
* This function creates two transformations, one from the color space and one to the
* color space. The destination color space is picked from a list of color space, such
* as the conversion between the two color space is of the best quality.
*
* The typical use case of this function is for KoColorTransformationFactory which
* doesn't support all color spaces, so unsupported color space have to find an
* acceptable conversion in order to use that KoColorTransformationFactory.
*
* @param colorSpace the source color space
* @param possibilities a list of color space among which we need to find the best
* conversion
* @param fromCS the conversion from the source color space will be affected to this
* variable
* @param toCS the revert conversion to the source color space will be affected to this
* variable
*/
void createColorConverters(const KoColorSpace* colorSpace, QList< QPair<KoID, KoID> >& possibilities, KoColorConversionTransformation*& fromCS, KoColorConversionTransformation*& toCS) const;
public:
/**
* This function return a text that can be compiled using dot to display
......@@ -83,6 +104,7 @@ class PIGMENTCMS_EXPORT KoColorConversionSystem {
private:
QString vertexToDot(Vertex* v, QString options) const;
private:
KoColorConversionTransformation* createTransformationFromPath(const Path* path, const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::IntentPerceptual) const;
/**
* Query the registry to get the color space associated with this
* node. (default profile)
......@@ -118,14 +140,12 @@ class PIGMENTCMS_EXPORT KoColorConversionSystem {
* Don't call that function, but raher findBestPath
* @internal
*/
template<bool ignoreHdr, bool ignoreColorCorrectness>
inline Path* findBestPathImpl2(const Node* srcNode, const Node* dstNode) const;
inline Path* findBestPathImpl2(const Node* srcNode, const Node* dstNode, bool ignoreHdr, bool ignoreColorCorrectness) const;
/**
* Don't call that function, but raher findBestPath
* @internal
*/
template<bool ignoreHdr>
inline Path* findBestPathImpl(const Node* srcNode, const Node* dstNode) const;
inline Path* findBestPathImpl(const Node* srcNode, const Node* dstNode, bool ignoreHdr) const;
private:
struct Private;
Private* const d;
......
/*
* Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
class KoMultipleColorConversionTransformation : public KoColorConversionTransformation {
public:
KoMultipleColorConversionTransformation(const KoColorSpace* srcCs, const KoColorSpace* dstCs, Intent renderingIntent = IntentPerceptual) : KoColorConversionTransformation(srcCs, dstCs, renderingIntent), m_maxPixelSize(qMax(srcCs->pixelSize(), dstCs->pixelSize()))
{
}
~KoMultipleColorConversionTransformation()
{
foreach(KoColorConversionTransformation* transfo, m_transfos)
{
delete transfo;
}
}
void appendTransfo(KoColorConversionTransformation* transfo)
{
m_transfos.append( transfo );
m_maxPixelSize = qMax(m_maxPixelSize, transfo->srcColorSpace()->pixelSize());
m_maxPixelSize = qMax(m_maxPixelSize, transfo->dstColorSpace()->pixelSize());
}
virtual void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const
{
Q_ASSERT(m_transfos.size() > 1); // Be sure to have a more than one transformation
quint8 *buff1 = new quint8[m_maxPixelSize*nPixels];
quint8 *buff2 = 0;
if(m_transfos.size() > 2)
{
buff2 = new quint8[m_maxPixelSize*nPixels]; // a second buffer is needed
}
m_transfos.first()->transform( src, buff1, nPixels);
int lastIndex = m_transfos.size() - 2;
for( int i = 1; i <= lastIndex; i++)
{
m_transfos[i]->transform( buff1, buff2, nPixels);
quint8* tmp = buff1;
buff1 = buff2;
buff2 = tmp;
}
m_transfos.last()->transform( buff1, dst, nPixels);
delete buff2;
delete buff1;
}
private:
QList<KoColorConversionTransformation*> m_transfos;
quint32 m_maxPixelSize;
};
struct KoColorConversionSystem::Node {
Node() : isIcc(false), isHdr(false), isInitialized(false), referenceDepth(0), isGray(false), canBeCrossed(true), colorSpaceFactory(0) {}
void init( const KoColorSpaceFactory* _colorSpaceFactory)
{
Q_ASSERT(not isInitialized);
isInitialized = true;
if(_colorSpaceFactory)
{
isIcc = _colorSpaceFactory->isIcc();
isHdr = _colorSpaceFactory->isHdr();
colorSpaceFactory = _colorSpaceFactory;
referenceDepth = _colorSpaceFactory->referenceDepth();
isGray = ( _colorSpaceFactory->colorModelId() == GrayAColorModelID
or _colorSpaceFactory->colorModelId() == GrayColorModelID );
}
}
QString id() const {
return modelId + " " + depthId;
}
QString modelId;
QString depthId;
bool isIcc;
bool isHdr;
bool isInitialized;
int referenceDepth;
QList<Vertex*> outputVertexes;
bool isGray;
bool canBeCrossed; ///< indicates wether this node can be use in the middle of a path
const KoColorSpaceFactory* colorSpaceFactory;
};
struct KoColorConversionSystem::Vertex {
Vertex(Node* _srcNode, Node* _dstNode) : srcNode(_srcNode), dstNode(_dstNode), factoryFromSrc(0), factoryFromDst(0)
{
}
~Vertex()
{
delete factoryFromSrc;
delete factoryFromDst;
}
void setFactoryFromSrc(KoColorConversionTransformationFactory* factory)
{
factoryFromSrc = factory;
initParameter(factoryFromSrc);
}
void setFactoryFromDst(KoColorConversionTransformationFactory* factory)
{
factoryFromDst = factory;
if( not factoryFromSrc) initParameter(factoryFromDst);
}
void initParameter(KoColorConversionTransformationFactory* transfo)
{
conserveColorInformation = transfo->conserveColorInformation();
conserveDynamicRange = transfo->conserveDynamicRange();
}
KoColorConversionTransformationFactory* factory()
{
if(factoryFromSrc) return factoryFromSrc;
return factoryFromDst;
}
Node* srcNode;
Node* dstNode;
bool conserveColorInformation;
bool conserveDynamicRange;
private:
KoColorConversionTransformationFactory* factoryFromSrc; // Factory provided by the destination node
KoColorConversionTransformationFactory* factoryFromDst; // Factory provided by the destination node
};
struct KoColorConversionSystem::NodeKey {
NodeKey(QString _modelId, QString _depthId) : modelId(_modelId), depthId(_depthId)
{}
bool operator==(const KoColorConversionSystem::NodeKey& rhs) const
{
return modelId == rhs.modelId && depthId == rhs.depthId;
}
QString modelId;
QString depthId;
};
struct KoColorConversionSystem::Path {
Path() : respectColorCorrectness(true), referenceDepth(0), keepDynamicRange(true), isGood(false)
{}
Node* startNode() {
return (vertexes.first())->srcNode;
}
const Node* startNode() const {
return (vertexes.first())->srcNode;
}
Node* endNode() {
return (vertexes.last())->dstNode;
}
const Node* endNode() const {
return (vertexes.last())->dstNode;
}
void appendVertex(Vertex* v) {
if(vertexes.empty())
{
referenceDepth = v->srcNode->referenceDepth;
}
vertexes.append(v);
if(not v->conserveColorInformation) respectColorCorrectness = false;
if(not v->conserveDynamicRange) keepDynamicRange = false;
referenceDepth = qMin( referenceDepth, v->dstNode->referenceDepth);
}
int length() const {
return vertexes.size();
}
bool contains(Node* n) const
{
foreach(Vertex* v, vertexes)
{
if(v->srcNode == n or v->dstNode == n)
{
return true;
}
}
return false;
}
QList<Vertex*> vertexes;
bool respectColorCorrectness;
int referenceDepth;
bool keepDynamicRange;
bool isGood;
};
class Node2PathHash : public QHash<KoColorConversionSystem::Node*, KoColorConversionSystem::Path*>
{
public:
~Node2PathHash() { qDeleteAll(*this); }
};
uint qHash(const KoColorConversionSystem::NodeKey &key)
{
return qHash(key.modelId) + qHash(key.depthId);
}
struct KoColorConversionSystem::Private {
QHash<NodeKey, Node*> graph;
QList<Vertex*> vertexes;
Node* alphaNode;
};
#define CHECK_ONE_AND_NOT_THE_OTHER(name) \
if(path1-> name and not path2-> name) \
{ \
return true; \
} \
if(not path1-> name and path2-> name) \
{ \
return false; \
}
struct PathQualityChecker {
PathQualityChecker(int _referenceDepth, bool _ignoreHdr, bool _ignoreColorCorrectness) : referenceDepth(_referenceDepth), ignoreHdr(_ignoreHdr), ignoreColorCorrectness(_ignoreColorCorrectness) {}
/// @return true if the path maximize all the criterions (except lenght)
inline bool isGoodPath(KoColorConversionSystem::Path* path)
{
return ( path->respectColorCorrectness or ignoreColorCorrectness ) and
( path->referenceDepth >= referenceDepth) and
( path->keepDynamicRange or ignoreHdr );
}
/**
* Compare two pathes.
*/
inline bool lessWorseThan(KoColorConversionSystem::Path* path1, KoColorConversionSystem::Path* path2)
{
// There is no point in comparing two pathes which doesn't start from the same node or doesn't end at the same node
Q_ASSERT(path1->startNode() == path2->startNode());
Q_ASSERT(path1->endNode() == path2->endNode());
if(not ignoreHdr)
{
CHECK_ONE_AND_NOT_THE_OTHER(keepDynamicRange)
}
if(not ignoreColorCorrectness)
{
CHECK_ONE_AND_NOT_THE_OTHER(respectColorCorrectness)
}
if( path1->referenceDepth == path2->referenceDepth)
{
return path1->length() < path2->length(); // if they have the same length, well anyway you have to choose one, and there is no point in keeping one and not the other
}
return path1->referenceDepth > path2->referenceDepth;
}
int referenceDepth;
bool ignoreHdr;
bool ignoreColorCorrectness;
};
#undef CHECK_ONE_AND_NOT_THE_OTHER
......@@ -26,9 +26,12 @@
#include "KoCompositeOp.h"
#include "KoColorTransformation.h"
#include "KoColorTransformationFactory.h"
#include "KoColorTransformationFactoryRegistry.h"
#include "KoColorConversionSystem.h"
#include "KoColorSpaceRegistry.h"
#include "KoCopyColorConversionTransformation.h"
#include "KoFallBackColorTransformation.h"
struct KoColorSpace::Private {
QString id;
......@@ -436,3 +439,24 @@ QVector<quint8> * KoColorSpace::threadLocalConversionCache(quint32 size) const
}
return ba;
}
KoColorTransformation* KoColorSpace::createColorTransformation( QString id, QHash<QString, QVariant> parameters) const
{
KoColorTransformationFactory* factory = KoColorTransformationFactoryRegistry::instance()->get( id );
if(not factory) return 0;
QPair<KoID, KoID> model( colorModelId(), colorDepthId() );
QList< QPair<KoID, KoID> > models = factory->supportedModels();
if(models.contains(model))
{
return factory->createTransformation( this, parameters);
} else {
// Find the best solution
KoColorConversionTransformation* csToFallBack = 0;
KoColorConversionTransformation* fallBackToCs = 0;
KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverters(this, models, csToFallBack, fallBackToCs);
Q_ASSERT(csToFallBack);
Q_ASSERT(fallBackToCs);
KoColorTransformation* transfo = factory->createTransformation(fallBackToCs->srcColorSpace(), parameters);
return new KoFallBackColorTransformation( csToFallBack, fallBackToCs, transfo);
}
}
......@@ -629,6 +629,8 @@ public:
*/
virtual QList<KisFilter*> createBackgroundFilters() const
{ return QList<KisFilter*>(); }
KoColorTransformation* createColorTransformation( QString id, QHash<QString, QVariant> parameters) const;
protected:
/**
* Use this function in the constructor of your colorspace to add the information about a channel.
......
......@@ -35,9 +35,9 @@ class KoColorSpaceFactory;
class KoColorProfile;
class KoColorConversionSystem;
// XXX: USE STATIC DELETER! USE STATIC DELETER!
/**
*
* XXX: USE STATIC DELETER! USE STATIC DELETER!
*
* The registry for colorspaces and profiles.
* This class contains:
......@@ -241,6 +241,7 @@ public:
* spaces to create color conversion transformation
*/
const KoColorConversionSystem* colorConversionSystem() const;
private:
KoColorSpaceRegistry();
KoColorSpaceRegistry(const KoColorSpaceRegistry&);
......@@ -253,4 +254,3 @@ private:
};
#endif // KOCOLORSPACEFACTORYREGISTRY_H
......@@ -25,6 +25,17 @@
/**
* This is the base class of all color transform that takes one pixel in input
* and one pixel in output.
*
* They are created by color spaces.
*
* For instance:
* @code
* KoColorSpace* cs = KoColorSpaceRegistry::rgb8();
* quint8 pixelsSrc[ nbpixels * cs->pixelSize() ];
* quint8 pixelsDst[ nbpixels * cs->pixelSize() ];
* KoColorTransformation* transfo = cs->createInvertTransformation();
* transfo->transform( pixelsSrc, pixelsDst, nbpixels );
* @endcode
*/
class KoColorTransformation {
public:
......
/*
* Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KoColorTransformationFactory.h"
struct KoColorTransformationFactory::Private {
QString id;
QString name;
};
KoColorTransformationFactory::KoColorTransformationFactory(QString id, QString name ) : d(new Private)
{
d->id = id;
d->name = name;
}
KoColorTransformationFactory::~KoColorTransformationFactory()
{
delete d;
}
QString KoColorTransformationFactory::id() const
{
return d->id;
}
QString KoColorTransformationFactory::name() const
{
return d->name;
}
/*
* Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _KO_COLOR_TRANSFORMATION_FACTORY_H_
#define _KO_COLOR_TRANSFORMATION_FACTORY_H_
#include <QList>
#include <QPair>
#include <QString>
class KoColorTransformation;
class KoColorSpace;
class KoID;
#include <pigment_export.h>
class PIGMENTCMS_EXPORT KoColorTransformationFactory {
public:
KoColorTransformationFactory(QString id, QString name);
virtual ~KoColorTransformationFactory();
public:
QString id() const;
QString name() const;
public:
virtual QList< QPair< KoID, KoID > > supportedModels() const = 0;
virtual KoColorTransformation* createTransformation(const KoColorSpace* colorSpace, QHash<QString, QVariant> parameters) const = 0;
private:
struct Private;
Private* const d;
};
#endif
/*
* Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KoColorTransformationFactoryRegistry.h"
struct KoColorTransformationFactoryRegistry::Private
{
static KoColorTransformationFactoryRegistry* s_registry;
};
KoColorTransformationFactoryRegistry* KoColorTransformationFactoryRegistry::Private::s_registry = 0;
KoColorTransformationFactoryRegistry::KoColorTransformationFactoryRegistry() : d(new Private)
{
}
KoColorTransformationFactoryRegistry::~KoColorTransformationFactoryRegistry()
{
delete d;
}
void KoColorTransformationFactoryRegistry::add(KoColorTransformationFactory* factory)
{
instance()->add(factory);
}
KoColorTransformationFactoryRegistry* KoColorTransformationFactoryRegistry::instance()
{
if(Private::s_registry == 0)
{
Private::s_registry = new KoColorTransformationFactoryRegistry();
}
return Private::s_registry;
}
/*
* Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _KO_COLOR_SPACE_REGISTRY_P_H_
#define _KO_COLOR_SPACE_REGISTRY_P_H_
#include <KoGenericRegistry.h>
#include <pigment_export.h>
class KoColorSpace;
class KoColorTransformationFactory;
/**
* This class list the available transformation. The only reason to use directly
* that class is for adding new factory use the static method
* KoColorTransformationFactoryRegistry::add.
*/
class PIGMENTCMS_EXPORT KoColorTransformationFactoryRegistry : private KoGenericRegistry<KoColorTransformationFactory*> {
friend class KoColorSpace;
public:
~KoColorTransformationFactoryRegistry();
/**
* Add a KoColorTransformationFactory to the registry.
*/
static void add(KoColorTransformationFactory* factory);
private:
static KoColorTransformationFactoryRegistry* instance();
private:
KoColorTransformationFactoryRegistry();
private:
struct Private;
Private* const d;
};
#endif
......@@ -32,12 +32,24 @@ struct KoFallBackColorTransformation::Private {
mutable qint32 buffSize;
};
KoFallBackColorTransformation::KoFallBackColorTransformation(const KoColorSpace* cs, const KoColorSpace* fallBackCS, KoColorTransformation* transfo) : d(new Private)
KoFallBackColorTransformation::KoFallBackColorTransformation(const KoColorSpace* _cs, const KoColorSpace* _fallBackCS, KoColorTransformation* _transfo) : d(new Private)
{
d->fallBackColorSpace = fallBackCS;