Commit d3bd5375 authored by Wolthera van Hövell's avatar Wolthera van Hövell 🛍

Push work-in-progress proofing

parent bb97947a
......@@ -47,6 +47,7 @@ set(kritapigment_SRCS
KoColorConversions.cpp
KoColorConversionSystem.cpp
KoColorConversionTransformation.cpp
KoColorProofingConversionTransformation.cpp
KoColorConversionTransformationFactory.cpp
KoColorModelStandardIds.cpp
KoColorProfile.cpp
......
......@@ -25,6 +25,7 @@
#include "KoColorConversionAlphaTransformation.h"
#include "KoColorConversionTransformation.h"
#include "KoColorProofingConversionTransformation.h"
#include "KoColorProfile.h"
#include "KoColorSpace.h"
#include "KoCopyColorConversionTransformation.h"
......@@ -261,6 +262,28 @@ KoColorConversionTransformation* KoColorConversionSystem::createColorConverter(c
return transfo;
}
KoColorProofingConversionTransformation* KoColorConversionSystem::createColorProofingConverter(const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, const KoColorSpace *proofingSpace, KoColorProofingConversionTransformation::Intent renderingIntent, KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const
{
/*if (*srcColorSpace == *dstColorSpace && *srcColorSpace == *proofingSpace) {
return new KoCopyColorConversionTransformation(srcColorSpace);
}*/
Q_ASSERT(srcColorSpace);
Q_ASSERT(dstColorSpace);
dbgPigmentCCS << srcColorSpace->id() << (srcColorSpace->profile() ? srcColorSpace->profile()->name() : "default");
dbgPigmentCCS << dstColorSpace->id() << (dstColorSpace->profile() ? dstColorSpace->profile()->name() : "default");
Path path = findBestPath(
nodeFor(srcColorSpace),
nodeFor(dstColorSpace));
Q_ASSERT(path.length() > 0);
const QList< Path::node2factory > pathOfNode = path.compressedPath();
//Let's hack our way around tis for now.
KoColorProofingConversionTransformation* transfo = pathOfNode[0].second->createColorProofingTransformation(srcColorSpace, dstColorSpace, proofingSpace, renderingIntent, conversionFlags);
Q_ASSERT(*transfo->srcColorSpace() == *srcColorSpace);
Q_ASSERT(*transfo->dstColorSpace() == *dstColorSpace);
Q_ASSERT(transfo);
return transfo;
}
void KoColorConversionSystem::createColorConverters(const KoColorSpace* colorSpace, const QList< QPair<KoID, KoID> >& possibilities, KoColorConversionTransformation*& fromCS, KoColorConversionTransformation*& toCS) const
{
// TODO This function currently only select the best conversion only based on the transformation
......
......@@ -27,6 +27,7 @@ class KoColorSpaceEngine;
class KoID;
#include "KoColorConversionTransformation.h"
#include "KoColorProofingConversionTransformation.h"
#include <QList>
#include <QPair>
......@@ -69,6 +70,7 @@ public:
* the best possible path between the two color space.
*/
KoColorConversionTransformation* createColorConverter(const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const;
KoColorProofingConversionTransformation* createColorProofingConverter(const KoColorSpace * srcColorSpace, const KoColorSpace * dstColorSpace, const KoColorSpace *proofingSpace, KoColorProofingConversionTransformation::Intent renderingIntent, KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const;
/**
* This function creates two transformations, one from the color space and one to the
......
......@@ -23,6 +23,7 @@
#include "kritapigment_export.h"
#include <KoColorConversionTransformation.h>
#include <KoColorProofingConversionTransformation.h>
class KRITAPIGMENT_EXPORT KoColorConversionTransformationAbstractFactory
{
......@@ -40,6 +41,21 @@ public:
const KoColorSpace* dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const = 0;
virtual KoColorProofingConversionTransformation* createColorProofingTransformation(const KoColorSpace* srcColorSpace,
const KoColorSpace* dstColorSpace,
const KoColorSpace* proofingSpace,
KoColorProofingConversionTransformation::Intent renderingIntent,
KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const
{
Q_UNUSED(srcColorSpace);
Q_UNUSED(dstColorSpace);
Q_UNUSED(proofingSpace);
Q_UNUSED(renderingIntent);
Q_UNUSED(conversionFlags);
qFatal("createColorProofinTransform undefined.");
return 0;
}
};
#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.1 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 "KoColorProofingConversionTransformation.h"
#include "KoColorSpace.h"
struct Q_DECL_HIDDEN KoColorProofingConversionTransformation::Private {
const KoColorSpace* srcColorSpace;
const KoColorSpace* dstColorSpace;
const KoColorSpace* proofingSpace;
Intent renderingIntent;
ConversionFlags conversionFlags;
};
KoColorProofingConversionTransformation::KoColorProofingConversionTransformation(const KoColorSpace* srcCs,
const KoColorSpace* dstCs,
const KoColorSpace* proofingSpace,
Intent renderingIntent,
ConversionFlags conversionFlags)
: d(new Private)
{
Q_ASSERT(srcCs);
Q_ASSERT(dstCs);
Q_ASSERT(proofingSpace);
d->srcColorSpace = srcCs;
d->dstColorSpace = dstCs;
d->proofingSpace = proofingSpace;
d->renderingIntent = renderingIntent;
d->conversionFlags = conversionFlags;
}
KoColorProofingConversionTransformation::~KoColorProofingConversionTransformation()
{
delete d;
}
const KoColorSpace* KoColorProofingConversionTransformation::srcColorSpace() const
{
return d->srcColorSpace;
}
const KoColorSpace* KoColorProofingConversionTransformation::dstColorSpace() const
{
return d->dstColorSpace;
}
const KoColorSpace* KoColorProofingConversionTransformation::proofingSpace() const
{
return d->proofingSpace;
}
KoColorProofingConversionTransformation::Intent KoColorProofingConversionTransformation::renderingIntent() const
{
return d->renderingIntent;
}
KoColorProofingConversionTransformation::ConversionFlags KoColorProofingConversionTransformation::conversionFlags() const
{
return d->conversionFlags;
}
void KoColorProofingConversionTransformation::setSrcColorSpace(const KoColorSpace* cs) const
{
Q_ASSERT(*d->srcColorSpace == *cs);
d->srcColorSpace = cs;
}
void KoColorProofingConversionTransformation::setDstColorSpace(const KoColorSpace* cs) const
{
Q_ASSERT(*d->dstColorSpace == *cs);
d->dstColorSpace = cs;
}
void KoColorProofingConversionTransformation::setProofingSpace(const KoColorSpace* cs) const
{
Q_ASSERT(*d->proofingSpace == *cs);
d->proofingSpace = cs;
}
void KoColorProofingConversionTransformation::setIntent(Intent renderingIntent) const
{
d->renderingIntent = renderingIntent;
}
void KoColorProofingConversionTransformation::setConversionFlags(ConversionFlags conversionFlags) const
{
d->conversionFlags = conversionFlags;
}
/*
* 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.1 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_PROOFING_CONVERSION_TRANSFORMATION_H_
#define _KO_COLOR_PROOFING_CONVERSION_TRANSFORMATION_H_
#include "KoColorTransformation.h"
#include "kritapigment_export.h"
class KoColorSpace;
class KoColorConversionCache;
/**
* This is the base class of all color transform that convert the color of a pixel
*/
class KRITAPIGMENT_EXPORT KoColorProofingConversionTransformation : public KoColorTransformation
{
friend class KoColorConversionCache;
struct Private;
public:
/**
* Possible value for the intent of a color conversion (useful only for ICC
* transformations)
*/
enum Intent {
IntentPerceptual = 0,
IntentRelativeColorimetric = 1,
IntentSaturation = 2,
IntentAbsoluteColorimetric = 3
};
/**
* Flags for the color conversion, see lcms2 documentation for more information
*/
enum ConversionFlag {
Empty = 0x0,
NoOptimization = 0x0100,
GamutCheck = 0x1000, // Out of Gamut alarm
SoftProofing = 0x4000, // Do softproofing
BlackpointCompensation = 0x2000,
NoWhiteOnWhiteFixup = 0x0004, // Don't fix scum dot
HighQuality = 0x0400, // Use more memory to give better accurancy
LowQuality = 0x0800 // Use less memory to minimize resouces
};
Q_DECLARE_FLAGS(ConversionFlags, ConversionFlag)
/**
* We have numerous places where we need to convert color spaces.
*
* In several cases the user asks us about the conversion
* explicitly, e.g. when changing the image type or converting
* pixel data to the monitor profile. Doing this explicitly the
* user can choose what rendering intent and conversion flags to
* use.
*
* But there are also cases when we have to do a conversion
* internally (transparently for the user), for example, when
* merging heterogeneous images, creating thumbnails, converting
* data to/from QImage or while doing some adjustments. We cannot
* ask the user about parameters for every single
* conversion. That's why in all these non-critical cases the
* following default values should be used.
*/
static Intent internalRenderingIntent() { return IntentPerceptual; }
static ConversionFlags internalConversionFlags() { return BlackpointCompensation; }
static Intent adjustmentRenderingIntent() { return IntentPerceptual; }
static ConversionFlags adjustmentConversionFlags() { return ConversionFlags(BlackpointCompensation | NoWhiteOnWhiteFixup); }
public:
KoColorProofingConversionTransformation(const KoColorSpace* srcCs,
const KoColorSpace* dstCs,
const KoColorSpace* proofingSpace,
Intent renderingIntent,
ConversionFlags conversionFlags);
~KoColorProofingConversionTransformation();
public:
/**
* @return the source color space for this transformation.
*/
const KoColorSpace* srcColorSpace() const;
/**
* @return the destination color space for this transformation.
*/
const KoColorSpace* dstColorSpace() const;
/**
* @brief proofingSpace
* @return the space that is used to proof the color transform
*/
const KoColorSpace* proofingSpace() const;
/**
* @return the rendering intent of this transformation (this is only useful
* for ICC transformations)
*/
Intent renderingIntent() const;
/**
* @return the conversion flags
*/
ConversionFlags conversionFlags() const;
/**
* perform the color conversion between two buffers.
* @param nPixels the number of pixels in the buffers.
*/
virtual void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const = 0;
/**
* @return false if the transformation is not valid
*/
virtual bool isValid() const { return true; }
private:
void setSrcColorSpace(const KoColorSpace*) const;
void setDstColorSpace(const KoColorSpace*) const;
void setProofingSpace(const KoColorSpace*) const;
void setIntent(Intent renderingIntent) const;
void setConversionFlags(ConversionFlags conversionFlags) const;
Private * const d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KoColorProofingConversionTransformation::ConversionFlags)
#endif
......@@ -417,6 +417,11 @@ KoColorConversionTransformation* KoColorSpace::createColorConverter(const KoColo
}
}
KoColorProofingConversionTransformation* KoColorSpace::createColorProofingConverter(const KoColorSpace * dstColorSpace, const KoColorSpace *proofingSpace, KoColorProofingConversionTransformation::Intent renderingIntent, KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const
{
return KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorProofingConverter(this, dstColorSpace, proofingSpace, renderingIntent, conversionFlags);
}
bool KoColorSpace::convertPixelsTo(const quint8 * src,
quint8 * dst,
const KoColorSpace * dstColorSpace,
......@@ -434,7 +439,24 @@ bool KoColorSpace::convertPixelsTo(const quint8 * src,
}
return true;
}
bool KoColorSpace::proofPixelsTo(const quint8 * src,
quint8 * dst,
const KoColorSpace * dstColorSpace,
const KoColorSpace * proofingSpace,
quint32 numPixels,
KoColorProofingConversionTransformation::Intent renderingIntent,
KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const
{
if (*this == *dstColorSpace && *this == *proofingSpace) {
if (src != dst) {
memcpy(dst, src, numPixels * sizeof(quint8) * pixelSize());
}
} else {
KoColorProofingConversionTransformation cct = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorProofingConverter(this, dstColorSpace, proofingSpace, renderingIntent, conversionFlags);
cct->transform(src, dst, numPixels);
}
return true;
}
void KoColorSpace::bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op,
KoColorConversionTransformation::Intent renderingIntent,
......
......@@ -29,6 +29,7 @@
#include "KoColorSpaceConstants.h"
#include "KoColorConversionTransformation.h"
#include "KoColorProofingConversionTransformation.h"
#include "KoCompositeOp.h"
#include <KoID.h>
#include "kritapigment_export.h"
......@@ -354,6 +355,10 @@ public:
virtual KoColorConversionTransformation* createColorConverter(const KoColorSpace * dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const;
virtual KoColorProofingConversionTransformation* createColorProofingConverter(const KoColorSpace * dstColorSpace,
const KoColorSpace * proofingSpace,
KoColorProofingConversionTransformation::Intent renderingIntent,
KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const;
/**
* Convert a byte array of srcLen pixels *src to the specified color space
......@@ -370,6 +375,12 @@ public:
quint32 numPixels,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const;
virtual bool proofPixelsTo(const quint8 * src,
quint8 * dst, const KoColorSpace * dstColorSpace,
const KoColorSpace * proofingSpace,
quint32 numPixels,
KoColorProofingConversionTransformation::Intent renderingIntent,
KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const;
//============================== Manipulation functions ==========================//
......
......@@ -157,6 +157,7 @@ private:
KisImageWSP m_image;
QRect m_storedImageBounds;
const KoColorProfile *m_monitorProfile;
const KoColorProfile *m_proofingProfile;
KoColorConversionTransformation::Intent m_renderingIntent;
KoColorConversionTransformation::ConversionFlags m_conversionFlags;
......
......@@ -209,6 +209,25 @@ public:
}
}
void proofTo(const KoColorSpace* dstCS, const KoColorSpace* proofingSpace,
KoColorProofingConversionTransformation::Intent renderingIntent,
KoColorProofingConversionTransformation::ConversionFlags conversionFlags)
{
if (dstCS == m_patchColorSpace && conversionFlags == KoColorProofingConversionTransformation::Empty) return;
if (m_patchRect.isValid()) {
const qint32 numPixels = m_patchRect.width() * m_patchRect.height();
const quint32 conversionCacheLength = numPixels * dstCS->pixelSize();
m_conversionCache.ensureNotSmaller(conversionCacheLength);
m_patchColorSpace->proofPixelsTo(m_patchPixels.data(), m_conversionCache.data(), dstCS, proofingSpace, numPixels, renderingIntent, conversionFlags);
m_patchColorSpace = dstCS;
m_conversionCache.swap(m_patchPixels);
m_patchPixelsLength = conversionCacheLength;
}
}
inline quint8* data() const {
return m_patchPixels.data();
}
......
......@@ -69,6 +69,81 @@ public:
cmsDeleteTransform(m_transform);
}
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) {
qreal alpha = srcColorSpace()->opacityF(src);
dstColorSpace()->setOpacity(dst, alpha, 1);
src += srcPixelSize;
dst += dstPixelSize;
numPixels--;
}
}
private:
mutable cmsHTRANSFORM m_transform;
};
class KoLcmsColorProofingConversionTransformation : public KoColorProofingConversionTransformation
{
public:
KoLcmsColorProofingConversionTransformation(const KoColorSpace *srcCs, quint32 srcColorSpaceType, LcmsColorProfileContainer *srcProfile,
const KoColorSpace *dstCs, quint32 dstColorSpaceType, LcmsColorProfileContainer *dstProfile,
const KoColorSpace *proofingSpace,
Intent renderingIntent,
ConversionFlags conversionFlags
)
: KoColorProofingConversionTransformation(srcCs, dstCs, proofingSpace, renderingIntent, conversionFlags)
, m_transform(0)
{
Q_ASSERT(srcCs);
Q_ASSERT(dstCs);
Q_ASSERT(renderingIntent < 4);
if (srcCs->colorDepthId() == Integer8BitsColorDepthID
|| srcCs->colorDepthId() == Integer16BitsColorDepthID) {
if ((srcProfile->name().contains(QLatin1String("linear"), Qt::CaseInsensitive) ||
dstProfile->name().contains(QLatin1String("linear"), Qt::CaseInsensitive)) &&
!conversionFlags.testFlag(KoColorProofingConversionTransformation::NoOptimization)) {
conversionFlags |= KoColorProofingConversionTransformation::NoOptimization;
}
}
quint16 alarm[4];//cyan!
alarm[0] = 65535;
alarm[1] = 0;
alarm[2] = 0;
alarm[3] = 65535;
cmsSetAlarmCodes(alarm);
m_transform = cmsCreateProofingTransform(srcProfile->lcmsProfile(),
srcColorSpaceType,
dstProfile->lcmsProfile(),
dstColorSpaceType,
dynamic_cast<const IccColorProfile *>(proofingSpace->profile())->asLcms()->lcmsProfile(),
renderingIntent,
renderingIntent,
conversionFlags);
Q_ASSERT(m_transform);
}
~KoLcmsColorProofingConversionTransformation()
{
cmsDeleteTransform(m_transform);
}
public:
virtual void transform(const quint8 *src, quint8 *dst, qint32 numPixels) const
......@@ -161,6 +236,23 @@ KoColorConversionTransformation *IccColorSpaceEngine::createColorTransformation(
dynamic_cast<const IccColorProfile *>(dstColorSpace->profile())->asLcms(), renderingIntent, conversionFlags);
}
KoColorProofingConversionTransformation *IccColorSpaceEngine::createColorProofingTransformation(const KoColorSpace *srcColorSpace,
const KoColorSpace *dstColorSpace,
const KoColorSpace *proofingSpace,
KoColorProofingConversionTransformation::Intent renderingIntent,
KoColorProofingConversionTransformation::ConversionFlags conversionFlags
) const
{
Q_ASSERT(srcColorSpace);
Q_ASSERT(dstColorSpace);
return new KoLcmsColorProofingConversionTransformation(
srcColorSpace, computeColorSpaceType(srcColorSpace),
dynamic_cast<const IccColorProfile *>(srcColorSpace->profile())->asLcms(), dstColorSpace, computeColorSpaceType(dstColorSpace),
dynamic_cast<const IccColorProfile *>(dstColorSpace->profile())->asLcms(), proofingSpace, renderingIntent, conversionFlags
);
}
quint32 IccColorSpaceEngine::computeColorSpaceType(const KoColorSpace *cs) const
{
Q_ASSERT(cs);
......
......@@ -33,6 +33,11 @@ public:
const KoColorSpace *dstColorSpace,
KoColorConversionTransformation::Intent renderingIntent,
KoColorConversionTransformation::ConversionFlags conversionFlags) const;
virtual KoColorProofingConversionTransformation *createColorProofingTransformation(const KoColorSpace *srcColorSpace,
const KoColorSpace *dstColorSpace,
const KoColorSpace *proofingSpace,
KoColorProofingConversionTransformation::Intent renderingIntent,
KoColorProofingConversionTransformation::ConversionFlags conversionFlags) const;
quint32 computeColorSpaceType(const KoColorSpace *cs) const;
private:
struct Private;
......
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