2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
14
#include <QPainterPath>
16
#include <QTemporaryFile>
19
#include "commonstrings.h"
20
#include "customfdialog.h"
21
#include "fonts/scfontmetrics.h"
22
#include "fpointarray.h"
23
#include "loadsaveplugin.h"
24
#include "menumanager.h"
26
#include "prefsfile.h"
27
#include "prefsmanager.h"
28
#include "propertiespalette.h"
29
#include "sccolorengine.h"
30
#include "scclocale.h"
33
#include "scmimedata.h"
35
#include "scpattern.h"
36
#include "scraction.h"
38
#include "scribusXml.h"
39
#include "scribuscore.h"
40
#include "scribusdoc.h"
41
#include "selection.h"
42
#include "svgplugin.h"
43
#include "undomanager.h"
45
#include "util_formats.h"
46
#include "util_icon.h"
47
#include "util_math.h"
52
int svgimplugin_getPluginAPIVersion()
54
return PLUGIN_API_VERSION;
57
ScPlugin* svgimplugin_getPlugin()
59
SVGImportPlugin* plug = new SVGImportPlugin();
64
void svgimplugin_freePlugin(ScPlugin* plugin)
66
SVGImportPlugin* plug = dynamic_cast<SVGImportPlugin*>(plugin);
71
SVGImportPlugin::SVGImportPlugin() : LoadSavePlugin(),
72
importAction(new ScrAction(ScrAction::DLL, QPixmap(), QPixmap(), "", QKeySequence(), this))
74
// Set action info in languageChange, so we only have to do
75
// it in one place. This includes registering file format
80
void SVGImportPlugin::addToMainWindowMenu(ScribusMainWindow *mw)
82
importAction->setEnabled(true);
83
connect( importAction, SIGNAL(triggered()), SLOT(import()) );
84
mw->scrMenuMgr->addMenuItem(importAction, "FileImport");
87
SVGImportPlugin::~SVGImportPlugin()
92
void SVGImportPlugin::languageChange()
94
importAction->setText( tr("Import &SVG..."));
95
// (Re)register file format support.
100
const QString SVGImportPlugin::fullTrName() const
102
return QObject::tr("SVG Import");
105
const ScActionPlugin::AboutData* SVGImportPlugin::getAboutData() const
107
AboutData* about = new AboutData;
108
about->authors = "Franz Schmid <franz@scribus.info>";
109
about->shortDescription = tr("Imports SVG Files");
110
about->description = tr("Imports most SVG files into the current document,\nconverting their vector data into Scribus objects.");
111
about->license = "GPL";
116
void SVGImportPlugin::deleteAboutData(const AboutData* about) const
122
void SVGImportPlugin::registerFormats()
124
FileFormat fmt(this);
125
fmt.trName = FormatsManager::instance()->nameOfFormat(FormatsManager::SVG);
126
fmt.formatId = FORMATID_SVGIMPORT;
127
fmt.filter = FormatsManager::instance()->extensionsForFormat(FormatsManager::SVG);
128
fmt.nameMatch = QRegExp("\\."+FormatsManager::instance()->extensionListForFormat(FormatsManager::SVG, 1)+"$", Qt::CaseInsensitive);
131
fmt.mimeTypes = FormatsManager::instance()->mimetypeOfFormat(FormatsManager::SVG);
136
bool SVGImportPlugin::fileSupported(QIODevice* /* file */, const QString & fileName) const
138
// TODO: identify valid SVG
142
bool SVGImportPlugin::loadFile(const QString & fileName, const FileFormat & /* fmt */, int flags, int /*index*/)
144
// For now, "load file" and import are the same thing for this plugin
145
return import(fileName, flags);
148
bool SVGImportPlugin::import(QString filename, int flags)
150
if (!checkFlags(flags))
152
m_Doc=ScCore->primaryMainWindow()->doc;
153
ScribusMainWindow* mw=(m_Doc==0) ? ScCore->primaryMainWindow() : m_Doc->scMW();
154
if (filename.isEmpty())
156
flags |= lfInteractive;
157
PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("SVGPlugin");
158
QString wdir = prefs->get("wdir", ".");
159
CustomFDialog diaf(mw, wdir, QObject::tr("Open"), FormatsManager::instance()->fileDialogFormatList(FormatsManager::SVG));
162
filename = diaf.selectedFile();
163
prefs->set("wdir", filename.left(filename.lastIndexOf("/")));
169
UndoTransaction* activeTransaction = NULL;
170
bool emptyDoc = (m_Doc == NULL);
171
bool hasCurrentPage = (m_Doc && m_Doc->currentPage());
172
TransactionSettings trSettings;
173
trSettings.targetName = hasCurrentPage ? m_Doc->currentPage()->getUName() : "";
174
trSettings.targetPixmap = Um::IImageFrame;
175
trSettings.actionName = Um::ImportSVG;
176
trSettings.description = filename;
177
trSettings.actionPixmap = Um::ISVG;
178
if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
179
UndoManager::instance()->setUndoEnabled(false);
180
if (UndoManager::undoEnabled())
181
activeTransaction = new UndoTransaction(UndoManager::instance()->beginTransaction(trSettings));
182
SVGPlug *dia = new SVGPlug(mw, flags);
184
dia->import(filename, trSettings, flags);
185
if (activeTransaction)
187
activeTransaction->commit();
188
delete activeTransaction;
189
activeTransaction = NULL;
191
if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
192
UndoManager::instance()->setUndoEnabled(true);
193
if (dia->importCanceled)
195
if (dia->importFailed)
196
QMessageBox::warning(mw, CommonStrings::trWarning, tr("The file could not be imported"), 1, 0, 0);
197
else if (dia->unsupported)
198
QMessageBox::warning(mw, CommonStrings::trWarning, tr("SVG file contains some unsupported features"), 1, 0, 0);
205
SVGPlug::SVGPlug( ScribusMainWindow* mw, int flags ) :
208
tmpSel=new Selection(this, false);
211
importFailed = false;
212
importCanceled = true;
213
importedColors.clear();
214
importedPatterns.clear();
218
interactive = (flags & LoadSavePlugin::lfInteractive);
219
// m_gc.setAutoDelete( true );
222
bool SVGPlug::import(QString fname, const TransactionSettings& trSettings, int flags)
224
if (!loadData(fname))
229
QString CurDirP = QDir::currentPath();
230
QFileInfo efp(fname);
231
QDir::setCurrent(efp.path());
232
convert(trSettings, flags);
233
QDir::setCurrent(CurDirP);
237
bool SVGPlug::loadData(QString fName)
240
bool isCompressed = false, success = false;
241
QByteArray bb(3, ' ');
243
if (fi.open(QIODevice::ReadOnly))
245
fi.read(bb.data(), 2);
247
// Qt4 bb[0]->QChar(bb[0])
248
if ((QChar(bb[0]) == QChar(0x1F)) && (QChar(bb[1]) == QChar(0x8B)))
251
if ((fName.right(2) == "gz") || (isCompressed))
253
ScGzFile file(fName);
254
if (!file.open(QIODevice::ReadOnly))
256
success = inpdoc.setContent(&file);
262
if (!file.open(QIODevice::ReadOnly))
264
success = inpdoc.setContent(&file);
270
void SVGPlug::convert(const TransactionSettings& trSettings, int flags)
273
SvgStyle *gc = new SvgStyle;
274
QDomElement docElem = inpdoc.documentElement();
275
QSize wh = parseWidthHeight(docElem);
276
double width = wh.width();
277
double height = wh.height();
278
if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
280
m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
282
m_Doc->view()->addPage(0);
286
if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
288
m_Doc=ScCore->primaryMainWindow()->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
289
ScCore->primaryMainWindow()->HaveNewDoc();
293
if ((ret) || (!interactive))
299
m_Doc->m_pageSize = "Custom";
301
FPoint minSize = m_Doc->minCanvasCoordinate;
302
FPoint maxSize = m_Doc->maxCanvasCoordinate;
303
FPoint cOrigin = m_Doc->view()->canvasOrigin();
304
m_Doc->view()->Deselect();
305
m_Doc->setLoading(true);
306
m_Doc->DoDrawing = false;
307
m_Doc->view()->updatesOn(false);
308
m_Doc->scMW()->setScriptRunning(true);
309
qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
310
gc->FontFamily = m_Doc->toolSettings.defFont;
311
if (!m_Doc->PageColors.contains("Black"))
312
m_Doc->PageColors.insert("Black", ScColor(0, 0, 0, 255));
318
if( !docElem.attribute( "viewBox" ).isEmpty() )
320
QString viewbox( docElem.attribute( "viewBox" ) );
321
QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split( ' ', QString::SkipEmptyParts );
322
if (points.size() > 3)
325
QSize wh2 = parseWidthHeight(docElem);
326
double w2 = wh2.width();
327
double h2 = wh2.height();
329
viewTransformX = ScCLocale::toDoubleC(points[0]);
330
viewTransformY = ScCLocale::toDoubleC(points[1]);
331
viewScaleX = w2 / ScCLocale::toDoubleC(points[2]);
332
viewScaleY = h2 / ScCLocale::toDoubleC(points[3]);
333
matrix.translate(-viewTransformX * viewScaleX, -viewTransformY * viewScaleY);
334
matrix.scale(viewScaleX, viewScaleY);
335
m_gc.top()->matrix = matrix;
338
QList<PageItem*> Elements = parseGroup( docElem );
339
if (flags & LoadSavePlugin::lfCreateDoc)
341
m_Doc->documentInfo.setTitle(docTitle);
342
m_Doc->documentInfo.setComments(docDesc);
345
if (Elements.count() == 0)
348
if (importedColors.count() != 0)
350
for (int cd = 0; cd < importedColors.count(); cd++)
352
m_Doc->PageColors.remove(importedColors[cd]);
355
if (importedPatterns.count() != 0)
357
for (int cd = 0; cd < importedPatterns.count(); cd++)
359
m_Doc->docPatterns.remove(importedPatterns[cd]);
363
if (Elements.count() > 1)
367
if (Elements.at(0)->Groups.count() != 0)
368
firstElem = Elements.at(0)->Groups.top();
369
for (int bx = 0; bx < Elements.count(); ++bx)
371
PageItem* bxi = Elements.at(bx);
372
if (bxi->Groups.count() != 0)
374
if (bxi->Groups.top() != firstElem)
382
double minx = 99999.9;
383
double miny = 99999.9;
384
double maxx = -99999.9;
385
double maxy = -99999.9;
386
uint lowestItem = 999999;
387
uint highestItem = 0;
388
for (int a = 0; a < Elements.count(); ++a)
390
Elements.at(a)->Groups.push(m_Doc->GroupCounter);
391
PageItem* currItem = Elements.at(a);
392
lowestItem = qMin(lowestItem, currItem->ItemNr);
393
highestItem = qMax(highestItem, currItem->ItemNr);
394
double x1, x2, y1, y2;
395
currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
396
minx = qMin(minx, x1);
397
miny = qMin(miny, y1);
398
maxx = qMax(maxx, x2);
399
maxy = qMax(maxy, y2);
403
double gw = maxx - minx;
404
double gh = maxy - miny;
405
PageItem *high = m_Doc->Items->at(highestItem);
406
int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, m_Doc->toolSettings.dBrush, m_Doc->toolSettings.dPen, true);
407
PageItem *neu = m_Doc->Items->takeAt(z);
408
m_Doc->Items->insert(lowestItem, neu);
409
neu->Groups.push(m_Doc->GroupCounter);
410
neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
411
neu->AutoName = false;
412
neu->isGroupControl = true;
413
neu->groupsLastItem = high;
414
for (int a = 0; a < m_Doc->Items->count(); ++a)
416
m_Doc->Items->at(a)->ItemNr = a;
418
neu->setRedrawBounding();
419
neu->setTextFlowMode(PageItem::TextFlowDisabled);
420
Elements.prepend(neu);
421
m_Doc->GroupCounter++;
424
m_Doc->DoDrawing = true;
425
m_Doc->scMW()->setScriptRunning(false);
427
m_Doc->setLoading(false);
428
qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
429
if ((Elements.count() > 0) && (!ret) && (interactive))
431
if (flags & LoadSavePlugin::lfScripted)
433
bool loadF = m_Doc->isLoading();
434
m_Doc->setLoading(false);
436
m_Doc->setLoading(loadF);
437
m_Doc->m_Selection->delaySignalsOn();
438
for (int dre=0; dre<Elements.count(); ++dre)
440
m_Doc->m_Selection->addItem(Elements.at(dre), true);
442
m_Doc->m_Selection->delaySignalsOff();
443
m_Doc->m_Selection->setGroupRect();
444
m_Doc->view()->updatesOn(true);
445
importCanceled = false;
450
m_Doc->DraggedElem = 0;
451
m_Doc->DragElements.clear();
452
m_Doc->m_Selection->delaySignalsOn();
453
for (int dre=0; dre<Elements.count(); ++dre)
455
m_Doc->DragElements.append(Elements.at(dre)->ItemNr);
456
tmpSel->addItem(Elements.at(dre), true);
458
ScriXmlDoc *ss = new ScriXmlDoc();
459
tmpSel->setGroupRect();
460
ScElemMimeData* md = new ScElemMimeData();
461
md->setScribusElem(ss->WriteElem(m_Doc, m_Doc->view(), tmpSel));
465
m_Doc->itemSelection_DeleteItem(tmpSel);
467
m_Doc->view()->updatesOn(true);
468
if (importedColors.count() != 0)
470
for (int cd = 0; cd < importedColors.count(); cd++)
472
m_Doc->PageColors.remove(importedColors[cd]);
475
if (importedPatterns.count() != 0)
477
for (int cd = 0; cd < importedPatterns.count(); cd++)
479
m_Doc->docPatterns.remove(importedPatterns[cd]);
482
m_Doc->m_Selection->delaySignalsOff();
483
// We must copy the TransationSettings object as it is owned
484
// by handleObjectImport method afterwards
485
TransactionSettings* transacSettings = new TransactionSettings(trSettings);
486
m_Doc->view()->handleObjectImport(md, transacSettings);
487
m_Doc->DragP = false;
488
m_Doc->DraggedElem = 0;
489
m_Doc->DragElements.clear();
494
bool loadF = m_Doc->isLoading();
495
m_Doc->setLoading(false);
497
m_Doc->reformPages();
498
m_Doc->view()->updatesOn(true);
499
m_Doc->setLoading(loadF);
503
void SVGPlug::addGraphicContext()
505
SvgStyle *gc = new SvgStyle;
507
*gc = *( m_gc.top() );
511
void SVGPlug::setupNode( const QDomElement &e )
515
parseStyle(m_gc.top(), e);
518
void SVGPlug::setupTransform( const QDomElement &e )
520
SvgStyle *gc = m_gc.top();
521
QMatrix mat = parseTransform( e.attribute( "transform" ) );
522
if (!e.attribute("transform").isEmpty())
523
gc->matrix = mat * gc->matrix;
526
void SVGPlug::finishNode( const QDomNode &e, PageItem* item)
528
SvgStyle *gc = m_gc.top();
529
QMatrix gcm = gc->matrix;
530
double BaseX = m_Doc->currentPage()->xOffset();
531
double BaseY = m_Doc->currentPage()->yOffset();
532
double coeff1 = sqrt(gcm.m11() * gcm.m11() + gcm.m12() * gcm.m12());
533
double coeff2 = sqrt(gcm.m21() * gcm.m21() + gcm.m22() * gcm.m22());
534
switch (item->itemType())
536
case PageItem::ImageFrame:
538
item->ClipEdited = true;
540
QMatrix mm = gc->matrix;
541
item->PoLine.map(mm);
542
item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
543
FPoint wh = getMaxClipF(&item->PoLine);
544
item->setWidthHeight(wh.x(), wh.y());
545
m_Doc->AdjustItemSize(item);
546
// item->moveBy(mm.dx(), mm.dy());
547
// item->setWidthHeight(item->width() * mm.m11(), item->height() * mm.m22());
548
// item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
549
if (item->PictureIsAvailable)
551
item->setImageXYOffset(0.0, 0.0);
552
item->setImageXYScale(item->width() / (item->pixm.width() * (item->pixm.imgInfo.xres / 72.0)),
553
item->height() / (item->pixm.height() * (item->pixm.imgInfo.yres / 72.0)));
554
item->setImageScalingMode(false, false); // fit to frame
558
case PageItem::TextFrame:
560
QMatrix mm = gc->matrix;
561
item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
566
item->ClipEdited = true;
568
QMatrix mm = gc->matrix;
569
item->PoLine.map(mm);
573
mv.translate(viewTransformX, viewTransformY);
574
mv.scale(viewScaleX, viewScaleY);
577
item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
578
FPoint wh = getMaxClipF(&item->PoLine);
579
item->setWidthHeight(wh.x(), wh.y());
580
// if (item->asPolyLine())
581
// item->setPolyClip(qRound(qMax(item->lineWidth() / 2.0, 1)));
583
// item->Clip = FlattenPath(item->PoLine, item->Segments);
584
FPoint wx = getMinClipF(&item->PoLine);
585
inGroupXOrigin = qMin(inGroupXOrigin, wx.x());
586
inGroupYOrigin = qMin(inGroupYOrigin, wx.y());
587
m_Doc->AdjustItemSize(item);
591
item->setRedrawBounding();
592
item->OwnPage = m_Doc->OnPage(item);
595
QString nodeId = e.toElement().attribute("id");
596
if( !nodeId.isEmpty() )
598
item->setItemName(" "+nodeId);
599
item->AutoName = false;
602
item->setFillTransparency( 1 - gc->FillOpacity * gc->Opacity );
603
item->setLineTransparency( 1 - gc->StrokeOpacity * gc->Opacity );
604
item->PLineEnd = gc->PLineEnd;
605
item->PLineJoin = gc->PLineJoin;
606
if (item->fillColor() == CommonStrings::None)
607
item->setTextFlowMode(PageItem::TextFlowDisabled);
609
item->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
610
item->DashOffset = gc->dashOffset;
611
item->DashValues = gc->dashArray;
612
if (gc->Gradient != 0)
614
if (gc->Gradient == 8)
616
item->GrType = gc->Gradient;
617
item->setPattern(importedPattTrans[gc->GCol1]);
618
QMatrix mm = gc->matrixg;
619
double rot = getRotationFromMatrix(mm, 0.0) * 180 / M_PI;
621
double patDx = (item->xPos() - BaseX) - mm.dx();
622
double patDy = (item->yPos() - BaseY) - mm.dy();
623
item->setPatternTransform(mm.m11() * 100.0, mm.m22() * 100.0, patDx, patDy, -rot);
627
if (gc->GradCo.Stops() > 1)
629
item->fill_gradient = gc->GradCo;
632
item->GrStartX = gc->GX1 * item->width();
633
item->GrStartY = gc->GY1 * item->height();
634
item->GrEndX = gc->GX2 * item->width();
635
item->GrEndY = gc->GY2 * item->height();
636
double angle1 = atan2(gc->GY2-gc->GY1,gc->GX2-gc->GX1)*(180.0/M_PI);
637
double angle2 = atan2(item->GrEndY - item->GrStartX, item->GrEndX - item->GrStartX)*(180.0/M_PI);
638
double dx = item->GrStartX + (item->GrEndX - item->GrStartX) / 2.0;
639
double dy = item->GrStartY + (item->GrEndY - item->GrStartY) / 2.0;
641
if ((gc->GY1 < gc->GY2) && (gc->GX1 < gc->GX2))
647
gra.setPoints(2, item->GrStartX-dx, item->GrStartY-dy, item->GrEndX-dx, item->GrEndY-dy);
649
gra.translate(dx, dy);
650
item->GrStartX = gra.point(0).x();
651
item->GrStartY = gra.point(0).y();
652
item->GrEndX = gra.point(1).x();
653
item->GrEndY = gra.point(1).y();
657
QMatrix mm = gc->matrix;
658
mm = gc->matrixg * mm;
660
gra.setPoints(2, gc->GX1, gc->GY1, gc->GX2, gc->GY2);
662
gc->GX1 = gra.point(0).x();
663
gc->GY1 = gra.point(0).y();
664
gc->GX2 = gra.point(1).x();
665
gc->GY2 = gra.point(1).y();
666
item->GrStartX = gc->GX1 - item->xPos() + BaseX;
667
item->GrStartY = gc->GY1 - item->yPos() + BaseY;
668
item->GrEndX = gc->GX2 - item->xPos() + BaseX;
669
item->GrEndY = gc->GY2 - item->yPos() + BaseY;
671
item->GrType = gc->Gradient;
676
QList<VColorStop*> cstops = gc->GradCo.colorStops();
677
item->setFillColor(cstops.at(0)->name);
678
item->setFillShade(cstops.at(0)->shade);
684
bool SVGPlug::isIgnorableNode( const QDomElement &e )
686
QString nodeName(e.tagName());
687
return isIgnorableNodeName(nodeName);
690
bool SVGPlug::isIgnorableNodeName( const QString &n )
692
if (n.startsWith("sodipodi") || n.startsWith("inkscape") || n == "metadata")
697
FPoint SVGPlug::parseTextPosition(const QDomElement &e, const FPoint* pos)
699
// FIXME According to spec, we should in fact return a point list
700
double x = pos ? pos->x() : 0.0;
701
double y = pos ? pos->y() : 0.0;
703
if (e.hasAttribute( "x" ))
705
QString xatt = e.attribute( "x" , "0" );
706
if ( xatt.contains(',') || xatt.contains(' ') )
708
xatt.replace(QChar(','), QChar(' '));
709
QStringList xl(xatt.split(QChar(' '), QString::SkipEmptyParts));
712
x = parseUnit( xatt );
715
if (e.hasAttribute( "y" ))
717
QString yatt = e.attribute( "y" , "0" );
718
if ( yatt.contains(',') || yatt.contains(' ') )
720
yatt.replace(QChar(','), QChar(' '));
721
QStringList yl(yatt.split(QChar(' '), QString::SkipEmptyParts));
724
y = parseUnit( yatt );
727
if (e.hasAttribute( "dx" ))
729
QString dxatt = e.attribute( "dx" , "0" );
730
if ( dxatt.contains(',') || dxatt.contains(' ') )
732
dxatt.replace(QChar(','), QChar(' '));
733
QStringList xl(dxatt.split(QChar(' '), QString::SkipEmptyParts));
736
x += parseUnit( dxatt );
739
if (e.hasAttribute( "dy" ))
741
QString dyatt = e.attribute( "dy" , "0" );
742
if ( dyatt.contains(',') || dyatt.contains(' ') )
744
dyatt.replace(QChar(','), QChar(' '));
745
QStringList xl(dyatt.split(QChar(' '), QString::SkipEmptyParts));
748
y += parseUnit( dyatt );
754
QSize SVGPlug::parseWidthHeight(const QDomElement &e)
756
QSize size(550, 841);
757
QString sw = e.attribute("width", "100%");
758
QString sh = e.attribute("height", "100%");
759
double w = 550, h = 841;
761
w = sw.endsWith("%") ? fromPercentage(sw) : parseUnit(sw);
763
h = sh.endsWith("%") ? fromPercentage(sh) : parseUnit(sh);
764
if (!e.attribute("viewBox").isEmpty())
766
QRect viewBox = parseViewBox(e);
767
double scw = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.width() : size.width();
768
double sch = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.height() : size.height();
769
w *= (sw.endsWith("%") ? scw : 1.0);
770
h *= (sh.endsWith("%") ? sch : 1.0);
774
w *= (sw.endsWith("%") ? size.width() : 1.0);
775
h *= (sh.endsWith("%") ? size.height() : 1.0);
777
// OpenOffice files may not have width and height attributes, so avoid unnecessary large dimensions
778
if (w > 10000 || h > 10000)
780
double m = max(w, h);
784
size.setWidth(qRound(w));
785
size.setHeight(qRound(h));
789
QRect SVGPlug::parseViewBox(const QDomElement &e)
791
QRect box(0, 0, 0, 0);
792
if ( !e.attribute( "viewBox" ).isEmpty() )
794
QString viewbox( e.attribute( "viewBox" ) );
795
QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split( ' ', QString::SkipEmptyParts );
796
if (points.size() > 3)
798
double left = ScCLocale::toDoubleC(points[0]);
799
double bottom = ScCLocale::toDoubleC(points[1]);
800
double width = ScCLocale::toDoubleC(points[2]);
801
double height = ScCLocale::toDoubleC(points[3]);
802
box.setCoords((int) left, (int) bottom, (int) (left + width), (int) (bottom + height));
808
void SVGPlug::parseDefs(const QDomElement &e)
810
for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
812
QDomElement b = n.toElement();
816
parseStyle( &svgStyle, b );
817
if ( !svgStyle.Display)
819
QString STag2 = b.tagName();
822
QString id = b.attribute("id", "");
824
m_nodeMap.insert(id, b);
827
else if ( STag2 == "linearGradient" || STag2 == "radialGradient" )
829
else if (STag2 == "clipPath")
831
else if (STag2 == "pattern")
833
else if ( b.hasAttribute("id") )
835
QString id = b.attribute("id");
837
m_nodeMap.insert(id, b);
842
void SVGPlug::parseClipPath(const QDomElement &e)
844
QString id(e.attribute("id"));
848
QDomNode n2 = e.firstChild();
849
QDomElement b2 = n2.toElement();
850
while (b2.nodeName() == "use")
851
b2 = getReferencedNode(b2);
852
if (b2.nodeName() == "path")
853
parseSVG( b2.attribute( "d" ), &clip );
854
else if (b2.nodeName() == "rect")
856
double x = parseUnit( b2.attribute( "x", "0.0" ));
857
double y = parseUnit( b2.attribute( "y", "0.0" ));
858
double width = parseUnit( b2.attribute( "width" ));
859
double height = parseUnit( b2.attribute( "height" ) );
860
clip.addQuadPoint(x, y, x, y, width+x, y, width+x, y);
861
clip.addQuadPoint(width+x, y, width+x, y, width+x, height+y, width+x, height+y);
862
clip.addQuadPoint(width+x, height+y, width+x, height+y, x, height+y, x, height+y);
863
clip.addQuadPoint(x, height+y, x, height+y, x, y, x, y);
865
if (clip.size() >= 2)
866
m_clipPaths.insert(id, clip);
870
void SVGPlug::parseClipPathAttr(const QDomElement &e, FPointArray& clipPath)
873
/* if (e.hasAttribute("style"))
875
QString style = e.attribute( "style" ).simplified();
876
QStringList substyles = style.split(';', QString::SkipEmptyParts);
877
for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
879
QStringList substyle = (*it).split(':', QString::SkipEmptyParts);
880
QString command(substyle[0].trimmed());
881
QString params(substyle[1].trimmed());
882
if (command == "clip-path")
884
if (params.startsWith( "url("))
886
unsigned int start = params.indexOf("#") + 1;
887
unsigned int end = params.lastIndexOf(")");
888
QString key = params.mid(start, end - start);
889
QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
890
if (it != m_clipPaths.end())
891
clipPath = it.value().copy();
896
if (e.hasAttribute("clip-path"))
898
QString attr = e.attribute("clip-path");
899
if (attr.startsWith( "url("))
901
unsigned int start = attr.indexOf("#") + 1;
902
unsigned int end = attr.lastIndexOf(")");
903
QString key = attr.mid(start, end - start);
904
QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
905
if (it != m_clipPaths.end())
906
clipPath = it.value().copy();
911
QList<PageItem*> SVGPlug::parseA(const QDomElement &e)
913
QList<PageItem*> aElements;
914
for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
916
QDomElement b = n.toElement();
917
if( b.isNull() || isIgnorableNode(b) )
920
parseStyle( &svgStyle, b);
921
if (!svgStyle.Display)
923
QList<PageItem*> el = parseElement(b);
924
for (int ec = 0; ec < el.count(); ++ec)
925
aElements.append(el.at(ec));
930
QList<PageItem*> SVGPlug::parseGroup(const QDomElement &e)
932
FPointArray clipPath;
933
QList<PageItem*> GElements, gElements;
934
double BaseX = m_Doc->currentPage()->xOffset();
935
double BaseY = m_Doc->currentPage()->yOffset();
938
parseClipPathAttr(e, clipPath);
939
int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, 1, 1, 0, CommonStrings::None, CommonStrings::None, true);
940
PageItem *neu = m_Doc->Items->at(z);
941
for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
943
QDomElement b = n.toElement();
944
if( b.isNull() || isIgnorableNode(b) )
947
parseStyle( &svgStyle, b);
948
if (!svgStyle.Display)
950
QList<PageItem*> el = parseElement(b);
951
for (int ec = 0; ec < el.count(); ++ec)
952
gElements.append(el.at(ec));
955
SvgStyle *gc = m_gc.top();
956
if (clipPath.size() == 0)
958
if (gc->clipPath.size() != 0)
959
clipPath = gc->clipPath.copy();
961
if (gElements.count() == 0 || (gElements.count() < 2 && (clipPath.size() == 0) && (gc->Opacity == 1.0)))
963
// Unfortunately we have to take the long route here, or we risk crash on undo/redo
964
// FIXME : create group object after parsing grouped objects
965
/*m_Doc->Items->takeAt(z);
967
Selection tmpSelection(m_Doc, false);
968
tmpSelection.addItem(neu);
969
m_Doc->itemSelection_DeleteItem(&tmpSelection);
970
for (int a = 0; a < m_Doc->Items->count(); ++a)
972
m_Doc->Items->at(a)->ItemNr = a;
974
for (int gr = 0; gr < gElements.count(); ++gr)
976
GElements.append(gElements.at(gr));
981
double minx = 99999.9;
982
double miny = 99999.9;
983
double maxx = -99999.9;
984
double maxy = -99999.9;
985
GElements.append(neu);
986
for (int gr = 0; gr < gElements.count(); ++gr)
988
PageItem* currItem = gElements.at(gr);
989
double x1, x2, y1, y2;
990
currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
991
minx = qMin(minx, x1);
992
miny = qMin(miny, y1);
993
maxx = qMax(maxx, x2);
994
maxy = qMax(maxy, y2);
998
double gw = maxx - minx;
999
double gh = maxy - miny;
1000
neu->setXYPos(gx, gy);
1001
neu->setWidthHeight(gw, gh);
1002
if (clipPath.size() != 0)
1004
QMatrix mm = gc->matrix;
1005
neu->PoLine = clipPath.copy();
1006
neu->PoLine.map(mm);
1007
neu->PoLine.translate(-gx + BaseX, -gy + BaseY);
1012
neu->SetRectFrame();
1013
neu->Clip = FlattenPath(neu->PoLine, neu->Segments);
1014
neu->Groups.push(m_Doc->GroupCounter);
1015
neu->isGroupControl = true;
1016
neu->groupsLastItem = gElements.at(gElements.count()-1);
1017
if( !e.attribute("id").isEmpty() )
1018
neu->setItemName(e.attribute("id"));
1020
neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
1021
neu->AutoName = false;
1022
neu->setFillTransparency(1 - gc->Opacity);
1023
neu->gXpos = neu->xPos() - gx;
1024
neu->gYpos = neu->yPos() - gy;
1027
for (int gr = 0; gr < gElements.count(); ++gr)
1029
gElements.at(gr)->Groups.push(m_Doc->GroupCounter);
1030
gElements.at(gr)->gXpos = gElements.at(gr)->xPos() - gx;
1031
gElements.at(gr)->gYpos = gElements.at(gr)->yPos() - gy;
1032
gElements.at(gr)->gWidth = gw;
1033
gElements.at(gr)->gHeight = gh;
1034
GElements.append(gElements.at(gr));
1036
neu->setRedrawBounding();
1037
neu->setTextFlowMode(PageItem::TextFlowDisabled);
1038
m_Doc->GroupCounter++;
1040
delete( m_gc.pop() );
1044
QList<PageItem*> SVGPlug::parseElement(const QDomElement &e)
1046
QList<PageItem*> GElements;
1047
if (e.hasAttribute("id"))
1048
m_nodeMap.insert(e.attribute("id"), e);
1049
QString STag = e.tagName();
1052
GElements = parseGroup( e );
1055
if ( STag == "defs" )
1057
else if ( STag == "a" )
1058
GElements = parseA(e);
1059
else if ( STag == "switch" )
1060
GElements = parseSwitch(e);
1061
else if ( STag == "symbol" )
1062
GElements = parseSymbol(e);
1063
else if ( STag == "use" )
1064
GElements = parseUse(e);
1065
else if ( STag == "linearGradient" || STag == "radialGradient" )
1067
else if ( STag == "rect" )
1068
GElements = parseRect(e);
1069
else if ( STag == "ellipse" )
1070
GElements = parseEllipse(e);
1071
else if ( STag == "circle" )
1072
GElements = parseCircle(e);
1073
else if ( STag == "line" )
1074
GElements = parseLine(e);
1075
else if ( STag == "path" )
1076
GElements = parsePath(e);
1077
else if ( STag == "polyline" || e.tagName() == "polygon" )
1078
GElements = parsePolyline(e);
1079
else if ( STag == "text" )
1080
GElements = parseText(e);
1081
else if ( STag == "clipPath" )
1083
else if ( STag == "desc" )
1085
if (groupLevel == 1)
1088
else if ( STag == "title" )
1090
if (groupLevel == 1)
1091
docTitle = e.text();
1093
else if ( STag == "image" )
1094
GElements = parseImage(e);
1095
/* else if ( STag == "i:pgf" )
1099
cdat = e.text().simplified();
1100
QList<QByteArray> cdlist = cdat.split(' ');
1101
for (int cd = 0; cd < cdlist.count(); cd++)
1103
ddat += QByteArray::fromBase64(cdlist[cd]);
1105
QFile outf("/home/franz/testdata.txt");
1106
outf.open(QIODevice::WriteOnly);
1109
QString f2 = "/home/franz/testdata_decom.ai";
1110
FILE *source = fopen("/home/franz/testdata.txt", "rb");
1111
FILE *dest = fopen(f2, "wb");
1117
strm.zalloc = Z_NULL;
1118
strm.zfree = Z_NULL;
1119
strm.opaque = Z_NULL;
1121
strm.next_in = Z_NULL;
1122
ret = inflateInit(&strm);
1127
strm.avail_in = fread(in, 1, 4096, source);
1130
(void)inflateEnd(&strm);
1133
if (strm.avail_in == 0)
1135
strm.next_in = (Bytef*)in;
1138
strm.avail_out = 4096;
1139
strm.next_out = (Bytef*)out;
1140
ret = inflate(&strm, Z_NO_FLUSH);
1141
assert(ret != Z_STREAM_ERROR);
1148
(void)inflateEnd(&strm);
1151
have = 4096 - strm.avail_out;
1152
if (fwrite(out, 1, have, dest) != have || ferror(dest))
1154
(void)inflateEnd(&strm);
1158
while (strm.avail_out == 0);
1160
while (ret != Z_STREAM_END);
1161
(void)inflateEnd(&strm);
1165
/* else if( STag == "image" )
1166
GElements = parseImage(e);
1168
else if (!isIgnorableNodeName(STag) )
1170
// warn if unsupported SVG feature are encountered
1171
if (!m_unsupportedFeatures.contains(STag))
1173
m_unsupportedFeatures.insert(STag, STag);
1174
qDebug() << QString("unsupported SVG feature: %1").arg(STag);
1181
QList<PageItem*> SVGPlug::parseCircle(const QDomElement &e)
1183
QList<PageItem*> CElements;
1184
double BaseX = m_Doc->currentPage()->xOffset();
1185
double BaseY = m_Doc->currentPage()->yOffset();
1186
double r = parseUnit( e.attribute( "r" ) );
1187
double x = parseUnit( e.attribute( "cx" ) ) - r;
1188
double y = parseUnit( e.attribute( "cy" ) ) - r;
1190
SvgStyle *gc = m_gc.top();
1191
int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, r * 2.0, r * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1192
PageItem* ite = m_Doc->Items->at(z);
1193
QMatrix mm = QMatrix();
1195
ite->PoLine.map(mm);
1196
FPoint wh = getMaxClipF(&ite->PoLine);
1197
ite->setWidthHeight(wh.x(), wh.y());
1199
CElements.append(ite);
1200
delete( m_gc.pop() );
1204
QList<PageItem*> SVGPlug::parseEllipse(const QDomElement &e)
1206
QList<PageItem*> EElements;
1207
double BaseX = m_Doc->currentPage()->xOffset();
1208
double BaseY = m_Doc->currentPage()->yOffset();
1209
double rx = parseUnit( e.attribute( "rx" ) );
1210
double ry = parseUnit( e.attribute( "ry" ) );
1211
double x = parseUnit( e.attribute( "cx" ) ) - rx;
1212
double y = parseUnit( e.attribute( "cy" ) ) - ry;
1214
SvgStyle *gc = m_gc.top();
1215
int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, rx * 2.0, ry * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1216
PageItem* ite = m_Doc->Items->at(z);
1217
QMatrix mm = QMatrix();
1219
ite->PoLine.map(mm);
1220
FPoint wh = getMaxClipF(&ite->PoLine);
1221
ite->setWidthHeight(wh.x(), wh.y());
1223
EElements.append(ite);
1224
delete( m_gc.pop() );
1228
QList<PageItem*> SVGPlug::parseImage(const QDomElement &e)
1230
FPointArray clipPath;
1231
QList<PageItem*> IElements;
1232
QString fname = e.attribute("xlink:href");
1233
double BaseX = m_Doc->currentPage()->xOffset();
1234
double BaseY = m_Doc->currentPage()->yOffset();
1235
double x = e.attribute( "x" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x" ) );
1236
double y = e.attribute( "y" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y" ) );
1237
double w = e.attribute( "width" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "width" ) );
1238
double h = e.attribute( "height" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "height" ) );
1240
parseClipPathAttr(e, clipPath);
1241
int z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, x+BaseX, y+BaseY, w, h, 1, m_Doc->toolSettings.dBrushPict, CommonStrings::None, true);
1242
PageItem* ite = m_Doc->Items->at(z);
1243
if (!fname.isEmpty())
1245
if (!fname.startsWith("data:"))
1246
m_Doc->LoadPict(fname, z);
1249
int startData = fname.indexOf(",");
1250
QString dataType = fname.left(startData);
1251
fname.remove(0, startData+1);
1254
if (dataType.contains("base64"))
1255
ba = QByteArray::fromBase64(ba);
1256
ite->tempImageFile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_svg_XXXXXX.png");
1257
ite->tempImageFile->open();
1258
QString fileName = getLongPathName(ite->tempImageFile->fileName());
1259
ite->tempImageFile->close();
1260
ite->isInlineImage = true;
1262
img.loadFromData(ba);
1263
img.save(fileName, "PNG");
1264
m_Doc->LoadPict(fileName, z);
1267
if (clipPath.size() != 0)
1268
ite->PoLine = clipPath.copy();
1270
ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
1272
IElements.append(ite);
1273
delete( m_gc.pop() );
1277
QList<PageItem*> SVGPlug::parseLine(const QDomElement &e)
1279
QList<PageItem*> LElements;
1280
double BaseX = m_Doc->currentPage()->xOffset();
1281
double BaseY = m_Doc->currentPage()->yOffset();
1282
double x1 = e.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x1" ) );
1283
double y1 = e.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y1" ) );
1284
double x2 = e.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x2" ) );
1285
double y2 = e.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y2" ) );
1287
SvgStyle *gc = m_gc.top();
1288
int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1289
PageItem* ite = m_Doc->Items->at(z);
1290
ite->PoLine.resize(4);
1291
ite->PoLine.setPoint(0, FPoint(x1, y1));
1292
ite->PoLine.setPoint(1, FPoint(x1, y1));
1293
ite->PoLine.setPoint(2, FPoint(x2, y2));
1294
ite->PoLine.setPoint(3, FPoint(x2, y2));
1296
LElements.append(ite);
1297
delete( m_gc.pop() );
1301
QList<PageItem*> SVGPlug::parsePath(const QDomElement &e)
1304
QList<PageItem*> PElements;
1305
double BaseX = m_Doc->currentPage()->xOffset();
1306
double BaseY = m_Doc->currentPage()->yOffset();
1308
SvgStyle *gc = m_gc.top();
1309
PageItem::ItemType itype = parseSVG(e.attribute("d"), &pArray) ? PageItem::PolyLine : PageItem::Polygon;
1310
int z = m_Doc->itemAdd(itype, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1311
PageItem* ite = m_Doc->Items->at(z);
1312
ite->fillRule = (gc->fillRule != "nonzero");
1313
ite->PoLine = pArray;
1314
if (ite->PoLine.size() < 4)
1316
// m_Doc->m_Selection->addItem(ite);
1317
tmpSel->addItem(ite);
1318
// m_Doc->itemSelection_DeleteItem();
1319
m_Doc->itemSelection_DeleteItem(tmpSel);
1320
// m_Doc->m_Selection->clear();
1325
PElements.append(ite);
1327
delete( m_gc.pop() );
1331
QList<PageItem*> SVGPlug::parsePolyline(const QDomElement &e)
1334
QList<PageItem*> PElements;
1335
double BaseX = m_Doc->currentPage()->xOffset();
1336
double BaseY = m_Doc->currentPage()->yOffset();
1338
SvgStyle *gc = m_gc.top();
1339
QString points = e.attribute( "points" );
1340
if (!points.isEmpty())
1342
QString STag = e.tagName();
1343
points = points.simplified().replace(',', " ");
1344
QStringList pointList = points.split( ' ', QString::SkipEmptyParts );
1345
if (( e.tagName() == "polygon" ) && (pointList.count() > 4))
1346
z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1348
z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1349
PageItem* ite = m_Doc->Items->at(z);
1350
ite->fillRule = (gc->fillRule != "nonzero");
1351
ite->PoLine.resize(0);
1352
ite->PoLine.svgInit();
1356
for( QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++ )
1360
x = ScCLocale::toDoubleC(*(it++));
1361
y = ScCLocale::toDoubleC(*it);
1362
ite->PoLine.svgMoveTo(x, y);
1367
x = ScCLocale::toDoubleC(*(it++));
1368
y = ScCLocale::toDoubleC(*it);
1369
ite->PoLine.svgLineTo(x, y);
1372
if (( STag == "polygon" ) && (pointList.count() > 4))
1373
ite->PoLine.svgClosePath();
1375
ite->convertTo(PageItem::PolyLine);
1377
PElements.append(ite);
1379
delete( m_gc.pop() );
1383
QList<PageItem*> SVGPlug::parseRect(const QDomElement &e)
1385
QList<PageItem*> RElements;
1386
double BaseX = m_Doc->currentPage()->xOffset();
1387
double BaseY = m_Doc->currentPage()->yOffset();
1388
double x = parseUnit( e.attribute( "x" ) );
1389
double y = parseUnit( e.attribute( "y" ) );
1390
double width = parseUnit( e.attribute( "width" ));
1391
double height = parseUnit( e.attribute( "height" ) );
1392
double rx = e.attribute( "rx" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "rx" ) );
1393
double ry = e.attribute( "ry" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "ry" ) );
1395
SvgStyle *gc = m_gc.top();
1396
int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, width, height, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1397
PageItem* ite = m_Doc->Items->at(z);
1398
if ((rx != 0) || (ry != 0))
1400
ite->setCornerRadius(qMax(rx, ry));
1401
ite->SetFrameRound();
1402
m_Doc->setRedrawBounding(ite);
1404
QMatrix mm = QMatrix();
1406
ite->PoLine.map(mm);
1407
FPoint wh = getMaxClipF(&ite->PoLine);
1408
ite->setWidthHeight(wh.x(), wh.y());
1410
RElements.append(ite);
1411
delete( m_gc.pop() );
1415
QList<PageItem*> SVGPlug::parseText(const QDomElement &e)
1417
QList<PageItem*> GElements;
1419
double chunkWidth = 0;
1420
FPoint currentPos = parseTextPosition(e);
1421
SvgStyle *gc = m_gc.top();
1422
if (gc->textAnchor != "start")
1423
getTextChunkWidth(e, chunkWidth);
1424
for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1426
if (n.isElement() && (n.toElement().tagName() == "tspan"))
1428
QList<PageItem*> el = parseTextSpan(n.toElement(), currentPos, chunkWidth);
1429
for (int ec = 0; ec < el.count(); ++ec)
1430
GElements.append(el.at(ec));
1434
QList<PageItem*> el = parseTextNode(n.toText(), currentPos, chunkWidth);
1435
for (int ec = 0; ec < el.count(); ++ec)
1436
GElements.append(el.at(ec));
1439
delete( m_gc.pop() );
1443
QList<PageItem*> SVGPlug::parseTextSpan(const QDomElement& e, FPoint& currentPos, double chunkW)
1445
QList<PageItem*> GElements;
1447
currentPos = parseTextPosition(e, ¤tPos);
1448
SvgStyle *gc = m_gc.top();
1449
if ((e.hasAttribute("x") || e.hasAttribute("y")) && (gc->textAnchor != "start"))
1452
getTextChunkWidth(e, chunkW);
1454
for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1456
if (n.isElement() && (n.toElement().tagName() == "tspan"))
1458
QList<PageItem*> el = parseTextSpan(n.toElement(), currentPos, chunkW);
1459
for (int ec = 0; ec < el.count(); ++ec)
1460
GElements.append(el.at(ec));
1464
QList<PageItem*> el = parseTextNode(n.toText(), currentPos, chunkW);
1465
for (int ec = 0; ec < el.count(); ++ec)
1466
GElements.append(el.at(ec));
1469
delete( m_gc.pop() );
1473
QList<PageItem*> SVGPlug::parseTextNode(const QDomText& e, FPoint& currentPos, double chunkW)
1475
QList<PageItem*> GElements;
1476
double BaseX = m_Doc->currentPage()->xOffset();
1477
double BaseY = m_Doc->currentPage()->yOffset();
1478
double StartX = currentPos.x(), StartY = currentPos.y();
1480
QString textString = e.data().simplified();
1481
if ( textString.isEmpty() )
1484
SvgStyle *gc = m_gc.top();
1485
QFont textFont = getFontFromStyle(*gc);
1486
QFontMetrics fm(textFont);
1487
double width = fm.width(textString);
1489
if( gc->textAnchor == "middle" )
1490
StartX -= chunkW / 2.0;
1491
else if( gc->textAnchor == "end")
1494
FPointArray textPath;
1495
QString textFillColor = gc->FillCol;
1496
QString textStrokeColor = gc->StrokeCol;
1497
QPainterPath painterPath;
1498
painterPath.addText( StartX, StartY, textFont, textString );
1499
textPath.fromQPainterPath(painterPath);
1500
if (textPath.size() > 0)
1502
// double lineWidth = 0.0;
1503
int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, textFillColor, textStrokeColor, true);
1504
PageItem* ite = m_Doc->Items->at(z);
1505
ite->PoLine = textPath;
1507
GElements.append(ite);
1509
currentPos.setX( currentPos.x() + width );
1513
QList<PageItem*> SVGPlug::parseSwitch(const QDomElement &e)
1517
QList<PageItem*> SElements;
1518
for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1520
QDomElement de = n.toElement();
1521
QString STag = de.tagName();
1522
if (STag == "foreignObject")
1524
if (de.hasAttribute("xlink:href"))
1526
href = de.attribute("xlink:href").mid(1);
1527
if (!href.isEmpty())
1530
for (QDomNode n1 = de.firstChild(); !n1.isNull(); n1 = n1.nextSibling())
1532
QDomElement de1 = n1.toElement();
1533
if (de1.hasAttribute("xlink:href"))
1535
href = de1.attribute("xlink:href").mid(1);
1536
if (!href.isEmpty())
1543
if (de.hasAttribute("requiredExtensions") || de.hasAttribute("requiredFeatures"))
1545
else if (de.hasAttribute("id") && hrefs.contains(de.attribute("id")))
1549
SElements = parseElement(de);
1550
if (SElements.count() > 0)
1558
QList<PageItem*> SVGPlug::parseSymbol(const QDomElement &e)
1560
QList<PageItem*> SElements;
1561
QString id = e.attribute("id");
1563
m_nodeMap.insert(id, e);
1567
QList<PageItem*> SVGPlug::parseUse(const QDomElement &e)
1569
QList<PageItem*> UElements;
1571
if( e.hasAttribute("x") || e.hasAttribute("y") )
1574
double xAtt = ScCLocale::toDoubleC(e.attribute("x", "0.0"));
1575
double yAtt = ScCLocale::toDoubleC(e.attribute("y", "0.0"));
1576
SvgStyle *gc = m_gc.top();
1577
gc->matrix = QMatrix(1.0, 0.0, 0.0, 1.0, xAtt, yAtt) * gc->matrix;
1579
QString href = e.attribute("xlink:href").mid(1);
1580
QMap<QString, QDomElement>::Iterator it = m_nodeMap.find(href);
1581
if (it != m_nodeMap.end())
1583
QDomElement elem = it.value().toElement();
1584
if( elem.tagName() == "symbol" )
1585
UElements = parseGroup(elem);
1587
UElements = parseElement(elem);
1589
delete (m_gc.pop());
1593
QFont SVGPlug::getFontFromStyle(SvgStyle& style)
1595
QFont font(QApplication::font());
1596
font.setStyleStrategy( QFont::PreferOutline );
1598
if (!style.FontFamily.isEmpty())
1599
font.setFamily(style.FontFamily);
1601
if (!style.FontStyle.isEmpty())
1603
if (style.FontStyle == "normal")
1604
font.setStyle(QFont::StyleNormal);
1605
else if (style.FontStyle == "italic")
1606
font.setStyle(QFont::StyleItalic);
1607
else if (style.FontStyle == "oblique")
1608
font.setStyle(QFont::StyleOblique);
1611
if (!style.FontWeight.isEmpty())
1613
if (style.FontWeight == "normal")
1614
font.setWeight(QFont::Normal);
1615
else if (style.FontWeight == "bold")
1616
font.setWeight(QFont::Bold);
1617
else if (style.FontWeight == "bolder")
1618
font.setWeight(QFont::DemiBold);
1619
else if (style.FontWeight == "lighter")
1620
font.setWeight(QFont::Light);
1623
bool weightIsNum = false;
1624
int fontWeight = style.FontWeight.toInt(&weightIsNum);
1627
if (fontWeight == 100 || fontWeight == 200)
1628
font.setWeight(QFont::Light);
1629
else if (fontWeight == 300 || fontWeight == 400)
1630
font.setWeight(QFont::Normal);
1631
else if (fontWeight == 500 || fontWeight == 600)
1632
font.setWeight(QFont::DemiBold);
1633
else if (fontWeight == 700 || fontWeight == 800)
1634
font.setWeight(QFont::Bold);
1635
else if (fontWeight == 900)
1636
font.setWeight(QFont::Black);
1641
if (!style.FontStretch.isEmpty())
1643
if (style.FontStretch == "normal")
1644
font.setStretch(QFont::Unstretched);
1645
else if (style.FontStretch == "ultra-condensed")
1646
font.setStretch(QFont::UltraCondensed);
1647
else if (style.FontStretch == "extra-condensed")
1648
font.setStretch(QFont::ExtraCondensed);
1649
else if (style.FontStretch == "condensed")
1650
font.setStretch(QFont::Condensed);
1651
else if (style.FontStretch == "semi-condensed")
1652
font.setStretch(QFont::SemiCondensed);
1653
else if (style.FontStretch == "semi-expanded")
1654
font.setStretch(QFont::SemiExpanded);
1655
else if (style.FontStretch == "expanded")
1656
font.setStretch(QFont::Expanded);
1657
else if (style.FontStretch == "extra-expanded")
1658
font.setStretch(QFont::ExtraExpanded);
1659
else if (style.FontStretch == "ultra-expanded")
1660
font.setStretch(QFont::UltraExpanded);
1661
else if (style.FontStretch == "narrower")
1662
font.setStretch(QFont::SemiCondensed);
1663
else if (style.FontStretch == "wider")
1664
font.setStretch(QFont::SemiExpanded);
1666
if (!style.textDecoration.isEmpty())
1668
bool underline = false, overline = false;
1669
bool strikeOut = false;
1670
if (style.textDecoration == "underline")
1672
else if (style.textDecoration == "overline")
1674
else if (style.textDecoration == "line-through")
1676
font.setUnderline(underline);
1677
font.setOverline(overline);
1678
font.setStrikeOut(strikeOut);
1680
font.setPointSize(style.FontSize / 10);
1684
QDomElement SVGPlug::getReferencedNode(const QDomElement &e)
1687
QMap<QString, QDomElement>::Iterator it;
1688
QString href = e.attribute("xlink:href").mid(1);
1689
it = m_nodeMap.find(href);
1690
if (it != m_nodeMap.end())
1691
ret = it.value().toElement();
1695
bool SVGPlug::getTextChunkWidth(const QDomElement &e, double& width)
1697
bool doBreak = false;
1699
QDomNode c = e.firstChild();
1700
for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1702
if (n.isElement() && (n.toElement().tagName() == "tspan"))
1704
QDomElement elem = n.toElement();
1705
if (elem.hasAttribute("x") || elem.hasAttribute("y"))
1710
doBreak = getTextChunkWidth(n.toElement(), width);
1715
QDomText text = n.toText();
1716
QString textString = text.data().simplified();
1717
if (textString.length() > 0)
1719
SvgStyle *gc = m_gc.top();
1720
QFont textFont = getFontFromStyle(*gc);
1721
QFontMetrics fm(textFont);
1722
width += fm.width(textString);
1726
delete (m_gc.pop());
1730
double SVGPlug::fromPercentage( const QString &s )
1733
if (s1.endsWith( ";" ))
1734
s1 = s1.left(s1.length() - 1);
1735
if (s1.endsWith( "%" ))
1737
s1 = s1.left(s1.length() - 1);
1738
return ScCLocale::toDoubleC(s1) / 100.0;
1741
return ScCLocale::toDoubleC(s1);
1744
double SVGPlug::parseFontSize(const QString& fsize)
1747
QString unit = fsize.right(2);
1748
if (unit == "pt" || unit == "cm" || unit == "mm" ||
1749
unit == "in" || unit == "px")
1753
double value = parseUnit(fsize);
1759
double SVGPlug::parseUnit(const QString &unit)
1761
bool noUnit = false;
1762
QString unitval=unit;
1763
if( unit.right( 2 ) == "pt" )
1764
unitval.replace( "pt", "" );
1765
else if( unit.right( 2 ) == "cm" )
1766
unitval.replace( "cm", "" );
1767
else if( unit.right( 2 ) == "mm" )
1768
unitval.replace( "mm" , "" );
1769
else if( unit.right( 2 ) == "in" )
1770
unitval.replace( "in", "" );
1771
else if( unit.right( 2 ) == "px" )
1772
unitval.replace( "px", "" );
1773
if (unitval == unit)
1775
double value = ScCLocale::toDoubleC(unitval);
1776
if( unit.right( 2 ) == "pt" )
1778
else if( unit.right( 2 ) == "cm" )
1779
value = ( value / 2.54 ) * 72;
1780
else if( unit.right( 2 ) == "mm" )
1781
value = ( value / 25.4 ) * 72;
1782
else if( unit.right( 2 ) == "in" )
1784
else if( unit.right( 2 ) == "px" )
1785
value = value * 0.8;
1791
QMatrix SVGPlug::parseTransform( const QString &transform )
1794
// Workaround for QString::split() bug when string ends with space
1795
QString trans = transform.simplified();
1796
// Split string for handling 1 transform statement at a time
1797
QStringList subtransforms = trans.split(')', QString::SkipEmptyParts);
1798
QStringList::ConstIterator it = subtransforms.begin();
1799
QStringList::ConstIterator end = subtransforms.end();
1800
for(; it != end; ++it)
1803
QStringList subtransform = it->split('(', QString::SkipEmptyParts);
1804
subtransform[0] = subtransform[0].trimmed().toLower();
1805
subtransform[1] = subtransform[1].simplified();
1806
QRegExp reg("[,( ]");
1807
QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
1808
if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
1809
subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
1810
if(subtransform[0] == "rotate")
1812
if(params.count() == 3)
1814
double x = ScCLocale::toDoubleC(params[1]);
1815
double y = ScCLocale::toDoubleC(params[2]);
1816
result.translate(x, y);
1817
result.rotate(ScCLocale::toDoubleC(params[0]));
1818
result.translate(-x, -y);
1821
result.rotate(ScCLocale::toDoubleC(params[0]));
1823
else if(subtransform[0] == "translate")
1825
if(params.count() == 2)
1826
result.translate(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[1]));
1827
else // Spec : if only one param given, assume 2nd param to be 0
1828
result.translate(ScCLocale::toDoubleC(params[0]), 0);
1830
else if(subtransform[0] == "scale")
1832
if(params.count() == 2)
1833
result.scale(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[1]));
1834
else // Spec : if only one param given, assume uniform scaling
1835
result.scale(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[0]));
1837
else if(subtransform[0] == "skewx")
1838
result.shear(tan(ScCLocale::toDoubleC(params[0]) * 0.01745329251994329576), 0.0F);
1839
else if(subtransform[0] == "skewy")
1840
result.shear(0.0F, tan(ScCLocale::toDoubleC(params[0]) * 0.01745329251994329576));
1841
else if(subtransform[0] == "matrix")
1843
if(params.count() >= 6)
1845
double sx = ScCLocale::toDoubleC(params[0]);
1846
double sy = ScCLocale::toDoubleC(params[3]);
1847
double p1 = ScCLocale::toDoubleC(params[1]);
1848
double p2 = ScCLocale::toDoubleC(params[2]);
1849
double p4 = ScCLocale::toDoubleC(params[4]);
1850
double p5 = ScCLocale::toDoubleC(params[5]);
1851
result.setMatrix(sx, p1, p2, sy, p4, p5);
1859
const char * SVGPlug::getCoord( const char *ptr, double &number )
1861
int integer, exponent;
1862
double decimal, frac;
1875
else if(*ptr == '-')
1881
// read the integer part
1882
while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1883
integer = (integer * 10) + *(ptr++) - '0';
1884
if(*ptr == '.') // read the decimals
1887
while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1888
decimal += (*(ptr++) - '0') * (frac *= 0.1);
1891
if(*ptr == 'e' || *ptr == 'E') // read the exponent part
1895
// read the sign of the exponent
1898
else if(*ptr == '-')
1905
while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1908
exponent += *ptr - '0';
1912
number = integer + decimal;
1913
number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
1914
// skip the following space
1921
bool SVGPlug::parseSVG( const QString &s, FPointArray *ite )
1923
return ite->parseSVG(s);
1927
QColor SVGPlug::parseColorN( const QString &rgbColor )
1930
keywordToRGB( rgbColor.toLower(), r, g, b );
1931
return QColor( r, g, b );
1935
QString SVGPlug::parseColor( const QString &s )
1938
QString ret = CommonStrings::None;
1939
if (s.length() > 11) // icc-color()
1941
int iccColorIndex = s.indexOf("icc-color");
1942
if (iccColorIndex >= 0)
1944
QString iccColorName = parseIccColor(s);
1945
if (iccColorName.length() > 0)
1946
return iccColorName;
1949
if (s.startsWith( "rgb(" ) )
1951
QString parse = s.trimmed();
1952
QStringList colors = parse.split(',', QString::SkipEmptyParts);
1953
QString r = colors[0].right( ( colors[0].length() - 4 ) );
1954
QString g = colors[1];
1955
QString b = colors[2].left( ( colors[2].length() - 1 ) );
1956
if (r.contains( "%" ))
1958
r = r.left( r.length() - 1 );
1959
r = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(r) ) / 100.0 ) ) );
1961
if (g.contains( "%" ))
1963
g = g.left( g.length() - 1 );
1964
g = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(g) ) / 100.0 ) ) );
1966
if (b.contains( "%" ))
1968
b = b.left( b.length() - 1 );
1969
b = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(b) ) / 100.0 ) ) );
1971
c = QColor(r.toInt(), g.toInt(), b.toInt());
1975
QString rgbColor = s.trimmed();
1976
if (rgbColor.startsWith( "#" ))
1978
rgbColor = rgbColor.left(7);
1979
c.setNamedColor( rgbColor );
1982
c = parseColorN( rgbColor );
1984
ColorList::Iterator it;
1988
for (it = m_Doc->PageColors.begin(); it != m_Doc->PageColors.end(); ++it)
1990
if (it.value().getColorModel() == colorModelRGB)
1992
it.value().getRGB(&r, &g, &b);
1993
tmpR.setRgb(r, g, b);
2006
tmp.setSpotColor(false);
2007
tmp.setRegistrationColor(false);
2008
QString newColorName = "FromSVG"+c.name();
2009
m_Doc->PageColors.insert(newColorName, tmp);
2010
importedColors.append(newColorName);
2016
QString SVGPlug::parseIccColor( const QString &s )
2020
bool iccColorFound = false, found = false;
2021
int iccColorIndex = s.indexOf("icc-color");
2022
if (iccColorIndex < 0)
2024
int iccFirst = s.indexOf("(", iccColorIndex);
2025
int iccLast = s.indexOf(")", iccColorIndex);
2026
if (iccFirst >= 0 && iccLast >= 0)
2028
QString iccColor = s.mid(iccFirst + 1, iccLast - iccFirst - 1);
2029
iccColor = iccColor.trimmed();
2030
QStringList colors = iccColor.split(',', QString::SkipEmptyParts);
2031
if (colors.count() == 5) // then we assume this is a cmyk color
2033
QString cs = colors[1], ms = colors[2], ys = colors[3], ks = colors[4];
2034
if (cs.contains( "%" ))
2036
cs = cs.left( cs.length() - 1 );
2037
cs = QString::number(ScCLocale::toDoubleC(cs) / 100);
2039
if (ms.contains( "%" ))
2041
ms = ms.left( ms.length() - 1 );
2042
ms = QString::number(ScCLocale::toDoubleC(ms) / 100);
2044
if (ys.contains( "%" ))
2046
ys = ys.left( ys.length() - 1 );
2047
ys = QString::number(ScCLocale::toDoubleC(ys) / 100);
2049
if (ks.contains( "%" ))
2051
ks = ks.left( ks.length() - 1 );
2052
ks = QString::number(ScCLocale::toDoubleC(ks) / 100);
2054
double cv = ScCLocale::toDoubleC(cs);
2055
double mv = ScCLocale::toDoubleC(ms);
2056
double yv = ScCLocale::toDoubleC(ys);
2057
double kv = ScCLocale::toDoubleC(ks);
2058
color.setCmykF(cv, mv, yv, kv);
2059
iccColorFound = true;
2062
if (iccColorFound == false)
2065
ColorList::Iterator it;
2066
for (it = m_Doc->PageColors.begin(); it != m_Doc->PageColors.end(); ++it)
2068
colorModel colorMod = it.value().getColorModel();
2069
if (colorMod == colorModelCMYK)
2071
it.value().getCMYK(&c, &m, &y, &k);
2072
tmpR.setCmyk(c, m, y, k);
2084
tmp.fromQColor(color);
2085
tmp.setSpotColor(false);
2086
tmp.setRegistrationColor(false);
2087
QString newColorName = "FromSVG"+tmp.name();
2088
m_Doc->PageColors.insert(newColorName, tmp);
2089
importedColors.append(newColorName);
2095
void SVGPlug::parsePA( SvgStyle *obj, const QString &command, const QString ¶ms )
2097
if( command == "display" )
2098
obj->Display = (params == "none") ? false : true;
2099
else if( command == "stroke-opacity" )
2100
obj->StrokeOpacity = fromPercentage(params);
2101
else if( command == "fill-opacity" )
2102
obj->FillOpacity = fromPercentage(params);
2103
else if( command == "opacity" )
2104
obj->Opacity = fromPercentage(params);
2105
else if( command == "fill" )
2107
// if ((obj->InherCol) && (params == "currentColor"))
2108
if (params == "currentColor")
2109
obj->FillCol = obj->CurCol;
2110
else if (params == "none")
2112
obj->FillCol = CommonStrings::None;
2114
else if( params.startsWith( "url(" ) )
2116
unsigned int start = params.indexOf("#") + 1;
2117
unsigned int end = params.lastIndexOf(")");
2118
QString key = params.mid(start, end - start);
2120
obj->matrixg = QMatrix();
2121
bool firstMatrixValid = false;
2122
if (m_gradients[key].matrixValid)
2124
firstMatrixValid = true;
2125
obj->matrixg = m_gradients[key].matrix;
2127
while (!m_gradients[key].reference.isEmpty())
2129
QString key2 = m_gradients[key].reference;
2130
if (m_gradients[key2].typeValid)
2131
obj->Gradient = m_gradients[key2].Type;
2132
if (obj->Gradient != 8)
2134
if (m_gradients[key2].gradientValid)
2135
obj->GradCo = m_gradients[key2].gradient;
2136
if (m_gradients[key2].cspaceValid)
2137
obj->CSpace = m_gradients[key2].CSpace;
2138
if (m_gradients[key2].x1Valid)
2139
obj->GX1 = m_gradients[key2].X1;
2140
if (m_gradients[key2].y1Valid)
2141
obj->GY1 = m_gradients[key2].Y1;
2142
if (m_gradients[key2].x2Valid)
2143
obj->GX2 = m_gradients[key2].X2;
2144
if (m_gradients[key2].y2Valid)
2145
obj->GY2 = m_gradients[key2].Y2;
2146
if (m_gradients[key2].matrixValid)
2147
obj->matrixg = m_gradients[key2].matrix;
2152
if ((m_gradients[key2].matrixValid) && (!firstMatrixValid))
2153
obj->matrixg *= m_gradients[key2].matrix;
2155
key = m_gradients[key].reference;
2157
if (obj->Gradient != 8)
2159
key = params.mid(start, end - start);
2160
if (m_gradients[key].typeValid)
2161
obj->Gradient = m_gradients[key].Type;
2162
if (obj->Gradient != 8)
2164
if (m_gradients[key].gradientValid)
2165
obj->GradCo = m_gradients[key].gradient;
2166
if (m_gradients[key].cspaceValid)
2167
obj->CSpace = m_gradients[key].CSpace;
2168
if (m_gradients[key].x1Valid)
2169
obj->GX1 = m_gradients[key].X1;
2170
if (m_gradients[key].y1Valid)
2171
obj->GY1 = m_gradients[key].Y1;
2172
if (m_gradients[key].x2Valid)
2173
obj->GX2 = m_gradients[key].X2;
2174
if (m_gradients[key].y2Valid)
2175
obj->GY2 = m_gradients[key].Y2;
2176
if (m_gradients[key].matrixValid)
2177
obj->matrixg = m_gradients[key].matrix;
2182
if (m_gradients[key].matrixValid)
2183
obj->matrixg = m_gradients[key].matrix;
2186
obj->FillCol = CommonStrings::None;
2189
obj->FillCol = parseColor(params);
2191
else if( command == "fill-rule" )
2193
obj->fillRule = params;
2195
else if( command == "color" )
2197
if (params == "none")
2198
obj->CurCol = CommonStrings::None;
2199
else if( params.startsWith( "url(" ) )
2200
obj->CurCol = CommonStrings::None;
2201
else if (params == "currentColor")
2202
obj->CurCol = obj->CurCol;
2204
obj->CurCol = parseColor(params);
2206
else if( command == "stroke" )
2208
// if ((obj->InherCol) && (params == "currentColor"))
2209
if (params == "currentColor")
2210
obj->StrokeCol = obj->CurCol;
2211
else if (params == "none")
2213
obj->StrokeCol = CommonStrings::None;
2215
else if( params.startsWith( "url(" ) )
2217
obj->StrokeCol = CommonStrings::None;
2220
obj->StrokeCol = parseColor(params);
2221
/* if( params == "none" )
2222
gc->stroke.setType( VStroke::none );
2223
else if( params.startsWith( "url(" ) )
2225
unsigned int start = params.find("#") + 1;
2226
unsigned int end = params.lastIndexOf(")");
2227
QString key = params.mid( start, end - start );
2228
gc->stroke.gradient() = m_gradients[ key ].gradient;
2229
gc->stroke.gradient().transform( m_gradients[ key ].gradientTransform );
2230
gc->stroke.gradient().transform( gc->matrix );
2231
gc->stroke.setType( VStroke::grad );
2235
parseColor( strokecolor, params );
2236
gc->stroke.setType( VStroke::solid );
2239
else if( command == "stroke-width" )
2240
obj->LWidth = parseUnit( params );
2241
else if( command == "stroke-linejoin" )
2243
if( params == "miter" )
2244
obj->PLineJoin = Qt::MiterJoin;
2245
else if( params == "round" )
2246
obj->PLineJoin = Qt::RoundJoin;
2247
else if( params == "bevel" )
2248
obj->PLineJoin = Qt::BevelJoin;
2250
else if( command == "stroke-linecap" )
2252
if( params == "butt" )
2253
obj->PLineEnd = Qt::FlatCap;
2254
else if( params == "round" )
2255
obj->PLineEnd = Qt::RoundCap;
2256
else if( params == "square" )
2257
obj->PLineEnd = Qt::SquareCap;
2259
// else if( command == "stroke-miterlimit" )
2260
// gc->stroke.setMiterLimit( params.todouble() );
2261
else if( command == "stroke-dasharray" )
2263
QVector<double> array;
2264
if(params != "none")
2266
QString params2 = params.simplified().replace(',', " ");
2267
QStringList dashes = params2.split(' ', QString::SkipEmptyParts);
2268
for( QStringList::Iterator it = dashes.begin(); it != dashes.end(); ++it )
2269
array.append( ScCLocale::toDoubleC(*it) );
2271
obj->dashArray = array;
2273
else if( command == "stroke-dashoffset" )
2274
obj->dashOffset = ScCLocale::toDoubleC(params);
2275
else if( command == "font-family" )
2276
obj->FontFamily = params;
2277
else if( command == "font-style" )
2278
obj->FontStyle = params;
2279
else if( command == "font-weight" )
2280
obj->FontWeight = params;
2281
else if( command == "font-stretch" )
2282
obj->FontStretch = params;
2283
else if( command == "font-size" )
2284
obj->FontSize = static_cast<int>(parseFontSize(params) * 10.0);
2285
else if( command == "text-anchor" )
2286
obj->textAnchor = params;
2287
else if( command == "text-decoration" )
2288
obj->textDecoration = params;
2289
else if (command == "clip-path")
2291
if (params.startsWith( "url("))
2293
unsigned int start = params.indexOf("#") + 1;
2294
unsigned int end = params.lastIndexOf(")");
2295
QString key = params.mid(start, end - start);
2296
QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
2297
if (it != m_clipPaths.end())
2298
obj->clipPath = it.value().copy();
2301
else if( !isIgnorableNodeName(command) )
2303
if (!m_unsupportedFeatures.contains(command))
2305
m_unsupportedFeatures.insert(command, command);
2306
qDebug() << QString("unsupported SVG feature: %1").arg(command);
2312
void SVGPlug::parseStyle( SvgStyle *obj, const QDomElement &e )
2314
SvgStyle *gc = m_gc.top();
2317
if( !e.attribute( "display" ).isEmpty() )
2318
parsePA( obj, "display", e.attribute( "display" ) );
2319
if( !e.attribute( "color" ).isEmpty() )
2321
if (e.attribute( "color" ) == "inherit")
2322
gc->InherCol = true;
2324
parsePA( obj, "color", e.attribute( "color" ) );
2326
if( !e.attribute( "fill" ).isEmpty() )
2327
parsePA( obj, "fill", e.attribute( "fill" ) );
2328
if( !e.attribute( "stroke" ).isEmpty() )
2329
parsePA( obj, "stroke", e.attribute( "stroke" ) );
2330
if( !e.attribute( "stroke-width" ).isEmpty() )
2331
parsePA( obj, "stroke-width", e.attribute( "stroke-width" ) );
2332
if( !e.attribute( "stroke-linejoin" ).isEmpty() )
2333
parsePA( obj, "stroke-linejoin", e.attribute( "stroke-linejoin" ) );
2334
if( !e.attribute( "stroke-linecap" ).isEmpty() )
2335
parsePA( obj, "stroke-linecap", e.attribute( "stroke-linecap" ) );
2336
if( !e.attribute( "stroke-dasharray" ).isEmpty() )
2337
parsePA( obj, "stroke-dasharray", e.attribute( "stroke-dasharray" ) );
2338
if( !e.attribute( "stroke-dashoffset" ).isEmpty() )
2339
parsePA( obj, "stroke-dashoffset", e.attribute( "stroke-dashoffset" ) );
2340
if( !e.attribute( "stroke-opacity" ).isEmpty() )
2341
parsePA( obj, "stroke-opacity", e.attribute( "stroke-opacity" ) );
2342
/* if( !e.attribute( "stroke-miterlimit" ).isEmpty() )
2343
parsePA( obj, "stroke-miterlimit", e.attribute( "stroke-miterlimit" ) ); */
2344
if( !e.attribute( "fill-rule" ).isEmpty() )
2345
parsePA( obj, "fill-rule", e.attribute( "fill-rule" ) );
2346
if( !e.attribute( "fill-opacity" ).isEmpty() )
2347
parsePA( obj, "fill-opacity", e.attribute( "fill-opacity" ) );
2348
if( !e.attribute( "opacity" ).isEmpty() )
2349
parsePA( obj, "opacity", e.attribute( "opacity" ) );
2350
if( !e.attribute( "font-family" ).isEmpty() )
2351
parsePA( obj, "font-family", e.attribute( "font-family" ) );
2352
if( !e.attribute( "font-style" ).isEmpty() )
2353
parsePA( obj, "font-style", e.attribute( "font-style" ) );
2354
if( !e.attribute( "font-weight" ).isEmpty() )
2355
parsePA( obj, "font-weight", e.attribute( "font-weight" ) );
2356
if( !e.attribute( "font-stretch" ).isEmpty() )
2357
parsePA( obj, "font-stretch", e.attribute( "font-stretch" ) );
2358
if( !e.attribute( "font-size" ).isEmpty() )
2359
parsePA( obj, "font-size", e.attribute( "font-size" ) );
2360
if( !e.attribute( "text-anchor" ).isEmpty() )
2361
parsePA( obj, "text-anchor", e.attribute( "text-anchor" ) );
2362
if( !e.attribute( "text-decoration" ).isEmpty() )
2363
parsePA( obj, "text-decoration", e.attribute( "text-decoration" ) );
2364
QString style = e.attribute( "style" ).simplified();
2365
QStringList substyles = style.split(';', QString::SkipEmptyParts);
2366
for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
2368
QStringList substyle = (*it).split(':', QString::SkipEmptyParts);
2369
QString command(substyle[0].trimmed());
2370
QString params(substyle[1].trimmed());
2371
parsePA( obj, command, params );
2376
void SVGPlug::parseColorStops(GradientHelper *gradient, const QDomElement &e)
2378
QString Col = "Black";
2382
parseStyle( &svgStyle, e );
2383
for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
2386
QDomElement stop = n.toElement();
2387
if(stop.tagName() == "stop")
2389
QString temp = stop.attribute( "offset" );
2390
if( temp.contains( '%' ) )
2392
temp = temp.left( temp.length() - 1 );
2393
offset = ScCLocale::toDoubleC(temp) / 100.0;
2396
offset = ScCLocale::toDoubleC(temp);
2397
if( !stop.attribute( "stop-opacity" ).isEmpty() )
2398
opa = fromPercentage(stop.attribute("stop-opacity"));
2399
if( !stop.attribute( "stop-color" ).isEmpty() )
2401
if (stop.attribute("stop-color") == "currentColor")
2402
Col = svgStyle.CurCol;
2404
Col = parseColor(stop.attribute("stop-color"));
2408
QString style = stop.attribute( "style" ).simplified();
2409
QStringList substyles = style.split(';', QString::SkipEmptyParts);
2410
for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
2412
QStringList substyle = (*it).split(':', QString::SkipEmptyParts);
2413
QString command(substyle[0].trimmed());
2414
QString params(substyle[1].trimmed());
2415
if( command == "stop-color" )
2416
Col = parseColor(params);
2417
if( command == "stop-opacity" )
2418
opa = fromPercentage(params);
2422
const ScColor& gradC = m_Doc->PageColors[Col];
2423
gradient->gradient.addStop( ScColorEngine::getRGBColor(gradC, m_Doc), offset, 0.5, opa, Col, 100 );
2424
gradient->gradientValid = true;
2426
if (gradient->gradientValid)
2427
gradient->gradient.filterStops();
2430
void SVGPlug::parsePattern(const QDomElement &b)
2432
GradientHelper gradhelper;
2433
QString href = b.attribute("xlink:href").mid(1);
2434
if (!href.isEmpty())
2436
if (m_gradients.contains(href))
2438
gradhelper.Type = m_gradients[href].Type;
2439
gradhelper.gradientValid = m_gradients[href].gradientValid;
2440
gradhelper.typeValid = m_gradients[href].typeValid;
2441
gradhelper.matrix = m_gradients[href].matrix;
2442
gradhelper.matrixValid = m_gradients[href].matrixValid;
2444
gradhelper.reference = href;
2446
QString id = b.attribute("id", "");
2447
QString origName = id;
2450
inGroupXOrigin = 999999;
2451
inGroupYOrigin = 999999;
2452
double wpat = parseUnit(b.attribute("width", "0"));
2453
double hpat = parseUnit(b.attribute("height", "0"));
2454
int ac = m_Doc->Items->count();
2455
QList<PageItem*> GElements;
2456
GElements = parseGroup( b );
2457
int ae = m_Doc->Items->count();
2458
if (GElements.count() > 0)
2460
ScPattern pat = ScPattern();
2462
PageItem* currItem = GElements.at(0);
2463
m_Doc->DoDrawing = true;
2464
pat.pattern = currItem->DrawObj_toImage();
2467
if (inGroupXOrigin < 0.0)
2468
xOrg = inGroupXOrigin;
2469
if (inGroupYOrigin < 0.0)
2470
yOrg = inGroupYOrigin;
2471
if ((xOrg != 0.0) || (yOrg != 0.0))
2472
pat.pattern = pat.pattern.copy(-xOrg, -yOrg, wpat, hpat);
2475
m_Doc->DoDrawing = false;
2476
pat.width = qMin(currItem->gWidth, wpat);
2477
pat.height = qMin(currItem->gHeight, hpat);
2479
for (int as = ac; as < ae; ++as)
2481
PageItem* Neu = m_Doc->Items->takeAt(ac);
2484
Neu->moveBy(xOrg, yOrg, true);
2489
Neu->ItemNr = pat.items.count();
2490
pat.items.append(Neu);
2492
m_Doc->addPattern(id, pat);
2493
importedPatterns.append(id);
2494
importedPattTrans.insert(origName, id);
2496
m_nodeMap.insert(origName, b);
2497
QString transf = b.attribute("patternTransform");
2498
if( !transf.isEmpty() )
2500
gradhelper.matrix = parseTransform( b.attribute("patternTransform") );
2501
gradhelper.matrixValid = true;
2504
gradhelper.matrixValid = false;
2505
gradhelper.gradientValid = true;
2506
gradhelper.gradient.clearStops();
2507
gradhelper.gradient.setRepeatMethod( VGradient::none );
2508
gradhelper.Type = 8;
2509
gradhelper.typeValid = true;
2510
m_gradients.insert(origName, gradhelper);
2514
void SVGPlug::parseGradient( const QDomElement &e )
2516
GradientHelper gradhelper;
2517
gradhelper.gradientValid = false;
2518
gradhelper.gradient.clearStops();
2519
gradhelper.gradient.setRepeatMethod( VGradient::none );
2521
QString href = e.attribute("xlink:href").mid(1);
2522
double x1=0, y1=0, x2=0, y2=0;
2523
if (!href.isEmpty())
2525
if (m_gradients.contains(href))
2527
gradhelper.Type = m_gradients[href].Type;
2528
gradhelper.gradient = m_gradients[href].gradient;
2529
gradhelper.X1 = m_gradients[href].X1;
2530
gradhelper.Y1 = m_gradients[href].Y1;
2531
gradhelper.X2 = m_gradients[href].X2;
2532
gradhelper.Y2 = m_gradients[href].Y2;
2533
gradhelper.CSpace = m_gradients[href].CSpace;
2534
gradhelper.matrix = m_gradients[href].matrix;
2535
gradhelper.x1Valid = m_gradients[href].x1Valid;
2536
gradhelper.x2Valid = m_gradients[href].x2Valid;
2537
gradhelper.y1Valid = m_gradients[href].y1Valid;
2538
gradhelper.y2Valid = m_gradients[href].y2Valid;
2539
gradhelper.cspaceValid = m_gradients[href].cspaceValid;
2540
gradhelper.matrixValid = m_gradients[href].matrixValid;
2541
gradhelper.gradientValid = m_gradients[href].gradientValid;
2542
gradhelper.typeValid = m_gradients[href].typeValid;
2544
gradhelper.reference = href;
2546
if (e.tagName() == "linearGradient")
2548
if (e.hasAttribute("x1"))
2550
gradhelper.X1 = parseUnit(e.attribute("x1", "0"));
2551
gradhelper.x1Valid = true;
2553
if (e.hasAttribute("y1"))
2555
gradhelper.Y1 = parseUnit(e.attribute("y1", "0"));
2556
gradhelper.y1Valid = true;
2558
if (e.hasAttribute("x2"))
2560
gradhelper.X2 = parseUnit(e.attribute("x2", "1"));
2561
gradhelper.x2Valid = true;
2563
if (e.hasAttribute("y2"))
2565
gradhelper.Y2 = parseUnit(e.attribute("y2", "0"));
2566
gradhelper.y2Valid = true;
2568
gradhelper.Type = 6;
2569
gradhelper.typeValid = true;
2573
if (e.hasAttribute("cx"))
2575
x1 = parseUnit(e.attribute("cx","0.5"));
2576
gradhelper.x1Valid = true;
2578
if (e.hasAttribute("cy"))
2580
y1 = parseUnit(e.attribute("cy", "0.5"));
2581
gradhelper.y1Valid = true;
2583
if (e.hasAttribute("r"))
2585
x2 = parseUnit(e.attribute("r", "0.5"));
2586
gradhelper.x2Valid = true;
2589
gradhelper.y2Valid = true;
2592
gradhelper.X2 = x1 + x2;
2594
gradhelper.Type = 7;
2595
gradhelper.typeValid = true;
2597
if ( !e.attribute( "gradientUnits" ).isEmpty() )
2599
QString uni = e.attribute( "gradientUnits");
2600
if (uni == "userSpaceOnUse")
2601
gradhelper.CSpace = true;
2603
gradhelper.CSpace = false;
2604
gradhelper.cspaceValid = true;
2608
gradhelper.CSpace = false;
2609
gradhelper.cspaceValid = false;
2611
QString transf = e.attribute("gradientTransform");
2612
if( !transf.isEmpty() )
2614
gradhelper.matrix = parseTransform( e.attribute("gradientTransform") );
2615
gradhelper.matrixValid = true;
2618
gradhelper.matrixValid = false;
2619
QString spreadMethod = e.attribute( "spreadMethod" );
2620
if( !spreadMethod.isEmpty() )
2622
if( spreadMethod == "reflect" )
2623
gradhelper.gradient.setRepeatMethod( VGradient::reflect );
2624
else if( spreadMethod == "repeat" )
2625
gradhelper.gradient.setRepeatMethod( VGradient::repeat );
2627
parseColorStops(&gradhelper, e);
2628
m_gradients.insert(e.attribute("id"), gradhelper);