Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svgmobject update with basic processing of 'text' tag #1083

Closed
wants to merge 9 commits into from

Conversation

iterater
Copy link

Motivation

Currently,, SVGMobject doesn't support <text> tag in SVG format. The support of this tag is good for plotting diagrams, graphs, and other structures from SVG. I've faced it when trying to plot graphs rendered by graphviz.

Implementation

I've added text processing to SVGMobject using Text mobject with the following features:

  • scaling text using text_scale for better drawing (original font size is incorrectly small;
  • support of font-family translated into font parameter of Text mobject;
  • additional shifting up to the half of 'o' height to adjust centered placement.

Testing

Tested by drawing SVG file with a graph built by graphviz. The used file is available here.

from manimlib.imports import *

class SvgGraphScene(Scene):
    def construct(self):
        g = SVGMobject(file_name=r'd:\g.svg', stroke_width=1.0, 
            fill_opacity=0.0, text_scale=2.0)
        g.scale(3)
        self.add(g)
        self.wait(5)

The result is shown below: left - before, right - after.

before_after

Additional notes

  • There are parameters in <text> tag which are not supported yet (further work): text-anchor, centering and rotation in font-family etc.
  • It will be good to extend the logic of SVGMobject to support different stroke/fill styles for different objects. E.g. to fill the text instead of stroking. Currently, it can be done using submobjects.
  • It seems that SVGMobject doesn't support stroke-dasharray in <path>. Could be useful. Again, currently, it seems to be available using submobjects.

Comment on lines 123 to 124
o_hight = Text('o', size=font_size*self.text_scale, font=font_family_list[0]).get_height() # vertical centering with 'o'
return txt_mobject.shift(UP*o_hight*0.5)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting kinda lost here so does a svg text element with the value o have incorrect vertical centering does this happen for other characters. I wonder if there is a way to do this automatically and not for the 'o' degenerate case

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default Text mobject is centered about the top of small letters (red dot below). I think the correct behavior is to use the central line of small letters (green dot).

centering

Without a half-o height shift, the result in PR looks like this (which seems to be incorrect).

shifted_center

Also, I've looked at TextWithFixHeight class in text_mobject.py for reference of text height measuring.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextWithFixHeight will create problems thats why i removed that in #1071

@NavpreetDevpuri
Copy link
Contributor

I think we have to use cairo directly to do this.
M Trying.

@NavpreetDevpuri
Copy link
Contributor

NavpreetDevpuri commented May 18, 2020

bandicam 2020-05-19 03-30-51-296
Look at the text background which is black colored rectangle
and the position of text is pink colored circle the mid point of that background rectangle
for now i don't know how to get that center for different-different fonts

@iterater
Copy link
Author

iterater commented May 18, 2020

@NavpreetDevpuri

Yes, currently, the arrangement is naturally done with whole text along the center of the rectangle (see red dots below).

test_1

The desired behavior is to arrange vertically along with the small characters of text ('o' position). To count that I propose counting extra space for each character using the original cairo function text_extents and comparing height and vertical bearing for the whole text and separate characters. So the text can be arranged as follows. Green dots - new vertical "center".

test_2

@NavpreetDevpuri
Copy link
Contributor

NavpreetDevpuri commented May 19, 2020

I think if we store all Text elements from svg files in a list and after that just replace Text elements in svg file with cairo rendered Texts at appropriate locations according to font and style. Save this new generated svg file may be in new media folder media/svg
This seems a better approach because we don't need to rebuild text render.

But for a base your method is just fine.
We can improve it later.

@NavpreetDevpuri
Copy link
Contributor

NavpreetDevpuri commented May 19, 2020

But svg file is still showing in wrong way.
Reset text_mobject.py
Left side is in chrome
Right side is in manim
collage

@iterater
Copy link
Author

@NavpreetDevpuri, yes, I see. The problem was in the interpretation of vertical alignment in SVG. The vertical anchor in SVG is along the baseline, not in center. Now the text placement seems to be correct:

test_3

@NavpreetDevpuri
Copy link
Contributor

Good job!
Now implement text-anchor shift text right or left by the half of width according to 'text-anchor' and set default value for text stroke to 0 and fill the text with color.

- text horizontal alignment
- fill text as stroke in main object
- text without stroke by default
@iterater
Copy link
Author

iterater commented May 19, 2020

@NavpreetDevpuri

  1. The horizontal alignment was updated. See below. NB The text-anchor attribute was modified manually in SVG file for "A" (text-anchor="start") and "B b" (text-anchor="end") nodes, so they are shifted. With the original file, everything is placed fine.

test_4

  1. Stroke and fill is updated for all submobjects in base VMobject. So, new update_text_stroke_and_fill() called in __init__ was added. The default stroke is used for text color. Stroke in the text is disabled by default.

@NavpreetDevpuri
Copy link
Contributor

NavpreetDevpuri commented May 19, 2020

I think if we store all Text elements from svg files in a list and after that just replace Text elements in svg file with cairo rendered Texts at appropriate locations according to font and style. Save this new generated svg file may be in new media folder media/svg
This seems a better approach because we don't need to rebuild text render.

But for a base your method is just fine.
We can improve it later.

as i said
a better way to use inkscape to convert svg's text to paths automatically according to font, size ..etc it handles everything.
You can try as follow
install inkscape then add C:\Program Files\Inkscape\bin; to environment variable path.
open terminal or cmd at 'g.svg' file's directory
then run following command

inkscape g.svg --export-text-to-path --export-plain-svg --export-filename=output.svg

this will create output.svg containing path tags instead of text tag.

@iterater
Copy link
Author

Yes, that possibly works. But as I see there are two issues.

  1. This requires additional external software to be used. As a general solution, that looks not so good. So I believe adding the functions proposed in this PR will be better.

  2. In my particular case, SVGMobject fails in the processing of <path> tag both in my branch and in master with the following error: TypeError: add_cubic_bezier_curve_to() missing 2 required positional arguments: 'handle2' and 'anchor'. Here is the input SVG file. And I think it should be another issue independent of this PR. (I can create an issue here for that)

All in all, for my purpose, my update seems to be working well. See an example from my current work (sorry for text in Cyrillic):

Shapes

eulertour pushed a commit to eulertour/manim-3b1b that referenced this pull request Mar 16, 2021
@TonyCrane
Copy link
Collaborator

It looks like this pull request is out of date, as SVGobject has been refactored in #1731 and support for text is also in the works.
Thanks for this, but I'm closing this pull request.

@TonyCrane TonyCrane closed this Feb 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants