File indexing completed on 2024-05-12 15:58:09

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
0003  *  SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "kis_asl_layer_style_serializer.h"
0009 #include "kis_image.h"
0010 
0011 #include <QDomDocument>
0012 #include <QMultiHash>
0013 
0014 #include <KisResourceModel.h>
0015 #include <KisEmbeddedResourceStorageProxy.h>
0016 
0017 #include <KoResourceServerProvider.h>
0018 #include <resources/KoAbstractGradient.h>
0019 #include <resources/KoSegmentGradient.h>
0020 #include <resources/KoStopGradient.h>
0021 #include <resources/KoPattern.h>
0022 
0023 #include "kis_layer_utils.h"
0024 #include "kis_dom_utils.h"
0025 
0026 #include <kis_layer.h>
0027 #include <kis_pointer_utils.h>
0028 
0029 #include "psd.h"
0030 #include "kis_global.h"
0031 
0032 #include "asl/kis_asl_reader.h"
0033 #include "asl/kis_asl_xml_parser.h"
0034 #include "asl/kis_asl_writer_utils.h"
0035 
0036 #include "asl/kis_asl_xml_writer.h"
0037 #include "asl/kis_asl_writer.h"
0038 
0039 #include <functional>
0040 
0041 using namespace std::placeholders;
0042 
0043 KisAslLayerStyleSerializer::KisAslLayerStyleSerializer()
0044     : m_localResourcesInterface(new KisLocalStrokeResources())
0045 {
0046 }
0047 
0048 KisAslLayerStyleSerializer::~KisAslLayerStyleSerializer()
0049 {
0050 }
0051 
0052 QVector<KisPSDLayerStyleSP> KisAslLayerStyleSerializer::styles() const
0053 {
0054     return m_stylesVector;
0055 }
0056 
0057 void KisAslLayerStyleSerializer::setStyles(const QVector<KisPSDLayerStyleSP> &styles)
0058 {
0059     m_stylesVector = styles;
0060     Q_FOREACH(const KisPSDLayerStyleSP style, styles) {
0061         m_stylesHash.insert(style->psdUuid(), style);
0062     }
0063     m_initialized = true;
0064 }
0065 
0066 QHash<QString, KoPatternSP> KisAslLayerStyleSerializer::patterns() const
0067 {
0068     return m_patternsStore;
0069 }
0070 
0071 QVector<KoAbstractGradientSP> KisAslLayerStyleSerializer::gradients() const
0072 {
0073     return m_gradientsStore;
0074 }
0075 
0076 QHash<QString, KisPSDLayerStyleSP> KisAslLayerStyleSerializer::stylesHash()
0077 {
0078     if (m_stylesHash.count() == 0 && m_stylesVector.count() != 0) {
0079         // build the hash
0080         Q_FOREACH(KisPSDLayerStyleSP style, m_stylesVector) {
0081             m_stylesHash.insert(style->psdUuid(), style);
0082         }
0083     }
0084     return m_stylesHash;
0085 }
0086 
0087 QString compositeOpToBlendMode(const QString &compositeOp)
0088 {
0089     QString mode = "Nrml";
0090 
0091     if (compositeOp == COMPOSITE_OVER) {
0092         mode = "Nrml";
0093     } else if (compositeOp == COMPOSITE_DISSOLVE) {
0094         mode = "Dslv";
0095     } else if (compositeOp == COMPOSITE_DARKEN) {
0096         mode = "Drkn";
0097     } else if (compositeOp == COMPOSITE_MULT) {
0098         mode = "Mltp";
0099     } else if (compositeOp == COMPOSITE_BURN) {
0100         mode = "CBrn";
0101     } else if (compositeOp == COMPOSITE_LINEAR_BURN) {
0102         mode = "linearBurn";
0103     } else if (compositeOp == COMPOSITE_DARKER_COLOR) {
0104         mode = "darkerColor";
0105     } else if (compositeOp == COMPOSITE_LIGHTEN) {
0106         mode = "Lghn";
0107     } else if (compositeOp == COMPOSITE_SCREEN) {
0108         mode = "Scrn";
0109     } else if (compositeOp == COMPOSITE_DODGE) {
0110         mode = "CDdg";
0111     } else if (compositeOp == COMPOSITE_LINEAR_DODGE) {
0112         mode = "linearDodge";
0113     } else if (compositeOp == COMPOSITE_LIGHTER_COLOR) {
0114         mode = "lighterColor";
0115     } else if (compositeOp == COMPOSITE_OVERLAY) {
0116         mode = "Ovrl";
0117     } else if (compositeOp == COMPOSITE_SOFT_LIGHT_PHOTOSHOP) {
0118         mode = "SftL";
0119     } else if (compositeOp == COMPOSITE_HARD_LIGHT) {
0120         mode = "HrdL";
0121     } else if (compositeOp == COMPOSITE_VIVID_LIGHT) {
0122         mode = "vividLight";
0123     } else if (compositeOp == COMPOSITE_LINEAR_LIGHT) {
0124         mode = "linearLight";
0125     } else if (compositeOp == COMPOSITE_PIN_LIGHT) {
0126         mode = "pinLight";
0127     } else if (compositeOp == COMPOSITE_HARD_MIX_PHOTOSHOP) {
0128         mode = "hardMix";
0129     } else if (compositeOp == COMPOSITE_DIFF) {
0130         mode = "Dfrn";
0131     } else if (compositeOp == COMPOSITE_EXCLUSION) {
0132         mode = "Xclu";
0133     } else if (compositeOp == COMPOSITE_SUBTRACT) {
0134         mode = "Sbtr";
0135     } else if (compositeOp == COMPOSITE_DIVIDE) {
0136         mode = "divide";
0137     } else if (compositeOp == COMPOSITE_HUE) {
0138         mode = "H   ";
0139     } else if (compositeOp == COMPOSITE_SATURATION) {
0140         mode = "Strt";
0141     } else if (compositeOp == COMPOSITE_COLOR) {
0142         mode = "Clr ";
0143     } else if (compositeOp == COMPOSITE_LUMINIZE) {
0144         mode = "Lmns";
0145     } else {
0146         dbgKrita << "Unknown composite op:" << mode << "Returning \"Nrml\"!";
0147     }
0148 
0149     return mode;
0150 }
0151 
0152 QString techniqueToString(psd_technique_type technique, const QString &typeId)
0153 {
0154     QString result = "SfBL";
0155 
0156     switch (technique) {
0157     case psd_technique_softer:
0158         result = "SfBL";
0159         break;
0160     case psd_technique_precise:
0161         result = "PrBL";
0162         break;
0163     case psd_technique_slope_limit:
0164         result = "Slmt";
0165         break;
0166     }
0167 
0168     if (typeId == "BETE" && technique == psd_technique_slope_limit) {
0169         warnKrita << "WARNING: techniqueToString: invalid technique type!" << ppVar(technique) << ppVar(typeId);
0170     }
0171 
0172     return result;
0173 }
0174 
0175 QString bevelStyleToString(psd_bevel_style style)
0176 {
0177     QString result = "OtrB";
0178 
0179     switch (style) {
0180     case psd_bevel_outer_bevel:
0181         result = "OtrB";
0182         break;
0183     case psd_bevel_inner_bevel:
0184         result = "InrB";
0185         break;
0186     case psd_bevel_emboss:
0187         result = "Embs";
0188         break;
0189     case psd_bevel_pillow_emboss:
0190         result = "PlEb";
0191         break;
0192     case psd_bevel_stroke_emboss:
0193         result = "strokeEmboss";
0194         break;
0195     }
0196 
0197     return result;
0198 }
0199 
0200 QString gradientTypeToString(psd_gradient_style style)
0201 {
0202     QString result = "Lnr ";
0203 
0204     switch (style) {
0205     case psd_gradient_style_linear:
0206         result = "Lnr ";
0207         break;
0208     case psd_gradient_style_radial:
0209         result = "Rdl ";
0210         break;
0211     case psd_gradient_style_angle:
0212         result = "Angl";
0213         break;
0214     case psd_gradient_style_reflected:
0215         result = "Rflc";
0216         break;
0217     case psd_gradient_style_diamond:
0218         result = "Dmnd";
0219         break;
0220     }
0221 
0222     return result;
0223 }
0224 
0225 QString strokePositionToString(psd_stroke_position position)
0226 {
0227     QString result = "OutF";
0228 
0229     switch (position) {
0230     case psd_stroke_outside:
0231         result = "OutF";
0232         break;
0233     case psd_stroke_inside:
0234         result = "InsF";
0235         break;
0236     case psd_stroke_center:
0237         result = "CtrF";
0238         break;
0239     }
0240 
0241     return result;
0242 }
0243 
0244 QString strokeFillTypeToString(psd_fill_type position)
0245 {
0246     QString result = "SClr";
0247 
0248     switch (position) {
0249     case psd_fill_solid_color:
0250         result = "SClr";
0251         break;
0252     case psd_fill_gradient:
0253         result = "GrFl";
0254         break;
0255     case psd_fill_pattern:
0256         result = "Ptrn";
0257         break;
0258     }
0259 
0260     return result;
0261 }
0262 
0263 QVector<KoPatternSP> KisAslLayerStyleSerializer::fetchAllPatterns(const KisPSDLayerStyle *style)
0264 {
0265     QVector <KoPatternSP> allPatterns;
0266 
0267     if (style->patternOverlay()->effectEnabled()) {
0268         allPatterns << style->patternOverlay()->pattern(style->resourcesInterface());
0269     }
0270 
0271     if (style->stroke()->effectEnabled() &&
0272         style->stroke()->fillType() == psd_fill_pattern) {
0273 
0274         allPatterns << style->stroke()->pattern(style->resourcesInterface());
0275     }
0276 
0277     if(style->bevelAndEmboss()->effectEnabled() &&
0278        style->bevelAndEmboss()->textureEnabled()) {
0279 
0280         allPatterns << style->bevelAndEmboss()->texturePattern(style->resourcesInterface());
0281     }
0282 
0283     KIS_SAFE_ASSERT_RECOVER(!allPatterns.contains(KoPatternSP()))
0284     {
0285         warnKrita << "WARNING: one or more patterns from the style is null";
0286         allPatterns.removeAll(KoPatternSP());
0287     }
0288 
0289     return allPatterns;
0290 }
0291 
0292 QString fetchPatternUuidSafe(KoPatternSP pattern, QHash<KoPatternSP, QString> patternToUuid)
0293 {
0294     if (patternToUuid.contains(pattern)) {
0295         return patternToUuid[pattern];
0296     } else {
0297         warnKrita << "WARNING: the pattern is not present in the Uuid map!";
0298         return "invalid-uuid";
0299     }
0300 }
0301 
0302 QDomDocument KisAslLayerStyleSerializer::formXmlDocument() const
0303 {
0304     KIS_ASSERT_RECOVER(!m_stylesVector.isEmpty()) { return QDomDocument(); }
0305 
0306     QVector<KoPatternSP> allPatterns;
0307 
0308     Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
0309         allPatterns += fetchAllPatterns(style.data());
0310     }
0311 
0312     QHash<KoPatternSP, QString> patternToUuidMap;
0313 
0314     KisAslXmlWriter w;
0315 
0316     if (!allPatterns.isEmpty()) {
0317         w.enterList(ResourceType::Patterns);
0318 
0319         Q_FOREACH (KoPatternSP pattern, allPatterns) {
0320             if (pattern) {
0321                 if (!patternToUuidMap.contains(pattern)) {
0322                     QString uuid = w.writePattern("", pattern);
0323                     patternToUuidMap.insert(pattern, uuid);
0324                 }
0325             } else {
0326                 warnKrita << "WARNING: KisAslLayerStyleSerializer::saveToDevice: saved pattern is null!";
0327             }
0328         }
0329 
0330         w.leaveList();
0331     }
0332 
0333     Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
0334 
0335         w.enterDescriptor("", "", "null");
0336         w.writeText("Nm  ", style->name());
0337         w.writeText("Idnt", style->psdUuid());
0338         w.leaveDescriptor();
0339 
0340         w.enterDescriptor("", "", "Styl");
0341 
0342         w.enterDescriptor("documentMode", "", "documentMode");
0343         w.leaveDescriptor();
0344 
0345         w.enterDescriptor("Lefx", "", "Lefx");
0346 
0347         w.writeUnitFloat("Scl ", "#Prc", 100);
0348         w.writeBoolean("masterFXSwitch", style->isEnabled());
0349 
0350 
0351         // Drop Shadow
0352         const psd_layer_effects_drop_shadow *dropShadow = style->dropShadow();
0353         if (dropShadow->effectEnabled()) {
0354             w.enterDescriptor("DrSh", "", "DrSh");
0355 
0356             w.writeBoolean("enab", dropShadow->effectEnabled());
0357             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(dropShadow->blendMode()));
0358             w.writeColor("Clr ", dropShadow->color());
0359 
0360             w.writeUnitFloat("Opct", "#Prc", dropShadow->opacity());
0361             w.writeBoolean("uglg", dropShadow->useGlobalLight());
0362             w.writeUnitFloat("lagl", "#Ang", dropShadow->angle());
0363             w.writeUnitFloat("Dstn", "#Pxl", dropShadow->distance());
0364             w.writeUnitFloat("Ckmt", "#Pxl", dropShadow->spread());
0365             w.writeUnitFloat("blur", "#Pxl", dropShadow->size());
0366             w.writeUnitFloat("Nose", "#Prc", dropShadow->noise());
0367 
0368             w.writeBoolean("AntA", dropShadow->antiAliased());
0369 
0370             // FIXME: save curves
0371             w.writeCurve("TrnS",
0372                          "Linear",
0373                          QVector<QPointF>() << QPointF() << QPointF(255, 255));
0374 
0375             w.writeBoolean("layerConceals", dropShadow->knocksOut());
0376             w.leaveDescriptor();
0377         }
0378 
0379         // Inner Shadow
0380         const psd_layer_effects_inner_shadow *innerShadow = style->innerShadow();
0381         if (innerShadow->effectEnabled()) {
0382             w.enterDescriptor("IrSh", "", "IrSh");
0383 
0384             w.writeBoolean("enab", innerShadow->effectEnabled());
0385             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(innerShadow->blendMode()));
0386             w.writeColor("Clr ", innerShadow->color());
0387 
0388             w.writeUnitFloat("Opct", "#Prc", innerShadow->opacity());
0389             w.writeBoolean("uglg", innerShadow->useGlobalLight());
0390             w.writeUnitFloat("lagl", "#Ang", innerShadow->angle());
0391             w.writeUnitFloat("Dstn", "#Pxl", innerShadow->distance());
0392             w.writeUnitFloat("Ckmt", "#Pxl", innerShadow->spread());
0393             w.writeUnitFloat("blur", "#Pxl", innerShadow->size());
0394             w.writeUnitFloat("Nose", "#Prc", innerShadow->noise());
0395 
0396             w.writeBoolean("AntA", innerShadow->antiAliased());
0397 
0398             // FIXME: save curves
0399             w.writeCurve("TrnS",
0400                          "Linear",
0401                          QVector<QPointF>() << QPointF() << QPointF(255, 255));
0402 
0403             w.leaveDescriptor();
0404         }
0405 
0406         // Outer Glow
0407         const psd_layer_effects_outer_glow *outerGlow = style->outerGlow();
0408         if (outerGlow->effectEnabled()) {
0409             w.enterDescriptor("OrGl", "", "OrGl");
0410 
0411             w.writeBoolean("enab", outerGlow->effectEnabled());
0412             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(outerGlow->blendMode()));
0413 
0414             if (outerGlow->fillType() == psd_fill_gradient && outerGlow->gradient(style->resourcesInterface())) {
0415                 KoSegmentGradient *segmentGradient = dynamic_cast<KoSegmentGradient*>(outerGlow->gradient(style->resourcesInterface()).data());
0416                 KoStopGradient *stopGradient = dynamic_cast<KoStopGradient*>(outerGlow->gradient(style->resourcesInterface()).data());
0417 
0418                 if (segmentGradient && segmentGradient->valid()) {
0419                     w.writeSegmentGradient("Grad", segmentGradient);
0420                 } else if (stopGradient  && stopGradient->valid()) {
0421                     w.writeStopGradient("Grad", stopGradient);
0422                 } else {
0423                     warnKrita << "WARNING: OG: Unknown gradient type!";
0424                     w.writeColor("Clr ", outerGlow->color());
0425                 }
0426 
0427             } else {
0428                 w.writeColor("Clr ", outerGlow->color());
0429             }
0430 
0431             w.writeUnitFloat("Opct", "#Prc", outerGlow->opacity());
0432 
0433             w.writeEnum("GlwT", "BETE", techniqueToString(outerGlow->technique(), "BETE"));
0434 
0435             w.writeUnitFloat("Ckmt", "#Pxl", outerGlow->spread());
0436             w.writeUnitFloat("blur", "#Pxl", outerGlow->size());
0437             w.writeUnitFloat("Nose", "#Prc", outerGlow->noise());
0438 
0439             w.writeUnitFloat("ShdN", "#Prc", outerGlow->jitter());
0440 
0441             w.writeBoolean("AntA", outerGlow->antiAliased());
0442 
0443             // FIXME: save curves
0444             w.writeCurve("TrnS",
0445                          "Linear",
0446                          QVector<QPointF>() << QPointF() << QPointF(255, 255));
0447 
0448             w.writeUnitFloat("Inpr", "#Prc", outerGlow->range());
0449 
0450             w.leaveDescriptor();
0451         }
0452 
0453         // Inner Glow
0454         const psd_layer_effects_inner_glow *innerGlow = style->innerGlow();
0455         if (innerGlow->effectEnabled()) {
0456             w.enterDescriptor("IrGl", "", "IrGl");
0457 
0458             w.writeBoolean("enab", innerGlow->effectEnabled());
0459             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(innerGlow->blendMode()));
0460 
0461             if (innerGlow->fillType() == psd_fill_gradient && innerGlow->gradient(style->resourcesInterface())) {
0462                 KoSegmentGradient *segmentGradient = dynamic_cast<KoSegmentGradient*>(innerGlow->gradient(style->resourcesInterface()).data());
0463                 KoStopGradient *stopGradient = dynamic_cast<KoStopGradient*>(innerGlow->gradient(style->resourcesInterface()).data());
0464 
0465                 if (segmentGradient  && innerGlow->gradient(style->resourcesInterface())->valid()) {
0466                     w.writeSegmentGradient("Grad", segmentGradient);
0467                 } else if (stopGradient  && innerGlow->gradient(style->resourcesInterface())->valid()) {
0468                     w.writeStopGradient("Grad", stopGradient);
0469                 } else {
0470                     warnKrita << "WARNING: IG: Unknown gradient type!";
0471                     w.writeColor("Clr ", innerGlow->color());
0472                 }
0473 
0474             } else {
0475                 w.writeColor("Clr ", innerGlow->color());
0476             }
0477 
0478             w.writeUnitFloat("Opct", "#Prc", innerGlow->opacity());
0479 
0480             w.writeEnum("GlwT", "BETE", techniqueToString(innerGlow->technique(), "BETE"));
0481 
0482             w.writeUnitFloat("Ckmt", "#Pxl", innerGlow->spread());
0483             w.writeUnitFloat("blur", "#Pxl", innerGlow->size());
0484 
0485             // NOTE: order is swapped in ASL!
0486             w.writeUnitFloat("ShdN", "#Prc", innerGlow->jitter());
0487             w.writeUnitFloat("Nose", "#Prc", innerGlow->noise());
0488 
0489             w.writeBoolean("AntA", innerGlow->antiAliased());
0490 
0491             w.writeEnum("glwS", "IGSr", innerGlow->source() == psd_glow_center ? "SrcC" : "SrcE");
0492 
0493             // FIXME: save curves
0494             w.writeCurve("TrnS",
0495                          "Linear",
0496                          QVector<QPointF>() << QPointF() << QPointF(255, 255));
0497 
0498             w.writeUnitFloat("Inpr", "#Prc", innerGlow->range());
0499 
0500             w.leaveDescriptor();
0501         }
0502 
0503         // Bevel and Emboss
0504         const psd_layer_effects_bevel_emboss *bevelAndEmboss = style->bevelAndEmboss();
0505         if (bevelAndEmboss->effectEnabled()) {
0506             w.enterDescriptor("ebbl", "", "ebbl");
0507 
0508             w.writeBoolean("enab", bevelAndEmboss->effectEnabled());
0509 
0510             w.writeEnum("hglM", "BlnM", compositeOpToBlendMode(bevelAndEmboss->highlightBlendMode()));
0511             w.writeColor("hglC", bevelAndEmboss->highlightColor());
0512             w.writeUnitFloat("hglO", "#Prc", bevelAndEmboss->highlightOpacity());
0513 
0514             w.writeEnum("sdwM", "BlnM", compositeOpToBlendMode(bevelAndEmboss->shadowBlendMode()));
0515             w.writeColor("sdwC", bevelAndEmboss->shadowColor());
0516             w.writeUnitFloat("sdwO", "#Prc", bevelAndEmboss->shadowOpacity());
0517 
0518             w.writeEnum("bvlT", "bvlT", techniqueToString(bevelAndEmboss->technique(), "bvlT"));
0519             w.writeEnum("bvlS", "BESl", bevelStyleToString(bevelAndEmboss->style()));
0520 
0521             w.writeBoolean("uglg", bevelAndEmboss->useGlobalLight());
0522             w.writeUnitFloat("lagl", "#Ang", bevelAndEmboss->angle());
0523             w.writeUnitFloat("Lald", "#Ang", bevelAndEmboss->altitude());
0524 
0525             w.writeUnitFloat("srgR", "#Prc", bevelAndEmboss->depth());
0526             w.writeUnitFloat("blur", "#Pxl", bevelAndEmboss->size());
0527             w.writeEnum("bvlD", "BESs", bevelAndEmboss->direction() == psd_direction_up ? "In  " : "Out ");
0528 
0529             // FIXME: save curves
0530             w.writeCurve("TrnS",
0531                          "Linear",
0532                          QVector<QPointF>() << QPointF() << QPointF(255, 255));
0533 
0534             w.writeBoolean("antialiasGloss", bevelAndEmboss->glossAntiAliased());
0535 
0536             w.writeUnitFloat("Sftn", "#Pxl", bevelAndEmboss->soften());
0537 
0538             if (bevelAndEmboss->contourEnabled()) {
0539                 w.writeBoolean("useShape", bevelAndEmboss->contourEnabled());
0540 
0541                 // FIXME: save curves
0542                 w.writeCurve("MpgS",
0543                              "Linear",
0544                              QVector<QPointF>() << QPointF() << QPointF(255, 255));
0545 
0546                 w.writeBoolean("AntA", bevelAndEmboss->antiAliased());
0547                 w.writeUnitFloat("Inpr", "#Prc", bevelAndEmboss->contourRange());
0548             }
0549 
0550             w.writeBoolean("useTexture", bevelAndEmboss->textureEnabled());
0551 
0552             if (bevelAndEmboss->textureEnabled()) {
0553                 w.writeBoolean("InvT", bevelAndEmboss->textureInvert());
0554                 w.writeBoolean("Algn", bevelAndEmboss->textureAlignWithLayer());
0555                 w.writeUnitFloat("Scl ", "#Prc", bevelAndEmboss->textureScale());
0556                 w.writeUnitFloat("textureDepth ", "#Prc", bevelAndEmboss->textureDepth());
0557 
0558                 KoPatternSP pattern = bevelAndEmboss->texturePattern(style->resourcesInterface());
0559                 w.writePatternRef("Ptrn", pattern, fetchPatternUuidSafe(pattern, patternToUuidMap));
0560                 w.writePhasePoint("phase", bevelAndEmboss->texturePhase());
0561             }
0562 
0563             w.leaveDescriptor();
0564         }
0565 
0566         // Satin
0567         const psd_layer_effects_satin *satin = style->satin();
0568         if (satin->effectEnabled()) {
0569             w.enterDescriptor("ChFX", "", "ChFX");
0570 
0571             w.writeBoolean("enab", satin->effectEnabled());
0572             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(satin->blendMode()));
0573             w.writeColor("Clr ", satin->color());
0574 
0575             w.writeBoolean("AntA", satin->antiAliased());
0576             w.writeBoolean("Invr", satin->invert());
0577             w.writeUnitFloat("Opct", "#Prc", satin->opacity());
0578             w.writeUnitFloat("lagl", "#Ang", satin->angle());
0579             w.writeUnitFloat("Dstn", "#Pxl", satin->distance());
0580             w.writeUnitFloat("blur", "#Pxl", satin->size());
0581 
0582             // FIXME: save curves
0583             w.writeCurve("MpgS",
0584                          "Linear",
0585                          QVector<QPointF>() << QPointF() << QPointF(255, 255));
0586 
0587             w.leaveDescriptor();
0588         }
0589 
0590         const psd_layer_effects_color_overlay *colorOverlay = style->colorOverlay();
0591         if (colorOverlay->effectEnabled()) {
0592             w.enterDescriptor("SoFi", "", "SoFi");
0593 
0594             w.writeBoolean("enab", colorOverlay->effectEnabled());
0595             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(colorOverlay->blendMode()));
0596             w.writeUnitFloat("Opct", "#Prc", colorOverlay->opacity());
0597             w.writeColor("Clr ", colorOverlay->color());
0598 
0599             w.leaveDescriptor();
0600         }
0601 
0602         // Gradient Overlay
0603         const psd_layer_effects_gradient_overlay *gradientOverlay = style->gradientOverlay();
0604         KoSegmentGradient *segmentGradient = dynamic_cast<KoSegmentGradient*>(gradientOverlay->gradient(style->resourcesInterface()).data());
0605         KoStopGradient *stopGradient = dynamic_cast<KoStopGradient*>(gradientOverlay->gradient(style->resourcesInterface()).data());
0606 
0607         if (gradientOverlay->effectEnabled() && ((segmentGradient && segmentGradient->valid()) || (stopGradient && stopGradient->valid()))) {
0608             w.enterDescriptor("GrFl", "", "GrFl");
0609 
0610             w.writeBoolean("enab", gradientOverlay->effectEnabled());
0611             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(gradientOverlay->blendMode()));
0612             w.writeUnitFloat("Opct", "#Prc", gradientOverlay->opacity());
0613 
0614             if (segmentGradient && segmentGradient->valid()) {
0615                 w.writeSegmentGradient("Grad", segmentGradient);
0616             } else if (stopGradient && stopGradient->valid()) {
0617                 w.writeStopGradient("Grad", stopGradient);
0618             }
0619 
0620             w.writeUnitFloat("Angl", "#Ang", gradientOverlay->angle());
0621 
0622             w.writeEnum("Type", "GrdT", gradientTypeToString(gradientOverlay->style()));
0623 
0624             w.writeBoolean("Rvrs", gradientOverlay->reverse());
0625             w.writeBoolean("Algn", gradientOverlay->alignWithLayer());
0626             w.writeUnitFloat("Scl ", "#Prc", gradientOverlay->scale());
0627 
0628             w.writeOffsetPoint("Ofst", gradientOverlay->gradientOffset());
0629 
0630             w.writeBoolean("Dthr", gradientOverlay->dither());
0631 
0632             w.leaveDescriptor();
0633         }
0634 
0635         // Pattern Overlay
0636         const psd_layer_effects_pattern_overlay *patternOverlay = style->patternOverlay();
0637         if (patternOverlay->effectEnabled()) {
0638             w.enterDescriptor("patternFill", "", "patternFill");
0639 
0640             w.writeBoolean("enab", patternOverlay->effectEnabled());
0641             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(patternOverlay->blendMode()));
0642             w.writeUnitFloat("Opct", "#Prc", patternOverlay->opacity());
0643 
0644             KoPatternSP pattern = patternOverlay->pattern(style->resourcesInterface());
0645             w.writePatternRef("Ptrn", pattern, fetchPatternUuidSafe(pattern, patternToUuidMap));
0646 
0647             w.writeUnitFloat("Scl ", "#Prc", patternOverlay->scale());
0648             w.writeBoolean("Algn", patternOverlay->alignWithLayer());
0649             w.writePhasePoint("phase", patternOverlay->patternPhase());
0650 
0651             w.leaveDescriptor();
0652         }
0653 
0654         const psd_layer_effects_stroke *stroke = style->stroke();
0655         if (stroke->effectEnabled()) {
0656             w.enterDescriptor("FrFX", "", "FrFX");
0657 
0658             w.writeBoolean("enab", stroke->effectEnabled());
0659 
0660             w.writeEnum("Styl", "FStl", strokePositionToString(stroke->position()));
0661             w.writeEnum("PntT", "FrFl", strokeFillTypeToString(stroke->fillType()));
0662 
0663             w.writeEnum("Md  ", "BlnM", compositeOpToBlendMode(stroke->blendMode()));
0664             w.writeUnitFloat("Opct", "#Prc", stroke->opacity());
0665 
0666             w.writeUnitFloat("Sz  ", "#Pxl", stroke->size());
0667 
0668             if (stroke->fillType() == psd_fill_solid_color) {
0669                 w.writeColor("Clr ", stroke->color());
0670             }
0671             else if (stroke->fillType() == psd_fill_gradient) {
0672                 KoSegmentGradient *segmentGradient = dynamic_cast<KoSegmentGradient*>(stroke->gradient(style->resourcesInterface()).data());
0673                 KoStopGradient *stopGradient = dynamic_cast<KoStopGradient*>(stroke->gradient(style->resourcesInterface()).data());
0674 
0675                 if (segmentGradient && segmentGradient->valid()) {
0676                     w.writeSegmentGradient("Grad", segmentGradient);
0677                 } else if (stopGradient && stopGradient->valid()) {
0678                     w.writeStopGradient("Grad", stopGradient);
0679                 } else {
0680                     warnKrita << "WARNING: Stroke: Unknown gradient type!";
0681                     w.writeColor("Clr ", stroke->color());
0682                 }
0683 
0684                 w.writeUnitFloat("Angl", "#Ang", stroke->angle());
0685                 w.writeEnum("Type", "GrdT", gradientTypeToString(stroke->style()));
0686 
0687                 w.writeBoolean("Rvrs", stroke->reverse());
0688                 w.writeUnitFloat("Scl ", "#Prc", stroke->scale());
0689                 w.writeBoolean("Algn", stroke->alignWithLayer());
0690                 w.writeOffsetPoint("Ofst", stroke->gradientOffset());
0691 
0692                 w.writeBoolean("Dthr", stroke->dither());
0693 
0694             } else if (stroke->fillType() == psd_fill_pattern) {
0695 
0696                 KoPatternSP pattern = stroke->pattern(style->resourcesInterface());
0697                 w.writePatternRef("Ptrn", pattern, fetchPatternUuidSafe(pattern, patternToUuidMap));
0698                 w.writeUnitFloat("Scl ", "#Prc", stroke->scale());
0699                 w.writeBoolean("Lnkd", stroke->alignWithLayer());
0700                 w.writePhasePoint("phase", stroke->patternPhase());
0701             }
0702 
0703             w.leaveDescriptor();
0704         }
0705 
0706         w.leaveDescriptor();
0707         w.leaveDescriptor();
0708     }
0709 
0710     return w.document();
0711 }
0712 
0713 inline QDomNode findNodeByClassId(const QString &classId, QDomNode parent) {
0714     return KisDomUtils::findElementByAttibute(parent, "node", "classId", classId);
0715 }
0716 
0717 void replaceAllChildren(QDomNode src, QDomNode dst)
0718 {
0719     QDomNode node;
0720 
0721     do {
0722         node = dst.lastChild();
0723         dst.removeChild(node);
0724 
0725     } while(!node.isNull());
0726 
0727 
0728     node = src.firstChild();
0729     while(!node.isNull()) {
0730         dst.appendChild(node);
0731         node = src.firstChild();
0732     }
0733 
0734     src.parentNode().removeChild(src);
0735 }
0736 
0737 QDomDocument KisAslLayerStyleSerializer::formPsdXmlDocument() const
0738 {
0739     QDomDocument doc = formXmlDocument();
0740 
0741     QDomNode nullNode = findNodeByClassId("null", doc.documentElement());
0742     QDomNode stylNode = findNodeByClassId("Styl", doc.documentElement());
0743     QDomNode lefxNode = findNodeByClassId("Lefx", stylNode);
0744 
0745     replaceAllChildren(lefxNode, nullNode);
0746 
0747     return doc;
0748 }
0749 
0750 QVector<KoResourceSP> KisAslLayerStyleSerializer::fetchEmbeddedResources(const KisPSDLayerStyle *style)
0751 {
0752     QVector<KoResourceSP> embeddedResources = implicitCastList<KoResourceSP>(fetchAllPatterns(style));
0753 
0754     if (style->gradientOverlay()->effectEnabled()) {
0755         embeddedResources << style->gradientOverlay()->gradient(style->resourcesInterface());
0756         KIS_ASSERT(embeddedResources.last().data());
0757     }
0758 
0759     if (style->innerGlow()->effectEnabled() && style->innerGlow()->fillType() == psd_fill_gradient) {
0760         embeddedResources << style->innerGlow()->gradient(style->resourcesInterface());
0761         KIS_ASSERT(embeddedResources.last().data());
0762     }
0763 
0764     if (style->outerGlow()->effectEnabled() && style->outerGlow()->fillType() == psd_fill_gradient) {
0765         embeddedResources << style->outerGlow()->gradient(style->resourcesInterface());
0766         KIS_ASSERT(embeddedResources.last().data());
0767     }
0768 
0769     if (style->stroke()->effectEnabled() && style->stroke()->fillType() == psd_fill_gradient) {
0770         embeddedResources << style->stroke()->gradient(style->resourcesInterface());
0771         KIS_ASSERT(embeddedResources.last().data());
0772     }
0773 
0774     KIS_SAFE_ASSERT_RECOVER(!embeddedResources.contains(KoResourceSP()))
0775     {
0776         embeddedResources.removeAll(KoResourceSP());
0777     }
0778 
0779     return embeddedResources;
0780 }
0781 
0782 void KisAslLayerStyleSerializer::saveToDevice(QIODevice &device)
0783 {
0784     QDomDocument doc = formXmlDocument();
0785     KIS_ASSERT(!doc.isNull());
0786 
0787     KisAslWriter writer;
0788     writer.writeFile(device, doc);
0789 }
0790 
0791 bool KisAslLayerStyleSerializer::saveToFile(const QString& filename)
0792 {
0793     QFile file(filename);
0794 
0795     if (!file.open(QIODevice::WriteOnly)) {
0796         dbgKrita << "Can't open file " << filename;
0797         return false;
0798     }
0799     saveToDevice(file);
0800     file.close();
0801 
0802     return true;
0803 }
0804 
0805 void convertAndSetBlendMode(const QString &mode, std::function<void(const QString &)> setBlendMode)
0806 {
0807     QString compositeOp = COMPOSITE_OVER;
0808 
0809     if (mode == "Nrml") {
0810         compositeOp = COMPOSITE_OVER;
0811     } else if (mode == "Dslv") {
0812         compositeOp = COMPOSITE_DISSOLVE;
0813     } else if (mode == "Drkn") {
0814         compositeOp = COMPOSITE_DARKEN;
0815     } else if (mode == "Mltp") {
0816         compositeOp = COMPOSITE_MULT;
0817     } else if (mode == "CBrn") {
0818         compositeOp = COMPOSITE_BURN;
0819     } else if (mode == "linearBurn") {
0820         compositeOp = COMPOSITE_LINEAR_BURN;
0821     } else if (mode == "darkerColor") {
0822         compositeOp = COMPOSITE_DARKER_COLOR;
0823     } else if (mode == "Lghn") {
0824         compositeOp = COMPOSITE_LIGHTEN;
0825     } else if (mode == "Scrn") {
0826         compositeOp = COMPOSITE_SCREEN;
0827     } else if (mode == "CDdg") {
0828         compositeOp = COMPOSITE_DODGE;
0829     } else if (mode == "linearDodge") {
0830         compositeOp = COMPOSITE_LINEAR_DODGE;
0831     } else if (mode == "lighterColor") {
0832         compositeOp = COMPOSITE_LIGHTER_COLOR;
0833     } else if (mode == "Ovrl") {
0834         compositeOp = COMPOSITE_OVERLAY;
0835     } else if (mode == "SftL") {
0836         compositeOp = COMPOSITE_SOFT_LIGHT_PHOTOSHOP;
0837     } else if (mode == "HrdL") {
0838         compositeOp = COMPOSITE_HARD_LIGHT;
0839     } else if (mode == "vividLight") {
0840         compositeOp = COMPOSITE_VIVID_LIGHT;
0841     } else if (mode == "linearLight") {
0842         compositeOp = COMPOSITE_LINEAR_LIGHT;
0843     } else if (mode == "pinLight") {
0844         compositeOp = COMPOSITE_PIN_LIGHT;
0845     } else if (mode == "hardMix") {
0846         compositeOp = COMPOSITE_HARD_MIX_PHOTOSHOP;
0847     } else if (mode == "Dfrn") {
0848         compositeOp = COMPOSITE_DIFF;
0849     } else if (mode == "Xclu") {
0850         compositeOp = COMPOSITE_EXCLUSION;
0851     } else if (mode == "Sbtr") {
0852         compositeOp = COMPOSITE_SUBTRACT;
0853     } else if (mode == "divide") {
0854         compositeOp = COMPOSITE_DIVIDE;
0855     } else if (mode == "H   ") {
0856         compositeOp = COMPOSITE_HUE;
0857     } else if (mode == "Strt") {
0858         compositeOp = COMPOSITE_SATURATION;
0859     } else if (mode == "Clr ") {
0860         compositeOp = COMPOSITE_COLOR;
0861     } else if (mode == "Lmns") {
0862         compositeOp = COMPOSITE_LUMINIZE;
0863     } else {
0864         dbgKrita << "Unknown blending mode:" << mode << "Returning COMPOSITE_OVER!";
0865     }
0866 
0867     setBlendMode(compositeOp);
0868 }
0869 
0870 void convertAndSetCurve(const QString &name, const QVector<QPointF> &points, std::function<void(const quint8 *)> setCurveLookupTable)
0871 {
0872     Q_UNUSED(name);
0873     Q_UNUSED(points);
0874     Q_UNUSED(setCurveLookupTable);
0875 
0876     warnKrita << "convertAndSetBlendMode:" << "Curve conversion is not implemented yet";
0877 }
0878 
0879 template<typename T>
0880 void convertAndSetEnum(const QString &value, const QMap<QString, T> map, std::function<void(T)> setMappedValue)
0881 {
0882     setMappedValue(map[value]);
0883 }
0884 
0885 inline QString _prepaddr(const QString &pref, const QString &addr) {
0886     return pref + addr;
0887 }
0888 
0889 #define CONN_TEXT_RADDR(addr, method, object, type) m_catcher.subscribeText(addr, std::bind(&type::method, object, _1))
0890 #define CONN_COLOR(addr, method, object, type, prefix) m_catcher.subscribeColor(_prepaddr(prefix, addr), std::bind(&type::method, object, _1))
0891 #define CONN_UNITF(addr, unit, method, object, type, prefix) m_catcher.subscribeUnitFloat(_prepaddr(prefix, addr), unit, std::bind(&type::method, object, _1))
0892 #define CONN_BOOL(addr, method, object, type, prefix) m_catcher.subscribeBoolean(_prepaddr(prefix, addr), std::bind(&type::method, object, _1))
0893 
0894 #define CONN_POINT(addr, method, object, type, prefix) m_catcher.subscribePoint(_prepaddr(prefix, addr), std::bind(&type::method, object, _1))
0895 
0896 #define CONN_COMPOSITE_OP(addr, method, object, type, prefix)                                                                                                  \
0897     {                                                                                                                                                          \
0898         std::function<void(const QString &)> setter = std::bind(&type::method, object, _1);                                                                    \
0899         m_catcher.subscribeEnum(_prepaddr(prefix, addr), "BlnM", std::bind(convertAndSetBlendMode, _1, setter));                                               \
0900     }
0901 
0902 #define CONN_CURVE(addr, method, object, type, prefix)                                                                                                         \
0903     {                                                                                                                                                          \
0904         std::function<void(const quint8 *)> setter = std::bind(&type::method, object, _1);                                                                     \
0905         m_catcher.subscribeCurve(_prepaddr(prefix, addr), std::bind(convertAndSetCurve, _1, _2, setter));                                                      \
0906     }
0907 
0908 #define CONN_ENUM(addr, tag, method, map, mapped_type, object, type, prefix)                                                                                   \
0909     {                                                                                                                                                          \
0910         std::function<void(mapped_type)> setter = std::bind(&type::method, object, _1);                                                                        \
0911         m_catcher.subscribeEnum(_prepaddr(prefix, addr), tag, std::bind(convertAndSetEnum<mapped_type>, _1, map, setter));                                     \
0912     }
0913 
0914 #define CONN_GRADIENT(addr, method, object, type, prefix)                                                                                                      \
0915     {                                                                                                                                                          \
0916         std::function<void(KoAbstractGradientSP)> setter = std::bind(&type::method, object, _1);                                                               \
0917         m_catcher.subscribeGradient(_prepaddr(prefix, addr), std::bind(&KisAslLayerStyleSerializer::assignGradientObject, this, _1, setter));                  \
0918     }
0919 
0920 #define CONN_PATTERN(addr, method, object, type, prefix)                                                                                                       \
0921     {                                                                                                                                                          \
0922         std::function<void(KoPatternSP)> setter = std::bind(&type::method, object, _1);                                                                        \
0923         m_catcher.subscribePatternRef(_prepaddr(prefix, addr), std::bind(&KisAslLayerStyleSerializer::assignPatternObject, this, _1, _2, setter));             \
0924     }
0925 
0926 void KisAslLayerStyleSerializer::registerPatternObject(const KoPatternSP pattern, const QString& patternUuid) {
0927 
0928     if (!pattern) {
0929         warnKrita << "WARNING: got an empty pattern:" << patternUuid;
0930         return;
0931     }
0932 
0933     if (m_patternsStore.contains(patternUuid)) {
0934         warnKrita << "WARNING: ASL style contains a duplicated pattern!" << ppVar(pattern->name()) << ppVar(m_patternsStore[patternUuid]->name());
0935     } else {
0936         pattern->setFilename(patternUuid + QString(".pat"));
0937         m_patternsStore.insert(patternUuid, pattern);
0938         m_localResourcesInterface->addResource(pattern);
0939     }
0940 }
0941 
0942 void KisAslLayerStyleSerializer::assignPatternObject(const QString &patternUuid, const QString &patternName, std::function<void(KoPatternSP)> setPattern)
0943 {
0944     Q_UNUSED(patternName);
0945 
0946     KoPatternSP pattern;
0947 
0948     if (!m_patternsStore.contains(patternUuid)) {
0949         warnKrita << "WARNING: ASL style contains non-existent pattern reference! Searching for uuid: "
0950                   << patternUuid << " (name: " << patternName << ")";
0951 
0952         QImage dumbImage(32, 32, QImage::Format_ARGB32);
0953         dumbImage.fill(Qt::red);
0954         KoPatternSP dumbPattern(new KoPattern(dumbImage, "invalid", ""));
0955         registerPatternObject(dumbPattern, patternUuid + QString("_invalid"));
0956         pattern = dumbPattern;
0957     } else {
0958         pattern = m_patternsStore[patternUuid];
0959     }
0960 
0961     setPattern(pattern);
0962 }
0963 
0964 void KisAslLayerStyleSerializer::assignGradientObject(KoAbstractGradientSP gradient, std::function<void(KoAbstractGradientSP)> setGradient)
0965 {
0966     m_gradientsStore.append(gradient);
0967     m_localResourcesInterface->addResource(gradient);
0968     setGradient(gradient);
0969 }
0970 
0971 class FillStylesCorrector {
0972 public:
0973 
0974     static void correct(KisPSDLayerStyle *style) {
0975         correctWithoutPattern(style->outerGlow(), style->resourcesInterface());
0976         correctWithoutPattern(style->innerGlow(), style->resourcesInterface());
0977         correctWithPattern(style->stroke(), style->resourcesInterface());
0978     }
0979 
0980 private:
0981 
0982     template <class T>
0983     static void correctWithPattern(T *config, KisResourcesInterfaceSP resourcesInterface) {
0984         if (config->pattern(resourcesInterface)) {
0985             config->setFillType(psd_fill_pattern);
0986         } else if (config->gradient(resourcesInterface)) {
0987             config->setFillType(psd_fill_gradient);
0988         } else {
0989             config->setFillType(psd_fill_solid_color);
0990         }
0991     }
0992 
0993     template <class T>
0994     static void correctWithoutPattern(T *config, KisResourcesInterfaceSP resourcesInterface) {
0995         if (config->gradient(resourcesInterface)) {
0996             config->setFillType(psd_fill_gradient);
0997         } else {
0998             config->setFillType(psd_fill_solid_color);
0999         }
1000     }
1001 };
1002 
1003 void KisAslLayerStyleSerializer::connectCatcherToStyle(KisPSDLayerStyle *style, const QString &prefix)
1004 {
1005     CONN_TEXT_RADDR("/null/Nm  ", setName, style, KisPSDLayerStyle);
1006     CONN_TEXT_RADDR("/null/Idnt", setPsdUuid, style, KisPSDLayerStyle);
1007 
1008     CONN_BOOL("/masterFXSwitch", setEnabled, style, KisPSDLayerStyle, prefix);
1009 
1010     psd_layer_effects_drop_shadow *dropShadow = style->dropShadow();
1011 
1012     CONN_COMPOSITE_OP("/DrSh/Md  ", setBlendMode, dropShadow, psd_layer_effects_drop_shadow, prefix);
1013     CONN_COLOR("/DrSh/Clr ", setColor, dropShadow, psd_layer_effects_drop_shadow, prefix);
1014     CONN_UNITF("/DrSh/Opct", "#Prc", setOpacity, dropShadow, psd_layer_effects_drop_shadow, prefix);
1015     CONN_UNITF("/DrSh/lagl", "#Ang", setAngle, dropShadow, psd_layer_effects_drop_shadow, prefix);
1016     CONN_UNITF("/DrSh/Dstn", "#Pxl", setDistance, dropShadow, psd_layer_effects_drop_shadow, prefix);
1017     CONN_UNITF("/DrSh/Ckmt", "#Pxl", setSpread, dropShadow, psd_layer_effects_drop_shadow, prefix);
1018     CONN_UNITF("/DrSh/blur", "#Pxl", setSize, dropShadow, psd_layer_effects_drop_shadow, prefix);
1019     CONN_UNITF("/DrSh/Nose", "#Prc", setNoise, dropShadow, psd_layer_effects_drop_shadow, prefix);
1020     CONN_BOOL("/DrSh/enab", setEffectEnabled, dropShadow, psd_layer_effects_drop_shadow, prefix);
1021     CONN_BOOL("/DrSh/uglg", setUseGlobalLight, dropShadow, psd_layer_effects_drop_shadow, prefix);
1022     CONN_BOOL("/DrSh/AntA", setAntiAliased, dropShadow, psd_layer_effects_drop_shadow, prefix);
1023     CONN_BOOL("/DrSh/layerConceals", setKnocksOut, dropShadow, psd_layer_effects_drop_shadow, prefix);
1024     CONN_CURVE("/DrSh/TrnS", setContourLookupTable, dropShadow, psd_layer_effects_drop_shadow, prefix);
1025 
1026     psd_layer_effects_inner_shadow *innerShadow = style->innerShadow();
1027 
1028     CONN_COMPOSITE_OP("/IrSh/Md  ", setBlendMode, innerShadow, psd_layer_effects_inner_shadow, prefix);
1029     CONN_COLOR("/IrSh/Clr ", setColor, innerShadow, psd_layer_effects_inner_shadow, prefix);
1030     CONN_UNITF("/IrSh/Opct", "#Prc", setOpacity, innerShadow, psd_layer_effects_inner_shadow, prefix);
1031     CONN_UNITF("/IrSh/lagl", "#Ang", setAngle, innerShadow, psd_layer_effects_inner_shadow, prefix);
1032     CONN_UNITF("/IrSh/Dstn", "#Pxl", setDistance, innerShadow, psd_layer_effects_inner_shadow, prefix);
1033     CONN_UNITF("/IrSh/Ckmt", "#Pxl", setSpread, innerShadow, psd_layer_effects_inner_shadow, prefix);
1034     CONN_UNITF("/IrSh/blur", "#Pxl", setSize, innerShadow, psd_layer_effects_inner_shadow, prefix);
1035     CONN_UNITF("/IrSh/Nose", "#Prc", setNoise, innerShadow, psd_layer_effects_inner_shadow, prefix);
1036     CONN_BOOL("/IrSh/enab", setEffectEnabled, innerShadow, psd_layer_effects_inner_shadow, prefix);
1037     CONN_BOOL("/IrSh/uglg", setUseGlobalLight, innerShadow, psd_layer_effects_inner_shadow, prefix);
1038     CONN_BOOL("/IrSh/AntA", setAntiAliased, innerShadow, psd_layer_effects_inner_shadow, prefix);
1039     CONN_CURVE("/IrSh/TrnS", setContourLookupTable, innerShadow, psd_layer_effects_inner_shadow, prefix);
1040 
1041     psd_layer_effects_outer_glow *outerGlow = style->outerGlow();
1042 
1043     CONN_COMPOSITE_OP("/OrGl/Md  ", setBlendMode, outerGlow, psd_layer_effects_outer_glow, prefix);
1044     CONN_COLOR("/OrGl/Clr ", setColor, outerGlow, psd_layer_effects_outer_glow, prefix);
1045     CONN_UNITF("/OrGl/Opct", "#Prc", setOpacity, outerGlow, psd_layer_effects_outer_glow, prefix);
1046     CONN_UNITF("/OrGl/Ckmt", "#Pxl", setSpread, outerGlow, psd_layer_effects_outer_glow, prefix);
1047     CONN_UNITF("/OrGl/blur", "#Pxl", setSize, outerGlow, psd_layer_effects_outer_glow, prefix);
1048     CONN_UNITF("/OrGl/Nose", "#Prc", setNoise, outerGlow, psd_layer_effects_outer_glow, prefix);
1049     CONN_BOOL("/OrGl/enab", setEffectEnabled, outerGlow, psd_layer_effects_outer_glow, prefix);
1050     CONN_BOOL("/OrGl/AntA", setAntiAliased, outerGlow, psd_layer_effects_outer_glow, prefix);
1051     CONN_CURVE("/OrGl/TrnS", setContourLookupTable, outerGlow, psd_layer_effects_outer_glow, prefix);
1052 
1053     QMap<QString, psd_technique_type> fillTechniqueMap;
1054     fillTechniqueMap.insert("PrBL", psd_technique_precise);
1055     fillTechniqueMap.insert("SfBL", psd_technique_softer);
1056     CONN_ENUM("/OrGl/GlwT", "BETE", setTechnique, fillTechniqueMap, psd_technique_type, outerGlow, psd_layer_effects_outer_glow, prefix);
1057 
1058     CONN_GRADIENT("/OrGl/Grad", setGradient, outerGlow, psd_layer_effects_outer_glow, prefix);
1059 
1060     CONN_UNITF("/OrGl/Inpr", "#Prc", setRange, outerGlow, psd_layer_effects_outer_glow, prefix);
1061     CONN_UNITF("/OrGl/ShdN", "#Prc", setJitter, outerGlow, psd_layer_effects_outer_glow, prefix);
1062 
1063 
1064     psd_layer_effects_inner_glow *innerGlow = style->innerGlow();
1065 
1066     CONN_COMPOSITE_OP("/IrGl/Md  ", setBlendMode, innerGlow, psd_layer_effects_inner_glow, prefix);
1067     CONN_COLOR("/IrGl/Clr ", setColor, innerGlow, psd_layer_effects_inner_glow, prefix);
1068     CONN_UNITF("/IrGl/Opct", "#Prc", setOpacity, innerGlow, psd_layer_effects_inner_glow, prefix);
1069     CONN_UNITF("/IrGl/Ckmt", "#Pxl", setSpread, innerGlow, psd_layer_effects_inner_glow, prefix);
1070     CONN_UNITF("/IrGl/blur", "#Pxl", setSize, innerGlow, psd_layer_effects_inner_glow, prefix);
1071     CONN_UNITF("/IrGl/Nose", "#Prc", setNoise, innerGlow, psd_layer_effects_inner_glow, prefix);
1072     CONN_BOOL("/IrGl/enab", setEffectEnabled, innerGlow, psd_layer_effects_inner_glow, prefix);
1073     CONN_BOOL("/IrGl/AntA", setAntiAliased, innerGlow, psd_layer_effects_inner_glow, prefix);
1074     CONN_CURVE("/IrGl/TrnS", setContourLookupTable, innerGlow, psd_layer_effects_inner_glow, prefix);
1075 
1076     CONN_ENUM("/IrGl/GlwT", "BETE", setTechnique, fillTechniqueMap, psd_technique_type, innerGlow, psd_layer_effects_inner_glow, prefix);
1077 
1078     CONN_GRADIENT("/IrGl/Grad", setGradient, innerGlow, psd_layer_effects_inner_glow, prefix);
1079 
1080     CONN_UNITF("/IrGl/Inpr", "#Prc", setRange, innerGlow, psd_layer_effects_inner_glow, prefix);
1081     CONN_UNITF("/IrGl/ShdN", "#Prc", setJitter, innerGlow, psd_layer_effects_inner_glow, prefix);
1082 
1083     QMap<QString, psd_glow_source> glowSourceMap;
1084     glowSourceMap.insert("SrcC", psd_glow_center);
1085     glowSourceMap.insert("SrcE", psd_glow_edge);
1086     CONN_ENUM("/IrGl/glwS", "IGSr", setSource, glowSourceMap, psd_glow_source, innerGlow, psd_layer_effects_inner_glow, prefix);
1087 
1088 
1089     psd_layer_effects_satin *satin = style->satin();
1090 
1091     CONN_COMPOSITE_OP("/ChFX/Md  ", setBlendMode, satin, psd_layer_effects_satin, prefix);
1092     CONN_COLOR("/ChFX/Clr ", setColor, satin, psd_layer_effects_satin, prefix);
1093 
1094     CONN_UNITF("/ChFX/Opct", "#Prc", setOpacity, satin, psd_layer_effects_satin, prefix);
1095     CONN_UNITF("/ChFX/lagl", "#Ang", setAngle, satin, psd_layer_effects_satin, prefix);
1096     CONN_UNITF("/ChFX/Dstn", "#Pxl", setDistance, satin, psd_layer_effects_satin, prefix);
1097     CONN_UNITF("/ChFX/blur", "#Pxl", setSize, satin, psd_layer_effects_satin, prefix);
1098 
1099     CONN_BOOL("/ChFX/enab", setEffectEnabled, satin, psd_layer_effects_satin, prefix);
1100     CONN_BOOL("/ChFX/AntA", setAntiAliased, satin, psd_layer_effects_satin, prefix);
1101     CONN_BOOL("/ChFX/Invr", setInvert, satin, psd_layer_effects_satin, prefix);
1102     CONN_CURVE("/ChFX/MpgS", setContourLookupTable, satin, psd_layer_effects_satin, prefix);
1103 
1104     psd_layer_effects_color_overlay *colorOverlay = style->colorOverlay();
1105 
1106     CONN_COMPOSITE_OP("/SoFi/Md  ", setBlendMode, colorOverlay, psd_layer_effects_color_overlay, prefix);
1107     CONN_COLOR("/SoFi/Clr ", setColor, colorOverlay, psd_layer_effects_color_overlay, prefix);
1108     CONN_UNITF("/SoFi/Opct", "#Prc", setOpacity, colorOverlay, psd_layer_effects_color_overlay, prefix);
1109     CONN_BOOL("/SoFi/enab", setEffectEnabled, colorOverlay, psd_layer_effects_color_overlay, prefix);
1110 
1111     psd_layer_effects_gradient_overlay *gradientOverlay = style->gradientOverlay();
1112 
1113     CONN_COMPOSITE_OP("/GrFl/Md  ", setBlendMode, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1114     CONN_UNITF("/GrFl/Opct", "#Prc", setOpacity, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1115     CONN_UNITF("/GrFl/Scl ", "#Prc", setScale, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1116     CONN_UNITF("/GrFl/Angl", "#Ang", setAngle, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1117     CONN_BOOL("/GrFl/enab", setEffectEnabled, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1118     CONN_BOOL("/GrFl/Dthr", setDither, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1119     CONN_BOOL("/GrFl/Rvrs", setReverse, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1120     CONN_BOOL("/GrFl/Algn", setAlignWithLayer, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1121     CONN_POINT("/GrFl/Ofst", setGradientOffset, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1122     CONN_GRADIENT("/GrFl/Grad", setGradient, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1123 
1124 
1125     QMap<QString, psd_gradient_style> gradientStyleMap;
1126     gradientStyleMap.insert("Lnr ", psd_gradient_style_linear);
1127     gradientStyleMap.insert("Rdl ", psd_gradient_style_radial);
1128     gradientStyleMap.insert("Angl", psd_gradient_style_angle);
1129     gradientStyleMap.insert("Rflc", psd_gradient_style_reflected);
1130     gradientStyleMap.insert("Dmnd", psd_gradient_style_diamond);
1131     CONN_ENUM("/GrFl/Type", "GrdT", setStyle, gradientStyleMap, psd_gradient_style, gradientOverlay, psd_layer_effects_gradient_overlay, prefix);
1132 
1133     psd_layer_effects_pattern_overlay *patternOverlay = style->patternOverlay();
1134 
1135     CONN_BOOL("/patternFill/enab", setEffectEnabled, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
1136     CONN_COMPOSITE_OP("/patternFill/Md  ", setBlendMode, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
1137     CONN_UNITF("/patternFill/Opct", "#Prc", setOpacity, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
1138     CONN_PATTERN("/patternFill/Ptrn", setPattern, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
1139     CONN_UNITF("/patternFill/Scl ", "#Prc", setScale, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
1140     CONN_BOOL("/patternFill/Algn", setAlignWithLayer, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
1141     CONN_POINT("/patternFill/phase", setPatternPhase, patternOverlay, psd_layer_effects_pattern_overlay, prefix);
1142 
1143     psd_layer_effects_stroke *stroke = style->stroke();
1144 
1145     CONN_COMPOSITE_OP("/FrFX/Md  ", setBlendMode, stroke, psd_layer_effects_stroke, prefix);
1146     CONN_BOOL("/FrFX/enab", setEffectEnabled, stroke, psd_layer_effects_stroke, prefix);
1147     CONN_UNITF("/FrFX/Opct", "#Prc", setOpacity, stroke, psd_layer_effects_stroke, prefix);
1148     CONN_UNITF("/FrFX/Sz  ", "#Pxl", setSize, stroke, psd_layer_effects_stroke, prefix);
1149 
1150     QMap<QString, psd_stroke_position> strokeStyleMap;
1151     strokeStyleMap.insert("OutF", psd_stroke_outside);
1152     strokeStyleMap.insert("InsF", psd_stroke_inside);
1153     strokeStyleMap.insert("CtrF", psd_stroke_center);
1154     CONN_ENUM("/FrFX/Styl", "FStl", setPosition, strokeStyleMap, psd_stroke_position, stroke, psd_layer_effects_stroke, prefix);
1155 
1156     QMap<QString, psd_fill_type> strokeFillType;
1157     strokeFillType.insert("SClr", psd_fill_solid_color);
1158     strokeFillType.insert("GrFl", psd_fill_gradient);
1159     strokeFillType.insert("Ptrn", psd_fill_pattern);
1160     CONN_ENUM("/FrFX/PntT", "FrFl", setFillType, strokeFillType, psd_fill_type, stroke, psd_layer_effects_stroke, prefix);
1161 
1162     // Color type
1163     CONN_COLOR("/FrFX/Clr ", setColor, stroke, psd_layer_effects_stroke, prefix);
1164 
1165     // Gradient Type
1166     CONN_GRADIENT("/FrFX/Grad", setGradient, stroke, psd_layer_effects_stroke, prefix);
1167     CONN_UNITF("/FrFX/Angl", "#Ang", setAngle, stroke, psd_layer_effects_stroke, prefix);
1168     CONN_UNITF("/FrFX/Scl ", "#Prc", setScale, stroke, psd_layer_effects_stroke, prefix);
1169     CONN_ENUM("/FrFX/Type", "GrdT", setStyle, gradientStyleMap, psd_gradient_style, stroke, psd_layer_effects_stroke, prefix);
1170     CONN_BOOL("/FrFX/Rvrs", setReverse, stroke, psd_layer_effects_stroke, prefix);
1171     CONN_BOOL("/FrFX/Algn", setAlignWithLayer, stroke, psd_layer_effects_stroke, prefix);
1172     CONN_POINT("/FrFX/Ofst", setGradientOffset, stroke, psd_layer_effects_stroke, prefix);
1173     CONN_BOOL("/FrFX/Dthr", setDither, stroke, psd_layer_effects_stroke, prefix);
1174 
1175     // Pattern type
1176 
1177     CONN_PATTERN("/FrFX/Ptrn", setPattern, stroke, psd_layer_effects_stroke, prefix);
1178     CONN_BOOL("/FrFX/Lnkd", setAlignWithLayer, stroke, psd_layer_effects_stroke, prefix); // yes, we share the params...
1179     CONN_POINT("/FrFX/phase", setPatternPhase, stroke, psd_layer_effects_stroke, prefix);
1180 
1181 
1182     psd_layer_effects_bevel_emboss *bevelAndEmboss = style->bevelAndEmboss();
1183 
1184     CONN_BOOL("/ebbl/enab", setEffectEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1185 
1186     CONN_COMPOSITE_OP("/ebbl/hglM", setHighlightBlendMode, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1187     CONN_COLOR("/ebbl/hglC", setHighlightColor, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1188     CONN_UNITF("/ebbl/hglO", "#Prc", setHighlightOpacity, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1189 
1190     CONN_COMPOSITE_OP("/ebbl/sdwM", setShadowBlendMode, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1191     CONN_COLOR("/ebbl/sdwC", setShadowColor, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1192     CONN_UNITF("/ebbl/sdwO", "#Prc", setShadowOpacity, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1193 
1194     QMap<QString, psd_technique_type> bevelTechniqueMap;
1195     bevelTechniqueMap.insert("PrBL", psd_technique_precise);
1196     bevelTechniqueMap.insert("SfBL", psd_technique_softer);
1197     bevelTechniqueMap.insert("Slmt", psd_technique_slope_limit);
1198     CONN_ENUM("/ebbl/bvlT", "bvlT", setTechnique, bevelTechniqueMap, psd_technique_type, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1199 
1200     QMap<QString, psd_bevel_style> bevelStyleMap;
1201     bevelStyleMap.insert("OtrB", psd_bevel_outer_bevel);
1202     bevelStyleMap.insert("InrB", psd_bevel_inner_bevel);
1203     bevelStyleMap.insert("Embs", psd_bevel_emboss);
1204     bevelStyleMap.insert("PlEb", psd_bevel_pillow_emboss);
1205     bevelStyleMap.insert("strokeEmboss", psd_bevel_stroke_emboss);
1206     CONN_ENUM("/ebbl/bvlS", "BESl", setStyle, bevelStyleMap, psd_bevel_style, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1207 
1208     CONN_BOOL("/ebbl/uglg", setUseGlobalLight, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1209 
1210     CONN_UNITF("/ebbl/lagl", "#Ang", setAngle, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1211     CONN_UNITF("/ebbl/Lald", "#Ang", setAltitude, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1212 
1213     CONN_UNITF("/ebbl/srgR", "#Prc", setDepth, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1214 
1215     CONN_UNITF("/ebbl/blur", "#Pxl", setSize, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1216 
1217 
1218     QMap<QString, psd_direction> bevelDirectionMap;
1219     bevelDirectionMap.insert("In  ", psd_direction_up);
1220     bevelDirectionMap.insert("Out ", psd_direction_down);
1221     CONN_ENUM("/ebbl/bvlD", "BESs", setDirection, bevelDirectionMap, psd_direction, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1222 
1223     CONN_CURVE("/ebbl/TrnS", setContourLookupTable, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1224 
1225     CONN_BOOL("/ebbl/antialiasGloss", setGlossAntiAliased, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1226 
1227     CONN_UNITF("/ebbl/Sftn", "#Pxl", setSoften, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1228 
1229     // Use shape mode
1230 
1231     CONN_BOOL("/ebbl/useShape", setContourEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1232     CONN_CURVE("/ebbl/MpgS", setGlossContourLookupTable, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1233     CONN_BOOL("/ebbl/AntA", setAntiAliased, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1234     CONN_UNITF("/ebbl/Inpr", "#Prc", setContourRange, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1235 
1236     // Use texture mode
1237 
1238     CONN_BOOL("/ebbl/useTexture", setTextureEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1239     CONN_BOOL("/ebbl/InvT", setTextureInvert, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1240     CONN_BOOL("/ebbl/Algn", setTextureAlignWithLayer, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1241     CONN_UNITF("/ebbl/Scl ", "#Prc", setTextureScale, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1242     CONN_UNITF("/ebbl/textureDepth", "#Prc", setTextureDepth, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1243     CONN_PATTERN("/ebbl/Ptrn", setTexturePattern, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1244     CONN_POINT("/ebbl/phase", setTexturePhase, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix);
1245 }
1246 
1247 void KisAslLayerStyleSerializer::newStyleStarted(bool isPsdStructure)
1248 {
1249     m_stylesVector.append(toQShared(new KisPSDLayerStyle("", m_localResourcesInterface)));
1250     KisPSDLayerStyleSP currentStyleSP = m_stylesVector.last();
1251     KisPSDLayerStyle *currentStyle = currentStyleSP.data();
1252 
1253     psd_layer_effects_context *context = currentStyleSP->context();
1254     context->keep_original = 0;
1255 
1256     QString prefix = isPsdStructure ? "/null" : "/Styl/Lefx";
1257     connectCatcherToStyle(currentStyle, prefix);
1258 }
1259 
1260 bool KisAslLayerStyleSerializer::readFromFile(const QString& filename)
1261 {
1262     QFile file(filename);
1263     if (file.size() == 0) return false;
1264 
1265     if (!file.open(QIODevice::ReadOnly)) {
1266         dbgKrita << "Can't open file " << filename;
1267         return false;
1268     }
1269 
1270     readFromDevice(file);
1271     file.close();
1272 
1273     return m_initialized;
1274 }
1275 
1276 QVector<KisPSDLayerStyleSP> KisAslLayerStyleSerializer::collectAllLayerStyles(KisNodeSP root)
1277 {
1278     KisLayer* layer = qobject_cast<KisLayer*>(root.data());
1279     QVector<KisPSDLayerStyleSP> layerStyles;
1280 
1281     if (layer && layer->layerStyle()) {
1282         KisPSDLayerStyleSP clone = layer->layerStyle()->clone().dynamicCast<KisPSDLayerStyle>();
1283         clone->setName(i18nc("Auto-generated layer style name for embedded styles (style itself)", "<%1> (embedded)", layer->name()));
1284         layerStyles << clone;
1285     }
1286 
1287     KisNodeSP child = root->firstChild();
1288     while (child) {
1289         layerStyles += collectAllLayerStyles(child);
1290         child = child->nextSibling();
1291     }
1292 
1293     return layerStyles;
1294 }
1295 
1296 void KisAslLayerStyleSerializer::assignAllLayerStylesToLayers(KisNodeSP root, const QString &storageLocation)
1297 {
1298     QVector<KisPSDLayerStyleSP> styles;
1299 
1300     KisEmbeddedResourceStorageProxy resourcesProxy(storageLocation);
1301 
1302     if (!storageLocation.isEmpty()) {
1303         Q_FOREACH(KoPatternSP pattern, patterns().values()) {
1304             resourcesProxy.addResource(pattern);
1305         }
1306         Q_FOREACH(KoAbstractGradientSP gradient, gradients()) {
1307             resourcesProxy.addResource(gradient);
1308         }
1309     }
1310 
1311     Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
1312         KisPSDLayerStyleSP newStyle = style->clone().dynamicCast<KisPSDLayerStyle>();
1313         newStyle->setResourcesInterface(resourcesProxy.detachedResourcesInterface());
1314         newStyle->setValid(true);
1315 
1316         if (!storageLocation.isEmpty()) {
1317             resourcesProxy.addResource(newStyle);
1318         }
1319 
1320         styles << newStyle;
1321     }
1322 
1323     KisLayerUtils::recursiveApplyNodes(root, [styles] (KisNodeSP node) {
1324         KisLayer* layer = qobject_cast<KisLayer*>(node.data());
1325 
1326         if (layer && layer->layerStyle()) {
1327             QUuid uuid = layer->layerStyle()->uuid();
1328 
1329             bool found = false;
1330 
1331             Q_FOREACH (KisPSDLayerStyleSP style, styles) {
1332                 if (style->uuid() == uuid) {
1333                     layer->setLayerStyle(style->cloneWithResourcesSnapshot(style->resourcesInterface(), 0));
1334                     found = true;
1335                     break;
1336                 }
1337             }
1338 
1339             if (!found) {
1340                 warnKrita << "WARNING: loading layer style for" << layer->name() << "failed! It requests inexistent style:" << uuid;
1341             }
1342         }
1343     });
1344 }
1345 
1346 void KisAslLayerStyleSerializer::readFromDevice(QIODevice &device)
1347 {
1348     m_catcher.subscribePattern("/patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
1349     m_catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
1350     m_catcher.subscribeNewStyleStarted(std::bind(&KisAslLayerStyleSerializer::newStyleStarted, this, false));
1351 
1352     KisAslReader reader;
1353     const QDomDocument doc = reader.readFile(device);
1354 
1355     if (doc.isNull()) {
1356         m_initialized = false;
1357         return;
1358     }
1359 
1360     //dbgKrita << ppVar(doc.toString());
1361 
1362     //KisAslObjectCatcher c2;
1363     KisAslXmlParser parser;
1364     parser.parseXML(doc, m_catcher);
1365 
1366     QMultiHash<QString, KisPSDLayerStyleSP> allStyles;
1367     QHash<QString, KisPSDLayerStyleSP> cleanedStyles;
1368 
1369     for(const auto &style : m_stylesVector)
1370         allStyles.insert(style->psdUuid(), style);
1371 
1372     // correct all the layer styles
1373     for (const auto &style : allStyles) {
1374         FillStylesCorrector::correct(style.data());
1375 
1376         if (allStyles.count(style->psdUuid()) > 1) {
1377             const auto &existingStyle = cleanedStyles.find(style->psdUuid());
1378 
1379             if (existingStyle != cleanedStyles.end()) {
1380                 if (existingStyle.value()->name() != style->name()) {
1381                     qWarning() << "Duplicated UUID" << style->psdUuid() << "for styles" << style->name() << "and"
1382                                << existingStyle.value()->name();
1383                     style->setMD5Sum("");
1384                     style->setUuid(QUuid::createUuid());
1385                 } else {
1386                     qWarning() << "Duplicated style" << style->name();
1387                     continue;
1388                 }
1389             }
1390         }
1391 
1392         style->setValid(!style->isEmpty());
1393 
1394         style->setFilename(style->uuid().toString());
1395 
1396         cleanedStyles.insert(style->psdUuid(), style);
1397     }
1398 
1399     m_stylesVector = cleanedStyles.values().toVector();
1400 
1401     m_initialized = true;
1402 }
1403 
1404 void KisAslLayerStyleSerializer::registerPSDPattern(const QDomDocument &doc)
1405 {
1406     KisAslCallbackObjectCatcher catcher;
1407     catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
1408     catcher.subscribePattern("/patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1, _2));
1409 
1410     //KisAslObjectCatcher c2;
1411     KisAslXmlParser parser;
1412     parser.parseXML(doc, catcher);
1413 }
1414 
1415 void KisAslLayerStyleSerializer::readFromPSDXML(const QDomDocument &doc)
1416 {
1417     // The caller prepares the document using the following code
1418     //
1419     // KisAslReader reader;
1420     // QDomDocument doc = reader.readLfx2PsdSection(device);
1421 
1422     m_stylesVector.clear();
1423 
1424     //m_catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1));
1425     m_catcher.subscribeNewStyleStarted(std::bind(&KisAslLayerStyleSerializer::newStyleStarted, this, true));
1426 
1427     //KisAslObjectCatcher c2;
1428     KisAslXmlParser parser;
1429     parser.parseXML(doc, m_catcher);
1430 
1431     // correct all the layer styles
1432     Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) {
1433         FillStylesCorrector::correct(style.data());
1434     }
1435 }