Krita Source Code Documentation
Loading...
Searching...
No Matches
Private Namespace Reference

Classes

class  CurveObjectCatcher
 
struct  matrix
 
struct  rotate
 
struct  scale
 
struct  skewX
 
struct  skewY
 
struct  transform_unit
 
struct  translate
 

Functions

void appendDoubleXMLNode (const QString &key, const QString &value, QDomElement *parent, QDomDocument *doc)
 
void appendIntegerXMLNode (const QString &key, const QString &value, QDomElement *parent, QDomDocument *doc)
 
void appendPointXMLNode (const QString &key, const QPointF &pt, QDomElement *parent, QDomDocument *doc)
 
void appendTextXMLNode (const QString &key, const QString &value, QDomElement *parent, QDomDocument *doc)
 
QDomElement appendXMLNodeCommon (const QString &key, const QString &value, const QString &type, QDomElement *parent, QDomDocument *doc)
 
QDomElement appendXMLNodeCommonNoValue (const QString &key, const QString &type, QDomElement *parent, QDomDocument *doc)
 
QString buildPath (const QString &parent, const QString &key)
 
qreal calculateMaxWeight (const QPainterPath &selectionPath, qreal exponent, bool searchForMax)
 
int calculateNumStyles (const QDomElement &root)
 
QPointF centerFromPath (const QPainterPath &selectionPath)
 
bool findBestStartingPoint (int numSamples, const QPainterPath &path, qreal exponent, bool searchForMax, qreal initialExtremumValue, QPointF *result)
 
qreal getDisnormedGradientValue (const QPointF &pt, const QPainterPath &selectionPath, qreal exponent)
 
qreal initialExtremumValue (bool searchForMax)
 
KoColor parseColorObject (QDomElement parent, QString classID)
 
void parseColorStopsList (QDomElement parent, QVector< qreal > &startLocations, QVector< qreal > &middleOffsets, QVector< KoColor > &colors, QVector< KoGradientSegmentEndpointType > &types)
 
void parseElement (const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void parseElement (const QDomElement &el, QIODevice &device, bool forceTypeInfo=false)
 
void parseTransparencyStopsList (QDomElement parent, QVector< qreal > &startLocations, QVector< qreal > &middleOffsets, QVector< qreal > &transparencies)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
QString readBoolAsString (QIODevice &device)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void readChildObject (QIODevice &device, QDomElement *parent, QDomDocument *doc, bool skipKey=false)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void readDescriptor (QIODevice &device, const QString &key, QDomElement *parent, QDomDocument *doc)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
QString readDoubleAsString (QIODevice &device)
 
QDomDocument readFileImpl (QIODevice &device)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
QString readIntAsString (QIODevice &device)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
qint64 readPattern (QIODevice &device, QDomElement *parent, QDomDocument *doc)
 
template<psd_byte_order byteOrder>
QImage readVirtualArrayList (QIODevice &device, int numPlanes, const QVector< QRgb > &palette)
 
bool tryParseDescriptor (const QDomElement &el, const QString &path, const QString &classId, KisAslObjectCatcher &catcher)
 
void writeFileImpl (QIODevice &device, const QDomDocument &doc)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void writeFillLayerSectionImpl (QIODevice &device, const QDomDocument &doc)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void writePsdLfx2SectionImpl (QIODevice &device, const QDomDocument &doc)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void writeTypeToolSectionImpl (QIODevice &device, const QDomDocument &doc, const QDomDocument &warpDoc, const QTransform tf, const QRectF bounds)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void writeVectorOriginationDataImpl (QIODevice &device, const QDomDocument &doc)
 
template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void writeVectorStrokeDataImpl (QIODevice &device, const QDomDocument &doc)
 

Function Documentation

◆ appendDoubleXMLNode()

void Private::appendDoubleXMLNode ( const QString & key,
const QString & value,
QDomElement * parent,
QDomDocument * doc )

Definition at line 98 of file kis_asl_reader.cpp.

99{
100 appendXMLNodeCommon(key, value, "Double", parent, doc);
101}
float value(const T *src, size_t ch)
QDomElement appendXMLNodeCommon(const QString &key, const QString &value, const QString &type, QDomElement *parent, QDomDocument *doc)

References appendXMLNodeCommon(), and value().

◆ appendIntegerXMLNode()

void Private::appendIntegerXMLNode ( const QString & key,
const QString & value,
QDomElement * parent,
QDomDocument * doc )

Definition at line 93 of file kis_asl_reader.cpp.

94{
95 appendXMLNodeCommon(key, value, "Integer", parent, doc);
96}

References appendXMLNodeCommon(), and value().

◆ appendPointXMLNode()

void Private::appendPointXMLNode ( const QString & key,
const QPointF & pt,
QDomElement * parent,
QDomDocument * doc )

Definition at line 108 of file kis_asl_reader.cpp.

109{
110 QDomElement el = appendXMLNodeCommonNoValue(key, "Descriptor", parent, doc);
111 el.setAttribute("classId", "CrPt");
112 el.setAttribute("name", "");
113
114 appendDoubleXMLNode("Hrzn", KisDomUtils::toString(pt.x()), &el, doc);
115 appendDoubleXMLNode("Vrtc", KisDomUtils::toString(pt.x()), &el, doc);
116}
QString toString(const QString &value)
void appendDoubleXMLNode(const QString &key, const QString &value, QDomElement *parent, QDomDocument *doc)
QDomElement appendXMLNodeCommonNoValue(const QString &key, const QString &type, QDomElement *parent, QDomDocument *doc)

References appendDoubleXMLNode(), appendXMLNodeCommonNoValue(), and KisDomUtils::toString().

◆ appendTextXMLNode()

void Private::appendTextXMLNode ( const QString & key,
const QString & value,
QDomElement * parent,
QDomDocument * doc )

Definition at line 103 of file kis_asl_reader.cpp.

104{
105 appendXMLNodeCommon(key, value, "Text", parent, doc);
106}

References appendXMLNodeCommon(), and value().

◆ appendXMLNodeCommon()

QDomElement Private::appendXMLNodeCommon ( const QString & key,
const QString & value,
const QString & type,
QDomElement * parent,
QDomDocument * doc )

XML generation functions

Add a node and fill the corresponding attributes

Definition at line 68 of file kis_asl_reader.cpp.

69{
70 QDomElement el = doc->createElement("node");
71 if (!key.isEmpty()) {
72 el.setAttribute("key", key);
73 }
74 el.setAttribute("type", type);
75 el.setAttribute("value", value);
76 parent->appendChild(el);
77
78 return el;
79}

References value().

◆ appendXMLNodeCommonNoValue()

QDomElement Private::appendXMLNodeCommonNoValue ( const QString & key,
const QString & type,
QDomElement * parent,
QDomDocument * doc )

Definition at line 81 of file kis_asl_reader.cpp.

82{
83 QDomElement el = doc->createElement("node");
84 if (!key.isEmpty()) {
85 el.setAttribute("key", key);
86 }
87 el.setAttribute("type", type);
88 parent->appendChild(el);
89
90 return el;
91}

◆ buildPath()

QString Private::buildPath ( const QString & parent,
const QString & key )
inline

Definition at line 312 of file kis_asl_xml_parser.cpp.

313{
314 return parent + "/" + key;
315}

◆ calculateMaxWeight()

qreal Private::calculateMaxWeight ( const QPainterPath & selectionPath,
qreal exponent,
bool searchForMax )

Definition at line 305 of file kis_polygonal_gradient_shape_strategy.cpp.

308 {
309 QPointF center = centerFromPath(selectionPath);
310 return searchForMax ?
311 getDisnormedGradientValue(center, selectionPath, exponent) : 0.0;
312 }
qreal getDisnormedGradientValue(const QPointF &pt, const QPainterPath &selectionPath, qreal exponent)
QPointF centerFromPath(const QPainterPath &selectionPath)

References centerFromPath(), and getDisnormedGradientValue().

◆ calculateNumStyles()

int Private::calculateNumStyles ( const QDomElement & root)

Definition at line 139 of file kis_asl_writer.cpp.

140{
141 int numStyles = 0;
142 QDomNode child = root.firstChild();
143
144 while (!child.isNull()) {
145 QDomElement el = child.toElement();
146 QString classId = el.attribute("classId", "");
147
148 if (classId == "null") {
149 numStyles++;
150 }
151
152 child = child.nextSibling();
153 }
154
155 return numStyles;
156}

◆ centerFromPath()

QPointF Private::centerFromPath ( const QPainterPath & selectionPath)

Definition at line 31 of file kis_polygonal_gradient_shape_strategy.cpp.

31 {
32 QPointF center;
33 int numPoints = 0;
34
35 for (int i = 0; i < selectionPath.elementCount(); i++) {
36 QPainterPath::Element element = selectionPath.elementAt(i);
37 if (element.type == QPainterPath::CurveToDataElement) continue;
38
39 center += element;
40 numPoints++;
41 }
42 if (numPoints == 0) { // can only happen if the path is empty
43 return center;
44 }
45 center /= numPoints;
46
47 return center;
48 }

◆ findBestStartingPoint()

bool Private::findBestStartingPoint ( int numSamples,
const QPainterPath & path,
qreal exponent,
bool searchForMax,
qreal initialExtremumValue,
QPointF * result )

Definition at line 108 of file kis_polygonal_gradient_shape_strategy.cpp.

111 {
112
113 const qreal minStepThreshold = 0.3;
114 const int numCandidatesThreshold = 4;
115
116 KIS_ASSERT_RECOVER(numSamples >= 4) {
117 *result = centerFromPath(path);
118 return true;
119 }
120
121 int totalSamples = numSamples;
122 int effectiveSamples = numSamples & 0x1 ?
123 (numSamples - 1) / 2 + 1 : numSamples;
124
125 QRectF rect = path.boundingRect();
126
127 qreal xOffset = rect.width() / (totalSamples + 1);
128 qreal xStep = effectiveSamples == totalSamples ? xOffset : 2 * xOffset;
129
130 qreal yOffset = rect.height() / (totalSamples + 1);
131 qreal yStep = effectiveSamples == totalSamples ? yOffset : 2 * yOffset;
132
133 if (xStep < minStepThreshold || yStep < minStepThreshold) {
134 return false;
135 }
136
137 int numFound = 0;
138 int numCandidates = 0;
139 QPointF extremumPoint;
140 qreal extremumValue = initialExtremumValue;
141
142 const qreal eps = 1e-3;
143 int sanityNumRows = 0;
144 for (qreal y = rect.y() + yOffset; y < rect.bottom() - eps; y += yStep) {
145 int sanityNumColumns = 0;
146
147 sanityNumRows++;
148 for (qreal x = rect.x() + xOffset; x < rect.right() - eps; x += xStep) {
149 sanityNumColumns++;
150
151 const QPointF pt(x, y);
152 if (!path.contains(pt)) continue;
153
154 qreal value = getDisnormedGradientValue(pt, path, exponent);
155 bool isExtremum = searchForMax ? value > extremumValue : value < extremumValue;
156
157 numCandidates++;
158
159 if (isExtremum) {
160 numFound++;
161 extremumPoint = pt;
162 extremumValue = value;
163 }
164 }
165
166 KIS_ASSERT_RECOVER_NOOP(sanityNumColumns == effectiveSamples);
167 }
168 KIS_ASSERT_RECOVER_NOOP(sanityNumRows == effectiveSamples);
169
170 bool success = numFound && numCandidates >= numCandidatesThreshold;
171
172 if (success) {
173 *result = extremumPoint;
174 } else {
175 int newNumSamples = 2 * numSamples + 1;
176 success = findBestStartingPoint(newNumSamples, path,
177 exponent, searchForMax,
178 extremumValue,
179 result);
180
181 if (!success && numFound > 0) {
182 *result = extremumPoint;
183 success = true;
184 }
185 }
186
187 return success;
188 }
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
const qreal eps
bool findBestStartingPoint(int numSamples, const QPainterPath &path, qreal exponent, bool searchForMax, qreal initialExtremumValue, QPointF *result)
qreal initialExtremumValue(bool searchForMax)

References centerFromPath(), eps, findBestStartingPoint(), getDisnormedGradientValue(), initialExtremumValue(), KIS_ASSERT_RECOVER, KIS_ASSERT_RECOVER_NOOP, and value().

◆ getDisnormedGradientValue()

qreal Private::getDisnormedGradientValue ( const QPointF & pt,
const QPainterPath & selectionPath,
qreal exponent )

Definition at line 50 of file kis_polygonal_gradient_shape_strategy.cpp.

51 {
52 // FIXME: exponent = 2.0
53 // We explicitly use pow2() and sqrt() functions here
54 // for efficiency reasons.
56 const qreal minHiLevel = std::pow(0.5, 1.0 / exponent);
57 qreal ptWeightNode = 0.0;
58
59 for (int i = 0; i < selectionPath.elementCount(); i++) {
60 if (selectionPath.elementAt(i).isMoveTo()) continue;
61
62 const int prevI = i > 0 ? i - 1 : selectionPath.elementCount() - 1;
63 const QPointF edgeP1 = selectionPath.elementAt(prevI);
64 const QPointF edgeP2 = selectionPath.elementAt(i);
65
66 const QPointF edgeVec = edgeP1 - edgeP2;
67 const QPointF q1 = pt - edgeP1;
68 const QPointF q2 = pt - edgeP2;
69
70 const qreal proj1 = KisAlgebra2D::dotProduct(edgeVec, q1);
71 const qreal proj2 = KisAlgebra2D::dotProduct(edgeVec, q2);
72
73 qreal hi = 1.0;
74
75 // pt's projection lays outside the edge itself,
76 // when the projections has the same sign
77
78 if (proj1 * proj2 >= 0) {
79 QPointF nearestPointVec =
80 qAbs(proj1) < qAbs(proj2) ? q1 : q2;
81
82 hi = KisAlgebra2D::norm(nearestPointVec);
83 } else {
84 QLineF line(edgeP1, edgeP2);
85 hi = kisDistanceToLine(pt, line);
86 }
87
88 hi = qMax(minHiLevel, hi);
89
90 // disabled for efficiency reasons
91 // ptWeightNode += 1.0 / std::pow(hi, exponent);
92
93 ptWeightNode += 1.0 / pow2(hi);
94 }
95
96 // disabled for efficiency reasons
97 // return 1.0 / std::pow(ptWeightNode, 1.0 / exponent);
98
99 return 1.0 / std::sqrt(ptWeightNode);
100 }
QPointF q1
QPointF q2
static bool qFuzzyCompare(half p1, half p2)
T pow2(const T &x)
Definition kis_global.h:166
qreal kisDistanceToLine(const QPointF &m, const QLineF &line)
Definition kis_global.h:234
qreal norm(const T &a)
PointTypeTraits< T >::value_type dotProduct(const T &a, const T &b)

References KisAlgebra2D::dotProduct(), KIS_ASSERT_RECOVER_NOOP, kisDistanceToLine(), KisAlgebra2D::norm(), pow2(), q1, q2, and qFuzzyCompare().

◆ initialExtremumValue()

qreal Private::initialExtremumValue ( bool searchForMax)

Definition at line 102 of file kis_polygonal_gradient_shape_strategy.cpp.

102 {
103 return searchForMax ?
104 std::numeric_limits<qreal>::min() :
105 std::numeric_limits<qreal>::max();
106 }

◆ parseColorObject()

KoColor Private::parseColorObject ( QDomElement parent,
QString classID )

Definition at line 62 of file kis_asl_xml_parser.cpp.

63{
64 KoColor color;
65 KoColor error = KoColor::fromXML("<color channeldepth='U8'><sRGB r='1.0' g='0.0' b='0.0'/></color>");
66 QDomDocument doc;
67 QDomElement root;
68 QString spotBook;
69 QString spotName;
70 int spotValue = 0;
71 double h = 0;
72 double s = 0;
73 double v= 0;
74
75 if (classID == "RGBC" || classID == "HSBC") {
76 color = KoColor(KoColorSpaceRegistry::instance()->rgb8());
77 root = doc.createElement("sRGB");
78 } else if (classID == "CMYC") {
79 root = doc.createElement("CMYK");
80 } else if (classID == "LbCl") {
81 root = doc.createElement("Lab");
82 } else if (classID == "Grsc") {
83 root = doc.createElement("Gray");
84 } else {
85 // Can be 'UnsC', or something else.
86 warnKrita << "Unknown color type:" << ppVar(classID);
87 return error;
88 }
89
90 QDomNode child = parent.firstChild();
91 while (!child.isNull()) {
92 QDomElement childEl = child.toElement();
93
94 QString type = childEl.attribute("type", "<unknown>");
95 QString key = childEl.attribute("key", "");
96
97 if (type == "Double" || type == "UnitFloat") {
98 if (classID == "RGBC") {
99 // For RGBC we'll just directly write to the KoColor data, to have as
100 // few rounding errors possible.
101 double value = KisDomUtils::toDouble(childEl.attribute("value", "0"));
102
103 if (key == "Rd ") {
104 color.data()[2] = value;
105 } else if (key == "Grn ") {
106 color.data()[1] = value;
107 } else if (key == "Bl ") {
108 color.data()[0] = value;
109 } else {
110 warnKrita << "Unknown color key value double:" << ppVar(key);
111 return error;
112 }
113 } else if (classID == "CMYC") {
114 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")) * 0.01;
115 // CMYK is stored in percentages...
116 if (key == "Cyn ") {
117 root.setAttribute("c", value);
118 } else if (key == "Mgnt") {
119 root.setAttribute("m", value);
120 } else if (key == "Ylw ") {
121 root.setAttribute("y", value);
122 } else if (key == "Blck") {
123 root.setAttribute("k", value);
124 } else {
125 warnKrita << "Unknown color key value double:" << ppVar(key);
126 return error;
127 }
128 } else if (classID == "LbCl") {
129 if (key == "Lmnc") {
130 root.setAttribute("L", childEl.attribute("value", "0"));
131 } else if (key == "A ") {
132 root.setAttribute("a", childEl.attribute("value", "0"));
133 } else if (key == "B ") {
134 root.setAttribute("b", childEl.attribute("value", "0"));
135 } else {
136 warnKrita << "Unknown color key value:" << ppVar(key);
137 return error;
138 }
139 } else if (classID == "Grsc") {
140 // Unsure that grey is stored as a percentage, might also be 255.
141 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")) * 0.01;
142 if (key == "Gry ") {
143 root.setAttribute("g", value);
144 } else {
145 warnKrita << "Unknown color key value:" << ppVar(key);
146 return error;
147 }
148 } else if (classID == "HSBC") {
149 double value = KisDomUtils::toDouble(childEl.attribute("value", "0"));
150 if (key == "H ") {
151 h = value;
152 } else if (key == "Strt") {
153 s = value * 0.01;
154 } else if (key == "Brgh") {
155 v = value * 0.01;
156 } else {
157 warnKrita << "Unknown color key value:" << ppVar(key);
158 return error;
159 }
160 }
161 } else if (type == "Text") {
162 if (key== "Bk ") {
163 spotBook = childEl.attribute("value", "");
164 } else if (key== "Nm ") {
165 spotName = childEl.attribute("value", "");
166 } else {
167 warnKrita << "Unknown color key value string:" << ppVar(key);
168 }
169 } else if (type == "Integer") {
170 if (key== "bookID") {
171 spotValue = KisDomUtils::toInt(childEl.attribute("value", "0"));
172 } else {
173 warnKrita << "Unknown color key value integer:" << ppVar(key);
174 }
175 } else {
176 qDebug() << "Unknown color component type:" << ppVar(type) << ppVar(key);
177 return error;
178 }
179
180 child = child.nextSibling();
181 }
182 if (classID == "HSBC") {
183 float r = 0.0;
184 float b = 0.0;
185 float g = 0.0;
186 HSVToRGB(h, s, v, &r, &g, &b);
187 root.setAttribute("r", r);
188 root.setAttribute("g", g);
189 root.setAttribute("b", b);
190 }
191 if (classID != "RGBC") {
192 color = KoColor::fromXML(root, "U8");
193 }
195 if (!spotName.isEmpty()) {
196 color.addMetadata("spotName", spotName);
197 color.addMetadata("psdSpotBook", spotBook);
198 color.addMetadata("psdSpotBookId", spotValue);
199 }
200
201 return color;
202}
qreal v
void HSVToRGB(float h, float s, float v, float *r, float *g, float *b)
const quint8 OPACITY_OPAQUE_U8
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
void addMetadata(QString key, QVariant value)
Definition KoColor.cpp:666
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
quint8 * data()
Definition KoColor.h:144
#define warnKrita
Definition kis_debug.h:87
#define ppVar(var)
Definition kis_debug.h:155
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
static KoColorSpaceRegistry * instance()

References KoColor::addMetadata(), KoColor::data(), KoColor::fromXML(), HSVToRGB(), KoColorSpaceRegistry::instance(), OPACITY_OPAQUE_U8, ppVar, KoColor::setOpacity(), KisDomUtils::toDouble(), KisDomUtils::toInt(), v, value(), and warnKrita.

◆ parseColorStopsList()

void Private::parseColorStopsList ( QDomElement parent,
QVector< qreal > & startLocations,
QVector< qreal > & middleOffsets,
QVector< KoColor > & colors,
QVector< KoGradientSegmentEndpointType > & types )

Definition at line 204 of file kis_asl_xml_parser.cpp.

209{
210 QDomNode child = parent.firstChild();
211 while (!child.isNull()) {
212 QDomElement childEl = child.toElement();
213
214 QString type = childEl.attribute("type", "<unknown>");
215 QString key = childEl.attribute("key", "");
216 QString classId = childEl.attribute("classId", "");
217
218 if (type == "Descriptor" && classId == "Clrt") {
219 // sorry for naming...
220 QDomNode child = childEl.firstChild();
221 while (!child.isNull()) {
222 QDomElement childEl = child.toElement();
223
224 QString type = childEl.attribute("type", "<unknown>");
225 QString key = childEl.attribute("key", "");
226 QString classId = childEl.attribute("classId", "");
227
228 if (type == "Integer" && key == "Lctn") {
229 int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
230 startLocations.append(qreal(value) / 4096.0);
231
232 } else if (type == "Integer" && key == "Mdpn") {
233 int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
234 middleOffsets.append(qreal(value) / 100.0);
235
236 } else if (type == "Descriptor" && key == "Clr ") {
237 colors.append(parseColorObject(childEl, classId));
238
239 } else if (type == "Enum" && key == "Type") {
240 QString typeId = childEl.attribute("typeId", "");
241
242 if (typeId != "Clry") {
243 warnKrita << "WARNING: Invalid typeId of a gradient stop type" << typeId;
244 }
245
246 QString value = childEl.attribute("value", "");
247 if (value == "BckC") {
248 types.append(BACKGROUND_ENDPOINT);
249 } else if (value == "FrgC") {
250 types.append(FOREGROUND_ENDPOINT);
251 } else {
252 types.append(COLOR_ENDPOINT);
253 }
254 }
255
256 child = child.nextSibling();
257 }
258 } else {
259 warnKrita << "WARNING: Unrecognized object in color stops list" << ppVar(type) << ppVar(key) << ppVar(classId);
260 }
261
262 child = child.nextSibling();
263 }
264}
@ COLOR_ENDPOINT
@ FOREGROUND_ENDPOINT
@ BACKGROUND_ENDPOINT
KoColor parseColorObject(QDomElement parent, QString classID)

References BACKGROUND_ENDPOINT, COLOR_ENDPOINT, FOREGROUND_ENDPOINT, parseColorObject(), ppVar, KisDomUtils::toInt(), value(), and warnKrita.

◆ parseElement() [1/2]

void Private::parseElement ( const QDomElement & el,
const QString & parentPath,
KisAslObjectCatcher & catcher )

Definition at line 713 of file kis_asl_xml_parser.cpp.

714{
715 KIS_ASSERT_RECOVER_RETURN(el.tagName() == "node");
716
717 QString type = el.attribute("type", "<unknown>");
718 QString key = el.attribute("key", "");
719
720 if (type == "Descriptor") {
721 QString classId = el.attribute("classId", "<noClassId>");
722 QString containerName = key.isEmpty() ? classId : key;
723 QString containerPath = buildPath(parentPath, containerName);
724
725 if (!tryParseDescriptor(el, containerPath, classId, catcher)) {
726 QDomNode child = el.firstChild();
727 while (!child.isNull()) {
728 parseElement(child.toElement(), containerPath, catcher);
729 child = child.nextSibling();
730 }
731 }
732 } else if (type == "List") {
733 catcher.setArrayMode(true);
734
735 QString containerName = key;
736 QString containerPath = buildPath(parentPath, containerName);
737
738 QDomNode child = el.firstChild();
739 while (!child.isNull()) {
740 parseElement(child.toElement(), containerPath, catcher);
741 child = child.nextSibling();
742 }
743
744 catcher.setArrayMode(false);
745 } else if (type == "Double") {
746 double v = KisDomUtils::toDouble(el.attribute("value", "0"));
747 catcher.addDouble(buildPath(parentPath, key), v);
748 } else if (type == "UnitFloat") {
749 QString unit = el.attribute("unit", "<unknown>");
750 double v = KisDomUtils::toDouble(el.attribute("value", "0"));
751 catcher.addUnitFloat(buildPath(parentPath, key), unit, v);
752 } else if (type == "Text") {
753 QString v = el.attribute("value", "");
754 catcher.addText(buildPath(parentPath, key), v);
755 } else if (type == "Enum") {
756 QString v = el.attribute("value", "");
757 QString typeId = el.attribute("typeId", "<unknown>");
758 catcher.addEnum(buildPath(parentPath, key), typeId, v);
759 } else if (type == "Integer") {
760 int v = KisDomUtils::toInt(el.attribute("value", "0"));
761 catcher.addInteger(buildPath(parentPath, key), v);
762 } else if (type == "Boolean") {
763 int v = KisDomUtils::toInt(el.attribute("value", "0"));
764 catcher.addBoolean(buildPath(parentPath, key), v);
765 } else if (type == "RawData") {
766 QDomNode dataNode = el.firstChild();
767
768 if (!dataNode.isCDATASection()) {
769 warnKrita << "WARNING: failed to parse RawData XML section!";
770 return;
771 }
772
773 QDomCDATASection dataSection = dataNode.toCDATASection();
774 QByteArray data = dataSection.data().toLatin1();
775 data = QByteArray::fromBase64(data);
776
777 if (data.isEmpty()) {
778 warnKrita << "WARNING: failed to parse RawData XML section!";
779 }
780 catcher.addRawData(buildPath(parentPath, key), data);
781 } else {
782 warnKrita << "WARNING: XML (ASL) Unknown element type:" << type << ppVar(parentPath) << ppVar(key);
783 }
784}
virtual void addUnitFloat(const QString &path, const QString &unit, double value)
virtual void addEnum(const QString &path, const QString &typeId, const QString &value)
virtual void addBoolean(const QString &path, bool value)
virtual void addInteger(const QString &path, int value)
virtual void addDouble(const QString &path, double value)
virtual void addText(const QString &path, const QString &value)
virtual void addRawData(const QString &path, QByteArray ba)
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
QString buildPath(const QString &parent, const QString &key)
void parseElement(const QDomElement &el, QIODevice &device, bool forceTypeInfo=false)
bool tryParseDescriptor(const QDomElement &el, const QString &path, const QString &classId, KisAslObjectCatcher &catcher)

References KisAslObjectCatcher::addBoolean(), KisAslObjectCatcher::addDouble(), KisAslObjectCatcher::addEnum(), KisAslObjectCatcher::addInteger(), KisAslObjectCatcher::addRawData(), KisAslObjectCatcher::addText(), KisAslObjectCatcher::addUnitFloat(), buildPath(), KIS_ASSERT_RECOVER_RETURN, parseElement(), ppVar, KisAslObjectCatcher::setArrayMode(), KisDomUtils::toDouble(), KisDomUtils::toInt(), tryParseDescriptor(), v, and warnKrita.

◆ parseElement() [2/2]

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::parseElement ( const QDomElement & el,
QIODevice & device,
bool forceTypeInfo = false )

Definition at line 27 of file kis_asl_writer.cpp.

28{
29 KIS_ASSERT_RECOVER_RETURN(el.tagName() == "node");
30
31 QString type = el.attribute("type", "<unknown>");
32 QString key = el.attribute("key", "");
33
34 // should be filtered on a higher level
36
37 if (type == "Descriptor") {
38 if (!key.isEmpty()) {
39 writeVarString<byteOrder>(key, device);
40 }
41
42 if (!key.isEmpty() || forceTypeInfo) {
43 writeFixedString<byteOrder>("Objc", device);
44 }
45
46 QString classId = el.attribute("classId", "");
47 QString name = el.attribute("name", "");
48
49 writeUnicodeString<byteOrder>(name, device);
50 writeVarString<byteOrder>(classId, device);
51
52 quint32 numChildren = static_cast<quint32>(el.childNodes().size());
53 SAFE_WRITE_EX(byteOrder, device, numChildren);
54
55 QDomNode child = el.firstChild();
56 while (!child.isNull()) {
57 parseElement<byteOrder>(child.toElement(), device);
58 child = child.nextSibling();
59 }
60
61 } else if (type == "List") {
62 writeVarString<byteOrder>(key, device);
63 writeFixedString<byteOrder>("VlLs", device);
64
65 quint32 numChildren = static_cast<quint32>(el.childNodes().size());
66 SAFE_WRITE_EX(byteOrder, device, numChildren);
67
68 QDomNode child = el.firstChild();
69 while (!child.isNull()) {
70 parseElement<byteOrder>(child.toElement(), device, true);
71 child = child.nextSibling();
72 }
73 } else if (type == "Double") {
74 double v = KisDomUtils::toDouble(el.attribute("value", "0"));
75
76 writeVarString<byteOrder>(key, device);
77 writeFixedString<byteOrder>("doub", device);
78 SAFE_WRITE_EX(byteOrder, device, v);
79
80 } else if (type == "UnitFloat") {
81 double v = KisDomUtils::toDouble(el.attribute("value", "0"));
82 QString unit = el.attribute("unit", "#Pxl");
83
84 if (!key.isEmpty()) {
85 writeVarString<byteOrder>(key, device);
86 }
87 writeFixedString<byteOrder>("UntF", device);
88 writeFixedString<byteOrder>(unit, device);
89 SAFE_WRITE_EX(byteOrder, device, v);
90 } else if (type == "Text") {
91 QString v = el.attribute("value", "");
92 writeVarString<byteOrder>(key, device);
93 writeFixedString<byteOrder>("TEXT", device);
94 writeUnicodeString<byteOrder>(v, device);
95 } else if (type == "Enum") {
96 QString v = el.attribute("value", "");
97 QString typeId = el.attribute("typeId", "DEAD");
98 writeVarString<byteOrder>(key, device);
99 writeFixedString<byteOrder>("enum", device);
100 writeVarString<byteOrder>(typeId, device);
101 writeVarString<byteOrder>(v, device);
102 } else if (type == "Integer") {
103 quint32 v = static_cast<quint32>(KisDomUtils::toInt(el.attribute("value", "0")));
104 writeVarString<byteOrder>(key, device);
105 writeFixedString<byteOrder>("long", device);
106 SAFE_WRITE_EX(byteOrder, device, v);
107 } else if (type == "Boolean") {
108 quint8 v = static_cast<quint8>(KisDomUtils::toInt(el.attribute("value", "0")));
109
110 writeVarString<byteOrder>(key, device);
111 writeFixedString<byteOrder>("bool", device);
112 SAFE_WRITE_EX(byteOrder, device, v);
113 } else if (type == "RawData" && key == "EngineData") {
114 writeVarString<byteOrder>(key, device);
115 writeFixedString<byteOrder>("tdta", device);
116
117 QDomNode dataNode = el.firstChild();
118
119 if (!dataNode.isCDATASection()) {
120 warnKrita << "WARNING: failed to parse RawData XML section!";
121 return;
122 }
123
124 QDomCDATASection dataSection = dataNode.toCDATASection();
125 QByteArray data = dataSection.data().toLatin1();
126 data = QByteArray::fromBase64(data);
127
128 if (data.isEmpty()) {
129 warnKrita << "WARNING: failed to parse RawData XML section!";
130 }
131 quint32 length = data.size();
132 SAFE_WRITE_EX(byteOrder, device, length);
133 device.write(data);
134 } else {
135 warnKrita << "WARNING: XML (ASL) Unknown element type:" << type << ppVar(key);
136 }
137}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
#define SAFE_WRITE_EX(byteOrder, device, varname)
const char * name(StandardAction id)
const QString Patterns

References KIS_ASSERT_RECOVER_RETURN, length(), ResourceType::Patterns, ppVar, SAFE_WRITE_EX, KisDomUtils::toDouble(), KisDomUtils::toInt(), v, and warnKrita.

◆ parseTransparencyStopsList()

void Private::parseTransparencyStopsList ( QDomElement parent,
QVector< qreal > & startLocations,
QVector< qreal > & middleOffsets,
QVector< qreal > & transparencies )

Definition at line 266 of file kis_asl_xml_parser.cpp.

267{
268 QDomNode child = parent.firstChild();
269 while (!child.isNull()) {
270 QDomElement childEl = child.toElement();
271
272 QString type = childEl.attribute("type", "<unknown>");
273 QString key = childEl.attribute("key", "");
274 QString classId = childEl.attribute("classId", "");
275
276 if (type == "Descriptor" && classId == "TrnS") {
277 // sorry for naming again...
278 QDomNode child = childEl.firstChild();
279 while (!child.isNull()) {
280 QDomElement childEl = child.toElement();
281
282 QString type = childEl.attribute("type", "<unknown>");
283 QString key = childEl.attribute("key", "");
284
285 if (type == "Integer" && key == "Lctn") {
286 int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
287 startLocations.append(qreal(value) / 4096.0);
288 } else if (type == "Integer" && key == "Mdpn") {
289 int value = KisDomUtils::toInt(childEl.attribute("value", "0"));
290 middleOffsets.append(qreal(value) / 100.0);
291 } else if (type == "UnitFloat" && key == "Opct") {
292 QString unit = childEl.attribute("unit", "");
293 if (unit != "#Prc") {
294 warnKrita << "WARNING: Invalid unit of a gradient stop transparency" << unit;
295 }
296
297 qreal value = KisDomUtils::toDouble(childEl.attribute("value", "100"));
298 transparencies.append(value / 100.0);
299 }
300
301 child = child.nextSibling();
302 }
303
304 } else {
305 warnKrita << "WARNING: Unrecognized object in transparency stops list" << ppVar(type) << ppVar(key) << ppVar(classId);
306 }
307
308 child = child.nextSibling();
309 }
310}

References ppVar, KisDomUtils::toDouble(), KisDomUtils::toInt(), value(), and warnKrita.

◆ readBoolAsString()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
QString Private::readBoolAsString ( QIODevice & device)

Definition at line 54 of file kis_asl_reader.cpp.

55{
56 quint8 value = 0.0;
57 SAFE_READ_EX(byteOrder, device, value);
58
60}
#define SAFE_READ_EX(byteOrder, device, varname)

References SAFE_READ_EX, KisDomUtils::toString(), and value().

◆ readChildObject()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::readChildObject ( QIODevice & device,
QDomElement * parent,
QDomDocument * doc,
bool skipKey = false )

Definition at line 126 of file kis_asl_reader.cpp.

127{
128 using namespace KisAslReaderUtils;
129
130 QString key;
131
132 if (!skipKey) {
133 key = readVarString<byteOrder>(device);
134 }
135
136 QString OSType = readFixedString<byteOrder>(device);
137
138 // dbgKrita << "Child" << ppVar(key) << ppVar(OSType);
139
140 if (OSType == "obj ") {
141 throw KisAslReaderUtils::ASLParseException("OSType 'obj' not implemented");
142
143 } else if (OSType == "Objc" || OSType == "GlbO") {
144 readDescriptor<byteOrder>(device, key, parent, doc);
145
146 } else if (OSType == "VlLs") {
147 quint32 numItems = GARBAGE_VALUE_MARK;
148 SAFE_READ_EX(byteOrder, device, numItems);
149
150 QDomElement el = appendXMLNodeCommonNoValue(key, "List", parent, doc);
151 for (quint32 i = 0; i < numItems; i++) {
152 readChildObject<byteOrder>(device, &el, doc, true);
153 }
154
155 } else if (OSType == "doub") {
156 appendDoubleXMLNode(key, readDoubleAsString<byteOrder>(device), parent, doc);
157
158 } else if (OSType == "UntF") {
159 const QString unit = readFixedString<byteOrder>(device);
160 const QString value = readDoubleAsString<byteOrder>(device);
161
162 QDomElement el = appendXMLNodeCommon(key, value, "UnitFloat", parent, doc);
163 el.setAttribute("unit", unit);
164
165 } else if (OSType == "TEXT") {
166 QString unicodeString = readUnicodeString<byteOrder>(device);
167 appendTextXMLNode(key, unicodeString, parent, doc);
168
169 } else if (OSType == "enum") {
170 const QString typeId = readVarString<byteOrder>(device);
171 const QString value = readVarString<byteOrder>(device);
172
173 QDomElement el = appendXMLNodeCommon(key, value, "Enum", parent, doc);
174 el.setAttribute("typeId", typeId);
175
176 } else if (OSType == "long") {
177 appendIntegerXMLNode(key, readIntAsString<byteOrder>(device), parent, doc);
178
179 } else if (OSType == "bool") {
180 const QString value = readBoolAsString<byteOrder>(device);
181 appendXMLNodeCommon(key, value, "Boolean", parent, doc);
182
183 } else if (OSType == "type") {
184 throw KisAslReaderUtils::ASLParseException("OSType 'type' not implemented");
185 } else if (OSType == "GlbC") {
186 throw KisAslReaderUtils::ASLParseException("OSType 'GlbC' not implemented");
187 } else if (OSType == "alis") {
188 throw KisAslReaderUtils::ASLParseException("OSType 'alis' not implemented");
189 } else if (OSType == "tdta") {
190
191 if (key == "EngineData") {
192 // This is PSD text engine data, which outputs
193 // Carousel Object Structure (PDF) data, much like the "Txt2" additional info block.
194 quint32 len = 0.0;
195 SAFE_READ_EX(byteOrder, device, len);
196 QByteArray ba = device.read(len);
197
198 QDomCDATASection dataSection;
199 dataSection = doc->createCDATASection(ba.toBase64());
200 QDomElement dataElement = doc->createElement("node");
201 dataElement.setAttribute("type", "RawData");
202 dataElement.setAttribute("key", key);
203 dataElement.appendChild(dataSection);
204 parent->appendChild(dataElement);
205 } else {
206 throw KisAslReaderUtils::ASLParseException("OSType 'tdta' not implemented");
207 }
208 }
209}
#define GARBAGE_VALUE_MARK
void appendIntegerXMLNode(const QString &key, const QString &value, QDomElement *parent, QDomDocument *doc)
void appendTextXMLNode(const QString &key, const QString &value, QDomElement *parent, QDomDocument *doc)

References appendDoubleXMLNode(), appendIntegerXMLNode(), appendTextXMLNode(), appendXMLNodeCommon(), appendXMLNodeCommonNoValue(), GARBAGE_VALUE_MARK, SAFE_READ_EX, and value().

◆ readDescriptor()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::readDescriptor ( QIODevice & device,
const QString & key,
QDomElement * parent,
QDomDocument * doc )

ASL -> XML parsing functions

Definition at line 214 of file kis_asl_reader.cpp.

215{
216 using namespace KisAslReaderUtils;
217
218 QString name = readUnicodeString(device);
219 QString classId = readVarString(device);
220
221 quint32 numChildren = GARBAGE_VALUE_MARK;
222 SAFE_READ_EX(byteOrder, device, numChildren);
223
224 QDomElement el = appendXMLNodeCommonNoValue(key, "Descriptor", parent, doc);
225 el.setAttribute("classId", classId);
226 el.setAttribute("name", name);
227
228 // dbgKrita << "Descriptor" << ppVar(key) << ppVar(classId) << ppVar(numChildren);
229
230 for (quint32 i = 0; i < numChildren; i++) {
231 readChildObject<byteOrder>(device, &el, doc);
232 }
233}

References appendXMLNodeCommonNoValue(), GARBAGE_VALUE_MARK, and SAFE_READ_EX.

◆ readDoubleAsString()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
QString Private::readDoubleAsString ( QIODevice & device)

Numerical fetch functions

We read numbers and convert them to strings to be able to store them in XML.

Definition at line 36 of file kis_asl_reader.cpp.

37{
38 double value = 0.0;
39 SAFE_READ_EX(byteOrder, device, value);
40
42}

References SAFE_READ_EX, KisDomUtils::toString(), and value().

◆ readFileImpl()

QDomDocument Private::readFileImpl ( QIODevice & device)

Definition at line 608 of file kis_asl_reader.cpp.

609{
610 using namespace KisAslReaderUtils;
611
612 QDomDocument doc;
613 QDomElement root = doc.createElement("asl");
614 doc.appendChild(root);
615
616 {
617 quint16 stylesVersion = GARBAGE_VALUE_MARK;
618 SAFE_READ_SIGNATURE_EX(psd_byte_order::psdBigEndian, device, stylesVersion, 2);
619 }
620
621 {
622 quint32 aslSignature = GARBAGE_VALUE_MARK;
623 const quint32 refSignature = 0x3842534c; // '8BSL' in little-endian
624 SAFE_READ_SIGNATURE_EX(psd_byte_order::psdBigEndian, device, aslSignature, refSignature);
625 }
626
627 {
628 quint16 patternsVersion = GARBAGE_VALUE_MARK;
629 SAFE_READ_SIGNATURE_EX(psd_byte_order::psdBigEndian, device, patternsVersion, 3);
630 }
631
632 // Patterns
633
634 {
635 quint32 patternsSize = GARBAGE_VALUE_MARK;
636 SAFE_READ_EX(psd_byte_order::psdBigEndian, device, patternsSize);
637
638 if (patternsSize > 0) {
639 SETUP_OFFSET_VERIFIER(patternsSectionVerifier, device, patternsSize, 0);
640
641 QDomElement patternsRoot = doc.createElement("node");
642 patternsRoot.setAttribute("type", "List");
643 patternsRoot.setAttribute("key", ResourceType::Patterns);
644 root.appendChild(patternsRoot);
645
646 try {
647 qint64 bytesRead = 0;
648 while (bytesRead < patternsSize) {
649 qint64 chunk = readPattern(device, &patternsRoot, &doc);
650 bytesRead += chunk;
651 }
652 } catch (ASLParseException &e) {
653 warnKrita << "WARNING: ASL (emb. pattern):" << e.what();
654 }
655 }
656 }
657
658 // Styles
659
660 quint32 numStyles = GARBAGE_VALUE_MARK;
661 SAFE_READ_EX(psd_byte_order::psdBigEndian, device, numStyles);
662
663 for (int i = 0; i < (int)numStyles; i++) {
664 quint32 bytesToRead = GARBAGE_VALUE_MARK;
665 SAFE_READ_EX(psd_byte_order::psdBigEndian, device, bytesToRead);
666
667 SETUP_OFFSET_VERIFIER(singleStyleSectionVerifier, device, bytesToRead, 0);
668
669 {
670 quint32 stylesFormatVersion = GARBAGE_VALUE_MARK;
671 SAFE_READ_SIGNATURE_EX(psd_byte_order::psdBigEndian, device, stylesFormatVersion, 16);
672 }
673
674 readDescriptor(device, "", &root, &doc);
675
676 {
677 quint32 stylesFormatVersion = GARBAGE_VALUE_MARK;
678 SAFE_READ_SIGNATURE_EX(psd_byte_order::psdBigEndian, device, stylesFormatVersion, 16);
679 }
680
681 readDescriptor(device, "", &root, &doc);
682 }
683
684 return doc;
685}
#define SAFE_READ_SIGNATURE_EX(byteOrder, device, varname, expected)
#define SETUP_OFFSET_VERIFIER(name, device, expectedOffset, maxPadding)
void readDescriptor(QIODevice &device, const QString &key, QDomElement *parent, QDomDocument *doc)
qint64 readPattern(QIODevice &device, QDomElement *parent, QDomDocument *doc)

References GARBAGE_VALUE_MARK, ResourceType::Patterns, psdBigEndian, readDescriptor(), readPattern(), SAFE_READ_EX, SAFE_READ_SIGNATURE_EX, SETUP_OFFSET_VERIFIER, and warnKrita.

◆ readIntAsString()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
QString Private::readIntAsString ( QIODevice & device)

Definition at line 45 of file kis_asl_reader.cpp.

46{
47 quint32 value = 0.0;
48 SAFE_READ_EX(byteOrder, device, value);
49
51}

References SAFE_READ_EX, KisDomUtils::toString(), and value().

◆ readPattern()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
qint64 Private::readPattern ( QIODevice & device,
QDomElement * parent,
QDomDocument * doc )

Create XML data

We are loading the pattern and convert it into ARGB right away, so we need not store real image mode and size of the pattern externally.

Definition at line 463 of file kis_asl_reader.cpp.

464{
465 using namespace KisAslReaderUtils;
466
467 quint32 patternSize = GARBAGE_VALUE_MARK;
468 SAFE_READ_EX(byteOrder, device, patternSize);
469
470 // patterns are always aligned by 4 bytes
471 patternSize = KisAslWriterUtils::alignOffsetCeil(patternSize, 4);
472
473 SETUP_OFFSET_VERIFIER(patternEndVerifier, device, patternSize, 0);
474
475 quint32 patternVersion = GARBAGE_VALUE_MARK;
476 SAFE_READ_EX(byteOrder, device, patternVersion);
477
478 if (patternVersion != 1) {
479 throw ASLParseException("Pattern version is not \'1\'");
480 }
481
482 quint32 patternImageMode = GARBAGE_VALUE_MARK;
483 SAFE_READ_EX(byteOrder, device, patternImageMode);
484
485 dbgFile << "Pattern format:" << patternImageMode << "(" << device.pos() << ")";
486
487 quint16 patternHeight = GARBAGE_VALUE_MARK;
488 SAFE_READ_EX(byteOrder, device, patternHeight);
489
490 dbgFile << "Pattern height:" << patternHeight << "(" << device.pos() << ")";
491
492 quint16 patternWidth = GARBAGE_VALUE_MARK;
493 SAFE_READ_EX(byteOrder, device, patternWidth);
494
495 dbgFile << "Pattern width:" << patternHeight << "(" << device.pos() << ")";
496
497 QString patternName;
498 psdread_unicodestring<byteOrder>(device, patternName);
499
500 dbgFile << "Pattern name:" << patternName << "(" << device.pos() << ")";
501
502 QString patternUuid = readPascalString<byteOrder>(device);
503
504 dbgFile << "Pattern UUID:" << patternUuid << "(" << device.pos() << ")";
505
506 // dbgKrita << "--";
507 // dbgKrita << ppVar(patternSize);
508 // dbgKrita << ppVar(patternImageMode);
509 // dbgKrita << ppVar(patternHeight);
510 // dbgKrita << ppVar(patternWidth);
511 // dbgKrita << ppVar(patternName);
512 // dbgKrita << ppVar(patternUuid);
513
514 int numPlanes = 0;
515 psd_color_mode mode = static_cast<psd_color_mode>(patternImageMode);
516
517 switch (mode) {
518 case MultiChannel:
519 case Grayscale:
520 case Indexed:
521 numPlanes = 1;
522 break;
523 case RGB:
524 numPlanes = 3;
525 break;
526 default: {
527 QString msg = QString("Unsupported image mode: %1!").arg(mode);
528 throw ASLParseException(msg);
529 }
530 }
531
533
534 if (mode == Indexed) {
535
536 palette.resize(256);
537
538 for(auto i = 0; i < 256; i++) {
539 quint8 r = 0;
540 quint8 g = 0;
541 quint8 b = 0;
542 psdread<byteOrder>(device, r);
543 psdread<byteOrder>(device, g);
544 psdread<byteOrder>(device, b);
545 palette[i] = qRgb(r, g, b);
546 }
547
548 dbgFile << "Palette: " << palette << "(" << device.pos() << ")";
549
550 // XXX: there's no way to detect this. Assume the 772 length
551 quint16 validColours = GARBAGE_VALUE_MARK;
552 psdread<byteOrder>(device, validColours);
553 palette.resize(validColours);
554 dbgFile << "Palette real size:" << validColours << "(" << device.pos() << ")";
555
556 // Set transparent colour
557 quint16 transparentIdx = GARBAGE_VALUE_MARK;
558 psdread<byteOrder>(device, transparentIdx);
559 dbgFile << "Transparent index:" << transparentIdx << "(" << device.pos() << ")";
560
561 palette[transparentIdx] = qRgba(qRed(palette[transparentIdx]),
562 qGreen(palette[transparentIdx]),
563 qBlue(palette[transparentIdx]), 0x00);
564 }
565
570 QDomElement pat = doc->createElement("node");
571
572 pat.setAttribute("classId", "KisPattern");
573 pat.setAttribute("type", "Descriptor");
574 pat.setAttribute("name", "");
575
576 QBuffer patternBuf;
577 patternBuf.open(QIODevice::WriteOnly);
578
579 { // ensure we don't keep resources for too long
580 // XXX: this QImage should tolerate 16-bit and higher
581 QString fileName = QString("%1.pat").arg(patternUuid);
582 QImage patternImage = readVirtualArrayList<byteOrder>(device, numPlanes, palette);
583 KoPattern realPattern(patternImage, patternName, fileName);
584 realPattern.savePatToDevice(&patternBuf);
585 }
586
592 appendTextXMLNode("Nm ", patternName, &pat, doc);
593 appendTextXMLNode("Idnt", patternUuid, &pat, doc);
594
595 QDomCDATASection dataSection = doc->createCDATASection(qCompress(patternBuf.buffer()).toBase64());
596
597 QDomElement dataElement = doc->createElement("node");
598 dataElement.setAttribute("type", "KisPatternData");
599 dataElement.setAttribute("key", "Data");
600
601 dataElement.appendChild(dataSection);
602 pat.appendChild(dataElement);
603 parent->appendChild(pat);
604
605 return sizeof(patternSize) + patternSize;
606}
Write API docs here.
Definition KoPattern.h:21
#define dbgFile
Definition kis_debug.h:53
qint64 alignOffsetCeil(qint64 pos, qint64 alignment)
rgba palette[MAX_PALETTE]
Definition palette.c:35
psd_color_mode
Definition psd.h:50
@ RGB
Definition psd.h:54
@ Indexed
Definition psd.h:53
@ MultiChannel
Definition psd.h:56
@ Grayscale
Definition psd.h:52

References KisAslWriterUtils::alignOffsetCeil(), appendTextXMLNode(), dbgFile, GARBAGE_VALUE_MARK, Grayscale, Indexed, MultiChannel, palette, RGB, SAFE_READ_EX, KoPattern::savePatToDevice(), and SETUP_OFFSET_VERIFIER.

◆ readVirtualArrayList()

template<psd_byte_order byteOrder>
QImage Private::readVirtualArrayList ( QIODevice & device,
int numPlanes,
const QVector< QRgb > & palette )

Definition at line 236 of file kis_asl_reader.cpp.

237{
238 using namespace KisAslReaderUtils;
239
240 quint32 arrayVersion = GARBAGE_VALUE_MARK;
241 SAFE_READ_EX(byteOrder, device, arrayVersion);
242
243 if (arrayVersion != 3) {
244 throw ASLParseException("VAList version is not '3'!");
245 }
246
247 quint32 arrayLength = GARBAGE_VALUE_MARK;
248 SAFE_READ_EX(byteOrder, device, arrayLength);
249
250 SETUP_OFFSET_VERIFIER(vaEndVerifier, device, arrayLength, 100);
251
252 quint32 x0 = 0;
253 quint32 y0 = 0;
254 quint32 x1 = 0;
255 quint32 y1 = 0;
256 SAFE_READ_EX(byteOrder, device, y0);
257 SAFE_READ_EX(byteOrder, device, x0);
258 SAFE_READ_EX(byteOrder, device, y1);
259 SAFE_READ_EX(byteOrder, device, x1);
260 QRect arrayRect(x0, y0, x1 - x0, y1 - y0);
261
262 quint32 numberOfChannels = GARBAGE_VALUE_MARK;
263 SAFE_READ_EX(byteOrder, device, numberOfChannels);
264
265 if (numberOfChannels != 24) {
266 throw ASLParseException("VAList: Krita doesn't support ASL files with 'numberOfChannels' flag not equal to 24 (it is not documented)!");
267 }
268
269 dbgKrita << ppVar(arrayVersion);
270 dbgKrita << ppVar(arrayLength);
271 dbgKrita << ppVar(arrayRect);
272 dbgKrita << ppVar(numberOfChannels);
273
274 if (numPlanes != 1 && numPlanes != 3) {
275 throw ASLParseException("VAList: unsupported number of planes!");
276 }
277
278 QVector<QByteArray> dataPlanes;
279 dataPlanes.resize(3);
280
281 quint32 pixelDepth1 = GARBAGE_VALUE_MARK;
282
283 for (int i = 0; i < numPlanes; i++) {
284 quint32 arrayWritten = GARBAGE_VALUE_MARK;
285 if (!psdread<byteOrder>(device, arrayWritten) || !arrayWritten) {
286 throw ASLParseException("VAList plane has not-written flag set!");
287 }
288
289 quint32 arrayPlaneLength = GARBAGE_VALUE_MARK;
290 if (!psdread<byteOrder>(device, arrayPlaneLength) || !arrayPlaneLength) {
291 throw ASLParseException("VAList has plane length set to zero!");
292 }
293
294 SETUP_OFFSET_VERIFIER(planeEndVerifier, device, arrayPlaneLength, 0);
295 qint64 nextPos = device.pos() + arrayPlaneLength;
296
297 SAFE_READ_EX(byteOrder, device, pixelDepth1);
298
299 quint32 x0 = 0;
300 quint32 y0 = 0;
301 quint32 x1 = 0;
302 quint32 y1 = 0;
303 SAFE_READ_EX(byteOrder, device, y0);
304 SAFE_READ_EX(byteOrder, device, x0);
305 SAFE_READ_EX(byteOrder, device, y1);
306 SAFE_READ_EX(byteOrder, device, x1);
307 QRect planeRect(x0, y0, x1 - x0, y1 - y0);
308
309 if (planeRect != arrayRect) {
310 throw ASLParseException("VAList: planes are not uniform. Not supported yet!");
311 }
312
313 quint16 pixelDepth2 = GARBAGE_VALUE_MARK;
314 SAFE_READ_EX(byteOrder, device, pixelDepth2);
315
316 quint8 useCompression = 9;
317 SAFE_READ_EX(byteOrder, device, useCompression);
318
319 // dbgKrita << "plane index:" << ppVar(i);
320 // dbgKrita << ppVar(arrayWritten);
321 // dbgKrita << ppVar(arrayPlaneLength);
322 // dbgKrita << ppVar(pixelDepth1);
323 // dbgKrita << ppVar(planeRect);
324 // dbgKrita << ppVar(pixelDepth2);
325 // dbgKrita << ppVar(useCompression);
326
327 if (pixelDepth1 != pixelDepth2) {
328 throw ASLParseException("VAList: two pixel depths of the plane are not equal (it is not documented)!");
329 }
330
331 if (pixelDepth1 != 1 && pixelDepth1 != 8 && pixelDepth1 != 16) {
332 throw ASLParseException(QString("VAList: unsupported pixel depth: %1!").arg(pixelDepth1));
333 }
334
335 const int channelSize = (pixelDepth1 == 1 || pixelDepth1 == 8) ? 1 : 2;
336
337 const int dataLength = planeRect.width() * planeRect.height() * channelSize;
338
339 if (useCompression == psd_compression_type::Uncompressed) {
340 dataPlanes[i] = device.read(arrayPlaneLength - 23);
341 } else if (useCompression == psd_compression_type::RLE) {
342 const int numRows = planeRect.height();
343
344 QVector<quint16> rowSizes;
345 rowSizes.resize(numRows);
346
347 for (int row = 0; row < numRows; row++) {
348 quint16 rowSize = GARBAGE_VALUE_MARK;
349 SAFE_READ_EX(byteOrder, device, rowSize);
350 rowSizes[row] = rowSize;
351 }
352
353 for (int row = 0; row < numRows; row++) {
354 const quint16 rowSize = rowSizes[row];
355
356 QByteArray compressedData = device.read(rowSize);
357
358 if (compressedData.size() != rowSize) {
359 throw ASLParseException("VAList: failed to read compressed data!");
360 }
361
362 dbgFile << "Going to decompress the pattern";
363
364 QByteArray uncompressedData =
365 Compression::uncompress(planeRect.width() * channelSize, compressedData, psd_compression_type::RLE);
366
367 if (uncompressedData.size() != planeRect.width()) {
368 throw ASLParseException("VAList: failed to decompress data!");
369 }
370
371 dataPlanes[i].append(uncompressedData);
372 }
373 } else if (useCompression == psd_compression_type::ZIP) {
374 QByteArray compressedBytes = device.read(arrayPlaneLength - 23);
375 dataPlanes[i] = Compression::uncompress(dataLength, compressedBytes, psd_compression_type::ZIP);
376 } else {
377 throw ASLParseException("VAList: ZIP compression is not implemented yet!");
378 }
379
380 if (dataPlanes[i].size() != dataLength) {
381 throw ASLParseException("VAList: failed to read/uncompress data plane!");
382 }
383
384 if (device.pos() != nextPos) {
385 warnFile << "VAList: Data is left out from reading"
386 << "(" << device.pos() << ")";
387 }
388 device.seek(nextPos);
389 }
390
391 QImage::Format format{};
392
393 if (pixelDepth1 == 1 || !palette.isEmpty()) {
394 if (palette.isEmpty()) {
395 format = QImage::Format_Grayscale8;
396 } else {
397 format = QImage::Format_Indexed8;
398 }
399 } else if (pixelDepth1 == 8) {
400 format = QImage::Format_ARGB32;
401 } else {
402 format = QImage::Format_RGBA64;
403 }
404
405 QImage image(arrayRect.size(), format);
406
407 if (format == QImage::Format_Indexed8) {
408 image.setColorTable(palette);
409 }
410 dbgFile << "Loading the data into an image of format" << format << arrayRect << "(" << device.pos() << ")";
411
412 const int dataLength = arrayRect.width() * arrayRect.height();
413
414 if (format == QImage::Format_ARGB32) {
415 quint8 *dstPtr = image.bits();
416
417 // This copies the single channel data into all three rgb channels, creating a grayscale picture
418 for (int i = 0; i < dataLength; i++) {
419 for (int j = 2; j >= 0; j--) {
420 int plane;
421 if (numPlanes == 1) {
422 plane = 0;
423 }
424 else {
425 plane = j;
426 }
427 *dstPtr++ = dataPlanes[plane][i];
428 }
429 *dstPtr++ = 0xFF;
430 }
431 } else if (format == QImage::Format_Indexed8 || format == QImage::Format_Grayscale8) {
432 const auto *dataPlane = reinterpret_cast<const quint8 *>(dataPlanes[0].constData());
433
434 for (int x = 0; x < arrayRect.height(); x++) {
435 quint8 *dstPtr = image.scanLine(x);
436
437 for (int y = 0; y < arrayRect.width(); y++) {
438 *dstPtr++ = dataPlane[x * arrayRect.width() + y];
439 }
440 }
441 } else {
442 quint16 *dstPtr = reinterpret_cast<quint16 *>(image.bits());
443
444 for (int i = 0; i < dataLength; i++) {
445 for (int j = 0; j <= 2; j++) {
446 const int plane = qMin(numPlanes, j);
447 const quint16 *dataPlane = reinterpret_cast<const quint16 *>(dataPlanes[plane].constData());
448 *dstPtr++ = qFromBigEndian(dataPlane[i]);
449 }
450 *dstPtr++ = 0xFFFF;
451 }
452 }
453
454 // static int i = -1; i++;
455 // QString filename = QString("pattern_image_%1.png").arg(i);
456 // dbgKrita << "### dumping pattern image" << ppVar(filename);
457 // image.save(filename);
458
459 return image.convertToFormat(QImage::Format_ARGB32, Qt::AutoColor | Qt::PreferDither);
460}
static QByteArray uncompress(int unpacked_len, QByteArray bytes, psd_compression_type compressionType, int row_size=0, int color_depth=0)
#define dbgKrita
Definition kis_debug.h:45
#define warnFile
Definition kis_debug.h:95
int size(const Forest< T > &forest)
Definition KisForest.h:1232
@ RLE
Definition psd.h:41
@ Uncompressed
Definition psd.h:40
@ ZIP
Definition psd.h:42

References dbgFile, dbgKrita, GARBAGE_VALUE_MARK, palette, ppVar, RLE, SAFE_READ_EX, SETUP_OFFSET_VERIFIER, Compression::uncompress(), Uncompressed, warnFile, and ZIP.

◆ tryParseDescriptor()

bool Private::tryParseDescriptor ( const QDomElement & el,
const QString & path,
const QString & classId,
KisAslObjectCatcher & catcher )

Filenames in Krita cannot have slashes inside, but some of the styles saved in 4.x days could have that. Here we just forcefully crop the directory part of the gradient to make sure that it fits the new policy.

Since ASL doesn't use this name as any linkage (actually, gradients are always embedded into the style) so we don't really care about the contents of the filename field. It should just be somewhat unique.

Definition at line 317 of file kis_asl_xml_parser.cpp.

318{
319 bool retval = true;
320
321 if (classId == "null") {
322 catcher.newStyleStarted();
323 // here we just notify that a new style is started, we haven't
324 // processed the whole block yet, so return false.
325 retval = false;
326 } else if (el.attribute("key", " ") == "Clr ") {
327 catcher.addColor(path, parseColorObject(el, classId));
328 } else if (el.attribute("key", " ") == "hglC" || el.attribute("key", " ") == "sdwC") {
329 // like Clr, but /ebbl/ likes to do everything differently - see bug 464218
330 catcher.addColor(path, parseColorObject(el, classId));
331 } else if (classId == "ShpC") {
332 CurveObjectCatcher curveCatcher;
333
334 QDomNode child = el.firstChild();
335 while (!child.isNull()) {
336 parseElement(child.toElement(), "", curveCatcher);
337 child = child.nextSibling();
338 }
339
340 catcher.addCurve(path, curveCatcher.m_name, curveCatcher.m_points);
341
342 } else if (classId == "CrPt") {
343 QPointF point;
344
345 QDomNode child = el.firstChild();
346 while (!child.isNull()) {
347 QDomElement childEl = child.toElement();
348
349 QString type = childEl.attribute("type", "<unknown>");
350 QString key = childEl.attribute("key", "");
351
352 if (type == "Boolean" && key == "Cnty") {
353 warnKrita << "WARNING: tryParseDescriptor: The points of the curve object contain \'Cnty\' flag which is unsupported by Krita";
354 warnKrita << " " << ppVar(type) << ppVar(key) << ppVar(path);
355
356 child = child.nextSibling();
357 continue;
358 }
359
360 if (type != "Double") {
361 warnKrita << "Unknown point component type:" << ppVar(type) << ppVar(key) << ppVar(path);
362 return false;
363 }
364
365 double value = KisDomUtils::toDouble(childEl.attribute("value", "0"));
366
367 if (key == "Hrzn") {
368 point.setX(value);
369 } else if (key == "Vrtc") {
370 point.setY(value);
371 } else {
372 warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path);
373 return false;
374 }
375
376 child = child.nextSibling();
377 }
378
379 catcher.addPoint(path, point);
380
381 } else if (classId == "Pnt ") {
382 QPointF point;
383
384 QDomNode child = el.firstChild();
385 while (!child.isNull()) {
386 QDomElement childEl = child.toElement();
387
388 QString type = childEl.attribute("type", "<unknown>");
389 QString key = childEl.attribute("key", "");
390 QString unit = childEl.attribute("unit", "");
391
392 if (type != "Double" && !(type == "UnitFloat" && unit == "#Prc")) {
393 warnKrita << "Unknown point component type:" << ppVar(unit) << ppVar(type) << ppVar(key) << ppVar(path);
394 return false;
395 }
396
397 double value = KisDomUtils::toDouble(childEl.attribute("value", "0"));
398
399 if (key == "Hrzn") {
400 point.setX(value);
401 } else if (key == "Vrtc") {
402 point.setY(value);
403 } else {
404 warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path);
405 return false;
406 }
407
408 child = child.nextSibling();
409 }
410
411 catcher.addPoint(path, point);
412
413 } else if (classId == "KisPattern") {
414 QByteArray patternData;
415 QString patternUuid;
416
417 QDomNode child = el.firstChild();
418 while (!child.isNull()) {
419 QDomElement childEl = child.toElement();
420
421 QString type = childEl.attribute("type", "<unknown>");
422 QString key = childEl.attribute("key", "");
423
424 if (type == "Text" && key == "Idnt") {
425 patternUuid = childEl.attribute("value", "").trimmed();
426 }
427
428 if (type == "KisPatternData" && key == "Data") {
429 QDomNode dataNode = child.firstChild();
430
431 if (!dataNode.isCDATASection()) {
432 warnKrita << "WARNING: failed to parse KisPatternData XML section!";
433 continue;
434 }
435
436 QDomCDATASection dataSection = dataNode.toCDATASection();
437 QByteArray data = dataSection.data().toLatin1();
438 data = QByteArray::fromBase64(data);
439 data = qUncompress(data);
440
441 if (data.isEmpty()) {
442 warnKrita << "WARNING: failed to parse KisPatternData XML section!";
443 continue;
444 }
445
446 patternData = data;
447 }
448
449 child = child.nextSibling();
450 }
451
452 if (!patternUuid.isEmpty() && !patternData.isEmpty()) {
453 QString fileName = QString("%1.pat").arg(patternUuid);
454
455 QSharedPointer<KoPattern> pattern(new KoPattern(fileName));
456
457 QBuffer buffer(&patternData);
458 buffer.open(QIODevice::ReadOnly);
459
460 if (pattern->loadPatFromDevice(&buffer) && pattern->valid()) {
461 catcher.addPattern(path, pattern, patternUuid);
462 }
463 else {
464 warnKrita << "WARNING: failed to create pattern:" << ppVar(patternUuid) << ppVar(pattern);
465 }
466 } else {
467 warnKrita << "WARNING: failed to load KisPattern XML section!" << ppVar(patternUuid);
468 }
469
470 } else if (classId == "Ptrn") { // reference to an existing pattern
471 QString patternUuid;
472 QString patternName;
473
474 QDomNode child = el.firstChild();
475 while (!child.isNull()) {
476 QDomElement childEl = child.toElement();
477
478 QString type = childEl.attribute("type", "<unknown>");
479 QString key = childEl.attribute("key", "");
480
481 if (type == "Text" && key == "Idnt") {
482 patternUuid = childEl.attribute("value", "");
483 } else if (type == "Text" && key == "Nm ") {
484 patternName = childEl.attribute("value", "");
485 } else {
486 warnKrita << "WARNING: unrecognized pattern-ref section key:" << ppVar(type) << ppVar(key);
487 }
488
489 child = child.nextSibling();
490 }
491
492 catcher.addPatternRef(path, patternUuid, patternName);
493
494 } else if (classId == "Grdn") {
495 QString gradientName;
496 qreal gradientSmoothness = 100.0;
497
498 QVector<qreal> startLocations;
499 QVector<qreal> middleOffsets;
500 QVector<KoColor> colors;
502
503 QVector<qreal> transpStartLocations;
504 QVector<qreal> transpMiddleOffsets;
505 QVector<qreal> transparencies;
506
507 QDomNode child = el.firstChild();
508 while (!child.isNull()) {
509 QDomElement childEl = child.toElement();
510
511 QString type = childEl.attribute("type", "<unknown>");
512 QString key = childEl.attribute("key", "");
513
514 if (type == "Text" && key == "Nm ") {
515 gradientName = childEl.attribute("value", "");
516 } else if (type == "Enum" && key == "GrdF") {
517 QString typeId = childEl.attribute("typeId", "");
518 QString value = childEl.attribute("value", "");
519
520 if (typeId != "GrdF" || value != "CstS") {
521 warnKrita << "WARNING: Unsupported gradient type (probably, noise-based):" << value;
522 return true;
523 }
524 } else if (type == "Double" && key == "Intr") {
525 double value = KisDomUtils::toDouble(childEl.attribute("value", "4096"));
526 gradientSmoothness = 100.0 * value / 4096.0;
527 } else if (type == "List" && key == "Clrs") {
528 parseColorStopsList(childEl, startLocations, middleOffsets, colors, types);
529 } else if (type == "List" && key == "Trns") {
530 parseTransparencyStopsList(childEl, transpStartLocations, transpMiddleOffsets, transparencies);
531 }
532
533 child = child.nextSibling();
534 }
535
536 if (colors.size() < transparencies.size()) {
537 const KoColor lastColor = !colors.isEmpty() ? colors.last() : KoColor();
538 const KoGradientSegmentEndpointType lastType = !types.isEmpty() ? types.last() : COLOR_ENDPOINT;
539 while (colors.size() != transparencies.size()) {
540 const int index = colors.size();
541 colors.append(lastColor);
542 startLocations.append(transpStartLocations[index]);
543 middleOffsets.append(transpMiddleOffsets[index]);
544 types.append(lastType);
545 }
546 }
547
548 if (colors.size() > transparencies.size()) {
549 const qreal lastTransparency = !transparencies.isEmpty() ? transparencies.last() : 1.0;
550 while (colors.size() != transparencies.size()) {
551 const int index = transparencies.size();
552 transparencies.append(lastTransparency);
553 transpStartLocations.append(startLocations[index]);
554 transpMiddleOffsets.append(middleOffsets[index]);
555 }
556 }
557
558 if (colors.size() == 1) {
559 colors.append(colors.last());
560 startLocations.append(1.0);
561 middleOffsets.append(0.5);
562 types.append(COLOR_ENDPOINT);
563
564 transparencies.append(transparencies.last());
565 transpStartLocations.append(1.0);
566 transpMiddleOffsets.append(0.5);
567 }
568
579 const QString fileName = QFileInfo(gradientName).fileName() + ".ggr";
581 Q_UNUSED(gradientSmoothness);
582 gradient->setName(gradientName);
583
584 if (colors.size() >= 2) {
585 for (int i = 1; i < colors.size(); i++) {
586 KoColor startColor = colors[i - 1];
587 KoColor endColor = colors[i];
588 startColor.setOpacity(transparencies[i - 1]);
589 endColor.setOpacity(transparencies[i]);
590
591 qreal start = startLocations[i - 1];
592 qreal end = startLocations[i];
593 qreal middle = start + middleOffsets[i - 1] * (end - start);
594
595 KoGradientSegmentEndpointType startType = types[i - 1];
596 KoGradientSegmentEndpointType endType = types[i];
597
598 gradient->createSegment(INTERP_LINEAR, COLOR_INTERP_RGB, start, end, middle, startColor, endColor, startType, endType);
599 }
600 gradient->setValid(true);
601 gradient->updatePreview();
602 } else {
603 gradient->setValid(false);
604 }
605
606 catcher.addGradient(path, gradient);
607 } else if (classId == "Trnf") {
608
609 double xx = 1.0;
610 double xy = 0.0;
611 double yx = 0.0;
612 double yy = 1.0;
613 double tx = 0.0;
614 double ty = 0.0;
615
616 QDomNode child = el.firstChild();
617 while (!child.isNull()) {
618 QDomElement childEl = child.toElement();
619
620 QString type = childEl.attribute("type", "<unknown>");
621 QString key = childEl.attribute("key", "");
622 double value = KisDomUtils::toDouble(childEl.attribute("value"));
623
624
625 if (type == "Double") {
626 if (key == "xx") {
627 xx = value;
628 } else if (key == "xy") {
629 xy = value;
630 } else if (key == "yx") {
631 yx = value;
632 } else if (key == "yy") {
633 yy = value;
634 } else if (key == "tx") {
635 tx = value;
636 } else if (key == "ty") {
637 ty = value;
638 }
639 }
640
641 child = child.nextSibling();
642 }
643 catcher.addTransform(path, QTransform(xx, xy, yx, yy, tx, ty));
644 } else if (classId == "classFloatRect") {
645
646 QRectF rect;
647
648 QDomNode child = el.firstChild();
649 while (!child.isNull()) {
650 QDomElement childEl = child.toElement();
651
652 QString type = childEl.attribute("type", "<unknown>");
653 QString key = childEl.attribute("key", "");
654 double value = KisDomUtils::toDouble(childEl.attribute("value"));
655
656
657 if (type == "Double") {
658 if (key == "Top ") {
659 rect.setTop(value);
660 } else if (key == "Left") {
661 rect.setLeft(value);
662 } else if (key == "Btom") {
663 rect.setBottom(value);
664 } else if (key == "Rght") {
665 rect.setRight(value);
666 }
667 }
668 child = child.nextSibling();
669 }
670
671 if (el.attribute("key", " ") == "keyOriginShapeBBox") {
672 catcher.addUnitRect(path, "#Pxl", rect);
673 } else {
674 catcher.addRect(path, rect);
675 }
676 } else if (classId == "unitRect") {
677 QRectF rect;
678
679 QDomNode child = el.firstChild();
680 QString unit;
681 while (!child.isNull()) {
682 QDomElement childEl = child.toElement();
683
684 QString type = childEl.attribute("type", "<unknown>");
685 QString key = childEl.attribute("key", "");
686 unit = childEl.attribute("unit", unit);
687 double value = KisDomUtils::toDouble(childEl.attribute("value"));
688
689
690 if (type == "UnitFloat") {
691 if (key == "Top ") {
692 rect.setTop(value);
693 } else if (key == "Left") {
694 rect.setLeft(value);
695 } else if (key == "Btom") {
696 rect.setBottom(value);
697 } else if (key == "Rght") {
698 rect.setRight(value);
699 }
700 }
701 child = child.nextSibling();
702 }
703
704 catcher.addUnitRect(path, unit, rect);
705
706 } else {
707 retval = false;
708 }
709
710 return retval;
711}
KoGradientSegmentEndpointType
@ INTERP_LINEAR
@ COLOR_INTERP_RGB
virtual void addPoint(const QString &path, const QPointF &value)
virtual void addColor(const QString &path, const KoColor &value)
virtual void addCurve(const QString &path, const QString &name, const QVector< QPointF > &points)
virtual void addTransform(const QString &path, const QTransform &transform)
virtual void addPattern(const QString &path, const KoPatternSP pattern, const QString &patternUuid)
virtual void addGradient(const QString &path, KoAbstractGradientSP gradient)
virtual void addRect(const QString &path, const QRectF &rect)
virtual void addUnitRect(const QString &path, const QString &unit, const QRectF &rect)
virtual void addPatternRef(const QString &path, const QString &patternUuid, const QString &patternName)
void parseTransparencyStopsList(QDomElement parent, QVector< qreal > &startLocations, QVector< qreal > &middleOffsets, QVector< qreal > &transparencies)
void parseColorStopsList(QDomElement parent, QVector< qreal > &startLocations, QVector< qreal > &middleOffsets, QVector< KoColor > &colors, QVector< KoGradientSegmentEndpointType > &types)

