PSD has a weird "optimization": if a group layer has only one child layer, it omits it's 'psd_bounding_divider' section. So fi you ever see an unbalanced layers group in PSD, most probably, it is just a single layered group.
In some files saved by PS CS6 the group layer sections seem to be unbalanced. I don't know why it happens because the reporter didn't provide us an example file. So here we just check if the new layer was created, and if not, skip the initialization of masks.
75{
76
77
79
81 if (!header.
read(io)) {
84 }
85
87 dbgFile <<
"Read header. pos:" << io.pos();
88
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
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
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
112
113
114
116 header.channelDepth);
117 if (colorSpaceId.first.isNull()) {
118 dbgFile <<
"Unsupported colorspace" << header.colormode << header.channelDepth;
120 }
121
122
126 if (iccProfileData ) {
128 colorSpaceId.second,
129 iccProfileData->
icc);
130 dbgFile <<
"Loaded ICC profile" << profile->
name();
132 }
133 }
134
135
137 if (!cs) {
139 }
140
141
142 QFile *
file =
dynamic_cast<QFile *
>(&io);
146
147 KisImageBarrierLock lock(
m_image);
148
149
152 if (resInfo) {
153
154 if (resInfo->
hRes * resInfo->
vRes > 0)
156
158 }
159 }
160
163 if (gridGuidesInfo) {
167 }
170 }
173 }
174 }
175
176
179 }
180
181
182 if (header.colormode ==
DuoTone) {
184 i18n("Duotone Colormode Block"),
185 colorModeBlock.data);
187 }
188
189
190
192 layerSection.globalInfoSection.embeddedPatterns;
193
195
197
199 if (!embeddedPatterns.isEmpty()) {
200 Q_FOREACH (const QDomDocument &doc, embeddedPatterns) {
202 }
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
215
216
217
218 if (layerSection.nLayers == 0) {
219 dbgFile <<
"Position" << io.pos() <<
"Going to read the projection into the first layer, which Photoshop calls 'Background'";
220
222
225
227
228
230 }
231
232
233
236
244
245 typedef QPair<QDomDocument, KisLayerSP> LayerStyleMapping;
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()) {
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 });
264 break;
265 }
266 }
267
268
269 for(int i = 0; i < layerSection.nLayers; ++i) {
270
272 dbgFile <<
"Going to read channels for layer" << i << layerRecord->
layerName;
276
280 groupStack.push(groupLayer);
281 newLayer = groupLayer;
282 }
285 (groupStack.size() > 1 || (lastAddedLayer && !groupStack.isEmpty()))) {
287
288 if (groupStack.size() <= 1) {
292 } else {
293 groupLayer = groupStack.pop();
294 }
295
297
298 if (!styleXml.isNull()) {
299 allStylesXml << LayerStyleMapping(styleXml, groupLayer);
300 }
301
304
306
307
308
309
313 }
314
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"
336 <<
" " <<
ppVar(groupStack.size());
337 continue;
338 }
339 } else {
343 QDomDocument fillConfig;
345
354 }
362 } else {
364 double angle;
367 QTransform scaleToPt = QTransform::fromScale(resMultiplier, resMultiplier).inverted();
368 size = QSizeF(
size.width()/resMultiplier,
size.height()/resMultiplier);
369
372 if (shapeName == "RectangleShape") {
377 } else if (shapeName == "StarShape") {
380
383 double totalHeight = a + 100.0;
384 double l =
size.height() / totalHeight * 100.0;
385
387
390 }
394 }
395 KoShape *shape =
f->createShape(&props, &manager);
396 if (!shape)
397 continue;
399 QTransform t;
400 t.rotate(360.0-angle);
401
404
405 vectorMask = shape;
406 }
407 }
410
418 if (vectorMask) {
420 }
421
424
427
431 if (vectorMask) {
433 }
434
435 } else {
437
443
445 if (vectorMask) {
447 }
448 }
449 if (vectorMask) {
451
452
465
468 }
472 stroke->setColor(c);
474 stroke->setLineBrush(grad.
getBrush());
475 }
476 } else {
477 stroke->setColor(Qt::transparent);
478 }
480
482 }
483
485 layer = shapeLayer;
486 } else {
487 cfg->fromXML(fillConfig.firstChildElement());
488 cfg->createLocalResourcesSnapshot();
491 layer = genlayer;
492 }
493
494
505
506 QString svg;
507 QString styles;
508
509 bool offsetByAscent = false;
510 QPointF offset1;
511
512
513
516 layerSection.globalInfoSection.txt2Data,
519 &svg, &styles,
520 offset1, offsetByAscent,
522 if (!res || !converter.
errors().isEmpty()) {
523 qWarning() << converter.
errors();
524 }
527 if (offsetByAscent) {
528 QPointF offset2 = QPointF() - shape->
outlineRect().topLeft();
530 offset2.setX(offset1.x());
531 } else {
532 offset2.setY(offset1.y());
533 }
534 shape->
setTransformation(QTransform::fromTranslate(offset2.x(), offset2.y()) * scaleToPt.inverted()
536 } else {
538 }
540 layer = textLayer;
541 } else {
546 }
547 }
549
551
553
554 if (!styleXml.isNull()) {
555 allStylesXml << LayerStyleMapping(styleXml, layer);
556 }
557
558 if (!groupStack.isEmpty()) {
560 }
561 else {
563 }
565 newLayer = layer;
566
567 }
568
572 const KisShapeLayer *shapeLayer = qobject_cast<KisShapeLayer *>(newLayer.
data());
579 }
581 if (fillLayer) {
583 dbgFile <<
"failed reading masks for generator layer: " << layerRecord->
layerName << layerRecord->
error;
584 }
585 if (hasVectorMask) {
588 shapeSelection->
addShape(vectorMask);
590 }
591 } else {
592 if (!(shapeLayer && hasVectorMask)) {
597 }
598 if (hasVectorMask) {
601 shapeSelection->
addShape(vectorMask);
603 }
605 }
606 }
607 }
608 }
609
610 lastAddedLayer = newLayer;
611 }
612
613 if (!allStylesXml.isEmpty()) {
614 Q_FOREACH (const LayerStyleMapping &mapping, allStylesXml) {
615
617
618 if (serializer.
styles().size() == 1) {
621
623 if (gradient && gradient->valid()) {
624 resourceProxy.addResource(gradient);
625 }
626 else {
627 qWarning() << "Invalid or empty gradient" << gradient;
628 }
629 }
630
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 {
651 }
652
653 }
654 }
655
657}
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
const QString COMPOSITE_PASS_THROUGH
constexpr qreal POINT_TO_INCH(qreal px)
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
KisSelectionSP globalSelection() const
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.
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)
void setTransformation(const QTransform &matrix)
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
void setUserData(KoShapeUserData *userData)
void setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor=KoFlake::Center)
virtual void setSize(const QSizeF &size)
Resize the shape.
QRectF outlineRect() const override
QMap< PSDResourceID, PSDResourceBlock * > resources
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)
psd_section_type sectionDividerType
QDomDocument vectorStroke
QDomDocument vectorOriginationData
QString sectionDividerBlendMode
QDomDocument layerStyleXml
psd_vector_mask vectorMask
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())
QStringList errors() const
QStringList warnings() const
T kisDegreesToRadians(T degrees)
KisSharedPtr< KisNode > KisNodeSP
@ FormatColorSpaceUnsupported
const char * name(StandardAction id)
int size(const Forest< T > &forest)
KisImportExportErrorCode workaroundUnsuitableImageColorSpace(KisImageSP image, KisImportUserFeedbackInterface *feedbackInterface, KisImageBarrierLock &lock)
QPair< QString, QString > psd_colormode_to_colormodelid(psd_color_mode colormode, quint16 channelDepth)
QString psd_blendmode_to_composite_op(const QString &blendmode)
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
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)
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
initSelection initializes the selection for the mask from the given selection's projection.
KisPaintDeviceSP paintDevice() const override
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
bool moveNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis)
KisPaintDeviceSP paintDevice
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)
QDomDocument getFillLayerConfig()
QSharedPointer< KoShapeBackground > getBackground()
QSharedPointer< KoShapeBackground > getBackground(KisEmbeddedResourceStorageProxy &embeddedProxy)
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_layer_pattern_fill *data)
QDomDocument getFillLayerConfig() const
QSharedPointer< KoShapeBackground > getBackground()
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_layer_solid_color *data)
QDomDocument getFillLayerConfig()
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_layer_type_shape *data)
QList< psd_path_sub_path > subPaths
QRectF originShapeBBox
pre-transform bbox.
static void setupCatcher(const QString path, KisAslCallbackObjectCatcher &catcher, psd_vector_origination_data *data)
double originResolution
Resolution of the coordinates.
int originPolySides
Only for 7 and 8.
void OriginalSizeAndAngle(QSizeF &size, double &angle)
bool canMakeParametricShape()
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)