Krita Source Code Documentation
Loading...
Searching...
No Matches
PsdTextDataConverter Class Reference

The PsdTextDataConverter class. More...

#include <psd_text_data_converter.h>

Classes

struct  Private
 

Public Member Functions

bool convertPSDTextEngineDataToSVG (const QVariantHash tySh, const QVariantHash txt2, const KoColorSpace *imageCs, const int textIndex, QString *svgText, QString *svgStyles, QPointF &offset, bool &offsetByAscent, bool &isHorizontal, QTransform scaleToPt=QTransform())
 
bool convertToPSDTextEngineData (const QString &svgText, QRectF &boundingBox, const QList< KoShape * > &shapesInside, QVariantHash &txt2, int &textIndex, QString &textTotal, bool &isHorizontal, QTransform scaleToPx=QTransform())
 
QStringList errors () const
 
 PsdTextDataConverter ()
 
QStringList warnings () const
 
 ~PsdTextDataConverter ()
 

Private Member Functions

QColor colorFromPSDStyleSheet (QVariantHash color, const KoColorSpace *imageCs)
 
void gatherFonts (const QMap< QString, QString > cssStyles, const QString text, QVariantList &fontSet, QVector< int > &lengths, QVector< int > &fontIndices)
 
QVariantHash gatherParagraphStyle (QDomElement el, QVariantHash defaultProperties, bool &isHorizontal, QString *inlineSize, QTransform scaleToPx)
 
void gatherStyles (QDomElement el, QString &text, QVariantHash parentStyle, QMap< QString, QString > parentCssStyles, QVariantList &styles, QVariantList &fontSet, QTransform scaleToPx)
 
QString stylesForPSDParagraphSheet (QVariantHash PSDParagraphSheet, QString &lang, QMap< int, KoCSSFontInfo > fontNames, QTransform scaleToPt, const KoColorSpace *imageCs)
 
QString stylesForPSDStyleSheet (QString &lang, QVariantHash PSDStyleSheet, QMap< int, KoCSSFontInfo > fontNames, QTransform scale, const KoColorSpace *imageCs)
 
QVariantHash styleToPSDStylesheet (const QMap< QString, QString > cssStyles, QVariantHash parentStyle, QTransform scaleToPx)
 

Private Attributes

const QScopedPointer< Privated
 

Detailed Description

The PsdTextDataConverter class.

This class handles converting PSD text engine data to actual SVG.

Definition at line 28 of file psd_text_data_converter.h.

Constructor & Destructor Documentation

◆ PsdTextDataConverter()

PsdTextDataConverter::PsdTextDataConverter ( )

Definition at line 38 of file psd_text_data_converter.cpp.

39 : d(new Private)
40{
41
42}
const QScopedPointer< Private > d

◆ ~PsdTextDataConverter()

PsdTextDataConverter::~PsdTextDataConverter ( )

Definition at line 44 of file psd_text_data_converter.cpp.

45{
46
47}

Member Function Documentation

◆ colorFromPSDStyleSheet()

QColor PsdTextDataConverter::colorFromPSDStyleSheet ( QVariantHash color,
const KoColorSpace * imageCs )
private

Definition at line 50 of file psd_text_data_converter.cpp.

50 {
51 QColor c(Qt::black);
52 if (color.keys().contains("/Color")) {
53 color = color["/Color"].toHash();
54 }
55 QDomDocument doc;
56 QDomElement root;
57 QVariantList values = color.value("/Values").toList();
58 if (color.value("/Type").toInt() == 0) { //graya
59 root = doc.createElement("Gray");
60 root.setAttribute("g", values.at(1).toDouble());
61 } else if (color.value("/Type").toInt() == 2) { // CMYK
62 root = doc.createElement("CMYK");
63 root.setAttribute("c", values.value(1).toDouble());
64 root.setAttribute("m", values.value(2).toDouble());
65 root.setAttribute("y", values.value(3).toDouble());
66 root.setAttribute("k", values.value(4).toDouble());
67 } else if (color.value("/Type").toInt() == 3) { // LAB
68 root = doc.createElement("Lab");
69 root.setAttribute("L", values.value(1).toDouble());
70 root.setAttribute("a", values.value(2).toDouble());
71 root.setAttribute("b", values.value(3).toDouble());
72 } else if (color.value("/Type").toInt() == 1) {
73 root = doc.createElement("RGB");
74 root.setAttribute("r", values.value(1).toDouble());
75 root.setAttribute("g", values.value(2).toDouble());
76 root.setAttribute("b", values.value(3).toDouble());
77 }
78 KoColor final = KoColor::fromXML(root, "U8");
79 if (final.colorSpace()->colorModelId() == imageCs->colorModelId()) {
80 final.setProfile(imageCs->profile());
81 }
82 final.toQColor(&c);
83 return c;
84}
virtual KoID colorModelId() const =0
virtual const KoColorProfile * profile() const =0
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350

References KoColorSpace::colorModelId(), KoColor::fromXML(), and KoColorSpace::profile().

◆ convertPSDTextEngineDataToSVG()

bool PsdTextDataConverter::convertPSDTextEngineDataToSVG ( const QVariantHash tySh,
const QVariantHash txt2,
const KoColorSpace * imageCs,
const int textIndex,
QString * svgText,
QString * svgStyles,
QPointF & offset,
bool & offsetByAscent,
bool & isHorizontal,
QTransform scaleToPt = QTransform() )

< 0 = point text, 1 = paragraph text (including text in shape), 2 = text on path.

Definition at line 817 of file psd_text_data_converter.cpp.

