kis_open_raster_stack_load_visitor.cpp 10.4 KB
Newer Older
1
/*
2
 *  Copyright (c) 2006-2007,2009 Cyrille Berger <cberger@cberger.net>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

Halla Rempt's avatar
Halla Rempt committed
19
#include "kis_open_raster_stack_load_visitor.h"
20 21 22 23 24 25 26 27

#include <QDomElement>
#include <QDomNode>

#include <KoColorSpaceRegistry.h>

// Includes from krita/image
#include <kis_adjustment_layer.h>
28 29
#include <filter/kis_filter.h>
#include <filter/kis_filter_registry.h>
30 31
#include <kis_group_layer.h>
#include <kis_image.h>
32
#include <KoCompositeOpRegistry.h>
33
#include <kis_filter_configuration.h>
34 35 36 37

#include <kis_paint_layer.h>
#include <kis_png_converter.h>
#include <kis_selection.h>
Halla Rempt's avatar
Halla Rempt committed
38
#include <kis_dom_utils.h>
39

40
#include "KisDocument.h"
41

Cyrille Berger's avatar
Cyrille Berger committed
42 43 44
#include "kis_open_raster_load_context.h"

struct KisOpenRasterStackLoadVisitor::Private {
45
    KisImageSP image;
46
    vKisNodeSP activeNodes;
Halla Rempt's avatar
Halla Rempt committed
47
    KisUndoStore* undoStore;
Cyrille Berger's avatar
Cyrille Berger committed
48
    KisOpenRasterLoadContext* loadContext;
49 50
    double xRes;
    double yRes;
Cyrille Berger's avatar
Cyrille Berger committed
51 52
};

Halla Rempt's avatar
Halla Rempt committed
53
KisOpenRasterStackLoadVisitor::KisOpenRasterStackLoadVisitor(KisUndoStore* undoStore, KisOpenRasterLoadContext* orlc)
Halla Rempt's avatar
Halla Rempt committed
54
        : d(new Private)
Cyrille Berger's avatar
Cyrille Berger committed
55
{
Halla Rempt's avatar
Halla Rempt committed
56
    d->undoStore = undoStore;
Cyrille Berger's avatar
Cyrille Berger committed
57 58 59 60
    d->loadContext = orlc;
}

KisOpenRasterStackLoadVisitor::~KisOpenRasterStackLoadVisitor()
61
{
Cyrille Berger's avatar
Cyrille Berger committed
62 63
    delete d;
}
64

65
KisImageSP KisOpenRasterStackLoadVisitor::image()
Cyrille Berger's avatar
Cyrille Berger committed
66 67 68 69
{
    return d->image;
}

70 71 72 73 74
vKisNodeSP KisOpenRasterStackLoadVisitor::activeNodes()
{
    return d->activeNodes;
}

Cyrille Berger's avatar
Cyrille Berger committed
75 76 77 78
void KisOpenRasterStackLoadVisitor::loadImage()
{

    QDomDocument doc = d->loadContext->loadStack();
79

80

Cyrille Berger's avatar
Cyrille Berger committed
81
    for (QDomNode node = doc.firstChild(); !node.isNull(); node = node.nextSibling()) {
Halla Rempt's avatar
Halla Rempt committed
82
        if (node.isElement() && node.nodeName() == "image") { // it's the image root
Cyrille Berger's avatar
Cyrille Berger committed
83
            QDomElement subelem = node.toElement();
84

85 86 87 88
            int width = 0;
            if (!subelem.attribute("w").isNull()) {
                width = subelem.attribute("w").toInt();
            }
89

90 91 92 93
            int height = 0;
            if (!subelem.attribute("h").isNull()) {
                height = subelem.attribute("h").toInt();
            }
94

95
            d->xRes = 75.0/72; // Setting the default value of the X Resolution = 75ppi
Halla Rempt's avatar
Halla Rempt committed
96 97
            if (!subelem.attribute("xres").isNull()){
                d->xRes = (KisDomUtils::toDouble(subelem.attribute("xres")) / 72);
98
            }
99

100
            d->yRes = 75.0/72;
Halla Rempt's avatar
Halla Rempt committed
101 102
            if (!subelem.attribute("yres").isNull()){
                d->yRes = (KisDomUtils::toDouble(subelem.attribute("yres")) / 72);
103 104 105
            }

            dbgFile << ppVar(width) << ppVar(height);
Halla Rempt's avatar
Halla Rempt committed
106
            d->image = new KisImage(d->undoStore, width, height, KoColorSpaceRegistry::instance()->rgb8(), "OpenRaster Image (name)");
107 108 109 110 111 112 113
            for (QDomNode node2 = node.firstChild(); !node2.isNull(); node2 = node2.nextSibling()) {
                if (node2.isElement() && node2.nodeName() == "stack") { // it's the root layer !
                    QDomElement subelem2 = node2.toElement();
                    loadGroupLayer(subelem2, d->image->rootLayer());
                    break;
                }
            }
114 115 116 117
        }
    }
}

118
void KisOpenRasterStackLoadVisitor::loadLayerInfo(const QDomElement& elem, KisLayerSP layer)
119 120 121 122
{
    layer->setName(elem.attribute("name"));
    layer->setX(elem.attribute("x").toInt());
    layer->setY(elem.attribute("y").toInt());
123
    if (elem.attribute("visibility") == "hidden") {
124 125 126 127
        layer->setVisible(false);
    } else {
        layer->setVisible(true);
    }
128
    if (elem.hasAttribute("edit-locked")) {
129
        layer->setUserLocked(elem.attribute("edit-locked") == "true");
130
    }
131
    if (elem.hasAttribute("selected") && elem.attribute("selected") == "true") {
132 133
        d->activeNodes.append(layer);
    }
Halla Rempt's avatar
Halla Rempt committed
134

Halla Rempt's avatar
Halla Rempt committed
135
    QString compop = elem.attribute("composite-op");
136
    if (compop.startsWith("svg:")) {
137 138
        //we don't have a 'composite op clear' despite the registery reserving a string for it, doesn't matter, ora doesn't use it.
        //if (compop == "svg:clear") layer->setCompositeOpId(COMPOSITE_CLEAR);
139
        if (compop == "svg:src-over") layer->setCompositeOpId(COMPOSITE_OVER);
140 141 142 143 144 145 146 147 148 149 150 151 152
        //not part of the spec.
        //if (compop == "svg:dst-over") layer->setCompositeOpId(COMPOSITE_BEHIND);
        //dst-in "The source that overlaps the destination, replaces the destination."
        if (compop == "svg:dst-in") layer->setCompositeOpId(COMPOSITE_DESTINATION_IN);
        //dst-out "dst is placed, where it falls outside of the source."
        if (compop == "svg:dst-out") layer->setCompositeOpId(COMPOSITE_ERASE);
        //src-atop "Destination which overlaps the source replaces the source. Source is placed elsewhere."
        //this is basically our alpha-inherit.
        if (compop == "svg:src-atop") layer->disableAlphaChannel(true);
        //dst-atop
        if (compop == "svg:dst-atop") layer->setCompositeOpId(COMPOSITE_DESTINATION_ATOP);
        //plus is svg standard's way of saying addtion... photoshop calls this linear dodge, btw, maybe make a similar alias?
        if (compop == "svg:plus") layer->setCompositeOpId(COMPOSITE_ADD);
153 154 155 156 157 158 159 160 161 162 163 164 165 166
        if (compop == "svg:multiply") layer->setCompositeOpId(COMPOSITE_MULT);
        if (compop == "svg:screen") layer->setCompositeOpId(COMPOSITE_SCREEN);
        if (compop == "svg:overlay") layer->setCompositeOpId(COMPOSITE_OVERLAY);
        if (compop == "svg:darken") layer->setCompositeOpId(COMPOSITE_DARKEN);
        if (compop == "svg:lighten") layer->setCompositeOpId(COMPOSITE_LIGHTEN);
        if (compop == "svg:color-dodge") layer->setCompositeOpId(COMPOSITE_DODGE);
        if (compop == "svg:color-burn") layer->setCompositeOpId(COMPOSITE_BURN);
        if (compop == "svg:hard-light") layer->setCompositeOpId(COMPOSITE_HARD_LIGHT);
        if (compop == "svg:soft-light") layer->setCompositeOpId(COMPOSITE_SOFT_LIGHT_SVG);
        if (compop == "svg:difference") layer->setCompositeOpId(COMPOSITE_DIFF);
        if (compop == "svg:color") layer->setCompositeOpId(COMPOSITE_COLOR);
        if (compop == "svg:luminosity") layer->setCompositeOpId(COMPOSITE_LUMINIZE);
        if (compop == "svg:hue") layer->setCompositeOpId(COMPOSITE_HUE);
        if (compop == "svg:saturation") layer->setCompositeOpId(COMPOSITE_SATURATION);
167 168
        //Exclusion isn't in the official list.
        //if (compop == "svg:exclusion") layer->setCompositeOpId(COMPOSITE_EXCLUSION);
169 170 171
    }
    else if (compop.startsWith("krita:")) {
        compop = compop.remove(0, 6);
172
        layer->setCompositeOpId(compop);
173
    }
Halla Rempt's avatar
Halla Rempt committed
174 175
    else {
        // to fix old bugs in krita's ora export
176 177
        if (compop == "color-dodge") layer->setCompositeOpId(COMPOSITE_DODGE);
        if (compop == "difference") layer->setCompositeOpId(COMPOSITE_DIFF);
178
        if (compop == "svg:add") layer->setCompositeOpId(COMPOSITE_ADD);
Halla Rempt's avatar
Halla Rempt committed
179
    }
180

181 182
}

183
void KisOpenRasterStackLoadVisitor::loadAdjustmentLayer(const QDomElement& elem, KisAdjustmentLayerSP aL)
184
{
185
    loadLayerInfo(elem, aL);
186 187
}

Cyrille Berger's avatar
Cyrille Berger committed
188
void KisOpenRasterStackLoadVisitor::loadPaintLayer(const QDomElement& elem, KisPaintLayerSP pL)
189
{
190
    loadLayerInfo(elem, pL);
191

Halla Rempt's avatar
Halla Rempt committed
192
    dbgFile << "Loading was unsuccessful";
193 194
}

195
void KisOpenRasterStackLoadVisitor::loadGroupLayer(const QDomElement& elem, KisGroupLayerSP groupLayer)
196
{
197 198
    dbFile << "Loading group layer" << d->image;
    loadLayerInfo(elem, groupLayer);
Cyrille Berger's avatar
Cyrille Berger committed
199
    for (QDomNode node = elem.firstChild(); !node.isNull(); node = node.nextSibling()) {
Halla Rempt's avatar
Halla Rempt committed
200
        if (node.isElement()) {
Cyrille Berger's avatar
Cyrille Berger committed
201
            QDomElement subelem = node.toElement();
Halla Rempt's avatar
Halla Rempt committed
202
            if (node.nodeName() == "stack") {
203
                double opacity = 1.0;
Halla Rempt's avatar
Halla Rempt committed
204
                if (!subelem.attribute("opacity").isNull()) {
Halla Rempt's avatar
Halla Rempt committed
205
                    opacity = KisDomUtils::toDouble(subelem.attribute("opacity", "1.0"));
206
                }
207
                KisGroupLayerSP layer = new KisGroupLayer(d->image, "", opacity * 255);
208 209 210 211 212
                bool passThrough = true;
                if (subelem.attribute("isolation")=="isolate") {
                    passThrough = false;
                }
                layer->setPassThroughMode(passThrough);
213
                d->image->addNode(layer, groupLayer.data(), 0);
214
                loadGroupLayer(subelem, layer);
Halla Rempt's avatar
Halla Rempt committed
215
            } else if (node.nodeName() == "layer") {
216
                QString filename = subelem.attribute("src");
Halla Rempt's avatar
Halla Rempt committed
217
                if (!filename.isNull()) {
218
                    double opacity = 1.0;
Halla Rempt's avatar
Halla Rempt committed
219
                    opacity = KisDomUtils::toDouble(subelem.attribute("opacity", "1.0"));
220
                    KisImageSP pngImage = d->loadContext->loadDeviceData(filename);
221
                    if (pngImage) {
222 223
                        // If ORA doesn't have resolution info, load the default value(75 ppi) else fetch from stack.xml
                        d->image->setResolution(d->xRes, d->yRes);
224 225 226
                        // now get the device
                        KisPaintDeviceSP device = pngImage->projection();

227 228
                        KisPaintLayerSP layer = new KisPaintLayer(groupLayer->image() , "", opacity * 255, device);
                        d->image->addNode(layer, groupLayer, 0);
229
                        loadPaintLayer(subelem, layer);
Halla Rempt's avatar
Halla Rempt committed
230
                        dbgFile << "Loading was successful";
231 232
                    }
                }
Halla Rempt's avatar
Halla Rempt committed
233
            } else if (node.nodeName() == "filter") {
234 235

                QString filterType = subelem.attribute("type");
236
                QStringList filterTypeSplit = filterType.split(':');
237
                KisFilterSP f = 0;
Halla Rempt's avatar
Halla Rempt committed
238
                if (filterTypeSplit[0] == "applications" && filterTypeSplit[1] == "krita") {
239 240
                    f = KisFilterRegistry::instance()->value(filterTypeSplit[2]);
                }
241
                KisFilterConfigurationSP  kfc = f->defaultConfiguration();
242 243
                KisAdjustmentLayerSP layer = new KisAdjustmentLayer(groupLayer->image() , "", kfc, KisSelectionSP(0));
                d->image->addNode(layer.data(), groupLayer.data(), 0);
244
                loadAdjustmentLayer(subelem, layer);
245

Cyrille Berger's avatar
Cyrille Berger committed
246
            } else {
247
                dbgFile << "Unknown element : " << node.nodeName();
248 249 250 251 252
            }
        }
    }

}