File indexing completed on 2024-12-22 04:15:06
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "layersplit.h" 0008 0009 #include <QMap> 0010 #include <QPointer> 0011 #include <QHash> 0012 0013 #include <klocalizedstring.h> 0014 #include <kpluginfactory.h> 0015 0016 #include <KoColorSpace.h> 0017 #include <KoChannelInfo.h> 0018 #include <KoColor.h> 0019 0020 #include <kis_debug.h> 0021 #include <kis_types.h> 0022 #include <KisViewManager.h> 0023 #include <kis_image.h> 0024 #include <kis_action.h> 0025 #include <KisDocument.h> 0026 #include <kis_node.h> 0027 #include <kis_painter.h> 0028 #include <kis_paint_device.h> 0029 #include <kis_paint_layer.h> 0030 #include <kis_group_layer.h> 0031 #include <kis_random_accessor_ng.h> 0032 #include "dlg_layersplit.h" 0033 #include "kis_node_manager.h" 0034 #include "kis_node_commands_adapter.h" 0035 #include "kis_undo_adapter.h" 0036 #include <KisImageBarrierLock.h> 0037 #include "kis_selection_mask.h" 0038 #include "kis_layer_utils.h" 0039 0040 #include <KoUpdater.h> 0041 #include <KoProgressUpdater.h> 0042 #include <KisCursorOverrideLock.h> 0043 0044 K_PLUGIN_FACTORY_WITH_JSON(LayerSplitFactory, "kritalayersplit.json", registerPlugin<LayerSplit>();) 0045 0046 LayerSplit::LayerSplit(QObject *parent, const QVariantList &) 0047 : KisActionPlugin(parent) 0048 { 0049 KisAction *action = createAction("layersplit"); 0050 connect(action, SIGNAL(triggered()), this, SLOT(slotLayerSplit())); 0051 } 0052 0053 LayerSplit::~LayerSplit() 0054 { 0055 } 0056 0057 0058 struct Layer { 0059 KoColor color; 0060 KisPaintDeviceSP device; 0061 KisRandomAccessorSP accessor; 0062 int pixelsWritten; 0063 0064 bool operator<(const Layer& other) const 0065 { 0066 return pixelsWritten < other.pixelsWritten; 0067 } 0068 }; 0069 0070 void LayerSplit::slotLayerSplit() 0071 { 0072 DlgLayerSplit dlg; 0073 0074 if (dlg.exec() == QDialog::Accepted) { 0075 0076 bool modeToLayer = !dlg.m_modeToMask; 0077 dlg.hide(); 0078 0079 KisImageSP image = viewManager()->image(); 0080 if (!image) return; 0081 0082 KisNodeSP node = viewManager()->activeNode(); 0083 if (!node) return; 0084 0085 // Convert to paint layer prior to splitting if current node is a colorize mask 0086 if (node->inherits("KisColorizeMask")) { 0087 std::future<KisNodeSP> convertedNode = KisLayerUtils::convertToPaintLayer(image, node); 0088 node = convertedNode.get(); 0089 } 0090 0091 if (!node) return; 0092 0093 KisImageBarrierLock lock(image); 0094 0095 KisPaintDeviceSP projection = node->projection(); 0096 if (!projection) return; 0097 0098 QList<Layer> colorMap; 0099 0100 const KoColorSpace *cs = projection->colorSpace(); 0101 QRect rc = image->bounds(); 0102 0103 int fuzziness = dlg.fuzziness(); 0104 0105 KisCursorOverrideLock cursorLock(Qt::WaitCursor); 0106 0107 QPointer<KoUpdater> updater; 0108 if( modeToLayer){ 0109 updater = viewManager()->createUnthreadedUpdater(i18n("Split into Layers")); 0110 } 0111 else { 0112 updater = viewManager()->createUnthreadedUpdater(i18n("Split into Masks")); 0113 } 0114 0115 updater->setProgress(0); 0116 0117 KisRandomConstAccessorSP acc = projection->createRandomConstAccessorNG(); 0118 0119 for (int row = rc.y(); row < rc.height(); ++row) { 0120 0121 for (int col = rc.x(); col < rc.width(); ++col) { 0122 0123 acc->moveTo(col, row); 0124 0125 KoColor c(cs); 0126 c.setColor(acc->rawDataConst(), cs); 0127 0128 if (c.opacityU8() == OPACITY_TRANSPARENT_U8) { 0129 continue; 0130 } 0131 0132 if (dlg.disregardOpacity()) { 0133 c.setOpacity(OPACITY_OPAQUE_U8); 0134 } 0135 0136 bool found = false; 0137 Q_FOREACH (const Layer &l, colorMap) { 0138 if (fuzziness == 0) { 0139 0140 found = (l.color == c); 0141 } 0142 else { 0143 quint8 match = cs->difference(l.color.data(), c.data()); 0144 found = (match <= fuzziness); 0145 } 0146 if (found) { 0147 KisRandomAccessorSP dstAcc = l.accessor; 0148 dstAcc->moveTo(col, row); 0149 memcpy(dstAcc->rawData(), acc->rawDataConst(), cs->pixelSize()); 0150 const_cast<Layer*>(&l)->pixelsWritten++; 0151 break; 0152 } 0153 } 0154 0155 if (!found) { 0156 QString name = ""; 0157 if (dlg.palette()) { 0158 name = dlg.palette()->getClosestSwatchInfo(c).swatch.name(); 0159 } 0160 0161 if (name.toLower() == "untitled" || name.toLower() == "none" || name.toLower() == "") { 0162 name = KoColor::toQString(c); 0163 } 0164 Layer l; 0165 l.color = c; 0166 l.device = new KisPaintDevice(cs, name); 0167 l.accessor = l.device->createRandomAccessorNG(); 0168 l.accessor->moveTo(col, row); 0169 memcpy(l.accessor->rawData(), acc->rawDataConst(), cs->pixelSize()); 0170 l.pixelsWritten = 1; 0171 colorMap << l; 0172 } 0173 } 0174 0175 if (updater->interrupted()) { 0176 return; 0177 } 0178 0179 updater->setProgress((row - rc.y()) * 100 / rc.height() - rc.y()); 0180 } 0181 0182 updater->setProgress(100); 0183 0184 dbgKrita << "Created" << colorMap.size() << "layers"; 0185 // Q_FOREACH (const Layer &l, colorMap) { 0186 // dbgKrita << "\t" << l.device->objectName() << ":" << l.pixelsWritten; 0187 // } 0188 0189 if (dlg.sortLayers()) { 0190 std::sort(colorMap.begin(), colorMap.end()); 0191 } 0192 0193 KisUndoAdapter *undo = image->undoAdapter(); 0194 undo->beginMacro(kundo2_i18n("Split Layer")); 0195 KisNodeCommandsAdapter adapter(viewManager()); 0196 0197 if(modeToLayer){ 0198 KisGroupLayerSP baseGroup = dynamic_cast<KisGroupLayer*>(node->parent().data()); 0199 if (!baseGroup) { 0200 // Masks are never nested 0201 baseGroup = dynamic_cast<KisGroupLayer*>(node->parent()->parent().data()); 0202 } 0203 0204 if (dlg.hideOriginal()) { 0205 node->setVisible(false); 0206 } 0207 0208 if (dlg.createBaseGroup()) { 0209 KisGroupLayerSP grp = new KisGroupLayer(image, i18n("Color"), OPACITY_OPAQUE_U8); 0210 adapter.addNode(grp, baseGroup, 1); 0211 baseGroup = grp; 0212 } 0213 0214 Q_FOREACH (const Layer &l, colorMap) { 0215 KisGroupLayerSP grp = baseGroup; 0216 if (dlg.createSeparateGroups()) { 0217 grp = new KisGroupLayer(image, l.device->objectName(), OPACITY_OPAQUE_U8); 0218 adapter.addNode(grp, baseGroup, 1); 0219 } 0220 KisPaintLayerSP paintLayer = new KisPaintLayer(image, l.device->objectName(), OPACITY_OPAQUE_U8, l.device); 0221 adapter.addNode(paintLayer, grp, 0); 0222 paintLayer->setAlphaLocked(dlg.lockAlpha()); 0223 } 0224 } 0225 else{ 0226 KisLayerSP baseGroup = dynamic_cast<KisLayer*>(node.data()); 0227 Q_FOREACH (const Layer &l, colorMap) { 0228 KisSelectionMaskSP mask = new KisSelectionMask(image); 0229 mask->setName( l.device->objectName()); 0230 0231 KisPaintDeviceSP temp = KisPainter::convertToAlphaAsPureAlpha(l.device); 0232 mask->initSelection(temp , baseGroup); 0233 adapter.addNode(mask, baseGroup,0); 0234 mask->setActive(true); 0235 } 0236 } 0237 0238 undo->endMacro(); 0239 } 0240 } 0241 0242 #include "layersplit.moc"