827{
828
829
830 QVariantHash root = tySh;
831 bool loadFallback = txt2.isEmpty();
832 const QVariantHash docObjects = txt2.value("/DocumentObjects").toHash();
833
834 QVariantHash textObject = docObjects.value("/TextObjects").toList().value(textIndex).toHash();
835 if (textObject.isEmpty() || loadFallback) {
836 textObject = root["/EngineDict"].toHash();
837 loadFallback = true;
838 }
839 if (textObject.isEmpty()) {
840 d->errors << "No engine dict found in PSD engine data";
841 return false;
842 }
843
844 QMap<int, KoCSSFontInfo> fontNames;
845 QVariantHash resourceDict = loadFallback? root.value("/DocumentResources").toHash(): txt2.value("/DocumentResources").toHash();
846 if (resourceDict.isEmpty()) {
847 d->errors << "No engine dict found in PSD engine data";
848 return false;
849 } else {
850 // PSD only stores the postscript name, and we'll need a bit more information than that.
851 QVariantList fonts = loadFallback? resourceDict.value("/FontSet").toList()
852 : resourceDict.value("/FontSet").toHash().value("/Resources").toList();
853 for (int i = 0; i < fonts.size(); i++) {
854 QVariantHash font = loadFallback? fonts.value(i).toHash()
855 : fonts.value(i).toHash().value("/Resource").toHash().value("/Identifier").toHash();
856 QString postScriptName = font.value("/Name").toString();
857 QString foundPostScriptName;
859 &foundPostScriptName);
860
861 if (postScriptName != foundPostScriptName) {
862 fontInfo.families = QStringList({"sans-serif"});
863 d->errors << QString("Font %1 not found, substituting %2").arg(postScriptName).arg(fontInfo.families.join(","));
864 }
865 fontNames.insert(i, fontInfo);
866 }
867 }
868
869 QString inlineSizeString;
870 QRectF bounds;
871
872 // load text shape
873 QScopedPointer<KoPathShape> textShape;
874 double textPathStartOffset = -3;
875 double shapePadding = 0.0;
876 int textType = 0;
877 bool reversed = false;
878 if (loadFallback) {
879 QVariantHash rendered = textObject.value("/Rendered").toHash();
880 // rendering info...
881 if (!rendered.isEmpty()) {
882 QVariantHash shapeChild = rendered.value("/Shapes").toHash().value("/Children").toList()[0].toHash();
883 textType = shapeChild.value("/ShapeType").toInt();
884 if (textType == 1) {
885 QVariantList BoxBounds = shapeChild.value("/Cookie").toHash().value("/Photoshop").toHash().value("/BoxBounds").toList();
886 if (BoxBounds.size() == 4) {
887 bounds = QRectF(BoxBounds[0].toDouble(), BoxBounds[1].toDouble(), BoxBounds[2].toDouble(), BoxBounds[3].toDouble());
888 bounds = scaleToPt.mapRect(bounds);
889 if (isHorizontal) {
890 inlineSizeString = " inline-size:"+QString::number(bounds.width())+";";
891 } else {
892 inlineSizeString = " inline-size:"+QString::number(bounds.height())+";";
893 }
894 }
895 }
896 }
897 } else {
898 QVariantHash view = textObject.value("/View").toHash();
899 // todo: if multiple frames in frames array, there's multiple shapes in shape-inside.
900 QVariantList frames = view.value("/Frames").toList();
901 if (!frames.isEmpty()) {
902 int textFrameIndex = view.value("/Frames").toList().value(0).toHash().value("/Resource").toInt();
903 QVariantList textFrameSet = resourceDict.value("/TextFrameSet").toHash().value("/Resources").toList();
904 QVariantHash textFrame = textFrameSet.at(textFrameIndex).toHash().value("/Resource").toHash();
905
906
907 if (!textFrame.isEmpty()) {
908 textType = textFrame["/Data"].toHash()["/Type"].toInt();
909
910 if (textType > 0) {
911 KoPathShape *textCurve = new KoPathShape();
912 QVariantHash data = textFrame.value("/Data").toHash();
913 QVariantList points = textFrame.value("/Bezier").toHash().value("/Points").toList();
914 QVariantList range = data.value("/TextOnPathTRange").toList();
915 QVariantList fm = data.value("/FrameMatrix").toList();
916 shapePadding = data.value("/Spacing").toDouble();
917 QVariantHash pathData = data.value("/PathData").toHash();
918 reversed = pathData.value("/Flip").toBool();
919
920 QVariant lineOrientation = data.value("/LineOrientation");
921 if (!lineOrientation.isNull()) {
922 if (lineOrientation.toInt() == 2) {
923 isHorizontal = false;
924 }
925 }
926 QTransform frameMatrix = scaleToPt;
927 if (fm.size() == 6) {
928 frameMatrix = QTransform(fm[0].toDouble(), fm[1].toDouble(), fm[2].toDouble(), fm[3].toDouble(), fm[4].toDouble(), fm[5].toDouble());
929 frameMatrix = frameMatrix * scaleToPt;
930 }
931
932 int length = points.size()/8;
933
934 QPointF startPoint;
935 QPointF endPoint;
936 for (int i = 0; i < length; i++) {
937 int iAdjust = i*8;
938 QPointF p1(points[iAdjust ].toDouble(), points[iAdjust+1].toDouble());
939 QPointF p2(points[iAdjust+2].toDouble(), points[iAdjust+3].toDouble());
940 QPointF p3(points[iAdjust+4].toDouble(), points[iAdjust+5].toDouble());
941 QPointF p4(points[iAdjust+6].toDouble(), points[iAdjust+7].toDouble());
942
943 if (i == 0 || endPoint != frameMatrix.map(p1)) {
944 if (endPoint == startPoint && i > 0) {
945 textCurve->closeMerge();
946 }
947 textCurve->moveTo(frameMatrix.map(p1));
948 startPoint = frameMatrix.map(p1);
949 }
950 if (p1==p2 && p3==p4) {
951 textCurve->lineTo(frameMatrix.map(p4));
952 } else {
953 textCurve->curveTo(frameMatrix.map(p2), frameMatrix.map(p3), frameMatrix.map(p4));
954 }
955 endPoint = frameMatrix.map(p4);
956 }
957 if (points.size() > 8) {
958 if (endPoint == startPoint) {
959 textCurve->closeMerge();
960 }
961 textShape.reset(textCurve);
962 } else {
963 delete textCurve;
964 }
965 if (!range.isEmpty()) {
966 textPathStartOffset = range[0].toDouble();
967 int segment = qFloor(textPathStartOffset);
968 double t = textPathStartOffset - segment;
969 double length = 0;
970 double totalLength = 0;
971 for (int i=0; i<textShape->subpathPointCount(0); i++) {
972 double l = textShape->segmentByIndex(KoPathPointIndex(0, i)).length();
973 totalLength += l;
974 if (i < segment) {
975 length += l;
976 } else if (i == segment) {
977 length += textShape->segmentByIndex(KoPathPointIndex(0, i)).lengthAt(t);
978 }
979 }
980 textPathStartOffset = (length/totalLength) * 100.0;
981 }
982 }
983 }
984 }
985 }
986 QString paragraphStyle = isHorizontal? "writing-mode: horizontal-tb;": "writing-mode: vertical-rl;";
987 paragraphStyle += " white-space: pre-wrap;";
988
989 QBuffer svgBuffer;
990 QBuffer styleBuffer;
991 svgBuffer.open(QIODevice::WriteOnly);
992 styleBuffer.open(QIODevice::WriteOnly);
993
994 QXmlStreamWriter svgWriter(&svgBuffer);
995 QXmlStreamWriter stylesWriter(&styleBuffer);
996 stylesWriter.writeStartElement("defs");
997 if (bounds.isValid()) {
998 stylesWriter.writeStartElement("rect");
999 stylesWriter.writeAttribute("id", "bounds");
1000 stylesWriter.writeAttribute("x", QString::number(bounds.x()));
1001 stylesWriter.writeAttribute("y", QString::number(bounds.y()));
1002 stylesWriter.writeAttribute("width", QString::number(bounds.width()));
1003 stylesWriter.writeAttribute("height", QString::number(bounds.height()));
1004 stylesWriter.writeEndElement();
1005 }
1006 if (textShape) {
1007 stylesWriter.writeStartElement("path");
1008 stylesWriter.writeAttribute("id", "textShape");
1009 stylesWriter.writeAttribute("d", textShape->toString());
1010 stylesWriter.writeAttribute("opacity", "0");
1011 stylesWriter.writeAttribute("sodipodi:nodetypes", textShape->nodeTypes());
1012 stylesWriter.writeEndElement();
1013 }
1014
1015
1016 // disable auto-formatting to avoid axtra spaces appearing here and there
1017 svgWriter.setAutoFormatting(false);
1018
1019 svgWriter.writeStartElement("text");
1020
1021 QVariantHash editor = loadFallback? textObject.value("/Editor").toHash() : textObject.value("/Model").toHash();
1022 QString text = "";
1023 if (editor.isEmpty()) {
1024 d->errors << "No editor dict found in PSD engine data";
1025 return false;
1026 } else {
1027 text = editor.value("/Text").toString();
1028 text.replace("\r", "\n"); // return, used for paragraph hard breaks.
1029 text.replace(QChar(0x03), "\n"); // end of text character, used for non-paragraph hard breaks.
1030 }
1031
1032 int antiAliasing = 0;
1033 antiAliasing = loadFallback? textObject.value("/AntiAlias").toInt()
1034 : textObject.value("/StorySheet").toHash().value("/AntiAlias").toInt();
1035 //0 = None, 4 = Sharp, 1 = Crisp, 2 = Strong, 3 = Smooth
1036 if (antiAliasing == 3) {
1037 svgWriter.writeAttribute("text-rendering", "auto");
1038 } else if (antiAliasing == 0) {
1039 svgWriter.writeAttribute("text-rendering", "OptimizeSpeed");
1040 }
1041
1042 QVariantHash paragraphRun = loadFallback? textObject.value("/ParagraphRun").toHash() : editor.value("/ParagraphRun").toHash();
1043 if (!paragraphRun.isEmpty()) {
1044 //QVariantList runLengthArray = paragraphRun.value("RunLengthArray").toList();
1045 QVariantList runArray = paragraphRun.value("/RunArray").toList();
1046 QString features = loadFallback? "/Properties": "/Features";
1047 QVariantHash style = loadFallback? runArray.value(0).toHash() : runArray.value(0).toHash().value("/RunData").toHash();
1048 QVariantHash parasheet = loadFallback? runArray.value(0).toHash()["/ParagraphSheet"].toHash():
1049 runArray.at(0).toHash()["/RunData"].toHash()["/ParagraphSheet"].toHash();
1050 QVariantHash styleSheet = parasheet[features].toHash();
1051
1052 QString lang;
1053 QString styleString = stylesForPSDParagraphSheet(styleSheet, lang, fontNames, scaleToPt, imageCs);
1054 if (!lang.isEmpty()) {
1055 svgWriter.writeAttribute("xml:lang", lang);
1056 }
1057 if (textType < 2) {
1058 if (textShape) {
1059 offsetByAscent = false;
1060 paragraphStyle += " shape-inside:url(#textShape);";
1061 if (shapePadding > 0) {
1062 QPointF sPadding = scaleToPt.map(QPointF(shapePadding, shapePadding));
1063 paragraphStyle += " shape-padding:"+QString::number(sPadding.x())+";";
1064 }
1065 } else if (styleString.contains("text-align:justify") && bounds.isValid()) {
1066 offsetByAscent = false;
1067 paragraphStyle += " shape-inside:url(#bounds);";
1068 } else if (bounds.isValid()){
1069 offsetByAscent = true;
1070 offset = isHorizontal? bounds.topLeft(): bounds.topRight();
1071 if (styleString.contains("text-anchor:middle")) {
1072 offset = isHorizontal? QPointF(bounds.center().x(), offset.y()):
1073 QPointF(offset.x(), bounds.center().y());
1074 } else if (styleString.contains("text-anchor:end")) {
1075 offset = isHorizontal? QPointF(bounds.right(), offset.y()):
1076 QPointF(offset.x(), bounds.bottom());
1077 }
1078 paragraphStyle += inlineSizeString;
1079 svgWriter.writeAttribute("transform", QString("translate(%1, %2)").arg(offset.x()).arg(offset.y()));
1080 }
1081 }
1082 paragraphStyle += styleString;
1083 svgWriter.writeAttribute("style", paragraphStyle);
1084
1085 }
1086
1087 bool textPathCreated = false;
1088 if (textShape && textType == 2) {
1089 svgWriter.writeStartElement("textPath");
1090 textPathCreated = true;
1091 svgWriter.writeAttribute("path", textShape->toString());
1092 if (reversed) {
1093 svgWriter.writeAttribute("side", "right");
1094 }
1095 svgWriter.writeAttribute("startOffset", QString::number(textPathStartOffset)+"%");
1096 }
1097
1098 QVariantHash styleRun = loadFallback? textObject.value("/StyleRun").toHash(): editor.value("/StyleRun").toHash();
1099 if (styleRun.isEmpty()) {
1100 d->errors << "No styleRun dict found in PSD engine data";
1101 return false;
1102 } else {
1103 QString features = loadFallback? "/StyleSheetData": "/Features";
1104 QVariantList runLengthArray = styleRun.value("/RunLengthArray").toList();
1105 QVariantList runArray = styleRun.value("/RunArray").toList();
1106 if (runArray.isEmpty()) {
1107 d->errors << "No styleRun dict found in PSD engine data";
1108 return false;
1109 } else {
1110 QVariantHash style = loadFallback? runArray.at(0).toHash() : runArray.at(0).toHash()["/RunData"].toHash();
1111 QVariantHash styleSheet = style.value("/StyleSheet").toHash().value(features).toHash();
1112 int length = 0;
1113 int pos = 0;
1114 for (int i = 0; i < runArray.size(); i++) {
1115 style = loadFallback? runArray.at(i).toHash() : runArray.at(i).toHash()["/RunData"].toHash();
1116 int l = loadFallback? runLengthArray.at(i).toInt(): runArray.at(i).toHash().value("/Length").toInt();
1117
1118 QVariantHash newStyleSheet = style.value("/StyleSheet").toHash().value(features).toHash();
1119 if (newStyleSheet == styleSheet) {
1120 length += l;
1121 } else {
1122 svgWriter.writeStartElement("tspan");
1123 QString lang;
1124 svgWriter.writeAttribute("style", stylesForPSDStyleSheet(lang, styleSheet, fontNames, scaleToPt, imageCs));
1125 if (!lang.isEmpty()) {
1126 svgWriter.writeAttribute("xml:lang", lang);
1127 }
1128 svgWriter.writeCharacters(text.mid(pos, length));
1129 svgWriter.writeEndElement();
1130 styleSheet = newStyleSheet;
1131 pos += length;
1132 length = l;
1133 }
1134 }
1135 svgWriter.writeStartElement("tspan");
1136 QString lang;
1137 svgWriter.writeAttribute("style", stylesForPSDStyleSheet(lang, styleSheet, fontNames, scaleToPt, imageCs));
1138 if (!lang.isEmpty()) {
1139 svgWriter.writeAttribute("xml:lang", lang);
1140 }
1141 svgWriter.writeCharacters(text.mid(pos));
1142 svgWriter.writeEndElement();
1143 }
1144 }
1145
1146 if (textPathCreated) {
1147 svgWriter.writeEndElement();
1148 }
1149
1150 svgWriter.writeEndElement();//text root element.
1151 stylesWriter.writeEndElement();
1152
1153 if (svgWriter.hasError() || stylesWriter.hasError()) {
1154 d->errors << i18n("Unknown error writing SVG text element");
1155 return false;
1156 }
1157 *svgText = QString::fromUtf8(svgBuffer.data()).trimmed();
1158 *svgStyles = QString::fromUtf8(styleBuffer.data()).trimmed();
1159
1160 return true;
1161}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
QPointF p2
QPointF p3
QPointF p1
QList< QString > QStringList
QPair< int, int > KoPathPointIndex
Definition KoPathShape.h:28
KoCSSFontInfo getCssDataForPostScriptName(const QString postScriptName, QString *foundPostScriptName)
static KoFontRegistry * instance()
The position of a path point within a path shape.
Definition KoPathShape.h:63
KoPathPoint * lineTo(const QPointF &p)
Adds a new line segment.
void closeMerge()
Closes the current subpath.
KoPathPoint * moveTo(const QPointF &p)
Starts a new Subpath.
KoPathPoint * curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p)
Adds a new cubic Bezier curve segment.
QString stylesForPSDStyleSheet(QString &lang, QVariantHash PSDStyleSheet, QMap< int, KoCSSFontInfo > fontNames, QTransform scale, const KoColorSpace *imageCs)
QString stylesForPSDParagraphSheet(QVariantHash PSDParagraphSheet, QString &lang, QMap< int, KoCSSFontInfo > fontNames, QTransform scaleToPt, const KoColorSpace *imageCs)
#define bounds(x, a, b)
double toDouble(const quint8 *data, int channelpos)
The KoCSSFontInfo class Convenience struct to make it easier to use KoFontRegistry....
QStringList families

