File indexing completed on 2024-05-19 04:26:57

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 #include "Selection.h"
0007 
0008 #include <KoColorSpace.h>
0009 #include "kis_iterator_ng.h"
0010 #include <kis_selection.h>
0011 #include <kis_pixel_selection.h>
0012 #include <kis_paint_device.h>
0013 #include <kis_selection_filters.h>
0014 #include <kis_painter.h>
0015 #include <kis_node.h>
0016 #include <kis_clipboard.h>
0017 #include <QByteArray>
0018 
0019 #include <Node.h>
0020 
0021 struct Selection::Private {
0022     Private() {}
0023     KisSelectionSP selection;
0024 };
0025 
0026 Selection::Selection(KisSelectionSP selection, QObject *parent)
0027     : QObject(parent)
0028     , d(new Private)
0029 {
0030     d->selection = selection;
0031 }
0032 
0033 
0034 Selection::Selection(QObject *parent)
0035     : QObject(parent)
0036     , d(new Private)
0037 {
0038     d->selection = new KisSelection();
0039 }
0040 
0041 Selection::~Selection()
0042 {
0043     delete d;
0044 }
0045 
0046 bool Selection::operator==(const Selection &other) const
0047 {
0048     return (d->selection == other.d->selection);
0049 }
0050 
0051 bool Selection::operator!=(const Selection &other) const
0052 {
0053     return !(operator==(other));
0054 }
0055 
0056 Selection *Selection::duplicate() const
0057 {
0058     return new Selection(d->selection ? new KisSelection(*d->selection)
0059                          : new KisSelection());
0060 }
0061 
0062 int Selection::width() const
0063 {
0064     if (!d->selection) return 0;
0065     return d->selection->selectedExactRect().width();
0066 }
0067 
0068 int Selection::height() const
0069 {
0070     if (!d->selection) return 0;
0071     return d->selection->selectedExactRect().height();
0072 }
0073 
0074 int Selection::x() const
0075 {
0076     if (!d->selection) return 0;
0077     int xPos = d->selection->x();
0078     if (d->selection->hasNonEmptyPixelSelection()) {
0079         xPos = d->selection->selectedExactRect().x();
0080     }
0081     return xPos;
0082 }
0083 
0084 int Selection::y() const
0085 {
0086     if (!d->selection) return 0;
0087     int yPos = d->selection->y();
0088     if (d->selection->hasNonEmptyPixelSelection()) {
0089         yPos = d->selection->selectedExactRect().y();
0090     }
0091     return yPos;
0092 }
0093 
0094 void Selection::move(int x, int y)
0095 {
0096     if (!d->selection) return;
0097     d->selection->pixelSelection()->moveTo(QPoint(x, y));
0098 }
0099 
0100 
0101 void Selection::clear()
0102 {
0103     if (!d->selection) return;
0104     d->selection->clear();
0105 }
0106 
0107 void Selection::contract(int value)
0108 {
0109     if (!d->selection) return;
0110     d->selection->pixelSelection()->select(QRect(x(), y(), width() - value, height() - value));
0111 }
0112 
0113 void Selection::copy(Node *node)
0114 {
0115     if (!node) return;
0116     if (!d->selection) return;
0117     if (node->node()->exactBounds().isEmpty()) return;
0118     if (!node->node()->hasEditablePaintDevice()) return;
0119 
0120     KisPaintDeviceSP dev = node->node()->paintDevice();
0121     KisPaintDeviceSP clip = new KisPaintDevice(dev->colorSpace());
0122     KisPaintDeviceSP selectionProjection = d->selection->projection();
0123 
0124     const KoColorSpace *cs = clip->colorSpace();
0125     const KoColorSpace *selCs = d->selection->projection()->colorSpace();
0126 
0127     QRect rc = d->selection->selectedExactRect();
0128 
0129     KisPainter::copyAreaOptimized(QPoint(), dev, clip, rc);
0130 
0131     KisHLineIteratorSP layerIt = clip->createHLineIteratorNG(0, 0, rc.width());
0132     KisHLineConstIteratorSP selectionIt = selectionProjection->createHLineIteratorNG(rc.x(), rc.y(), rc.width());
0133 
0134     for (qint32 y = 0; y < rc.height(); y++) {
0135         for (qint32 x = 0; x < rc.width(); x++) {
0136 
0137             qreal dstAlpha = cs->opacityF(layerIt->rawData());
0138             qreal sel = selCs->opacityF(selectionIt->oldRawData());
0139             qreal newAlpha = sel * dstAlpha / (1.0 - dstAlpha + sel * dstAlpha);
0140             float mask = newAlpha / dstAlpha;
0141 
0142             cs->applyAlphaNormedFloatMask(layerIt->rawData(), &mask, 1);
0143 
0144             layerIt->nextPixel();
0145             selectionIt->nextPixel();
0146         }
0147         layerIt->nextRow();
0148         selectionIt->nextRow();
0149     }
0150 
0151     KisClipboard::instance()->setClip(clip, rc.topLeft());
0152 }
0153 
0154 void Selection::cut(Node* node)
0155 {
0156     if (!node) return;
0157     if (!d->selection) return;
0158     if (node->node()->exactBounds().isEmpty()) return;
0159     if (!node->node()->hasEditablePaintDevice()) return;
0160     KisPaintDeviceSP dev = node->node()->paintDevice();
0161     copy(node);
0162     dev->clearSelection(d->selection);
0163     node->node()->setDirty(d->selection->selectedExactRect());
0164 }
0165 
0166 void Selection::paste(Node *destination, int x, int y)
0167 {
0168     if (!destination) return;
0169     if (!d->selection) return;
0170     if (!KisClipboard::instance()->hasClip()) return;
0171 
0172     KisPaintDeviceSP src = KisClipboard::instance()->clip(QRect(), false);
0173     KisPaintDeviceSP dst = destination->node()->paintDevice();
0174     if (!dst || !src) return;
0175     KisPainter::copyAreaOptimized(QPoint(x, y),
0176                                   src,
0177                                   dst,
0178                                   src->exactBounds(),
0179                                   d->selection);
0180     destination->node()->setDirty();
0181 }
0182 
0183 void Selection::erode()
0184 {
0185     if (!d->selection) return;
0186     KisErodeSelectionFilter esf;
0187     QRect rc = esf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0188     esf.process(d->selection->pixelSelection(), rc);
0189 }
0190 
0191 void Selection::dilate()
0192 {
0193     if (!d->selection) return;
0194     KisDilateSelectionFilter dsf;
0195     QRect rc = dsf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0196     dsf.process(d->selection->pixelSelection(), rc);
0197 }
0198 
0199 void Selection::border(int xRadius, int yRadius)
0200 {
0201     if (!d->selection) return;
0202     KisBorderSelectionFilter sf(xRadius, yRadius, true);
0203     QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0204     sf.process(d->selection->pixelSelection(), rc);
0205 }
0206 
0207 void Selection::feather(int radius)
0208 {
0209     if (!d->selection) return;
0210     KisFeatherSelectionFilter fsf(radius);
0211     QRect rc = fsf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0212     fsf.process(d->selection->pixelSelection(), rc);
0213 }
0214 
0215 void Selection::grow(int xradius, int yradius)
0216 {
0217     if (!d->selection) return;
0218     KisGrowSelectionFilter gsf(xradius, yradius);
0219     QRect rc = gsf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0220     gsf.process(d->selection->pixelSelection(), rc);
0221 }
0222 
0223 
0224 void Selection::shrink(int xRadius, int yRadius, bool edgeLock)
0225 {
0226     if (!d->selection) return;
0227     KisShrinkSelectionFilter sf(xRadius, yRadius, edgeLock);
0228     QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0229     sf.process(d->selection->pixelSelection(), rc);
0230 }
0231 
0232 void Selection::smooth()
0233 {
0234     if (!d->selection) return;
0235     KisSmoothSelectionFilter sf;
0236     QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0237     sf.process(d->selection->pixelSelection(), rc);
0238 }
0239 
0240 
0241 void Selection::invert()
0242 {
0243     if (!d->selection) return;
0244     KisInvertSelectionFilter sf;
0245     QRect rc = sf.changeRect(d->selection->selectedExactRect(), d->selection->pixelSelection()->defaultBounds());
0246     sf.process(d->selection->pixelSelection(), rc);
0247 }
0248 
0249 void Selection::resize(int w, int h)
0250 {
0251     if (!d->selection) return;
0252     d->selection->pixelSelection()->select(QRect(x(), y(), w, h));
0253 }
0254 
0255 void Selection::select(int x, int y, int w, int h, int value)
0256 {
0257     if (!d->selection) return;
0258     d->selection->pixelSelection()->select(QRect(x, y, w, h), value);
0259 }
0260 
0261 void Selection::selectAll(Node *node, int value)
0262 {
0263     if (!d->selection) return;
0264     d->selection->pixelSelection()->select(node->node()->exactBounds(), value);
0265 }
0266 
0267 void Selection::replace(Selection *selection)
0268 {
0269     if (!d->selection) return;
0270     d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_REPLACE);
0271 }
0272 
0273 void Selection::add(Selection *selection)
0274 {
0275     if (!d->selection) return;
0276     d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_ADD);
0277 }
0278 
0279 void Selection::subtract(Selection *selection)
0280 {
0281     if (!d->selection) return;
0282     d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_SUBTRACT);
0283 }
0284 
0285 void Selection::intersect(Selection *selection)
0286 {
0287     if (!d->selection) return;
0288     d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_INTERSECT);
0289 }
0290 
0291 void Selection::symmetricdifference(Selection *selection)
0292 {
0293     if (!d->selection) return;
0294     d->selection->pixelSelection()->applySelection(selection->selection()->pixelSelection(), SELECTION_SYMMETRICDIFFERENCE);
0295 }
0296 
0297 
0298 QByteArray Selection::pixelData(int x, int y, int w, int h) const
0299 {
0300     QByteArray ba;
0301     if (!d->selection) return ba;
0302     KisPaintDeviceSP dev = d->selection->projection();
0303     quint8 *data = new quint8[w * h];
0304     dev->readBytes(data, x, y, w, h);
0305     ba = QByteArray((const char*)data, (int)(w * h));
0306     delete[] data;
0307     return ba;
0308 }
0309 
0310 void Selection::setPixelData(QByteArray value, int x, int y, int w, int h)
0311 {
0312     if (!d->selection) return;
0313     KisPixelSelectionSP dev = d->selection->pixelSelection();
0314     if (!dev) return;
0315     dev->writeBytes((const quint8*)value.constData(), x, y, w, h);
0316 }
0317 
0318 KisSelectionSP Selection::selection() const
0319 {
0320     return d->selection;
0321 }
0322 
0323