How to insert a SVG image into a text frame?

Previous topic - Next topic

Darkoni

Hello,

I'm trying to insert a SVG file into a text frame as a inline graphic.

I find it very easy to do so using the GUI, but I'm having trouble doing it from a Python script.

Darkoni

#1
Here is the code that I have - run the script with

scribus -py svg-inline.py
from scribus import *

margins  = ( 10 , 10 , 20 , 20 )

newDocument( PAPER_A4_MM , margins , PORTRAIT , 1 , UNIT_MM , NOFACINGPAGES , FIRSTPAGERIGHT , 1 )

createText( 15 , 25 , 180 , 247 , 'textFrame' )
insertHtmlText( 'svg-inline.html' , 'textFrame' )
setFontSize( 12 , 'textFrame' )
layoutText( 'textFrame' )

text = getAllText( 'textFrame' )
findtext = 'here is placeholder for SVG item'
index = text.find( findtext )
selectText( index , len( findtext ) , 'textFrame' )
setTextColor( 'Red' , 'textFrame' )

placeSVG( 'svg-inline.svg' , 10 , 10 ) # 'layer1' is placed item name
setItemName( 'mysvg' , 'layer1' ) # rename item to 'mysvg'

copyObjects( 'mysvg' )
pasted = pasteObjects() # ['Copy of mysvg']
moveObjectAbs( 150 , 10 , pasted[0] )



# TODO pasteObjects into textFrame



print( '---' )
print( 'getAllObjects',getAllObjects() )
print( '---' )

deselectAll()

saveDocAs("svg-inline-test.sla")


Please, see attached svg-inline.zip

a.l.e

#2
i don't think you can do that with the current version of scribus.

for this to work, you would need this patch

https://bugs.scribus.net/view.php?id=16294

here is a "cleaned up" version of your script, that does work once you have `setEditMode()` from the patch:

Code (python) Select
import scribus

scribus.newDocument(scribus.PAPER_A4_MM, (10, 10, 10, 10), scribus.PORTRAIT, 1, scribus.UNIT_MM, scribus.NOFACINGPAGES, scribus.FIRSTPAGERIGHT, 1)


# TODO: how to get the group name? placeSVG does not return and the group is not selected
# svg_item = scribus.placeSVG( '/tmp/svg-inline.svg', 10, 10)
scribus.placeSVG('svg-inline.svg', 10, 10)
svg_item = scribus.getAllObjects()[0] # the svg group is the only object on the page
scribus.copyObjects(svg_item) # copying the object also selects it!


text_frame = scribus.createText(10 , 25 , 55 , 15)

scribus.deselectAll()
scribus.selectObject(text_frame)
scribus.setEditMode() # this function does not exist yet! see https://bugs.scribus.net/view.php?id=16294
scribus.pasteObjects()
scribus.setNormalMode()

scribus.deleteObject(svg_item)

a.l.e

i noticed later, that your code tries to replace a text placeholder through an inline svg.

that's also possible (under the same condition that you have the patch, of course!)

Code (python) Select
import scribus

scribus.newDocument(scribus.PAPER_A4_MM, (10, 10, 10, 10), scribus.PORTRAIT, 1, scribus.UNIT_MM, scribus.NOFACINGPAGES, scribus.FIRSTPAGERIGHT, 1)

text_frame = scribus.createText(10 , 25 , 55 , 30)
scribus.insertText('here is the placeholder', 0, text_frame)
scribus.layoutText(text_frame)

# TODO: how to get the group name? placeSVG does not return and the group is not selected
# svg_item = scribus.placeSVG('/svg-inline.svg', 10 , 10)
scribus.placeSVG('/tmp/svg-inline.svg', 10 , 10)
svg_item = scribus.getAllObjects()[1] # the svg group is the only object on the page
scribus.copyObjects(svg_item) # copying the object also selects it!


scribus.deselectAll()
scribus.selectObject(text_frame)

text = scribus.getAllText(text_frame)
start_i = text.find('placeholder')
scribus.selectText(start_i, len('placeholder'), text_frame)

scribus.setEditMode() # this function does not exist yet! see https://bugs.scribus.net/view.php?id=16294
scribus.pasteObjects()
scribus.setNormalMode()

scribus.deleteObject(svg_item)

