Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_asl_xml_parser.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <stdexcept>
10#include <string>
11
12#include <QBuffer>
13#include <QDomDocument>
14#include <QIODevice>
15#include <QFileInfo>
16
17#include <QColor>
18
20#include <KoColorConversions.h>
22
23#include "kis_dom_utils.h"
24
25#include "compression.h"
26#include "kis_debug.h"
27#include "psd.h"
28#include "psd_utils.h"
29
31
32namespace Private
33{
34void parseElement(const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher);
35
37{
38public:
39 void addText(const QString &path, const QString &value) override
40 {
41 if (path == "/Nm ") {
42 m_name = value;
43 } else {
44 warnKrita << "XML (ASL): failed to parse curve object" << path << value;
45 }
46 }
47
48 void addPoint(const QString &path, const QPointF &value) override
49 {
50 if (!m_arrayMode) {
51 warnKrita << "XML (ASL): failed to parse curve object (array fault)" << path << value << ppVar(m_arrayMode);
52 }
53
54 m_points.append(value);
55 }
56
57public:
59 QString m_name;
60};
61
62KoColor parseColorObject(QDomElement parent, QString classID)
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}
203
204void parseColorStopsList(QDomElement parent,
205 QVector<qreal> &startLocations,
206 QVector<qreal> &middleOffsets,
207 QVector<KoColor> &colors,
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}
265
266void parseTransparencyStopsList(QDomElement parent, QVector<qreal> &startLocations, QVector<qreal> &middleOffsets, QVector<qreal> &transparencies)
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}
311
312inline QString buildPath(const QString &parent, const QString &key)
313{
314 return parent + "/" + key;
315}
316
317bool tryParseDescriptor(const QDomElement &el, const QString &path, const QString &classId, KisAslObjectCatcher &catcher)
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}
712
713void parseElement(const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher)
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}
785
786} // namespace
787
788void KisAslXmlParser::parseXML(const QDomDocument &doc, KisAslObjectCatcher &catcher)
789{
790 QDomElement root = doc.documentElement();
791 if (root.tagName() != "asl") {
792 return;
793 }
794
795 QDomNode child = root.firstChild();
796 while (!child.isNull()) {
797 Private::parseElement(child.toElement(), "", catcher);
798 child = child.nextSibling();
799 }
800}
float value(const T *src, size_t ch)
qreal v
void HSVToRGB(float h, float s, float v, float *r, float *g, float *b)
const quint8 OPACITY_OPAQUE_U8
KoGradientSegmentEndpointType
@ COLOR_ENDPOINT
@ FOREGROUND_ENDPOINT
@ BACKGROUND_ENDPOINT
@ 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 addUnitFloat(const QString &path, const QString &unit, double 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 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 addRect(const QString &path, const QRectF &rect)
virtual void addDouble(const QString &path, double value)
virtual void addUnitRect(const QString &path, const QString &unit, const QRectF &rect)
virtual void addPatternRef(const QString &path, const QString &patternUuid, const QString &patternName)
virtual void addText(const QString &path, const QString &value)
virtual void addRawData(const QString &path, QByteArray ba)
void parseXML(const QDomDocument &doc, KisAslObjectCatcher &catcher)
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
Write API docs here.
Definition KoPattern.h:21
void addText(const QString &path, const QString &value) override
void addPoint(const QString &path, const QPointF &value) override
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#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)
void parseTransparencyStopsList(QDomElement parent, QVector< qreal > &startLocations, QVector< qreal > &middleOffsets, QVector< qreal > &transparencies)
KoColor parseColorObject(QDomElement parent, QString classID)
QString buildPath(const QString &parent, const QString &key)
void parseColorStopsList(QDomElement parent, QVector< qreal > &startLocations, QVector< qreal > &middleOffsets, QVector< KoColor > &colors, QVector< KoGradientSegmentEndpointType > &types)
void parseElement(const QDomElement &el, QIODevice &device, bool forceTypeInfo=false)
bool tryParseDescriptor(const QDomElement &el, const QString &path, const QString &classId, KisAslObjectCatcher &catcher)
static KoColorSpaceRegistry * instance()