Commit d08414a8 authored by Agata Cacko's avatar Agata Cacko Committed by Halla Rempt
Browse files

Fix oilpaint filter's tiling artifacts

Before this commit, the oilpaint filter was broken: it would show tiling
sometimes and when painting on a layer with an oilpaint filter mask
attached, it would tile very badly around the brush (I was using
Wet Textured Soft for testing).
This commit fixes this behaviour by ensuring proper handling of opacity
and by changing usages of rawDataConst to oldRawData().

After changes, the results are roughly the same as before changes,
except that there is no tiling visible and painting is possible.
However the results are still quite much worse than in the
plugins/filters/tests/kis_all_filter_test expected results
would suggest. On the other hand, Krita's and Digikam's results are very
similar, too (and Digikam's results look wrong since they have random
black pixels in various places; Krita don't have them).

The problem of tiling was first noticed by SafariMonkey which also
contributed with first version of the patch (without handling of
transparency).

(cherry picked from commit 3891b207)
parent 1706d49f
......@@ -122,7 +122,7 @@ void KisOilPaintFilter::MostFrequentColor(KisPaintDeviceSP src, quint8* dst, con
double Scale = Intensity / 255.0;
// Alloc some arrays to be used
uchar *IntensityCount = new uchar[(Intensity + 1) * sizeof(uchar)];
uchar *IntensityCount = new uchar[(Intensity + 1)];
const KoColorSpace* cs = src->colorSpace();
......@@ -132,20 +132,32 @@ void KisOilPaintFilter::MostFrequentColor(KisPaintDeviceSP src, quint8* dst, con
// Erase the array
memset(IntensityCount, 0, (Intensity + 1) * sizeof(uchar));
int startx = qMax(X - Radius, bounds.left());
int starty = qMax(Y - Radius, bounds.top());
int startx = X - Radius;
int starty = Y - Radius;
int width = (2 * Radius) + 1;
if ((startx + width - 1) > bounds.right()) width = bounds.right() - startx + 1;
Q_ASSERT((startx + width - 1) <= bounds.right());
int height = (2 * Radius) + 1;
if ((starty + height) > bounds.bottom()) height = bounds.bottom() - starty + 1;
Q_ASSERT((starty + height - 1) <= bounds.bottom());
qreal middlePointAlpha = 1;
{
// if the current pixel is transparent, the result must be transparent, too.
KisSequentialConstIterator middlePointIt(src, QRect(X, Y, 1, 1));
middlePointIt.nextPixel();
middlePointAlpha = cs->opacityF(middlePointIt.oldRawData());
}
KisSequentialConstIterator srcIt(src, QRect(startx, starty, width, height));
while (srcIt.nextPixel()) {
while (middlePointAlpha > 0 && srcIt.nextPixel()) {
cs->normalisedChannelsValue(srcIt.oldRawData(), channel);
if (cs->opacityU8(srcIt.oldRawData()) == 0) {
// if the pixel is transparent, it's not going to provide any useful information
continue;
}
cs->normalisedChannelsValue(srcIt.rawDataConst(), channel);
I = (uint)(cs->intensity8(srcIt.oldRawData()) * Scale);
I = (uint)(cs->intensity8(srcIt.rawDataConst()) * Scale);
IntensityCount[I]++;
if (IntensityCount[I] == 1) {
......@@ -173,9 +185,10 @@ void KisOilPaintFilter::MostFrequentColor(KisPaintDeviceSP src, quint8* dst, con
channel[i] /= MaxInstance;
}
cs->fromNormalisedChannelsValue(dst, channel);
cs->setOpacity(dst, OPACITY_OPAQUE_U8, middlePointAlpha);
} else {
memset(dst, 0, cs->pixelSize());
cs->setOpacity(dst, OPACITY_OPAQUE_U8, 1);
cs->setOpacity(dst, OPACITY_OPAQUE_U8, middlePointAlpha);
}
......@@ -183,6 +196,19 @@ void KisOilPaintFilter::MostFrequentColor(KisPaintDeviceSP src, quint8* dst, con
delete [] AverageChannels;
}
QRect KisOilPaintFilter::neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const
{
const quint32 brushSize = _config ? _config->getInt("brushSize", 1) : 1;
return rect.adjusted(-brushSize * 2, -brushSize * 2, brushSize * 2, brushSize * 2);
}
QRect KisOilPaintFilter::changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const
{
const quint32 brushSize = _config ? _config->getInt("brushSize", 1) : 1;
return rect.adjusted( -brushSize*2, -brushSize*2, brushSize*2, brushSize*2);
}
KisConfigWidget * KisOilPaintFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP, bool) const
{
......
......@@ -39,6 +39,10 @@ public:
}
KisFilterConfigurationSP defaultConfiguration() const override;
QRect neededRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const override;
QRect changedRect(const QRect & rect, const KisFilterConfigurationSP _config, int lod) const override;
public:
KisConfigWidget * createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev, bool useForMasks) const override;
......
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