layersplit.cpp 6.79 KB
Newer Older
1
/*
2
 * Copyright (C) 2014 Boudewijn Rempt <boud@valdyas.org>
3
 *
4 5 6 7
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
8
 *
9 10 11 12
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
13
 *
14 15 16 17
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
18 19 20 21 22 23 24 25
 */

#include "layersplit.h"

#include <QMap>
#include <QPointer>
#include <QHash>

26
#include <klocalizedstring.h>
27 28 29 30
#include <kpluginfactory.h>

#include <KoColorSpace.h>
#include <KoChannelInfo.h>
31
#include <KoColor.h>
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

#include <kis_debug.h>
#include <kis_types.h>
#include <KisViewManager.h>
#include <kis_image.h>
#include <kis_action.h>
#include <KisDocument.h>
#include <kis_node.h>
#include <kis_painter.h>
#include <kis_paint_device.h>
#include <kis_paint_layer.h>
#include <kis_group_layer.h>
#include <kis_random_accessor_ng.h>
#include "dlg_layersplit.h"
#include "kis_node_manager.h"
#include "kis_node_commands_adapter.h"
#include "kis_undo_adapter.h"

#include <KoUpdater.h>
#include <KoProgressUpdater.h>

53
K_PLUGIN_FACTORY_WITH_JSON(LayerSplitFactory, "kritalayersplit.json", registerPlugin<LayerSplit>();)
54 55

LayerSplit::LayerSplit(QObject *parent, const QVariantList &)
56
    : KisViewPlugin(parent)
57
{
58
    KisAction *action  = createAction("layersplit");
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    connect(action, SIGNAL(triggered()), this, SLOT(slotLayerSplit()));
}

LayerSplit::~LayerSplit()
{
}


struct Layer {
    KoColor color;
    KisPaintDeviceSP device;
    KisRandomAccessorSP accessor;
    int pixelsWritten;

    bool operator<(const Layer& other) const
    {
        return pixelsWritten < other.pixelsWritten;
    }
};

void LayerSplit::slotLayerSplit()
{
    DlgLayerSplit dlg;

    if (dlg.exec() == QDialog::Accepted) {

        dlg.hide();

        QApplication::setOverrideCursor(Qt::WaitCursor);

        KoProgressUpdater* pu = m_view->createProgressUpdater(KoProgressUpdater::Unthreaded);
        pu->start(100, i18n("Split into Layers"));
        QPointer<KoUpdater> updater = pu->startSubtask();

        KisImageSP image = m_view->image();
        if (!image) return;

        image->lock();

        KisNodeSP node = m_view->activeNode();
        if (!node) return;

        KisPaintDeviceSP projection = node->projection();
        if (!projection) return;

        QList<Layer> colorMap;

        const KoColorSpace *cs = projection->colorSpace();
        QRect rc = image->bounds();

        int fuzziness = dlg.fuzziness();

        updater->setProgress(0);

        KisRandomConstAccessorSP acc = projection->createRandomConstAccessorNG(rc.x(), rc.y());

        for (int row = rc.y(); row < rc.height(); ++row) {

            for (int col = rc.x(); col < rc.width(); ++col) {

                acc->moveTo(col, row);

                KoColor c(cs);
                c.setColor(acc->rawDataConst(), cs);

Boudewijn Rempt's avatar
Boudewijn Rempt committed
124 125 126 127
                if (c.opacityU8() == OPACITY_TRANSPARENT_U8) {
                    continue;
                }

128 129 130 131 132
                if (dlg.disregardOpacity()) {
                    c.setOpacity(OPACITY_OPAQUE_U8);
                }

                bool found = false;
133
                Q_FOREACH (const Layer &l, colorMap) {
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
                    if (fuzziness == 0) {

                        found = (l.color == c);
                    }
                    else {
                        quint8 match = cs->difference(l.color.data(), c.data());
                        found = (match <= fuzziness);
                    }
                    if (found) {
                        KisRandomAccessorSP dstAcc = l.accessor;
                        dstAcc->moveTo(col, row);
                        memcpy(dstAcc->rawData(), acc->rawDataConst(), cs->pixelSize());
                        const_cast<Layer*>(&l)->pixelsWritten++;
                        break;
                    }
                }

                if (!found) {
152 153 154 155
                    QString name = dlg.palette()->closestColorName(c);
                    if (name.toLower() == "untitled" || name.toLower() == "none" || name.toLower() == "") {
                        name = KoColor::toQString(c);
                    }
156 157
                    Layer l;
                    l.color = c;
158
                    l.device = new KisPaintDevice(cs, name);
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
                    l.accessor = l.device->createRandomAccessorNG(col, row);
                    l.accessor->moveTo(col, row);
                    memcpy(l.accessor->rawData(), acc->rawDataConst(), cs->pixelSize());
                    l.pixelsWritten = 1;
                    colorMap << l;
                }
            }

            if (updater->interrupted()) {
                return;
            }

            updater->setProgress((row - rc.y()) * 100 / rc.height() - rc.y());
        }

        updater->setProgress(100);

176
        dbgKrita << "Created" << colorMap.size() << "layers";
177
//        Q_FOREACH (const Layer &l, colorMap) {
178
//            dbgKrita << "\t" << l.device->objectName() << ":" << l.pixelsWritten;
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
//        }

        if (dlg.sortLayers()) {
            qSort(colorMap);
        }

        KisUndoAdapter *undo = image->undoAdapter();
        undo->beginMacro(kundo2_i18n("Split Layer"));
        KisNodeCommandsAdapter adapter(m_view);

        KisGroupLayerSP baseGroup = dynamic_cast<KisGroupLayer*>(node->parent().data());
        if (!baseGroup) {
            // Masks are never nested
            baseGroup = dynamic_cast<KisGroupLayer*>(node->parent()->parent().data());
        }

        if (dlg.hideOriginal()) {
            node->setVisible(false);
        }

        if (dlg.createBaseGroup()) {
            KisGroupLayerSP grp = new KisGroupLayer(image, i18n("Color"), OPACITY_OPAQUE_U8);
            adapter.addNode(grp, baseGroup, 1);
            baseGroup = grp;
        }

205
        Q_FOREACH (const Layer &l, colorMap) {
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
            KisGroupLayerSP grp = baseGroup;
            if (dlg.createSeparateGroups()) {
                grp = new KisGroupLayer(image, l.device->objectName(), OPACITY_OPAQUE_U8);
                adapter.addNode(grp, baseGroup, 1);
            }
            KisPaintLayerSP paintLayer = new KisPaintLayer(image, l.device->objectName(), OPACITY_OPAQUE_U8, l.device);
            adapter.addNode(paintLayer, grp, 0);
            paintLayer->setAlphaLocked(dlg.lockAlpha());
        }

        undo->endMacro();
        image->unlock();
        image->setModified();
   }

    QApplication::restoreOverrideCursor();
}

#include "layersplit.moc"