References KisAslObjectCatcher::addColor(), KisAslObjectCatcher::addCurve(), KisAslObjectCatcher::addGradient(), KisAslObjectCatcher::addPattern(), KisAslObjectCatcher::addPatternRef(), KisAslObjectCatcher::addPoint(), KisAslObjectCatcher::addRect(), KisAslObjectCatcher::addTransform(), KisAslObjectCatcher::addUnitRect(), COLOR_ENDPOINT, COLOR_INTERP_RGB, INTERP_LINEAR, Private::CurveObjectCatcher::m_name, Private::CurveObjectCatcher::m_points, KisAslObjectCatcher::newStyleStarted(), parseColorObject(), parseColorStopsList(), parseElement(), parseTransparencyStopsList(), ppVar, KoColor::setOpacity(), KisDomUtils::toDouble(), value(), and warnKrita.

◆ writeFileImpl()

void Private::writeFileImpl ( QIODevice & device,
const QDomDocument & doc )

Definition at line 159 of file kis_asl_writer.cpp.

160{
161 {
162 quint16 stylesVersion = 2;
163 SAFE_WRITE_EX(psd_byte_order::psdBigEndian, device, stylesVersion);
164 }
165
166 {
167 QString signature("8BSL");
168 if (!device.write(signature.toLatin1().data(), 4)) {
169 throw ASLWriteException("Failed to write ASL signature");
170 }
171 }
172
173 {
174 quint16 patternsVersion = 3;
175 SAFE_WRITE_EX(psd_byte_order::psdBigEndian, device, patternsVersion);
176 }
177
178 {
180
181 KisAslPatternsWriter patternsWriter(doc, device, psd_byte_order::psdBigEndian);
182 patternsWriter.writePatterns();
183 }
184
185 QDomElement root = doc.documentElement();
186 KIS_ASSERT_RECOVER_RETURN(root.tagName() == "asl");
187
188 int numStyles = calculateNumStyles(root);
189 KIS_ASSERT_RECOVER_RETURN(numStyles > 0);
190
191 {
192 const quint32 numStylesTag = static_cast<quint32>(numStyles);
193 SAFE_WRITE_EX(psd_byte_order::psdBigEndian, device, numStylesTag);
194 }
195
196 QDomNode child = root.firstChild();
197
198 for (int styleIndex = 0; styleIndex < numStyles; styleIndex++) {
200
201 KIS_ASSERT_RECOVER_RETURN(!child.isNull());
202
203 {
204 quint32 stylesFormatVersion = 16;
205 SAFE_WRITE_EX(psd_byte_order::psdBigEndian, device, stylesFormatVersion);
206 }
207
208 while (!child.isNull()) {
209 QDomElement el = child.toElement();
210 QString key = el.attribute("key", "");
211
212 if (key != ResourceType::Patterns)
213 break;
214
215 child = child.nextSibling();
216 }
217
218 parseElement(child.toElement(), device);
219 child = child.nextSibling();
220
221 {
222 quint32 stylesFormatVersion = 16;
223 SAFE_WRITE_EX(psd_byte_order::psdBigEndian, device, stylesFormatVersion);
224 }
225
226 parseElement(child.toElement(), device);
227 child = child.nextSibling();
228
229 // ASL files' size should be 4-bytes aligned
230 const qint64 paddingSize = 4 - (device.pos() & 0x3);
231 if (paddingSize != 4) {
232 QByteArray padding(paddingSize, '\0');
233 device.write(padding);
234 }
235 }
236}
int calculateNumStyles(const QDomElement &root)

References calculateNumStyles(), KIS_ASSERT_RECOVER_RETURN, parseElement(), ResourceType::Patterns, psdBigEndian, SAFE_WRITE_EX, and KisAslPatternsWriter::writePatterns().

◆ writeFillLayerSectionImpl()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::writeFillLayerSectionImpl ( QIODevice & device,
const QDomDocument & doc )

Definition at line 281 of file kis_asl_writer.cpp.

282{
283 QDomElement root = doc.documentElement();
284 KIS_ASSERT_RECOVER_RETURN(root.tagName() == "asl");
285
286 {
287 quint32 descriptorVersion = 16;
288 SAFE_WRITE_EX(byteOrder, device, descriptorVersion);
289 }
290
291 QDomNode child = root.firstChild();
292
293 while (!child.isNull()) {
294 QDomElement el = child.toElement();
295 QString key = el.attribute("key", "");
296
297 if (key != ResourceType::Patterns)
298 break;
299
300 child = child.nextSibling();
301 }
302
303 parseElement<byteOrder>(child.toElement(), device);
304 child = child.nextSibling();
305
306 // ASL files' size should be 4-bytes aligned
307 const qint64 paddingSize = 4 - (device.pos() & 0x3);
308 if (paddingSize != 4) {
309 QByteArray padding(static_cast<int>(paddingSize), '\0');
310 device.write(padding);
311 }
312}

