From kde-kimageshop Tue Jan 04 00:20:34 2011 From: Silvio Heinrich Date: Tue, 04 Jan 2011 00:20:34 +0000 To: kde-kimageshop Subject: Patch: Smudge Brush fixes Message-Id: <4D2267D2.6010303 () web ! de> X-MARC-Message: https://marc.info/?l=kde-kimageshop&m=129413006727205 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--------------060209050507070401070107" This is a multi-part message in MIME format. --------------060209050507070401070107 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Now it should work pretty similar to the smudge tool in gimp. But I still need to do some tweaks to how the rate values (color and smudge rates) are used. It only smudges/paints correctly in a certain region of the rates. But the transparency issues should be solved by now, so no black color should be introduced anymore (hopefully :P). --------------060209050507070401070107 Content-Type: text/x-diff; name="SmudgeBrush.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="SmudgeBrush.patch" From db2c5f5cc5aee64ff8af4c6470fe879e09981a18 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Fri, 31 Dec 2010 00:23:07 +0100 Subject: [PATCH 1/6] Fixed (reprogrammed) smudge brush Reprogrammed the smudge brush with a simpler algorithm. An option to mix color into the smudge process is also introduced. --- .../defaultpaintops/smudge/kis_smudgeop.cpp | 107 ++++++++++++++++---- .../paintops/defaultpaintops/smudge/kis_smudgeop.h | 3 +- .../smudge/kis_smudgeop_settings_widget.cpp | 10 +- krita/plugins/paintops/libpaintop/CMakeLists.txt | 2 + .../libpaintop/kis_pressure_composite_option.cpp | 76 ++++++++++++++ .../libpaintop/kis_pressure_composite_option.h | 58 +++++++++++ .../kis_pressure_composite_option_widget.cpp | 104 +++++++++++++++++++ .../kis_pressure_composite_option_widget.h | 46 +++++++++ 8 files changed, 380 insertions(+), 26 deletions(-) create mode 100644 krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp create mode 100644 krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h create mode 100644 krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp create mode 100644 krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index ee7927f..c8dde6d 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp @@ -58,11 +58,11 @@ KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings *settings, KisPainte Q_ASSERT(settings); Q_ASSERT(painter); m_sizeOption.readOptionSetting(settings); - m_opacityOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); + m_compositeOption.readOptionSetting(settings); m_sizeOption.sensor()->reset(); - m_opacityOption.sensor()->reset(); m_rateOption.sensor()->reset(); + m_compositeOption.sensor()->reset(); m_tempDev = new KisPaintDevice(painter->device()->colorSpace()); @@ -76,9 +76,77 @@ KisSmudgeOp::~KisSmudgeOp() { } -/* To smudge, one does the following: - 1.- First step: initialize a temporary paint device (m_tempDev) with a copy of the colors below the mouse pointer. + +qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) +{ + // Simple error catching + if (!painter()->device()) + return 1.0; + + KisBrushSP brush = m_brush; + + if(!brush || !brush->canPaintFor(info)) + return 1.0; + + double scale = m_sizeOption.apply(info); + + if((scale*brush->width()) <= 0.01 || (scale*brush->height()) <= 0.01) + return 1.0; + + setCurrentScale(scale); + + QPointF point = info.pos() - brush->hotSpot(scale, scale); + + qint32 x, y; + qreal xFraction, yFraction; + splitCoordinate(point.x(), &x, &xFraction); + splitCoordinate(point.y(), &y, &yFraction); + + KisFixedPaintDeviceSP maskDab = cachedDab(painter()->device()->colorSpace()); + + // Extract the brush mask (maskDab) from brush, and turn it into a transparency mask (alpha8). + if(brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { + // This is for bitmap brushes + maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, info, xFraction, yFraction); + } else { + // This is for parametric brushes, those created in the Autobrush popup config dialogue + maskDab = cachedDab(); + brush->mask(maskDab, painter()->paintColor(), scale, scale, 0.0, info, xFraction, yFraction); + } + + maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8()); + + KisPainter copyPainter(m_tempDev); + + if(m_compositeOption.isChecked()) { + m_compositeOption.apply(©Painter, OPACITY_OPAQUE_U8, info); + + copyPainter.setFillStyle(KisPainter::FillStyleForegroundColor); + copyPainter.setPaintColor(painter()->paintColor()); + copyPainter.paintRect(maskDab->bounds()); + } + + quint8 newOpacity = m_rateOption.apply(OPACITY_OPAQUE_U8, info); + + painter()->setOpacity(newOpacity); + painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height()); + //painter()->bitBlt(QPoint(x,y), m_tempDev, dab->bounds()); + + m_tempDev->clear(maskDab->bounds()); + + copyPainter.setCompositeOp(COMPOSITE_OVER); + copyPainter.setOpacity(OPACITY_OPAQUE_U8); + copyPainter.bitBlt(0, 0, painter()->device(), x, y, maskDab->bounds().width(), maskDab->bounds().height()); + copyPainter.end(); + + return spacing(scale); +} + + +/* To smudge, one does the following: + * + 1 *.- First step: initialize a temporary paint device (m_tempDev) with a copy of the colors below the mouse pointer. All other times: 2.- Vanishing step: Reduce the transparency of the temporary paint device so as to let it mix gradually. 3.- Combine: Combine the temporary device with the piece the brush currently is 'painting', according to a ratio: @@ -93,8 +161,7 @@ KisSmudgeOp::~KisSmudgeOp() temporary device is cached such that only the colored areas are considered. TODO: Make this cached value dump colors that have faded nearly completely and lie outside of the rectangle (dab) of the current iteration. -*/ - + * qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) { KisBrushSP brush = m_brush; @@ -109,14 +176,14 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) if ((scale * brush->width()) <= 0.01 || (scale * brush->height()) <= 0.01) return 1.0; setCurrentScale(scale); - /* Align a point that represents the top-left corner of the brush-stroke-rendering - with the mouse pointer and take into account the brush mask size */ + // Align a point that represents the top-left corner of the brush-stroke-rendering + // with the mouse pointer and take into account the brush mask size QPointF hotSpot = brush->hotSpot(scale, scale); QPointF pt = info.pos() - hotSpot; - /* Split the coordinates into integer plus fractional parts. The integer - is where the dab will be positioned and the fractional part determines - the sub-pixel positioning. */ + // Split the coordinates into integer plus fractional parts. The integer + //is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. qint32 x, y; qreal xFraction, yFraction; @@ -141,17 +208,17 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) qint32 sw = maskDab->bounds().width(); qint32 sh = maskDab->bounds().height(); - /* Prepare the top left corner of the temporary paint device where the extracted color will be drawn */ + // Prepare the top left corner of the temporary paint device where the extracted color will be drawn QPoint extractionTopLeft = QPoint(ANCHOR_POINT.x() - sw / 2, ANCHOR_POINT.y() - sh / 2); - /* In the block below, the opacity of the colors stored in m_tempDev - is reduced in opacity. Nothing of the color present inside it is left out */ + // In the block below, the opacity of the colors stored in m_tempDev + // is reduced in opacity. Nothing of the color present inside it is left out quint8 opacity = OPACITY_OPAQUE_U8; if (!m_firstRun) { opacity = m_rateOption.apply(opacity, info); - /* Without those limits, the smudge brush doesn't smudge anymore, it either makes a single - dropplet of color, or drags a frame indefinitely over the canvas. */ + // Without those limits, the smudge brush doesn't smudge anymore, it either makes a single + // dropplet of color, or drags a frame indefinitely over the canvas. opacity = qBound(MIXABLE_LOWER_LIMIT, opacity, MIXABLE_UPPER_LIMIT); // Invert the opacity value for color absorption in the next lines (copyPainter) @@ -162,9 +229,9 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) m_firstRun = false; m_wholeTempData = QRect(extractionTopLeft, maskDab->bounds().size()); } - /* copyPainter will extract the piece of color (image) to be duplicated to generate the smudge effect, - it extracts a simple unmasked rectangle and adds it to what was extracted before in this same block of code, - this sometimes shows artifacts when the brush is used with stylus and high spacing */ + // copyPainter will extract the piece of color (image) to be duplicated to generate the smudge effect, + // it extracts a simple unmasked rectangle and adds it to what was extracted before in this same block of code, + // this sometimes shows artifacts when the brush is used with stylus and high spacing KisPainter copyPainter(m_tempDev); copyPainter.setCompositeOp(COMPOSITE_COPY); copyPainter.setOpacity(opacity); @@ -179,4 +246,4 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) renderMirrorMask(QRect(QPoint(x,y),QSize(sw,sh)),m_tempDev,extractionTopLeft.x(), extractionTopLeft.y(),maskDab); return spacing(scale); -} +}//*/ diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h index 6e3e63f..35a5b64 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h @@ -31,6 +31,7 @@ #include #include #include +#include class KisBrushBasedPaintOpSettings; @@ -56,8 +57,8 @@ private: KoColor m_color; KisPressureSizeOption m_sizeOption; - KisPressureOpacityOption m_opacityOption; KisPressureRateOption m_rateOption; + KisPressureCompositeOption m_compositeOption; }; #endif // KIS_SMUDGEOP_H_ diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp index 07a70ca..3f01533 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp @@ -24,12 +24,13 @@ #include "kis_brush_based_paintop_settings.h" #include #include -#include -#include #include +#include #include #include #include +#include + KisSmudgeOpSettingsWidget::KisSmudgeOpSettingsWidget(QWidget* parent) : KisBrushBasedPaintopOptionWidget(parent) @@ -37,9 +38,8 @@ KisSmudgeOpSettingsWidget::KisSmudgeOpSettingsWidget(QWidget* parent) setObjectName("brush option widget"); addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption())); - addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption())); - addPaintOpOption(new KisCurveOptionWidget(new KisPressureDarkenOption)); addPaintOpOption(new KisPressureRateOptionWidget()); + addPaintOpOption(new KisPressureCompositeOptionWidget()); } @@ -51,7 +51,7 @@ KisPropertiesConfiguration* KisSmudgeOpSettingsWidget::configuration() const { KisBrushBasedPaintOpSettings *config = new KisBrushBasedPaintOpSettings(); config->setOptionsWidget(const_cast(this)); - config->setProperty("paintop", "smudge"); // XXX: make this a const id string + config->setProperty("paintop", "smudge"); // TODO: make this a const id string writeConfiguration(config); return config; } diff --git a/krita/plugins/paintops/libpaintop/CMakeLists.txt b/krita/plugins/paintops/libpaintop/CMakeLists.txt index 996cafc..b0bc55d 100644 --- a/krita/plugins/paintops/libpaintop/CMakeLists.txt +++ b/krita/plugins/paintops/libpaintop/CMakeLists.txt @@ -38,6 +38,8 @@ set(kritalibpaintop_LIB_SRCS kis_pressure_size_option.cpp kis_pressure_softness_option.cpp kis_pressure_mix_option.cpp + kis_pressure_composite_option.cpp + kis_pressure_composite_option_widget.cpp kis_sensor_selector.cc kis_text_brush_chooser.cpp kis_brush_based_paintop_options_widget.cpp diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp new file mode 100644 index 0000000..18a9882 --- /dev/null +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + * Copyright (C) Boudewijn Rempt , (C) 2008 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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 "kis_pressure_composite_option.h" + + +#include + +#include +#include + +#include +#include +#include + +KisPressureCompositeOption::KisPressureCompositeOption() + : KisCurveOption(i18n("Color"), "Color", KisPaintOpOption::brushCategory(), false) +{ + setMinimumLabel(i18n("Full Color")); + setMaximumLabel(i18n("No Color")); +} + +void KisPressureCompositeOption::writeOptionSetting(KisPropertiesConfiguration* setting) const +{ + KisCurveOption::writeOptionSetting(setting); + setting->setProperty("CompositeOp", m_compositeOp); + setting->setProperty("CompositeRateValue", m_rate); +} + +void KisPressureCompositeOption::readOptionSetting(const KisPropertiesConfiguration* setting) +{ + KisCurveOption::readOptionSetting(setting); + m_compositeOp = setting->getString("CompositeOp"); + m_rate = setting->getInt("CompositeRateValue"); + + if(m_compositeOp == "") //TODO: test if compositeOp is valid instead of just testing for an empty string + m_compositeOp = COMPOSITE_OVER; +} + +QString KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) const +{ + if(!isChecked()) + return painter->compositeOp()->id(); + + QString oldCompositeOp = painter->compositeOp()->id(); + + opacity = (m_rate * 255) / 100; + opacity = qBound((qint32)OPACITY_TRANSPARENT_U8, + (qint32)(double(opacity) * computeValue(info) / PRESSURE_DEFAULT), + (qint32)OPACITY_OPAQUE_U8); + + //qreal opacity1 = (qreal)(painter->opacity() * computeValue(info)); + //quint8 opacity2 = (quint8)qRound(qBound(OPACITY_TRANSPARENT_U8, opacity1, OPACITY_OPAQUE_U8)); + + painter->setCompositeOp(m_compositeOp); + painter->setOpacity(opacity); + + return oldCompositeOp; +} + diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h new file mode 100644 index 0000000..f05642a --- /dev/null +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + * Copyright (C) Boudewijn Rempt , (C) 2008 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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 KIS_PRESSURE_COMPOSITE_OPTION_H +#define KIS_PRESSURE_COMPOSITE_OPTION_H + +#include "kis_curve_option.h" +#include +#include +#include + +class QSlider; +class KisPropertiesConfiguration; +class KisPainter; + +class PAINTOP_EXPORT KisPressureCompositeOption : public KisCurveOption +{ +public: + KisPressureCompositeOption(); + + /** + * Set the composite mode and opacity of the painter based on the pressure + * and the curve (if checked) and return the old composite mode + * of the painter. + */ + QString apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) const; + + void writeOptionSetting(KisPropertiesConfiguration* setting) const; + void readOptionSetting(const KisPropertiesConfiguration* setting); + + void setCompositeOp(const QString& compositeOp) { m_compositeOp = compositeOp; } + QString getCompositeOp() { return m_compositeOp; } + + void setRate(int rate) { m_rate = rate; } + int getRate() { return m_rate; } + +private: + QString m_compositeOp; + int m_rate; +}; + +#endif // KIS_PRESSURE_COMPOSITE_OPTION_H diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp new file mode 100644 index 0000000..140c628 --- /dev/null +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp @@ -0,0 +1,104 @@ +/* This file is part of the KDE project + * Copyright (C) Boudewijn Rempt , (C) 2008 + * Copyright (C) Sven Langkamp , (C) 2009 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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 "kis_pressure_composite_option_widget.h" +#include "kis_pressure_composite_option.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +KisPressureCompositeOptionWidget::KisPressureCompositeOptionWidget() + : KisCurveOptionWidget(new KisPressureCompositeOption()) +{ + QWidget* widget = new QWidget; + QLabel* modeLabel = new QLabel(i18n("Mode: ")); + QLabel* rateLabel = new QLabel(i18n("Rate: ")); + + m_compositeOpBox = new QComboBox(); + m_compositeOpBox->addItem(COMPOSITE_OVER); + m_compositeOpBox->addItem(COMPOSITE_OVERLAY); + m_compositeOpBox->addItem(COMPOSITE_SCREEN); + m_compositeOpBox->addItem(COMPOSITE_ADD); + m_compositeOpBox->addItem(COMPOSITE_SUBTRACT); + + m_rateSlider = new QSlider(); + m_rateSlider->setMinimum(0); + m_rateSlider->setMaximum(100); + m_rateSlider->setPageStep(1); + m_rateSlider->setValue(90); + m_rateSlider->setOrientation(Qt::Horizontal); + + connect(m_compositeOpBox, SIGNAL(activated(QString)), this, SLOT(compositeOpChanged(QString))); + connect(m_rateSlider, SIGNAL(valueChanged(int)), this, SLOT(rateChanged(int))); + + QGridLayout* gridLayout = new QGridLayout(); + gridLayout->addWidget(modeLabel, 0, 0); + gridLayout->addWidget(m_compositeOpBox, 0, 1); + gridLayout->addWidget(rateLabel, 1, 0); + gridLayout->addWidget(m_rateSlider, 1, 1); + + QVBoxLayout* vBoxLayout = new QVBoxLayout; + vBoxLayout->addLayout(gridLayout); + vBoxLayout->addWidget(curveWidget()); + + widget->setLayout(vBoxLayout); + + setConfigurationPage(widget); + + compositeOpChanged(COMPOSITE_OVER); + rateChanged(m_rateSlider->value()); +} + +void KisPressureCompositeOptionWidget::readOptionSetting(const KisPropertiesConfiguration* setting) +{ + KisCurveOptionWidget::readOptionSetting(setting); + + QString compositeOp = static_cast(curveOption())->getCompositeOp(); + + for(int i=0; icount(); ++i) { + if(m_compositeOpBox->itemText(i) == compositeOp) { + m_compositeOpBox->setCurrentIndex(i); + break; + } + } + + m_rateSlider->setValue(static_cast(curveOption())->getRate()); +} + +void KisPressureCompositeOptionWidget::compositeOpChanged(const QString& compositeOp) +{ + static_cast(curveOption())->setCompositeOp(compositeOp); + emit sigSettingChanged(); +} + +void KisPressureCompositeOptionWidget::rateChanged(int rate) +{ + static_cast(curveOption())->setRate(rate); + emit sigSettingChanged(); +} diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h new file mode 100644 index 0000000..6660f72 --- /dev/null +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + * Copyright (C) Sven Langkamp , (C) 2009 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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 KIS_PRESSURE_COMPOSITE_OPTION_WIDGET_H +#define KIS_PRESSURE_COMPOSITE_OPTION_WIDGET_H + +#include "kis_curve_option_widget.h" + +class QComboBox; +class QSlider; + +class PAINTOP_EXPORT KisPressureCompositeOptionWidget : public KisCurveOptionWidget +{ + Q_OBJECT + +public: + KisPressureCompositeOptionWidget(); + + void readOptionSetting(const KisPropertiesConfiguration* setting); + +private slots: + void compositeOpChanged(const QString& compositeOp); + void rateChanged(int rate); + +private: + QComboBox* m_compositeOpBox; + QSlider* m_rateSlider; +}; + +#endif // KIS_PRESSURE_COMPOSITE_OPTION_WIDGET_H -- 1.7.1 From 11e99bf63e2cff5667b3a2314eaa7e724ac8de37 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Fri, 31 Dec 2010 21:28:09 +0100 Subject: [PATCH 2/6] Some cleanup and documentation and added more composite modes to KisPressureCompositeOptionWidget. --- .../defaultpaintops/smudge/kis_smudgeop.cpp | 163 ++++---------------- .../paintops/defaultpaintops/smudge/kis_smudgeop.h | 8 +- .../libpaintop/kis_pressure_composite_option.cpp | 7 +- .../libpaintop/kis_pressure_composite_option.h | 7 +- .../kis_pressure_composite_option_widget.cpp | 6 + 5 files changed, 42 insertions(+), 149 deletions(-) diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index c8dde6d..372a1b7 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp @@ -40,19 +40,8 @@ #include #include - -// Both limits defined to be 15 units away from the min (0) or max (255) to allow actual mixing of colors -const quint8 MIXABLE_UPPER_LIMIT = 240; -const quint8 MIXABLE_LOWER_LIMIT = 15; - -// All pieces of color extracted from the canvas will be centered around ANCHOR_POINT -const QPoint ANCHOR_POINT = QPoint(0, 0); - - KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings *settings, KisPainter *painter, KisImageWSP image) - : KisBrushBasedPaintOp(settings, painter) - , m_firstRun(true) - , m_tempDev(0) + : KisBrushBasedPaintOp(settings, painter), m_tempDev(0) { Q_UNUSED(image); Q_ASSERT(settings); @@ -65,11 +54,6 @@ KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings *settings, KisPainte m_compositeOption.sensor()->reset(); m_tempDev = new KisPaintDevice(painter->device()->colorSpace()); - - // Initializing to a valid value to avoid weird errors during modifications - m_wholeTempData = QRect(0, 0, 0, 0); - - m_color = painter->paintColor(); } KisSmudgeOp::~KisSmudgeOp() @@ -89,8 +73,10 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) if(!brush || !brush->canPaintFor(info)) return 1.0; + // get the scaling factor calculated by the size option double scale = m_sizeOption.apply(info); + // don't paint anything if the brush is too samll if((scale*brush->width()) <= 0.01 || (scale*brush->height()) <= 0.01) return 1.0; @@ -105,7 +91,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) KisFixedPaintDeviceSP maskDab = cachedDab(painter()->device()->colorSpace()); - // Extract the brush mask (maskDab) from brush, and turn it into a transparency mask (alpha8). + // Extract the brush mask (maskDab) from brush with the correct scaled size if(brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { // This is for bitmap brushes maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, info, xFraction, yFraction); @@ -115,135 +101,46 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) brush->mask(maskDab, painter()->paintColor(), scale, scale, 0.0, info, xFraction, yFraction); } + // transforms the fixed paint device with the current brush to alpha color space (to use it as alpha/transparency mask) maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8()); - KisPainter copyPainter(m_tempDev); - - if(m_compositeOption.isChecked()) { - m_compositeOption.apply(©Painter, OPACITY_OPAQUE_U8, info); - - copyPainter.setFillStyle(KisPainter::FillStyleForegroundColor); - copyPainter.setPaintColor(painter()->paintColor()); - copyPainter.paintRect(maskDab->bounds()); - } - + // GET the opacy calculated by the rate option (apply is misleading because the opacy will not be applied) quint8 newOpacity = m_rateOption.apply(OPACITY_OPAQUE_U8, info); + // set opacity calculated by the rate option + // then blit the temporary painting device on the canvas at the current brush position + // the alpha mask (maskDab) will be used here to only blit the pixels that lie in the area (shape) of the brush painter()->setOpacity(newOpacity); painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height()); - //painter()->bitBlt(QPoint(x,y), m_tempDev, dab->bounds()); + // IMPORTANT: clear the temporary painting device to color black with zero opacity + // it will only clear the extents of the brush m_tempDev->clear(maskDab->bounds()); + KisPainter copyPainter(m_tempDev); + + // reset composite mode and opacity + // then cut out the area from the canvas under the brush + // and blit it to the temporary painting device copyPainter.setCompositeOp(COMPOSITE_OVER); copyPainter.setOpacity(OPACITY_OPAQUE_U8); copyPainter.bitBlt(0, 0, painter()->device(), x, y, maskDab->bounds().width(), maskDab->bounds().height()); - copyPainter.end(); - - return spacing(scale); -} - - -/* To smudge, one does the following: - * - 1 *.- First step: initialize a temporary paint device (m_tempDev) with a copy of the colors below the mouse pointer. - All other times: - 2.- Vanishing step: Reduce the transparency of the temporary paint device so as to let it mix gradually. - 3.- Combine: Combine the temporary device with the piece the brush currently is 'painting', according to a ratio: - in this case, opacity. (This is what in the first step does the copying of the data). - 4.- Blit to screen: This combination is then composited upon the actual image. - 5.- Special case: If the size of the dab (brush mask) changes during the stroke (for example, when - using a stylus sensitive to pressure), align the colors extracted to the center of the previously absorbed colors, - and in the vanishing step, ensure that all the colors have their opacity slowly reduced, not just the ones below - the current brush mask. - - For the sake of speed optimization, the extent of the largest area of color contained in the - temporary device is cached such that only the colored areas are considered. - TODO: Make this cached value dump colors that have faded nearly completely and lie outside of the rectangle (dab) - of the current iteration. - * -qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) -{ - KisBrushSP brush = m_brush; - // Simple error catching - if (!painter()->device()) return 1.0; - if (!brush) return 1.0; - if (!brush->canPaintFor(info)) return 1.0; - - // Grow the brush (this includes the mask) according to pressure or other parameters - double scale = m_sizeOption.apply(info); - if ((scale * brush->width()) <= 0.01 || (scale * brush->height()) <= 0.01) return 1.0; - setCurrentScale(scale); - - // Align a point that represents the top-left corner of the brush-stroke-rendering - // with the mouse pointer and take into account the brush mask size - QPointF hotSpot = brush->hotSpot(scale, scale); - QPointF pt = info.pos() - hotSpot; - - // Split the coordinates into integer plus fractional parts. The integer - //is where the dab will be positioned and the fractional part determines - // the sub-pixel positioning. - qint32 x, y; - qreal xFraction, yFraction; - - splitCoordinate(pt.x(), &x, &xFraction); - splitCoordinate(pt.y(), &y, &yFraction); - - KisFixedPaintDeviceSP maskDab = 0; - - // Extract the brush mask (maskDab) from brush, and turn it into a transparency mask (alpha8). - if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { - // This is for bitmap brushes - maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, info, xFraction, yFraction); - maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8()); - } else { - // This is for parametric brushes, those created in the Autobrush popup config dialogue - maskDab = cachedDab(); - brush->mask(maskDab, m_color, scale, scale, 0.0, info, xFraction, yFraction); - maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8()); - } - - // Convenient renaming for the limits of the maskDab - qint32 sw = maskDab->bounds().width(); - qint32 sh = maskDab->bounds().height(); - - // Prepare the top left corner of the temporary paint device where the extracted color will be drawn - QPoint extractionTopLeft = QPoint(ANCHOR_POINT.x() - sw / 2, - ANCHOR_POINT.y() - sh / 2); - - // In the block below, the opacity of the colors stored in m_tempDev - // is reduced in opacity. Nothing of the color present inside it is left out - quint8 opacity = OPACITY_OPAQUE_U8; - if (!m_firstRun) { - opacity = m_rateOption.apply(opacity, info); - // Without those limits, the smudge brush doesn't smudge anymore, it either makes a single - // dropplet of color, or drags a frame indefinitely over the canvas. - opacity = qBound(MIXABLE_LOWER_LIMIT, opacity, MIXABLE_UPPER_LIMIT); - - // Invert the opacity value for color absorption in the next lines (copyPainter) - opacity = OPACITY_OPAQUE_U8 - opacity; - m_wholeTempData |= QRect(extractionTopLeft, maskDab->bounds().size()); - } - else { - m_firstRun = false; - m_wholeTempData = QRect(extractionTopLeft, maskDab->bounds().size()); + // if the user selected the color smudge option + // we will mix some color into the temorary painting device (m_tempDev) + if(m_compositeOption.isChecked()) { + // this will apply the composite mode and the opacy (selected by the user) + // to copyPainter + m_compositeOption.apply(©Painter, OPACITY_OPAQUE_U8, info); + + // paint a rectangle with the current color (foreground color) + // into the temporary painting device + copyPainter.setFillStyle(KisPainter::FillStyleForegroundColor); + copyPainter.setPaintColor(painter()->paintColor()); + copyPainter.paintRect(maskDab->bounds()); } - // copyPainter will extract the piece of color (image) to be duplicated to generate the smudge effect, - // it extracts a simple unmasked rectangle and adds it to what was extracted before in this same block of code, - // this sometimes shows artifacts when the brush is used with stylus and high spacing - KisPainter copyPainter(m_tempDev); - copyPainter.setCompositeOp(COMPOSITE_COPY); - copyPainter.setOpacity(opacity); - copyPainter.bitBlt(m_wholeTempData.x(), m_wholeTempData.y(), painter()->device(), - x - m_wholeTempData.x() + extractionTopLeft.x(), - y - m_wholeTempData.y() + extractionTopLeft.y(), - m_wholeTempData.width(), m_wholeTempData.height()); - copyPainter.end(); - // This is the line that renders the extracted colors to the screen, with maskDab giving it the brush shape - painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, 0, 0, extractionTopLeft.x(), extractionTopLeft.y(), sw, sh); - renderMirrorMask(QRect(QPoint(x,y),QSize(sw,sh)),m_tempDev,extractionTopLeft.x(), extractionTopLeft.y(),maskDab); + copyPainter.end(); return spacing(scale); -}//*/ +} diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h index 35a5b64..5948e04 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h @@ -49,13 +49,7 @@ public: qreal paintAt(const KisPaintInformation& info); private: - bool m_firstRun; - // The "temporary paint device" - KisPaintDeviceSP m_tempDev; - // The size of the rectangle encompassing the whole data in the temporary device needs to be cached for speed - QRect m_wholeTempData; - KoColor m_color; - + KisPaintDeviceSP m_tempDev; // The temporary paint device KisPressureSizeOption m_sizeOption; KisPressureRateOption m_rateOption; KisPressureCompositeOption m_compositeOption; diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp index 18a9882..ca09eb6 100644 --- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp @@ -30,7 +30,7 @@ #include KisPressureCompositeOption::KisPressureCompositeOption() - : KisCurveOption(i18n("Color"), "Color", KisPaintOpOption::brushCategory(), false) + : KisCurveOption(i18n("Color"), "Color", KisPaintOpOption::brushCategory(), false) { setMinimumLabel(i18n("Full Color")); setMaximumLabel(i18n("No Color")); @@ -53,7 +53,7 @@ void KisPressureCompositeOption::readOptionSetting(const KisPropertiesConfigurat m_compositeOp = COMPOSITE_OVER; } -QString KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) const +void KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) const { if(!isChecked()) return painter->compositeOp()->id(); @@ -65,9 +65,6 @@ QString KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, co (qint32)(double(opacity) * computeValue(info) / PRESSURE_DEFAULT), (qint32)OPACITY_OPAQUE_U8); - //qreal opacity1 = (qreal)(painter->opacity() * computeValue(info)); - //quint8 opacity2 = (quint8)qRound(qBound(OPACITY_TRANSPARENT_U8, opacity1, OPACITY_OPAQUE_U8)); - painter->setCompositeOp(m_compositeOp); painter->setOpacity(opacity); diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h index f05642a..2ba3d8b 100644 --- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h @@ -35,11 +35,10 @@ public: KisPressureCompositeOption(); /** - * Set the composite mode and opacity of the painter based on the pressure - * and the curve (if checked) and return the old composite mode - * of the painter. + * Set the composite mode and opacity of the painter based on the user selection + * and the pressure curve (if checked) */ - QString apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) const; + void apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) const; void writeOptionSetting(KisPropertiesConfiguration* setting) const; void readOptionSetting(const KisPropertiesConfiguration* setting); diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp index 140c628..6f17544 100644 --- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp @@ -46,6 +46,12 @@ KisPressureCompositeOptionWidget::KisPressureCompositeOptionWidget() m_compositeOpBox->addItem(COMPOSITE_SCREEN); m_compositeOpBox->addItem(COMPOSITE_ADD); m_compositeOpBox->addItem(COMPOSITE_SUBTRACT); + m_compositeOpBox->addItem(COMPOSITE_DIVIDE); + m_compositeOpBox->addItem(COMPOSITE_BURN); + m_compositeOpBox->addItem(COMPOSITE_DODGE); + m_compositeOpBox->addItem(COMPOSITE_COLOR); + m_compositeOpBox->addItem(COMPOSITE_HARD_LIGHT); + m_compositeOpBox->addItem(COMPOSITE_SOFT_LIGHT); m_rateSlider = new QSlider(); m_rateSlider->setMinimum(0); -- 1.7.1 From aa6eb274013a01d46d97d05a6a45f4f3ff9bc2e5 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Mon, 3 Jan 2011 00:43:51 +0100 Subject: [PATCH 3/6] Fixed the handling of transparency for the smudge brush. Implemented the COMPOSITE_COPY_OPACY mode to fix it --- .../defaultpaintops/smudge/kis_smudgeop.cpp | 28 +++-- .../paintops/defaultpaintops/smudge/kis_smudgeop.h | 2 + .../smudge/kis_smudgeop_settings_widget.cpp | 1 + .../libpaintop/kis_pressure_composite_option.cpp | 10 +- .../libpaintop/kis_pressure_composite_option.h | 2 +- .../kis_pressure_composite_option_widget.cpp | 3 +- .../kis_pressure_composite_option_widget.h | 2 +- libs/pigment/compositeops/KoCompositeOpCopyOpacy.h | 133 ++++++++++++++++++++ libs/pigment/compositeops/KoCompositeOps.h | 5 +- 9 files changed, 165 insertions(+), 21 deletions(-) create mode 100644 libs/pigment/compositeops/KoCompositeOpCopyOpacy.h diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index 372a1b7..0dabf9a 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp @@ -6,6 +6,7 @@ * Copyright (c) 2004,2010 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara Toloza + * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -53,7 +54,8 @@ KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings *settings, KisPainte m_rateOption.sensor()->reset(); m_compositeOption.sensor()->reset(); - m_tempDev = new KisPaintDevice(painter->device()->colorSpace()); + m_tempDev = new KisPaintDevice(painter->device()->colorSpace()); + m_firstRun = true; } KisSmudgeOp::~KisSmudgeOp() @@ -89,7 +91,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) splitCoordinate(point.x(), &x, &xFraction); splitCoordinate(point.y(), &y, &yFraction); - KisFixedPaintDeviceSP maskDab = cachedDab(painter()->device()->colorSpace()); + KisFixedPaintDeviceSP maskDab = 0; // Extract the brush mask (maskDab) from brush with the correct scaled size if(brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { @@ -107,15 +109,22 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) // GET the opacy calculated by the rate option (apply is misleading because the opacy will not be applied) quint8 newOpacity = m_rateOption.apply(OPACITY_OPAQUE_U8, info); - // set opacity calculated by the rate option - // then blit the temporary painting device on the canvas at the current brush position - // the alpha mask (maskDab) will be used here to only blit the pixels that lie in the area (shape) of the brush - painter()->setOpacity(newOpacity); - painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height()); + if(!m_firstRun) { + // set opacity calculated by the rate option + // then blit the temporary painting device on the canvas at the current brush position + // the alpha mask (maskDab) will be used here to only blit the pixels that lie in the area (shape) of the brush + painter()->setOpacity(newOpacity / 2); + painter()->setCompositeOp(COMPOSITE_OVER); + painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height()); + painter()->setOpacity(newOpacity); + painter()->setCompositeOp(COMPOSITE_COPY_OPACITY); + painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height()); + } + else m_firstRun = false; // IMPORTANT: clear the temporary painting device to color black with zero opacity // it will only clear the extents of the brush - m_tempDev->clear(maskDab->bounds()); + m_tempDev->clear(QRect(0, 0, brush->width(), brush->height())); KisPainter copyPainter(m_tempDev); @@ -124,7 +133,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) // and blit it to the temporary painting device copyPainter.setCompositeOp(COMPOSITE_OVER); copyPainter.setOpacity(OPACITY_OPAQUE_U8); - copyPainter.bitBlt(0, 0, painter()->device(), x, y, maskDab->bounds().width(), maskDab->bounds().height()); + copyPainter.bitBlt(0, 0, painter()->device(), x, y, brush->width(), brush->width()); // if the user selected the color smudge option // we will mix some color into the temorary painting device (m_tempDev) @@ -141,6 +150,5 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) } copyPainter.end(); - return spacing(scale); } diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h index 5948e04..333df09 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h @@ -5,6 +5,7 @@ * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2010 José Luis Vergara Toloza + * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,6 +50,7 @@ public: qreal paintAt(const KisPaintInformation& info); private: + bool m_firstRun; KisPaintDeviceSP m_tempDev; // The temporary paint device KisPressureSizeOption m_sizeOption; KisPressureRateOption m_rateOption; diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp index 3f01533..a07d7f4 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp @@ -4,6 +4,7 @@ * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger + * Copyright (C) 2011 Silvio Heinrich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp index ca09eb6..6d82865 100644 --- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp @@ -1,5 +1,5 @@ /* This file is part of the KDE project - * Copyright (C) Boudewijn Rempt , (C) 2008 + * Copyright (C) Silvio Heinrich , (C) 2011 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,8 +32,8 @@ KisPressureCompositeOption::KisPressureCompositeOption() : KisCurveOption(i18n("Color"), "Color", KisPaintOpOption::brushCategory(), false) { - setMinimumLabel(i18n("Full Color")); - setMaximumLabel(i18n("No Color")); + setMinimumLabel(i18n("No Color")); + setMaximumLabel(i18n("Full Color")); } void KisPressureCompositeOption::writeOptionSetting(KisPropertiesConfiguration* setting) const @@ -56,7 +56,7 @@ void KisPressureCompositeOption::readOptionSetting(const KisPropertiesConfigurat void KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) const { if(!isChecked()) - return painter->compositeOp()->id(); + return; QString oldCompositeOp = painter->compositeOp()->id(); @@ -67,7 +67,5 @@ void KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const painter->setCompositeOp(m_compositeOp); painter->setOpacity(opacity); - - return oldCompositeOp; } diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h index 2ba3d8b..1ed6ff7 100644 --- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h @@ -1,5 +1,5 @@ /* This file is part of the KDE project - * Copyright (C) Boudewijn Rempt , (C) 2008 + * Copyright (C) Silvio Heinrich , (C) 2011 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp index 6f17544..f075a3c 100644 --- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp @@ -1,6 +1,5 @@ /* This file is part of the KDE project - * Copyright (C) Boudewijn Rempt , (C) 2008 - * Copyright (C) Sven Langkamp , (C) 2009 + * Copyright (C) Silvio Heinrich , (C) 2011 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h index 6660f72..30c09ce 100644 --- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h +++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h @@ -1,5 +1,5 @@ /* This file is part of the KDE project - * Copyright (C) Sven Langkamp , (C) 2009 + * Copyright (C) Silvio Heinrich , (C) 2011 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h new file mode 100644 index 0000000..97dcbfd --- /dev/null +++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2008 Silvio Heinrich + * + * 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. +*/ + +#ifndef KOCOMPOSITEOPCOPYOPACY_H_ +#define KOCOMPOSITEOPCOPYOPACY_H_ + +#include +#include +#include + +/** + * A template version of the copy opacy composite operation to use in colorspaces. + */ +template +class KoCompositeOpCopyOpacy : public KoCompositeOp +{ + typedef typename _CSTraits::channels_type channels_type; + static const qint32 channels_nb = _CSTraits::channels_nb; + static const qint32 alpha_pos = _CSTraits::alpha_pos; + static const qint32 pixelSize = _CSTraits::pixelSize; + +public: + KoCompositeOpCopyOpacy(const KoColorSpace * cs) + : KoCompositeOp(cs, COMPOSITE_COPY_OPACITY, i18n("Copy Opacy"), KoCompositeOp::categoryArithmetic(), true) { + } + +public: + inline static channels_type selectAlpha(channels_type srcAlpha, channels_type dstAlpha) { + return qMin(srcAlpha, dstAlpha); + } + + void composite(quint8 *dstRowStart, + qint32 dstRowStride, + const quint8 *srcRowStart, + qint32 srcRowStride, + const quint8 *maskRowStart, + qint32 maskRowStride, + qint32 rows, + qint32 cols, + quint8 U8_opacity, + const QBitArray & channelFlags) const + { + bool useMask = maskRowStart != 0; + channels_type opacity = KoColorSpaceMaths::scaleToA(U8_opacity); + + if(srcRowStride != 0) { + for(; rows>0; --rows) { + const quint8* mskRowItr = maskRowStart; + const channels_type* srcRowItr = reinterpret_cast(srcRowStart) + alpha_pos; + channels_type* dstRowItr = reinterpret_cast(dstRowStart) + alpha_pos; + + for(qint32 c=cols; c>0; --c) { + channels_type value = 0; + + switch(U8_opacity) + { + case OPACITY_TRANSPARENT_U8: { value = *dstRowItr; } break; + case OPACITY_OPAQUE_U8: { value = *srcRowItr; } break; + default: { value = KoColorSpaceMaths::blend(*srcRowItr, *dstRowItr, opacity); } break; + } + + if(useMask) { + channels_type blend = KoColorSpaceMaths::scaleToA(*mskRowItr); + value = KoColorSpaceMaths::blend(value, *dstRowItr, blend); + value = (value > *dstRowItr) ? (value-1) : value; + ++mskRowItr; + } + + *dstRowItr = value; + srcRowItr += channels_nb; + dstRowItr += channels_nb; + + } + + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + maskRowStart += maskRowStride; + } + } + else { + channels_type srcValue = *(reinterpret_cast(srcRowStart) + alpha_pos); + + for(; rows>0; --rows) { + const quint8* mskRowItr = maskRowStart; + channels_type* dstRowItr = reinterpret_cast(dstRowStart) + alpha_pos; + + for(qint32 c=cols; c>0; --c) { + channels_type value = 0; + + switch(U8_opacity) + { + case OPACITY_TRANSPARENT_U8: { value = *dstRowItr; } break; + case OPACITY_OPAQUE_U8: { value = srcValue; } break; + default: { value = KoColorSpaceMaths::blend(srcValue, *dstRowItr, opacity); } break; + } + + if(useMask) { + channels_type blend = KoColorSpaceMaths::scaleToA(*mskRowItr); + value = KoColorSpaceMaths::blend(value, *dstRowItr, blend); + value = (value > *dstRowItr) ? (value-1) : value; + ++mskRowItr; + } + + *dstRowItr = value; + dstRowItr += channels_nb; + } + + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + maskRowStart += maskRowStride; + } + } + } + +}; + +#endif // KOCOMPOSITEOPCOPYOPACY_H_ diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index d278234..b222f32 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2007 Cyrille Berger + * Copyright (c) 2007 Cyrille Berger + * Copyright (c) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,6 +38,7 @@ #include "compositeops/KoCompositeOpSoftlight.h" #include "compositeops/KoCompositeOpHardlight.h" #include "compositeops/KoCompositeOpCopy2.h" +#include "compositeops/KoCompositeOpCopyOpacy.h" /** * This function add to the colorspace all the composite ops defined by @@ -59,6 +61,7 @@ void addStandardCompositeOps(KoColorSpace* cs) cs->addCompositeOp(new KoCompositeOpSubtract<_Traits_>(cs)); cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); + cs->addCompositeOp(new KoCompositeOpCopyOpacy<_Traits_>(cs)); } #endif -- 1.7.1 From bf5ed07167a9bd844c5c0aa608488a26b0d6367b Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Mon, 3 Jan 2011 21:34:41 +0100 Subject: [PATCH 4/6] Fixed some gliches introducing transparency and black color where it should not be. --- .../defaultpaintops/smudge/kis_smudgeop.cpp | 6 +++--- libs/pigment/compositeops/KoCompositeOpCopyOpacy.h | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index 0dabf9a..ef48e1f 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp @@ -87,7 +87,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) QPointF point = info.pos() - brush->hotSpot(scale, scale); qint32 x, y; - qreal xFraction, yFraction; + qreal xFraction, yFraction; // will not be used splitCoordinate(point.x(), &x, &xFraction); splitCoordinate(point.y(), &y, &yFraction); @@ -96,11 +96,11 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) // Extract the brush mask (maskDab) from brush with the correct scaled size if(brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { // This is for bitmap brushes - maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, info, xFraction, yFraction); + maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, info, 0.0, 0.0); } else { // This is for parametric brushes, those created in the Autobrush popup config dialogue maskDab = cachedDab(); - brush->mask(maskDab, painter()->paintColor(), scale, scale, 0.0, info, xFraction, yFraction); + brush->mask(maskDab, painter()->paintColor(), scale, scale, 0.0, info, 0.0, 0.0); } // transforms the fixed paint device with the current brush to alpha color space (to use it as alpha/transparency mask) diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h index 97dcbfd..48f63ce 100644 --- a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h +++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h @@ -78,14 +78,13 @@ public: if(useMask) { channels_type blend = KoColorSpaceMaths::scaleToA(*mskRowItr); value = KoColorSpaceMaths::blend(value, *dstRowItr, blend); - value = (value > *dstRowItr) ? (value-1) : value; ++mskRowItr; } + value = (value > *dstRowItr) ? (value-1) : value; *dstRowItr = value; srcRowItr += channels_nb; dstRowItr += channels_nb; - } srcRowStart += srcRowStride; @@ -113,10 +112,10 @@ public: if(useMask) { channels_type blend = KoColorSpaceMaths::scaleToA(*mskRowItr); value = KoColorSpaceMaths::blend(value, *dstRowItr, blend); - value = (value > *dstRowItr) ? (value-1) : value; ++mskRowItr; } + value = (value > *dstRowItr) ? (value-1) : value; *dstRowItr = value; dstRowItr += channels_nb; } @@ -127,7 +126,7 @@ public: } } } - + }; #endif // KOCOMPOSITEOPCOPYOPACY_H_ -- 1.7.1 From f72641b0df5016f8e11085365110e808aeb1edae Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Tue, 4 Jan 2011 00:49:28 +0100 Subject: [PATCH 5/6] Opacity adjustment. --- .../defaultpaintops/smudge/kis_smudgeop.cpp | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index ef48e1f..e03121f 100644 --- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp +++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp @@ -112,8 +112,8 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info) if(!m_firstRun) { // set opacity calculated by the rate option // then blit the temporary painting device on the canvas at the current brush position - // the alpha mask (maskDab) will be used here to only blit the pixels that lie in the area (shape) of the brush - painter()->setOpacity(newOpacity / 2); + // the alpha mask (maskDab) will be used here to only blit the pixels that are in the area (shape) of the brush + painter()->setOpacity(newOpacity); painter()->setCompositeOp(COMPOSITE_OVER); painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height()); painter()->setOpacity(newOpacity); -- 1.7.1 From 1f43c1c7113a98f3f4d42b58932a0679736d7706 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Tue, 4 Jan 2011 00:55:43 +0100 Subject: [PATCH 6/6] Fixed copyright/author information --- libs/pigment/compositeops/KoCompositeOpCopyOpacy.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h index 48f63ce..03a43d2 100644 --- a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h +++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Silvio Heinrich + * Copyright (c) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public -- 1.7.1 --------------060209050507070401070107 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kimageshop mailing list kimageshop@kde.org https://mail.kde.org/mailman/listinfo/kimageshop --------------060209050507070401070107--