automate text input from .txt and place in inkscape?

Discussion about writing code for Inkscape.
paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

automate text input from .txt and place in inkscape?

Postby paulsomlo » Sat Sep 30, 2017 4:17 am

I'm making buttons (name badges) for an event. In Inkscape, each button will consist of graphics inside of a circle. Each page will contain 12 buttons in three columns of four. I also have the names in a .txt file, one name per line. Is it possible to automate the process? I would like an extension/script that can fetch the names from the .txt file, change the font and size, then place them in the individual circles, having the "center" of the name coincide with the center of it's corresponding circle.

The alternative, is that I have to type 140 or so names into Inkscape and manually place them, which is painful.

Paul

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Sat Sep 30, 2017 7:30 am

If you use a CSV file instead, you can use the Generator extension:
http://wiki.inkscape.org/wiki/index.php ... #Generator
For usage instructions, see linked example files.
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Sat Sep 30, 2017 7:30 am

Oh, sorry, overlooked that it needs to change the font size - that's currently not possible.
But both centering and adapting the size should be possible via script...
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

tylerdurden
Posts: 2344
Joined: Sun Apr 14, 2013 12:04 pm
Location: Michigan, USA

Re: automate text input from .txt and place in inkscape?

Postby tylerdurden » Sat Sep 30, 2017 8:34 am

If there are only 140 names, copy /paste into a template is not so bad, and would probably be faster than making a script.
Have a nice day.

I'm using Inkscape 0.92.2 (5c3e80d, 2017-08-06), 64 bit win8.1

The Inkscape manual has lots of helpful info! http://tavmjong.free.fr/INKSCAPE/MANUAL/html/

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Sat Sep 30, 2017 12:04 pm

It's not a totally unusual request, I've seen this asked a couple of times. It's probably not even too difficult to do...
I'd make the script create the text in the standard font size first, then I'd ask Inkscape how wide the text is, and then, if too wide, I'd scale it down. Then center on object with specified ID.
Another approach could make the texts all the same width, but that runs the risk of getting a too tall text, when it's short, so that's not really better.
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

User avatar
brynn
Posts: 10309
Joined: Wed Sep 26, 2007 4:34 pm
Location: western USA
Contact:

Re: automate text input from .txt and place in inkscape?

Postby brynn » Sun Oct 01, 2017 10:09 pm

It would make for a nice extension, if an Inkscape extension could do that.

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Mon Oct 02, 2017 4:18 am

Well, it sort of worked. While it inherited the font and size from %VAR_name%, which is very nice, the positioning was not consistent. I was able to get the positioning correct for one name, but not for other names. Vertically, all the names were in the correct place, but horizontally the names shifted, seeming to correspond to the size of the name, but not the number of letters. Also, the output consists of one file for each name. Ideally, I would like to start with 12 graphics on a page and be able to place a different name in each graphic.

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Mon Oct 02, 2017 4:22 am

I compared some output files. It appears that the first letter in each name begins in the same place, consistently.
How does the .svg file know how to position the text?

tylerdurden
Posts: 2344
Joined: Sun Apr 14, 2013 12:04 pm
Location: Michigan, USA

Re: automate text input from .txt and place in inkscape?

Postby tylerdurden » Mon Oct 02, 2017 6:58 am

paulsomlo wrote:I compared some output files. It appears that the first letter in each name begins in the same place, consistently.
How does the .svg file know how to position the text?

Usually by the justification buttons in the text controls... for left/center/right/jusified. Positions a "text anchor" that is the snap-point for the text object.
Have a nice day.

I'm using Inkscape 0.92.2 (5c3e80d, 2017-08-06), 64 bit win8.1

The Inkscape manual has lots of helpful info! http://tavmjong.free.fr/INKSCAPE/MANUAL/html/

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Tue Oct 03, 2017 6:53 am

tylerdurden wrote:
paulsomlo wrote:I compared some output files. It appears that the first letter in each name begins in the same place, consistently.
How does the .svg file know how to position the text?

Usually by the justification buttons in the text controls... for left/center/right/jusified. Positions a "text anchor" that is the snap-point for the text object.

Doesn't work as expected.

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Tue Oct 03, 2017 10:52 am

Moini wrote:It's not a totally unusual request, I've seen this asked a couple of times. It's probably not even too difficult to do...
I'd make the script create the text in the standard font size first, then I'd ask Inkscape how wide the text is, and then, if too wide, I'd scale it down. Then center on object with specified ID.
Another approach could make the texts all the same width, but that runs the risk of getting a too tall text, when it's short, so that's not really better.

I've looked at the XML file and the coordinates given for text remain a mystery to me. They apparently don't correspond to the center and I don't know if they correspond to an edge, a corner, one of the "handles", or what. I finally found a way to center the text - I drew two vertical lines, placed each one at the periphery of the circle, diametrically opposed. I then centered %VAR_name% between them using the "distribution" function, rather than "align". Then using "stroke", I made the two vertical lines invisible. Now, my text is centered in the circle, but I'd like to be able to fill the circle equally for different size names. If I set the font size of %VAR_name% large, "Bob" works, but not so good for "Caroline". So, getting back to your suggestion Moini, how do I extract the width of the text? I see it displayed in inkscape, but not in the corresponding XML file. Or maybe I don't need to extract the text width, I just need to know how wide a space I have to fill. Then, I need to figure out how to scale the text to fit.

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Wed Oct 04, 2017 1:14 am

The centering can be done via setting text justification in the template file, as TylerDurden wrote (and of course, one must take care that the text center for the %blah% thing is in the correct position, as you found out).

The automatical adjustment of the width of the text or the font size would need to be done by editing the extensions program code. Inkscape can return an object's width via the command line, and it can also be set there.

If you want to work on the extension, see https://inkscape.org/en/develop/extensions/ and https://inkscape.org/doc/inkscape-man.html.
You can remove the helper lines, they don't need to be made invisible - unless you want to reuse them for all 144 names, and do the centering manually.
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Wed Oct 04, 2017 11:25 am

I got the centering to work, for the most part - longer names need a slight horizontal adjustment. I was able to figure out how to query the text width from the command line, but am not able to figure out how to change it from the command line. I can't find an inkscape verb that seems to do this directly. I also noticed that the XML file does not give font width, it gives font size in pixels, which corresponds to the height of the font as given in the svg file.

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Thu Oct 05, 2017 2:04 am

Yes, sorry for causing confusion. There's no direct verb for this. You'd need to use the python-based XML-editing extensions part. Take a look at other extensions that do scaling. They use functions from simpletransform.py. It will take a combination of both the bash and the python approach, due to the inconvenience of verbs not taking any parameters.
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Thu Oct 05, 2017 2:15 am

You'd have to set a scale transform for the text, I think.
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Fri Oct 06, 2017 4:18 pm

Well, I finished up this evening. I never did figure out how to scale the text; I chose a font size that would make the shortest names large enough to read, then went through the files with long names and manually reduced their size. I put 12 graphics on each page and did so manually. I may find a way to automate that in the future, but it only took about an hour and a half to place 200 something graphics into 20 pages of 12 each.

I did learn quite a bit about Inkscape, and some of my shell programming is coming back to me. Thank you all for your help.

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Sat Oct 07, 2017 6:37 am

Will you share the modified code?
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Fri Oct 20, 2017 11:25 am

Moini wrote:Will you share the modified code?

My apologies for not getting back to you sooner - I didn't have "reply notifications" turned on.

I didn't actually modify any code. I used the standard generator to place the names, which worked very well. The names that were too long, I changed manually by opening each file. I manually imported 12 files into each inkscape document and arranged them in 3 columns of 4.

I spent time today trying to automate the text sizing, but failed. I drew a rectangle in the document of the width I would like the text to be. Then I turned off the stroke, so as to make the rectangle invisible. Then, I used the commands EditCopy and EditPasteWidth to copy the rectangle to the clipboard and make the text the same width as the rectangle. It worked, but the text did not scale proportionally. I would like to have the document open with the width and height of the text locked, but can't figure out how to do this. I tried modifying default.svg, but it doesn't keep that setting.

I also played around with scaling, using matrix values, but when the text is scaled, it also seems to change x,y position. If I could figure out how to maintain the text position as it scales, I could add the matrix into the XML code using sed.

The one method that did work, was to replace the nominal px size of the text using sed. I suppose I could iterate through all the files, querying each one as to the text width, then make a decision based on width, whether to change the px size. The problem is, that when I open a file in Inkscape and select the text, the px size shown with x,y position is one number (the actual text size), the px size in the XML is another number (nominal size?), and the px size shown next to the box which indicates the font is something else. So I don't really know how much to reduce the px size from the command line - I'm just shooting in the dark.

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Sat Oct 21, 2017 3:45 am

I came up with a workable solution:

Code: Select all

#!/bin/sh
for file in *.svg
do
width=$(inkscape $file --query-width --query-id text3585)
width=${width%.*}
if [ $width -gt 120 ]
then
scalefactor=$(awk "BEGIN {print 120/$width*45}")
sed -i "s/font-size:45px/font-size:"$scalefactor"px/g" $file
fi
done


I iterate through all the .svg files in the directory. For each one, I query the width of the text element. The ${width%.*} makes $width an integer, to overcome the "integer expected" error. I would like my text to be 120px wide or less, thus I make a decision based on $width. If $width is greater than 120px, I calculate a scale factor. I used awk to do the calculation, since bash only does integer arithmetic, but any number of devices could have been used (bc, calc, etc.). Then I used sed to replace the font size in the XML code with $scalefactor.

It turns out that it really doesn't matter how font-size in the XML code is interpreted, whether it's some nominal value or whatever - as long as it can accept the scaled value.

My next hurdle to overcome is duplicate files - since I'm making name badges, there are always more than one "bob" or "linda", etc.. If I include duplicate names in the .csv file, the generator extension just overwrites each one, giving only one file. Maybe there's a built in shell command that renames a file in case it already exists. Or I need to modify the extension to check for the existence of a file, and if so, append a number onto the end of the file name.

Moini
Posts: 3381
Joined: Mon Oct 05, 2015 10:44 am

