View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0017438 | Scribus | Import / Export | public | 2025-03-06 07:25 | 2025-03-06 19:13 |
Reporter | ale | Assigned To | |||
Priority | normal | Severity | minor | Reproducibility | N/A |
Status | new | Resolution | open | ||
Product Version | 1.7.1.svn | ||||
Summary | 0017438: [PATCH] Export selection | ||||
Description | For the export that matter (SVG, image, EPS) it should be possible to optionally export the current selection only. | ||||
Tags | No tags attached. | ||||
Patch | Yes | ||||
|
Here is a patch for exporting the selection to SVG - The option is only active, if there is a selection and all its items are on the same page (it might be possible to relax the second condition) - It creates SVG layers for each Scribus layer in the selection (if items from other layers can be selected) - I've refactored a little bit of code that is used by both the export of the whole page and the one for the selection export-selection-to-svg.diff (8,198 bytes)
From f035fd4e2fdfaff942a8bb2869b877e859c6a3d7 Mon Sep 17 00:00:00 2001 From: ale rimoldi <ale@graphicslab.org> Date: Thu, 6 Mar 2025 20:03:38 +0100 Subject: add an option to save the current selection to SVG diff --git a/scribus/plugins/export/svgexplugin/svgexplugin.cpp b/scribus/plugins/export/svgexplugin/svgexplugin.cpp index 3d515db63..359d1be3a 100644 --- a/scribus/plugins/export/svgexplugin/svgexplugin.cpp +++ b/scribus/plugins/export/svgexplugin/svgexplugin.cpp @@ -41,6 +41,7 @@ for which a new license (GPL+exception) is in place. #include "prefsfile.h" #include "prefscontext.h" #include "qtiocompressor.h" +#include "selection.h" #include "scpage.h" #include "scpattern.h" #include "scribus.h" @@ -134,15 +135,26 @@ bool SVGExportPlugin::run(ScribusDoc* doc, const QString& filename) openDia->setSelection(getFileNameByPage(doc, doc->currentPage()->pageNr(), "svg")); openDia->setExtension("svg"); openDia->setZipExtension("svgz"); + QCheckBox* compress = new QCheckBox(openDia.data()); compress->setText( tr("Compress File")); compress->setChecked(false); openDia->addWidgets(compress); + QCheckBox* inlineImages = new QCheckBox(openDia.data()); inlineImages->setText( tr("Save Images inline")); inlineImages->setToolTip( tr("Adds all Images on the Page inline to the SVG.\nCaution: this will increase the file size!")); inlineImages->setChecked(true); openDia->addWidgets(inlineImages); + + // TODO: only if there is a selection + QCheckBox* selectionOnly = new QCheckBox(openDia.data()); + selectionOnly->setText( tr("Current selection only")); + selectionOnly->setToolTip( tr("Adds the items in the current selection to the SVG.\nAll items shall be on the same page.")); + selectionOnly->setEnabled(!doc->m_Selection->isEmpty() && doc->m_Selection->itemsAreOnSamePage()); + selectionOnly->setChecked(selectionOnly->isEnabled()); + openDia->addWidgets(selectionOnly); + QCheckBox* exportBack = new QCheckBox(openDia.data()); exportBack->setText( tr("Export Page background")); exportBack->setToolTip( tr("Adds the Page itself as background to the SVG")); @@ -161,6 +173,7 @@ bool SVGExportPlugin::run(ScribusDoc* doc, const QString& filename) SVGOptions Options; Options.inlineImages = inlineImages->isChecked(); + Options.selectionOnly = selectionOnly->isChecked(); Options.exportPageBackground = exportBack->isChecked(); Options.compressFile = compress->isChecked(); @@ -188,6 +201,7 @@ SVGExPlug::SVGExPlug( ScribusDoc* doc ) { m_Doc = doc; Options.inlineImages = true; + Options.selectionOnly = false; Options.exportPageBackground = false; Options.compressFile = false; m_glyphNames.clear(); @@ -211,12 +225,12 @@ bool SVGExPlug::doExport( const QString& fName, SVGOptions &Opts ) m_domDoc.setContent(st); ScPage *page = m_Doc->currentPage(); - double pageWidth = page->width(); - double pageHeight = page->height(); + double svgWidth = Options.selectionOnly ? m_Doc->m_Selection->width() : page->width(); + double svgHeight = Options.selectionOnly ? m_Doc->m_Selection->height() : page->height(); m_domElem = m_domDoc.documentElement(); - m_domElem.setAttribute("width", FToStr(pageWidth) + "pt"); - m_domElem.setAttribute("height", FToStr(pageHeight) + "pt"); - m_domElem.setAttribute("viewBox", QString("0 0 %1 %2").arg(pageWidth).arg(pageHeight)); + m_domElem.setAttribute("width", FToStr(svgWidth) + "pt"); + m_domElem.setAttribute("height", FToStr(svgHeight) + "pt"); + m_domElem.setAttribute("viewBox", QString("0 0 %1 %2").arg(svgWidth).arg(svgHeight)); m_domElem.setAttribute("xmlns", "http://www.w3.org/2000/svg"); m_domElem.setAttribute("xmlns:inkscape","http://www.inkscape.org/namespaces/inkscape"); m_domElem.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink"); @@ -239,29 +253,27 @@ bool SVGExPlug::doExport( const QString& fName, SVGOptions &Opts ) writeBasePatterns(); writeBaseSymbols(); m_domElem.appendChild(m_globalDefs); + if (Options.exportPageBackground) { QDomElement backG = m_domDoc.createElement("rect"); backG.setAttribute("x", "0"); backG.setAttribute("y", "0"); - backG.setAttribute("width", FToStr(pageWidth)); - backG.setAttribute("height", FToStr(pageHeight)); + backG.setAttribute("width", FToStr(svgWidth)); + backG.setAttribute("height", FToStr(svgHeight)); backG.setAttribute("style", "fill:" + m_Doc->paperColor().name() + ";" + "stroke:none;"); m_domElem.appendChild(backG); } - ScLayer ll; - ll.isPrintable = false; - for (int la = 0; la < m_Doc->Layers.count(); la++) + + if (Options.selectionOnly) { - m_Doc->Layers.levelToLayer(ll, la); - if (ll.isPrintable) - { - page = m_Doc->MasterPages.at(m_Doc->MasterNames[m_Doc->currentPage()->masterPageName()]); - processPageLayer(page, ll); - page = m_Doc->currentPage(); - processPageLayer(page, ll); - } + processSelection(); } + else + { + processPage(page); + } + if(Options.compressFile) { // zipped saving @@ -290,9 +302,61 @@ bool SVGExPlug::doExport( const QString& fName, SVGOptions &Opts ) return true; } + +QDomElement SVGExPlug::createSvgLayer(const ScLayer& layer) +{ + QDomElement svgLayer = m_domDoc.createElement("g"); + svgLayer.setAttribute("id", layer.Name); + svgLayer.setAttribute("inkscape:label", layer.Name); + svgLayer.setAttribute("inkscape:groupmode", "layer"); + if (layer.transparency != 1.0) + svgLayer.setAttribute("opacity", FToStr(layer.transparency)); + return svgLayer; +}; + +void SVGExPlug::processSelection() +{ + double sel_x0, sel_y0, sel_w, sel_h; + m_Doc->m_Selection->getGroupRect(&sel_x0, &sel_y0, &sel_w, &sel_h); + + QMap<QString, QDomElement> svgLayers; + + for (const auto item: m_Doc->m_Selection->items()) + { + if (!item->printEnabled()) + continue; + auto layer = *m_Doc->Layers.byID(item->m_layerID); + if (!svgLayers.contains(layer.Name)) + { + svgLayers[layer.Name] = createSvgLayer(layer); + } + processItemOnPage(item->xPos() - sel_x0, item->yPos() - sel_y0, item, &svgLayers[layer.Name]); + } + for (auto [lanyerName, svgLayer] : svgLayers.asKeyValueRange()) + { + m_domElem.appendChild(svgLayer); + } +}; + +void SVGExPlug::processPage(ScPage *page) +{ + ScLayer ll; + ll.isPrintable = false; + for (int la = 0; la < m_Doc->Layers.count(); la++) + { + m_Doc->Layers.levelToLayer(ll, la); + if (ll.isPrintable) + { + page = m_Doc->MasterPages.at(m_Doc->MasterNames[m_Doc->currentPage()->masterPageName()]); + processPageLayer(page, ll); + page = m_Doc->currentPage(); + processPageLayer(page, ll); + } + } +} + void SVGExPlug::processPageLayer(ScPage *page, ScLayer& layer) { - QDomElement layerGroup; PageItem *item; QList<PageItem*> items; ScPage* SavedAct = m_Doc->currentPage(); @@ -306,12 +370,8 @@ void SVGExPlug::processPageLayer(ScPage *page, ScLayer& layer) return; m_Doc->setCurrentPage(page); - layerGroup = m_domDoc.createElement("g"); - layerGroup.setAttribute("id", layer.Name); - layerGroup.setAttribute("inkscape:label", layer.Name); - layerGroup.setAttribute("inkscape:groupmode", "layer"); - if (layer.transparency != 1.0) - layerGroup.setAttribute("opacity", FToStr(layer.transparency)); + QDomElement layerGroup = createSvgLayer(layer); + for (int j = 0; j < items.count(); ++j) { item = items.at(j); diff --git a/scribus/plugins/export/svgexplugin/svgexplugin.h b/scribus/plugins/export/svgexplugin/svgexplugin.h index d2517f32f..f45bc58d9 100644 --- a/scribus/plugins/export/svgexplugin/svgexplugin.h +++ b/scribus/plugins/export/svgexplugin/svgexplugin.h @@ -24,6 +24,7 @@ class ScText; struct SVGOptions { bool inlineImages; + bool selectionOnly; bool exportPageBackground; bool compressFile; }; @@ -87,6 +88,19 @@ private: QDomElement m_globalDefs; QList<QString> m_glyphNames; + + /** + * Creates an SVG layer, based on the information in the Scribus layer. + */ + QDomElement createSvgLayer(const ScLayer& layer); + /** + * Add all items in the selection to the SVG. + */ + void processSelection(); + /** + * Add all items on the page to the SVG. + */ + void processPage(ScPage *page); /*! \author Franz Schmid \brief Process a page to export to SVG format |
|
Further work to be done once the patch is accepted: - add the option to the scripter - think if it's useful to add the same option to the export to bitmaps (it's probably ok if it's easy; otherwise a screenshot or an export from Inkscape can be enough) - check if the same code can be used to copy a selection from scribu and paste it in inkscape (does it need a new command "copy as SVG" or can we simply create create SVG when Scribus puts multiple items in an "external" clipboard? ... I must admit that I have no clue about how copy pasting between applications works) |
Date Modified | Username | Field | Change |
---|---|---|---|
2025-03-06 07:25 | ale | New Issue | |
2025-03-06 19:07 | ale | Note Added: 0052165 | |
2025-03-06 19:07 | ale | File Added: export-selection-to-svg.diff | |
2025-03-06 19:09 | ale | Summary | Export selection => [PATCH] Export selection |
2025-03-06 19:09 | ale | Patch | No => Yes |
2025-03-06 19:13 | ale | Note Added: 0052167 |