References KIS_ASSERT_RECOVER_RETURN, ResourceType::Patterns, and SAFE_WRITE_EX.

◆ writePsdLfx2SectionImpl()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::writePsdLfx2SectionImpl ( QIODevice & device,
const QDomDocument & doc )

Definition at line 239 of file kis_asl_writer.cpp.

240{
241 QDomElement root = doc.documentElement();
242 KIS_ASSERT_RECOVER_RETURN(root.tagName() == "asl");
243
244 int numStyles = calculateNumStyles(root);
245 KIS_ASSERT_RECOVER_RETURN(numStyles == 1);
246
247 {
248 quint32 objectEffectsVersion = 0;
249 SAFE_WRITE_EX(byteOrder, device, objectEffectsVersion);
250 }
251
252 {
253 quint32 descriptorVersion = 16;
254 SAFE_WRITE_EX(byteOrder, device, descriptorVersion);
255 }
256
257 QDomNode child = root.firstChild();
258
259 while (!child.isNull()) {
260 QDomElement el = child.toElement();
261 QString key = el.attribute("key", "");
262
263 if (key != ResourceType::Patterns)
264 break;
265
266 child = child.nextSibling();
267 }
268
269 parseElement<byteOrder>(child.toElement(), device);
270 child = child.nextSibling();
271
272 // ASL files' size should be 4-bytes aligned
273 const qint64 paddingSize = 4 - (device.pos() & 0x3);
274 if (paddingSize != 4) {
275 QByteArray padding(static_cast<int>(paddingSize), '\0');
276 device.write(padding);
277 }
278}