Re: automate text input from .txt and place in inkscape?

Postby Moini » Sat Oct 21, 2017 5:11 am

Great work so far - and thanks for explaining! I'm not really experienced in writing bash code, so I would have used python, and my suggestions were for that - glad you figured out a way that works in your preferred language :)
Something doesn't work? - Keeping an eye on the status bar can save you a lot of time!

Inkscape FAQ - Learning Resources - Website with tutorials (German and English)

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Fri Oct 27, 2017 6:19 am

Here's how I chose to deal with duplicate files:

Code: Select all

#!/bin/bash
# external variables: names.txt, test.svg
file="names.txt"
while read line
do
  sed "s/name/$line/g" test.svg > tmp.svg
  if [ -e $line.svg ]
    then
    i=1
    while [ -e $line$i.svg ]
    do
      let i++
    done
    line=$line$i
  fi
  cp tmp.svg $line.svg
done <"$file"
rm tmp.svg

I found some code online where someone else had solved the same problem. Rather than modifying the inkscape generator extension, I ended up writing a bash script to do the text replacement. I realized that out of 200 or so lines of code in the generator, I only needed about 20 to do what I needed. The generator worked fine, but it allows for much more flexibility than I need, and provides a graphical interface, which I'm not sure that I really need. Also, the generator wants a .csv file as input, whereas I would rather use my .txt file.

The code produces the following:
If names.txt contains the name "john" three times, the first file will be named "john", the second file "john1", the third file "john2". Each time I encounter a duplicate name in names.txt, the variable i will increment. The naming convention may not be ideal, but for my purposes, the filename is almost arbitrary.

I've now got a script that will place the names and properly deal with duplicate names, and another script that will resize names that are too large to fit on the badge. The final frontier, is to find a way to automatically import 12 individual files into one inkscape file. I've been playing with svg_stack.py from the command line, which does the import fine, but despite using the "margin" option, I can't place the imported files where I want them. The files end up at the same coordinates whether I use the margin option or not. Anyone have any experience with svg_stack? Or can suggest another way?

pelle
Posts: 53
Joined: Wed Mar 05, 2008 8:23 am

Re: automate text input from .txt and place in inkscape?

Postby pelle » Thu Mar 08, 2018 7:23 pm

I did not see this earlier because I do not log in often. My countersheets-extension (see https://www.boardgamegeek.com/thread/299033/inkscape-extensions-boardgame-development) can cope with centered text (at least I never had any issues with it, just making sure the text style is set to align center) and it can spit out sheets full of labels as individual layers (and optionally export each layer to a PDF and/or PNG).

What it can not do is automatically re-scale text to fit inside of a circle. Never thought of that and no one ever requested it. It would probably be just a few minutes of work to add that feature for anyone with some python skills. The extension already calls out to inkscape --query-all at least once to get the positions and sizes of elements in the template(s) and sometimes also in the generated sheet (see viewtopic.php?f=34&t=31091&p=103681#p103681). It would be possible to look up what the size of the generated text ended up being, what the size of some other element is (eg the circle that the text is supposed to be inside) and then apply the correct scale transform to make the text fit in the other element (with some configurable margins). Would be happy to accept a pull request (https://github.com/lifelike/countershee ... sion/pulls hint, hint).

The big part of the job would be to come up with a way to configure it that the user can understan. Somehow either in the SVG or CSV (or a combination) declare that "whatever is generated in this element should be scaled to fit inside of the bounds of that other element, and make it X% of that size just to have some margins").

EDIT: Of course a simple work-around would be to make several templates and then just make sure (manually or using a simple script) that in the CSV the longer names use a template with a bigger circle. Alternatively using one column in the CSV to set the font-size for the text.

https://github.com/lifelike/countershee ... /Set-Style

User avatar
prkos
Posts: 1625
Joined: Tue Nov 06, 2007 8:45 am
Location: Croatia

Re: automate text input from .txt and place in inkscape?

Postby prkos » Fri Mar 09, 2018 12:30 am

+1 on automatically re-scale text to fit inside of a circle (or other object?) that would be awesome!

I've used Inkscape sometimes to draw diagrams but in the end had to go with Dia, saves formatting time.

It would be best if you email the dev list at inkscape-devel@lists.sf.net and see if you can cross-pollinate :)
just hand over the chocolate and nobody gets hurt

Inkscape Manual on Floss
Inkscape FAQ
very comprehensive Inkscape guide
Inkscape 0.48 Illustrator's Cookbook - 109 recipes to learn and explore Inkscape - with SVG examples to download

paulsomlo
Posts: 11
Joined: Sat Sep 30, 2017 4:04 am

Re: automate text input from .txt and place in inkscape?

Postby paulsomlo » Fri Mar 09, 2018 4:58 am

I ended up using several bash scripts to modify inkscape's XML code. One to place the names (which reside in a text file), another to query the width of the name and resize if necessary, and another to import groups of 12 files (using svg_stack.py) into a template containing 12 circles. I then use inkscape verbs to align the 12 files with the 12 circles.

The application is name badges (buttons).


Return to “Programming”