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