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

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "kis_psd_layer_style.h"
0007 
0008 #include <QBuffer>
0009 #include <QIODevice>
0010 #include <QUuid>
0011 #include <KLocalizedString>
0012 
0013 #include <kis_assert.h>
0014 #include <kis_global.h>
0015 #include <psd_utils.h>
0016 #include "krita_container_utils.h"
0017 
0018 #include <KoCanvasResourcesInterface.h>
0019 #include <KoAbstractGradient.h>
0020 #include <KisRequiredResourcesOperators.h>
0021 #include <KoMD5Generator.h>
0022 
0023 #include "kis_asl_layer_style_serializer.h"
0024 
0025 
0026 struct Q_DECL_HIDDEN KisPSDLayerStyle::Private
0027 {
0028     Private(KisResourcesInterfaceSP _resourcesInterface)
0029         : version(-1)
0030         , effectEnabled(true)
0031         , resourcesInterface(_resourcesInterface)
0032     {
0033         if (!resourcesInterface) {
0034             resourcesInterface.reset(new KisLocalStrokeResources());
0035         }
0036     }
0037 
0038     Private(const Private &rhs)
0039         : name(rhs.name),
0040           uuid(rhs.uuid),
0041           version(rhs.version),
0042           effectEnabled(rhs.effectEnabled),
0043           context(rhs.context),
0044           drop_shadow(rhs.drop_shadow),
0045           inner_shadow(rhs.inner_shadow),
0046           outer_glow(rhs.outer_glow),
0047           inner_glow(rhs.inner_glow),
0048           bevel_emboss(rhs.bevel_emboss),
0049           satin(rhs.satin),
0050           color_overlay(rhs.color_overlay),
0051           gradient_overlay(rhs.gradient_overlay),
0052           pattern_overlay(rhs.pattern_overlay),
0053           stroke(rhs.stroke),
0054           resourcesInterface(rhs.resourcesInterface)
0055     {}
0056 
0057     Private operator=(const Private &rhs)
0058     {
0059         if (this != &rhs) {
0060             name = rhs.name;
0061             uuid = rhs.uuid;
0062             version = rhs.version;
0063             effectEnabled = rhs.effectEnabled;
0064             context = rhs.context;
0065             drop_shadow = rhs.drop_shadow;
0066             inner_shadow = rhs.inner_shadow;
0067             outer_glow = rhs.outer_glow;
0068             inner_glow = rhs.inner_glow;
0069             bevel_emboss = rhs.bevel_emboss;
0070             satin = rhs.satin;
0071             color_overlay = rhs.color_overlay;
0072             gradient_overlay = rhs.gradient_overlay;
0073             pattern_overlay = rhs.pattern_overlay;
0074             stroke = rhs.stroke;
0075             resourcesInterface = rhs.resourcesInterface;
0076         }
0077 
0078         return *this;
0079     }
0080 
0081     QString name;
0082     QUuid uuid;
0083     quint16 version;
0084     bool effectEnabled;
0085     psd_layer_effects_context context;
0086     psd_layer_effects_drop_shadow drop_shadow;
0087     psd_layer_effects_inner_shadow inner_shadow;
0088     psd_layer_effects_outer_glow outer_glow;
0089     psd_layer_effects_inner_glow inner_glow;
0090     psd_layer_effects_bevel_emboss bevel_emboss;
0091     psd_layer_effects_satin satin;
0092     psd_layer_effects_color_overlay color_overlay;
0093     psd_layer_effects_gradient_overlay gradient_overlay;
0094     psd_layer_effects_pattern_overlay pattern_overlay;
0095     psd_layer_effects_stroke stroke;
0096 
0097     KisResourcesInterfaceSP resourcesInterface;
0098 };
0099 
0100 KisPSDLayerStyle::KisPSDLayerStyle(const QString &filename, KisResourcesInterfaceSP resourcesInterface)
0101     : KoResource(filename)
0102     , d(new Private(resourcesInterface))
0103 {
0104     d->name = i18n("Unnamed");
0105     d->version = 7;
0106 }
0107 
0108 KisPSDLayerStyle::~KisPSDLayerStyle()
0109 {
0110     delete d;
0111 }
0112 
0113 KisPSDLayerStyle::KisPSDLayerStyle(const KisPSDLayerStyle &rhs)
0114     : KoResource(rhs)
0115     , d(new Private(*rhs.d))
0116 {
0117     setValid(valid());
0118 }
0119 
0120 bool KisPSDLayerStyle::isEnabled() const
0121 {
0122     return d->effectEnabled;
0123 }
0124 
0125 void KisPSDLayerStyle::setEnabled(bool value)
0126 {
0127     d->effectEnabled = value;
0128 }
0129 
0130 KoResourceSP KisPSDLayerStyle::clone() const
0131 {
0132     return toQShared(new KisPSDLayerStyle(*this)).dynamicCast<KoResource>();
0133 }
0134 
0135 bool KisPSDLayerStyle::isSerializable() const
0136 {
0137     return false;
0138 }
0139 
0140 bool KisPSDLayerStyle::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface)
0141 {
0142     Q_UNUSED(dev);
0143     Q_UNUSED(resourcesInterface);
0144     return false;
0145 }
0146 
0147 bool KisPSDLayerStyle::saveToDevice(QIODevice *) const
0148 {
0149     KIS_SAFE_ASSERT_RECOVER_NOOP(false && "KisPSDLayerStyle is not meant to be serializable!");
0150     return false;
0151 }
0152 
0153 void KisPSDLayerStyle::clear()
0154 {
0155     *d = Private(d->resourcesInterface);
0156 }
0157 
0158 bool KisPSDLayerStyle::isEmpty() const
0159 {
0160     return !(d->drop_shadow.effectEnabled() ||
0161              d->inner_shadow.effectEnabled() ||
0162              d->outer_glow.effectEnabled() ||
0163              d->inner_glow.effectEnabled() ||
0164              d->bevel_emboss.effectEnabled() ||
0165              d->satin.effectEnabled() ||
0166              d->color_overlay.effectEnabled() ||
0167              d->gradient_overlay.effectEnabled() ||
0168              d->pattern_overlay.effectEnabled() ||
0169              d->stroke.effectEnabled());
0170 }
0171 
0172 QString KisPSDLayerStyle::name() const
0173 {
0174     return d->name;
0175 }
0176 
0177 void KisPSDLayerStyle::setName(const QString &value)
0178 {
0179     d->name = value;
0180     dynamic_cast<KoResource*>(this)->setName(value);
0181 }
0182 
0183 QUuid KisPSDLayerStyle::uuid() const
0184 {
0185     if (d->uuid.isNull()) {
0186         d->uuid = QUuid::createUuid();
0187     }
0188 
0189     return d->uuid;
0190 }
0191 
0192 void KisPSDLayerStyle::setUuid(const QUuid &value)
0193 {
0194     d->uuid = value;
0195     this->setMD5Sum(KoMD5Generator::generateHash(value.toByteArray()));
0196 }
0197 
0198 QString KisPSDLayerStyle::psdUuid() const
0199 {
0200     return uuid().toString().mid(1, 36);
0201 }
0202 
0203 void KisPSDLayerStyle::setPsdUuid(const QString &value)
0204 {
0205     setUuid(QUuid(QString("{%1}").arg(value)));
0206 }
0207 
0208 const psd_layer_effects_context* KisPSDLayerStyle::context() const
0209 {
0210     return &d->context;
0211 }
0212 
0213 const psd_layer_effects_drop_shadow* KisPSDLayerStyle::dropShadow() const
0214 {
0215     return &d->drop_shadow;
0216 }
0217 
0218 const psd_layer_effects_inner_shadow* KisPSDLayerStyle::innerShadow() const
0219 {
0220     return &d->inner_shadow;
0221 }
0222 
0223 const psd_layer_effects_outer_glow* KisPSDLayerStyle::outerGlow() const
0224 {
0225     return &d->outer_glow;
0226 }
0227 
0228 const psd_layer_effects_inner_glow* KisPSDLayerStyle::innerGlow() const
0229 {
0230     return &d->inner_glow;
0231 }
0232 
0233 const psd_layer_effects_satin* KisPSDLayerStyle::satin() const
0234 {
0235     return &d->satin;
0236 }
0237 
0238 const psd_layer_effects_color_overlay* KisPSDLayerStyle::colorOverlay() const
0239 {
0240     return &d->color_overlay;
0241 }
0242 
0243 const psd_layer_effects_gradient_overlay* KisPSDLayerStyle::gradientOverlay() const
0244 {
0245     return &d->gradient_overlay;
0246 }
0247 
0248 const psd_layer_effects_pattern_overlay* KisPSDLayerStyle::patternOverlay() const
0249 {
0250     return &d->pattern_overlay;
0251 }
0252 
0253 const psd_layer_effects_stroke* KisPSDLayerStyle::stroke() const
0254 {
0255     return &d->stroke;
0256 }
0257 
0258 const psd_layer_effects_bevel_emboss* KisPSDLayerStyle::bevelAndEmboss() const
0259 {
0260     return &d->bevel_emboss;
0261 }
0262 
0263 psd_layer_effects_context* KisPSDLayerStyle::context()
0264 {
0265     return &d->context;
0266 }
0267 
0268 psd_layer_effects_drop_shadow* KisPSDLayerStyle::dropShadow()
0269 {
0270     return &d->drop_shadow;
0271 }
0272 
0273 psd_layer_effects_inner_shadow* KisPSDLayerStyle::innerShadow()
0274 {
0275     return &d->inner_shadow;
0276 }
0277 
0278 psd_layer_effects_outer_glow* KisPSDLayerStyle::outerGlow()
0279 {
0280     return &d->outer_glow;
0281 }
0282 
0283 psd_layer_effects_inner_glow* KisPSDLayerStyle::innerGlow()
0284 {
0285     return &d->inner_glow;
0286 }
0287 
0288 psd_layer_effects_satin* KisPSDLayerStyle::satin()
0289 {
0290     return &d->satin;
0291 }
0292 
0293 psd_layer_effects_color_overlay* KisPSDLayerStyle::colorOverlay()
0294 {
0295     return &d->color_overlay;
0296 }
0297 
0298 psd_layer_effects_gradient_overlay* KisPSDLayerStyle::gradientOverlay()
0299 {
0300     return &d->gradient_overlay;
0301 }
0302 
0303 psd_layer_effects_pattern_overlay* KisPSDLayerStyle::patternOverlay()
0304 {
0305     return &d->pattern_overlay;
0306 }
0307 
0308 psd_layer_effects_stroke* KisPSDLayerStyle::stroke()
0309 {
0310     return &d->stroke;
0311 }
0312 
0313 psd_layer_effects_bevel_emboss* KisPSDLayerStyle::bevelAndEmboss()
0314 {
0315     return &d->bevel_emboss;
0316 }
0317 
0318 KisResourcesInterfaceSP KisPSDLayerStyle::resourcesInterface() const
0319 {
0320     return d->resourcesInterface;
0321 }
0322 
0323 void KisPSDLayerStyle::setResourcesInterface(KisResourcesInterfaceSP resourcesInterface)
0324 {
0325     d->resourcesInterface = resourcesInterface;
0326 }
0327 
0328 bool KisPSDLayerStyle::hasLocalResourcesSnapshot() const
0329 {
0330     return KisRequiredResourcesOperators::hasLocalResourcesSnapshot(this);
0331 }
0332 
0333 KisPSDLayerStyleSP KisPSDLayerStyle::cloneWithResourcesSnapshot(KisResourcesInterfaceSP globalResourcesInterface, KoCanvasResourcesInterfaceSP canvasResourcesInterface) const
0334 {
0335     KisPSDLayerStyleSP style = KisRequiredResourcesOperators::cloneWithResourcesSnapshot<KisPSDLayerStyleSP>(this, globalResourcesInterface);
0336 
0337     /**
0338      * Passing null into cloneWithResourcesSnapshot() means that we expect all the
0339      * canvas resources to be backed into the style. That is exactly what we expect
0340      * when loading the styles saved in the layers.
0341      */
0342 
0343     if (!requiredCanvasResources().isEmpty() && !canvasResourcesInterface) {
0344         qWarning() << "KisPSDLayerStyle::cloneWithResourcesSnapshot: layer style"
0345                    << name() << "is expected to have all the canvas resources"
0346                    << "backed, but still depends on something";
0347         qWarning() << ppVar(requiredCanvasResources());
0348     }
0349 
0350     if (canvasResourcesInterface) {
0351 
0352         QSharedPointer<KisLocalStrokeResources> localResourcesSnapshot =
0353              style->resourcesInterface().dynamicCast<KisLocalStrokeResources>();
0354         KIS_ASSERT_RECOVER_RETURN_VALUE(localResourcesSnapshot, style);
0355 
0356         auto bakeGradient = [canvasResourcesInterface, localResourcesSnapshot] (KoAbstractGradientSP gradient) {
0357             if (gradient && !gradient->requiredCanvasResources().isEmpty()) {
0358 
0359                 /**
0360                  * Since we haven't cloned the required resources when putting them
0361                  * into the local storage (which is rather questionable), we need to
0362                  * clone the gradients explicitly before modification.
0363                  */
0364 
0365                 KoAbstractGradientSP clonedGradient =
0366                     gradient->cloneAndBakeVariableColors(canvasResourcesInterface);
0367 
0368                 localResourcesSnapshot->removeResource(gradient);
0369                 localResourcesSnapshot->addResource(clonedGradient);
0370             }
0371         };
0372 
0373         if (style->gradientOverlay()->effectEnabled()) {
0374             bakeGradient(style->gradientOverlay()->gradient(style->resourcesInterface()));
0375         }
0376 
0377         if (style->innerGlow()->effectEnabled() && style->innerGlow()->fillType() == psd_fill_gradient) {
0378             bakeGradient(style->innerGlow()->gradient(style->resourcesInterface()));
0379         }
0380 
0381         if (style->outerGlow()->effectEnabled() && style->outerGlow()->fillType() == psd_fill_gradient) {
0382             bakeGradient(style->outerGlow()->gradient(style->resourcesInterface()));
0383         }
0384 
0385         if (style->stroke()->effectEnabled() && style->stroke()->fillType() == psd_fill_gradient) {
0386             bakeGradient(style->stroke()->gradient(style->resourcesInterface()));
0387         }
0388     }
0389 
0390     return style;
0391 }
0392 
0393 QList<KoResourceLoadResult> KisPSDLayerStyle::embeddedResources(KisResourcesInterfaceSP globalResourcesInterface) const
0394 {
0395     Q_UNUSED(globalResourcesInterface);
0396     return implicitCastList<KoResourceLoadResult>(QList<KoResourceSP>::fromVector(KisAslLayerStyleSerializer::fetchEmbeddedResources(this)));
0397 }
0398 
0399 QList<int> KisPSDLayerStyle::requiredCanvasResources() const
0400 {
0401     QList<int> result;
0402 
0403     auto addCanvasResources = [&result] (KoAbstractGradientSP gradient) {
0404         if (gradient) {
0405             result << gradient->requiredCanvasResources();
0406         }
0407     };
0408 
0409     if (gradientOverlay()->effectEnabled()) {
0410         addCanvasResources(gradientOverlay()->gradient(resourcesInterface()));
0411     }
0412 
0413     if (innerGlow()->effectEnabled() && innerGlow()->fillType() == psd_fill_gradient) {
0414         addCanvasResources(innerGlow()->gradient(resourcesInterface()));
0415     }
0416 
0417     if (outerGlow()->effectEnabled() && outerGlow()->fillType() == psd_fill_gradient) {
0418         addCanvasResources(outerGlow()->gradient(resourcesInterface()));
0419     }
0420 
0421     if (stroke()->effectEnabled() && stroke()->fillType() == psd_fill_gradient) {
0422         addCanvasResources(stroke()->gradient(resourcesInterface()));
0423     }
0424 
0425     KritaUtils::makeContainerUnique(result);
0426 
0427     return result;
0428 }