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.
7
/***************************************************************************
8
svgexplugin.cpp - description
10
begin : Sun Aug 3 08:00:00 CEST 2002
11
copyright : (C) 2002 by Franz Schmid
12
email : Franz.Schmid@altmuehlnet.de
13
***************************************************************************/
15
/***************************************************************************
17
* This program is free software; you can redistribute it and/or modify *
18
* it under the terms of the GNU General Public License as published by *
19
* the Free Software Foundation; either version 2 of the License, or *
20
* (at your option) any later version. *
22
***************************************************************************/
25
#include <QTextStream>
26
#include <QDataStream>
31
#include <QScopedPointer>
33
#include "svgexplugin.h"
37
#include "cmsettings.h"
38
#include "commonstrings.h"
39
#include "customfdialog.h"
40
#include "scribuscore.h"
43
#include "prefsmanager.h"
44
#include "prefsfile.h"
45
#include "prefscontext.h"
46
#include "scmessagebox.h"
47
#include "scpattern.h"
49
#include "util_math.h"
50
#include "customfdialog.h"
51
#include "sctextstruct.h"
52
#include "guidemanager.h"
53
#include "sccolorengine.h"
54
#include "util_formats.h"
56
int svgexplugin_getPluginAPIVersion()
58
return PLUGIN_API_VERSION;
61
ScPlugin* svgexplugin_getPlugin()
63
SVGExportPlugin* plug = new SVGExportPlugin();
68
void svgexplugin_freePlugin(ScPlugin* plugin)
70
SVGExportPlugin* plug = dynamic_cast<SVGExportPlugin*>(plugin);
75
SVGExportPlugin::SVGExportPlugin() : ScActionPlugin()
77
// Set action info in languageChange, so we only have to do
82
SVGExportPlugin::~SVGExportPlugin() {};
84
void SVGExportPlugin::languageChange()
86
// Note that we leave the unused members unset. They'll be initialised
87
// with their default ctors during construction.
89
m_actionInfo.name = "ExportAsSVG";
90
// Action text for menu, including accel
91
m_actionInfo.text = tr("Save as &SVG...");
93
m_actionInfo.menu = "FileExport";
94
m_actionInfo.enabledOnStartup = false;
95
m_actionInfo.needsNumObjects = -1;
98
const QString SVGExportPlugin::fullTrName() const
100
return QObject::tr("SVG Export");
103
const ScActionPlugin::AboutData* SVGExportPlugin::getAboutData() const
105
AboutData* about = new AboutData;
106
about->authors = "Franz Schmid <franz@scribus.info>";
107
about->shortDescription = tr("Exports SVG Files");
108
about->description = tr("Exports the current page into an SVG file.");
109
about->license = "GPL";
114
void SVGExportPlugin::deleteAboutData(const AboutData* about) const
120
bool SVGExportPlugin::run(ScribusDoc* doc, QString filename)
122
Q_ASSERT(filename.isEmpty());
126
PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("svgex");
127
QString wdir = prefs->get("wdir", ".");
128
QScopedPointer<CustomFDialog> openDia( new CustomFDialog(doc->scMW(), wdir, QObject::tr("Save as"), QObject::tr("%1;;All Files (*)").arg(FormatsManager::instance()->extensionsForFormat(FormatsManager::SVG)), fdHidePreviewCheckBox) );
129
openDia->setSelection(getFileNameByPage(doc, doc->currentPage()->pageNr(), "svg"));
130
openDia->setExtension("svg");
131
openDia->setZipExtension("svgz");
132
QCheckBox* compress = new QCheckBox(openDia.data());
133
compress->setText( tr("Compress File"));
134
compress->setChecked(false);
135
openDia->addWidgets(compress);
136
QCheckBox* inlineImages = new QCheckBox(openDia.data());
137
inlineImages->setText( tr("Save Images inline"));
138
inlineImages->setToolTip( tr("Adds all Images on the Page inline to the SVG.\nCaution: this will increase the file size!"));
139
inlineImages->setChecked(true);
140
openDia->addWidgets(inlineImages);
141
QCheckBox* exportBack = new QCheckBox(openDia.data());
142
exportBack->setText( tr("Export Page background"));
143
exportBack->setToolTip( tr("Adds the Page itself as background to the SVG."));
144
exportBack->setChecked(false);
145
openDia->addWidgets(exportBack);
147
if (!openDia->exec())
149
fileName = openDia->selectedFile();
150
QFileInfo fi(fileName);
151
QString baseDir = fi.absolutePath();
152
if (compress->isChecked())
153
fileName = baseDir + "/" + fi.baseName() + ".svgz";
155
fileName = baseDir + "/" + fi.baseName() + ".svg";
158
Options.inlineImages = inlineImages->isChecked();
159
Options.exportPageBackground = exportBack->isChecked();
160
Options.compressFile = compress->isChecked();
162
if (fileName.isEmpty())
164
prefs->set("wdir", fileName.left(fileName.lastIndexOf("/")));
168
int exit = QMessageBox::warning(doc->scMW(), CommonStrings::trWarning,
169
QObject::tr("Do you really want to overwrite the file:\n%1 ?").arg(fileName),
170
QMessageBox::Yes | QMessageBox::No);
171
if (exit == QMessageBox::No)
174
SVGExPlug *dia = new SVGExPlug(doc);
175
dia->doExport(fileName, Options);
181
SVGExPlug::SVGExPlug( ScribusDoc* doc )
184
Options.inlineImages = true;
185
Options.exportPageBackground = false;
186
Options.compressFile = false;
190
bool SVGExPlug::doExport( QString fName, SVGOptions &Opts )
193
QFileInfo fiBase(fName);
194
baseDir = fiBase.absolutePath();
199
docu = QDomDocument("svgdoc");
200
QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
201
QString st = "<svg></svg>";
203
page = m_Doc->currentPage();
204
double pageWidth = page->width();
205
double pageHeight = page->height();
206
docElement = docu.documentElement();
207
docElement.setAttribute("width", FToStr(pageWidth)+"pt");
208
docElement.setAttribute("height", FToStr(pageHeight)+"pt");
209
docElement.setAttribute("viewBox", QString("0 0 %1 %2").arg(pageWidth).arg(pageHeight));
210
docElement.setAttribute("xmlns", "http://www.w3.org/2000/svg");
211
docElement.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");
212
docElement.setAttribute("version","1.1");
213
if (!m_Doc->documentInfo.getTitle().isEmpty())
215
QDomText title = docu.createTextNode(m_Doc->documentInfo.getTitle());
216
QDomElement titleElem = docu.createElement("title");
217
titleElem.appendChild(title);
218
docElement.appendChild(titleElem);
220
if (!m_Doc->documentInfo.getComments().isEmpty())
222
QDomText desc = docu.createTextNode(m_Doc->documentInfo.getComments());
223
QDomElement descElem = docu.createElement("desc");
224
descElem.appendChild(desc);
225
docElement.appendChild(descElem);
227
globalDefs = docu.createElement("defs");
228
docElement.appendChild(globalDefs);
229
if (Options.exportPageBackground)
231
QDomElement backG = docu.createElement("rect");
232
backG.setAttribute("x", "0");
233
backG.setAttribute("y", "0");
234
backG.setAttribute("width", FToStr(pageWidth));
235
backG.setAttribute("height", FToStr(pageHeight));
236
backG.setAttribute("style", "fill:"+m_Doc->papColor.name()+";" + "stroke:none;");
237
docElement.appendChild(backG);
239
page = m_Doc->MasterPages.at(m_Doc->MasterNames[m_Doc->currentPage()->MPageNam]);
241
page = m_Doc->currentPage();
243
if(Options.compressFile)
246
QByteArray array(docu.toString().toUtf8());
247
if (!ScGzFile::writeToFile(fName, array, vo.toUtf8().data()))
253
if(!f.open(QIODevice::WriteOnly))
257
wr += docu.toString();
258
QByteArray utf8wr = wr.toUtf8();
259
s.writeRawData(utf8wr.data(), utf8wr.length());
265
void SVGExPlug::ProcessPage(Page *page)
269
ll.isPrintable = false;
271
QDomElement layerGroup;
273
QList<PageItem*> Items;
274
QStack<PageItem*> groupStack;
275
QStack<QDomElement> groupStack2;
276
Page* SavedAct = m_Doc->currentPage();
277
if (page->pageName().isEmpty())
278
Items = m_Doc->DocItems;
280
Items = m_Doc->MasterItems;
281
if (Items.count() == 0)
283
m_Doc->setCurrentPage(page);
284
for (int la = 0; la < m_Doc->Layers.count(); la++)
286
m_Doc->Layers.levelToLayer(ll, Lnr);
289
layerGroup = docu.createElement("g");
290
layerGroup.setAttribute("id", ll.Name);
291
if (ll.transparency != 1.0)
292
layerGroup.setAttribute("opacity", FToStr(ll.transparency));
293
for(int j = 0; j < Items.count(); ++j)
296
if (Item->LayerNr != ll.LNr)
298
if (!Item->printEnabled())
300
double x = page->xOffset();
301
double y = page->yOffset();
302
double w = page->width();
303
double h = page->height();
304
double x2 = Item->BoundingX;
305
double y2 = Item->BoundingY;
306
double w2 = Item->BoundingW;
307
double h2 = Item->BoundingH;
308
if (!( qMax( x, x2 ) <= qMin( x+w, x2+w2 ) && qMax( y, y2 ) <= qMin( y+h, y2+h2 )))
310
if ((!page->pageName().isEmpty()) && (Item->OwnPage != static_cast<int>(page->pageNr())) && (Item->OwnPage != -1))
312
if (Item->isGroupControl)
314
groupStack.push(Item->groupsLastItem);
315
groupStack2.push(layerGroup);
316
layerGroup = docu.createElement("g");
318
layerGroup.setAttribute("id", Item->itemName());
319
if (Item->fillTransparency() != 0)
320
layerGroup.setAttribute("opacity", FToStr(1.0 - Item->fillTransparency()));
321
QDomElement ob = docu.createElement("clipPath");
322
ob.setAttribute("id", "Clip"+IToStr(ClipCount));
323
QDomElement cl = docu.createElement("path");
324
cl.setAttribute("d", SetClipPath(&Item->PoLine, true));
325
QString trans = "translate("+FToStr(Item->xPos()-page->xOffset())+", "+FToStr(Item->yPos()-page->yOffset())+")";
326
if (Item->rotation() != 0)
327
trans += " rotate("+FToStr(Item->rotation())+")";
328
cl.setAttribute("transform", trans);
330
globalDefs.appendChild(ob);
331
layerGroup.setAttribute("clip-path", "url(#Clip"+IToStr(ClipCount)+")");
335
ProcessItemOnPage(Item->xPos()-page->xOffset(), Item->yPos()-page->yOffset(), Item, &layerGroup);
336
if (groupStack.count() != 0)
338
while (Item == groupStack.top())
341
groupStack2.top().appendChild(layerGroup);
342
layerGroup = groupStack2.pop();
343
if (groupStack.count() == 0)
348
for(int j = 0; j < Items.count(); ++j)
351
if (Item->LayerNr != ll.LNr)
353
if (!Item->printEnabled())
355
double x = page->xOffset();
356
double y = page->yOffset();
357
double w = page->width();
358
double h = page->height();
359
double x2 = Item->BoundingX;
360
double y2 = Item->BoundingY;
361
double w2 = Item->BoundingW;
362
double h2 = Item->BoundingH;
363
if (!( qMax( x, x2 ) <= qMin( x+w, x2+w2 ) && qMax( y, y2 ) <= qMin( y+h, y2+h2 )))
365
if (!Item->isTableItem)
367
if ((Item->lineColor() == CommonStrings::None) || (Item->lineWidth() == 0.0))
369
if ((Item->TopLine) || (Item->RightLine) || (Item->BottomLine) || (Item->LeftLine))
371
QString trans = "translate("+FToStr(Item->xPos()-page->xOffset())+", "+FToStr(Item->yPos()-page->yOffset())+")";
372
if (Item->rotation() != 0)
373
trans += " rotate("+FToStr(Item->rotation())+")";
374
QString stroke = getStrokeStyle(Item);
375
QDomElement ob = docu.createElement("path");
376
ob.setAttribute("transform", trans);
377
ob.setAttribute("style", "fill:none; " + stroke);
378
QString pathAttr = "";
380
pathAttr += "M 0 0 L "+FToStr(Item->width())+" 0";
382
pathAttr += " M " + FToStr(Item->width()) + "0 L "+FToStr(Item->width())+" "+FToStr(Item->height());
383
if (Item->BottomLine)
384
pathAttr += " M 0 " + FToStr(Item->height()) + " L "+FToStr(Item->width())+" "+FToStr(Item->height());
386
pathAttr += " M 0 0 L 0 "+FToStr(Item->height());
387
ob.setAttribute("d", pathAttr);
388
layerGroup.appendChild(ob);
391
docElement.appendChild(layerGroup);
395
m_Doc->setCurrentPage(SavedAct);
398
void SVGExPlug::ProcessItemOnPage(double xOffset, double yOffset, PageItem *Item, QDomElement *parentElem)
401
QString trans = "translate("+FToStr(xOffset)+", "+FToStr(yOffset)+")";
402
if (Item->rotation() != 0)
403
trans += " rotate("+FToStr(Item->rotation())+")";
404
QString fill = getFillStyle(Item);
405
QString stroke = "stroke:none";
406
if (!Item->isTableItem)
407
stroke = getStrokeStyle(Item);
408
switch (Item->itemType())
410
case PageItem::Polygon:
411
case PageItem::PolyLine:
412
ob = processPolyItem(Item, trans, fill, stroke);
413
if ((Item->lineColor() != CommonStrings::None) && ((Item->startArrowIndex() != 0) || (Item->endArrowIndex() != 0)))
414
ob = processArrows(Item, ob, trans);
417
ob = processLineItem(Item, trans, stroke);
418
if ((Item->lineColor() != CommonStrings::None) && ((Item->startArrowIndex() != 0) || (Item->endArrowIndex() != 0)))
419
ob = processArrows(Item, ob, trans);
421
case PageItem::ImageFrame:
422
case PageItem::LatexFrame:
423
ob = processImageItem(Item, trans, fill, stroke);
425
case PageItem::TextFrame:
426
ob = processTextItem(Item, trans, fill, stroke);
428
case PageItem::PathText:
429
ob = processPathTextItem(Item, trans, stroke);
435
ob.setAttribute("id", Item->itemName());
436
parentElem->appendChild(ob);
439
QDomElement SVGExPlug::processPolyItem(PageItem *Item, QString trans, QString fill, QString stroke)
443
if (Item->itemType() == PageItem::Polygon)
447
if (Item->NamedLStyle.isEmpty())
449
ob = docu.createElement("path");
450
ob.setAttribute("d", SetClipPath(&Item->PoLine, closedPath));
451
ob.setAttribute("transform", trans);
452
ob.setAttribute("style", fill + stroke);
456
ob = docu.createElement("g");
457
ob.setAttribute("transform", trans);
458
QDomElement ob2 = docu.createElement("path");
459
ob2.setAttribute("d", SetClipPath(&Item->PoLine, closedPath));
460
ob2.setAttribute("style", fill);
462
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
463
for (int it = ml.size()-1; it > -1; it--)
465
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
467
QDomElement ob3 = docu.createElement("path");
468
ob3.setAttribute("d", SetClipPath(&Item->PoLine, closedPath));
469
ob3.setAttribute("style", GetMultiStroke(&ml[it], Item));
477
QDomElement SVGExPlug::processLineItem(PageItem *Item, QString trans, QString stroke)
480
if (Item->NamedLStyle.isEmpty())
482
ob = docu.createElement("path");
483
ob.setAttribute("d", "M 0 0 L "+FToStr(Item->width())+" 0");
484
ob.setAttribute("transform", trans);
485
ob.setAttribute("style", stroke);
489
ob = docu.createElement("g");
490
ob.setAttribute("transform", trans);
491
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
492
for (int it = ml.size()-1; it > -1; it--)
494
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
496
QDomElement ob2 = docu.createElement("path");
497
ob2.setAttribute("d", "M 0 0 L "+FToStr(Item->width())+" 0");
498
ob2.setAttribute("style", GetMultiStroke(&ml[it], Item));
506
QDomElement SVGExPlug::processImageItem(PageItem *Item, QString trans, QString fill, QString stroke)
509
ob = docu.createElement("g");
510
ob.setAttribute("transform", trans);
511
if ((Item->fillColor() != CommonStrings::None) || (Item->GrType != 0))
513
QDomElement ob1 = docu.createElement("path");
514
ob1.setAttribute("d", SetClipPath(&Item->PoLine, true));
515
ob1.setAttribute("style", fill);
518
if ((Item->PictureIsAvailable) && (!Item->Pfile.isEmpty()))
520
QDomElement ob2 = docu.createElement("clipPath");
521
ob2.setAttribute("id", "Clip"+IToStr(ClipCount));
522
ob2.setAttribute("clipPathUnits", "userSpaceOnUse");
523
ob2.setAttribute("clip-rule", "evenodd");
524
QDomElement cl = docu.createElement("path");
525
if (Item->imageClip.size() != 0)
526
cl.setAttribute("d", SetClipPath(&Item->imageClip, true));
528
cl.setAttribute("d", SetClipPath(&Item->PoLine, true));
530
globalDefs.appendChild(ob2);
531
QDomElement ob3 = docu.createElement("image");
532
ob3.setAttribute("clip-path", "url(#Clip"+IToStr(ClipCount)+")");
534
CMSettings cms(m_Doc, Item->IProfile, Item->IRender);
535
img.LoadPicture(Item->Pfile, Item->pixm.imgInfo.actualPageNumber, cms, Item->UseEmbedded, true, ScImage::RGBProof, 72);
536
img.applyEffect(Item->effectsInUse, m_Doc->PageColors, true);
537
if (Options.inlineImages)
540
buffer.open(QIODevice::WriteOnly);
541
img.qImage().save(&buffer, "PNG");
542
QByteArray ba = buffer.buffer().toBase64();
544
ob3.setAttribute("xlink:href", "data:image/png;base64,"+QString(ba));
548
QFileInfo fi = QFileInfo(Item->Pfile);
549
QString imgFileName = baseDir + "/" + fi.baseName()+".png";
550
QFileInfo im = QFileInfo(imgFileName);
552
imgFileName = baseDir + "/" + fi.baseName()+"_copy.png";
553
img.qImage().save(imgFileName, "PNG");
554
QFileInfo fi2 = QFileInfo(imgFileName);
555
ob3.setAttribute("xlink:href", fi2.baseName()+".png");
557
ob3.setAttribute("x", FToStr(Item->imageXOffset() * Item->imageXScale()));
558
ob3.setAttribute("y", FToStr(Item->imageYOffset() * Item->imageYScale()));
559
ob3.setAttribute("width", FToStr(img.width() * Item->imageXScale()));
560
ob3.setAttribute("height", FToStr(img.height() * Item->imageYScale()));
562
if (Item->imageFlippedH())
564
mpa.translate(Item->width(), 0);
567
if (Item->imageFlippedV())
569
mpa.translate(0, Item->height());
572
ob3.setAttribute("transform", MatrixToStr(mpa));
576
if (Item->NamedLStyle.isEmpty())
578
QDomElement ob4 = docu.createElement("path");
579
ob4.setAttribute("d", SetClipPath(&Item->PoLine, true));
580
ob4.setAttribute("style", "fill:none; "+stroke);
585
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
586
for (int it = ml.size()-1; it > -1; it--)
588
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
590
QDomElement ob5 = docu.createElement("path");
591
ob5.setAttribute("d", SetClipPath(&Item->PoLine, true));
592
ob5.setAttribute("style", "fill:none; "+GetMultiStroke(&ml[it], Item));
600
QDomElement SVGExPlug::processTextItem(PageItem *Item, QString trans, QString fill, QString stroke)
603
ob = docu.createElement("g");
604
ob.setAttribute("transform", trans);
605
if ((Item->fillColor() != CommonStrings::None) || (Item->GrType != 0))
607
QDomElement ob1 = docu.createElement("path");
608
ob1.setAttribute("d", SetClipPath(&Item->PoLine, true));
609
ob1.setAttribute("style", fill);
614
for (uint ll=0; ll < Item->itemText.lines(); ++ll)
616
LineSpec ls = Item->itemText.line(ll);
618
for (int a = ls.firstItem; a <= ls.lastItem; ++a)
622
ScText * hl = Item->itemText.item(a);
623
const CharStyle& charStyle(Item->itemText.charStyle(a));
624
chstr = Item->itemText.text(a,1);
625
if ((chstr == QChar(13)) || (chstr == QChar(29)))
627
if (chstr == QChar(29))
628
CurX += hl->glyph.wide();
631
if (chstr == QChar(30))
633
chstr = Item->ExpandToken(a);
634
if (chstr == QChar(32))
636
CurX += hl->glyph.wide();
640
double chs = charStyle.fontSize();
641
if (hl->effects() & ScStyle_SmallCaps)
643
if (chstr.toUpper() != chstr)
645
chs = qMax(static_cast<int>(hl->fontSize() * m_Doc->typographicSettings.valueSmallCaps / 100), 1);
646
chstr = chstr.toUpper();
649
else if (hl->effects() & ScStyle_AllCaps)
650
chstr = chstr.toUpper();
651
uint chr = chstr[0].unicode();
652
QMatrix chma, chma2, chma3, chma4, chma6;
653
QMatrix trafo = QMatrix( 1, 0, 0, 1, CurX, ls.y );
654
if (Item->rotation() != 0)
657
sca.translate(-Item->xPos(), -Item->yPos());
660
chma.scale(hl->glyph.scaleH * charStyle.fontSize() / 100.00, hl->glyph.scaleV * charStyle.fontSize() / 100.0);
661
if (Item->reversed())
663
if (a < Item->itemText.length()-1)
664
wide = hl->font().charWidth(chstr[0], hl->fontSize(), Item->itemText.text(a+1));
666
wide = hl->font().charWidth(chstr[0], hl->fontSize());
668
chma3.translate(-wide, 0);
670
chma4.translate(0, Item->BaseOffs - (charStyle.fontSize() / 10.0) * hl->glyph.scaleV);
671
if (charStyle.effects() & (ScStyle_Subscript | ScStyle_Superscript | ScStyle_DropCap))
672
chma6.translate(0, hl->glyph.yoffset);
673
if (hl->baselineOffset() != 0)
674
chma6.translate(0, (-charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0));
675
QMatrix finalMat = QMatrix(chma * chma2 * chma3 * chma4 * chma6 * trafo);
676
if (Item->rotation() != 0)
679
sca.translate(Item->xPos(), Item->yPos());
682
if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem()))
684
ob.appendChild(processInlineItem(CurX + hl->glyph.xoffset, ls.y + hl->glyph.yoffset, finalMat, hl, false, trans));
685
InlineFrame& embedded(const_cast<InlineFrame&>(hl->embedded));
686
CurX += (embedded.getItem()->gWidth + embedded.getItem()->lineWidth()) * hl->glyph.scaleH;
691
if (chstr > QChar(32))
692
glName = handleGlyph(chr, hl);
693
if ((charStyle.effects() & ScStyle_Shadowed) && (charStyle.strokeColor() != CommonStrings::None) && (chstr > QChar(32)))
695
QMatrix sha = finalMat;
697
shad.translate(charStyle.fontSize() * charStyle.shadowXOffset() / 10000.0, -charStyle.fontSize() * charStyle.shadowYOffset() / 10000.0);
699
QDomElement ob2 = docu.createElement("use");
700
ob2.setAttribute("xlink:href", "#" + glName);
701
ob2.setAttribute("transform", MatrixToStr(sha));
702
ob2.setAttribute("style", "fill:"+SetColor(hl->strokeColor(), hl->strokeShade())+";" + "stroke:none;");
705
QChar chstc = hl->ch;
706
if (((charStyle.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstc))
707
|| ((charStyle.effects() & ScStyle_UnderlineWords) && !chstc.isSpace() && !SpecialChars::isBreak(chstc)))
711
double Ulen = hl->glyph.xadvance;
712
double Upos, lw, kern;
713
if (charStyle.effects() & ScStyle_StartOfLine)
716
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
717
if ((charStyle.underlineOffset() != -1) || (charStyle.underlineWidth() != -1))
719
if (charStyle.underlineOffset() != -1)
720
Upos = (charStyle.underlineOffset() / 1000.0) * (charStyle.font().descent(charStyle.fontSize() / 10.0));
722
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
723
if (charStyle.underlineWidth() != -1)
724
lw = (charStyle.underlineWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
726
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
730
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
731
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
733
if (charStyle.baselineOffset() != 0)
734
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
735
QDomElement ob6 = docu.createElement("path");
736
if (charStyle.effects() & ScStyle_Subscript)
737
ob6.setAttribute("d", QString("M %1 %2 L%3 %4").arg(x + hl->glyph.xoffset-kern).arg(y + hl->glyph.yoffset - Upos).arg(x + hl->glyph.xoffset+Ulen).arg(y + hl->glyph.yoffset - Upos));
739
ob6.setAttribute("d", QString("M %1 %2 L%3 %4").arg(x + hl->glyph.xoffset-kern).arg(y - Upos).arg(x + hl->glyph.xoffset+Ulen).arg(y - Upos));
740
QString sT = "stroke:none;";
741
if (charStyle.fillColor() != CommonStrings::None)
743
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
744
sT += " stroke-width:"+FToStr(lw)+";";
746
ob6.setAttribute("style", "fill:none;" + sT);
749
if (chstr > QChar(32))
751
QDomElement ob3 = docu.createElement("use");
752
ob3.setAttribute("xlink:href", "#" + glName);
753
ob3.setAttribute("transform", MatrixToStr(finalMat));
754
QString fT = "fill:"+SetColor(hl->fillColor(), hl->fillShade())+";";
755
QString sT = "stroke:none;";
756
if (charStyle.effects() & ScStyle_Outline)
758
sT = "stroke:"+SetColor(hl->strokeColor(), hl->strokeShade())+";";
759
sT += " stroke-width:"+FToStr(chs * hl->outlineWidth() / 10000.0)+";";
761
ob3.setAttribute("style", fT + sT);
764
if (charStyle.effects() & ScStyle_Strikethrough)
768
double Ulen = hl->glyph.xadvance;
769
double Upos, lw, kern;
770
if (charStyle.effects() & ScStyle_StartOfLine)
773
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
774
if ((charStyle.strikethruOffset() != -1) || (charStyle.strikethruWidth() != -1))
776
if (charStyle.strikethruOffset() != -1)
777
Upos = (charStyle.strikethruOffset() / 1000.0) * (charStyle.font().ascent(charStyle.fontSize() / 10.0));
779
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
780
if (charStyle.strikethruWidth() != -1)
781
lw = (charStyle.strikethruWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
783
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
787
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
788
lw = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
790
if (charStyle.baselineOffset() != 0)
791
Upos += (charStyle.fontSize() / 10.0) * hl->glyph.scaleV * (charStyle.baselineOffset() / 1000.0);
792
QDomElement ob7 = docu.createElement("path");
793
ob7.setAttribute("d", QString("M %1 %2 L%3 %4").arg(x + hl->glyph.xoffset-kern).arg(y + hl->glyph.yoffset - Upos).arg(x + hl->glyph.xoffset+Ulen).arg(y + hl->glyph.yoffset - Upos));
794
QString sT = "stroke:none;";
795
if (charStyle.fillColor() != CommonStrings::None)
797
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
798
sT += " stroke-width:"+FToStr(lw)+";";
800
ob7.setAttribute("style", "fill:none;" + sT);
803
CurX += hl->glyph.wide();
807
if (Item->NamedLStyle.isEmpty())
809
QDomElement ob4 = docu.createElement("path");
810
ob4.setAttribute("d", SetClipPath(&Item->PoLine, true));
811
ob4.setAttribute("style", "fill:none; "+stroke);
816
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
817
for (int it = ml.size()-1; it > -1; it--)
819
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
821
QDomElement ob5 = docu.createElement("path");
822
ob5.setAttribute("d", SetClipPath(&Item->PoLine, true));
823
ob5.setAttribute("style", "fill:none; "+GetMultiStroke(&ml[it], Item));
831
QDomElement SVGExPlug::processPathTextItem(PageItem *Item, QString trans, QString stroke)
834
ob = docu.createElement("g");
835
ob.setAttribute("transform", trans);
838
if (Item->NamedLStyle.isEmpty())
840
QDomElement ob4 = docu.createElement("path");
841
ob4.setAttribute("d", SetClipPath(&Item->PoLine, false));
842
ob4.setAttribute("style", "fill:none; "+stroke);
847
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
848
for (int it = ml.size()-1; it > -1; it--)
850
if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
852
QDomElement ob5 = docu.createElement("path");
853
ob5.setAttribute("d", SetClipPath(&Item->PoLine, false));
854
ob5.setAttribute("style", "fill:none; "+GetMultiStroke(&ml[it], Item));
862
for (int a = 0; a < Item->itemText.length(); ++a)
866
ScText *hl = Item->itemText.item(a);
867
const CharStyle& charStyle(Item->itemText.charStyle(a));
868
chstr = Item->itemText.text(a,1);
869
if ((chstr == QChar(13)) || (chstr == QChar(29)))
871
if (chstr == QChar(30))
873
chstr = Item->ExpandToken(a);
874
if (chstr == QChar(32))
877
double chs = charStyle.fontSize();
878
if (hl->effects() & ScStyle_SmallCaps)
880
if (chstr.toUpper() != chstr)
882
chs = qMax(static_cast<int>(hl->fontSize() * m_Doc->typographicSettings.valueSmallCaps / 100), 1);
883
chstr = chstr.toUpper();
886
else if (hl->effects() & ScStyle_AllCaps)
887
chstr = chstr.toUpper();
888
uint chr = chstr[0].unicode();
889
QPointF tangt = QPointF( cos(hl->PRot), sin(hl->PRot) );
890
QMatrix chma, chma2, chma3, chma4, chma6;
891
QMatrix trafo = QMatrix( 1, 0, 0, -1, -hl->PDx, 0 );
892
if (Item->textPathFlipped)
893
trafo *= QMatrix(1, 0, 0, -1, 0, 0);
894
if (Item->textPathType == 0)
895
trafo *= QMatrix( tangt.x(), tangt.y(), tangt.y(), -tangt.x(), hl->PtransX, hl->PtransY );
896
else if (Item->textPathType == 1)
897
trafo *= QMatrix(1, 0, 0, -1, hl->PtransX, hl->PtransY );
898
else if (Item->textPathType == 2)
907
if (fabs(tangt.x()) > 0.1)
908
trafo *= QMatrix( a, (tangt.y() / tangt.x()) * b, 0, -1, hl->PtransX, hl->PtransY ); // ID's Skew mode
910
trafo *= QMatrix( a, 6 * b, 0, -1, hl->PtransX, hl->PtransY );
912
if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem()))
914
QMatrix finalMat = QMatrix(chma * chma2 * chma3 * chma4 * chma6 * trafo);
915
ob.appendChild(processInlineItem(0, 0, finalMat, hl, true, trans));
919
if (Item->rotation() != 0)
922
sca.translate(-Item->xPos(), -Item->yPos());
925
chma.scale(hl->glyph.scaleH * charStyle.fontSize() / 100.00, hl->glyph.scaleV * charStyle.fontSize() / 100.0);
926
if (Item->reversed())
928
if (a < Item->itemText.length()-1)
929
wide = hl->font().charWidth(chstr[0], hl->fontSize(), Item->itemText.text(a+1));
931
wide = hl->font().charWidth(chstr[0], hl->fontSize());
933
chma3.translate(-wide, 0);
935
chma4.translate(0, Item->BaseOffs - (charStyle.fontSize() / 10.0) * hl->glyph.scaleV);
936
if (charStyle.effects() & (ScStyle_Subscript | ScStyle_Superscript | ScStyle_DropCap))
937
chma6.translate(0, hl->glyph.yoffset);
938
if (hl->baselineOffset() != 0)
939
chma6.translate(0, (-charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0));
940
QMatrix finalMat = QMatrix(chma * chma2 * chma3 * chma4 * chma6 * trafo);
941
if (Item->rotation() != 0)
944
sca.translate(Item->xPos(), Item->yPos());
947
QChar chstc = hl->ch;
948
if (((charStyle.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstc))
949
|| ((charStyle.effects() & ScStyle_UnderlineWords) && !chstc.isSpace() && !SpecialChars::isBreak(chstc)))
951
QMatrix stro = QMatrix(chma2 * chma3 * chma6 * trafo);
952
if (Item->rotation() != 0)
955
sca.translate(Item->xPos(), Item->yPos());
958
double Ulen = hl->glyph.xadvance;
959
double Upos, Uwid, kern;
960
if (hl->effects() & ScStyle_StartOfLine)
963
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
964
if ((charStyle.underlineOffset() != -1) || (charStyle.underlineWidth() != -1))
966
if (charStyle.underlineOffset() != -1)
967
Upos = (charStyle.underlineOffset() / 1000.0) * (charStyle.font().descent(charStyle.fontSize() / 10.0));
969
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
970
if (charStyle.underlineWidth() != -1)
971
Uwid = (charStyle.underlineWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
973
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
977
Upos = charStyle.font().underlinePos(charStyle.fontSize() / 10.0);
978
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
980
if (charStyle.baselineOffset() != 0)
981
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
982
QDomElement ob8 = docu.createElement("path");
983
ob8.setAttribute("transform", MatrixToStr(stro));
984
if (charStyle.effects() & ScStyle_Subscript)
985
ob8.setAttribute("d", QString("M %1 %2 L%3 %4").arg(hl->glyph.xoffset-kern).arg(-Upos).arg(hl->glyph.xoffset+Ulen).arg(-Upos));
987
ob8.setAttribute("d", QString("M %1 %2 L%3 %4").arg(hl->glyph.xoffset-kern).arg(-(Upos + hl->glyph.yoffset)).arg(hl->glyph.xoffset+Ulen).arg(-(Upos + hl->glyph.yoffset)));
988
QString sT = "stroke:none;";
989
if (charStyle.fillColor() != CommonStrings::None)
991
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
992
sT += " stroke-width:"+FToStr(Uwid)+";";
994
ob8.setAttribute("style", "fill:none;" + sT);
997
if (chstr > QChar(32))
999
QString glName = handleGlyph(chr, hl);
1000
if ((charStyle.effects() & ScStyle_Shadowed) && (charStyle.strokeColor() != CommonStrings::None))
1002
QMatrix sha = finalMat;
1004
shad.translate(charStyle.fontSize() * charStyle.shadowXOffset() / 10000.0, -charStyle.fontSize() * charStyle.shadowYOffset() / 10000.0);
1006
QDomElement ob2 = docu.createElement("use");
1007
ob2.setAttribute("xlink:href", "#" + glName);
1008
ob2.setAttribute("transform", MatrixToStr(sha));
1009
ob2.setAttribute("style", "fill:"+SetColor(hl->strokeColor(), hl->strokeShade())+";" + "stroke:none;");
1010
ob.appendChild(ob2);
1012
QDomElement ob1 = docu.createElement("use");
1013
ob1.setAttribute("xlink:href", "#" + glName);
1014
ob1.setAttribute("transform", MatrixToStr(finalMat));
1015
QString fT = "fill:"+SetColor(hl->fillColor(), hl->fillShade())+";";
1016
QString sT = "stroke:none;";
1017
if (charStyle.effects() & ScStyle_Outline)
1019
sT = "stroke:"+SetColor(hl->strokeColor(), hl->strokeShade())+";";
1020
sT += " stroke-width:"+FToStr(chs * hl->outlineWidth() / 10000.0)+";";
1022
ob1.setAttribute("style", fT + sT);
1023
ob.appendChild(ob1);
1025
if (charStyle.effects() & ScStyle_Strikethrough)
1027
QMatrix stro = QMatrix(chma2 * chma3 * chma6 * trafo);
1028
if (Item->rotation() != 0)
1031
sca.translate(Item->xPos(), Item->yPos());
1034
double Ulen = hl->glyph.xadvance;
1035
double Upos, Uwid, kern;
1036
if (hl->effects() & ScStyle_StartOfLine)
1039
kern = charStyle.fontSize() * charStyle.tracking() / 10000.0;
1040
if ((charStyle.strikethruOffset() != -1) || (charStyle.strikethruWidth() != -1))
1042
if (charStyle.strikethruOffset() != -1)
1043
Upos = (charStyle.strikethruOffset() / 1000.0) * (charStyle.font().ascent(charStyle.fontSize() / 10.0));
1045
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
1046
if (charStyle.strikethruWidth() != -1)
1047
Uwid = (charStyle.strikethruWidth() / 1000.0) * (charStyle.fontSize() / 10.0);
1049
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
1053
Upos = charStyle.font().strikeoutPos(charStyle.fontSize() / 10.0);
1054
Uwid = qMax(charStyle.font().strokeWidth(charStyle.fontSize() / 10.0), 1.0);
1056
if (charStyle.baselineOffset() != 0)
1057
Upos += (charStyle.fontSize() / 10.0) * (charStyle.baselineOffset() / 1000.0);
1058
QDomElement ob7 = docu.createElement("path");
1059
ob7.setAttribute("transform", MatrixToStr(stro));
1060
ob7.setAttribute("d", QString("M %1 %2 L%3 %4").arg(hl->glyph.xoffset-kern).arg(-Upos).arg(hl->glyph.xoffset+Ulen).arg(-Upos));
1061
QString sT = "stroke:none;";
1062
if (charStyle.fillColor() != CommonStrings::None)
1064
sT = "stroke:"+SetColor(charStyle.fillColor(), charStyle.fillShade())+";";
1065
sT += " stroke-width:"+FToStr(Uwid)+";";
1067
ob7.setAttribute("style", "fill:none;" + sT);
1068
ob.appendChild(ob7);
1075
QDomElement SVGExPlug::processInlineItem(double xpos, double ypos, QMatrix &finalMat, ScText *hl, bool pathT, QString trans)
1077
const CharStyle & charStyle(*hl);
1078
QList<PageItem*> emG = hl->embedded.getGroupedItems();
1079
QStack<PageItem*> groupStack;
1080
QStack<QDomElement> groupStack2;
1081
QDomElement layerGroup = docu.createElement("g");
1083
layerGroup.setAttribute("transform", MatrixToStr(finalMat));
1084
for (int em = 0; em < emG.count(); ++em)
1086
PageItem* embedded = emG.at(em);
1087
if (embedded->isGroupControl)
1089
groupStack.push(embedded->groupsLastItem);
1090
groupStack2.push(layerGroup);
1091
layerGroup = docu.createElement("g");
1092
if (embedded->fillTransparency() != 0)
1093
layerGroup.setAttribute("opacity", FToStr(1.0 - embedded->fillTransparency()));
1094
QDomElement ob = docu.createElement("clipPath");
1095
ob.setAttribute("id", "Clip"+IToStr(ClipCount));
1096
QDomElement cl = docu.createElement("path");
1097
cl.setAttribute("d", SetClipPath(&embedded->PoLine, true));
1099
mm.translate(xpos + embedded->gXpos * (charStyle.scaleH() / 1000.0), (ypos - (embedded->gHeight * (charStyle.scaleV() / 1000.0)) + embedded->gYpos * (charStyle.scaleV() / 1000.0)));
1100
if (charStyle.baselineOffset() != 0)
1101
mm.translate(0, embedded->gHeight * (charStyle.baselineOffset() / 1000.0));
1102
if (charStyle.scaleH() != 1000)
1103
mm.scale(charStyle.scaleH() / 1000.0, 1);
1104
if (charStyle.scaleV() != 1000)
1105
mm.scale(1, charStyle.scaleV() / 1000.0);
1106
mm.rotate(embedded->rotation());
1107
cl.setAttribute("transform", MatrixToStr(mm));
1109
globalDefs.appendChild(ob);
1110
layerGroup.setAttribute("clip-path", "url(#Clip"+IToStr(ClipCount)+")");
1115
QString fill = getFillStyle(embedded);
1116
QString stroke = "stroke:none";
1117
if (!embedded->isTableItem)
1118
stroke = getStrokeStyle(embedded);
1119
switch (embedded->itemType())
1121
case PageItem::Polygon:
1122
case PageItem::PolyLine:
1123
obE = processPolyItem(embedded, trans, fill, stroke);
1124
if ((embedded->lineColor() != CommonStrings::None) && ((embedded->startArrowIndex() != 0) || (embedded->endArrowIndex() != 0)))
1125
obE = processArrows(embedded, obE, trans);
1127
case PageItem::Line:
1128
obE = processLineItem(embedded, trans, stroke);
1129
if ((embedded->lineColor() != CommonStrings::None) && ((embedded->startArrowIndex() != 0) || (embedded->endArrowIndex() != 0)))
1130
obE = processArrows(embedded, obE, trans);
1132
case PageItem::ImageFrame:
1133
case PageItem::LatexFrame:
1134
obE = processImageItem(embedded, trans, fill, stroke);
1136
case PageItem::TextFrame:
1137
obE = processTextItem(embedded, trans, fill, stroke);
1139
case PageItem::PathText:
1140
obE = processPathTextItem(embedded, trans, stroke);
1146
mm.translate(xpos + embedded->gXpos * (charStyle.scaleH() / 1000.0), (ypos - (embedded->gHeight * (charStyle.scaleV() / 1000.0)) + embedded->gYpos * (charStyle.scaleV() / 1000.0)));
1147
if (charStyle.baselineOffset() != 0)
1148
mm.translate(0, embedded->gHeight * (charStyle.baselineOffset() / 1000.0));
1149
if (charStyle.scaleH() != 1000)
1150
mm.scale(charStyle.scaleH() / 1000.0, 1);
1151
if (charStyle.scaleV() != 1000)
1152
mm.scale(1, charStyle.scaleV() / 1000.0);
1153
mm.rotate(embedded->rotation());
1154
obE.setAttribute("transform", MatrixToStr(mm));
1155
layerGroup.appendChild(obE);
1156
if (groupStack.count() != 0)
1158
while (embedded == groupStack.top())
1161
groupStack2.top().appendChild(layerGroup);
1162
layerGroup = groupStack2.pop();
1163
if (groupStack.count() == 0)
1168
for (int em = 0; em < emG.count(); ++em)
1170
PageItem* embedded = emG.at(em);
1171
if (!embedded->isTableItem)
1173
if ((embedded->lineColor() == CommonStrings::None) || (embedded->lineWidth() == 0.0))
1175
if ((embedded->TopLine) || (embedded->RightLine) || (embedded->BottomLine) || (embedded->LeftLine))
1178
mm.translate(xpos + embedded->gXpos * (charStyle.scaleH() / 1000.0), (ypos - (embedded->gHeight * (charStyle.scaleV() / 1000.0)) + embedded->gYpos * (charStyle.scaleV() / 1000.0)));
1179
if (charStyle.baselineOffset() != 0)
1180
mm.translate(0, embedded->gHeight * (charStyle.baselineOffset() / 1000.0));
1181
if (charStyle.scaleH() != 1000)
1182
mm.scale(charStyle.scaleH() / 1000.0, 1);
1183
if (charStyle.scaleV() != 1000)
1184
mm.scale(1, charStyle.scaleV() / 1000.0);
1185
mm.rotate(embedded->rotation());
1186
QString stroke = getStrokeStyle(embedded);
1187
QDomElement obL = docu.createElement("path");
1188
obL.setAttribute("transform", MatrixToStr(mm));
1189
obL.setAttribute("style", "fill:none; " + stroke);
1190
QString pathAttr = "";
1191
if (embedded->TopLine)
1192
pathAttr += "M 0 0 L "+FToStr(embedded->width())+" 0";
1193
if (embedded->RightLine)
1194
pathAttr += " M " + FToStr(embedded->width()) + "0 L "+FToStr(embedded->width())+" "+FToStr(embedded->height());
1195
if (embedded->BottomLine)
1196
pathAttr += " M 0 " + FToStr(embedded->height()) + " L "+FToStr(embedded->width())+" "+FToStr(embedded->height());
1197
if (embedded->LeftLine)
1198
pathAttr += " M 0 0 L 0 "+FToStr(embedded->height());
1199
obL.setAttribute("d", pathAttr);
1200
layerGroup.appendChild(obL);
1206
QString SVGExPlug::handleGlyph(uint chr, ScText *hl)
1210
QString glName = QString("Gl%1%2").arg(hl->font().psName().simplified().replace(QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" )).arg(chr);
1211
if (glyphNames.contains(glName))
1213
uint gl = hl->font().char2CMap(chr);
1214
FPointArray pts = hl->font().glyphOutline(gl);
1215
QDomElement ob = docu.createElement("path");
1216
ob.setAttribute("d", SetClipPath(&pts, true));
1217
ob.setAttribute("id", glName);
1218
globalDefs.appendChild(ob);
1219
glyphNames.append(glName);
1223
QDomElement SVGExPlug::processArrows(PageItem *Item, QDomElement line, QString trans)
1226
gr = docu.createElement("g");
1227
gr.appendChild(line);
1228
if (Item->startArrowIndex() != 0)
1231
FPointArray arrow = m_Doc->arrowStyles.at(Item->startArrowIndex()-1).points.copy();
1232
if (Item->itemType() == PageItem::Line)
1234
arrowTrans.translate(0, 0);
1235
if (Item->NamedLStyle.isEmpty())
1237
if (Item->lineWidth() != 0.0)
1238
arrowTrans.scale(Item->lineWidth(), Item->lineWidth());
1242
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
1243
if (ml[ml.size()-1].Width != 0.0)
1244
arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1246
arrowTrans.scale(-1,1);
1250
FPoint Start = Item->PoLine.point(0);
1251
for (uint xx = 1; xx < Item->PoLine.size(); xx += 2)
1253
FPoint Vector = Item->PoLine.point(xx);
1254
if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
1256
double r = atan2(Start.y()-Vector.y(),Start.x()-Vector.x())*(180.0/M_PI);
1257
arrowTrans.translate(Start.x(), Start.y());
1258
arrowTrans.rotate(r);
1259
if (Item->NamedLStyle.isEmpty())
1261
if (Item->lineWidth() != 0.0)
1262
arrowTrans.scale(Item->lineWidth(), Item->lineWidth());
1266
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
1267
if (ml[ml.size()-1].Width != 0.0)
1268
arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1274
arrow.map(arrowTrans);
1275
if (Item->NamedLStyle.isEmpty())
1277
ob = docu.createElement("path");
1278
ob.setAttribute("d", SetClipPath(&arrow, true));
1279
ob.setAttribute("transform", trans);
1280
QString aFill = "fill:"+SetColor(Item->lineColor(), Item->lineShade())+";";
1281
if (Item->lineTransparency() != 0)
1282
aFill += " fill-opacity:"+FToStr(1.0 - Item->lineTransparency())+";";
1283
ob.setAttribute("style", aFill + " stroke:none;");
1288
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
1289
if (ml[0].Color != CommonStrings::None)
1291
ob = docu.createElement("path");
1292
ob.setAttribute("d", SetClipPath(&arrow, true));
1293
ob.setAttribute("transform", trans);
1294
QString aFill = "fill:"+SetColor(ml[0].Color, ml[0].Shade)+";";
1295
ob.setAttribute("style", aFill + " stroke:none;");
1298
for (int it = ml.size()-1; it > 0; it--)
1300
if (ml[it].Color != CommonStrings::None)
1302
QDomElement ob5 = docu.createElement("path");
1303
ob5.setAttribute("d", SetClipPath(&arrow, true));
1304
ob5.setAttribute("transform", trans);
1305
QString stroke = "fill:none; stroke:"+SetColor(ml[it].Color, ml[it].Shade)+"; stroke-linecap:butt; stroke-linejoin:miter; stroke-dasharray:none;";
1306
if (ml[it].Width != 0.0)
1307
stroke += " stroke-width:"+FToStr(ml[it].Width)+";";
1309
stroke += " stroke-width:1px;";
1310
ob5.setAttribute("style", stroke);
1311
gr.appendChild(ob5);
1316
if (Item->endArrowIndex() != 0)
1319
FPointArray arrow = m_Doc->arrowStyles.at(Item->endArrowIndex()-1).points.copy();
1320
if (Item->itemType() == PageItem::Line)
1322
arrowTrans.translate(Item->width(), 0);
1323
if (Item->NamedLStyle.isEmpty())
1325
if (Item->lineWidth() != 0.0)
1326
arrowTrans.scale(Item->lineWidth(), Item->lineWidth());
1330
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
1331
if (ml[ml.size()-1].Width != 0.0)
1332
arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1337
FPoint End = Item->PoLine.point(Item->PoLine.size()-2);
1338
for (uint xx = Item->PoLine.size()-1; xx > 0; xx -= 2)
1340
FPoint Vector = Item->PoLine.point(xx);
1341
if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
1343
double r = atan2(End.y()-Vector.y(),End.x()-Vector.x())*(180.0/M_PI);
1344
arrowTrans.translate(End.x(), End.y());
1345
arrowTrans.rotate(r);
1346
if (Item->NamedLStyle.isEmpty())
1348
if (Item->lineWidth() != 0.0)
1349
arrowTrans.scale(Item->lineWidth(), Item->lineWidth());
1353
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
1354
if (ml[ml.size()-1].Width != 0.0)
1355
arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1361
arrow.map(arrowTrans);
1362
if (Item->NamedLStyle.isEmpty())
1364
ob = docu.createElement("path");
1365
ob.setAttribute("d", SetClipPath(&arrow, true));
1366
ob.setAttribute("transform", trans);
1367
QString aFill = "fill:"+SetColor(Item->lineColor(), Item->lineShade())+";";
1368
if (Item->lineTransparency() != 0)
1369
aFill += " fill-opacity:"+FToStr(1.0 - Item->lineTransparency())+";";
1370
ob.setAttribute("style", aFill + " stroke:none;");
1375
multiLine ml = m_Doc->MLineStyles[Item->NamedLStyle];
1376
if (ml[0].Color != CommonStrings::None)
1378
ob = docu.createElement("path");
1379
ob.setAttribute("d", SetClipPath(&arrow, true));
1380
ob.setAttribute("transform", trans);
1381
QString aFill = "fill:"+SetColor(ml[0].Color, ml[0].Shade)+";";
1382
ob.setAttribute("style", aFill + " stroke:none;");
1385
for (int it = ml.size()-1; it > 0; it--)
1387
if (ml[it].Color != CommonStrings::None)
1389
QDomElement ob5 = docu.createElement("path");
1390
ob5.setAttribute("d", SetClipPath(&arrow, true));
1391
ob5.setAttribute("transform", trans);
1392
QString stroke = "fill:none; stroke:"+SetColor(ml[it].Color, ml[it].Shade)+"; stroke-linecap:butt; stroke-linejoin:miter; stroke-dasharray:none;";
1393
if (ml[it].Width != 0.0)
1394
stroke += " stroke-width:"+FToStr(ml[it].Width)+";";
1396
stroke += " stroke-width:1px;";
1397
ob5.setAttribute("style", stroke);
1398
gr.appendChild(ob5);
1406
QString SVGExPlug::getFillStyle(PageItem *Item)
1410
if (Item->asPathText())
1411
return "fill:none;";
1412
if ((Item->fillColor() != CommonStrings::None) || (Item->GrType != 0))
1414
fill = "fill:"+SetColor(Item->fillColor(), Item->fillShade())+";";
1415
if (Item->GrType != 0)
1417
if (Item->GrType == 8)
1419
QStack<PageItem*> groupStack;
1420
QStack<QDomElement> groupStack2;
1421
QString pattID = Item->pattern()+IToStr(PattCount);
1423
ScPattern pa = m_Doc->docPatterns[Item->pattern()];
1424
QDomElement patt = docu.createElement("pattern");
1425
patt.setAttribute("id", pattID);
1426
patt.setAttribute("height", pa.height);
1427
patt.setAttribute("width", pa.width);
1428
patt.setAttribute("patternUnits", "userSpaceOnUse");
1429
double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
1430
Item->patternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
1432
mpa.translate(patternOffsetX, patternOffsetY);
1433
mpa.rotate(patternRotation);
1434
mpa.scale(pa.scaleX, pa.scaleY);
1435
mpa.scale(patternScaleX / 100.0 , patternScaleY / 100.0);
1436
patt.setAttribute("patternTransform", MatrixToStr(mpa));
1437
for (int em = 0; em < pa.items.count(); ++em)
1439
PageItem* Item = pa.items.at(em);
1440
if (Item->isGroupControl)
1442
groupStack.push(Item->groupsLastItem);
1443
groupStack2.push(patt);
1444
patt = docu.createElement("g");
1445
if (Item->fillTransparency() != 0)
1446
patt.setAttribute("opacity", FToStr(1.0 - Item->fillTransparency()));
1447
QDomElement ob = docu.createElement("clipPath");
1448
ob.setAttribute("id", "Clip"+IToStr(ClipCount));
1449
QDomElement cl = docu.createElement("path");
1450
cl.setAttribute("d", SetClipPath(&Item->PoLine, true));
1451
QString trans = "translate("+FToStr(Item->gXpos)+", "+FToStr(Item->gYpos)+")";
1452
if (Item->rotation() != 0)
1453
trans += " rotate("+FToStr(Item->rotation())+")";
1454
cl.setAttribute("transform", trans);
1456
globalDefs.appendChild(ob);
1457
patt.setAttribute("clip-path", "url(#Clip"+IToStr(ClipCount)+")");
1461
ProcessItemOnPage(Item->gXpos, Item->gYpos, Item, &patt);
1462
if (groupStack.count() != 0)
1464
while (Item == groupStack.top())
1467
groupStack2.top().appendChild(patt);
1468
patt = groupStack2.pop();
1469
if (groupStack.count() == 0)
1474
for (int em = 0; em < pa.items.count(); ++em)
1476
PageItem* embedded = pa.items.at(em);
1477
QString trans = "translate("+FToStr(embedded->gXpos)+", "+FToStr(embedded->gYpos)+")";
1478
if (embedded->rotation() != 0)
1479
trans += " rotate("+FToStr(embedded->rotation())+")";
1480
if (!embedded->isTableItem)
1482
if ((embedded->lineColor() == CommonStrings::None) || (embedded->lineWidth() == 0.0))
1484
if ((embedded->TopLine) || (embedded->RightLine) || (embedded->BottomLine) || (embedded->LeftLine))
1486
QString stroke = getStrokeStyle(embedded);
1487
QDomElement obL = docu.createElement("path");
1488
obL.setAttribute("transform", trans);
1489
obL.setAttribute("style", "fill:none; " + stroke);
1490
QString pathAttr = "";
1491
if (embedded->TopLine)
1492
pathAttr += "M 0 0 L "+FToStr(embedded->width())+" 0";
1493
if (embedded->RightLine)
1494
pathAttr += " M " + FToStr(embedded->width()) + "0 L "+FToStr(embedded->width())+" "+FToStr(embedded->height());
1495
if (embedded->BottomLine)
1496
pathAttr += " M 0 " + FToStr(embedded->height()) + " L "+FToStr(embedded->width())+" "+FToStr(embedded->height());
1497
if (embedded->LeftLine)
1498
pathAttr += " M 0 0 L 0 "+FToStr(embedded->height());
1499
obL.setAttribute("d", pathAttr);
1500
patt.appendChild(obL);
1503
globalDefs.appendChild(patt);
1504
fill = "fill:url(#"+pattID+");";
1508
if ((Item->GrType == 5) || (Item->GrType == 7))
1509
grad = docu.createElement("radialGradient");
1511
grad = docu.createElement("linearGradient");
1512
grad.setAttribute("id", "Grad"+IToStr(GradCount));
1513
grad.setAttribute("gradientUnits", "userSpaceOnUse");
1514
switch (Item->GrType)
1517
grad.setAttribute("x1", "0");
1518
grad.setAttribute("y1", FToStr(Item->height() / 2.0));
1519
grad.setAttribute("x2", FToStr(Item->width()));
1520
grad.setAttribute("y2", FToStr(Item->height() / 2.0));
1523
grad.setAttribute("x1", FToStr(Item->width()/ 2.0));
1524
grad.setAttribute("y1", "0");
1525
grad.setAttribute("x2", FToStr(Item->width()/ 2.0));
1526
grad.setAttribute("y2", FToStr(Item->height()));
1529
grad.setAttribute("x1", "0");
1530
grad.setAttribute("y1", "0");
1531
grad.setAttribute("x2", FToStr(Item->width()));
1532
grad.setAttribute("y2", FToStr(Item->height()));
1535
grad.setAttribute("x1", "0");
1536
grad.setAttribute("y1", FToStr(Item->height()));
1537
grad.setAttribute("x2", FToStr(Item->width()));
1538
grad.setAttribute("y2", "0");
1541
grad.setAttribute("r", FToStr(qMax(Item->width() / 2.0, Item->height() / 2.0)));
1542
grad.setAttribute("cx", FToStr(Item->width() / 2.0));
1543
grad.setAttribute("cy", FToStr(Item->height() / 2.0));
1546
grad.setAttribute("x1", FToStr(Item->GrStartX));
1547
grad.setAttribute("y1", FToStr(Item->GrStartY));
1548
grad.setAttribute("x2", FToStr(Item->GrEndX));
1549
grad.setAttribute("y2", FToStr(Item->GrEndY));
1552
grad.setAttribute("r", FToStr(qMax(Item->width() / 2.0, Item->height() / 2.0)));
1553
grad.setAttribute("cx", FToStr(Item->GrStartX));
1554
grad.setAttribute("cy", FToStr(Item->GrStartY));
1557
bool isFirst = true;
1558
double actualStop = 0.0, lastStop = 0.0;
1559
QList<VColorStop*> cstops = Item->fill_gradient.colorStops();
1560
for (uint cst = 0; cst < Item->fill_gradient.Stops(); ++cst)
1562
actualStop = cstops.at(cst)->rampPoint;
1563
if ((actualStop != lastStop) || (isFirst))
1565
QDomElement itcl = docu.createElement("stop");
1566
itcl.setAttribute("offset", FToStr(cstops.at(cst)->rampPoint*100)+"%");
1567
itcl.setAttribute("stop-opacity", FToStr(cstops.at(cst)->opacity));
1568
itcl.setAttribute("stop-color", SetColor(cstops.at(cst)->name, cstops.at(cst)->shade));
1569
grad.appendChild(itcl);
1570
lastStop = actualStop;
1574
globalDefs.appendChild(grad);
1575
fill = "fill:url(#Grad"+IToStr(GradCount)+");";
1580
fill += " fill-rule:evenodd;";
1582
fill += " fill-rule:nonzero;";
1583
if (Item->fillTransparency() != 0)
1584
fill += " fill-opacity:"+FToStr(1.0 - Item->fillTransparency())+";";
1587
fill = "fill:none;";
1591
QString SVGExPlug::getStrokeStyle(PageItem *Item)
1593
QString stroke = "";
1594
if (Item->lineColor() != CommonStrings::None)
1596
stroke = "stroke:"+SetColor(Item->lineColor(), Item->lineShade())+";";
1597
if (Item->lineTransparency() != 0)
1598
stroke += " stroke-opacity:"+FToStr(1.0 - Item->lineTransparency())+";";
1599
if (Item->lineWidth() != 0.0)
1600
stroke += " stroke-width:"+FToStr(Item->lineWidth())+";";
1602
stroke += " stroke-width:1px;";
1603
stroke += " stroke-linecap:";
1604
switch (Item->PLineEnd)
1610
stroke += "square;";
1619
stroke += " stroke-linejoin:";
1620
switch (Item->PLineJoin)
1635
stroke += " stroke-dasharray:";
1636
if (Item->DashValues.count() != 0)
1638
QVector<double>::iterator it;
1639
for ( it = Item->DashValues.begin(); it != Item->DashValues.end(); ++it )
1641
stroke += IToStr(static_cast<int>(*it))+" ";
1643
stroke += "; stroke-dashoffset:"+IToStr(static_cast<int>(Item->DashOffset))+";";
1647
if (Item->PLineArt == Qt::SolidLine)
1651
QString Da = getDashString(Item->PLineArt, Item->lineWidth());
1655
stroke += Da.replace(" ", ", ")+";";
1660
stroke = "stroke:none;";
1664
QString SVGExPlug::SetClipPath(FPointArray *ite, bool closed)
1667
FPoint np, np1, np2, np3;
1669
if (ite->size() > 3)
1671
for (uint poi=0; poi<ite->size()-3; poi += 4)
1673
if (ite->point(poi).x() > 900000)
1681
np = ite->point(poi);
1682
tmp += QString("M%1 %2 ").arg(np.x()).arg(np.y());
1685
np = ite->point(poi);
1686
np1 = ite->point(poi+1);
1687
np2 = ite->point(poi+3);
1688
np3 = ite->point(poi+2);
1689
if ((np == np1) && (np2 == np3))
1690
tmp += QString("L%1 %2 ").arg(np3.x()).arg(np3.y());
1692
tmp += QString("C%1 %2 %3 %4 %5 %6 ").arg(np1.x()).arg(np1.y()).arg(np2.x()).arg(np2.y()).arg(np3.x()).arg(np3.y());
1700
QString SVGExPlug::FToStr(double c)
1703
return cc.setNum(c);
1706
QString SVGExPlug::IToStr(int c)
1709
return cc.setNum(c);
1712
QString SVGExPlug::MatrixToStr(QMatrix &mat)
1714
QString cc("matrix(%1 %2 %3 %4 %5 %6)");
1715
return cc.arg(mat.m11()).arg(mat.m12()).arg(mat.m21()).arg(mat.m22()).arg(mat.dx()).arg(mat.dy());
1718
QString SVGExPlug::SetColor(QString farbe, int shad)
1720
const ScColor& col = m_Doc->PageColors[farbe];
1721
return ScColorEngine::getShadeColorProof(col, m_Doc, shad).name();
1724
QString SVGExPlug::GetMultiStroke(struct SingleLine *sl, PageItem *Item)
1726
QString tmp = "fill:none; ";
1727
tmp += "stroke:"+SetColor(sl->Color, sl->Shade)+"; ";
1728
if (Item->fillTransparency() != 0)
1729
tmp += QString(" stroke-opacity:%1; ").arg(1.0 - Item->fillTransparency());
1730
tmp += QString("stroke-width:%1; ").arg(sl->Width);
1731
tmp += "stroke-linecap:";
1732
switch (static_cast<Qt::PenCapStyle>(sl->LineEnd))
1747
tmp += " stroke-linejoin:";
1748
switch (static_cast<Qt::PenJoinStyle>(sl->LineJoin))
1763
tmp += " stroke-dasharray:";
1764
if (static_cast<Qt::PenStyle>(sl->Dash) == Qt::SolidLine)
1768
QString Da = getDashString(sl->Dash, sl->Width);
1772
tmp += Da.replace(" ", ", ")+";";
1777
SVGExPlug::~SVGExPlug()