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
305 QString compositeOp = psd_blendmode_to_composite_op(layerRecord->infoBlocks.sectionDividerBlendMode);
306
307 // Krita doesn't support pass-through blend
308 // mode. Instead it is just a property of a group
309 // layer, so flip it
310 if (compositeOp == COMPOSITE_PASS_THROUGH) {
311 compositeOp = COMPOSITE_OVER;
312 groupLayer->setPassThroughMode(true);
313 }
314
315 groupLayer->setCompositeOpId(compositeOp);
316
317 newLayer = groupLayer;
318 } else {
329 warnKrita << "WARNING: Provided PSD has unbalanced group "
330 << "layer markers. Some masks and/or layers can "
331 << "be lost while loading this file. Please "
332 << "report a bug to Krita developers and attach "
333 << "this file to the bugreport\n"
334 << " " << ppVar(layerRecord->layerName) << "\n"
335 << " " << ppVar(layerRecord->infoBlocks.sectionDividerType) << "\n"
336 << " " << ppVar(groupStack.size());
337 continue;
338 }
339 } else {
340 KisLayerSP layer;
341 if (!layerRecord->infoBlocks.fillConfig.isNull()) {
343 QDomDocument fillConfig;
345
346 KoShape *vectorMask = nullptr;
347 if (layerRecord->infoBlocks.keys.contains("vmsk") || layerRecord->infoBlocks.keys.contains("vsms")) {
349 if (!layerRecord->infoBlocks.vectorOriginationData.isNull()) {
351 psd_vector_origination_data::setupCatcher("/null", catcher, &data);
352 KisAslXmlParser parser;
353 parser.parseXML(layerRecord->infoBlocks.vectorOriginationData, catcher);
354 }
355 QString shapeName = data.shapeName();
356 const KoShapeFactoryBase *f = KoShapeRegistry::instance()->value(shapeName);
357 if (!(data.canMakeParametricShape() && f)) {
358 double width = m_image->width() / m_image->xRes();
359 double height = m_image->height() / m_image->yRes();
360 vectorMask = layerRecord->constructPathShape(layerRecord->infoBlocks.vectorMask.path, width, height);
361 vectorMask->setUserData(new KisShapeSelectionMarker);
362 } else {
363 QSizeF size;
364 double angle;
365 data.OriginalSizeAndAngle(size, angle);
366 double resMultiplier = data.originResolution/72.0;
367 QTransform scaleToPt = QTransform::fromScale(resMultiplier, resMultiplier).inverted();
368 size = QSizeF(size.width()/resMultiplier, size.height()/resMultiplier);
369
371 KoProperties props;
372 if (shapeName == "RectangleShape") {
373 props.setProperty("x", 0);
374 props.setProperty("y", 0);
375 props.setProperty("width", size.width());
376 props.setProperty("height", size.height());
377 } else if (shapeName == "StarShape") {
378 props.setProperty("corners", data.originPolySides);
379 props.setProperty("convex", !data.isStar);
380
381 double angle = 360.0/(data.originPolySides*2);
382 double a = cos(kisDegreesToRadians(angle)) * 100.0;
383 double totalHeight = a + 100.0;
384 double l = size.height() / totalHeight * 100.0;
385
386 if (data.isStar) {
387 // 100% is a normal polygon.
388 a = cos(kisDegreesToRadians(angle)) * ((data.originPolyStarRatio*0.01) * l);
389 props.setProperty("baseRadius", a);
390 }
391 props.setProperty("tipRadius", l);
392 props.setProperty("baseRoundness", 0.0);
393 props.setProperty("tipRoundness", 0.0);
394 }
395 KoShape *shape = f->createShape(&props, &manager);
396 if (!shape)
397 continue;
398 shape->setSize(size);
399 QTransform t;
400 t.rotate(360.0-angle);
401
402 shape->setTransformation(t * scaleToPt.inverted() * data.transform * scaleToPt);
403 shape->setAbsolutePosition(scaleToPt.map(data.originShapeBBox.center()));
404
405 vectorMask = shape;
406 }
407 }
408 if (layerRecord->infoBlocks.fillType == psd_fill_gradient) {
410
412 fill.imageWidth = m_image->width();
413 fill.imageHeight = m_image->height();
414 psd_layer_gradient_fill::setupCatcher("/null", catcher, &fill);
415 KisAslXmlParser parser;
416 parser.parseXML(layerRecord->infoBlocks.fillConfig, catcher);
417 fillConfig = fill.getFillLayerConfig();
418 if (vectorMask) {
419 vectorMask->setBackground(fill.getBackground());
420 }
421
422 } else if (layerRecord->infoBlocks.fillType == psd_fill_pattern) {
424
426 psd_layer_pattern_fill::setupCatcher("/null", catcher, &fill);
427
428 KisAslXmlParser parser;
429 parser.parseXML(layerRecord->infoBlocks.fillConfig, catcher);
430 fillConfig = fill.getFillLayerConfig();
431 if (vectorMask) {
432 vectorMask->setBackground(fill.getBackground(resourceProxy));
433 }
434
435 } else {
437
439 fill.cs = m_image->colorSpace();
440 psd_layer_solid_color::setupCatcher("/null", catcher, &fill);
441 KisAslXmlParser parser;
442 parser.parseXML(layerRecord->infoBlocks.fillConfig, catcher);
443
444 fillConfig = fill.getFillLayerConfig();
445 if (vectorMask) {
446 vectorMask->setBackground(fill.getBackground());
447 }
448 }
449 if (vectorMask) {
450 KisShapeLayerSP shapeLayer = new KisShapeLayer(m_doc->shapeController(), m_image, layerRecord->layerName, layerRecord->opacity);
451
452
453 if (!layerRecord->infoBlocks.vectorStroke.isNull()) {
454 KoShapeStrokeSP stroke(new KoShapeStroke());
458 fill.cs = m_image->colorSpace();
459 KisAslCallbackObjectCatcher strokeCatcher;
460 psd_vector_stroke_data::setupCatcher("", strokeCatcher, &data);
461 psd_layer_solid_color::setupCatcher("/strokeStyle/strokeStyleContent", strokeCatcher, &fill);
462 psd_layer_gradient_fill::setupCatcher("/strokeStyle/strokeStyleContent", strokeCatcher, &grad);
463 KisAslXmlParser parser;
464 parser.parseXML(layerRecord->infoBlocks.vectorStroke, strokeCatcher);
465
466 if (!data.fillEnabled) {
468 }
469 if (data.strokeEnabled) {
470 QColor c = fill.getBrush().color();
471 c.setAlphaF(data.opacity);
472 stroke->setColor(c);
473 if (!grad.gradient.isNull()) {
474 stroke->setLineBrush(grad.getBrush());
475 }
476 } else {
477 stroke->setColor(Qt::transparent);
478 }
479 data.setupShapeStroke(stroke);
480
481 vectorMask->setStroke(stroke);
482 }
483
484 shapeLayer->addShape(vectorMask);
485 layer = shapeLayer;
486 } else {
487 cfg->fromXML(fillConfig.firstChildElement());
488 cfg->createLocalResourcesSnapshot();
489 KisGeneratorLayerSP genlayer = new KisGeneratorLayer(m_image, layerRecord->layerName, cfg, m_image->globalSelection());
490 genlayer->setFilter(cfg);
491 layer = genlayer;
492 }
493
494
495 } else if (!layerRecord->infoBlocks.textData.isNull() && convertTextToShape) {
496 KisShapeLayerSP textLayer = new KisShapeLayer(m_doc->shapeController(), m_image, layerRecord->layerName, layerRecord->opacity);
499 psd_layer_type_shape::setupCatcher(QString(), catcher, &text);
500 KisAslXmlParser parser;
501 parser.parseXML(layerRecord->infoBlocks.textData, catcher);
502 KoSvgTextShape *shape = new KoSvgTextShape();
503 PsdTextDataConverter converter;
504 KoSvgTextShapeMarkupConverter svgConverter(shape);
505
506 QString svg;
507 QString styles;
508 // This is to align inlinesize appropriately.
509 bool offsetByAscent = false;
510 QPointF offset1;
511 // PSD text layers have all their coordinates in pixels, and because fonts can be very precise-unit sensitive,
512 // we want to ensure all values are scaled appropriately.
513
514 QTransform scaleToPt = QTransform::fromScale(m_image->xRes(), m_image->yRes()).inverted();
515 bool res = converter.convertPSDTextEngineDataToSVG(text.engineData,
516 layerSection.globalInfoSection.txt2Data,
518 text.textIndex,
519 &svg, &styles,
520 offset1, offsetByAscent,
521 text.isHorizontal, scaleToPt);
522 if (!res || !converter.errors().isEmpty()) {
523 qWarning() << converter.errors();
524 }
525 dbgFile << converter.warnings();
526 svgConverter.convertFromSvg(svg, styles, m_image->bounds(), m_image->xRes()*72.0);
527 if (offsetByAscent) {
528 QPointF offset2 = QPointF() - shape->outlineRect().topLeft();
529 if (text.isHorizontal) {
530 offset2.setX(offset1.x());
531 } else {
532 offset2.setY(offset1.y());
533 }
534 shape->setTransformation(QTransform::fromTranslate(offset2.x(), offset2.y()) * scaleToPt.inverted()
535 * layerRecord->infoBlocks.textTransform * scaleToPt);
536 } else {
537 shape->setTransformation(scaleToPt.inverted() * layerRecord->infoBlocks.textTransform * scaleToPt);
538 }
539 textLayer->addShape(shape);
540 layer = textLayer;
541 } else {
542 layer = new KisPaintLayer(m_image, layerRecord->layerName, layerRecord->opacity);
543 if (!layerRecord->readPixelData(io, layer->paintDevice())) {
544 dbgFile << "failed reading channels for layer: " << layerRecord->layerName << layerRecord->error;
546 }
547 }
549
550 layer->setColorLabelIndex(layerRecord->labelColor);
551
552 const QDomDocument &styleXml = layerRecord->infoBlocks.layerStyleXml;
553
554 if (!styleXml.isNull()) {
555 allStylesXml << LayerStyleMapping(styleXml, layer);
556 }
557
558 if (!groupStack.isEmpty()) {
559 m_image->addNode(layer, groupStack.top());
560 }
561 else {
562 m_image->addNode(layer, m_image->root());
563 }
564 layer->setVisible(layerRecord->visible);
565 newLayer = layer;
566
567 }
568
569 Q_FOREACH (ChannelInfo *channelInfo, layerRecord->channelInfoRecords) {
570 if (channelInfo->channelId < -1) {
571 const KisGeneratorLayer *fillLayer = qobject_cast<KisGeneratorLayer *>(newLayer.data());
572 const KisShapeLayer *shapeLayer = qobject_cast<KisShapeLayer *>(newLayer.data());
573 KoPathShape *vectorMask = new KoPathShape();
574 if (layerRecord->infoBlocks.keys.contains("vmsk") || layerRecord->infoBlocks.keys.contains("vsms")) {
575 double width = m_image->width() / m_image->xRes();
576 double height = m_image->height() / m_image->yRes();
577 vectorMask = layerRecord->constructPathShape(layerRecord->infoBlocks.vectorMask.path, width, height);
578 vectorMask->setUserData(new KisShapeSelectionMarker);
579 }
580 bool hasVectorMask = vectorMask->pointCount() > 0 && layerRecord->infoBlocks.vectorMask.path.subPaths.size() > 0;
581 if (fillLayer) {
582 if (!layerRecord->readMask(io, fillLayer->paintDevice(), channelInfo)) {
583 dbgFile << "failed reading masks for generator layer: " << layerRecord->layerName << layerRecord->error;
584 }
585 if (hasVectorMask) {
586 KisShapeSelection* shapeSelection = new KisShapeSelection(m_doc->shapeController(), fillLayer->internalSelection());
587 fillLayer->internalSelection()->convertToVectorSelectionNoUndo(shapeSelection);
588 shapeSelection->addShape(vectorMask);
589 fillLayer->internalSelection()->updateProjection();
590 }
591 } else {
592 if (!(shapeLayer && hasVectorMask)) {
593 KisTransparencyMaskSP mask = new KisTransparencyMask(m_image, i18n("Transparency Mask"));
594 mask->initSelection(newLayer);
595 if (!layerRecord->readMask(io, mask->paintDevice(), channelInfo)) {
596 dbgFile << "failed reading masks for layer: " << layerRecord->layerName << layerRecord->error;
597 }
598 if (hasVectorMask) {
599 KisShapeSelection* shapeSelection = new KisShapeSelection(m_doc->shapeController(), mask->selection());
600 mask->selection()->convertToVectorSelectionNoUndo(shapeSelection);
601 shapeSelection->addShape(vectorMask);
602 mask->selection()->updateProjection();
603 }
604 m_image->addNode(mask, newLayer);
605 }
606 }
607 }
608 }
609
610 lastAddedLayer = newLayer;
611 }
612
613 if (!allStylesXml.isEmpty()) {
614 Q_FOREACH (const LayerStyleMapping &mapping, allStylesXml) {
615
616 serializer.readFromPSDXML(mapping.first);
617
618 if (serializer.styles().size() == 1) {
619 KisPSDLayerStyleSP layerStyle = serializer.styles().first();
620 KisLayerSP layer = mapping.second;
621
622 Q_FOREACH (KoAbstractGradientSP gradient, serializer.gradients()) {
623 if (gradient && gradient->valid()) {
624 resourceProxy.addResource(gradient);
625 }
626 else {
627 qWarning() << "Invalid or empty gradient" << gradient;
628 }
629 }
630
631 Q_FOREACH (const KoPatternSP &pattern, serializer.patterns()) {
632 if (pattern && pattern->valid()) {
633 resourceProxy.addResource(pattern);
634 } else {
635 qWarning() << "Invalid or empty pattern" << pattern;
636 }
637 }
638
639 layerStyle->setName(layer->name());
640 layerStyle->setResourcesInterface(resourceProxy.detachedResourcesInterface());
641 if (!layerStyle->uuid().isNull()) {
642 layerStyle->setUuid(QUuid::createUuid());
643 }
644 layerStyle->setValid(true);
645
646 resourceProxy.addResource(layerStyle);
647
648 layer->setLayerStyle(layerStyle->cloneWithResourcesSnapshot(layerStyle->resourcesInterface(), 0));
649 } else {
650 warnKrita << "WARNING: Couldn't read layer style!" << ppVar(serializer.styles());
651 }
652
653 }
654 }
655
657}
658
660{
661 return decode(io);
662}
663
664
666{
667 return m_image;
668}
669
671{
672 m_stop = true;
673}
674
675
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:695
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:1081
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:417
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
Definition KoShape.cpp:918
void setUserData(KoShapeUserData *userData)
Definition KoShape.cpp:705
void setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor=KoFlake::Center)
Definition KoShape.cpp:668
virtual void setSize(const QSizeF &size)
Resize the shape.
Definition KoShape.cpp:276
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:87
#define ppVar(var)
Definition kis_debug.h:155
#define dbgFile
Definition kis_debug.h:53
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 setVisible(bool visible, bool loading=false)
void setColorLabelIndex(int index)
void setName(const QString &name)
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)