References calculateNumStyles(), KIS_ASSERT_RECOVER_RETURN, ResourceType::Patterns, and SAFE_WRITE_EX.

◆ writeTypeToolSectionImpl()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::writeTypeToolSectionImpl ( QIODevice & device,
const QDomDocument & doc,
const QDomDocument & warpDoc,
const QTransform tf,
const QRectF bounds )

Definition at line 315 of file kis_asl_writer.cpp.

316{
317 QDomElement root = doc.documentElement();
318 KIS_ASSERT_RECOVER_RETURN(root.tagName() == "asl");
319
320 {
321 quint16 descriptorVersion = 1;
322 SAFE_WRITE_EX(byteOrder, device, descriptorVersion);
323 }
324
325 {
326 SAFE_WRITE_EX(byteOrder, device, double(tf.m11()));
327 SAFE_WRITE_EX(byteOrder, device, double(tf.m12()));
328 SAFE_WRITE_EX(byteOrder, device, double(tf.m21()));
329 SAFE_WRITE_EX(byteOrder, device, double(tf.m22()));
330 SAFE_WRITE_EX(byteOrder, device, double(tf.dx()));
331 SAFE_WRITE_EX(byteOrder, device, double(tf.dy()));
332 }
333
334 {
335 quint16 textVersion = 50;
336 SAFE_WRITE_EX(byteOrder, device, textVersion);
337 quint32 descriptorVersion = 16;
338 SAFE_WRITE_EX(byteOrder, device, descriptorVersion);
339 }
340
341 QDomNode child = root.firstChild();
342 parseElement<byteOrder>(child.toElement(), device);
343
344 // warp data
345 {
346 quint16 textVersion = 1;
347 SAFE_WRITE_EX(byteOrder, device, textVersion);
348 quint32 descriptorVersion = 16;
349 SAFE_WRITE_EX(byteOrder, device, descriptorVersion);
350 }
351
352 QDomElement warpRoot = warpDoc.documentElement();
353 KIS_ASSERT_RECOVER_RETURN(warpRoot.tagName() == "asl");
354
355 QDomNode warpChild = warpRoot.firstChild();
356 parseElement<byteOrder>(warpChild.toElement(), device);
357
358 {
359 SAFE_WRITE_EX(byteOrder, device, double(bounds.left()));
360 SAFE_WRITE_EX(byteOrder, device, double(bounds.top()));
361 SAFE_WRITE_EX(byteOrder, device, double(bounds.right()));
362 SAFE_WRITE_EX(byteOrder, device, double(bounds.bottom()));
363 }
364
365 // ASL files' size should be 4-bytes aligned
366 const qint64 paddingSize = 4 - (device.pos() & 0x3);
367 if (paddingSize != 4) {
368 QByteArray padding(static_cast<int>(paddingSize), '\0');
369 device.write(padding);
370 }
371}
#define bounds(x, a, b)