References bounds, KoPathShape::closeMerge(), KoPathShape::curveTo(), d, KoCSSFontInfo::families, KoFontRegistry::getCssDataForPostScriptName(), KoFontRegistry::instance(), length(), KoPathShape::lineTo(), KoPathShape::moveTo(), p1, p2, p3, stylesForPSDParagraphSheet(), stylesForPSDStyleSheet(), and toDouble().

◆ convertToPSDTextEngineData()

bool PsdTextDataConverter::convertToPSDTextEngineData ( const QString & svgText,
QRectF & boundingBox,
const QList< KoShape * > & shapesInside,
QVariantHash & txt2,
int & textIndex,
QString & textTotal,
bool & isHorizontal,
QTransform scaleToPx = QTransform() )

< 0 point, 1 paragraph, 2 text-on-path.

Definition at line 1519 of file psd_text_data_converter.cpp.

1526{
1527 QVariantHash root;
1528
1529 QVariantHash model;
1530 QVariantHash view;
1531
1532 QString text;
1533 QVariantList styles;
1534 QVariantList fontSet;
1535
1536 QVariantList textObjects = txt2.value("/DocumentObjects").toHash().value("/TextObjects").toList();
1537 QVariantHash defaultParagraphProps = txt2.value("/DocumentObjects").toHash().value("/OriginalNormalParagraphFeatures").toHash();
1538
1539 const int tIndex = textObjects.size();
1540 QVariantHash docResources = txt2.value("/DocumentResources").toHash();
1541 QVariantList textFrames = docResources.value("/TextFrameSet").toHash().value("/Resources").toList();
1542 const QVariantList resFontSet = docResources.value("/FontSet").toHash().value("/Resources").toList();
1543
1544 Q_FOREACH(const QVariant entry, resFontSet) {
1545 const QVariantHash docFont = entry.toHash().value("/Resource").toHash();
1546 QVariantHash font = docFont.value("/Identifier").toHash();
1547 fontSet.append(font);
1548 }
1549
1550 QVector<int> lengths;
1551 QVector<int> fontIndices;
1552 gatherFonts(KoSvgTextProperties::defaultProperties().convertToSvgTextAttributes(), "", fontSet, lengths, fontIndices);
1553
1554 // go down the document children to get the style.
1555 QDomDocument doc;
1556 doc.setContent(svgText);
1557 gatherStyles(doc.documentElement(), text, QVariantHash(), QMap<QString, QString>(), styles, fontSet, scaleToPx);
1558
1559 QString inlineSize;
1560 QVariantHash paragraphStyle = gatherParagraphStyle(doc.documentElement(),
1561 defaultParagraphProps,
1562 isHorizontal, &inlineSize,
1563 scaleToPx);
1564
1565 text += '\n';
1566 model.insert("/Text", text);
1567
1568 QVariantHash paragraphSet;
1569 paragraphSet.insert("/Length", QVariant(text.length()));
1570 paragraphSet.insert("/RunData", QVariantHash{{"/ParagraphSheet", paragraphStyle}});
1571
1572 model.insert("/ParagraphRun", QVariantHash{{"/RunArray", QVariantList({paragraphSet})}});
1573
1574 QVariantHash styleRun;
1575 QVariantList properStyleRun;
1576 Q_FOREACH(QVariant entry, styles) {
1577 properStyleRun.append(entry);
1578 }
1579 styleRun.insert("/RunArray", properStyleRun);
1580
1581 model.insert("/StyleRun", styleRun);
1582
1583 QVariantHash storySheet;
1584 storySheet.insert("/UseFractionalGlyphWidths", true);
1585 storySheet.insert("/AntiAlias", 1);
1586 model.insert("/StorySheet", storySheet);
1587
1588 QRectF bounds;
1589 if (!(inlineSize.isEmpty() || inlineSize == "auto")) {
1590 bounds = boundingBox;
1591 bool ok;
1592 double inlineSizeVal = inlineSize.toDouble(&ok);
1593 if (ok) {
1594 if (isHorizontal) {
1595 bounds.setWidth(inlineSizeVal);
1596 } else {
1597 bounds.setHeight(inlineSizeVal);
1598 }
1599 }
1600 } else {
1601 bounds = QRectF();
1602 }
1603
1604 int shapeType = bounds.isEmpty()? 0: 1;
1605 int writingDirection = isHorizontal? 0: 2;
1606
1607
1608 const int textFrameIndex = textFrames.size();
1609 QVariantHash newTextFrame;
1610 QVariantHash newTextFrameData;
1611 newTextFrameData.insert("/LineOrientation", writingDirection);
1612
1613
1614 QList<QPointF> points;
1615
1616 QScopedPointer<KoPathShape> textShape;
1617 Q_FOREACH(KoShape *shape, shapesInside) {
1618 KoPathShape *p = dynamic_cast<KoPathShape*>(shape);
1619 if (p) {
1620 textShape.reset(p);
1621 break;
1622 }
1623 }
1624 if (textShape) {
1625 for (int i = 0; i<textShape->subpathPointCount(0); i++) {
1626 KoPathSegment s = textShape->segmentByIndex(KoPathPointIndex(0, i));
1627 points.append(s.first()->point());
1628 points.append(s.first()->controlPoint2());
1629 points.append(s.second()->controlPoint1());
1630 points.append(s.second()->point());
1631 }
1632 } else if (!bounds.isEmpty()) {
1633 points.append(bounds.topLeft());
1634 points.append(bounds.topLeft());
1635 points.append(bounds.topRight());
1636 points.append(bounds.topRight());
1637 points.append(bounds.topRight());
1638 points.append(bounds.topRight());
1639 points.append(bounds.bottomRight());
1640 points.append(bounds.bottomRight());
1641 points.append(bounds.bottomRight());
1642 points.append(bounds.bottomRight());
1643 points.append(bounds.bottomLeft());
1644 points.append(bounds.bottomLeft());
1645 points.append(bounds.bottomLeft());
1646 points.append(bounds.bottomLeft());
1647 points.append(bounds.topLeft());
1648 points.append(bounds.topLeft());
1649 }
1650 if (!points.isEmpty()) {
1651 QVariantList p;
1652 for(int i = 0; i < points.size(); i++) {
1653 QPointF p2 = scaleToPx.map(points.at(i));
1654 p.append(p2.x());
1655 p.append(p2.y());
1656 }
1657 newTextFrame.insert("/Bezier", QVariantHash({{"/Points", p}}));
1658 shapeType = 1;
1659 }
1660 newTextFrameData.insert("/Type", shapeType);
1661 newTextFrame.insert("/Data", newTextFrameData);
1662
1663 view.insert("/Frames", QVariantList({QVariantHash({{"/Resource", textFrameIndex}})}));
1664
1665 QVariantList bbox = {0.0, 0.0, bounds.width(), bounds.height()};
1666 QVariantList bbox2 = {bounds.left(), bounds.top(), bounds.right(), bounds.bottom()};
1667
1668 /*
1669 QVariantHash glyphStrike {
1670 {"/Bounds", bbox},
1671 {"/GlyphAdjustments", QVariantHash({{"/Data", QVariantList()}, {"/RunLengths", QVariantList()}})},
1672 {"/Glyphs", QVariantList()},
1673 {"/Invalidation", bbox},
1674 {"/RenderedBounds", bbox},
1675 {"/VisualBounds", bbox},
1676 {"/SelectionAscent", 10.0},
1677 {"/SelectionDescent", -10.0},
1678 {"/ShadowStylesRun", QVariantHash({{"/Data", QVariantList()}, {"/RunLengths", QVariantList()}})},
1679 {"/StreamTag", "/GlyphStrike"},
1680 {"/Transform", QVariantHash({{"/Origin", QVariantList({0.0, 0.0})}})}
1681 };
1682 QVariantHash frameStrike {
1683 {"/Bounds", QVariantList({0.0, 0.0, 0.0, 0.0})},
1684 {"/ChildProcession", 2},
1685 {"/Children", QVariantList({glyphStrike})},
1686 {"/StreamTag", "/FrameStrike"},
1687 {"/Frame", textFrameIndex},
1688 {"/Transform", QVariantHash({{"/Origin", QVariantList({0.0, 0.0})}})}
1689 };
1690 QVariantHash pathStrike {
1691 {"/Bounds", QVariantList({0.0, 0.0, 0.0, 0.0})},
1692 {"/ChildProcession", 0},
1693 {"/Children", QVariantList({frameStrike})},
1694 {"/StreamTag", "/PathSelectGroupCharacter"},
1695 {"/Transform", QVariantHash({{"/Origin", QVariantList({0.0, 0.0})}})}
1696 };
1697 view.insert("/Strikes", QVariantList({pathStrike}));*/
1698 QVariantHash rendered {
1699 {"/RunData", QVariantHash({{"/LineCount", 1}})},
1700 {"/Length", textTotal.length()}
1701 };
1702 view.insert("/RenderedData", QVariantHash({{"/RunArray", QVariantList({rendered})}}));
1703
1704
1705 textFrames.append(QVariantHash({{"/Resource", newTextFrame}}));
1706 textObjects.append(QVariantHash({{"/Model", model}, {"/View", view}}));
1707
1708 // default resource dict
1709
1710 textTotal = text;
1711
1712 QVariantList newFontSet;
1713
1714 Q_FOREACH(const QVariant entry, fontSet) {
1715 newFontSet.append(QVariantHash({{"/Resource", QVariantHash({{"/StreamTag", "/CoolTypeFont"}, {"/Identifier", entry}})}}));
1716 }
1717
1718 QVariantHash docObjects = txt2.value("/DocumentObjects").toHash();
1719 docObjects.insert("/TextObjects", textObjects);
1720 txt2.insert("/DocumentObjects", docObjects);
1721 docResources.insert("/TextFrameSet", QVariantHash({{"/Resources", textFrames}}));
1722 docResources.insert("/FontSet", QVariantHash({{"/Resources", newFontSet}}));
1723 txt2.insert("/DocumentResources", docResources);
1724 textIndex = tIndex;
1725
1726 return true;
1727}
const Params2D p
QPointF point
QPointF controlPoint1
QPointF controlPoint2
A KoPathSegment consist of two neighboring KoPathPoints.
KoPathPoint * first
KoPathPoint * second
static const KoSvgTextProperties & defaultProperties()
QVariantHash gatherParagraphStyle(QDomElement el, QVariantHash defaultProperties, bool &isHorizontal, QString *inlineSize, QTransform scaleToPx)
void gatherFonts(const QMap< QString, QString > cssStyles, const QString text, QVariantList &fontSet, QVector< int > &lengths, QVector< int > &fontIndices)
void gatherStyles(QDomElement el, QString &text, QVariantHash parentStyle, QMap< QString, QString > parentCssStyles, QVariantList &styles, QVariantList &fontSet, QTransform scaleToPx)

