Commit fb059616 authored by Cyrille Berger's avatar Cyrille Berger

finish the KoColorTransformation refactoring with the KoColorConversionTransformation

svn path=/trunk/koffice/; revision=714814
parent 42d263d0
......@@ -14,6 +14,7 @@ set(pigment_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/KoColorSpaceRegistry.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorSpace.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoLcmsColorSpace.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorSpaceMaths.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoCompositeOp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorProfile.cpp
......
......@@ -22,19 +22,14 @@
#include "KoColorSpace.h"
struct KoColorConversionTransformation::Private {
KoColorSpace* srcColorSpace;
KoColorSpace* dstColorSpace;
const KoColorSpace* srcColorSpace;
const KoColorSpace* dstColorSpace;
Intent renderingIntent;
};
KoColorConversionTransformation::KoColorConversionTransformation(KoColorSpace* srcCs, KoColorSpace* dstCs, Intent renderingIntent) : d(new Private)
KoColorConversionTransformation::KoColorConversionTransformation(const KoColorSpace* srcCs, const KoColorSpace* dstCs, Intent renderingIntent) : d(new Private)
{
d->srcColorSpace = srcCs;
setParameters(dstCs, renderingIntent);
}
void KoColorConversionTransformation::setParameters(KoColorSpace* dstCs, Intent renderingIntent)
{
d->dstColorSpace = dstCs;
d->renderingIntent = renderingIntent;
}
......@@ -55,7 +50,7 @@ KoColorConversionTransformation::Intent KoColorConversionTransformation::renderi
}
void KoColorConversionTransformation::transform(const quint8 *src, quint8 *dst, qint32 nPixels) const
{
{
// 4 channels: labA, 2 bytes per lab channel
quint8 *pixels = new quint8[sizeof(quint16)*4*nPixels];
srcColorSpace()->toLabA16(src, pixels,nPixels);
......@@ -63,5 +58,3 @@ void KoColorConversionTransformation::transform(const quint8 *src, quint8 *dst,
delete [] pixels;
}
......@@ -22,12 +22,14 @@
#include "KoColorTransformation.h"
#include <pigment_export.h>
class KoColorSpace;
/**
* This is the base class of all color transform that convert the color of a pixel
*/
class KoColorConversionTransformation : KoColorTransformation{
class PIGMENT_EXPORT KoColorConversionTransformation : KoColorTransformation{
struct Private;
public:
enum Intent {
......@@ -37,9 +39,8 @@ class KoColorConversionTransformation : KoColorTransformation{
IntentAbsoluteColorimetric =3
};
public:
KoColorConversionTransformation(KoColorSpace* srcCs, KoColorSpace* cs, Intent renderingIntent = IntentPerceptual);
KoColorConversionTransformation(const KoColorSpace* srcCs, const KoColorSpace* dstCs, Intent renderingIntent = IntentPerceptual);
public:
virtual void setParameters(KoColorSpace* dstCs, Intent renderingIntent);
const KoColorSpace* srcColorSpace() const;
const KoColorSpace* dstColorSpace() const;
Intent renderingIntent();
......
......@@ -152,6 +152,11 @@ void KoColorSpace::addCompositeOp(const KoCompositeOp * op)
}
}
KoColorConversionTransformation* KoColorSpace::createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent) const
{
return new KoColorConversionTransformation(this, dstColorSpace, renderingIntent);
}
bool KoColorSpace::convertPixelsTo(const quint8 * src,
quint8 * dst,
const KoColorSpace * dstColorSpace,
......@@ -160,16 +165,12 @@ bool KoColorSpace::convertPixelsTo(const quint8 * src,
{
Q_UNUSED(renderingIntent);
if (*this == *dstColorSpace) {
memmove(dst, src, numPixels*pixelSize());
} else {
// 4 channels: labA, 2 bytes per lab channel
quint8 *pixels = new quint8[sizeof(quint16)*4*numPixels];
toLabA16(src, pixels,numPixels);
dstColorSpace->fromLabA16(pixels, dst,numPixels);
delete [] pixels;
}
if (*this == *dstColorSpace) {
memmove(dst, src, numPixels*pixelSize());
} else {
KoColorConversionTransformation* transfo =new KoColorConversionTransformation(this, dstColorSpace, renderingIntent);
transfo->transform(src, dst, numPixels);
}
return true;
}
......
......@@ -400,11 +400,20 @@ public:
*/
virtual void fromRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const =0;
/**
* Create a color conversion transformation.
*/
virtual KoColorConversionTransformation* createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::IntentPerceptual) const;
/**
* Convert a byte array of srcLen pixels *src to the specified color space
* and put the converted bytes into the prepared byte array *dst.
*
* Returns false if the conversion failed, true if it succeeded
*
* This function is not thread-safe. If you want to apply multiple conversion
* in different threads at the same time, you need to create one color converter
* per-thread using createColorConverter.
*/
virtual bool convertPixelsTo(const quint8 * src,
quint8 * dst, const KoColorSpace * dstColorSpace,
......
/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2005-2006 Casper Boemann <cbr@boemann.dk>
* Copyright (c) 2004,2006-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 <KoLcmsColorSpace.h>
cmsHTRANSFORM KoLcmsColorConversionTransformation::createTransform(
KoLcmsColorProfile * srcProfile,
KoLcmsColorProfile * dstProfile,
qint32 renderingIntent) const
{
KConfigGroup cfg = KGlobal::config()->group("");
bool bpCompensation = cfg.readEntry("useBlackPointCompensation", false);
int flags = 0;
if (bpCompensation) {
flags = cmsFLAGS_BLACKPOINTCOMPENSATION;
}
Q_ASSERT(dynamic_cast<const KoLcmsInfo*>(srcColorSpace()));
Q_ASSERT(dynamic_cast<const KoLcmsInfo*>(dstColorSpace()));
cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->lcmsProfile(),
dynamic_cast<const KoLcmsInfo*>(srcColorSpace())->colorSpaceType(),
dstProfile->lcmsProfile(),
dynamic_cast<const KoLcmsInfo*>(dstColorSpace())->colorSpaceType(),
renderingIntent,
flags);
return tf;
}
......@@ -29,6 +29,8 @@
#include <KoColorSpaceAbstract.h>
#include <KoColorSpaceRegistry.h>
#include <pigment_export.h>
struct KoLcmsColorTransformation : public KoColorTransformation
{
KoLcmsColorTransformation() : KoColorTransformation()
......@@ -96,6 +98,45 @@ struct KoLcmsDarkenTransformation : public KoColorTransformation
double m_compensation;
};
class PIGMENT_EXPORT KoLcmsColorConversionTransformation : public KoColorConversionTransformation {
public:
KoLcmsColorConversionTransformation(const KoColorSpace* srcCs, KoLcmsColorProfile* srcProfile, const KoColorSpace* dstCs, KoLcmsColorProfile* dstProfile, Intent renderingIntent = IntentPerceptual) : KoColorConversionTransformation(srcCs, dstCs, renderingIntent), m_transform(0)
{
m_transform = this->createTransform(
srcProfile,
dstProfile,
renderingIntent);
}
public:
virtual void transform(const quint8 *src, quint8 *dst, qint32 numPixels) const
{
Q_ASSERT(m_transform);
qint32 srcPixelSize = srcColorSpace()->pixelSize();
qint32 dstPixelSize = dstColorSpace()->pixelSize();
cmsDoTransform(m_transform, const_cast<quint8 *>(src), dst, numPixels);
// Lcms does nothing to the destination alpha channel so we must convert that manually.
while (numPixels > 0) {
quint8 alpha = srcColorSpace()->alpha(src);
dstColorSpace()->setAlpha(dst, alpha, 1);
src += srcPixelSize;
dst += dstPixelSize;
numPixels--;
}
}
private:
cmsHTRANSFORM createTransform(
KoLcmsColorProfile * srcProfile,
KoLcmsColorProfile * dstProfile,
qint32 renderingIntent) const;
private:
mutable cmsHTRANSFORM m_transform;
};
class KoLcmsInfo {
struct Private {
DWORD cmType; // The colorspace type as defined by littlecms
......@@ -145,10 +186,10 @@ class KoLcmsColorSpace : public KoColorSpaceAbstract<_CSTraits>, public KoLcmsIn
KoLcmsColorProfile * profile;
mutable const KoColorSpace *lastUsedDstColorSpace;
mutable cmsHTRANSFORM lastUsedTransform;
mutable KoColorConversionTransformation* lastUsedTransform;
// cmsHTRANSFORM is a void *, so this should work.
typedef QMap<const KoColorSpace *, cmsHTRANSFORM> TransformMap;
typedef QMap<const KoColorSpace *, KoColorConversionTransformation*> TransformMap;
mutable TransformMap transforms; // Cache for existing transforms
};
protected:
......@@ -347,6 +388,17 @@ class KoLcmsColorSpace : public KoColorSpaceAbstract<_CSTraits>, public KoLcmsIn
}
}
virtual KoColorConversionTransformation* createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::IntentPerceptual) const
{
KoLcmsColorProfile* dstprofile = toLcmsProfile(dstColorSpace->profile());
if(d->profile and dstprofile and dynamic_cast<const KoLcmsInfo*>(dstColorSpace))
{
return new KoLcmsColorConversionTransformation(this, d->profile, dstColorSpace, dstprofile, renderingIntent);
} else {
return KoColorSpaceAbstract<_CSTraits>::createColorConverter(dstColorSpace, renderingIntent);
}
}
virtual bool convertPixelsTo(const quint8 * src,
quint8 * dst,
const KoColorSpace * dstColorSpace,
......@@ -362,10 +414,7 @@ class KoLcmsColorSpace : public KoColorSpaceAbstract<_CSTraits>, public KoLcmsIn
return true;
}
cmsHTRANSFORM tf = 0;
qint32 srcPixelSize = this->pixelSize();
qint32 dstPixelSize = dstColorSpace->pixelSize();
KoColorConversionTransformation* tf = 0;
if (d->lastUsedTransform != 0 && d->lastUsedDstColorSpace != 0) {
if (dstColorSpace->id() == d->lastUsedDstColorSpace->id() &&
......@@ -373,49 +422,23 @@ class KoLcmsColorSpace : public KoColorSpaceAbstract<_CSTraits>, public KoLcmsIn
tf = d->lastUsedTransform;
}
}
KoLcmsColorProfile* dstprofile = toLcmsProfile(dstColorSpace->profile());
if (!tf && d->profile && dstprofile) {
if (not tf) {
if (!d->transforms.contains(dstColorSpace)) {
tf = this->createTransform(dstColorSpace,
d->profile,
dstprofile,
renderingIntent);
if (tf) {
// XXX: Should we clear the transform cache if it gets too big?
d->transforms[dstColorSpace] = tf;
}
tf = this->createColorConverter(dstColorSpace, renderingIntent);
d->transforms[dstColorSpace] = tf;
}
else {
tf = d->transforms[dstColorSpace];
}
if ( tf ) {
d->lastUsedTransform = tf;
d->lastUsedDstColorSpace = dstColorSpace;
}
}
if (tf) {
cmsDoTransform(tf, const_cast<quint8 *>(src), dst, numPixels);
// Lcms does nothing to the destination alpha channel so we must convert that manually.
while (numPixels > 0) {
quint8 alpha = this->alpha(src);
dstColorSpace->setAlpha(dst, alpha, 1);
src += srcPixelSize;
dst += dstPixelSize;
numPixels--;
}
return true;
d->lastUsedTransform = tf;
d->lastUsedDstColorSpace = dstColorSpace;
}
tf->transform(src, dst, numPixels);
// Last resort fallback. This happens when either src or dst isn't a lcms colorspace.
return KoColorSpace::convertPixelsTo(src, dst, dstColorSpace, numPixels, renderingIntent);
}
virtual KoColorTransformation *createBrightnessContrastAdjustment(const quint16 *transferValues) const
......@@ -606,36 +629,6 @@ class KoLcmsColorSpace : public KoColorSpaceAbstract<_CSTraits>, public KoLcmsIn
return true;
}
cmsHTRANSFORM createTransform(const KoColorSpace * dstColorSpace,
KoColorProfile * srcKoProfile,
KoColorProfile * dstKoProfile,
qint32 renderingIntent) const
{
KConfigGroup cfg = KGlobal::config()->group("");
bool bpCompensation = cfg.readEntry("useBlackPointCompensation", false);
int flags = 0;
if (bpCompensation) {
flags = cmsFLAGS_BLACKPOINTCOMPENSATION;
}
const KoLcmsInfo* dstColorSpaceInfo = dynamic_cast<const KoLcmsInfo*>(dstColorSpace);
KoLcmsColorProfile * srcProfile = dynamic_cast<KoLcmsColorProfile *>(srcKoProfile);
KoLcmsColorProfile * dstProfile = dynamic_cast<KoLcmsColorProfile *>(dstKoProfile);
if (dstColorSpaceInfo && dstProfile && srcProfile ) {
cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->lcmsProfile(),
this->colorSpaceType(),
dstProfile->lcmsProfile(),
dstColorSpaceInfo->colorSpaceType(),
renderingIntent,
flags);
return tf;
}
return 0;
}
Private * const d;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment