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 QScopedPointer<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.data());
962 }
963 if (!range.isEmpty()) {
964 textPathStartOffset = range[0].toDouble();
965 int segment = qFloor(textPathStartOffset);
966 double t = textPathStartOffset - segment;
967 double length = 0;
968 double totalLength = 0;
969 for (int i=0; i<textShape->subpathPointCount(0); i++) {
970 double l = textShape->segmentByIndex(KoPathPointIndex(0, i)).length();
971 totalLength += l;
972 if (i < segment) {
973 length += l;
974 } else if (i == segment) {
975 length += textShape->segmentByIndex(KoPathPointIndex(0, i)).lengthAt(t);
976 }
977 }
978 textPathStartOffset = (length/totalLength) * 100.0;
979 }
980 }
981 }
982 }
983 }
984 QString paragraphStyle = isHorizontal? "writing-mode: horizontal-tb;": "writing-mode: vertical-rl;";
985 paragraphStyle += " white-space: pre-wrap;";
986
987 QBuffer svgBuffer;
988 QBuffer styleBuffer;
989 svgBuffer.open(QIODevice::WriteOnly);
990 styleBuffer.open(QIODevice::WriteOnly);
991
992 QXmlStreamWriter svgWriter(&svgBuffer);
993 QXmlStreamWriter stylesWriter(&styleBuffer);
994 stylesWriter.writeStartElement("defs");
995 if (bounds.isValid()) {
996 stylesWriter.writeStartElement("rect");
997 stylesWriter.writeAttribute("id", "bounds");
998 stylesWriter.writeAttribute("x", QString::number(bounds.x()));
999 stylesWriter.writeAttribute("y", QString::number(bounds.y()));
1000 stylesWriter.writeAttribute("width", QString::number(bounds.width()));
1001 stylesWriter.writeAttribute("height", QString::number(bounds.height()));
1002 stylesWriter.writeEndElement();
1003 }
1004 if (textShape) {
1005 stylesWriter.writeStartElement("path");
1006 stylesWriter.writeAttribute("id", "textShape");
1007 stylesWriter.writeAttribute("d", textShape->toString());
1008 stylesWriter.writeAttribute("sodipodi:nodetypes", textShape->nodeTypes());
1009 stylesWriter.writeEndElement();
1010 }
1011
1012
1013 // disable auto-formatting to avoid axtra spaces appearing here and there
1014 svgWriter.setAutoFormatting(false);
1015
1016 svgWriter.writeStartElement("text");
1017
1018 QVariantHash editor = loadFallback? textObject.value("/Editor").toHash() : textObject.value("/Model").toHash();
1019 QString text = "";
1020 if (editor.isEmpty()) {
1021 d->errors << "No editor dict found in PSD engine data";
1022 return false;
1023 } else {
1024 text = editor.value("/Text").toString();
1025 text.replace("\r", "\n"); // return, used for paragraph hard breaks.
1026 text.replace(QChar(0x03), "\n"); // end of text character, used for non-paragraph hard breaks.
1027 }
1028
1029 int antiAliasing = 0;
1030 antiAliasing = loadFallback? textObject.value("/AntiAlias").toInt()
1031 : textObject.value("/StorySheet").toHash().value("/AntiAlias").toInt();
1032 //0 = None, 4 = Sharp, 1 = Crisp, 2 = Strong, 3 = Smooth
1033 if (antiAliasing == 3) {
1034 svgWriter.writeAttribute("text-rendering", "auto");
1035 } else if (antiAliasing == 0) {
1036 svgWriter.writeAttribute("text-rendering", "OptimizeSpeed");
1037 }
1038
1039 QVariantHash paragraphRun = loadFallback? textObject.value("/ParagraphRun").toHash() : editor.value("/ParagraphRun").toHash();
1040 if (!paragraphRun.isEmpty()) {
1041 //QVariantList runLengthArray = paragraphRun.value("RunLengthArray").toList();
1042 QVariantList runArray = paragraphRun.value("/RunArray").toList();
1043 QString features = loadFallback? "/Properties": "/Features";
1044 QVariantHash style = loadFallback? runArray.value(0).toHash() : runArray.value(0).toHash().value("/RunData").toHash();
1045 QVariantHash parasheet = loadFallback? runArray.value(0).toHash()["/ParagraphSheet"].toHash():
1046 runArray.at(0).toHash()["/RunData"].toHash()["/ParagraphSheet"].toHash();
1047 QVariantHash styleSheet = parasheet[features].toHash();
1048
1049 QString lang;
1050 QString styleString = stylesForPSDParagraphSheet(styleSheet, lang, fontNames, scaleToPt, imageCs);
1051 if (!lang.isEmpty()) {
1052 svgWriter.writeAttribute("xml:lang", lang);
1053 }
1054 if (textType < 2) {
1055 if (textShape) {
1056 offsetByAscent = false;
1057 paragraphStyle += " shape-inside:url(#textShape);";
1058 if (shapePadding > 0) {
1059 QPointF sPadding = scaleToPt.map(QPointF(shapePadding, shapePadding));
1060 paragraphStyle += " shape-padding:"+QString::number(sPadding.x())+";";
1061 }
1062 } else if (styleString.contains("text-align:justify") && bounds.isValid()) {
1063 offsetByAscent = false;
1064 paragraphStyle += " shape-inside:url(#bounds);";
1065 } else if (bounds.isValid()){
1066 offsetByAscent = true;
1067 offset = isHorizontal? bounds.topLeft(): bounds.topRight();
1068 if (styleString.contains("text-anchor:middle")) {
1069 offset = isHorizontal? QPointF(bounds.center().x(), offset.y()):
1070 QPointF(offset.x(), bounds.center().y());
1071 } else if (styleString.contains("text-anchor:end")) {
1072 offset = isHorizontal? QPointF(bounds.right(), offset.y()):
1073 QPointF(offset.x(), bounds.bottom());
1074 }
1075 paragraphStyle += inlineSizeString;
1076 svgWriter.writeAttribute("transform", QString("translate(%1, %2)").arg(offset.x()).arg(offset.y()));
1077 }
1078 }
1079 paragraphStyle += styleString;
1080 svgWriter.writeAttribute("style", paragraphStyle);
1081
1082 }
1083
1084 bool textPathCreated = false;
1085 if (textShape && textType == 2) {
1086 svgWriter.writeStartElement("textPath");
1087 textPathCreated = true;
1088 svgWriter.writeAttribute("path", textShape->toString());
1089 if (reversed) {
1090 svgWriter.writeAttribute("side", "right");
1091 }
1092 svgWriter.writeAttribute("startOffset", QString::number(textPathStartOffset)+"%");
1093 }
1094
1095 QVariantHash styleRun = loadFallback? textObject.value("/StyleRun").toHash(): editor.value("/StyleRun").toHash();
1096 if (styleRun.isEmpty()) {
1097 d->errors << "No styleRun dict found in PSD engine data";
1098 return false;
1099 } else {
1100 QString features = loadFallback? "/StyleSheetData": "/Features";
1101 QVariantList runLengthArray = styleRun.value("/RunLengthArray").toList();
1102 QVariantList runArray = styleRun.value("/RunArray").toList();
1103 if (runArray.isEmpty()) {
1104 d->errors << "No styleRun dict found in PSD engine data";
1105 return false;
1106 } else {
1107 QVariantHash style = loadFallback? runArray.at(0).toHash() : runArray.at(0).toHash()["/RunData"].toHash();
1108 QVariantHash styleSheet = style.value("/StyleSheet").toHash().value(features).toHash();
1109 int length = 0;
1110 int pos = 0;
1111 for (int i = 0; i < runArray.size(); i++) {
1112 style = loadFallback? runArray.at(i).toHash() : runArray.at(i).toHash()["/RunData"].toHash();
1113 int l = loadFallback? runLengthArray.at(i).toInt(): runArray.at(i).toHash().value("/Length").toInt();
1114
1115 QVariantHash newStyleSheet = style.value("/StyleSheet").toHash().value(features).toHash();
1116 if (newStyleSheet == styleSheet) {
1117 length += l;
1118 } else {
1119 svgWriter.writeStartElement("tspan");
1120 QString lang;
1121 svgWriter.writeAttribute("style", stylesForPSDStyleSheet(lang, styleSheet, fontNames, scaleToPt, imageCs));
1122 if (!lang.isEmpty()) {
1123 svgWriter.writeAttribute("xml:lang", lang);
1124 }
1125 svgWriter.writeCharacters(text.mid(pos, length));
1126 svgWriter.writeEndElement();
1127 styleSheet = newStyleSheet;
1128 pos += length;
1129 length = l;
1130 }
1131 }
1132 svgWriter.writeStartElement("tspan");
1133 QString lang;
1134 svgWriter.writeAttribute("style", stylesForPSDStyleSheet(lang, styleSheet, fontNames, scaleToPt, imageCs));
1135 if (!lang.isEmpty()) {
1136 svgWriter.writeAttribute("xml:lang", lang);
1137 }
1138 svgWriter.writeCharacters(text.mid(pos));
1139 svgWriter.writeEndElement();
1140 }
1141 }
1142
1143 if (textPathCreated) {
1144 svgWriter.writeEndElement();
1145 }
1146
1147 svgWriter.writeEndElement();//text root element.
1148 stylesWriter.writeEndElement();
1149
1150 if (svgWriter.hasError() || stylesWriter.hasError()) {
1151 d->errors << i18n("Unknown error writing SVG text element");
1152 return false;
1153 }
1154 *svgText = QString::fromUtf8(svgBuffer.data()).trimmed();
1155 *svgStyles = QString::fromUtf8(styleBuffer.data()).trimmed();
1156
1157 return true;
1158}
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
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, d, KoCSSFontInfo::families, KoFontRegistry::getCssDataForPostScriptName(), KoFontRegistry::instance(), length(), 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 1516 of file psd_text_data_converter.cpp.

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

