View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0017438 | Scribus | Import / Export | public | 2025-03-06 07:25 | 2025-09-23 17:41 |
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) |
|
any feedback? |
|
I would have needed this today to copy my shapes from Scribus to Inkscape, without exporting the whole file... |
|
I don't understand why any new layer and all this extra code is created??? Why not just test isSelected() in the items loop? |
|
After six months I also wonder what the reasons are... I've now tried to just add the isSelected() in the loop and export a set of three shapes to svg and the most obvious difference is that the SVG document has the size of the page and not the one of the selection. For the creation of layers, I suppose that the code is trying to just create the layers where the selection is, and not create all the layers that exist in the Scribus document. I've not applied again the patch, but the code with the isSelected() all alone does create all the layers. And when you export a selection, most of the time all the items will be on the same layer... And my note that was introducing the patch seems to say that this is one of the changes the patch introduces. (it might also do the same for the full page export...) Skimming the patch, it seems that most of the changes relate to: - adding a checkbox - setting the size of the SVG to the size of the selection - processing the selected items or the current page Sadly, the diff is not as clean as it could be... but that's the way it got automatically generated... I don't think there is much I can do. |
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 | |
2025-03-27 08:45 | ale | Note Added: 0052347 | |
2025-05-17 07:33 | ale | Relationship added | related to 0003031 |
2025-06-05 06:36 | ale | Relationship added | child of 0017541 |
2025-09-13 07:21 | ale | Note Added: 0053025 | |
2025-09-18 20:41 | cbradney | Note Added: 0053029 | |
2025-09-23 17:41 | ale | Note Added: 0053034 |