References bounds, KIS_ASSERT_RECOVER_RETURN, and SAFE_WRITE_EX.

◆ writeVectorOriginationDataImpl()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::writeVectorOriginationDataImpl ( QIODevice & device,
const QDomDocument & doc )

Definition at line 396 of file kis_asl_writer.cpp.

397{
398 QDomElement root = doc.documentElement();
399 KIS_ASSERT_RECOVER_RETURN(root.tagName() == "asl");
400
401 {
402 quint32 version = 1;
403 SAFE_WRITE_EX(byteOrder, device, version);
404 }
405 {
406 quint32 descriptorVersion = 16;
407 SAFE_WRITE_EX(byteOrder, device, descriptorVersion);
408 }
409
410 QDomNode child = root.firstChild();
411 parseElement<byteOrder>(child.toElement(), device);
412
413 // ASL files' size should be 4-bytes aligned
414 const qint64 paddingSize = 4 - (device.pos() & 0x3);
415 if (paddingSize != 4) {
416 QByteArray padding(static_cast<int>(paddingSize), '\0');
417 device.write(padding);
418 }
419}

References KIS_ASSERT_RECOVER_RETURN, and SAFE_WRITE_EX.

◆ writeVectorStrokeDataImpl()

template<psd_byte_order byteOrder = psd_byte_order::psdBigEndian>
void Private::writeVectorStrokeDataImpl ( QIODevice & device,
const QDomDocument & doc )

Definition at line 374 of file kis_asl_writer.cpp.

375{
376 QDomElement root = doc.documentElement();
377 KIS_ASSERT_RECOVER_RETURN(root.tagName() == "asl");
378
379 {
380 quint32 descriptorVersion = 16;
381 SAFE_WRITE_EX(byteOrder, device, descriptorVersion);
382 }
383
384 QDomNode child = root.firstChild();
385 parseElement<byteOrder>(child.toElement(), device);
386
387 // ASL files' size should be 4-bytes aligned
388 const qint64 paddingSize = 4 - (device.pos() & 0x3);
389 if (paddingSize != 4) {
390 QByteArray padding(static_cast<int>(paddingSize), '\0');
391 device.write(padding);
392 }
393}

References KIS_ASSERT_RECOVER_RETURN, and SAFE_WRITE_EX.