References bounds, KoPathPoint::controlPoint1, KoPathPoint::controlPoint2, KoSvgTextProperties::defaultProperties(), KoPathSegment::first, gatherFonts(), gatherParagraphStyle(), gatherStyles(), p, p2, KoPathPoint::point, and KoPathSegment::second.

◆ errors()

QStringList PsdTextDataConverter::errors ( ) const

A list of errors happened during loading the user's text

Definition at line 1729 of file psd_text_data_converter.cpp.

1730{
1731 return d->errors;
1732}

References d.

◆ gatherFonts()

void PsdTextDataConverter::gatherFonts ( const QMap< QString, QString > cssStyles,
const QString text,
QVariantList & fontSet,
QVector< int > & lengths,
QVector< int > & fontIndices )
private

Definition at line 1165 of file psd_text_data_converter.cpp.

1166 {
1167 if (cssStyles.contains("font-family")) {
1168 QStringList families = cssStyles.value("font-family").split(",");
1169 int fontSize = cssStyles.value("font-size", "10").toInt();
1170 int fontWeight = cssStyles.value("font-weight", "400").toInt();
1171 int fontWidth = cssStyles.value("font-stretch", "100").toInt();
1172
1173 KoCSSFontInfo fontInfo;
1174 fontInfo.families = families;
1175 fontInfo.size = fontSize;
1176 fontInfo.weight = fontWeight;
1177 fontInfo.width = fontWidth;
1178 const std::vector<FT_FaceSP> faces = KoFontRegistry::instance()->facesForCSSValues(lengths, fontInfo,
1179 text, 72, 72);
1180
1181 for (uint i = 0; i < faces.size(); i++) {
1182 const FT_FaceSP &face = faces.at(static_cast<size_t>(i));
1183 QString postScriptName = face->family_name;
1184 if (FT_Get_Postscript_Name(face.data())) {
1185 postScriptName = FT_Get_Postscript_Name(face.data());
1186 }
1187
1188 int fontIndex = -1;
1189 for(int j=0; j<fontSet.size(); j++) {
1190 if (fontSet[j].toHash()["/Name"] == postScriptName) {
1191 fontIndex = j;
1192 break;
1193 }
1194 }
1195 if (fontIndex < 0) {
1196 QVariantHash font;
1197 font["/Name"] = postScriptName;
1198 font["/Type"] = 1;
1199 fontSet.append(font);
1200 fontIndex = fontSet.size()-1;
1201 }
1202 fontIndices << fontIndex;
1203 }
1204 }
1205}
unsigned int uint
std::vector< FT_FaceSP > facesForCSSValues(QVector< int > &lengths, KoCSSFontInfo info=KoCSSFontInfo(), const QString &text="", quint32 xRes=72, quint32 yRes=72, bool disableFontMatching=false, const QString &language=QString())
facesForCSSValues This selects a font with fontconfig using the given values. If "text" is not empty ...

References KisLibraryResourcePointer< T, P >::data(), KoFontRegistry::facesForCSSValues(), KoCSSFontInfo::families, KoFontRegistry::instance(), KoCSSFontInfo::size, KoCSSFontInfo::weight, and KoCSSFontInfo::width.

◆ gatherParagraphStyle()

QVariantHash PsdTextDataConverter::gatherParagraphStyle ( QDomElement el,
QVariantHash defaultProperties,
bool & isHorizontal,
QString * inlineSize,
QTransform scaleToPx )
private

Definition at line 1461 of file psd_text_data_converter.cpp.

1465 {
1466 QString cssStyle = el.attribute("style");
1467 QStringList dummy = cssStyle.split(";");
1468 QMap<QString, QString> cssStyles;
1469 Q_FOREACH(QString style, dummy) {
1470 QString key = style.split(":").first().trimmed();
1471 QString val = style.split(":").last().trimmed();
1472 cssStyles.insert(key, val);
1473 }
1474 for (int i = 0; i < el.attributes().length(); i++) {
1475 const QDomAttr attr = el.attributes().item(i).toAttr();
1476 cssStyles.insert(attr.name(), attr.value());
1477 }
1478 int alignVal = 0;
1479 int anchorVal = 0;
1480
1481 QVariantHash paragraphStyleSheet = defaultProperties;
1482 Q_FOREACH(QString key, cssStyles.keys()) {
1483 QString val = cssStyles.value(key);
1484
1485 if (key == "text-align") {
1486 if (val == "start") {alignVal = 0;}
1487 if (val == "center") {alignVal = 2;}
1488 if (val == "end") {alignVal = 1;}
1489 if (val == "justify start") {alignVal = 3;}
1490 if (val == "justify center") {alignVal = 4;}
1491 if (val == "justify end") {alignVal = 5;}
1492 if (val == "justify") {alignVal = 6;}
1493 } else if (key == "text-anchor") {
1494 if (val == "start") {anchorVal = 0;}
1495 if (val == "middle") {anchorVal = 2;}
1496 if (val == "end") {anchorVal = 1;}
1497 } else if (key == "writing-mode") {
1498 if (val == "horizontal-tb") {
1499 isHorizontal = true;
1500 } else {
1501 isHorizontal = false;
1502 }
1503 } else if (key == "direction") {
1504 paragraphStyleSheet["/ParagraphDirection"] = val == "ltr"? 0 :1;
1505 } else if (key == "line-height") {
1506 paragraphStyleSheet["/AutoLeading"] = val.toDouble();
1507 } else if (key == "inline-size") {
1508 *inlineSize = val;
1509 }
1510 }
1511 if (cssStyles.keys().contains("shape-inside")) {
1512 paragraphStyleSheet["/Justification"] = alignVal;
1513 } else {
1514 paragraphStyleSheet["/Justification"] = anchorVal;
1515 }
1516 return QVariantHash{{"/Name", ""}, {"/Parent", 0}, {"/Features", paragraphStyleSheet}};
1517}