1727{
1728 return d->errors;
1729}

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 1162 of file psd_text_data_converter.cpp.

1163 {
1164 if (cssStyles.contains("font-family")) {
1165 QStringList families = cssStyles.value("font-family").split(",");
1166 int fontSize = cssStyles.value("font-size", "10").toInt();
1167 int fontWeight = cssStyles.value("font-weight", "400").toInt();
1168 int fontWidth = cssStyles.value("font-stretch", "100").toInt();
1169
1170 KoCSSFontInfo fontInfo;
1171 fontInfo.families = families;
1172 fontInfo.size = fontSize;
1173 fontInfo.weight = fontWeight;
1174 fontInfo.width = fontWidth;
1175 const std::vector<FT_FaceSP> faces = KoFontRegistry::instance()->facesForCSSValues(lengths, fontInfo,
1176 text, 72, 72);
1177
1178 for (uint i = 0; i < faces.size(); i++) {
1179 const FT_FaceSP &face = faces.at(static_cast<size_t>(i));
1180 QString postScriptName = face->family_name;
1181 if (FT_Get_Postscript_Name(face.data())) {
1182 postScriptName = FT_Get_Postscript_Name(face.data());
1183 }
1184
1185 int fontIndex = -1;
1186 for(int j=0; j<fontSet.size(); j++) {
1187 if (fontSet[j].toHash()["/Name"] == postScriptName) {
1188 fontIndex = j;
1189 break;
1190 }
1191 }
1192 if (fontIndex < 0) {
1193 QVariantHash font;
1194 font["/Name"] = postScriptName;
1195 font["/Type"] = 1;
1196 fontSet.append(font);
1197 fontIndex = fontSet.size()-1;
1198 }
1199 fontIndices << fontIndex;
1200 }
1201 }
1202}
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 1458 of file psd_text_data_converter.cpp.

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

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 1402 of file psd_text_data_converter.cpp.

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

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

References d, and psdLanguageMap.

◆ warnings()

QStringList PsdTextDataConverter::warnings ( ) const

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

Definition at line 1731 of file psd_text_data_converter.cpp.

1732{
1733 return d->warnings;
1734}

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: