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