@@ -342,21 +342,14 @@ def new_path(tag, clipping_path: bool = False):
342342 if clipping_path :
343343 path = ClippingPath ()
344344 apply_styles (path , tag )
345-
346345 return path
347346
348347 @classmethod
349348 def rect (cls , tag , clipping_path : bool = False ):
350349 """Convert an SVG <rect> into a PDF path."""
351350 # svg rect is wound clockwise
352- if "x" in tag .attrib :
353- x = resolve_length (tag .attrib ["x" ])
354- else :
355- x = 0
356- if "y" in tag .attrib :
357- y = resolve_length (tag .attrib ["y" ])
358- else :
359- y = 0
351+ x = resolve_length (tag .attrib .get ("x" , 0 ))
352+ y = resolve_length (tag .attrib .get ("y" , 0 ))
360353 width = tag .attrib .get ("width" , "0" )
361354 if width .endswith ("%" ):
362355 width = Percent (width [:- 1 ])
@@ -397,7 +390,6 @@ def rect(cls, tag, clipping_path: bool = False):
397390 ry = height / 2
398391
399392 path = cls .new_path (tag , clipping_path )
400-
401393 path .rectangle (x , y , width , height , rx , ry )
402394 return path
403395
@@ -409,7 +401,6 @@ def circle(cls, tag, clipping_path: bool = False):
409401 r = float (tag .attrib ["r" ])
410402
411403 path = cls .new_path (tag , clipping_path )
412-
413404 path .circle (cx , cy , r )
414405 return path
415406
@@ -447,34 +438,24 @@ def line(cls, tag):
447438 y2 = float (tag .attrib ["y2" ])
448439
449440 path = cls .new_path (tag )
450-
451441 path .move_to (x1 , y1 )
452442 path .line_to (x2 , y2 )
453-
454443 return path
455444
456445 @classmethod
457446 def polyline (cls , tag ):
458447 """Convert an SVG <polyline> into a PDF path."""
459- points = tag .attrib ["points" ]
460-
461448 path = cls .new_path (tag )
462-
463- points = "M" + points
449+ points = "M" + tag .attrib ["points" ]
464450 svg_path_converter (path , points )
465-
466451 return path
467452
468453 @classmethod
469454 def polygon (cls , tag , clipping_path : bool = False ):
470455 """Convert an SVG <polygon> into a PDF path."""
471- points = tag .attrib ["points" ]
472-
473456 path = cls .new_path (tag , clipping_path )
474-
475- points = "M" + points + "Z"
457+ points = "M" + tag .attrib ["points" ] + "Z"
476458 svg_path_converter (path , points )
477-
478459 return path
479460
480461
@@ -878,6 +859,8 @@ def handle_defs(self, defs):
878859 self .build_path (child )
879860 elif child .tag in xmlns_lookup ("svg" , "image" ):
880861 self .build_image (child )
862+ elif child .tag in xmlns_lookup ("svg" , "text" ):
863+ self .build_text (child )
881864 elif child .tag in shape_tags :
882865 self .build_shape (child )
883866 elif child .tag in xmlns_lookup ("svg" , "clipPath" ):
@@ -947,6 +930,8 @@ def build_group(self, group, pdf_group=None):
947930 pdf_group .add_item (self .build_xref (child ))
948931 elif child .tag in xmlns_lookup ("svg" , "image" ):
949932 pdf_group .add_item (self .build_image (child ))
933+ elif child .tag in xmlns_lookup ("svg" , "text" ):
934+ pdf_group .add_item (self .build_text (child ))
950935 else :
951936 LOGGER .debug ("Unsupported SVG tag: <%s>" , child .tag )
952937
@@ -987,6 +972,43 @@ def apply_clipping_path(self, stylable, svg_element):
987972 clipping_path_id = re .search (r"url\((\#\w+)\)" , clipping_path )
988973 stylable .clipping_path = self .cross_references [clipping_path_id [1 ]]
989974
975+ @force_nodocument
976+ def build_text (self , text ):
977+ if "dx" in text .attrib or "dy" in text .attrib :
978+ raise NotImplementedError (
979+ '"dx" / "dy" defined on <text> is currently not supported (but contributions are welcome!)'
980+ )
981+ if "lengthAdjust" in text .attrib :
982+ raise NotImplementedError (
983+ '"lengthAdjust" defined on <text> is currently not supported (but contributions are welcome!)'
984+ )
985+ if "rotate" in text .attrib :
986+ raise NotImplementedError (
987+ '"rotate" defined on <text> is currently not supported (but contributions are welcome!)'
988+ )
989+ if "style" in text .attrib :
990+ raise NotImplementedError (
991+ '"style" defined on <text> is currently not supported (but contributions are welcome!)'
992+ )
993+ if "textLength" in text .attrib :
994+ raise NotImplementedError (
995+ '"textLength" defined on <text> is currently not supported (but contributions are welcome!)'
996+ )
997+ if "transform" in text .attrib :
998+ raise NotImplementedError (
999+ '"transform" defined on <text> is currently not supported (but contributions are welcome!)'
1000+ )
1001+ font_family = text .attrib .get ("font-family" )
1002+ font_size = text .attrib .get ("font-size" )
1003+ # TODO: reuse code from line_break & text_region modules.
1004+ # We could either:
1005+ # 1. handle text regions in this module (svg), with a dedicated SVGText class.
1006+ # 2. handle text regions in the drawing module, maybe by defining a PaintedPath.text() method.
1007+ # This may be the best approach, as we would benefit from the global transformation performed in SVGObject.transform_to_rect_viewport()
1008+ svg_text = None
1009+ self .update_xref (text .attrib .get ("id" ), svg_text )
1010+ return svg_text
1011+
9901012 @force_nodocument
9911013 def build_image (self , image ):
9921014 href = None
0 commit comments