References length().

◆ gatherStyles()

void PsdTextDataConverter::gatherStyles ( QDomElement el,
QString & text,
QVariantHash parentStyle,
QMap< QString, QString > parentCssStyles,
QVariantList & styles,
QVariantList & fontSet,
QTransform scaleToPx )
private

Definition at line 1405 of file psd_text_data_converter.cpp.

1409 {
1410 QMap<QString, QString> cssStyles = parentCssStyles;
1411 if (el.hasAttribute("style")) {
1412 QString style = el.attribute("style");
1413 QStringList dummy = style.split(";");
1414
1415 Q_FOREACH(QString style, dummy) {
1416 QString key = style.split(":").first().trimmed();
1417 QString val = style.split(":").last().trimmed();
1418 cssStyles.insert(key, val);
1419 }
1420 Q_FOREACH(QString attribute, KoSvgTextProperties::supportedXmlAttributes()) {
1421 if (el.hasAttribute(attribute)) {
1422 cssStyles.insert(attribute, el.attribute(attribute));
1423 }
1424 }
1425 }
1426
1427 if (el.firstChild().isText()) {
1428 QDomText textNode = el.firstChild().toText();
1429 QString currentText = textNode.data();
1430 text += currentText;
1431
1432 QVariantHash styleDict = styleToPSDStylesheet(cssStyles, parentStyle, scaleToPx);
1433 gatherFills(el, styleDict);
1434
1435 QVector<int> lengths;
1436 QVector<int> fontIndices;
1437 gatherFonts(cssStyles, currentText, fontSet, lengths, fontIndices);
1438 for (int i = 0; i< fontIndices.size(); i++) {
1439 QVariantHash curDict = styleDict;
1440 curDict["/Font"] = fontIndices.at(i);
1441 QVariantHash fDict = {
1442 {"/StyleSheet", QVariantHash({{"/Name", ""}, {"/Parent", 0}, {"/Features", curDict}})}
1443 };
1444 styles.append(QVariantHash({
1445 {"/Length", lengths.at(i)},
1446 {"/RunData", fDict},
1447 }));
1448 }
1449
1450 } else if (el.childNodes().size()>0) {
1451 QVariantHash styleDict = styleToPSDStylesheet(cssStyles, parentStyle, scaleToPx);
1452 gatherFills(el, styleDict);
1453 QDomElement childEl = el.firstChildElement();
1454 while(!childEl.isNull()) {
1455 gatherStyles(childEl, text, styleDict, cssStyles, styles, fontSet, scaleToPx);
1456 childEl = childEl.nextSiblingElement();
1457 }
1458 }
1459}
static QStringList supportedXmlAttributes()
QVariantHash styleToPSDStylesheet(const QMap< QString, QString > cssStyles, QVariantHash parentStyle, QTransform scaleToPx)
void gatherFills(QDomElement el, QVariantHash &styleDict)

References gatherFills(), gatherFonts(), gatherStyles(), styleToPSDStylesheet(), and KoSvgTextProperties::supportedXmlAttributes().

◆ stylesForPSDParagraphSheet()

QString PsdTextDataConverter::stylesForPSDParagraphSheet ( QVariantHash PSDParagraphSheet,
QString & lang,
QMap< int, KoCSSFontInfo > fontNames,
QTransform scaleToPt,
const KoColorSpace * imageCs )
private

Definition at line 629 of file psd_text_data_converter.cpp.

629 {
630 QStringList styles;
631 QStringList unsupportedStyles;
632
633 for (int i=0; i < PSDParagraphSheet.keys().size(); i++) {
634 const QString key = PSDParagraphSheet.keys().at(i);
635 double val = PSDParagraphSheet.value(key).toDouble();
636 if (key == "/Justification") {
637 QString textAlign = "start";
638 QString textAnchor = "start";
639 switch (PSDParagraphSheet.value(key).toInt()) {
640 case 0:
641 textAlign = "start";
642 textAnchor = "start";
643 break;
644 case 1:
645 textAlign = "end";
646 textAnchor = "end";
647 break;
648 case 2:
649 textAlign = "center";
650 textAnchor = "middle";
651 break;
652 case 3:
653 textAlign = "justify start";
654 textAnchor = "start";
655 break;
656 case 4:
657 textAlign = "justify end"; // guess
658 textAnchor = "end";
659 break;
660 case 5:
661 textAlign = "justify center"; // guess
662 textAnchor = "middle";
663 break;
664 case 6:
665 textAlign = "justify";
666 textAnchor = "middle";
667 break;
668 default:
669 textAlign = "start";
670 }
671
672 styles.append("text-align:"+textAlign);
673 styles.append("text-anchor:"+textAnchor);
674 } else if (key == "/FirstLineIndent") { //-1296..1296
675 val = scaleToPt.map(QPointF(val, val)).x();
676 styles.append("text-indent:"+QString::number(val));
677 continue;
678 } else if (key == "/StartIndent") {
679 // left margin (also for rtl?), pixels -1296..1296
680 unsupportedStyles << key;
681 continue;
682 } else if (key == "/EndIndent") {
683 // right margin (also for rtl?), pixels -1296..1296
684 unsupportedStyles << key;
685 continue;
686 } else if (key == "/SpaceBefore") {
687 // top margin for paragraph, pixels -1296..1296
688 unsupportedStyles << key;
689 continue;
690 } else if (key == "/SpaceAfter") {
691 // bottom margin for paragraph, pixels -1296..1296
692 unsupportedStyles << key;
693 continue;
694 } else if (key == "/AutoHyphenate") {
695 // hyphenate: auto;
696 unsupportedStyles << key;
697 continue;
698 } else if (key == "/HyphenatedWordSize") {
699 // minimum wordsize at which to start hyphenating. 2-25
700 unsupportedStyles << key;
701 continue;
702 } else if (key == "/PreHyphen") {
703 // minimum number of letters before hyphenation is allowed to start in a word. 1-15
704 // CSS-Text-4 hyphenate-limit-chars value 1.
705 unsupportedStyles << key;
706 continue;
707 } else if (key == "/PostHyphen") {
708 // minimum amount of letters a hyphnated word is allowed to end with. 1-15
709 // CSS-Text-4 hyphenate-limit-chars value 2.
710 unsupportedStyles << key;
711 continue;
712 } else if (key == "/ConsecutiveHyphens") {
713 // maximum consecutive lines with hyphenation. 2-25
714 // CSS-Text-4 hyphenate-limit-lines.
715 unsupportedStyles << key;
716 continue;
717 } else if (key == "/HyphenateCapitalized") {
718 unsupportedStyles << key;
719 continue;
720 } else if (key == "/HyphenationPreference") {
721 unsupportedStyles << key;
722 continue;
723 } else if (key == "/SingleWordJustification") {
724 unsupportedStyles << key;
725 continue;
726 } else if (key == "/Zone") {
727 // Hyphenation zone to control where hyphenation is allowed to start, pixels. 0..8640 for 72ppi
728 // CSS-Text-4 hyphenation-limit-zone.
729 unsupportedStyles << key;
730 continue;
731 } else if (key == "/WordSpacing") {
732 // val 0 is minimum allowed spacing, and val 2 is maximum allowed spacing, both for justified text.
733 // 0 to 1000%, 100% default.
734 unsupportedStyles << key;
735 continue;
736 } else if (key == "/LetterSpacing") {
737 // val 0 is minimum allowed spacing, and val 2 is maximum allowed spacing, both for justified text.
738 // -100% to 500%, 0% default.
739 unsupportedStyles << key;
740 continue;
741 } else if (key == "/GlyphSpacing") {
742 // scaling of the glyphs, list of vals, 50% to 200%, default 100%.
743 unsupportedStyles << key;
744 continue;
745 } else if (key == "/AutoLeading") {
746 styles.append("line-height:"+QString::number(val));
747 continue;
748 } else if (key == "/LeadingType") {
749 // Probably how leading is measured for asian glyphs.
750 // 0 = top-to-top, 1 = bottom-to-bottom. CSS can only do the second.
751 unsupportedStyles << key;
752 continue;
753 } else if (key == "/Hanging") {
754 // Roman hanging punctuation (?), bool
755 continue;
756 } else if (key == "/Burasagari" || key == "/BurasagariType") {
757 // CJK hanging punctuation, bool
758 // options are none, regular (allow-end) and force (force-end).
759 if (PSDParagraphSheet.value(key).toBool()) {
760 styles.append("hanging-punctuation:allow-end");
761 }
762 continue;
763 } else if (key == "/Kinsoku") {
764 // line breaking strictness.
765 unsupportedStyles << key;
766 continue;
767 } else if (key == "/KinsokuOrder") {
768 // might be 0 = pushInFirst, 1 = pushOutFirst, 2 = pushOutOnly, if so, Krita only supports 2.
769 unsupportedStyles << key;
770 continue;
771 } else if (key == "/EveryLineComposer") {
772 // bool representing which text-wrapping method to use.
773 //'single-line' is 'stable/greedy' line breaking,
774 //'everyline' uses a penalty based system like Knuth's method.
775 unsupportedStyles << key;
776 continue;
777 } else if (key == "/ComposerEngine") {
778 unsupportedStyles << key;
779 continue;
780 } else if (key == "/KurikaeshiMojiShori") {
781 unsupportedStyles << key;
782 continue;
783 } else if (key == "/MojiKumiTable") {
784 unsupportedStyles << key;
785 continue;
786 } else if (key == "/DropCaps") {
787 unsupportedStyles << key;
788 continue;
789 } else if (key == "/TabStops" || key == "/AutoTCY" || key == "/KeepTogether" ) {
790 unsupportedStyles << key;
791 continue;
792 } else if (key == "/ParagraphDirection") {
793 switch (PSDParagraphSheet.value(key).toInt()) {
794 case 1:
795 styles.append("direction:rtl");
796 break;
797 case 0:
798 styles.append("direction:ltr");
799 break;
800 default:
801 break;
802 }
803 } else if (key == "/DefaultTabWidth") {
804 unsupportedStyles << key;
805 continue;
806 } else if (key == "/DefaultStyle") {
807 styles.append(stylesForPSDStyleSheet(lang, PSDParagraphSheet.value(key).toHash(), fontNames, scaleToPt, imageCs));
808 } else {
809 d->warnings << QString("Unknown PSD character stylesheet style key, %1: %2").arg(key).arg(PSDParagraphSheet.value(key).toString());
810 }
811 }
812 d->warnings << QString("Unsupported paragraph styles: %1").arg(unsupportedStyles.join(","));
813
814 return styles.join("; ");
815}
int size(const Forest< T > &forest)
Definition KisForest.h:1232

