Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_smart_patch.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Eugene Ingerman
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include "QApplication"
10#include "QPainterPath"
11
12#include <klocalizedstring.h>
13#include <KoColor.h>
14#include <KisViewManager.h>
15#include "kis_canvas2.h"
16#include "kis_cursor.h"
17#include "kis_painter.h"
18#include "kis_paintop_preset.h"
19
20#include "kundo2magicstring.h"
21#include "kundo2stack.h"
23#include "kis_transaction.h"
24
26#include "kis_datamanager.h"
27
30
33
34#include "kis_paint_layer.h"
35#include "kis_algebra_2d.h"
37
38QRect patchImage(KisPaintDeviceSP imageDev, KisPaintDeviceSP maskDev, int radius, int accuracy, KisSelectionSP selection);
39
56
60 float brushRadius = 50.; //initial default. actually read from ui.
63 QPainterPath brushOutline;
64};
65
66
68 : KisToolPaint(canvas, KisCursor::blankCursor()),
69 m_d(new Private)
70{
72 setObjectName("tool_SmartPatch");
73 m_d->maskDev = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8());
74 m_d->maskDevPainter.begin( m_d->maskDev );
75
76 m_d->maskDevPainter.setPaintColor(KoColor(Qt::magenta, m_d->maskDev->colorSpace()));
77 m_d->maskDevPainter.setBackgroundColor(KoColor(Qt::white, m_d->maskDev->colorSpace()));
78 m_d->maskDevPainter.setFillStyle( KisPainter::FillStyleForegroundColor );
79}
80
82{
83 m_d->optionsWidget = nullptr;
84 m_d->maskDevPainter.end();
85}
86
87void KisToolSmartPatch::activate(const QSet<KoShape*> &shapes)
88{
90}
91
96
101
107
113
115{
116 KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2 *>(canvas());
117 KIS_ASSERT(canvas2);
118 const KisCoordinatesConverter *converter = canvas2->coordinatesConverter();
119
120 QPointF imagePos = currentImage()->documentToPixel(event->point);
121 QPainterPath currentBrushOutline = brushOutline().translated(KisAlgebra2D::alignForZoom(imagePos, converter->effectivePhysicalZoom()));
122 m_d->maskDevPainter.fillPainterPath(currentBrushOutline);
123
124 canvas()->updateCanvas(currentImage()->pixelToDocument(m_d->maskDev->exactBounds()));
125}
126
128{
129 //we can only apply inpaint operation to paint layer
130 if ( currentNode().isNull() || !currentNode()->inherits("KisPaintLayer") || nodePaintAbility()!=NodePaintAbility::PAINT ) {
131 KisCanvas2 * kiscanvas = static_cast<KisCanvas2*>(canvas());
132 kiscanvas->viewManager()->
133 showFloatingMessage(
134 i18n("Select a paint layer to use this tool"),
135 QIcon(), 2000, KisFloatingMessage::Medium, Qt::AlignCenter);
136 event->ignore();
137 return;
138 }
139
140 addMaskPath(event);
143}
144
151
153{
155 addMaskPath(event);
158
159 KisCursorOverrideLock cursorLock(KisCursor::waitCursor());
160
161 int accuracy = 50; //default accuracy - middle value
162 int patchRadius = 4; //default radius, which works well for most cases tested
163
164 if (m_d->optionsWidget) {
165 accuracy = m_d->optionsWidget->getAccuracy();
166 patchRadius = m_d->optionsWidget->getPatchRadius();
167 }
168
169 KisResourcesSnapshotSP resources =
170 new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager());
171
173 kundo2_i18n("Smart Patch"));
174
175 //actual inpaint operation. filling in areas masked by user
177 currentNode()->paintDevice(),
178 accuracy, patchRadius,
179 resources->activeSelection()),
181
182 applicator.end();
183 image()->waitForDone();
184
185 m_d->maskDev->clear();
186}
187
189{
190 const qreal diameter = m_d->brushRadius;
191 QPainterPath outline;
192 outline.addEllipse(QPointF(0,0), -0.5 * diameter, -0.5 * diameter );
193 return outline;
194}
195
196QPainterPath KisToolSmartPatch::getBrushOutlinePath(const QPointF &documentPos,
197 const KoPointerEvent *event)
198{
199 Q_UNUSED(event);
200
201 QPointF imagePos = currentImage()->documentToPixel(documentPos);
202 QPainterPath path = brushOutline();
203
204 KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2 *>(canvas());
205 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas2, QPainterPath());
206 const KisCoordinatesConverter *converter = canvas2->coordinatesConverter();
207
208 return path.translated(KisAlgebra2D::alignForZoom(imagePos, converter->effectivePhysicalZoom()));
209}
210
211void KisToolSmartPatch::requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event)
212{
213 static QPointF lastDocPoint = QPointF(0,0);
214 if( event )
215 lastDocPoint=outlineDocPoint;
216
217 m_d->brushRadius = currentPaintOpPreset()->settings()->paintOpSize();
218 m_d->brushOutline = getBrushOutlinePath(lastDocPoint, event);
219
220 QRectF outlinePixelRect = m_d->brushOutline.boundingRect();
221 QRectF outlineDocRect = currentImage()->pixelToDocument(outlinePixelRect);
222
223 // This adjusted call is needed as we paint with a 3 pixel wide brush and the pen is outside the bounds of the path
224 // Pen uses view coordinates so we have to zoom the document value to match 2 pixel in view coordinates
225 // See BUG 275829
226 qreal zoomX;
227 qreal zoomY;
228 canvas()->viewConverter()->zoom(&zoomX, &zoomY);
229 qreal xoffset = 2.0/zoomX;
230 qreal yoffset = 2.0/zoomY;
231
232 if (!outlineDocRect.isEmpty()) {
233 outlineDocRect.adjust(-xoffset,-yoffset,xoffset,yoffset);
234 }
235
236 if (!m_d->oldOutlineRect.isEmpty()) {
237 canvas()->updateCanvas(m_d->oldOutlineRect);
238 }
239
240 if (!outlineDocRect.isEmpty()) {
241 canvas()->updateCanvas(outlineDocRect);
242 }
243
244 m_d->oldOutlineRect = outlineDocRect;
245}
246
247void KisToolSmartPatch::paint(QPainter &painter, const KoViewConverter &converter)
248{
249 Q_UNUSED(converter);
250
251 painter.save();
252 QPainterPath path = pixelToView(m_d->brushOutline);
253 paintToolOutline(&painter, path);
254 painter.restore();
255
256 painter.save();
257 painter.setBrush(Qt::magenta);
258 QImage img = m_d->maskDev->convertToQImage(0);
259 if( !img.size().isEmpty() ){
260 painter.drawImage(pixelToView(m_d->maskDev->exactBounds()), img);
261 }
262 painter.restore();
263}
264
266{
267 KisCanvas2 * kiscanvas = dynamic_cast<KisCanvas2*>(canvas());
268 KIS_ASSERT(kiscanvas);
269
270 m_d->optionsWidget = new KisToolSmartPatchOptionsWidget(kiscanvas->viewManager()->canvasResourceProvider(), 0);
271 m_d->optionsWidget->setObjectName(toolId() + "option widget");
272
273 return m_d->optionsWidget;
274}
275
QVector< KisImageSignalType > KisImageSignalVector
KisCoordinatesConverter * coordinatesConverter
void updateCanvas(const QRectF &rc) override
KisViewManager * viewManager() const
const KoViewConverter * viewConverter() const override
static QCursor waitCursor()
Definition kis_cursor.cc:54
void waitForDone()
QPointF documentToPixel(const QPointF &documentCoord) const
QPointF pixelToDocument(const QPointF &pixelCoord) const
@ FillStyleForegroundColor
static KisPaintDeviceSP convertToAlphaAsAlpha(KisPaintDeviceSP src)
void applyCommand(KUndo2Command *command, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
The KisResourcesSnapshot class takes a snapshot of the various resources like colors and settings use...
KisSelectionSP activeSelection() const
void setSupportOutline(bool supportOutline)
void deactivate() override
void activate(const QSet< KoShape * > &shapes) override
void setOutlineVisible(bool visible)
void deactivatePrimaryAction() override
void setMode(ToolMode mode) override
void activatePrimaryAction() override
InpaintCommand(KisPaintDeviceSP maskDev, KisPaintDeviceSP imageDev, int accuracy, int patchRadius, KisSelectionSP selection)
void deactivatePrimaryAction() override
QPainterPath getBrushOutlinePath(const QPointF &documentPos, const KoPointerEvent *event)
void beginPrimaryAction(KoPointerEvent *event) override
void paint(QPainter &painter, const KoViewConverter &converter) override
QWidget * createOptionWidget() override
const QScopedPointer< Private > m_d
void activate(const QSet< KoShape * > &shapes) override
void endPrimaryAction(KoPointerEvent *event) override
void continuePrimaryAction(KoPointerEvent *event) override
void addMaskPath(KoPointerEvent *event)
KisToolSmartPatch(KoCanvasBase *canvas)
void resetCursorStyle() override
void requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event) override
void activatePrimaryAction() override
KUndo2Command * endAndTake()
KisCanvasResourceProvider * canvasResourceProvider()
QPointF point
The point in document coordinates.
Q_INVOKABLE QString toolId() const
virtual KoToolSelection * selection()
virtual void zoom(qreal *zoomX, qreal *zoomY) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
QRect patchImage(const KisPaintDeviceSP imageDev, const KisPaintDeviceSP maskDev, int patchRadius, int accuracy, KisSelectionSP selection)
#define CHECK_MODE_SANITY_OR_RETURN(_mode)
Definition kis_tool.h:27
QRect patchImage(KisPaintDeviceSP imageDev, KisPaintDeviceSP maskDev, int radius, int accuracy, KisSelectionSP selection)
KUndo2MagicString kundo2_i18n(const char *text)
QPointF alignForZoom(const QPointF &pt, qreal zoom)
KisToolSmartPatchOptionsWidget * optionsWidget
KisImageWSP currentImage()
Definition kis_tool.cc:393
KisTool::NodePaintAbility nodePaintAbility()
Definition kis_tool.cc:539
virtual void resetCursorStyle()
Definition kis_tool.cc:613
virtual void beginPrimaryAction(KoPointerEvent *event)
Definition kis_tool.cc:431
KisPaintOpPresetSP currentPaintOpPreset()
Definition kis_tool.cc:359
QPointF pixelToView(const QPoint &pixelCoord) const
Definition kis_tool.cc:269
KisNodeSP currentNode() const
Definition kis_tool.cc:370
virtual void endPrimaryAction(KoPointerEvent *event)
Definition kis_tool.cc:446
virtual void continuePrimaryAction(KoPointerEvent *event)
Definition kis_tool.cc:441
void paintToolOutline(QPainter *painter, const KisOptimizedBrushOutline &path)
Definition kis_tool.cc:589
KisImageWSP image() const
Definition kis_tool.cc:332
@ PAINT_MODE
Definition kis_tool.h:300
@ HOVER_MODE
Definition kis_tool.h:299
static KoColorSpaceRegistry * instance()
KisCanvas2 * canvas