File indexing completed on 2024-05-12 15:59:08

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