References d, and stylesForPSDStyleSheet().

◆ stylesForPSDStyleSheet()

QString PsdTextDataConverter::stylesForPSDStyleSheet ( QString & lang,
QVariantHash PSDStyleSheet,
QMap< int, KoCSSFontInfo > fontNames,
QTransform scale,
const KoColorSpace * imageCs )
private

Definition at line 119 of file psd_text_data_converter.cpp.

119 {
120 QStringList styles;
121
122 QStringList unsupportedStyles;
123
124 int weight = 400;
125 bool italic = false;
126 QStringList textDecor;
127 QStringList baselineShift;
128 QStringList fontVariantLigatures;
129 QStringList fontVariantNumeric;
130 QStringList fontVariantCaps;
131 QStringList fontVariantEastAsian;
132 QStringList fontFeatureSettings;
133 QString underlinePos;
134 for (int i=0; i < PSDStyleSheet.keys().size(); i++) {
135 const QString key = PSDStyleSheet.keys().at(i);
136 if (key == "/Font") {
137 KoCSSFontInfo fontInfo = fontNames.value(PSDStyleSheet.value(key).toInt());
138 weight = fontInfo.weight;
139 italic = italic? true: fontInfo.slantMode != QFont::StyleNormal;
140 styles.append("font-family:"+fontInfo.families.join(","));
141 if (fontInfo.width != 100) {
142 styles.append("font-width:"+QString::number(fontInfo.width));
143 }
144 continue;
145 } else if (key == "/FontSize") {
146 double val = PSDStyleSheet.value(key).toDouble();
147 val = scale.map(QPointF(val, val)).y();
148 styles.append("font-size:"+QString::number(val));
149 continue;
150 } else if (key == "/AutoKerning" || key == "/AutoKern") {
151 if (!PSDStyleSheet.value(key).toBool()) {
152 styles.append("font-kerning: none");
153 }
154 continue;
155 } else if (key == "/Kerning") {
156 // adjusts kerning value, we don't support this.
157 unsupportedStyles << key;
158 continue;
159 } else if (key == "/FauxBold") {
160 if (PSDStyleSheet.value(key).toBool()) {
161 weight = 700;
162 }
163 continue;
164 } else if (key == "/FauxItalic") {
165 if (PSDStyleSheet.value(key).toBool()) {
166 italic = true;
167 }
168 // synthetic Italic, bool
169 continue;
170 } else if (key == "/Leading") {
171 bool autoleading = true;
172 if (PSDStyleSheet.keys().contains("AutoLeading")) {
173 autoleading = PSDStyleSheet.value("AutoLeading").toBool();
174 }
175 if (!autoleading) {
176 double fontSize = PSDStyleSheet.value("FontSize").toDouble();
177 double val = PSDStyleSheet.value(key).toDouble();
178 styles.append("line-height:"+QString::number(val/fontSize));
179 }
180 // value for line-height
181 continue;
182 } else if (key == "/HorizontalScale" || key == "/VerticalScale") {
183 // adjusts scale glyphs, we don't support this.
184 unsupportedStyles << key;
185 continue;
186 } else if (key == "/Tracking") {
187 // tracking is in 1/1000 of an EM (as is kerning for that matter...)
188 double letterSpacing = (0.001 * PSDStyleSheet.value(key).toDouble());
189 styles.append("letter-spacing:"+QString::number(letterSpacing)+"em");
190 continue;
191 } else if (key == "/BaselineShift") {
192 if (PSDStyleSheet.value(key).toDouble() > 0) {
193 double val = PSDStyleSheet.value(key).toDouble();
194 val = scale.map(QPointF(val, val)).y();
195 baselineShift.append(QString::number(val));
196 }
197 continue;
198 } else if (key == "/FontCaps") {
199 switch (PSDStyleSheet.value(key).toInt()) {
200 case 0:
201 break;
202 case 1:
203 fontVariantCaps.append("all-small-caps");
204 break;
205 case 2:
206 styles.append("text-transform:uppercase");
207 break;
208 default:
209 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
210 }
211 continue;
212 } else if (key == "/FontBaseline") {
213 // NOTE: This might also be better done with font-variant-position, though
214 // we don't support synthetic font stuff, including super and sub script.
215 // Actually, seems like this is specifically font-synthesis
216 switch (PSDStyleSheet.value(key).toInt()) {
217 case 0:
218 break;
219 case 1:
220 baselineShift.append("super");
221 break;
222 case 2:
223 baselineShift.append("sub");
224 break;
225 default:
226 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
227 }
228 continue;
229 } else if (key == "/FontOTPosition") {
230 // NOTE: This might also be better done with font-variant-position, though
231 // we don't support synthetic font stuff, including super and sub script.
232 switch (PSDStyleSheet.value(key).toInt()) {
233 case 0:
234 break;
235 case 1:
236 styles.append("font-variant-position:super");
237 break;
238 case 2:
239 styles.append("font-variant-position:sub");
240 break;
241 case 3:
242 fontFeatureSettings.append("'numr' 1");
243 break;
244 case 4:
245 fontFeatureSettings.append("'dnum' 1");
246 break;
247 default:
248 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
249 }
250 continue;
251 } else if (key == "/Underline") {
252 if (PSDStyleSheet.value(key).toBool()) {
253 textDecor.append("underline");
254 }
255 continue;
256 } else if (key == "/UnderlinePosition") {
257 switch (PSDStyleSheet.value(key).toInt()) {
258 case 0:
259 break;
260 case 1:
261 textDecor.append("underline");
262 underlinePos = "auto left";
263 break;
264 case 2:
265 textDecor.append("underline");
266 underlinePos = "auto right";
267 break;
268 default:
269 d->warnings << QString("Unknown value for %1: %1").arg(key).arg(PSDStyleSheet.value(key).toString());
270 }
271 continue;
272 } else if (key == "/YUnderline") {
273 // Option relating to vertical underline left or right
274 if (PSDStyleSheet.value(key).toInt() == 1) {
275 underlinePos = "auto left";
276 } else if (PSDStyleSheet.value(key).toInt() == 0) {
277 underlinePos = "auto right";
278 }
279 continue;
280 } else if (key == "/Strikethrough" || key == "/StrikethroughPosition") {
281 if (PSDStyleSheet.value(key).toBool()) {
282 textDecor.append("line-through");
283 }
284 continue;
285 } else if (key == "/Ligatures") {
286 if (!PSDStyleSheet.value(key).toBool()) {
287 fontVariantLigatures.append("no-common-ligatures");
288 }
289 continue;
290 } else if (key == "/DLigatures" || key == "/DiscretionaryLigatures" || key == "/AlternateLigatures") {
291 if (PSDStyleSheet.value(key).toBool()) {
292 fontVariantLigatures.append("discretionary-ligatures");
293 }
294 continue;
295 } else if (key == "/ContextualLigatures") {
296 if (PSDStyleSheet.value(key).toBool()) {
297 fontVariantLigatures.append("contextual");
298 }
299 continue;
300 } else if (key == "/Fractions") {
301 if (PSDStyleSheet.value(key).toBool()) {
302 fontVariantNumeric.append("diagonal-fractions");
303 }
304 continue;
305 } else if (key == "/Ordinals") {
306 if (PSDStyleSheet.value(key).toBool()) {
307 fontVariantNumeric.append("ordinal");
308 }
309 continue;
310 } else if (key == "/Swash") {
311 if (PSDStyleSheet.value(key).toBool()) {
312 fontFeatureSettings.append("'swsh' 1");
313 }
314 continue;
315 } else if (key == "/Titling") {
316 if (PSDStyleSheet.value(key).toBool()) {
317 fontVariantCaps.append("titling-caps");
318 }
319 continue;
320 } else if (key == "/StylisticAlternates") {
321 if (PSDStyleSheet.value(key).toBool()) {
322 fontFeatureSettings.append("'salt' 1");
323 }
324 continue;
325 } else if (key == "/Ornaments") {
326 if (PSDStyleSheet.value(key).toBool()) {
327 fontFeatureSettings.append("'ornm' 1");
328 }
329 continue;
330 } else if (key == "/OldStyle") {
331 if (PSDStyleSheet.value(key).toBool() && !fontVariantNumeric.contains("oldstyle-nums")) {
332 fontVariantNumeric.append("oldstyle-nums");
333 }
334 continue;
335 } else if (key == "/FigureStyle") {
336 switch (PSDStyleSheet.value(key).toInt()) {
337 case 0:
338 break;
339 case 1:
340 fontVariantNumeric.append("tabular-nums");
341 fontVariantNumeric.append("lining-nums");
342 break;
343 case 2:
344 fontVariantNumeric.append("proportional-nums");
345 fontVariantNumeric.append("oldstyle-nums");
346 break;
347 case 3:
348 fontVariantNumeric.append("proportional-nums");
349 fontVariantNumeric.append("lining-nums");
350 break;
351 case 4:
352 fontVariantNumeric.append("tabular-nums");
353 fontVariantNumeric.append("oldstyle-nums");
354 break;
355 default:
356 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
357 }
358 continue;
359 } else if (key == "/Italics") {
360 // This is an educated guess: other italic happens via postscript name.
361 if (PSDStyleSheet.value(key).toBool()) {
362 fontFeatureSettings.append("'ital' 1");
363 }
364 continue;
365 } else if (key == "/BaselineDirection") {
366 int val = PSDStyleSheet.value(key).toInt();
367 if (val == 1) {
368 styles.append("text-orientation: upright");
369 } else if (val == 2) {
370 styles.append("text-orientation: mixed");
371 } else if (val == 3) { //TCY or tate-chu-yoko
372 styles.append("text-combine-upright: all");
373 } else {
374 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
375 }
376 continue;
377 } else if (key == "/Tsume" || key == "/LeftAki" || key == "/RightAki" || key == "/JiDori") {
378 // Reduce spacing around a single character. Partially related to text-spacing,
379 // Tsume is reduction, Aki expansion, and both can be used as part of Mojikumi
380 // However, in this particular case, the property seems to just reduce the space
381 // of a single character, and may not be possible to support (as in CSS that'd
382 // just be padding/margin-reduction, but SVG cannot do that).
383 unsupportedStyles << key;
384 continue;
385 } else if (key == "/StyleRunAlignment") {
386 // 3 = roman
387 // 5 = em-box top/right, 2 = em-box center, 0 = em-box bottom/left
388 // 4 = icf-top/right, 1 icf-bottom/left?
389 QString dominantBaseline;
390 switch(PSDStyleSheet.value(key).toInt()) {
391 case 3:
392 dominantBaseline = "alphabetic";
393 break;
394 case 2:
395 dominantBaseline = "center";
396 break;
397 case 0:
398 dominantBaseline = "ideographic";
399 break;
400 case 4:
401 dominantBaseline = "text-top";
402 break;
403 case 1:
404 dominantBaseline = "text-bottom";
405 break;
406 default:
407 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
408 dominantBaseline = QString();
409 }
410 if (!dominantBaseline.isEmpty()) {
411 styles.append("dominant-baseline: "+dominantBaseline);
412 styles.append("alignment-baseline: "+dominantBaseline);
413 }
414 continue;
415 } else if (key == "/Language") {
416 int val = PSDStyleSheet.value(key).toInt();
417 if (psdLanguageMap.keys().contains(val)) {
418 lang = psdLanguageMap.value(val);
419 } else {
420 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
421 }
422 continue;
423 } else if (key == "/ProportionalMetrics") {
424 if (PSDStyleSheet.value(key).toBool()) {
425 fontFeatureSettings.append("'palt' 1");
426 }
427 continue;
428 } else if (key == "/Kana") {
429 if (PSDStyleSheet.value(key).toBool()) {
430 fontFeatureSettings.append("'hkna' 1");
431 }
432 continue;
433 } else if (key == "/Ruby") {
434 if (PSDStyleSheet.value(key).toBool()) {
435 fontVariantEastAsian.append("ruby");
436 }
437 } else if (key == "/JapaneseAlternateFeature") {
438 // hojo kanji - 'hojo'
439 // nlc kanji - 'nlck'
440 // alternate notation - nalt
441 // proportional kana - 'pkna'
442 // vertical kana - 'vkna'
443 // vert alt+rot - vrt2, or vert + vrtr
444 int val = PSDStyleSheet.value(key).toInt();
445 if (val == 0) {
446 continue;
447 } else if (val == 1) { // japanese traditional - 'tnam'/'trad'
448 fontVariantEastAsian.append("traditional");
449 } else if (val == 2) { // japanese expert - 'expt'
450 fontFeatureSettings.append("'expt' 1");
451 } else if (val == 3) { // Japanese 78 - jis78
452 fontVariantEastAsian.append("jis78");
453 } else {
454 d->warnings << QString("Unknown value for %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
455 }
456 continue;
457 } else if (key == "/NoBreak") {
458 // Prevents word from breaking... I guess word-break???
459 if (PSDStyleSheet.value(key).toBool()) {
460 styles.append("word-break: keep-all");
461 }
462 continue;
463 } else if (key == "/DirOverride") {
464 QString dir = PSDStyleSheet.value(key).toBool()? "rtl": "ltr";
465 if (PSDStyleSheet.value(key).toBool()) {
466 styles.append("direction: "+dir);
467 styles.append("unicode-bidi: isolate");
468 }
469 continue;
470 } else if (key == "/FillColor") {
471 bool fill = true;
472 if (PSDStyleSheet.keys().contains("/FillFlag")) {
473 fill = PSDStyleSheet.value("/FillFlag").toBool();
474 }
475 if (fill) {
476 QVariantHash color = PSDStyleSheet.value(key).toHash();
477 styles.append("fill:"+colorFromPSDStyleSheet(color, imageCs).name());
478 } else {
479 styles.append("fill:none");
480 }
481 } else if (key == "/StrokeColor") {
482 bool fill = true;
483 if (PSDStyleSheet.keys().contains("/StrokeFlag")) {
484 fill = PSDStyleSheet.value("/StrokeFlag").toBool();
485 }
486 if (fill) {
487 QVariantHash color = PSDStyleSheet.value(key).toHash();
488 styles.append("stroke:"+colorFromPSDStyleSheet(color, imageCs).name());
489 } else {
490 styles.append("stroke:none");
491 }
492 continue;
493 } else if (key == "/OutlineWidth" || key == "/LineWidth") {
494 double val = PSDStyleSheet.value(key).toDouble();
495 val = scale.map(QPointF(val, val)).y();
496 styles.append("stroke-width:"+QString::number(val));
497 } else if (key == "/FillFirst") {
498 // draw fill on top of stroke? paint-order: stroke markers fill, I guess.
499 if (PSDStyleSheet.value(key).toBool()) {
500 styles.append("paint-order: fill");
501 }
502 continue;
503 } else if (key == "/HindiNumbers") {
504 // bool. Looks like this automatically selects hindi numbers for arabic. There also
505 // seems to be a more complex option to automatically have arabic numbers for hebrew, and an option for farsi numbers, but this might be a different bool altogether.
506 unsupportedStyles << key;
507 continue;
508 } else if (key == "/Kashida") {
509 // number, s related to drawing/inserting Kashida/Tatweel into Arabic justified text... We don't support this.
510 // options are none, short, medium, long, stylistic, indesign apparently has a 'naskh' option, which is what toggles jalt usage.
511 unsupportedStyles << key;
512 continue;
513 } else if (key == "/DiacriticPos") {
514 // number, which is odd, because it looks like it should be a point.
515 // this controls how high or low the diacritic is on arabic text.
516 unsupportedStyles << key;
517 continue;
518 } else if (key == "/SlashedZero") {
519 // font-variant: common-ligatures
520 if (PSDStyleSheet.value(key).toBool()) {
521 fontVariantNumeric.append("slashed-zero");
522 }
523 continue;
524 } else if (key == "/StylisticSets") {
525 int flags = PSDStyleSheet.value(key).toInt();
526 for (int i = 1; i <= 20; i++) {
527 const int bit = 2^(i-1);
528 const QString tag = i > 9? QString("ss%1").arg(i):QString("ss0%1").arg(i);
529 if (flags & bit) {
530 fontFeatureSettings.append(QString("\'%1\' 1").arg(tag));
531 }
532 }
533 continue;
534 } else if (key == "/LineCap") {
535 switch (PSDStyleSheet.value(key).toInt()) {
536 case 0:
537 styles.append("stroke-linecap: butt");
538 break;
539 case 1:
540 styles.append("stroke-linecap: round");
541 break;
542 case 2:
543 styles.append("stroke-linecap: square");
544 break;
545 default:
546 styles.append("stroke-linecap: butt");
547 }
548 } else if (key == "/LineJoin") {
549 switch (PSDStyleSheet.value(key).toInt()) {
550 case 0:
551 styles.append("stroke-linejoin: miter");
552 break;
553 case 1:
554 styles.append("stroke-linejoin: round");
555 break;
556 case 2:
557 styles.append("stroke-linejoin: bevel");
558 break;
559 default:
560 styles.append("stroke-linejoin: miter");
561 }
562 } else if (key == "/MiterLimit") {
563 styles.append("stroke-miterlimit: "+PSDStyleSheet.value(key).toString());
564 //} else if (key == "/LineDashArray") {
565 //"stroke-dasharray"
566 } else if (key == "/LineDashOffset") {
567 styles.append("stroke-dashoffset: "+PSDStyleSheet.value(key).toString());
568 } else if (key == "/EnableWariChu" || key == "/WariChuWidowAmount" || key == "/WariChuLineGap" || key == "/WariChuJustification"
569 || key == "/WariChuOrphanAmount" || key == "/WariChuLineCount" || key == "/WariChuSubLineAmount") {
570 // Inline cutting note features.
571 unsupportedStyles << key;
572 continue;
573 } else if (key == "/TCYUpDownAdjustment" || key == "/TCYLeftRightAdjustment") {
574 // Extra text-combine-upright stuff we don't support.
575 unsupportedStyles << key;
576 continue;
577 } else if (key == "/Type1EncodingNames" || key == "/ConnectionForms") {
578 // no clue what these are
579 unsupportedStyles << key;
580 continue;
581 } else if (key == "/FillOverPrint" || key == "/StrokeOverPrint" || key == "/Blend") {
582 // Fill stuff we don't support.
583 unsupportedStyles << key;
584 continue;
585 } else if (key == "/UnderlineOffset") {
586 // Needs css text-decor-4 features
587 unsupportedStyles << key;
588 continue;
589 } else {
590 if (key != "/FillFlag" && key != "/StrokeFlag" && key != "/AutoLeading") {
591 d->warnings << QString("Unknown PSD character stylesheet style key, %1: %2").arg(key).arg(PSDStyleSheet.value(key).toString());
592 }
593 }
594 }
595 if (weight != 400) {
596 styles.append("font-weight:"+QString::number(weight));
597 }
598 if (italic) {
599 styles.append("font-style:italic");
600 }
601 if (!textDecor.isEmpty()) {
602 styles.append("text-decoration:"+textDecor.join(" "));
603 }
604 if (!baselineShift.isEmpty()) {
605 styles.append("baseline-shift:"+baselineShift.join(" "));
606 }
607 if (!fontVariantLigatures.isEmpty()) {
608 styles.append("font-variant-ligatures:"+fontVariantLigatures.join(" "));
609 }
610 if (!fontVariantNumeric.isEmpty()) {
611 styles.append("font-variant-numeric:"+fontVariantNumeric.join(" "));
612 }
613 if (!fontVariantCaps.isEmpty()) {
614 styles.append("font-variant-caps:"+fontVariantCaps.join(" "));
615 }
616 if (!fontVariantEastAsian.isEmpty()) {
617 styles.append("font-variant-east-asian:"+fontVariantEastAsian.join(" "));
618 }
619 if (!fontFeatureSettings.isEmpty()) {
620 styles.append("font-feature-settings:"+fontFeatureSettings.join(", "));
621 }
622 if (!underlinePos.isEmpty()) {
623 styles.append("text-decoration-position:"+underlinePos);
624 }
625 d->warnings << QString("Unsupported styles: %1").arg(unsupportedStyles.join(","));
626 return styles.join("; ");
627}
QColor colorFromPSDStyleSheet(QVariantHash color, const KoColorSpace *imageCs)
const char * name(StandardAction id)
static QHash< int, QString > psdLanguageMap
QFont::Style slantMode

References colorFromPSDStyleSheet(), d, KoCSSFontInfo::families, psdLanguageMap, KoCSSFontInfo::slantMode, KoCSSFontInfo::weight, and KoCSSFontInfo::width.

◆ styleToPSDStylesheet()

QVariantHash PsdTextDataConverter::styleToPSDStylesheet ( const QMap< QString, QString > cssStyles,
QVariantHash parentStyle,
QTransform scaleToPx )
private

Definition at line 1207 of file psd_text_data_converter.cpp.

1208 {
1209 QVariantHash styleSheet = parentStyle;
1210
1211 Q_FOREACH(QString key, cssStyles.keys()) {
1212 QString val = cssStyles.value(key);
1213
1214 if (key == "font-size") {
1215 double size = val.toDouble();
1216 size = scaleToPx.map(QPointF(size, size)).x();
1217 styleSheet["/FontSize"] = size;
1218 } else if (key == "letter-spacing") {
1219 double space = val.toDouble();
1220 space = scaleToPx.map(QPointF(space, space)).x();
1221 double size = styleSheet["/FontSize"].toDouble();
1222 styleSheet["/Tracking"] = (space/size) * 1000.0;
1223 } else if (key == "line-height") {
1224 double space = val.toDouble();
1225 double size = styleSheet["/FontSize"].toDouble();
1226 styleSheet["/Leading"] = (space*size);
1227 styleSheet["/AutoLeading"] = false;
1228 } else if (key == "font-kerning") {
1229 if (val == "none") {
1230 styleSheet["/AutoKern"] = 0;
1231 }
1232 } else if (key == "baseline-shift") {
1233 if (val == "super") {
1234 styleSheet["/FontBaseline"] = 1;
1235 } else if (val == "super") {
1236 styleSheet["/FontBaseline"] = 2;
1237 } else {
1238 double offset = val.toDouble();
1239 offset = scaleToPx.map(QPointF(offset, offset)).y();
1240 styleSheet["/BaselineShift"] = offset;
1241 }
1242 } else if (key == "text-decoration") {
1243 QStringList decor = val.split(" ");
1244 Q_FOREACH(QString param, decor) {
1245 if (param == "underline") {
1246 styleSheet["/UnderlinePosition"] = 1;
1247 if (cssStyles.value("text-decoration-position").contains("right")) {
1248 styleSheet["/UnderlinePosition"] = 2;
1249 }
1250 } else if (param == "line-through"){
1251 styleSheet["/StrikethroughPosition"] = 1;
1252 }
1253 }
1254 } else if (key == "font-variant") {
1255 QStringList params = val.split(" ");
1256 bool tab = params.contains("tabular-nums");
1257 bool old = params.contains("oldstyle-nums");
1258 Q_FOREACH(QString param, params) {
1259 if (param == "small-caps" || param == "all-small-caps") {
1260 styleSheet["/FontCaps"] = 1;
1261 } else if (param == "titling-caps") {
1262 styleSheet["/Titling"] = true;
1263 } else if (param == "no-common-ligatures"){
1264 styleSheet["/Ligatures"] = false;
1265 } else if (param == "discretionary-ligatures"){
1266 styleSheet["/DiscretionaryLigatures"] = true;
1267 } else if (param == "contextual"){
1268 styleSheet["/ContextualLigatures"] = true;
1269 } else if (param == "diagonal-fractions"){
1270 styleSheet["/Fractions"] = true;
1271 } else if (param == "ordinal"){
1272 styleSheet["/Ordinals"] = true;
1273 } else if (param == "slashed-zero"){
1274 styleSheet["/SlashedZero"] = true;
1275 } else if (param == "super") {
1276 styleSheet["/FontOTPosition"] = 1;
1277 } else if (param == "sub") {
1278 styleSheet["/FontOTPosition"] = 2;
1279 } else if (param == "ruby") {
1280 styleSheet["/Ruby"] = true;
1281 } else if (param == "traditional") {
1282 styleSheet["/JapaneseAlternateFeature"] = 1;
1283 } else if (param == "jis78") {
1284 styleSheet["/JapaneseAlternateFeature"] = 3;
1285 }
1286 }
1287 styleSheet["/OldStyle"] = old;
1288 if (tab && old) {
1289 styleSheet["/FigureStyle"] = 4;
1290 } else if (tab) {
1291 styleSheet["/FigureStyle"] = 1;
1292 } else if (old) {
1293 styleSheet["/FigureStyle"] = 2;
1294 }
1295 } else if (key == "font-feature-settings") {
1296 QStringList params = val.split(",");
1297 Q_FOREACH(QString param, params) {
1298 if (param.trimmed() == "'swsh' 1") {
1299 styleSheet["/Swash"] = true;
1300 } else if (param.trimmed() == "'titl' 1") {
1301 styleSheet["/Titling"] = true;
1302 } else if (param.trimmed() == "'salt' 1") {
1303 styleSheet["/StylisticAlternates"] = true;
1304 } else if (param.trimmed() == "'ornm' 1") {
1305 styleSheet["/Ornaments"] = true;
1306 } else if (param.trimmed() == "'ital' 1") {
1307 styleSheet["/Italics"] = true;
1308 } else if (param.trimmed() == "'numr' 1") {
1309 styleSheet["/FontOTPosition"] = 3;
1310 } else if (param.trimmed() == "'dnum' 1") {
1311 styleSheet["/FontOTPosition"] = 4;
1312 } else if (param.trimmed() == "'expt' 1") {
1313 styleSheet["/JapaneseAlternateFeature"] = 2;
1314 } else if (param.trimmed() == "'hkna' 1") {
1315 styleSheet["/Kana"] = true;
1316 } else if (param.trimmed() == "'palt' 1") {
1317 styleSheet["/ProportionalMetrics"] = true;
1318 }
1319 }
1320 } else if (key == "text-orientation") {
1321 if (val == "upright") {
1322 styleSheet["/BaselineDirection"] = 1;
1323 } else if (val == "mixed") {
1324 styleSheet["/BaselineDirection"] = 2;
1325 }
1326 } else if (key == "text-combine-upright") {
1327 if (val == "all") {
1328 styleSheet["/BaselineDirection"] = 3;
1329 }
1330 } else if (key == "word-break") {
1331 styleSheet["/NoBreak"] = val == "keep-all";
1332 } else if (key == "direction") {
1333 styleSheet["/DirOverride"] = val == "ltr"? 0 :1;
1334 } else if (key == "xml:lang") {
1335 if (psdLanguageMap.values().contains(val)) {
1336 styleSheet["/Language"] = psdLanguageMap.key(val);
1337 }
1338 } else if (key == "paint-order") {
1339 QStringList decor = val.split(" ");
1340 styleSheet["/FillFirst"] = decor.first() == "fill";
1341 } else {
1342 d->errors << "Unsupported css-style:" << key << val;
1343 }
1344 }
1345
1346 return styleSheet;
1347}

References d, and psdLanguageMap.

◆ warnings()

QStringList PsdTextDataConverter::warnings ( ) const

A list of warnings produced during loading the user's text

Definition at line 1734 of file psd_text_data_converter.cpp.

1735{
1736 return d->warnings;
1737}

References d.

Member Data Documentation

◆ d

const QScopedPointer<Private> PsdTextDataConverter::d
private

Definition at line 73 of file psd_text_data_converter.h.


The documentation for this class was generated from the following files: