Commit e6bda0c7 authored by Silvio Heinrich's avatar Silvio Heinrich

Improved the "alpha darken" blending mode.

parent 07068513
This diff is collapsed.
......@@ -259,17 +259,17 @@ void KoColorSpace::bitBlt(quint8* dst,
const quint8* srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
quint8 flow,
qint32 rows,
qint32 cols,
const QString& op,
const QBitArray& channelFlags) const
{
if (d->compositeOps.contains(op)) {
bitBlt(dst, dststride, srcSpace, src, srcRowStride, srcAlphaMask, maskRowStride, opacity, flow, rows, cols, d->compositeOps.value(op), channelFlags);
bitBlt(dst, dststride, srcSpace, src, srcRowStride, srcAlphaMask, maskRowStride, opacity, rows, cols, d->compositeOps.value(op), channelFlags);
} else {
bitBlt(dst, dststride, srcSpace, src, srcRowStride, srcAlphaMask, maskRowStride, opacity, flow, rows, cols, d->compositeOps.value(COMPOSITE_OVER), channelFlags);
bitBlt(dst, dststride, srcSpace, src, srcRowStride, srcAlphaMask, maskRowStride, opacity, rows, cols, d->compositeOps.value(COMPOSITE_OVER), channelFlags);
}
}
void KoColorSpace::bitBlt(quint8* dst,
......@@ -277,10 +277,9 @@ void KoColorSpace::bitBlt(quint8* dst,
const KoColorSpace* srcSpace,
const quint8* src,
qint32 srcRowStride,
const quint8* srcAlphaMask,
const quint8 *srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
quint8 flow,
qint32 rows,
qint32 cols,
const KoCompositeOp* op,
......@@ -309,17 +308,43 @@ void KoColorSpace::bitBlt(quint8* dst,
conversionData, conversionBufferStride,
srcAlphaMask, maskRowStride,
rows, cols,
opacity, flow, channelFlags);
opacity, channelFlags);
} else {
op->composite(dst, dstRowStride,
src, srcRowStride,
srcAlphaMask, maskRowStride,
rows, cols,
opacity, flow, channelFlags);
opacity, channelFlags);
}
}
void KoColorSpace::bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op) const
{
Q_ASSERT_X(*op->colorSpace() == *this, "KoColorSpace::bitBlt", QString("Composite op is for color space %1 (%2) while this is %3 (%4)").arg(op->colorSpace()->id()).arg(op->colorSpace()->profile()->name()).arg(id()).arg(profile()->name()).toLatin1());
if(params.rows <= 0 || params.cols <= 0)
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);
}
KoCompositeOp::ParameterInfo paramInfo(params);
paramInfo.srcRowStart = conversionData;
paramInfo.srcRowStride = conversionBufferStride;
op->composite(paramInfo);
}
else op->composite(params);
}
QVector<quint8> * KoColorSpace::threadLocalConversionCache(quint32 size) const
{
QVector<quint8> * ba = 0;
......
......@@ -30,6 +30,7 @@
#include "KoColorSpaceConstants.h"
#include "KoColorConversionTransformation.h"
#include "KoCompositeOp.h"
#include <KoChannelInfo.h>
#include <KoID.h>
#include "pigment_export.h"
......@@ -497,19 +498,33 @@ public:
* @param channelFlags a bit array reflecting which channels will be composited and which
* channels won't. The order is pixel order, not colorspace order.
*/
virtual void bitBlt(quint8* dst,
virtual void bitBlt(quint8 *dst,
qint32 dststride,
const KoColorSpace* srcSpace,
const quint8* src,
const quint8 *src,
qint32 srcRowStride,
const quint8 *srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
quint8 flow,
qint32 rows,
qint32 cols,
const KoCompositeOp* op,
const QBitArray& channelFlags=QBitArray()) const;
/**
* Compose two arrays of pixels together. If source and target
* are not the same color model, the source pixels will be
* converted to the target model. We're "dst" -- "dst" pixels are always in _this_
* colorspace.
*
* @param srcSpace the colorspace of the source pixels that will be composited onto "us"
* @param param the information needed for blitting e.g. the source and destination pixel data,
* the opacity and flow, ...
* @param op the composition operator to use, e.g. COPY_OVER
*
*/
virtual void bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op) const;
/**
* Convenience function for the above if you don't have the composite op object yet.
*/
......@@ -521,12 +536,11 @@ public:
const quint8* srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
quint8 flow,
qint32 rows,
qint32 cols,
const QString& op,
const QBitArray& channelFlags=QBitArray()) const;
/**
* Serialize this color following Create's swatch color specification available
* at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format
......
......@@ -254,7 +254,7 @@ void KoCompositeOp::composite(quint8 *dstRowStart, qint32 dstRowStride,
const quint8 *srcRowStart, qint32 srcRowStride,
const quint8 *maskRowStart, qint32 maskRowStride,
qint32 rows, qint32 numColumns,
quint8 opacity, quint8 flow, const QBitArray& channelFlags) const
quint8 opacity, const QBitArray& channelFlags) const
{
KoCompositeOp::ParameterInfo params;
params.dstRowStart = dstRowStart;
......@@ -265,33 +265,19 @@ void KoCompositeOp::composite(quint8 *dstRowStart, qint32 dstRowStride,
params.maskRowStride = maskRowStride;
params.rows = rows;
params.cols = numColumns;
params.opacity = opacity;
params.opacity2 = 255;
params.flow = flow;
params.opacity = float(opacity) / 255.0f;
params.flow = 1.0f;
params.channelFlags = channelFlags;
composite(params);
}
void KoCompositeOp::composite(quint8 *dstRowStart, qint32 dstRowStride,
const quint8 *srcRowStart, qint32 srcRowStride,
const quint8 *maskRowStart, qint32 maskRowStride,
qint32 rows, qint32 numColumns,
quint8 opacity, const QBitArray& channelFlags) const
{
composite(dstRowStart, dstRowStride,
srcRowStart, srcRowStride,
maskRowStart, maskRowStride,
rows, numColumns,
opacity, 255, channelFlags);
}
void KoCompositeOp::composite(const KoCompositeOp::ParameterInfo& params) const
{
composite(params.dstRowStart , params.dstRowStride ,
params.srcRowStart , params.srcRowStride ,
params.maskRowStart, params.maskRowStride,
params.rows , params.cols ,
params.opacity , params.channelFlags );
composite(params.dstRowStart , params.dstRowStride ,
params.srcRowStart , params.srcRowStride ,
params.maskRowStart , params.maskRowStride,
params.rows , params.cols ,
quint8(params.opacity*255.0f), params.channelFlags );
}
......
/*
* Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
* Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
* Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
*
* This library is free software; you can redistribute it and/or
......@@ -182,7 +182,7 @@ public:
static QString categoryMix();
static QString categoryMisc();
struct PIGMENTCMS_EXPORT ParameterInfo
struct ParameterInfo
{
quint8* dstRowStart;
qint32 dstRowStride;
......@@ -192,9 +192,8 @@ public:
qint32 maskRowStride;
qint32 rows;
qint32 cols;
quint8 opacity;
quint8 opacity2;
quint8 flow;
float opacity;
float flow;
QBitArray channelFlags;
};
......@@ -249,28 +248,17 @@ public:
* @param rows number of scanlines to blend
* @param numColumns length of the row of pixels in pixels
* @param opacity transparency with which to blend
* @param flow transparency with which to blend the dab
* @param channelFlags a bit array that determines which channels should be processed (channels are in the order of the channels in the colorspace)
*/
virtual void composite(quint8 *dstRowStart, qint32 dstRowStride,
const quint8 *srcRowStart, qint32 srcRowStride,
const quint8 *maskRowStart, qint32 maskRowStride,
qint32 rows, qint32 numColumns,
quint8 opacity, quint8 flow, const QBitArray& channelFlags) const;
/**
* Same as previous, but without flow parameter
*/
virtual void composite(quint8 *dstRowStart, qint32 dstRowStride,
const quint8 *srcRowStart, qint32 srcRowStride,
const quint8 *maskRowStart, qint32 maskRowStride,
qint32 rows, qint32 numColumns,
quint8 opacity,
const QBitArray& channelFlags=QBitArray()) const;
quint8 opacity, const QBitArray& channelFlags=QBitArray()) const;
/**
* Same as previous, but uses a parameter structure
*/
* Same as previous, but uses a parameter structure
*/
virtual void composite(const ParameterInfo& params) const;
private:
......
......@@ -25,46 +25,74 @@
#include "KoCompositeOpBase.h"
/**
* A template version of the alphadarken composite operation to use in colorspaces<
* A template version of the alphadarken composite operation to use in colorspaces
*/
template<class Traits>
class KoCompositeOpAlphaDarken: public KoCompositeOpBase< Traits, KoCompositeOpAlphaDarken<Traits> >
class KoCompositeOpAlphaDarken: public KoCompositeOp
{
typedef KoCompositeOpBase< Traits, KoCompositeOpAlphaDarken<Traits> > base_class;
typedef typename Traits::channels_type channels_type;
typedef typename Traits::channels_type channels_type;
static const qint32 channels_nb = Traits::channels_nb;
static const qint32 alpha_pos = Traits::alpha_pos;
public:
KoCompositeOpAlphaDarken(const KoColorSpace* cs):
base_class(cs, COMPOSITE_ALPHA_DARKEN, i18n("Alpha darken"), KoCompositeOp::categoryMix(), false) { }
KoCompositeOp(cs, COMPOSITE_ALPHA_DARKEN, i18n("Alpha darken"), KoCompositeOp::categoryMix(), true) { }
public:
template<bool alphaLocked, bool allChannelFlags>
inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
channels_type* dst, channels_type dstAlpha,
channels_type opacity, channels_type flow, const QBitArray& channelFlags) {
using KoCompositeOp::composite;
virtual void composite(const KoCompositeOp::ParameterInfo& params) const
{
using namespace Arithmetic;
srcAlpha = mul(srcAlpha, opacity);
qint32 srcInc = (params.srcRowStride == 0) ? 0 : channels_nb;
bool useMask = params.maskRowStart != 0;
channels_type flow = scale<channels_type>(params.flow);
channels_type opacity = mul(flow, scale<channels_type>(params.opacity));
quint8* dstRowStart = params.dstRowStart;
const quint8* srcRowStart = params.srcRowStart;
const quint8* maskRowStart = params.maskRowStart;
if(dstAlpha != zeroValue<channels_type>()) {
for(qint32 i=0; i <channels_nb; i++) {
if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i)))
dst[i] = lerp(dst[i], src[i], srcAlpha);
for(quint32 r=params.rows; r>0; --r) {
const channels_type* src = reinterpret_cast<const channels_type*>(srcRowStart);
channels_type* dst = reinterpret_cast<channels_type*>(dstRowStart);
const quint8* mask = maskRowStart;
for(qint32 c=params.cols; c>0; --c) {
channels_type srcAlpha = (alpha_pos == -1) ? unitValue<channels_type>() : src[alpha_pos];
channels_type dstAlpha = (alpha_pos == -1) ? unitValue<channels_type>() : dst[alpha_pos];
channels_type mskAlpha = useMask ? mul(scale<channels_type>(*mask), srcAlpha) : srcAlpha;
srcAlpha = mul(mskAlpha, opacity);
if(dstAlpha != zeroValue<channels_type>()) {
for(qint32 i=0; i <channels_nb; i++) {
if(i != alpha_pos)
dst[i] = lerp(dst[i], src[i], srcAlpha);
}
}
else {
for(qint32 i=0; i <channels_nb; i++) {
if(i != alpha_pos)
dst[i] = src[i];
}
}
if(alpha_pos != -1) {
channels_type alpha1 = unionShapeOpacity(srcAlpha, dstAlpha); // alpha with 0% flow
channels_type alpha2 = (opacity > dstAlpha) ? lerp(dstAlpha, opacity, mskAlpha) : dstAlpha; // alpha with 100% flow
dst[alpha_pos] = lerp(alpha1, alpha2, flow);
}
src += srcInc;
dst += channels_nb;
++mask;
}
srcRowStart += params.srcRowStride;
dstRowStart += params.dstRowStride;
maskRowStart += params.maskRowStride;
}
else {
for(qint32 i=0; i <channels_nb; i++) {
if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i)))
dst[i] = src[i];
}
}
channels_type alpha1 = unionShapeOpacity(srcAlpha, dstAlpha); // alpha with 0% flow
channels_type alpha2 = (dstAlpha > srcAlpha) ? dstAlpha : srcAlpha; // alpha with 100% flow
return lerp(alpha1, alpha2, flow);
}
};
......
......@@ -81,8 +81,7 @@ private:
qint32 srcInc = (params.srcRowStride == 0) ? 0 : channels_nb;
bool useMask = params.maskRowStart != 0;
channels_type flow = scale<channels_type>(params.flow);
channels_type opacity = mul(scale<channels_type>(params.opacity), flow);
channels_type opacity = scale<channels_type>(params.opacity);
quint8* dstRowStart = params.dstRowStart;
const quint8* srcRowStart = params.srcRowStart;
const quint8* maskRowStart = params.maskRowStart;
......@@ -98,7 +97,7 @@ private:
channels_type blend = useMask ? mul(opacity, scale<channels_type>(*mask)) : opacity;
channels_type newDstAlpha = _compositeOp::template composeColorChannels<alphaLocked,allChannelFlags>(
src, srcAlpha, dst, dstAlpha, blend, flow, channelFlags
src, srcAlpha, dst, dstAlpha, blend, channelFlags
);
if(alpha_pos != -1)
......
......@@ -45,8 +45,7 @@ public:
template<bool alphaLocked, bool allChannelFlags>
inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
channels_type* dst, channels_type dstAlpha,
channels_type opacity, channels_type flow, const QBitArray& channelFlags) {
Q_UNUSED(flow);
channels_type opacity, const QBitArray& channelFlags) {
using namespace Arithmetic;
channels_type blendAlpha = opacity;
......
......@@ -47,8 +47,7 @@ public:
template<bool alphaLocked, bool allChannelFlags>
inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
channels_type* dst, channels_type dstAlpha,
channels_type opacity, channels_type flow, const QBitArray& channelFlags) {
Q_UNUSED(flow);
channels_type opacity, const QBitArray& channelFlags) {
using namespace Arithmetic;
if(allChannelFlags || channelFlags.testBit(channel_pos)) {
......
......@@ -50,8 +50,7 @@ public:
template<bool alphaLocked, bool allChannelFlags>
inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
channels_type* dst, channels_type dstAlpha,
channels_type opacity, channels_type flow, const QBitArray& channelFlags) {
Q_UNUSED(flow);
channels_type opacity, const QBitArray& channelFlags) {
using namespace Arithmetic;
srcAlpha = mul(srcAlpha, opacity);
......@@ -109,8 +108,7 @@ public:
template<bool alphaLocked, bool allChannelFlags>
inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
channels_type* dst, channels_type dstAlpha,
channels_type opacity, channels_type flow, const QBitArray& channelFlags) {
Q_UNUSED(flow);
channels_type opacity, const QBitArray& channelFlags) {
using namespace Arithmetic;
srcAlpha = mul(srcAlpha, opacity);
......
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