Rough implementation of evalString, forward references, SVGs, and more

Bug #1135051 reported by Kyle MacFarlane
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
z3c.rml
Fix Committed
Undecided
Unassigned

Bug Description

Thanks for the amazing work on this package. I'd been working with a fork of the mess that is trml2pdf for a long time and decided that it was quicker to implement the features I needed into z3c.rml than to keep hacking away at trml2pdf. Included in the patch are some of the following, but I wouldn't apply this patch directly.

BUG FIX: _getText for pageNumber, getName, etc was missing the tail.

BUG FIX: TT and Type1 fonts didn't have their file attributes set to attr.File which meant they didn't support looking in packages. I don't know if other font types like Cid also need to be changed because I'm not sure how they load their fonts.

BUG FIX: namedString was drawing its contents instead of being silent.

BUG FIX: namedString wasn't evaluating its contents so you couldn't use elements like pageNumber inside of it.

NEW/FIX: getName was missing the default attribute. This should be set to a similar length string as what it's likely to return so that the number of pages doesn't change on a second pass. In the RML docs you will often seen it set to just "X".

NEW: getName now supports forward references so you can now do "Page X of Y". Surprisingly, this was probably the easiest thing to implement.

It seems like getName, pageNumber, evalString, etc are actually meant to be some kind of flowable, and the official RML docs show them being used in such a way outside of paragraphs (e.g. in table cells). I think the base flowable would look something like reportlab.platypus.doctemplate.IndexingFlowable and the method isSatisfied would return 0 when a second pass is needed. Any flowable that returns 1 for isIndexing is added to a special list by reportlab.platypus.doctemplate.BaseDocTemplate.multiBuild and then the method isSatisfied is checked to decide if another pass is required.

Instead of completely refactoring how these elements worked I just add a dummy IndexingFlowable that asks for +1 pass if getName accesses a name not yet defined. The official RML docs also say that it will never perform more than 2 passes so I limited the max passes to 2 as well. In practice if a third pass is needed you have a problem and just have to wait longer for the error message anyway.

NEW: evalString is now implemented. You'll probably notice that I've just copied and pasted the pageNumber, evalString, getName, etc code all over the place. They need to be redone in a DRY way but if any refactoring is going to be done it might as well address the above issue as well.

Implementing evalString as a ParaFrag was probably the hardest thing to figure out. It's obviously not what ParaFrags are meant to do. There's actually an alternative Paragraph flowable in reportlab.platypus.para that references evalString, getName, etc and looks like it's maybe the interface to how ReportLab Plus / rl2extra does it. There might be some ideas in there.

evalString evaluates the expression with Python's eval with all builtins disabled. It's probably still not 100% safe but then again probably neither is ReportLab itself.

NEW: SVGs are now supported as a file type to Image tags.

There's no mention of it in the official RML docs but according to posts by ReportLab employees RML proper apparently does support SVGs. There's no mention of how it's done and whether it's a different tag or not but I implemented it using the regular Image tag. The ReportLab source mentions svglib by Dinu Gherman which has a function called svg2rlg and converts an SVG to a Drawing object. However svglib only managed to draw 5-10% of the paths in my SVGs and I had much better success with a package confusingly also called svg2rlg by Runar Tenfjord and so I've used that instead. Of course you can't use bitmap fills or anything like that.

NEW: Added printScaling attribute to docinit. This is something that you can't do with regular RML.

reportlab.pdfgen.canvas.Canvas has a method called setViewerPreferences which allows you to set the preferences mentioned in reportlab.pdfbase.pdfdoc.ViewerPreferencesPDFDictionary. The most useful of these preferences is PrintScaling which lets you set whether the PDF document is printed by the viewer at actual size or scaled to fit. This is very useful when printing things like labels that require a certain amount of precision. For example, when set to None, in Acrobat the print dialog will select "Actual Size" by default and in Chrome "Fit to page" will be unticked by default.

I don't know if this attribute should be on docinit or document or wherever. It might also be worth just implementing all the possible viewer preference options, maybe with a custom tag similar to pageInfo.

Something else I noticed but couldn't be bothered to fix is that all types of styles are put in the same dictionary so table, para and box styles with the same name clash. It was easier to just rename my styles than to change z3c.rml.

Revision history for this message
Kyle MacFarlane (kyle-deletethetrees) wrote :
Changed in z3c.rml:
status: New → Fix Committed
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.