r18832 by fschmid - ODG-Importer: first support for Custom Shapes, still not complete yet, but a lot of shapes are already useable.

scribus-commit scribus-commit at lists.scribus.net
Sat Feb 22 21:39:31 UTC 2014


Author: fschmid
Date: Sat Feb 22 21:39:31 2014
New Revision: 18832

URL: http://scribus.net/websvn/listing.php?repname=Scribus&sc=1&rev=18832
Log:
ODG-Importer: first support for Custom Shapes, still not complete yet, but a lot of shapes are already useable.

Modified:
    trunk/Scribus/scribus/plugins/import/odg/importodg.cpp
    trunk/Scribus/scribus/plugins/import/odg/importodg.h

Modified: trunk/Scribus/scribus/plugins/import/odg/importodg.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=18832&path=/trunk/Scribus/scribus/plugins/import/odg/importodg.cpp
==============================================================================
--- trunk/Scribus/scribus/plugins/import/odg/importodg.cpp (original)
+++ trunk/Scribus/scribus/plugins/import/odg/importodg.cpp Sat Feb 22 21:39:31 2014
@@ -34,6 +34,7 @@
 
 #include "importodg.h"
 #include "fileloader.h"
+#include "fparser.h"
 #include "loadsaveplugin.h"
 #include "pageitem_table.h"
 #include "pagesize.h"
@@ -608,8 +609,171 @@
 		retObj = parseFrame(draw);
 	else if (draw.tagName() == "draw:measure")
 		retObj = parseMeasure(draw);
+	else if (draw.tagName() == "draw:custom-shape")
+		retObj = parseCustomShape(draw);
 	else
 		qDebug() << "Unhandled Tag" << draw.tagName();
+	return retObj;
+}
+
+PageItem* OdgPlug::parseCustomShape(QDomElement &e)
+{
+	ObjStyle tmpOStyle;
+	PageItem *retObj = NULL;
+	QList<PageItem*> GElements;
+	double x = parseUnit(e.attribute("svg:x"));
+	double y = parseUnit(e.attribute("svg:y")) ;
+	double w = parseUnit(e.attribute("svg:width"));
+	double h = parseUnit(e.attribute("svg:height"));
+	resovleStyle(tmpOStyle, e.attribute("draw:style-name"));
+	if ((tmpOStyle.fill_type == 0) && (tmpOStyle.stroke_type == 0))
+		return retObj;
+	for(QDomElement p = e.firstChildElement(); !p.isNull(); p = p.nextSiblingElement())
+	{
+		if (p.tagName() == "draw:enhanced-geometry")
+		{
+			FunctionParser fpa;
+			double vx = 0;
+			double vy = 0;
+			double vw = 1;
+			double vh = 1;
+			parseViewBox(p, &vx, &vy, &vw, &vh);
+			fpa.AddConstant("top", vy);
+			fpa.AddConstant("bottom", vh);
+			fpa.AddConstant("left", vx);
+			fpa.AddConstant("right", vw);
+			fpa.AddConstant("width", vw - vx);
+			fpa.AddConstant("height", vh - vy);
+			fpa.AddConstant("xstretch", parseUnit(e.attribute("draw:path-stretchpoint-x", "0")));
+			fpa.AddConstant("ystretch", parseUnit(e.attribute("draw:path-stretchpoint-y", "0")));
+			fpa.AddConstant("hasfill", tmpOStyle.fill_type == 0 ? 0 : 1);
+			fpa.AddConstant("hasstroke", tmpOStyle.stroke_type == 0 ? 0 : 1);
+			fpa.AddConstant("pi", M_PI);
+			QString enhPath = p.attribute("draw:enhanced-path");
+			QMap<QString, QString> func_Results;
+			QMap<QString, QString> modi_Values;
+			QString mods = p.attribute("draw:modifiers");
+			ScTextStream Code(&mods, QIODevice::ReadOnly);
+			int modCount = 0;
+			while (!Code.atEnd())
+			{
+				double d;
+				Code >> d;
+				QString modName = QString("Const_%1").arg(modCount);
+				fpa.AddConstant(modName.toStdString(), d);
+				modi_Values.insert(QString("$%1").arg(modCount), QString("%1").arg(d));
+				modCount++;
+			}
+			if (p.hasChildNodes())
+			{
+				for(QDomElement f = p.firstChildElement(); !f.isNull(); f = f.nextSiblingElement())
+				{
+					if (f.tagName() == "draw:equation")
+					{
+						QString formName = f.attribute("draw:name");
+						QString formula = f.attribute("draw:formula", "0");
+						formula.replace("$", "Const_");
+						formula.replace("?", "Func_");
+						double erg = 0;
+						int ret = fpa.Parse(formula.toStdString(), "", false);
+						if(ret < 0)
+							erg = fpa.Eval(NULL);
+						func_Results.insert("?" + formName, QString("%1").arg(erg));
+						formName.prepend("Func_");
+						fpa.AddConstant(formName.toStdString(), erg);
+					}
+				}
+			}
+			if (!modi_Values.isEmpty())
+			{
+				QMapIterator<QString, QString> it(modi_Values);
+				it.toBack();
+				while (it.hasPrevious())
+				{
+					it.previous();
+					enhPath.replace(it.key(), it.value());
+				}
+			}
+			if (!func_Results.isEmpty())
+			{
+				QMapIterator<QString, QString> it(func_Results);
+				it.toBack();
+				while (it.hasPrevious())
+				{
+					it.previous();
+					enhPath.replace(it.key(), it.value());
+				}
+			}
+			QStringList paths = enhPath.split("N", QString::SkipEmptyParts);
+			if (!paths.isEmpty())
+			{
+				for (int a = 0; a < paths.count(); a++)
+				{
+					FPointArray pArray;
+					pArray.svgInit();
+					bool filled = true;
+					bool stroked = true;
+					PageItem::ItemType itype = parseEnhPath(paths[a], pArray, filled, stroked) ? PageItem::PolyLine : PageItem::Polygon;
+					if (pArray.size() > 3)
+					{
+						QString fillC = tmpOStyle.CurrColorFill;
+						if (!filled)
+							fillC = CommonStrings::None;
+						QString strokeC = tmpOStyle.CurrColorStroke;
+						if (!stroked)
+							strokeC = CommonStrings::None;
+						int z = m_Doc->itemAdd(itype, PageItem::Unspecified, baseX + x, baseY + y, w, h, tmpOStyle.LineW, fillC, strokeC, true);
+						retObj = m_Doc->Items->at(z);
+						retObj->PoLine = pArray.copy();
+						retObj->setFillEvenOdd(true);
+						QTransform mat;
+						double sx = (vw != 0.0) ? (w / vw) : w;
+						double sy = (vh != 0.0) ? (h / vh) : h;
+						mat.scale(sx, sy);
+						retObj->PoLine.map(mat);
+						if (e.hasAttribute("draw:transform"))
+							parseTransform(&retObj->PoLine, e.attribute("draw:transform"));
+						finishItem(retObj, tmpOStyle);
+						GElements.append(retObj);
+						m_Doc->Items->removeLast();
+					}
+				}
+				if (GElements.count() > 1)
+				{
+					double minx =  std::numeric_limits<double>::max();
+					double miny =  std::numeric_limits<double>::max();
+					double maxx = -std::numeric_limits<double>::max();
+					double maxy = -std::numeric_limits<double>::max();
+					for (int ep = 0; ep < GElements.count(); ++ep)
+					{
+						PageItem* currItem = GElements.at(ep);
+						double x1, x2, y1, y2;
+						currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
+						minx = qMin(minx, x1);
+						miny = qMin(miny, y1);
+						maxx = qMax(maxx, x2);
+						maxy = qMax(maxy, y2);
+					}
+					double gx = minx;
+					double gy = miny;
+					double gw = maxx - minx;
+					double gh = maxy - miny;
+					int z = m_Doc->itemAdd(PageItem::Group, PageItem::Rectangle, gx, gy, gw, gh, 0, CommonStrings::None, CommonStrings::None, true);
+					retObj = m_Doc->Items->at(z);
+					retObj->ClipEdited = true;
+					retObj->FrameType = 3;
+					retObj->setFillEvenOdd(false);
+					retObj->OldB2 = retObj->width();
+					retObj->OldH2 = retObj->height();
+					retObj->updateClip();
+					m_Doc->groupObjectsToItem(retObj, GElements);
+					retObj->OwnPage = m_Doc->OnPage(retObj);
+					m_Doc->GroupOnPage(retObj);
+					m_Doc->Items->removeLast();
+				}
+			}
+		}
+	}
 	return retObj;
 }
 
@@ -2189,6 +2353,257 @@
 	return value;
 }
 
