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 }