Krita Source Code Documentation
Loading...
Searching...
No Matches
psd_loader.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6#include "psd_loader.h"
7
8#include <QApplication>
9
10#include <QStack>
11#include <QMessageBox>
12
13#include <KoColorSpace.h>
16#include <KoColorProfile.h>
17#include <KoCompositeOp.h>
18#include <KoUnit.h>
19#include <KoSvgTextShape.h>
21#include <kis_shape_layer.h>
22#include <KoPathShape.h>
23#include <KoShapeStroke.h>
24#include <kis_shape_selection.h>
25#include <SvgShape.h>
26#include <KoShapeFactoryBase.h>
27#include <KoShapeRegistry.h>
29#include <KoProperties.h>
30
31#include <kis_annotation.h>
32#include <kis_types.h>
33#include <kis_paint_layer.h>
34#include <KisDocument.h>
35#include <kis_image.h>
36#include <kis_group_layer.h>
37#include <kis_paint_device.h>
38#include <kis_transaction.h>
40#include <kis_generator_layer.h>
42#include <kis_guides_config.h>
43
48
49#include "psd.h"
50#include "psd_header.h"
51#include "psd_colormode_block.h"
52#include "psd_utils.h"
54#include "psd_layer_section.h"
55#include "psd_resource_block.h"
56#include "psd_image_data.h"
58#include "KisImageBarrierLock.h"
60
61
63 : m_image(0)
64 , m_doc(doc)
65 , m_stop(false)
66 , m_feedbackInterface(feedbackInterface)
67{
68}
69
73
75{
76 // open the file
77
78 dbgFile << "pos:" << io.pos();
79
80 PSDHeader header;
81 if (!header.read(io)) {
82 dbgFile << "failed reading header: " << header.error;
84 }
85
86 dbgFile << header;
87 dbgFile << "Read header. pos:" << io.pos();
88
89 PSDColorModeBlock colorModeBlock(header.colormode);
90 if (!colorModeBlock.read(io)) {
91 dbgFile << "failed reading colormode block: " << colorModeBlock.error;
93 }
94
95 dbgFile << "Read color mode block. pos:" << io.pos();
96
97 PSDImageResourceSection resourceSection;
98 if (!resourceSection.read(io)) {
99 dbgFile << "failed image reading resource section: " << resourceSection.error;
101 }
102 dbgFile << "Read image resource section. pos:" << io.pos();
103
104 PSDLayerMaskSection layerSection(header);
105 if (!layerSection.read(io)) {
106 dbgFile << "failed reading layer/mask section: " << layerSection.error;
108 }
109 dbgFile << "Read layer/mask section. " << layerSection.nLayers << "layers. pos:" << io.pos();
110
111 // Done reading, except possibly for the image data block, which is only relevant if there
112 // are no layers.
113
114 // Get the right colorspace
115 QPair<QString, QString> colorSpaceId = psd_colormode_to_colormodelid(header.colormode,
116 header.channelDepth);
117 if (colorSpaceId.first.isNull()) {
118 dbgFile << "Unsupported colorspace" << header.colormode << header.channelDepth;
120 }
121
122 // Get the icc profile from the image resource section
123 const KoColorProfile* profile = 0;
124 if (resourceSection.resources.contains(PSDImageResourceSection::ICC_PROFILE)) {
125 ICC_PROFILE_1039 *iccProfileData = dynamic_cast<ICC_PROFILE_1039*>(resourceSection.resources[PSDImageResourceSection::ICC_PROFILE]->resource);
126 if (iccProfileData ) {
127 profile = KoColorSpaceRegistry::instance()->createColorProfile(colorSpaceId.first,
128 colorSpaceId.second,
129 iccProfileData->icc);
130 dbgFile << "Loaded ICC profile" << profile->name();
131 delete resourceSection.resources.take(PSDImageResourceSection::ICC_PROFILE);
132 }
133 }
134
135 // Create the colorspace
136 const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(colorSpaceId.first, colorSpaceId.second, profile);
137 if (!cs) {
139 }
140
141 // Creating the KisImage
142 QFile *file = dynamic_cast<QFile *>(&io);
143 QString name = file ? file->fileName() : "Imported";
144 m_image = new KisImage(m_doc->createUndoStore(), header.width, header.height, cs, name);
145 Q_CHECK_PTR(m_image);
146
147 KisImageBarrierLock lock(m_image);
148
149 // set the correct resolution
150 if (resourceSection.resources.contains(PSDImageResourceSection::RESN_INFO)) {
151 RESN_INFO_1005 *resInfo = dynamic_cast<RESN_INFO_1005*>(resourceSection.resources[PSDImageResourceSection::RESN_INFO]->resource);
152 if (resInfo) {
153 // check resolution size is not zero
154 if (resInfo->hRes * resInfo->vRes > 0)
156 // let's skip the unit for now; we can only set that on the KisDocument, and krita doesn't use it.
157 delete resourceSection.resources.take(PSDImageResourceSection::RESN_INFO);
158 }
159 }
160
161 if (resourceSection.resources.contains(PSDImageResourceSection::GRID_GUIDE)) {
162 GRID_GUIDE_1032 *gridGuidesInfo = dynamic_cast<GRID_GUIDE_1032*>(resourceSection.resources[PSDImageResourceSection::GRID_GUIDE]->resource);
163 if (gridGuidesInfo) {
165 Q_FOREACH(quint32 guide, gridGuidesInfo->verticalGuides) {
166 config.addGuideLine(Qt::Vertical, guide / m_image->xRes());
167 }
168 Q_FOREACH(quint32 guide, gridGuidesInfo->horizontalGuides) {
169 config.addGuideLine(Qt::Horizontal, guide / m_image->yRes());
170 }
171 config.setShowGuides(true);
172 m_doc->setGuidesConfig(config);
173 }
174 }
175
176 // Preserve all the annotations
177 Q_FOREACH (PSDResourceBlock *resourceBlock, resourceSection.resources.values()) {
178 m_image->addAnnotation(resourceBlock);
179 }
180
181 // Preserve the duotone colormode block for saving back to psd
182 if (header.colormode == DuoTone) {
183 KisAnnotationSP annotation = new KisAnnotation("DuotoneColormodeBlock",
184 i18n("Duotone Colormode Block"),
185 colorModeBlock.data);
186 m_image->addAnnotation(annotation);
187 }
188
189 // Load embedded patterns early for fill layers.
190
191 const QVector<QDomDocument> &embeddedPatterns =
193
194 const QString storageLocation = m_doc->embeddedResourcesStorageId();
195
196 KisEmbeddedResourceStorageProxy resourceProxy(storageLocation);
197
199 if (!embeddedPatterns.isEmpty()) {
200 Q_FOREACH (const QDomDocument &doc, embeddedPatterns) {
201 serializer.registerPSDPattern(doc);
202 }
203 Q_FOREACH (KoPatternSP pattern, serializer.patterns()) {
204 if (pattern && pattern->valid()) {
205 resourceProxy.addResource(pattern);
206 dbgFile << "Loaded embedded pattern: " << pattern->name();
207 }
208 else {
209 qWarning() << "Invalid or empty pattern" << pattern;
210 }
211 }
212 }
213
214 // Read the projection into our single layer. Since we only read the projection when
215 // we have just one layer, we don't need to later on apply the alpha channel of the
216 // first layer to the projection if the number of layers is negative/
217 // See https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_16000.
218 if (layerSection.nLayers == 0) {
219 dbgFile << "Position" << io.pos() << "Going to read the projection into the first layer, which Photoshop calls 'Background'";
220
221 KisPaintLayerSP layer = new KisPaintLayer(m_image, i18nc("Name for the bottom-most layer in the layerstack", "Background"), OPACITY_OPAQUE_U8);
222
223 PSDImageData imageData(&header);
224 imageData.read(io, layer->paintDevice());
225
226 m_image->addNode(layer, m_image->rootLayer());
227
228 // Only one layer, the background layer, so we're done.
230 }
231
232 // More than one layer, so now construct the Krita image from the info we read.
233
234 QStack<KisGroupLayerSP> groupStack;
235 groupStack.push(m_image->rootLayer());
236
243 KisNodeSP lastAddedLayer;
244
245 typedef QPair<QDomDocument, KisLayerSP> LayerStyleMapping;
246 QVector<LayerStyleMapping> allStylesXml;
247 using namespace std::placeholders;
248
249 bool convertTextToShape = true;
250 for (int i = 0; i < layerSection.nLayers; i++) {
251 if (!layerSection.layers.at(i)->infoBlocks.textData.isNull()) {
253 m_feedbackInterface->askUser([&] (QWidget *parent) {
254 QMessageBox::StandardButton btn = QMessageBox::question(parent,
255 i18nc("@title:window PSD import question about text.", "Found Text Layers"),
256 i18nc("PSD import question about text",
257 "Found text objects, do you wish to load them as editable text shapes? "
258 "If not, they will be loaded as pixel data, which will be visually"
259 " more accurate to the original file."));
260 return (btn == QMessageBox::Yes);
261 });
262 convertTextToShape = (result == KisImportUserFeedbackInterface::Success
264 break;
265 }
266 }
267
268 // read the channels for the various layers
269 for(int i = 0; i < layerSection.nLayers; ++i) {
270
271 PSDLayerRecord* layerRecord = layerSection.layers.at(i);
272 dbgFile << "Going to read channels for layer" << i << layerRecord->layerName;
273 KisLayerSP newLayer;
274 if (layerRecord->infoBlocks.keys.contains("lsct") &&
275 layerRecord->infoBlocks.sectionDividerType != psd_other) {
276
277 if (layerRecord->infoBlocks.sectionDividerType == psd_bounding_divider && !groupStack.isEmpty()) {
278 KisGroupLayerSP groupLayer = new KisGroupLayer(m_image, "temp", OPACITY_OPAQUE_U8);
279 m_image->addNode(groupLayer, groupStack.top());
280 groupStack.push(groupLayer);
281 newLayer = groupLayer;
282 }
283 else if ((layerRecord->infoBlocks.sectionDividerType == psd_open_folder ||
285 (groupStack.size() > 1 || (lastAddedLayer && !groupStack.isEmpty()))) {
286 KisGroupLayerSP groupLayer;
287
288 if (groupStack.size() <= 1) {
289 groupLayer = new KisGroupLayer(m_image, "temp", OPACITY_OPAQUE_U8);
290 m_image->addNode(groupLayer, groupStack.top());
291 m_image->moveNode(lastAddedLayer, groupLayer, KisNodeSP());
292 } else {
293 groupLayer = groupStack.pop();
294 }
295
296 const QDomDocument &styleXml = layerRecord->infoBlocks.layerStyleXml;
297
298 if (!styleXml.isNull()) {
299 allStylesXml << LayerStyleMapping(styleXml, groupLayer);
300 }
301
302 groupLayer->setName(layerRecord->layerName);
303 groupLayer->setVisible(layerRecord->visible);
304 groupLayer->setUserLocked(layerRecord->userLocked);
305
306 if (layerRecord->infoBlocks.sectionDividerType == psd_closed_folder) {
307 groupLayer->setCollapsed(true);
308 }
309
310 QString compositeOp = psd_blendmode_to_composite_op(layerRecord->infoBlocks.sectionDividerBlendMode);
311
312 // Krita doesn't support pass-through blend
313 // mode. Instead it is just a property of a group
314 // layer, so flip it
315 if (compositeOp == COMPOSITE_PASS_THROUGH) {
316 compositeOp = COMPOSITE_OVER;
317 groupLayer->setPassThroughMode(true);
318 }
319
320 groupLayer->setCompositeOpId(compositeOp);
321
322 newLayer = groupLayer;
323 } else {
334 warnKrita << "WARNING: Provided PSD has unbalanced group "
335 << "layer markers. Some masks and/or layers can "
336 << "be lost while loading this file. Please "
337 << "report a bug to Krita developers and attach "
338 << "this file to the bugreport\n"
339 << " " << ppVar(layerRecord->layerName) << "\n"
340 << " " << ppVar(layerRecord->infoBlocks.sectionDividerType) << "\n"
341 << " " << ppVar(groupStack.size());
342 continue;
343 }
344 } else {
345 KisLayerSP layer;
346 if (!layerRecord->infoBlocks.fillConfig.isNull()) {
348 QDomDocument fillConfig;
350
351 KoShape *vectorMask = nullptr;
352 if (layerRecord->infoBlocks.keys.contains("vmsk") || layerRecord->infoBlocks.keys.contains("vsms")) {
354 if (!layerRecord->infoBlocks.vectorOriginationData.isNull()) {
356 psd_vector_origination_data::setupCatcher("/null", catcher, &data);
357 KisAslXmlParser parser;
358 parser.parseXML(layerRecord->infoBlocks.vectorOriginationData, catcher);
359 }
360 QString shapeName = data.shapeName();
361 const KoShapeFactoryBase *f = KoShapeRegistry::instance()->value(shapeName);
362 if (!(data.canMakeParametricShape() && f)) {
363 double width = m_image->width() / m_image->xRes();
364 double height = m_image->height() / m_image->yRes();
365 vectorMask = layerRecord->constructPathShape(layerRecord->infoBlocks.vectorMask.path, width, height);
366 vectorMask->setUserData(new KisShapeSelectionMarker);
367 } else {
368 QSizeF size;
369 double angle;
370 data.OriginalSizeAndAngle(size, angle);
371 double resMultiplier = data.originResolution/72.0;
372 QTransform scaleToPt = QTransform::fromScale(resMultiplier, resMultiplier).inverted();
373 size = QSizeF(size.width()/resMultiplier, size.height()/resMultiplier);
374
376 KoProperties props;
377 if (shapeName == "RectangleShape") {
378 props.setProperty("x", 0);
379 props.setProperty("y", 0);
380 props.setProperty("width", size.width());
381 props.setProperty("height", size.height());
382 } else if (shapeName == "StarShape") {
383 props.setProperty("corners", data.originPolySides);
384 props.setProperty("convex", !data.isStar);
385
386 double angle = 360.0/(data.originPolySides*2);
387 double a = cos(kisDegreesToRadians(angle)) * 100.0;
388 double totalHeight = a + 100.0;
389 double l = size.height() / totalHeight * 100.0;
390
391 if (data.isStar) {
392 // 100% is a normal polygon.
393 a = cos(kisDegreesToRadians(angle)) * ((data.originPolyStarRatio*0.01) * l);
394 props.setProperty("baseRadius", a);
395 }
396 props.setProperty("tipRadius", l);
397 props.setProperty("baseRoundness", 0.0);
398 props.setProperty("tipRoundness", 0.0);
399 }
400 KoShape *shape = f->createShape(&props, &manager);
401 if (!shape)
402 continue;
403 shape->setSize(size);
404 QTransform t;
405 t.rotate(360.0-angle);
406
407 shape->setTransformation(t * scaleToPt.inverted() * data.transform * scaleToPt);
408 shape->setAbsolutePosition(scaleToPt.map(data.originShapeBBox.center()));
409
410 vectorMask = shape;
411 }
412 }
413 if (layerRecord->infoBlocks.fillType == psd_fill_gradient) {
415
417 fill.imageWidth = m_image->width();
418 fill.imageHeight = m_image->height();
419 psd_layer_gradient_fill::setupCatcher("/null", catcher, &fill);
420 KisAslXmlParser parser;
421 parser.parseXML(layerRecord->infoBlocks.fillConfig, catcher);
422 fillConfig = fill.getFillLayerConfig();
423 if (vectorMask) {
424 vectorMask->setBackground(fill.getBackground());
425 }
426
427 } else if (layerRecord->infoBlocks.fillType == psd_fill_pattern) {
429
431 psd_layer_pattern_fill::setupCatcher("/null", catcher, &fill);
432
433 KisAslXmlParser parser;
434 parser.parseXML(layerRecord->infoBlocks.fillConfig, catcher);
435 fillConfig = fill.getFillLayerConfig();
436 if (vectorMask) {
437 vectorMask->setBackground(fill.getBackground(resourceProxy));
438 }
439
440 } else {
442
444 fill.cs = m_image->colorSpace();
445 psd_layer_solid_color::setupCatcher("/null", catcher, &fill);
446 KisAslXmlParser parser;
447 parser.parseXML(layerRecord->infoBlocks.fillConfig, catcher);
448
449 fillConfig = fill.getFillLayerConfig();
450 if (vectorMask) {
451 vectorMask->setBackground(fill.getBackground());
452 }
453 }
454 if (vectorMask) {
455 KisShapeLayerSP shapeLayer = new KisShapeLayer(m_doc->shapeController(), m_image, layerRecord->layerName, layerRecord->opacity);
456
457
458 if (!layerRecord->infoBlocks.vectorStroke.isNull()) {
459 KoShapeStrokeSP stroke(new KoShapeStroke());
463 fill.cs = m_image->colorSpace();
464 KisAslCallbackObjectCatcher strokeCatcher;
465 psd_vector_stroke_data::setupCatcher("", strokeCatcher, &data);
466 psd_layer_solid_color::setupCatcher("/strokeStyle/strokeStyleContent", strokeCatcher, &fill);
467 psd_layer_gradient_fill::setupCatcher("/strokeStyle/strokeStyleContent", strokeCatcher, &grad);
468 KisAslXmlParser parser;
469 parser.parseXML(layerRecord->infoBlocks.vectorStroke, strokeCatcher);
470
471 if (!data.fillEnabled) {
473 }
474 if (data.strokeEnabled) {
475 QColor c = fill.getBrush().color();
476 c.setAlphaF(data.opacity);
477 stroke->setColor(c);
478 if (!grad.gradient.isNull()) {
479 stroke->setLineBrush(grad.getBrush());
480 }
481 } else {
482 stroke->setColor(Qt::transparent);
483 }
484 data.setupShapeStroke(stroke);
485
486 vectorMask->setStroke(stroke);
487 }
488
489 shapeLayer->addShape(vectorMask);
490 layer = shapeLayer;
491 } else {
492 cfg->fromXML(fillConfig.firstChildElement());
493 cfg->createLocalResourcesSnapshot();
494 KisGeneratorLayerSP genlayer = new KisGeneratorLayer(m_image, layerRecord->layerName, cfg, m_image->globalSelection());
495 genlayer->setFilter(cfg);
496 layer = genlayer;
497 }
498
499
500 } else if (!layerRecord->infoBlocks.textData.isNull() && convertTextToShape) {
501 KisShapeLayerSP textLayer = new KisShapeLayer(m_doc->shapeController(), m_image, layerRecord->layerName, layerRecord->opacity);
504 psd_layer_type_shape::setupCatcher(QString(), catcher, &text);
505 KisAslXmlParser parser;
506 parser.parseXML(layerRecord->infoBlocks.textData, catcher);
507 KoSvgTextShape *shape = new KoSvgTextShape();
508 PsdTextDataConverter converter;
509 KoSvgTextShapeMarkupConverter svgConverter(shape);
510
511 QString svg;
512 QString styles;
513 // This is to align inlinesize appropriately.
514 bool offsetByAscent = false;
515 QPointF offset1;
516 // PSD text layers have all their coordinates in pixels, and because fonts can be very precise-unit sensitive,
517 // we want to ensure all values are scaled appropriately.
518
519 QTransform scaleToPt = QTransform::fromScale(m_image->xRes(), m_image->yRes()).inverted();
520 bool res = converter.convertPSDTextEngineDataToSVG(text.engineData,
521 layerSection.globalInfoSection.txt2Data,
523 text.textIndex,
524 &svg, &styles,
525 offset1, offsetByAscent,
526 text.isHorizontal, scaleToPt);
527 if (!res || !converter.errors().isEmpty()) {
528 qWarning() << converter.errors();
529 }
530 dbgFile << converter.warnings();
531 svgConverter.convertFromSvg(svg, styles, m_image->bounds(), m_image->xRes()*72.0);
532 if (offsetByAscent) {
533 QPointF offset2 = QPointF() - shape->outlineRect().topLeft();
534 if (text.isHorizontal) {
535 offset2.setX(offset1.x());
536 } else {
537 offset2.setY(offset1.y());
538 }
539 shape->setTransformation(QTransform::fromTranslate(offset2.x(), offset2.y()) * scaleToPt.inverted()
540 * layerRecord->infoBlocks.textTransform * scaleToPt);
541 } else {
542 shape->setTransformation(scaleToPt.inverted() * layerRecord->infoBlocks.textTransform * scaleToPt);
543 }
544 textLayer->addShape(shape);
545 layer = textLayer;
546 } else {
547 layer = new KisPaintLayer(m_image, layerRecord->layerName, layerRecord->opacity);
548 if (!layerRecord->readPixelData(io, layer->paintDevice())) {
549 dbgFile << "failed reading channels for layer: " << layerRecord->layerName << layerRecord->error;
551 }
552 }
554
555 layer->setColorLabelIndex(layerRecord->labelColor);
556
557 const QDomDocument &styleXml = layerRecord->infoBlocks.layerStyleXml;
558
559 if (!styleXml.isNull()) {
560 allStylesXml << LayerStyleMapping(styleXml, layer);
561 }
562
563 if (!groupStack.isEmpty()) {
564 m_image->addNode(layer, groupStack.top());
565 }
566 else {
567 m_image->addNode(layer, m_image->root());
568 }
569 layer->setVisible(layerRecord->visible);
570 layer->setUserLocked(layerRecord->userLocked);
571 newLayer = layer;
572
573 }
574
575 Q_FOREACH (ChannelInfo *channelInfo, layerRecord->channelInfoRecords) {
576 if (channelInfo->channelId < -1) {
577 const KisGeneratorLayer *fillLayer = qobject_cast<KisGeneratorLayer *>(newLayer.data());
578 const KisShapeLayer *shapeLayer = qobject_cast<KisShapeLayer *>(newLayer.data());
579 KoPathShape *vectorMask = new KoPathShape();
580 if (layerRecord->infoBlocks.keys.contains("vmsk") || layerRecord->infoBlocks.keys.contains("vsms")) {
581 double width = m_image->width() / m_image->xRes();
582 double height = m_image->height() / m_image->yRes();
583 vectorMask = layerRecord->constructPathShape(layerRecord->infoBlocks.vectorMask.path, width, height);
584 vectorMask->setUserData(new KisShapeSelectionMarker);
585 }
586 bool hasVectorMask = vectorMask->pointCount() > 0 && layerRecord->infoBlocks.vectorMask.path.subPaths.size() > 0;
587 if (fillLayer) {
588 if (!layerRecord->readMask(io, fillLayer->paintDevice(), channelInfo)) {
589 dbgFile << "failed reading masks for generator layer: " << layerRecord->layerName << layerRecord->error;
590 }
591 if (hasVectorMask) {
592 KisShapeSelection* shapeSelection = new KisShapeSelection(m_doc->shapeController(), fillLayer->internalSelection());
593 fillLayer->internalSelection()->convertToVectorSelectionNoUndo(shapeSelection);
594 shapeSelection->addShape(vectorMask);
595 fillLayer->internalSelection()->updateProjection();
596 }
597 } else {
598 if (!(shapeLayer && hasVectorMask)) {
599 KisTransparencyMaskSP mask = new KisTransparencyMask(m_image, i18n("Transparency Mask"));
600 mask->initSelection(newLayer);
601 if (!layerRecord->readMask(io, mask->paintDevice(), channelInfo)) {
602 dbgFile << "failed reading masks for layer: " << layerRecord->layerName << layerRecord->error;
603 }
604 if (hasVectorMask) {
605 KisShapeSelection* shapeSelection = new KisShapeSelection(m_doc->shapeController(), mask->selection());
606 mask->selection()->convertToVectorSelectionNoUndo(shapeSelection);
607 shapeSelection->addShape(vectorMask);
608 mask->selection()->updateProjection();
609 }
610 m_image->addNode(mask, newLayer);
611 }
612 }
613 }
614 }
615
616 lastAddedLayer = newLayer;
617 }
618
619 if (!allStylesXml.isEmpty()) {
620 Q_FOREACH (const LayerStyleMapping &mapping, allStylesXml) {
621
622 serializer.readFromPSDXML(mapping.first);
623
624 if (serializer.styles().size() == 1) {
625 KisPSDLayerStyleSP layerStyle = serializer.styles().first();
626 KisLayerSP layer = mapping.second;
627
628 Q_FOREACH (KoAbstractGradientSP gradient, serializer.gradients()) {
629 if (gradient && gradient->valid()) {
630 resourceProxy.addResource(gradient);
631 }
632 else {
633 qWarning() << "Invalid or empty gradient" << gradient;
634 }
635 }
636
637 Q_FOREACH (const KoPatternSP &pattern, serializer.patterns()) {
638 if (pattern && pattern->valid()) {
639 resourceProxy.addResource(pattern);
640 } else {
641 qWarning() << "Invalid or empty pattern" << pattern;
642 }
643 }
644
645 layerStyle->setName(layer->name());
646 layerStyle->setResourcesInterface(resourceProxy.detachedResourcesInterface());
647 if (!layerStyle->uuid().isNull()) {
648 layerStyle->setUuid(QUuid::createUuid());
649 }
650 layerStyle->setValid(true);
651
652 resourceProxy.addResource(layerStyle);
653
654 layer->setLayerStyle(layerStyle->cloneWithResourcesSnapshot(layerStyle->resourcesInterface(), 0));
655 } else {
656 warnKrita << "WARNING: Couldn't read layer style!" << ppVar(serializer.styles());
657 }
658
659 }
660 }
661
663}
664
666{
667 return decode(io);
668}
669
670
672{
673 return m_image;
674}
675
677{
678 m_stop = true;
679}
680
681
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
const QString COMPOSITE_PASS_THROUGH
constexpr qreal POINT_TO_INCH(qreal px)
Definition KoUnit.h:37
A data extension mechanism for Krita.
QVector< KoAbstractGradientSP > gradients() const
QVector< KisPSDLayerStyleSP > styles() const
void readFromPSDXML(const QDomDocument &doc)
void registerPSDPattern(const QDomDocument &doc)
QHash< QString, KoPatternSP > patterns() const
void parseXML(const QDomDocument &doc, KisAslObjectCatcher &catcher)
KisUndoStore * createUndoStore()
KisShapeController * shapeController
QString embeddedResourcesStorageId() const
void setGuidesConfig(const KisGuidesConfig &data)
KisGuidesConfig guidesConfig
static KisGeneratorRegistry * instance()
void setShowGuides(bool value)
void addGuideLine(Qt::Orientation orientation, qreal position)
Add a guide line to the canvas.
void addAnnotation(KisAnnotationSP annotation)
KisGroupLayerSP rootLayer() const
const KoColorSpace * colorSpace() const
qint32 width() const
double xRes() const
double yRes() const
qint32 height() const
KisSelectionSP globalSelection() const
Definition kis_image.cc:721
QRect bounds() const override
void setResolution(double xres, double yres)
virtual Result askUser(AskCallback callback)=0
ask the user a question about the loading process
const T value(const QString &id) const
The position of a path point within a path shape.
Definition KoPathShape.h:63
int pointCount() const
Returns the number of points in the path.
void setProperty(const QString &name, const QVariant &value)
void addShape(KoShape *shape)
static KoShapeRegistry * instance()
virtual void setStroke(KoShapeStrokeModelSP stroke)
Definition KoShape.cpp:899
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:369
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
Definition KoShape.cpp:746
void setUserData(KoShapeUserData *userData)
Definition KoShape.cpp:620
void setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor=KoFlake::Center)
Definition KoShape.cpp:583
virtual void setSize(const QSizeF &size)
Resize the shape.
Definition KoShape.cpp:249
bool convertFromSvg(const QString &svgText, const QString &stylesText, const QRectF &boundsInPixels, qreal pixelsPerInch)
upload the svg representation of text into the shape
QRectF outlineRect() const override
bool read(QIODevice &io)
psd_color_mode colormode
Definition psd_header.h:48
quint16 channelDepth
Definition psd_header.h:47
quint32 height
Definition psd_header.h:45
quint32 width
Definition psd_header.h:46
bool read(QIODevice &device)
QString error
Definition psd_header.h:52
bool read(QIODevice &io, KisPaintDeviceSP dev)
QMap< PSDResourceID, PSDResourceBlock * > resources
bool read(QIODevice &io)
PsdAdditionalLayerInfoBlock globalInfoSection
QVector< PSDLayerRecord * > layers
PsdAdditionalLayerInfoBlock infoBlocks
bool readPixelData(QIODevice &io, KisPaintDeviceSP device)
QVector< ChannelInfo * > channelInfoRecords
KoPathShape * constructPathShape(psd_path path, double shapeWidth, double shapeHeight)
constructPathShape create a KoPathshape based on a psd_path struct, used in vector masks and path res...
bool readMask(QIODevice &io, KisPaintDeviceSP dev, ChannelInfo *channel)
virtual void cancel()
KisImportExportErrorCode decode(QIODevice &io)
~PSDLoader() override
KisImageSP image()
KisDocument * m_doc
Definition psd_loader.h:42
KisImageSP m_image
Definition psd_loader.h:41
bool m_stop
Definition psd_loader.h:43
PSDLoader(KisDocument *doc, KisImportUserFeedbackInterface *feedbackInterface)
KisImportUserFeedbackInterface * m_feedbackInterface
Definition psd_loader.h:44
KisImportExportErrorCode buildImage(QIODevice &io)
The PsdTextDataConverter class.
bool convertPSDTextEngineDataToSVG(const QVariantHash tySh, const QVariantHash txt2, const KoColorSpace *imageCs, const int textIndex, QString *svgText, QString *svgStyles, QPointF &offset, bool &offsetByAscent, bool &isHorizontal, QTransform scaleToPt=QTransform())
This file is part of the Krita application in calligra.
#define warnKrita
Definition kis_debug.h:94
#define ppVar(var)
Definition kis_debug.h:163
#define dbgFile
Definition kis_debug.h:57
T kisDegreesToRadians(T degrees)
Definition kis_global.h:176
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
KisImportExportErrorCode workaroundUnsuitableImageColorSpace(KisImageSP image, KisImportUserFeedbackInterface *feedbackInterface, KisImageBarrierLock &lock)
QPair< QString, QString > psd_colormode_to_colormodelid(psd_color_mode colormode, quint16 channelDepth)
Definition psd.cpp:16
QString psd_blendmode_to_composite_op(const QString &blendmode)
Definition psd.cpp:59
@ psd_other
Definition psd.h:144
@ psd_open_folder
Definition psd.h:144
@ psd_closed_folder
Definition psd.h:144
@ psd_bounding_divider
Definition psd.h:144
@ psd_fill_gradient
Definition psd.h:125
@ psd_fill_pattern
Definition psd.h:126
@ DuoTone
Definition psd.h:57
QList< quint32 > verticalGuides
QList< quint32 > horizontalGuides
virtual void setUserLocked(bool l)
virtual void setVisible(bool visible, bool loading=false)
void setColorLabelIndex(int index)
void setName(const QString &name)
void setCollapsed(bool collapsed)
virtual KisPaintDeviceSP paintDevice() const =0
QString name() const
void setCompositeOpId(const QString &compositeOpId)
virtual KisFilterConfigurationSP defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const
void setFilter(KisFilterConfigurationSP filterConfig, bool checkCompareConfig=true) override
void setPassThroughMode(bool value)
void setLayerStyle(KisPSDLayerStyleSP layerStyle)
Definition kis_layer.cc:254
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
initSelection initializes the selection for the mask from the given selection's projection.
Definition kis_mask.cc:157
KisSelectionSP selection
Definition kis_mask.cc:44
KisPaintDeviceSP paintDevice() const override
Definition kis_mask.cc:223
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
bool moveNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis)
KisPaintDeviceSP paintDevice
KisSelectionSP internalSelection() const
void updateProjection(const QRect &rect)
void convertToVectorSelectionNoUndo(KisSelectionComponent *shapeSelection)
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_layer_gradient_fill *data)
QSharedPointer< KoShapeBackground > getBackground()
QSharedPointer< KoShapeBackground > getBackground(KisEmbeddedResourceStorageProxy &embeddedProxy)
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_layer_pattern_fill *data)
QSharedPointer< KoShapeBackground > getBackground()
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_layer_solid_color *data)
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_layer_type_shape *data)
QList< psd_path_sub_path > subPaths
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_vector_origination_data *data)
double originResolution
Resolution of the coordinates.
void OriginalSizeAndAngle(QSizeF &size, double &angle)
double originPolyStarRatio
Only for 8, percentage of small radius to big radius.
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_vector_stroke_data *data)
void setupShapeStroke(KoShapeStrokeSP stroke)