+const char * OdgPlug::getCoord( const char *ptr, double &number )
+{
+	int integer, exponent;
+	double decimal, frac;
+	int sign, expsign;
+
+	exponent = 0;
+	integer = 0;
+	frac = 1.0;
+	decimal = 0;
+	sign = 1;
+	expsign = 1;
+
+	// read the sign
+	if(*ptr == '+')
+		ptr++;
+	else if(*ptr == '-')
+	{
+		ptr++;
+		sign = -1;
+	}
+
+	// read the integer part
+	while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+		integer = (integer * 10) + *(ptr++) - '0';
+	if(*ptr == '.') // read the decimals
+	{
+		ptr++;
+		while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+			decimal += (*(ptr++) - '0') * (frac *= 0.1);
+	}
+
+	if(*ptr == 'e' || *ptr == 'E') // read the exponent part
+	{
+		ptr++;
+
+		// read the sign of the exponent
+		if(*ptr == '+')
+			ptr++;
+		else if(*ptr == '-')
+		{
+			ptr++;
+			expsign = -1;
+		}
+
+		exponent = 0;
+		while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+		{
+			exponent *= 10;
+			exponent += *ptr - '0';
+			ptr++;
+		}
+	}
+	number = integer + decimal;
+	number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
+
+	// skip the following space
+	if(*ptr == ' ')
+		ptr++;
+
+	return ptr;
+}
+
+bool OdgPlug::parseEnhPath(const QString& svgPath, FPointArray &result, bool &fill, bool &stroke)
+{
+	QString d = svgPath;
+	d = d.replace( QRegExp( "," ), " ");
+	bool ret = false;
+	fill = true;
+	stroke = true;
+	if( !d.isEmpty() )
+	{
+		QPainterPath pPath;
+		d = d.simplified();
+		QByteArray pathData = d.toLatin1();
+		const char *ptr = pathData.constData();
+		const char *end = pathData.constData() + pathData.length() + 1;
+		double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
+		double px1, py1, px2, py2, px3, py3;
+		int moveCount = 0;
+		result.svgInit();
+		char command = *(ptr++), lastCommand = ' ';
+		subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
+		while( ptr < end )
+		{
+			if( *ptr == ' ' )
+				ptr++;
+			switch( command )
+			{
+			case 'A':
+			case 'B':
+				{
+					ptr = getCoord( ptr, tox );
+					ptr = getCoord( ptr, toy );
+					ptr = getCoord( ptr, px1 );
+					ptr = getCoord( ptr, py1 );
+					ptr = getCoord( ptr, px2 );
+					ptr = getCoord( ptr, py2 );
+					ptr = getCoord( ptr, px3 );
+					ptr = getCoord( ptr, py3 );
+					double startA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px2, py2)).angle();
+					double endA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px3, py3)).angle();
+					if (command == 'B')
+						pPath.moveTo(px2, py2);
+					pPath.arcTo(QRectF(QPointF(tox, toy), QPointF(px1, py1)), startA, endA - startA);
+					break;
+				}
+			case 'C':
+				{
+					ptr = getCoord( ptr, x1 );
+					ptr = getCoord( ptr, y1 );
+					ptr = getCoord( ptr, x2 );
+					ptr = getCoord( ptr, y2 );
+					ptr = getCoord( ptr, tox );
+					ptr = getCoord( ptr, toy );
+					result.svgCurveToCubic(x1, y1, x2, y2, tox, toy);
+					pPath.cubicTo(x1, y1, x2, y2, tox, toy);
+					contrlx = x2;
+					contrly = y2;
+					curx = tox;
+					cury = toy;
+					break;
+				}
+			case 'F':
+				{
+					fill = false;
+					break;
+				}
+			case 'L':
+				{
+					ptr = getCoord( ptr, tox );
+					ptr = getCoord( ptr, toy );
+					curx = tox;
+					cury = toy;
+					result.svgLineTo( curx, cury );
+					pPath.lineTo(tox, toy);
+					break;
+				}
+			case 'M':
+				{
+					ptr = getCoord( ptr, tox );
+					ptr = getCoord( ptr, toy );
+					subpathx = curx = tox;
+					subpathy = cury = toy;
+					result.svgMoveTo(curx, cury );
+					pPath.moveTo(tox, toy);
+					moveCount++;
+					break;
+				}
+			case 'Q':
+				{
+					ptr = getCoord( ptr, x1 );
+					ptr = getCoord( ptr, y1 );
+					ptr = getCoord( ptr, tox );
+					ptr = getCoord( ptr, toy );
+					px1 = (curx + 2 * x1) * (1.0 / 3.0);
+					py1 = (cury + 2 * y1) * (1.0 / 3.0);
+					px2 = (tox + 2 * x1) * (1.0 / 3.0);
+					py2 = (toy + 2 * y1) * (1.0 / 3.0);
+					px3 = tox;
+					py3 = toy;
+					result.svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
+					pPath.quadTo(x1, y1, tox, toy);
+					contrlx = (tox + 2 * x1) * (1.0 / 3.0);
+					contrly = (toy + 2 * y1) * (1.0 / 3.0);
+					curx = tox;
+					cury = toy;
+					break;
+				}
+			case 'S':
+				{
+					stroke = false;
+					break;
+				}
+			case 'T':
+			case 'U':
+				{
+					ptr = getCoord(ptr, px1);
+					ptr = getCoord(ptr, py1);
+					ptr = getCoord(ptr, px2);
+					ptr = getCoord(ptr, py2);
+					ptr = getCoord(ptr, tox);
+					ptr = getCoord(ptr, toy);
+					if (command == 'U')
+						pPath.arcMoveTo(px1 - px2, py1 - py2, px2 * 2, py2 * 2, tox);
+					pPath.arcTo(px1 - px2, py1 - py2, px2 * 2, py2 * 2, tox, toy - tox);
+					break;
+				}
+			case 'V':
+			case 'W':
+				{
+					ptr = getCoord( ptr, tox );
+					ptr = getCoord( ptr, toy );
+					ptr = getCoord( ptr, px1 );
+					ptr = getCoord( ptr, py1 );
+					ptr = getCoord( ptr, px2 );
+					ptr = getCoord( ptr, py2 );
+					ptr = getCoord( ptr, px3 );
+					ptr = getCoord( ptr, py3 );
+					double startA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px2, py2)).angle();
+					double endA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px3, py3)).angle();
+					if (command == 'V')
+						pPath.moveTo(px2, py2);
+					pPath.arcTo(QRectF(QPointF(tox, toy), QPointF(px1, py1)), startA, endA - startA);
+					break;
+				}
+			case 'X':
+			case 'Y':
+				{
+					ptr = getCoord( ptr, tox );
+					ptr = getCoord( ptr, toy );
+				//	qDebug() << "Command X and Y not implemented yet";
+					break;
+				}
+			case 'Z':
+				{
+					curx = subpathx;
+					cury = subpathy;
+					result.svgClosePath();
+					pPath.closeSubpath();
+					break;
+				}
+			}
+			lastCommand = command;
+			if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
+			{
+				// there are still coords in this command
+				if(command == 'M')
+					command = 'L';
+			}
+			else
+				command = *(ptr++);
+
+			if( lastCommand != 'C' && lastCommand != 'S' && lastCommand != 'Q' && lastCommand != 'T')
+			{
+				contrlx = curx;
+				contrly = cury;
+			}
+		}
+		if ((lastCommand != 'Z') || (moveCount > 1))
+			ret = true;
+		if (result.size() > 2)
+		{
+			if ((result.point(0).x() == result.point(result.size()-2).x()) && (result.point(0).y() == result.point(result.size()-2).y()) && (moveCount == 1))
+				ret = false;
+		}
+		result.fromQPainterPath(pPath, !ret);
+	}
+	return ret;
+}
+
 PageItem* OdgPlug::addClip(PageItem* retObj, ObjStyle &obState)
 {
 	/*if (!obState.clipPath.isEmpty())
@@ -2499,7 +2914,6 @@
 	item->setWidthHeight(wh.x(), wh.y());
 	item->Clip = FlattenPath(item->PoLine, item->Segments);
 	m_Doc->AdjustItemSize(item, true);
-	item->setFillEvenOdd(false);
 	item->OldB2 = item->width();
 	item->OldH2 = item->height();
 	item->updateClip();

Modified: trunk/Scribus/scribus/plugins/import/odg/importodg.h
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=18832&path=/trunk/Scribus/scribus/plugins/import/odg/importodg.h
==============================================================================
--- trunk/Scribus/scribus/plugins/import/odg/importodg.h (original)
+++ trunk/Scribus/scribus/plugins/import/odg/importodg.h Sat Feb 22 21:39:31 2014
@@ -266,6 +266,7 @@
 	bool parseDocReference(QString designMap);
 	bool parseDocReferenceXML(QDomDocument &designMapDom);
 	PageItem* parseObj(QDomElement &draw);
+	PageItem* parseCustomShape(QDomElement &e);
 	PageItem* parseMeasure(QDomElement &e);
 	PageItem* parseLine(QDomElement &e);
 	PageItem* parseEllipse(QDomElement &e);
@@ -282,6 +283,8 @@
 	void parseStyles(QDomElement &sp);
 	void resovleStyle(ObjStyle &tmpOStyle, QString pAttrs);
 	double parseUnit(const QString &unit);
+	const char * getCoord( const char *ptr, double &number );
+	bool parseEnhPath(const QString& svgPath, FPointArray &result, bool &fill, bool &stroke);
 	QColor parseColorN( const QString &rgbColor );
 	QString parseColor( const QString &s );
 	QString constructFontName(QString fontBaseName, QString fontStyle);




More information about the scribus-commit mailing list