Open girstenbrei opened 5 years ago
Thanks for the well-presented report.
I've studied a bit what ReportLab allows us to do with text. Although the pdfgen.PDFTextObject
has some advanced rendering capabilities (notable the setTextRenderMode
method which would allow to activate the fill and stroke mode), I didn't yet found the method to leverage them from the graphics.String
limited set of properties. Maybe @deeplook will have an idea.
@claudep Thank you for your quick reply!
Disclaimer: I have no idea, how svglib works or how reportlab works.
So the except block in svglib.py:1349 hides that the setattr(shape, rlgAttr, meth(svgAttrValue))
one line earlier fails. This seems to be caused by reportlabs.graphics.shapes.String missing the stroke*
-attributes, shapes.String:1426. IMHO this should log the error on debug level.
I tried to simply add the missing attributes to shapes.String
, and after a little time (copy pasting stuff) the pdf converted, but still was missing the text outline (also checked with Illustrator if the outline may be invisible).
I have no real reason why, but maybe my added attributes get lost between seeting them by svglib and rendering the pdf. And maybe this todo notice in shapes.String:1808, a line above the _attrMap
may have something to do with that.
But I just don't know enough to start investigating reportlab and everything that is happening from setting the attribute until rendering the pdf. Could anyone point me in the right direction? Or should I contact reportlabs maintainers for this? @deeplook do you maybe know anything about this?
My next step would be to take svglib out of the equation, just trying to set text on a canvas in reportlab directly, investigating if stroke works when used directly.
In between I had a problem caused by the default of strokeDashArray in svglib.py:1319, the default is set to none. But if used, it seems to be handed down to svglib.py:351 convertLengthList which does not now how to handel none
. Is this a separate Issue?
My next step would be to take svglib out of the equation
Good approach, tell us about your pure reportlab findings.
Is this a separate Issue?
Probably., If you can trigger the problem with a minimal SVG, it would be great (and create a new issue for that).
Small experiment with reportlabs:
from reportlab.pdfgen.canvas import Canvas
c = Canvas('hello.pdf')
c.setStrokeColor((1,0,0))
c.setFillColor((0,0,1))
c.setLineWidth(2)
c.setFont('Helvetica',36)
c.drawString(100,700,'Hello World', mode=2)
c.save()
produces a PDF with text outlined by another color (good in Adobe Reader, Illustrator shows that every char is a separate object). This and this source both contain the information, but I could not find anything in the official docs. The first source even talks about this issue. But as mentioned in source 2, this only works having direct access to the canvas.
And after reading some code: the example above works, because reportlabs Canvas.drawString in canvas.py:1561 does set the TextRenderMode to the value of mode. Svglib (or any other drawing for that matter) uses the drawString method in renderPDF:157 which does offer mode settings.
The following produces (semi-good) results:
stroke*
attributes to _attrMap in shapes.Stringstroke*
attributesCritique
I have no idea what I broke with this. Especially, as the two drawString
methods seem to have completely different intentions (canvas setting text related values like RenderMode, CharSpace, ... and _PDFRenderer beeing able to compute different text alignments but completely ignoring any values set on the text itself).
Semi-good results meaning, opening the pdf in Adobe Reader works fine (with outline). But opening it in Illustrator shows, that the text and outline are completely separate objects and, at least in Illustrator, they are not even close to beeing aligned. And, at the moment, the outline is always dashed. Pro: dashing works. Con: only able to dash the line ... .
Conclusion Svglib seems to do all the right things. Yeah! Reportlab just has a few different and unconnected ways to draw a String. So, unless any one has a better idea, I will open an issue with them.
IMHO, I would leave this issue open until I know how to proceed with reportlab. Then I would add a debug log statement in svglib:1349 and send you a PR. Is that ok for you?
Thanks again for your help, cheers! Chris
Many thanks for this thorough experimentation! Your plan sounds good.
If at some point svglib has to subclass a ReportLab object (say shapes.String
) to allow for more attributes (waiting a fix in RL itself), we can also try to do that.
@claudep I thought about pushing the functionality from svglib into reportlabs as I noticed the monkeypatch_reportlab - method, something along the lines of subclassing shapes.String
, adding the missing attributes and then patching it back into reportlab (additionally forcing the change in the drawString
methods). But this gets uggly quick ...
I'll let you know what the reportlab devs say!
Edit: the Issue at reportlab: https://bitbucket.org/rptlab/reportlab/issues/185/unable-to-outline-stroke-a-string-in-a
It looks like some progress has been made on Reportlab's side (from version 3.5.60). See:
So I would like to convert an svg with text to a pdf. In conversion, the text looses its outline ('stroke' in svg speak, so the internet tells me.)
This is an example svg to reproduce the problem, test.pdf is the result I get when running it.
test.pdf
Viewing the svg in Chrome/Firefox/Inkscape/Illustrator shows the outline as expected. Also, I am not sure if this is a problem with svglib or reportlabs rendering of the pdf.
It tested stroke on a circle, that worked. But everything else I tried for text did not (changing font, size, stroke color, stroke width). Am I missing something?
Additional Infos: Running on Windows 10, Python 3.7.3, svglib 0.9.1, reportlab 3.5.23 I'd be happy to provide you with any more information if needed!
Thank you all for developing this and helping me, you are awesome!