From a9f32a28259908779065b2dc462ec875a3ddaddc Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 27 Mar 2021 19:27:52 -0600 Subject: [PATCH 1/4] Add fill tool transparency mode switch --- app/src/tooloptionwidget.cpp | 12 ++++ app/src/tooloptionwidget.h | 1 + app/ui/tooloptions.ui | 63 +++++++++++++++----- core_lib/src/graphics/bitmap/bitmapimage.cpp | 39 ++++++++++-- core_lib/src/graphics/bitmap/bitmapimage.h | 2 +- core_lib/src/managers/toolmanager.cpp | 6 ++ core_lib/src/managers/toolmanager.h | 1 + core_lib/src/tool/basetool.cpp | 6 ++ core_lib/src/tool/basetool.h | 2 + core_lib/src/tool/buckettool.cpp | 23 +++++-- core_lib/src/tool/buckettool.h | 1 + core_lib/src/util/pencildef.h | 1 + 12 files changed, 133 insertions(+), 24 deletions(-) diff --git a/app/src/tooloptionwidget.cpp b/app/src/tooloptionwidget.cpp index 11fdba46f7..23e09e66c2 100644 --- a/app/src/tooloptionwidget.cpp +++ b/app/src/tooloptionwidget.cpp @@ -78,6 +78,7 @@ void ToolOptionWidget::updateUI() setPreserveAlpha(p.preserveAlpha); setVectorMergeEnabled(p.vectorMergeEnabled); setAA(p.useAA); + setFillMode(p.fillMode); setStabilizerLevel(p.stabilizerLevel); setTolerance(static_cast(p.tolerance)); setFillContour(p.useFillContour); @@ -109,6 +110,8 @@ void ToolOptionWidget::makeConnectionToEditor(Editor* editor) connect(ui->vectorMergeBox, &QCheckBox::clicked, toolManager, &ToolManager::setVectorMergeEnabled); connect(ui->useAABox, &QCheckBox::clicked, toolManager, &ToolManager::setAA); + connect(ui->fillMode, static_cast(&QComboBox::activated), toolManager, &ToolManager::setFillMode); + connect(ui->inpolLevelsCombo, static_cast(&QComboBox::activated), toolManager, &ToolManager::setStabilizerLevel); connect(ui->toleranceSlider, &SpinSlider::valueChanged, toolManager, &ToolManager::setTolerance); @@ -135,6 +138,7 @@ void ToolOptionWidget::onToolPropertyChanged(ToolType, ToolPropertyType ePropert case PRESERVEALPHA: setPreserveAlpha(p.preserveAlpha); break; case VECTORMERGE: setVectorMergeEnabled(p.vectorMergeEnabled); break; case ANTI_ALIASING: setAA(p.useAA); break; + case FILL_MODE: setFillMode(p.fillMode); break; case STABILIZATION: setStabilizerLevel(p.stabilizerLevel); break; case TOLERANCE: setTolerance(static_cast(p.tolerance)); break; case FILLCONTOUR: setFillContour(p.useFillContour); break; @@ -157,6 +161,7 @@ void ToolOptionWidget::setVisibility(BaseTool* tool) ui->makeInvisibleBox->setVisible(tool->isPropertyEnabled(INVISIBILITY)); ui->preserveAlphaBox->setVisible(tool->isPropertyEnabled(PRESERVEALPHA)); ui->useAABox->setVisible(tool->isPropertyEnabled(ANTI_ALIASING)); + ui->fillModeGroup->setVisible(tool->isPropertyEnabled(FILL_MODE)); ui->stabilizerLabel->setVisible(tool->isPropertyEnabled(STABILIZATION)); ui->inpolLevelsCombo->setVisible(tool->isPropertyEnabled(STABILIZATION)); ui->toleranceSlider->setVisible(tool->isPropertyEnabled(TOLERANCE)); @@ -187,6 +192,7 @@ void ToolOptionWidget::setVisibility(BaseTool* tool) ui->sizeSlider->setLabel(tr("Stroke Thickness")); ui->toleranceSlider->setVisible(false); ui->toleranceSpinBox->setVisible(false); + ui->fillModeGroup->setVisible(false); break; default: ui->sizeSlider->setLabel(tr("Width")); @@ -299,6 +305,11 @@ void ToolOptionWidget::setAA(int x) } } +void ToolOptionWidget::setFillMode(int x) +{ + ui->fillMode->setCurrentIndex(qBound(0, x, ui->fillMode->count() - 1)); +} + void ToolOptionWidget::setStabilizerLevel(int x) { ui->inpolLevelsCombo->setCurrentIndex(qBound(0, x, ui->inpolLevelsCombo->count() - 1)); @@ -341,6 +352,7 @@ void ToolOptionWidget::disableAllOptions() ui->preserveAlphaBox->hide(); ui->vectorMergeBox->hide(); ui->useAABox->hide(); + ui->fillModeGroup->hide(); ui->inpolLevelsCombo->hide(); ui->toleranceSlider->hide(); ui->toleranceSpinBox->hide(); diff --git a/app/src/tooloptionwidget.h b/app/src/tooloptionwidget.h index 7733ac9929..968a1b263d 100644 --- a/app/src/tooloptionwidget.h +++ b/app/src/tooloptionwidget.h @@ -61,6 +61,7 @@ public slots: void setPreserveAlpha(int); void setVectorMergeEnabled(int); void setAA(int); + void setFillMode(int); void setStabilizerLevel(int); void setTolerance(int); void setFillContour(int); diff --git a/app/ui/tooloptions.ui b/app/ui/tooloptions.ui index 0b576fe525..0bcd20d442 100644 --- a/app/ui/tooloptions.ui +++ b/app/ui/tooloptions.ui @@ -47,21 +47,6 @@ - - 6 - - - 0 - - - 0 - - - 0 - - - 2 - @@ -241,6 +226,54 @@ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Transparency + + + + + + + + 0 + 0 + + + + Defines how the fill will behave when the new color is not opaque + + + + Overlay + + + + + Replace + + + + + + + diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index d5dc50ef8f..d2a5dd6aee 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -794,7 +794,8 @@ void BitmapImage::floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, - int tolerance) + int tolerance, + int fillMode) { // If the point we are supposed to fill is outside the image and camera bounds, do nothing if(!cameraRect.united(targetImage->bounds()).contains(point)) @@ -808,6 +809,15 @@ void BitmapImage::floodFill(BitmapImage* targetImage, QRgb oldColor = targetImage->pixel(point); oldColor = qRgba(qRed(oldColor), qGreen(oldColor), qBlue(oldColor), qAlpha(oldColor)); + QRgb fillColor = newColor; + if (fillMode == 1) + { + QColor tempColor; + tempColor.setRgba(newColor); + tempColor.setAlphaF(1); + fillColor = tempColor.rgba(); + } + // Preparations QList queue; // queue all the pixels of the filled area (as they are found) @@ -844,11 +854,11 @@ void BitmapImage::floodFill(BitmapImage* targetImage, spanLeft = spanRight = false; while (xTemp <= targetImage->mBounds.right() && compareColor(targetImage->constScanLine(xTemp, point.y()), oldColor, tolerance, cache.data()) && - newPlacedColor != newColor) + newPlacedColor != fillColor) { // Set pixel color - replaceImage->scanLine(xTemp, point.y(), newColor); + replaceImage->scanLine(xTemp, point.y(), fillColor); if (!spanLeft && (point.y() > targetImage->mBounds.top()) && compareColor(targetImage->constScanLine(xTemp, point.y() - 1), oldColor, tolerance, cache.data())) { @@ -876,7 +886,28 @@ void BitmapImage::floodFill(BitmapImage* targetImage, } } - targetImage->paste(replaceImage); + switch(fillMode) + { + default: + case 0: + targetImage->paste(replaceImage); + break; + case 1: + BitmapImage fullOpacity(*replaceImage); + if (qAlpha(newColor) == 0xFF) + { + targetImage->paste(replaceImage); + } + else + { + targetImage->paste(replaceImage, QPainter::CompositionMode_DestinationOut); + BitmapImage properColor(targetImage->mBounds, QColor::fromRgba(newColor)); + properColor.paste(replaceImage, QPainter::CompositionMode_DestinationIn); + targetImage->paste(&properColor); + } + break; + } + targetImage->modification(); delete replaceImage; } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index eb3552a262..d362f12fdd 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -75,7 +75,7 @@ class BitmapImage : public KeyFrame void clear(QRectF rectangle) { clear(rectangle.toRect()); } static inline bool compareColor(QRgb newColor, QRgb oldColor, int tolerance, QHash *cache); - static void floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, int tolerance); + static void floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, int tolerance, int fillMode); void drawLine(QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm, bool antialiasing); void drawRect(QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing); diff --git a/core_lib/src/managers/toolmanager.cpp b/core_lib/src/managers/toolmanager.cpp index a28605a58d..91615def27 100644 --- a/core_lib/src/managers/toolmanager.cpp +++ b/core_lib/src/managers/toolmanager.cpp @@ -194,6 +194,12 @@ void ToolManager::setAA(int usingAA) emit toolPropertyChanged(currentTool()->type(), ANTI_ALIASING); } +void ToolManager::setFillMode(int mode) +{ + currentTool()->setFillMode(mode); + emit toolPropertyChanged(currentTool()->type(), FILL_MODE); +} + void ToolManager::setStabilizerLevel(int level) { currentTool()->setStabilizerLevel(level); diff --git a/core_lib/src/managers/toolmanager.h b/core_lib/src/managers/toolmanager.h index 16666cef47..4a552f315f 100644 --- a/core_lib/src/managers/toolmanager.h +++ b/core_lib/src/managers/toolmanager.h @@ -66,6 +66,7 @@ public slots: void setBezier(bool); void setPressure(bool); void setAA(int); + void setFillMode(int); void setStabilizerLevel(int); void setTolerance(int); void setUseFillContour(bool); diff --git a/core_lib/src/tool/basetool.cpp b/core_lib/src/tool/basetool.cpp index fe7ba6ebe9..54890694a4 100644 --- a/core_lib/src/tool/basetool.cpp +++ b/core_lib/src/tool/basetool.cpp @@ -63,6 +63,7 @@ BaseTool::BaseTool(QObject* parent) : QObject(parent) mPropertyEnabled.insert(PRESERVEALPHA, false); mPropertyEnabled.insert(BEZIER, false); mPropertyEnabled.insert(ANTI_ALIASING, false); + mPropertyEnabled.insert(FILL_MODE, false); mPropertyEnabled.insert(STABILIZATION, false); } @@ -443,6 +444,11 @@ void BaseTool::setAA(const int useAA) properties.useAA = useAA; } +void BaseTool::setFillMode(const int mode) +{ + properties.fillMode = mode; +} + void BaseTool::setStabilizerLevel(const int level) { properties.stabilizerLevel = level; diff --git a/core_lib/src/tool/basetool.h b/core_lib/src/tool/basetool.h index 0334ac9986..2d1a87487e 100644 --- a/core_lib/src/tool/basetool.h +++ b/core_lib/src/tool/basetool.h @@ -47,6 +47,7 @@ class Properties bool bezier_state = false; bool useFeather = true; int useAA = 0; + int fillMode = 0; int stabilizerLevel = 0; qreal tolerance = 0; bool useFillContour = false; @@ -113,6 +114,7 @@ class BaseTool : public QObject virtual void setPreserveAlpha(const bool preserveAlpha); virtual void setVectorMergeEnabled(const bool vectorMergeEnabled); virtual void setAA(const int useAA); + virtual void setFillMode(const int mode); virtual void setStabilizerLevel(const int level); virtual void setTolerance(const int tolerance); virtual void setUseFillContour(const bool useFillContour); diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index 8bd252ad63..46bfbc9817 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -47,6 +47,7 @@ void BucketTool::loadSettings() { mPropertyEnabled[TOLERANCE] = true; mPropertyEnabled[WIDTH] = true; + mPropertyEnabled[FILL_MODE] = true; QSettings settings(PENCIL2D, PENCIL2D); @@ -54,6 +55,7 @@ void BucketTool::loadSettings() properties.feather = 10; properties.stabilizerLevel = StabilizationLevel::NONE; properties.useAA = DISABLED; + properties.fillMode = settings.value("fillMode", 0).toInt(); properties.tolerance = settings.value("tolerance", 32.0).toDouble(); } @@ -61,6 +63,7 @@ void BucketTool::resetToDefault() { setWidth(4.0); setTolerance(32.0); + setFillMode(0); } QCursor BucketTool::cursor() @@ -79,6 +82,17 @@ QCursor BucketTool::cursor() } } +void BucketTool::setTolerance(const int tolerance) +{ + // Set current property + properties.tolerance = tolerance; + + // Update settings + QSettings settings(PENCIL2D, PENCIL2D); + settings.setValue("tolerance", tolerance); + settings.sync(); +} + /** * @brief BrushTool::setWidth * @param width @@ -95,14 +109,14 @@ void BucketTool::setWidth(const qreal width) settings.sync(); } -void BucketTool::setTolerance(const int tolerance) +void BucketTool::setFillMode(int mode) { // Set current property - properties.tolerance = tolerance; + properties.fillMode = mode; // Update settings QSettings settings(PENCIL2D, PENCIL2D); - settings.setValue("tolerance", tolerance); + settings.setValue("fillMode", mode); settings.sync(); } @@ -173,7 +187,8 @@ void BucketTool::paintBitmap(Layer* layer) cameraRect, point, qPremultiply(mEditor->color()->frontColor().rgba()), - properties.tolerance); + properties.tolerance, + properties.fillMode); mScribbleArea->setModified(layerNumber, mEditor->currentFrame()); } diff --git a/core_lib/src/tool/buckettool.h b/core_lib/src/tool/buckettool.h index 900e7e44cb..b8331cff8c 100644 --- a/core_lib/src/tool/buckettool.h +++ b/core_lib/src/tool/buckettool.h @@ -41,6 +41,7 @@ class BucketTool : public StrokeTool void setTolerance(const int tolerance) override; void setWidth(const qreal width) override; + void setFillMode(int mode) override; void paintBitmap(Layer* layer); void paintVector(Layer* layer); diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index 9f01776709..6c75527d65 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -55,6 +55,7 @@ enum ToolPropertyType USEFEATHER, VECTORMERGE, ANTI_ALIASING, + FILL_MODE, STABILIZATION, TOLERANCE, FILLCONTOUR From eadd8ae48fc533a2f7ba0ed3822e49513dc50009 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Wed, 21 Apr 2021 20:05:28 -0600 Subject: [PATCH 2/4] Move some of flood fill algorithm to bucket tool --- core_lib/src/graphics/bitmap/bitmapimage.cpp | 43 ++--------------- core_lib/src/graphics/bitmap/bitmapimage.h | 2 +- core_lib/src/tool/buckettool.cpp | 50 +++++++++++++++++--- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index d2a5dd6aee..cdee543a32 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -790,17 +790,16 @@ bool BitmapImage::compareColor(QRgb newColor, QRgb oldColor, int tolerance, QHas // Flood fill // ----- http://lodev.org/cgtutor/floodfill.html -void BitmapImage::floodFill(BitmapImage* targetImage, +BitmapImage* BitmapImage::floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, - QRgb newColor, - int tolerance, - int fillMode) + QRgb fillColor, + int tolerance) { // If the point we are supposed to fill is outside the image and camera bounds, do nothing if(!cameraRect.united(targetImage->bounds()).contains(point)) { - return; + return nullptr; } // Square tolerance for use with compareColor @@ -809,15 +808,6 @@ void BitmapImage::floodFill(BitmapImage* targetImage, QRgb oldColor = targetImage->pixel(point); oldColor = qRgba(qRed(oldColor), qGreen(oldColor), qBlue(oldColor), qAlpha(oldColor)); - QRgb fillColor = newColor; - if (fillMode == 1) - { - QColor tempColor; - tempColor.setRgba(newColor); - tempColor.setAlphaF(1); - fillColor = tempColor.rgba(); - } - // Preparations QList queue; // queue all the pixels of the filled area (as they are found) @@ -886,28 +876,5 @@ void BitmapImage::floodFill(BitmapImage* targetImage, } } - switch(fillMode) - { - default: - case 0: - targetImage->paste(replaceImage); - break; - case 1: - BitmapImage fullOpacity(*replaceImage); - if (qAlpha(newColor) == 0xFF) - { - targetImage->paste(replaceImage); - } - else - { - targetImage->paste(replaceImage, QPainter::CompositionMode_DestinationOut); - BitmapImage properColor(targetImage->mBounds, QColor::fromRgba(newColor)); - properColor.paste(replaceImage, QPainter::CompositionMode_DestinationIn); - targetImage->paste(&properColor); - } - break; - } - - targetImage->modification(); - delete replaceImage; + return replaceImage; } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index d362f12fdd..02522db41d 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -75,7 +75,7 @@ class BitmapImage : public KeyFrame void clear(QRectF rectangle) { clear(rectangle.toRect()); } static inline bool compareColor(QRgb newColor, QRgb oldColor, int tolerance, QHash *cache); - static void floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, int tolerance, int fillMode); + static BitmapImage* floodFill(BitmapImage* targetImage, QRect cameraRect, QPoint point, QRgb newColor, int tolerance); void drawLine(QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm, bool antialiasing); void drawRect(QRectF rectangle, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing); diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index 46bfbc9817..7db1ebe358 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -18,6 +18,7 @@ GNU General Public License for more details. #include #include +#include #include #include #include "pointerevent.h" @@ -183,12 +184,49 @@ void BucketTool::paintBitmap(Layer* layer) QPoint point = QPoint(qFloor(getLastPoint().x()), qFloor(getLastPoint().y())); QRect cameraRect = mScribbleArea->getCameraRect().toRect(); - BitmapImage::floodFill(targetImage, - cameraRect, - point, - qPremultiply(mEditor->color()->frontColor().rgba()), - properties.tolerance, - properties.fillMode); + + QRgb fillColor = qPremultiply(mEditor->color()->frontColor().rgba()); + QRgb origColor = fillColor; + if (properties.fillMode == 1) + { + QColor tempColor; + tempColor.setRgba(fillColor); + tempColor.setAlphaF(1); + fillColor = tempColor.rgba(); + } + + std::unique_ptr fillImage( + BitmapImage::floodFill(targetImage, + cameraRect, + point, + fillColor, + properties.tolerance)); + + if (fillImage == nullptr) + { + return; + } + + switch(properties.fillMode) + { + default: + case 0: + targetImage->paste(fillImage.get()); + break; + case 1: + if (qAlpha(origColor) == 0xFF) + { + targetImage->paste(fillImage.get()); + } + else + { + targetImage->paste(fillImage.get(), QPainter::CompositionMode_DestinationOut); + BitmapImage properColor(targetImage->bounds(), QColor::fromRgba(origColor)); + properColor.paste(fillImage.get(), QPainter::CompositionMode_DestinationIn); + targetImage->paste(&properColor); + } + break; + } mScribbleArea->setModified(layerNumber, mEditor->currentFrame()); } From 77e1daf6e610419791384ebadb8161aba8cb1c0c Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Wed, 21 Apr 2021 20:10:32 -0600 Subject: [PATCH 3/4] Skip overlay filling when fully transparent --- core_lib/src/tool/buckettool.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index 7db1ebe358..5aad744cbc 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -187,7 +187,14 @@ void BucketTool::paintBitmap(Layer* layer) QRgb fillColor = qPremultiply(mEditor->color()->frontColor().rgba()); QRgb origColor = fillColor; - if (properties.fillMode == 1) + if (properties.fillMode == 0) + { + if (qAlpha(fillColor) == 0) + { + return; + } + } + else if (properties.fillMode == 1) { QColor tempColor; tempColor.setRgba(fillColor); From 6d259592e787007a1b9e44a6ff11bfa8cf8ce9f9 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Wed, 21 Apr 2021 20:19:38 -0600 Subject: [PATCH 4/4] Document fill mode code better --- core_lib/src/tool/buckettool.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index 5aad744cbc..ea0b6c58a7 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -191,11 +191,16 @@ void BucketTool::paintBitmap(Layer* layer) { if (qAlpha(fillColor) == 0) { + // Filling in overlay mode with a fully transparent color has no + // effect, so we can skip it in this case return; } } else if (properties.fillMode == 1) { + // Pass a fully opaque version of the new color to floodFill + // This is required so we can fully mask out the existing data before + // writing the new color. QColor tempColor; tempColor.setRgba(fillColor); tempColor.setAlphaF(1); @@ -211,25 +216,32 @@ void BucketTool::paintBitmap(Layer* layer) if (fillImage == nullptr) { + // Nothing was filled for whatever reason return; } switch(properties.fillMode) { default: - case 0: + case 0: // Overlay mode + // Write fill image on top of target image targetImage->paste(fillImage.get()); break; - case 1: + case 1: // Replace mode if (qAlpha(origColor) == 0xFF) { + // When the new color is fully opaque, replace mode + // behaves exactly like overlay mode, and origColor == fillColor targetImage->paste(fillImage.get()); } else { + // Clearly all pixels in the to-be-filled region from the target image targetImage->paste(fillImage.get(), QPainter::CompositionMode_DestinationOut); + // Reduce the opacity of the fill to match the new color BitmapImage properColor(targetImage->bounds(), QColor::fromRgba(origColor)); properColor.paste(fillImage.get(), QPainter::CompositionMode_DestinationIn); + // Write reduced-opacity fill image on top of target image targetImage->paste(&properColor); } break;