Darkoni

Hi a.l.e!

Thank you for your fast reply!

scribus.setEditMode() will really help me!

But, how can I apply the patch?

I am using Scribus 1.5.8 - installed with yum on Fedora 38.

Many thanks!

a.l.e

hi darkoni

there are two ways:

  • you get the sources and compile it with the patch applied (which is probably not doable if you don't already know how to compile software)
  • you wait for the patch being applied to scribus and then get the "nightly" appimage with the patch in it (no idea why the patch has not been applied at the time it has been created... but it might have been because i was not very carefully and unrelated changes slipped in...)

i guess that the best bet is waiting for the team to apply the patch, now that there is a use case and the patch has been cleaned up (and tested with your script) a bit...

ciao
a.l.e

Darkoni

Hi a.l.e

$ svn checkout svn://scribus.net
$ cmake .
$ make
$ sudo make install
$ scribus

It looks great!

"Scribus Version 1.7.0.svn"

Tomorrow I will add lines from edit-mode.diff to cmdmani.cpp and recompile.

Hope everything will go as smooth as today.

Many thanks a.l.e  :)

a.l.e

if that works, then YES you're ready for compiling scribus and applying the patch!

just one remark: 1.7.0 is a development branch in its first stages, so things might change and some might not work as expected (not that often).


if you need to share the .sla files with other people, you might rather want to compile the 1.5.9 (or is it already called 1.6.0?) branch.
otherwise, scribus development branches are known for working rather well and several people prefer to use it for their daily work.

all in all, since you seem to set up an automated workflow, if you can create the PDFs you need and print them correctly, then you're probably fine with the nicer 1.7.0 (yes, once you're used to 1.7.0, 1.6.0 feels outdated even before it's released: thanks martin for our precious work!!!)

a.l.e

p.s.: no need to apply the patch anymore : - )

https://bugs.scribus.net/view.php?id=16294

and if you wait a few minutes, you'll also be able to get the appimage for 1.6svn without even compiling it.

thanks craig for applying the patch!

Darkoni

Hi a.l.e & Craig !!!

Everything is going great!!!

BIG thanks to you both a.l.e & Craig and the whole Scribus team !!!

$ svn checkout svn://scribus.net
U    trunk/Scribus/scribus/plugins/scriptplugin/cmdmani.cpp
U    trunk/Scribus/scribus/plugins/scriptplugin/cmdmani.h
U    trunk/Scribus/scribus/plugins/scriptplugin/scriptplugin.cpp
U    branches/Version15x/Scribus/scribus/plugins/scriptplugin/cmdmani.cpp
U    branches/Version15x/Scribus/scribus/plugins/scriptplugin/cmdmani.h
U    branches/Version15x/Scribus/scribus/plugins/scriptplugin/scriptplugin.cpp
Checked out revision 25788.
$ cd trunk/Scribus
$ make
$ sudo make install

Then I wrote a script dir_scribus.py

from scribus import *

d = dir(scribus)

print("")
print("-------------------------------------------")
print(d)
print("-------------------------------------------")
print("setEditMode:", "setEditMode" in d)
print("setNormalMode:", "setNormalMode" in d)
print("-------------------------------------------")
print("scribus_version:", scribus_version)
print("scribus_version_info:", scribus_version_info)
print("-------------------------------------------")
print("")

Run the script with Scribus

scribus -g -py dir_scribus.py

The result is

-------------------------------------------
setEditMode: True
setNormalMode: True
-------------------------------------------
scribus_version: 1.7.0.svn
scribus_version_info: (1, 7, 0, '.svn', 0)
-------------------------------------------

Darkoni

Hi!

Life would be more simple if functions placeEPS, placeODG, placeSVG, placeSXD, placeVectorFile accepted 'suggested' name as a parameter and can return the name of the created item, just like the function createText.

placeEPS("filename", x, y)
placeODG("filename", x, y)
placeSVG("filename", x, y)
placeSXD("filename", x, y)
placeVectorFile("filename", x, y)

createText(x, y, width, height, ["name"]) -> string

Source files are:

trunk/Scribus/scribus/plugins/scripter/api_page.cpp
trunk/Scribus/scribus/plugins/scriptplugin/cmdobj.cpp

Currently, placeSVG assigns a 'random' name to each created item and this makes it difficult to rename it to my own name.

