48 return "Real User Supplied Layer Mask (when both a user mask and a vector mask are present";
50 return "User Supplied Layer Mask";
52 return "Transparency mask";
57 return QString(
"bitmap or indexed: %1").arg(channelId);
72 return QString(
"multichannel channel %1").arg(channelId);
75 return QString(
"duotone channel %1").arg(channelId);
77 return QString(
"unknown: %1").arg(channelId);
83 return QString(
"WARNING bitmap or indexed: %1").arg(channelId);
86 return QString(
"WARNING: %1").arg(channelId);
98 return QString(
"multichannel channel %1").arg(channelId);
101 return QString(
"duotone channel %1").arg(channelId);
103 return QString(
"unknown: %1").arg(channelId);
109 return QString(
"WARNING bitmap or indexed: %1").arg(channelId);
112 return QString(
"WARNING: %1").arg(channelId);
124 return QString(
"multichannel channel %1").arg(channelId);
127 return QString(
"duotone channel %1").arg(channelId);
129 return QString(
"unknown: %1").arg(channelId);
135 return QString(
"WARNING bitmap or indexed: %1").arg(channelId);
138 return QString(
"WARNING: %1").arg(channelId);
141 return QString(
"alpha: %1").arg(channelId);
144 return QString(
"alpha: %1").arg(channelId);
150 return QString(
"multichannel channel %1").arg(channelId);
153 return QString(
"duotone channel %1").arg(channelId);
155 return QString(
"unknown: %1").arg(channelId);
158 return QString(
"unknown: %1").arg(channelId);
172 return readImpl<psd_byte_order::psdLittleEndian>(io);
178template<psd_
byte_order
byteOrder>
181 dbgFile <<
"Going to read layer record. Pos:" << io.pos();
183 if (!psdread<byteOrder>(io,
top) || !psdread<byteOrder>(io,
left) || !psdread<byteOrder>(io,
bottom) || !psdread<byteOrder>(io,
right)
185 error =
"could not read layer record";
207 error =
"Could not read enough data for channels";
213 if (!psdread<byteOrder>(io, info->
channelId)) {
214 error =
"could not read channel id";
220 quint32 channelDataLength;
221 r = psdread<byteOrder>(io, channelDataLength);
227 error =
"Could not read length for channel data";
245 if (!psdread<byteOrder>(io,
opacity)) {
246 error =
"Could not read opacity";
252 if (!psdread<byteOrder>(io,
clipping)) {
253 error =
"Could not read clipping";
260 if (!psdread<byteOrder>(io, flags)) {
261 error =
"Could not read flags";
264 dbgFile <<
"\tflags" << flags << io.pos();
270 visible = flags & 2 ? false :
true;
282 dbgFile <<
"\tfiller at " << io.pos();
285 if (!psdread<byteOrder>(io, filler) || filler != 0) {
286 error =
"Could not read padding";
290 dbgFile <<
"\tGoing to read extra data length" << io.pos();
292 quint32 extraDataLength;
293 if (!psdread<byteOrder>(io, extraDataLength) || io.bytesAvailable() < extraDataLength) {
294 error = QString(
"Could not read extra layer data: %1 at pos %2").arg(extraDataLength).arg(io.pos());
298 dbgFile <<
"\tExtra data length" << extraDataLength;
300 if (extraDataLength > 0) {
301 dbgFile <<
"Going to read extra data field. Bytes available: " << io.bytesAvailable() <<
"pos" << io.pos();
304 quint32 layerMaskLength = 1;
305 if (!psdread<byteOrder>(io, layerMaskLength) || io.bytesAvailable() < layerMaskLength) {
306 error = QString(
"Could not read layer mask length: %1").arg(layerMaskLength);
312 if (layerMaskLength == 0) {
313 dbgFile <<
"\tNo layer mask/adjustment layer data. pos" << io.pos();
315 dbgFile <<
"\tReading layer mask/adjustment layer data. Length of block:" << layerMaskLength <<
"pos"
321 error =
"could not read common records of layer mask";
328 const bool hasMaskParameters = (flags & 8) != 0;
332 <<
", needs to read mask parameters" << hasMaskParameters;
334 if (layerMaskLength == 20) {
336 if (!psdread<byteOrder>(io, padding)) {
337 error =
"Could not read layer mask padding";
341 quint32 remainingBlockLength = layerMaskLength - 18;
343 dbgFile <<
"\tReading selective records from layer mask info. Remaining block length"
344 << remainingBlockLength;
346 if (hasMaskParameters) {
347 if (!psdread<byteOrder>(io, flags)) {
348 error =
"could not read mask parameters";
352 remainingBlockLength -= 1;
354 dbgFile <<
"\t\tMask parameters" << QString::number(flags, 2) <<
". Remaining block length"
355 << remainingBlockLength;
359 if (!psdread<byteOrder>(io, dummy)) {
360 error =
"could not read user mask density";
363 remainingBlockLength -=
sizeof(dummy);
368 if (!psdread<byteOrder>(io, dummy)) {
369 error =
"could not read user mask feather";
372 remainingBlockLength -=
sizeof(dummy);
377 if (!psdread<byteOrder>(io, dummy)) {
378 error =
"could not read vector mask density";
381 remainingBlockLength -=
sizeof(dummy);
386 if (!psdread<byteOrder>(io, dummy)) {
387 error =
"could not read vector mask feather";
390 remainingBlockLength -=
sizeof(dummy);
394 if (remainingBlockLength >= 1) {
395 if (!psdread<byteOrder>(io, flags)) {
396 error =
"could not read 'real' mask record";
403 const bool hasMaskParameters = (flags & 8) != 0;
407 <<
", needs to read mask parameters" << hasMaskParameters;
409 remainingBlockLength -= 1;
411 dbgFile <<
"\t\tRemaining block length" << remainingBlockLength;
414 if (remainingBlockLength >= 1) {
416 error =
"could not read 'real' default color";
419 remainingBlockLength -= 1;
420 dbgFile <<
"\t\tRead 'real' default color. Remaining block length" << remainingBlockLength;
423 if (remainingBlockLength >= 16) {
426 error =
"could not read 'real' mask rectangle";
429 remainingBlockLength -= 16;
430 dbgFile <<
"\t\tRead 'real' mask rectangle. Remaining block length" << remainingBlockLength;
436 quint32 blendingDataLength = 0;
437 if (!psdread<byteOrder>(io, blendingDataLength) || io.bytesAvailable() < blendingDataLength) {
438 error =
"Could not read extra blending data.";
442 quint32 blendingNchannels = blendingDataLength > 0 ? (blendingDataLength - 8) / 4 / 2 : 0;
444 dbgFile <<
"\tNumber of blending channels:" << blendingNchannels;
446 if (blendingDataLength > 0) {
447 if (blendingDataLength > 0) {
452 error =
"Could not read blending black/white values";
456 blendingDataLength -= 4;
458 if (blendingDataLength > 0) {
463 error =
"Could not read blending black/white values";
467 blendingDataLength -= 4;
469 dbgFile <<
"\tBlending ranges:";
473 for (quint32 i = 0; i < blendingNchannels; ++i) {
476 if (!psdread<byteOrder>(io, src.blackValues[0]) || !psdread<byteOrder>(io, src.blackValues[1]) || !psdread<byteOrder>(io, src.whiteValues[0])
477 || !psdread<byteOrder>(io, src.whiteValues[1]) || !psdread<byteOrder>(io, dst.blackValues[0]) || !psdread<byteOrder>(io, dst.blackValues[1])
478 || !psdread<byteOrder>(io, dst.whiteValues[0]) || !psdread<byteOrder>(io, dst.whiteValues[1])) {
479 error = QString(
"could not read src/dst range for channel %1").arg(i);
482 dbgFile <<
"\t\tread range " << src <<
"to" << dst <<
"for channel" << i;
487 dbgFile <<
"\tGoing to read layer name at" << io.pos();
488 quint8 layerNameLength;
489 if (!psdread<byteOrder>(io, layerNameLength)) {
490 error =
"Could not read layer name length";
494 dbgFile <<
"\tlayer name length unpadded" << layerNameLength <<
"pos" << io.pos();
495 layerNameLength = ((layerNameLength + 1 + 3) & ~0x03) - 1;
497 dbgFile <<
"\tlayer name length padded" << layerNameLength <<
"pos" << io.pos();
502 dbgFile <<
"\tAbout to read additional info blocks at" << io.pos();
522 const QRect &maskRect,
524 const QDomDocument &stylesXmlDoc,
525 bool useLfxsLayerStyleFormat)
529 return writeImpl<psd_byte_order::psdLittleEndian>(io,
531 onlyTransparencyMask,
535 useLfxsLayerStyleFormat);
537 return writeImpl(io, layerContentDevice, onlyTransparencyMask, maskRect, sectionType, stylesXmlDoc, useLfxsLayerStyleFormat);
541template<psd_
byte_order
byteOrder>
545 const QRect &maskRect,
547 const QDomDocument &stylesXmlDoc,
548 bool useLfxsLayerStyleFormat)
550 dbgFile <<
"writing layer info record"
566 KisAslWriterUtils::writeRect<byteOrder>(layerRect, io);
580 const quint32 fakeChannelSize = 0;
585 const quint16 userSuppliedMaskChannelId = -2;
590 const quint32 fakeTransparencyMaskSize = 0;
597 KisAslWriterUtils::writeFixedString<byteOrder>(
"8BIM", io);
598 KisAslWriterUtils::writeFixedString<byteOrder>(
blendModeKey, io);
627 const quint32 layerMaskDataSize = 20;
643 quint8 maskFlags = 0;
649 const quint16 padding = 0;
653 const quint32 nullLayerMaskDataSize = 0;
659 const quint32 nullBlendingRangesSize = 0;
664 psdwrite_pascalstring<byteOrder>(io,
layerName, 4);
679 if (!stylesXmlDoc.isNull()) {
680 additionalInfoBlock.
writeLfx2BlockEx(io, stylesXmlDoc, useLfxsLayerStyleFormat);
730 switch (colorLabelIndex) {
798template<psd_
byte_order
byteOrder>
808 (quint8 *)buffer.data(),
823 writePixelDataImpl<psd_byte_order::psdLittleEndian>(io, compressionType);
834template<psd_
byte_order
byteOrder>
843 dbgFile <<
"Layer is empty! Writing placeholder information.";
851 writeTransparencyMaskPixelData<byteOrder>(io);
868 writeTransparencyMaskPixelData<byteOrder>(io);
879 dbgFile <<
"Reading pixel data for layer" <<
layerName <<
"pos" << io.pos();
919 if (maskRect.isEmpty()) {
935 infoRecords << channelInfo;
946 QTransform tf = QTransform::fromScale(shapeWidth, shapeHeight);
950 for (
int i = 0; i < subPath.
nodes.size(); i++) {
963 nodeTypes.append(
"s");
965 nodeTypes.append(
"c");
989 QTransform tf = QTransform::fromScale(shapeWidth, shapeHeight).inverted();
1005 subPath.
nodes.append(node);
1008 path.subPaths.append(subPath);
1015 dbg.nospace() <<
"valid: " <<
const_cast<PSDLayerRecord *
>(&layer)->valid();
1016 dbg.nospace() <<
", name: " << layer.
layerName;
1017 dbg.nospace() <<
", top: " << layer.
top;
1018 dbg.nospace() <<
", left:" << layer.
left;
1019 dbg.nospace() <<
", bottom: " << layer.
bottom;
1020 dbg.nospace() <<
", right: " << layer.
right;
1021 dbg.nospace() <<
", number of channels: " << layer.
nChannels;
1022 dbg.nospace() <<
", blendModeKey: " << layer.
blendModeKey;
1023 dbg.nospace() <<
", opacity: " << layer.
opacity;
1024 dbg.nospace() <<
", clipping: " << layer.
clipping;
1026 dbg.nospace() <<
", visible: " << layer.
visible;
1027 dbg.nospace() <<
", irrelevant: " << layer.
irrelevant <<
"\n";
1029 dbg.space() << channel;
1032 return dbg.nospace();
1040 return dbg.nospace();
QPair< int, int > KoPathPointIndex
quint32 pixelSize() const
void setDefaultPixel(const KoColor &defPixel)
const KoColorSpace * colorSpace() const
KoColor defaultPixel() const
void convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KUndo2Command *parentCommand=nullptr, KoUpdater *progressUpdater=nullptr)
void readBytes(quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h) const
A KoPathPoint represents a point in a path.
PointProperties properties
@ IsSmooth
it is smooth, both control points on a line through the point
@ IsSymmetric
it is symmetric, like smooth but control points have same distance to point
The position of a path point within a path shape.
int subpathPointCount(int subpathIndex) const
Returns the number of points in a subpath.
bool isClosedSubpath(int subpathIndex) const
Checks if a subpath is closed.
KoPathPoint * lineTo(const QPointF &p)
Adds a new line segment.
void closeMerge()
Closes the current subpath.
KoPathPoint * moveTo(const QPointF &p)
Starts a new Subpath.
int pointCount() const
Returns the number of points in the path.
KoPathPoint * curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p)
Adds a new cubic Bezier curve segment.
int subpathCount() const
Returns the number of subpaths in the path.
void loadNodeTypes(const QString &nodeTypes)
Loads node types.
KoPathPoint * pointByIndex(const KoPathPointIndex &pointIndex) const
Returns the path point specified by a path point index.
QTransform absoluteTransformation() const
bool readImpl(QIODevice &io)
PSDLayerRecord(const PSDHeader &header)
PsdAdditionalLayerInfoBlock infoBlocks
qint64 m_transparencyMaskSizeOffset
KisPaintDeviceSP convertMaskDeviceIfNeeded(KisPaintDeviceSP dev)
QRect m_onlyTransparencyMaskRect
void writePixelData(QIODevice &io, psd_compression_type compressionType)
void writeTransparencyMaskPixelData(QIODevice &io)
psd_vector_mask vectorMask
psd_layer_type_shape textShape
bool readPixelData(QIODevice &io, KisPaintDeviceSP device)
void writePixelDataImpl(QIODevice &io, psd_compression_type compressionType)
QDomDocument vectorOriginationData
KisPaintDeviceSP m_layerContentDevice
quint16 psdLabelColor(int colorLabelIndex)
LayerBlendingRanges blendingRanges
QVector< ChannelInfo * > channelInfoRecords
QRect channelRect(ChannelInfo *channel) const
QDomDocument vectorStroke
void write(QIODevice &io, KisPaintDeviceSP layerContentDevice, KisNodeSP onlyTransparencyMask, const QRect &maskRect, psd_section_type sectionType, const QDomDocument &stylesXmlDoc, bool useLfxsLayerStyleFormat)
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...
void addPathShapeToPSDPath(psd_path &path, KoPathShape *shape, double shapeWidth, double shapeHeight)
addPathShapeToPSDPath add all KoPathShape subpaths to the given psd_path struct.
bool transparencyProtected
int kritaColorLabelIndex(quint16 labelColor)
KisNodeSP m_onlyTransparencyMask
void writeImpl(QIODevice &io, KisPaintDeviceSP layerContentDevice, KisNodeSP onlyTransparencyMask, const QRect &maskRect, psd_section_type sectionType, const QDomDocument &stylesXmlDoc, bool useLfxsLayerStyleFormat)
bool readMask(QIODevice &io, KisPaintDeviceSP dev, ChannelInfo *channel)
The PsdAdditionalLayerInfoBlock class implements the Additional Layer Information block.
void writeLfx2BlockEx(QIODevice &io, const QDomDocument &stylesXmlDoc, bool useLfxsLayerStyleFormat)
void writeFillLayerBlockEx(QIODevice &io, const QDomDocument &fillConfig, psd_fill_type type)
void writeVmskBlockEx(QIODevice &io, psd_vector_mask mask)
void writeVectorOriginationDataEx(QIODevice &io, const QDomDocument &vectorOrigination)
void writeLsctBlockEx(QIODevice &io, psd_section_type sectionType, bool isPassThrough, const QString &blendModeKey)
void writeVectorStrokeDataEx(QIODevice &io, const QDomDocument &vectorStroke)
void writeLuniBlockEx(QIODevice &io, const QString &layerName)
void writeLclrBlockEx(QIODevice &io, const quint16 &labelColor)
void writeTypeToolBlockEx(QIODevice &io, psd_layer_type_shape typeTool)
#define SAFE_WRITE_EX(byteOrder, device, varname)
#define KIS_ASSERT_RECOVER(cond)
#define KIS_ASSERT_RECOVER_NOOP(cond)
#define PREPEND_METHOD(msg)
void writePixelDataCommon(QIODevice &io, KisPaintDeviceSP dev, const QRect &rc, psd_color_mode colorMode, int channelSize, bool alphaFirst, const bool writeCompressionType, QVector< ChannelWritingInfo > &writingInfoList, psd_compression_type compressionType, psd_byte_order byteOrder)
void readChannels(QIODevice &io, KisPaintDeviceSP device, psd_color_mode colorMode, int channelSize, const QRect &layerRect, QVector< ChannelInfo * > infoRecords, psd_byte_order byteOrder)
void writeChannelDataRLE(QIODevice &io, const quint8 *plane, const int channelSize, const QRect &rc, const qint64 sizeFieldOffset, const qint64 rleBlockOffset, const bool writeCompressionType, psd_byte_order byteOrder)
void readAlphaMaskChannels(QIODevice &io, KisPaintDeviceSP device, int channelSize, const QRect &layerRect, QVector< ChannelInfo * > infoRecords, psd_byte_order byteOrder)
QString channelIdToChannelType(int channelId, psd_color_mode colormode)
QDebug operator<<(QDebug dbg, const PSDLayerRecord &layer)
psd_compression_type compressionType
quint64 channelDataLength
virtual KisPaintDeviceSP paintDevice() const =0
static KoColorSpaceRegistry * instance()
QVector< QPair< LayerBlendingRange, LayerBlendingRange > > sourceDestinationRanges
QPair< LayerBlendingRange, LayerBlendingRange > compositeGrayRange
bool positionedRelativeToLayer
bool invertLayerMaskWhenBlending
QList< psd_path_node > nodes
QList< psd_path_sub_path > subPaths