/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "core/UBPersistenceManager.h" #include "document/UBDocumentProxy.h" #include "domain/UBItem.h" #include "domain/UBGraphicsPolygonItem.h" #include "domain/UBGraphicsStroke.h" #include "domain/UBGraphicsTextItem.h" #include "domain/UBGraphicsSvgItem.h" #include "UBCFFSubsetAdaptor.h" #include "UBMetadataDcSubsetAdaptor.h" #include "UBThumbnailAdaptor.h" #include "UBSvgSubsetAdaptor.h" #include "core/UBApplication.h" #include "QFile" //enum of xmlparse status //tag names definition //use them everiwhere! static QString tElement = "element"; static QString tEllipse = "ellipse"; static QString tIwb = "iwb"; static QString tMeta = "meta"; static QString tPage = "page"; static QString tPageset = "pageset"; static QString tPolygon = "polygon"; static QString tPolyline = "polyline"; static QString tRect = "rect"; static QString tSvg = "svg"; static QString tText = "text"; static QString tTextarea = "textarea"; static QString tTspan = "tspan"; static QString tBreak = "tbreak"; //attribute names definition static QString aFill = "fill"; static QString aFillopacity = "fill-opacity"; static QString aX = "x"; static QString aY = "y"; static QString aWidth = "width"; static QString aHeight = "height"; static QString aStroke = "stroke"; static QString aStrokewidth = "stroke-width"; static QString aCx = "cx"; static QString aCy = "cy"; static QString aRx = "rx"; static QString aRy = "ry"; static QString aTransform = "transform"; static QString aViewbox = "viewbox"; static QString aFontSize = "font-size"; static QString aFontfamily = "font-family"; static QString aFontstretch = "font-stretch"; static QString aFontstyle = "font-style"; static QString aFontweight = "font-weight"; static QString aTextalign = "text-align"; static QString aPoints = "points"; UBCFFSubsetAdaptor::UBCFFSubsetAdaptor() { } bool UBCFFSubsetAdaptor::ConvertCFFFileToUbz(QString &cffSourceFile, UBDocumentProxy* pDocument) { //TODO // fill document proxy metadata // create persistance manager to save data using proxy // create UBCFFSubsetReader and make it parse cffSourceFolder QFile file(cffSourceFile); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Cannot open file " << cffSourceFile << " for reading ..."; return false; } // QTextStream out(&file); // out.setCodec("UTF-8"); // QString dta = out.readAll(); QByteArray data = file.readAll(); if (data.length() == 0) { qWarning() << "Either content file " << cffSourceFile << " is empty or failed to read from file"; file.close(); return false; } UBCFFSubsetReader cffReader(pDocument, data); bool result = cffReader.parse(); file.close(); return result; } UBCFFSubsetAdaptor::UBCFFSubsetReader::UBCFFSubsetReader(UBDocumentProxy *proxy, QByteArray &content): mReader(content), mProxy(proxy), currentState(NONE) { // QFile tfile("/home/ilia/Documents/tmp/2/out.xml"); // tfile.open(QIODevice::ReadWr ite | QIODevice::Text); // QTextStream out(&tfile); // out << content; // tfile.close(); } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parse() { UBMetadataDcSubsetAdaptor::persist(mProxy); mIndent = ""; if (!getTempFileName()) return false; bool result = parseDoc(); if (result) result = mProxy->pageCount() != 0; if (QFile::exists(mTempFilePath)) QFile::remove(mTempFilePath); return result; } int UBCFFSubsetAdaptor::UBCFFSubsetReader::PopState() { if (stateStack.count() == 0) currentState = NONE; else currentState = stateStack.pop(); return currentState; } void UBCFFSubsetAdaptor::UBCFFSubsetReader::PushState(int state) { if (currentState != NONE) stateStack.push(currentState); currentState = state; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseDoc() { while (!mReader.atEnd()) { mReader.readNext(); if (mReader.isStartElement()) { if (!parseCurrentElementStart()) return false; } else if (mReader.isCharacters()) { if (!parseCurrentElementCharacters()) return false; } else if (mReader.isEndElement()) { if (!parseCurrentElementEnd()) return false; } } if (!mReader.error() == QXmlStreamReader::NoError) UBApplication::showMessage(mReader.errorString()); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseCurrentElementStart() { QStringRef elName = mReader.name(); QString log = QString("%1<%2>").arg(mIndent).arg(elName.toString()); qDebug() << log; mIndent += " "; if ( elName == tIwb) { if (!parseIwb()) return false; PushState(IWB); } else if ( elName == tMeta) { if (!parseIwbMeta()) return false; } else if ( elName == tSvg) { if (!parseSvg()) return false; PushState(SVG); } else if ( elName == tRect) { if (!parseRect()) return false; } else if ( elName == tEllipse) { if (!parseEllipse()) return false; } else if ( elName == tText) { if (!parseText()) return false; } else if ( elName == tTextarea) { if (!parseTextArea()) return false; } else if ( elName == tPolygon) { if (!parsePolygon()) return false; } else if ( elName == tPolyline) { if (!parsePolyline()) return false; } else if ( elName == tPage) { if (!parsePage()) return false; PushState(PAGE); } else if ( elName == tPageset) { if (!parsePageSet()) return false; PushState(PAGESET); } else if ( elName == tElement) { if (!parseIwbElementRef()) return false; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseCurrentElementCharacters() { return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseCurrentElementEnd() { QStringRef elName = mReader.name(); mIndent.remove(0,1); QString log = QString("%1").arg(mIndent).arg(elName.toString()); qDebug() << log; if ( elName == tIwb) PopState(); else if ( elName == tMeta) { } else if ( elName == tSvg) { persistCurrentScene(); PopState(); } else if ( elName == tPage) { persistCurrentScene(); PopState(); } else if ( elName == tPageset) { PopState(); } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwb() { if (!stateStack.empty() || currentState != NONE) { qWarning() << "iwb content parse error, unexpected iwb tag at line" << mReader.lineNumber(); return false; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbMeta() { if (currentState != IWB) { qWarning() << "iwb content parse error, unexpected meta tag at line" << mReader.lineNumber(); return false; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseSvg() { if (currentState != IWB) { qWarning() << "iwb content parse error, unexpected svg tag at line" << mReader.lineNumber(); return false; } getViewBoxDimenstions(mReader.attributes().value(aViewbox).toString()); mSize = QSize(mReader.attributes().value(aWidth).toString().toInt(), mReader.attributes().value(aHeight).toString().toInt()); return true; } void UBCFFSubsetAdaptor::UBCFFSubsetReader::repositionSvgItem(UBGraphicsSvgItem *item, qreal width, qreal height, qreal x, qreal y, bool useTransform, QTransform &transform) { QTransform curTrans = item->transform(); qWarning() << QString().sprintf("Item current transform = %f 0 0 %f %f %f, position %f, %f", curTrans.m11(), curTrans.m22(), curTrans.dx(), curTrans.dy(), item->x(), item->y()); //check if rect is rotated //rotate svg item itself QRectF itemBounds = item->boundingRect(); //first, svg is mapped to svg item bound //second, svg item is mapped to scene //so, get svg to svg item scale and multiple by scene scale qreal hScale = itemBounds.width() / width * curTrans.m11(); qreal vScale = itemBounds.height() / height * curTrans.m22(); if (useTransform) { QPointF oldVector((x - transform.dx()), (y - transform.dy())); QTransform rTransform(transform.m11(), transform.m12(), transform.m21(), transform.m22(), 0, 0); QPointF newVector = rTransform.map(oldVector); rTransform.scale(curTrans.m11(), curTrans.m22()); item->setTransform(QTransform(rTransform.m11(), rTransform.m12(), rTransform.m21(), rTransform.m22(), 0, 0)); item->setPos((x - mViewBoxCenter.x() + (newVector - oldVector).x()) * hScale, (y - mViewBoxCenter.y() + (newVector - oldVector).y()) * vScale ); } else { item->setPos((x - mViewBoxCenter.x()) * hScale, (y - mViewBoxCenter.y()) * vScale); } QTransform newTrans = item->transform(); qWarning() << QString("Item new transform = %3 0 0 %4 %1 %2, position %5, %6").arg(newTrans.dx()).arg(newTrans.dy()).arg(newTrans.m11()).arg(newTrans.m22()).arg(item->x()).arg(item->y()); } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseRect() { if (currentState != SVG && currentState != PAGE) { qWarning() << "iwb content parse error, unexpected rect tag at line" << mReader.lineNumber(); return false; } //create new scene if it's not created yet (for one page document case) if (currentState == SVG && mCurrentScene == NULL) createNewScene(); //rect lef top corner coordinates qreal x1 = mReader.attributes().value(aX).toString().toDouble(); qreal y1 = mReader.attributes().value(aY).toString().toDouble(); //rect dimensions qreal width = mReader.attributes().value(aWidth).toString().toDouble(); qreal height = mReader.attributes().value(aHeight).toString().toDouble(); //init svg generator with temp file QSvgGenerator *generator = createSvgGenerator(width + 10, height + 10); //init painter to paint to svg QPainter painter; painter.begin(generator); //fill rect if (mReader.attributes().hasAttribute(aFill)) { QColor fillColor = colorFromString(mReader.attributes().value(aFill).toString()); painter.setBrush(QBrush(fillColor)); painter.fillRect(5, 5, width, height, fillColor); } bool hasStrokeColor = mReader.attributes().hasAttribute(aStroke); bool hasStrokeWidth = mReader.attributes().hasAttribute(aStrokewidth); if (hasStrokeColor || hasStrokeWidth) { QPen pen; if (hasStrokeColor) pen.setColor(colorFromString(mReader.attributes().value(aStroke).toString())); if (hasStrokeWidth) pen.setWidth(mReader.attributes().value(aStrokewidth).toString().toInt()); painter.setPen(pen); painter.drawRect(5, 5, width, height); } painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; bool hastransform = getCurElementTransorm(transform); repositionSvgItem(svgItem, width + 10, height + 10, x1 - 5, y1 - 5, hastransform, transform); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseEllipse() { if (currentState != SVG && currentState != PAGE) { qWarning() << "iwb content parse error, unexpected ellipse tag at line" << mReader.lineNumber(); return false; } //create new scene if it's not created yet (for one page document case) if (currentState == SVG && mCurrentScene == NULL) createNewScene(); //ellipse horisontal and vertical radius qreal rx = mReader.attributes().value(aRx).toString().toDouble(); qreal ry = mReader.attributes().value(aRy).toString().toDouble(); QSvgGenerator *generator = createSvgGenerator(rx * 2 + 10, ry * 2 + 10); //fill and stroke color QColor fillColor = colorFromString(mReader.attributes().value(aFill).toString()); QColor strokeColor = colorFromString(mReader.attributes().value(aStroke).toString()); int strokeWidth = mReader.attributes().value(aStrokewidth).toString().toInt(); //ellipse center coordinates qreal cx = mReader.attributes().value(aCx).toString().toDouble(); qreal cy = mReader.attributes().value(aCy).toString().toDouble(); //init painter to paint to svg QPainter painter; painter.begin(generator); QPen pen(strokeColor); pen.setWidth(strokeWidth); painter.setPen(pen); painter.setBrush(QBrush(fillColor)); painter.drawEllipse(5, 5, rx * 2, ry * 2); painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; bool hasTransform = getCurElementTransorm(transform); repositionSvgItem(svgItem, rx * 2 + 10, ry * 2 + 10, cx - rx - 5, cy - ry -5, hasTransform, transform); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTextArea() { if (currentState != SVG && currentState != PAGE) { qWarning() << "iwb content parse error, unexpected textarea tag at line" << mReader.lineNumber(); return false; } //create new scene if it's not created yet (for one page document case) if (currentState == SVG && mCurrentScene == NULL) createNewScene(); //TODO textarea node qreal x = mReader.attributes().value(aX).toString().toDouble(); qreal y = mReader.attributes().value(aY).toString().toDouble(); qreal width = mReader.attributes().value(aWidth).toString().toDouble(); qreal height = mReader.attributes().value(aHeight).toString().toDouble(); qWarning() << QString().sprintf("Text coordinates : %f,%f. Text size %f,%f", x, y, width, height); qreal fontSize = 12.0; QColor fontColor; QString fontFamily = "Arial"; QString fontStretch = "normal"; bool italic = false; int fontWeight = QFont::Normal; int textAlign = Qt::AlignLeft; QTransform fontTransform; parseTextAttributes(fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); QSvgGenerator *generator = createSvgGenerator(width, height); QPainter painter; painter.begin(generator); painter.setFont(QFont(fontFamily, fontSize, fontWeight, italic)); qreal curY = 0.0; qreal curX = 0.0; qreal linespacing = QFontMetricsF(painter.font()).leading(); //remember if text area has transform QString transformString; QTransform transform; bool hasTransform = getCurElementTransorm(transform); QRectF lastDrawnTextBoundingRect; //parse text area tags while(true) { mReader.readNext(); QStringRef elementName = mReader.name(); if (mReader.isEndDocument()) break; if (mReader.isEndElement() && elementName == tBreak) { //when tbreak appers, move down by the drawn rect height //TODO: line spacing is not calculated yet, additional code is required curY += lastDrawnTextBoundingRect.height() + linespacing; curX = 0.0; lastDrawnTextBoundingRect = QRectF(0,0,0,0); continue; } if (mReader.isEndElement() && elementName == tTextarea) break; if (mReader.isStartElement() && elementName == tTspan) { parseTextAttributes(fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); painter.setFont(QFont(fontFamily, fontSize, fontWeight, italic)); painter.setPen(fontColor); linespacing = QFontMetricsF(painter.font()).leading(); continue; } if (mReader.isCharacters() || mReader.isCDATA()) { QString text = mReader.text().toString().trimmed(); //skip empty text if (text.length() == 0) continue; //get bounding rect to obtain desired text height lastDrawnTextBoundingRect = painter.boundingRect(QRectF(curX, curY, width, height - curY), textAlign|Qt::TextWordWrap, text); QString log = QString().sprintf(" at rect %f, %f, %f, %f. Bounding rect is %f, %f, %f, %f", 0.0, curY, width, height - curY, lastDrawnTextBoundingRect.x(), lastDrawnTextBoundingRect.y(), lastDrawnTextBoundingRect.width(), lastDrawnTextBoundingRect.height()); qWarning() << "Text " << text << log; painter.drawText(curX, curY, width, lastDrawnTextBoundingRect.height(), textAlign|Qt::TextWordWrap, text); curX += lastDrawnTextBoundingRect.x() + lastDrawnTextBoundingRect.width(); continue; } } painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); repositionSvgItem(svgItem, width, height, x, y, hasTransform, transform); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseText() { if (currentState != SVG && currentState != PAGE) { qWarning() << "iwb content parse error, unexpected textarea tag at line" << mReader.lineNumber(); return false; } //create new scene if it's not created yet (for one page document case) if (currentState == SVG && mCurrentScene == NULL) createNewScene(); qreal x = mReader.attributes().value(aX).toString().toDouble(); qreal y = mReader.attributes().value(aY).toString().toDouble(); qreal width = 0; qreal height = 0; QList textRects; QList textFonts; QList textLines; QList textAligns; QList textColors; qWarning() << QString().sprintf("Text coordinates : %f,%f. Text size %f,%f", x, y, width, height); qreal fontSize = 12.0; QFont textFont; QColor fontColor; QString fontFamily = "Arial"; QString fontStretch = "normal"; bool italic = false; int fontWeight = QFont::Normal; int textAlign = Qt::AlignLeft; QTransform fontTransform; parseTextAttributes(fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); textFont = QFont(fontFamily, fontSize, fontWeight, italic); QFontMetricsF metrics = QFontMetricsF(textFont); qreal curHeight = metrics.height(); qreal curY = 0.0; qreal curX = 0.0; qreal linespacing = QFontMetrics(textFont).leading(); //remember if text area has transform QTransform transform; bool hasTransform = getCurElementTransorm(transform); QRectF lastDrawnTextBoundingRect; QStack fontStack; QStack colorStack; QStack alignStack; // first extimate desired text area size // to do that, parse text area tags while(true) { mReader.readNext(); QStringRef elementName = mReader.name(); if (mReader.isEndDocument()) break; if (mReader.isEndElement()) { if (elementName == tBreak) { //when tbreak appers, move down by the drawn rect height //TODO: line spacing is not calculated yet, probably additional code is required curY += lastDrawnTextBoundingRect.height() + linespacing; curX = 0.0; height += lastDrawnTextBoundingRect.height(); lastDrawnTextBoundingRect = QRectF(0,0,0,0); continue; } if (elementName == tTspan) { textFont = fontStack.pop(); fontColor = colorStack.pop(); textAlign = alignStack.pop(); continue; } } if (mReader.isEndElement() && elementName == tText) break; if (mReader.isStartElement() && elementName == tTspan) { fontStack.push(textFont); colorStack.push(fontColor); alignStack.push(textAlign); parseTextAttributes(fontSize, fontColor, fontFamily, fontStretch, italic, fontWeight, textAlign, fontTransform); textFont = QFont(fontFamily, fontSize, fontWeight, italic); metrics = QFontMetricsF(textFont); curHeight = metrics.height(); linespacing = QFontMetricsF(textFont).leading(); continue; } if (mReader.isCharacters() || mReader.isCDATA()) { QString text = mReader.text().toString(); //skip empty text if (text.trimmed().length() == 0) continue; //get bounding rect to obtain desired text height lastDrawnTextBoundingRect = metrics.boundingRect(QRectF(), textAlign, text); QString log = QString().sprintf(" at rect %f, %f, %f, %f. Bounding rect is %f, %f, %f, %f", 0.0, curY, width, height - curY, lastDrawnTextBoundingRect.x(), lastDrawnTextBoundingRect.y(), lastDrawnTextBoundingRect.width(), lastDrawnTextBoundingRect.height()); qWarning() << "Text " << text << log; textFonts.append(textFont); textRects.append(QRectF(curX, curY, lastDrawnTextBoundingRect.width(), lastDrawnTextBoundingRect.height())); textLines.append(text); textAligns.append(textAlign); textColors.append(fontColor); curX += lastDrawnTextBoundingRect.width(); if (width < curX) width = curX; if (height == 0) height = curHeight; continue; } } QSvgGenerator *generator = createSvgGenerator(width, height); QPainter painter; painter.begin(generator); if (textRects.count() != 0) { QListIterator textRectsIter(textRects); QListIterator textFontsIter(textFonts); QListIterator textLinesIter(textLines); QListIterator textAlignsIter(textAligns); QListIterator textColorsIter(textColors); while (textRectsIter.hasNext()) { QRectF rt = textRectsIter.next(); QFont font = textFontsIter.next(); QString line = textLinesIter.next(); int align = textAlignsIter.next(); QColor color = textColorsIter.next(); painter.setFont(font); painter.setPen(color); painter.drawText(rt.x(), rt.y(), rt.width(), rt.height(), align, line); } } painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); repositionSvgItem(svgItem, width, height, x, y, hasTransform, transform); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parsePolygon() { if (currentState != SVG && currentState != PAGE) { qWarning() << "iwb content parse error, unexpected polygon tag at line" << mReader.lineNumber(); return false; } //create new scene if it's not created yet (for one page document case) if (currentState == SVG && mCurrentScene == NULL) createNewScene(); QStringRef svgPoints = mReader.attributes().value("points"); QPolygonF polygon; if (!svgPoints.isNull()) { QStringList ts = svgPoints.toString().split(QLatin1Char(' '), QString::SkipEmptyParts); foreach(const QString sPoint, ts) { QStringList sCoord = sPoint.split(QLatin1Char(','), QString::SkipEmptyParts); if (sCoord.size() == 2) { QPointF point; point.setX(sCoord.at(0).toFloat()); point.setY(sCoord.at(1).toFloat()); polygon << point; } else { qWarning() << "cannot make sense of a 'point' value" << sCoord; } } } //bounding rect lef top corner coordinates qreal x1 = polygon.boundingRect().topLeft().x(); qreal y1 = polygon.boundingRect().topLeft().y(); //bounding rect dimensions qreal width = polygon.boundingRect().width(); qreal height = polygon.boundingRect().height(); QPen pen; if (mReader.attributes().hasAttribute(aStroke)) pen.setColor(colorFromString(mReader.attributes().value(aStroke).toString())); if (mReader.attributes().hasAttribute(aStrokewidth)) pen.setWidth(mReader.attributes().value(aStrokewidth).toString().toInt()); QBrush brush; if (mReader.attributes().hasAttribute(aFill)) { brush.setColor(colorFromString(mReader.attributes().value(aFill).toString())); brush.setStyle(Qt::SolidPattern); } QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); QPainter painter; painter.begin(generator); //drawing to svg tmp file painter.translate(pen.widthF() / 2 - x1, pen.widthF() / 2 - y1); painter.setBrush(brush); painter.setPen(pen); painter.drawPolygon(polygon); painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; bool hastransform = getCurElementTransorm(transform); repositionSvgItem(svgItem, width + 10, height + 10, x1 - 5, y1 - 5, hastransform, transform); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parsePolyline() { if (currentState != SVG && currentState != PAGE) { qWarning() << "iwb content parse error, unexpected polyline tag at line" << mReader.lineNumber(); return false; } //create new scene if it's not created yet (for one page document case) if (currentState == SVG && mCurrentScene == NULL) createNewScene(); QStringRef svgPoints = mReader.attributes().value("points"); QPolygonF polygon; if (!svgPoints.isNull()) { QStringList ts = svgPoints.toString().split(QLatin1Char(' '), QString::SkipEmptyParts); foreach(const QString sPoint, ts) { QStringList sCoord = sPoint.split(QLatin1Char(','), QString::SkipEmptyParts); if (sCoord.size() == 2) { QPointF point; point.setX(sCoord.at(0).toFloat()); point.setY(sCoord.at(1).toFloat()); polygon << point; } else { qWarning() << "cannot make sense of a 'point' value" << sCoord; } } polygon.translate(-polygon.boundingRect().topLeft()); } //bounding rect lef top corner coordinates qreal x1 = polygon.boundingRect().topLeft().x(); qreal y1 = polygon.boundingRect().topLeft().y(); //bounding rect dimensions qreal width = polygon.boundingRect().width(); qreal height = polygon.boundingRect().height(); QPen pen; if (mReader.attributes().hasAttribute(aStroke)) pen.setColor(colorFromString(mReader.attributes().value(aStroke).toString())); if (mReader.attributes().hasAttribute(aStrokewidth)) pen.setWidth(mReader.attributes().value(aStrokewidth).toString().toInt()); pen.setColor(Qt::yellow); QSvgGenerator *generator = createSvgGenerator(width + pen.width(), height + pen.width()); QPainter painter; painter.begin(generator); //drawing to svg tmp file painter.translate(pen.widthF() / 2, pen.widthF() / 2); painter.setPen(pen); painter.drawPolyline(polygon); painter.end(); //add resulting svg file to scene UBGraphicsSvgItem *svgItem = mCurrentScene->addSvg(QUrl::fromLocalFile(generator->fileName())); QTransform transform; bool hastransform = getCurElementTransorm(transform); repositionSvgItem(svgItem, width + 10, height + 10, x1 - 5, y1 - 5, hastransform, transform); delete generator; return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parsePage() { if (currentState != PAGESET && currentState != SVG) { qWarning() << "iwb content parse error, unexpected page tag at line" << mReader.lineNumber(); return false; } createNewScene(); qWarning() << "Added page number" << mProxy->pageCount(); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parsePageSet() { if (currentState != SVG) { qWarning() << "iwb content parse error, unexpected page tag at line" << mReader.lineNumber(); return false; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::parseIwbElementRef() { if (currentState != IWB) { qWarning() << "iwb content parse error, unexpected element tag at line" << mReader.lineNumber(); return false; } return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::createNewScene() { mCurrentScene = UBPersistenceManager::persistenceManager()->createDocumentSceneAt(mProxy, mProxy->pageCount()); mCurrentSceneRect = mCurrentScene->normalizedSceneRect(); return true; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::persistCurrentScene() { if (mCurrentScene != 0 && mCurrentScene->isModified()) { UBThumbnailAdaptor::persistScene(mProxy->persistencePath(), mCurrentScene, mProxy->pageCount() - 1); UBSvgSubsetAdaptor::persistScene(mProxy, mCurrentScene, mProxy->pageCount() - 1); mCurrentScene->setModified(false); mCurrentScene = 0; } return true; } QColor UBCFFSubsetAdaptor::UBCFFSubsetReader::colorFromString(const QString& clrString) { //init regexp with pattern //pattern corresponds to strings like 'rgb(1,2,3) or rgb(10%,20%,30%)' QRegExp regexp("rgb\\(([0-9]+%{0,1}),([0-9]+%{0,1}),([0-9]+%{0,1})\\)"); if (regexp.exactMatch(clrString)) { if (regexp.capturedTexts().count() == 4 && regexp.capturedTexts().at(0).length() == clrString.length()) { int r = regexp.capturedTexts().at(1).toInt(); if (regexp.capturedTexts().at(1).indexOf("%") != -1) r = r * 255 / 100; int g = regexp.capturedTexts().at(2).toInt(); if (regexp.capturedTexts().at(2).indexOf("%") != -1) g = g * 255 / 100; int b = regexp.capturedTexts().at(3).toInt(); if (regexp.capturedTexts().at(3).indexOf("%") != -1) b = b * 255 / 100; return QColor(r, g, b); } else return QColor(); } else return QColor(clrString); } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getCurElementTransorm(QTransform &transform) { if (mReader.attributes().hasAttribute(aTransform)) { transform = transformFromString(mReader.attributes().value(aTransform).toString()); return true; } else return false; } QTransform UBCFFSubsetAdaptor::UBCFFSubsetReader::transformFromString(const QString trString) { //check pattern for strings like 'rotate(10)' QRegExp regexp("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)"); if (regexp.exactMatch(trString)) { if (regexp.capturedTexts().count() == 2 && regexp.capturedTexts().at(0).length() == trString.length()) { qreal angle = regexp.capturedTexts().at(1).toDouble(); return QTransform().rotate(angle); } } //check pattern for strings like 'rotate(10,20,20)' or 'rotate(10.1,10.2,34.2)' regexp.setPattern("rotate\\( *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *, *([-+]{0,1}[0-9]*\\.{0,1}[0-9]*) *\\)"); if (regexp.exactMatch(trString)) { if (regexp.capturedTexts().count() == 4 && regexp.capturedTexts().at(0).length() == trString.length()) { qreal angle = regexp.capturedTexts().at(1).toDouble(); qreal dx = regexp.capturedTexts().at(2).toDouble(); qreal dy = regexp.capturedTexts().at(3).toDouble(); return QTransform().translate(dx, dy).rotate(angle); } } return QTransform(); } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getViewBoxDimenstions(const QString& viewBox) { //check pattern for strings like 'rotate(10)' QRegExp regexp("([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)"); if (regexp.exactMatch(viewBox)) { int capturesCount = regexp.capturedTexts().count(); if (capturesCount == 5 && regexp.capturedTexts().at(0).length() == viewBox.length()) { mViewBox = QRectF(0, 0, regexp.capturedTexts().at(3).toDouble(), regexp.capturedTexts().at(4).toDouble()); mViewBoxCenter.setX(mViewBox.width() / 2); mViewBoxCenter.setY(mViewBox.height() / 2); return true; } } mViewBox = QRectF(0, 0, 1000, 1000); mViewBoxCenter = QPointF(500, 500); return false; } QSvgGenerator* UBCFFSubsetAdaptor::UBCFFSubsetReader::createSvgGenerator(qreal width, qreal height) { QSvgGenerator* generator = new QSvgGenerator(); qWarning() << QString("Making generator with file %1, size (%2, %3) and viewbox (%4 %5 %6 %7)").arg(mTempFilePath) .arg(width).arg(height).arg(0.0).arg(0.0).arg(width).arg(width); generator->setResolution(QApplication::desktop()->physicalDpiY()); generator->setFileName(mTempFilePath); generator->setSize(QSize(width, height)); generator->setViewBox(QRectF(0, 0, width, height)); return generator; } bool UBCFFSubsetAdaptor::UBCFFSubsetReader::getTempFileName() { int tmpNumber = 0; QDir rootDir; while (true) { mTempFilePath = QString("%1/sanksvg%2.%3") .arg(rootDir.tempPath()) .arg(QDateTime::currentDateTime().toString("dd_MM_yyyy_HH-mm")) .arg(tmpNumber); if (!QFile::exists(mTempFilePath)) return true; tmpNumber++; if (tmpNumber == 100000) { qWarning() << "Import failed. Failed to create temporary file for svg objects"; return false; } } } void UBCFFSubsetAdaptor::UBCFFSubsetReader::parseTextAttributes(qreal &fontSize, QColor &fontColor, QString &fontFamily, QString &fontStretch, bool &italic, int &fontWeight, int &textAlign, QTransform &fontTransform) { if (mReader.attributes().hasAttribute(aFontSize)) { //consider inch has 72 liens //since svg font size is given in pixels, divide it by pixels per line fontSize = mReader.attributes().value(aFontSize).toString().toDouble() * 72 / QApplication::desktop()->physicalDpiY(); } if (mReader.attributes().hasAttribute(aFill)) fontColor = colorFromString(mReader.attributes().value(aFill).toString()); if (mReader.attributes().hasAttribute(aFontfamily)) fontFamily = mReader.attributes().value(aFontfamily).toString(); if (mReader.attributes().hasAttribute(aFontstretch)) fontStretch = mReader.attributes().value(aFontstretch).toString(); if (mReader.attributes().hasAttribute(aFontstyle)) { QStringRef fontStyle = mReader.attributes().value(aFontstyle); italic = fontStyle == "italic"; } if (mReader.attributes().hasAttribute(aFontweight)) { QStringRef weight = mReader.attributes().value(aFontweight); if (weight == "normal") fontWeight = QFont::Normal; else if (weight == "light") fontWeight = QFont::Light; else if (weight == "demibold") fontWeight = QFont::DemiBold; else if (weight == "bold") fontWeight = QFont::Bold; if (weight == "black") fontWeight = QFont::Black; } if (mReader.attributes().hasAttribute(aTextalign)) { QString align = mReader.attributes().value(aTextalign).toString(); if (align == "middle" || align == "center") textAlign = Qt::AlignHCenter; else if (align == "start") textAlign = Qt::AlignLeft; else if (align == "end") textAlign = Qt::AlignRight; } if (mReader.attributes().hasAttribute(aTransform)) fontTransform = transformFromString(mReader.attributes().value(aTransform).toString()); }