PS: In the morning, I will see if I can do something.

Regards

a.l.e

#11
hi darkoni

as i was replicating the relevant parts of your script, i also wondered why it was not possible to retrieve the group's name.

what i've found out is that the scripter command is defined in

plugins/scriptplugin/svgimport.cpp
which calls

fmt->loadFile(fName, flags);
the relevant loadFile being defined in

plugins/import/svg/svgplugin.cpp
where it calls a local import which is defined as

bool SVGImportPlugin::import(QString filename, int flags)
which calls

dia->import(filename, trSettings, flags);
defined as

bool SVGPlug::import(const QString& fname, const TransactionSettings& trSettings, int flags)
in the same file

where it calls

loadData(fname)
defined just below as

bool SVGPlug::loadData(const QString& fName)
at that point my thoughts were

- screw "success = inpdoc.setContent(&compressor, nullptr);"
- too many signatures to change (since the same has to be done for each type of vector file).
- the bool return value seems to be unused but who knows if some parts of code use it for some file type?
- still no clue where the group name gets set.
- i can get the list of elements on the page before and after the import of the svg, do the diff, and call it a day.

but if you're brave enough to give it a try:

- i agree that the name "layer1" is stupid (i guess it's based on the root element of the svg).
- the name should be "Group#" (where is # is the highest number in the document).
- the scripter command should return the name that has been generated.
- forget about plugins/scripter, just work on plugins/scriptplugin.
- first only patch placeSVG since it's the most relevant one and wait for the feedback from the team before doing more work on the other commands.

and, finally, GOOD LUCK!

a.l.e

a.l.e

somehow a boring afternoon...

this sets the group name to "Group#"...

https://gitlab.com/a.l.e/scribus/-/commit/067c7b006c66b3e66c8d42fb54f688536a4ea6e7

diff --git a/scribus/plugins/import/svg/svgplugin.cpp b/scribus/plugins/import/svg/svgplugin.cpp
index c9b8b7111be091a03dc9aaeb3bffc90aa0ffab2f..929ffeb70a999e88cb82447871ca01dfc6039bf3 100644
--- a/scribus/plugins/import/svg/svgplugin.cpp
+++ b/scribus/plugins/import/svg/svgplugin.cpp
@@ -508,6 +508,9 @@ void SVGPlug::convert(const TransactionSettings& trSettings, int flags)
  if ((Elements.count() > 1) && (!(flags & LoadSavePlugin::lfCreateDoc)))
  {
  m_Doc->groupObjectsList(Elements);
+ } else {
+ Elements.at(0)->setItemName( tr("Group%1").arg(m_Doc->GroupCounter));
+ m_Doc->GroupCounter++;
  }
  m_Doc->DoDrawing = true;
  m_Doc->scMW()->setScriptRunning(false);

now, i wonder how to meaningfully return the new name...

Darkoni

#13
I am almost done with automatization of "small ads" page layout.

1) I have a script that creates SVG labels
node oglasi-labels.js

2) Scribus Python script loads SVG labels and creates oglasi-template.sla
scribus --no-splash -py oglasi-create-template.py

3) For file oglasi-template.sla I manually set styles for characters and paragraphs

4) File oglasi.html was created with JavaScript. Because I can't put ads here with the actuall text. Script creates random number of ads for each category.
node oglasi-create-test-html.js > oglasi.html

5) Scribus Python script oglasi.py opened the Scribus file oglasi-template.sla,
* took the formatted HTML from the file oglasi.html, and
* replaced the placeholders from the text behind the labels.
* The placeholders for the lines were replaced with the Scribus line item.
* On the end, file is saved as oglasi.sla
scribus --no-splash -py oglasi.py

For to final touch, I did a manual adjustment to get all texts to be aligned to bottom page margin.

Question: Is it possible to let Scribus manually adjust text in the frame, that all texts stretch or shrink to be on the bottom page margin?



See screenshots:

https://ibb.co/hRJ4yxb

https://ibb.co/T837dn9

https://ibb.co/k6YWdwL

https://ibb.co/hyQ1gY8

https://ibb.co/qm82dnW

https://ibb.co/c3cS51g

https://ibb.co/nRQ0pfT

https://ibb.co/drYDFh0