Commit dba4e8b0 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implemented a proper conversion when composing usual color spaces on the top of alpha8

alpha8() colorspace is very special in pigment. Firstly, it is not handled
by the lcms. More than that, most of the compositions do not work in it,
since it has a bit weird definition of what is color and what is alpha
channel. So when painting another colorspace above it, it is more sane
to do the composition in the source colorspace, and only then convert
the result to the destination alpha8.

This patch implements a property for a color space, which defines
whether the color space prefers such way of composition.

TODO: there is a small problem currently, the bitBlt function should
      request the compositeOp of another color space every time it is
      called. That is not ideal of course and should probably fixed with
      some caching strategy.
parent cea15360
This diff is collapsed.
......@@ -28,13 +28,13 @@ class KisSelectionTest : public QObject
Q_OBJECT
private slots:
void testGrayColorspaceConversion();
void testGrayColorspaceOverComposition();
void testSelectionComponents();
void testSelectionActions();
void testInvertSelection();
void testInvertSelectionSemi();
void testUpdatePixelSelection();
void testUpdateSelectionProjection();
void testCopy();
void testSelectionExactBounds();
void testSetParentNodeAfterCreation();
......
......@@ -262,22 +262,53 @@ void KoColorSpace::bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::Par
return;
if(!(*this == *srcSpace)) {
quint32 conversionBufferStride = params.cols * pixelSize();
QVector<quint8> * conversionCache = threadLocalConversionCache(params.rows * conversionBufferStride);
quint8* conversionData = conversionCache->data();
for(qint32 row=0; row<params.rows; row++) {
srcSpace->convertPixelsTo(params.srcRowStart + row*params.srcRowStride,
conversionData + row*conversionBufferStride, this, params.cols,
renderingIntent, conversionFlags);
if (preferCompositionInSourceColorSpace() &&
srcSpace->hasCompositeOp(op->id())) {
quint32 conversionDstBufferStride = params.cols * srcSpace->pixelSize();
QVector<quint8> * conversionDstCache = threadLocalConversionCache(params.rows * conversionDstBufferStride);
quint8* conversionDstData = conversionDstCache->data();
for(qint32 row=0; row<params.rows; row++) {
convertPixelsTo(params.dstRowStart + row * params.dstRowStride,
conversionDstData + row * conversionDstBufferStride, srcSpace, params.cols,
renderingIntent, conversionFlags);
}
// FIXME: do not calculate the otherOp every time
const KoCompositeOp *otherOp = srcSpace->compositeOp(op->id());
KoCompositeOp::ParameterInfo paramInfo(params);
paramInfo.dstRowStart = conversionDstData;
paramInfo.dstRowStride = conversionDstBufferStride;
otherOp->composite(paramInfo);
for(qint32 row=0; row<params.rows; row++) {
srcSpace->convertPixelsTo(conversionDstData + row * conversionDstBufferStride,
params.dstRowStart + row * params.dstRowStride, this, params.cols,
renderingIntent, conversionFlags);
}
} else {
quint32 conversionBufferStride = params.cols * pixelSize();
QVector<quint8> * conversionCache = threadLocalConversionCache(params.rows * conversionBufferStride);
quint8* conversionData = conversionCache->data();
for(qint32 row=0; row<params.rows; row++) {
srcSpace->convertPixelsTo(params.srcRowStart + row * params.srcRowStride,
conversionData + row * conversionBufferStride, this, params.cols,
renderingIntent, conversionFlags);
}
KoCompositeOp::ParameterInfo paramInfo(params);
paramInfo.srcRowStart = conversionData;
paramInfo.srcRowStride = conversionBufferStride;
op->composite(paramInfo);
}
KoCompositeOp::ParameterInfo paramInfo(params);
paramInfo.srcRowStart = conversionData;
paramInfo.srcRowStride = conversionBufferStride;
op->composite(paramInfo);
}
else op->composite(params);
else {
op->composite(params);
}
}
......@@ -331,3 +362,8 @@ QImage KoColorSpace::convertToQImage(const quint8 *data, qint32 width, qint32 he
return img;
}
bool KoColorSpace::preferCompositionInSourceColorSpace() const
{
return false;
}
......@@ -554,6 +554,33 @@ protected:
*/
QVector<quint8> * threadLocalConversionCache(quint32 size) const;
/**
* This function defines the behavior of the bitBlt function
* when the composition of pixels in different colorspaces is
* requested, that is in case:
*
* srcCS == any
* dstCS == this
*
* 1) preferCompositionInSourceColorSpace() == false,
*
* the source pixels are first converted to *this color space
* and then composition is performed.
*
*2) preferCompositionInSourceColorSpace() == true,
*
* the destination pixels are first converted into *srcCS color
* space, then the composition is done, and the result is finally
* converted into *this colorspace.
*
* This is used by alpha8() color space mostly, because it has
* weaker representation of the color, so the composition
* should be done in CS with richer functionality.
*/
virtual bool preferCompositionInSourceColorSpace() const;
struct Private;
Private * const d;
......
......@@ -356,3 +356,7 @@ KoColorSpace* KoAlphaColorSpace::clone() const
return new KoAlphaColorSpace();
}
bool KoAlphaColorSpace::preferCompositionInSourceColorSpace() const
{
return true;
}
......@@ -160,6 +160,8 @@ public:
warnPigment << i18n("Undefined operation in the alpha color space");
}
protected:
virtual bool preferCompositionInSourceColorSpace() const;
private:
KoColorProfile* m_profile;
......
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