
    hG                       d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZmZ ddlmZ ddlmZmZmZmZmZmZ ddlmZ ddlmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z& ddl'm(Z( dd	l)m*Z*m+Z+ dd
l,m-Z- ddl.m/Z/m0Z0 ddl1m2Z2 	 ddl3m4Z4 ddl6Z6ddl7Z7ddl8m9Z9 ddl:m;Z;m<Z<m=Z=m>Z>m?Z? ddl:m@ZA ddl:mBZC ddlDmEZEmFZFmGZG dej0                  dej0                  fdZH	 	 	 	 dLdeIdeeI   deIdeIdeeI   deeeI   eJf   fdZB	 dMdeIdeIdeIdeeIeJf   fdZ@dZK eL       ZM ej                  eO      ZP edg d       ZQ ej                  d!      j                  ZT G d" d#e!      ZU G d$ d%e!      ZV G d& d'e6j                        ZX G d( d)      ZY G d* d+eY      ZZ G d, d-e6j                        Z\ G d. d/e]      Z^ G d0 d1      Z_ G d2 d3      Z` G d4 d5      Za G d6 d7ea      Zb	 dNd8eeIej                  eI   f   d9eJd:edee   fd;Zdd<eee   ddfd=Zf	 dNd8eeIej                  eI   f   d9eJdee   fd>Zgd?edeeI   fd@ZhdOd?edAeJdBeidefdCZj	 	 dPdDeeI   dAeJdEeJdFeJdeeI   f
dGZkdHedIeddfdJZldQdKZm em        y# e5$ r
 ddlm4Z4 Y w xY w)Rap  A library for reading and converting SVG files.

This module provides a converter from SVG to ReportLab Graphics (RLG) drawings.
It handles basic shapes, paths, and simple text elements.

The intended usage is either as a module within other projects or from the
command-line for converting SVG files to PDF. It also supports gzip-compressed
SVG files with the .svgz extension.

Example:
    To convert an SVG file to a ReportLab Drawing object::

        from svglib.svglib import svg2rlg
        drawing = svg2rlg("foo.svg")

    To convert an SVG file to a PDF from the command-line::

        $ python -m svglib foo.svg
    N)defaultdict
namedtuple)BytesIO)AnyDictListOptionalTupleUnion)Image)
_CLOSEPATHCircleDrawingEllipseGroupr   LinePathPolygonPolyLineRect
SolidShapeString)colors)picatoLength)stringWidth)FILL_EVEN_ODDFILL_NON_ZERO)PDFImage)mmult)etree   )DEFAULT_FONT_NAMEDEFAULT_FONT_SIZEDEFAULT_FONT_STYLEDEFAULT_FONT_WEIGHTget_global_font_map)	find_font)register_font)bezier_arc_from_end_pointsconvert_quadratic_to_cubic_pathnormalise_svg_pathimagereturnc                 b    | j                   dk(  rd| j                  v r| j                  d      S | S )a  Convert a palette-based image with transparency to RGBA format.

    This function checks if a PIL Image is in palette mode ('P') and has
    transparency information. If so, it converts the image to RGBA to prevent
    potential warnings or errors during processing.

    Args:
        image: The input PIL Image object.

    Returns:
        The converted RGBA PIL Image object if changes were made, otherwise
        the original image.
    PtransparencyRGBA)modeinfoconvert)r-   s    =/home/dcms/DCMS/lib/python3.12/site-packages/svglib/svglib.py_convert_palette_to_rgbar7   Z   s/     zzS^uzz9}}V$$L    	font_name	font_pathweightstylerlgFontNamec                      t        | ||||      S )ao  Register a font for use in SVG processing.

    This function serves as a backward-compatible wrapper for the font
    registration logic defined in the `svglib.fonts` module.

    Args:
        font_name: The name of the font to register.
        font_path: The file path to the font file (optional).
        weight: The font weight (e.g., 'normal', 'bold').
        style: The font style (e.g., 'normal', 'italic').
        rlgFontName: The ReportLab-specific font name (optional).

    Returns:
        A tuple containing the registered font name and a boolean indicating
        if the registration was successful.
    )_fonts_register_font)r9   r:   r;   r<   r=   s        r6   r)   r)   n   s    .  	9fe[QQr8   c                     t        | ||      S )a  Find a registered font by its properties.

    This function serves as a backward-compatible wrapper for the font
    finding logic defined in the `svglib.fonts` module.

    Args:
        font_name: The name of the font to find.
        weight: The font weight to match.
        style: The font style to match.

    Returns:
        A tuple containing the matched font name and a boolean indicating
        if an exact match was found.
    )_fonts_find_font)r9   r;   r<   s      r6   r(   r(      s    " Ivu55r8   z$http://www.w3.org/XML/1998/namespaceBox)xywidthheightz[^ \t\r\n\f]+c                   R     e Zd ZdZdededdf fdZdededeeef   f fdZ xZ	S )NoStrokePathzA Path object that never has a stroke width.

    This class is used to create filled shapes from unclosed paths, where
    only the fill should be rendered and the stroke should be ignored.
    argskwargsr.   Nc                     |j                  dd       }t        |   |i | |r9| j                  j	                  t        j                  |j                               y y )N	copy_from)popsuper__init____dict__updatecopydeepcopy)selfrI   rJ   rL   	__class__s       r6   rO   zNoStrokePath.__init__   sN    JJ{D1	$)&)MM  y/A/A!BC r8   c                 J    t        |   |i |}d|v rd|d<   d|v rd|d<   |S )zAReturn the properties of the path, ensuring no stroke is applied.strokeWidthr   strokeColorN)rN   getProperties)rT   rI   rJ   propsrU   s       r6   rY   zNoStrokePath.getProperties   s@    %t6v6E!#$E- E!#'E- r8   )
__name__
__module____qualname____doc__r   rO   r   strrY   __classcell__rU   s   @r6   rH   rH      sM    Dc DS DT D3 # $sCx.  r8   rH   c                   B    e Zd ZdZdededdfdZdededeeef   fdZy)ClippingPathzA Path object used for defining a clipping region.

    This path will not be rendered with a fill or stroke but will be used
    as a clipping mask for other shapes.
    rI   rJ   r.   Nc                     |j                  dd       }t        j                  | g|i | |r8| j                  j	                  t        j                  |j                               d| _        y )NrL   r"   )rM   r   rO   rP   rQ   rR   rS   
isClipPath)rT   rI   rJ   rL   s       r6   rO   zClippingPath.__init__   sS    JJ{D1	d,T,V,MM  y/A/A!BCr8   c                 \    t        j                  | g|i |}d|v rd|d<   d|v rd|d<   |S )z>Return the properties of the path, ensuring no fill or stroke.	fillColorNrX   )r   rY   )rT   rI   rJ   rZ   s       r6   rY   zClippingPath.getProperties   sE    ""49$9&9%!%E+E!#'E- r8   )	r[   r\   r]   r^   r   rO   r   r_   rY    r8   r6   rc   rc      sC    c S T 3 # $sCx. r8   rc   c                        e Zd ZdZdeddfdZy)
CSSMatcherz?A CSS matcher to handle styles defined in SVG <style> elements.style_contentr.   Nc                 :   t        j                  |dd      }|D ]  }|j                  r|j                  dk(  rt	        j
                  |j                        }t        j                  |j                        }t        j                  |j                        j                  d      D ci c]I  }d|v rC|j                  d      d   j                         |j                  d      d   j                         K }}||f}|D ]  }	| j                  |	|         yc c}w )	zParse a string of CSS rules and add them to the matcher.

        Args:
            style_content: A string containing CSS rules.
        T)skip_commentsskip_whitespacezat-rule;:r   r"   N)tinycss2parse_stylesheetpreludetype
cssselect2compile_selector_list	serializecontentsplitstripadd_selector)
rT   rk   rulesrule	selectorsselector_stringattrcontent_dictpayloadselectors
             r6   
add_styleszCSSMatcher.add_styles   s
    ))t
  	5D<<499	#9"88FI&00>O %..t||<BB3G$; 

3"((*DJJsOA,>,D,D,FFL 
 '5G% 5!!(G45	5
s   (AD)r[   r\   r]   r^   r_   r   rh   r8   r6   rj   rj      s    I5 5 5r8   rj   c                       e Zd ZdZddZdee   ddfdZdede	eef   fdZ
d	ed
edefdZd	ede	eef   fdZdedefdZdedeeeeeeedf   f   f      fdZy)AttributeConverterzHAn abstract class for converting SVG attributes to ReportLab properties.r.   Nc                      d | _         d | _        y N)	css_rulesmain_boxrT   s    r6   rO   zAttributeConverter.__init__   s    /3'+r8   r   c                     || _         y)zSet the main viewbox for resolving percentage-based units.

        Args:
            main_box: A Box tuple representing the main viewbox.
        N)r   )rT   r   s     r6   set_boxzAttributeConverter.set_box   s     !r8   linec                    |j                  d      }|D cg c]  }|j                          }}|D cg c]  }t        |      dkD  s| }}i }|D ])  }|j                  d      \  }}d ||fD        \  }}|||<   + |S c c}w c c}w )zParse a compound attribute string into a dictionary.

        Args:
            line: A string of semicolon-separated style attributes.

        Returns:
            A dictionary of attribute key-value pairs.
        ro   r   rp   c              3   <   K   | ]  }|j                           y wr   )rz   ).0ss     r6   	<genexpr>z:AttributeConverter.parseMultiAttributes.<locals>.<genexpr>  s     .!AGGI.   )ry   rz   len)rT   r   attrsa	new_attrskvs          r6   parseMultiAttributesz'AttributeConverter.parseMultiAttributes  s     

3$)*q**!0qSVaZ00	 	A773<DAq.1v.DAqIaL	
  +0s   A?BBsvgNodenamec                 Z   |j                   j                  dd      s| j                  |j                  | j                         |j                   j                  d      rr| j	                  |j                   j                  d            }|j                         D ]&  \  }}|j                  d      r||j                   |<   ( d|j                   d<   |j                   j                  |d      j                         }|r|dk7  r|S |j                  | j                  |j                  |      S y)a  Find an attribute value, searching the node and its ancestors.

        The search order is:
        1. The node's own attributes.
        2. The node's 'style' attribute.
        3. The node's parent, recursively.

        Args:
            svgNode: The lxml node to start the search from.
            name: The name of the attribute to find.

        Returns:
            The attribute value, or an empty string if not found.
        __rules_appliedFr<   -1 inherit)
attribgetr   apply_rulesr   items
startswithrz   parentfindAttr)rT   r   r   r   keyval
attr_values          r6   r   zAttributeConverter.findAttr  s     ~~!!"3U;~~)##DNN3~~!!'*11'..2D2DW2MN % 2HC>>#..1s+2 5801^^''b1779
*	1>>%==66r8   c                 v   i }t        |j                               dk(  r.|j                  | j                  |j                                      |j                  j                  d      }|r"| j                  |      }|j                  |       |j                  j                         D ]  \  }}|dk7  s|||<    |S )zReturn a dictionary of all attributes of a node and its ancestors.

        Args:
            svgNode: The lxml node to get attributes from.

        Returns:
            A dictionary of all applicable attributes.
        gr<   )	node_name	getparentrQ   getAllAttributesr   r   r   r   )rT   r   dictr<   dr   values          r6   r   z#AttributeConverter.getAllAttributes>  s     W&&()S0KK--g.?.?.ABC""7+))%0AKKN!....0 	"JCg~!S		" r8   svgAttrc                     |S )z!Return the attribute value as is.rh   rT   r   s     r6   idzAttributeConverter.idW  s    r8   .c           	      D   |j                         }|dd }g }g }t        |      D ]  \  }}|dv s|j                  |        t        dt	        |      d      D ]  }||   ||dz      }	}||dz   |	 }
|
j                         }
|
j                  dd      }
t        j                  dd|
      }
	 d|
v r1|j                  t        d	 |
j                  d      D                     n|j                  t        |
             |d| d|	|z
  dz   z  z   ||	dz   d z   } |j                  dd      j                         }t	        |      t	        |      k7  rt        j                  d
|       g S g }t        |      D ]  \  }}|j                  |||   f        |S # t        $ r Y Ew xY w)a  Parse a transform attribute string into a list of operations.

        Args:
            svgAttr: The SVG transform attribute string.

        Returns:
            A list of tuples, where each tuple contains the transform
            operation and its arguments.

        Example:
            >>> converter = AttributeConverter()
            >>> converter.convertTransform("scale(2) translate(10,20)")
            [('scale', 2.0), ('translate', (10.0, 20.0))]
        Nz()r      r"   , z[ ]+c              3   2   K   | ]  }t        |        y wr   float)r   nums     r6   r   z6AttributeConverter.convertTransform.<locals>.<genexpr>}  s     (Rs(Rs   z'Unable to parse transform expression %r)rz   	enumerateappendranger   replaceresubtuplery   r   
ValueErrorloggerwarning)rT   r   r   opsbracketsindicesilinbibjsublineops_listresultops                 r6   convertTransformz#AttributeConverter.convertTransform[  s   $ }}7 9;o 	#FAsd{"	# q#h-+ 	AAa[(1q5/B26B'GmmoGooc3/GffVS'2G'>NN5(Rw}}S?Q(R#RSNN5>2 cr(SBGaK003rAvx=@C	A "kk#s399;x=CL(NNDgNIx( 	,EArMM2wqz*+	,   s   +AF	FFr.   N)r[   r\   r]   r^   rO   r	   rB   r   r_   r   r   r   r   r   r   r   r
   r   r   r   rh   r8   r6   r   r      s    R,! !$ ! c3h *" "3 "3 "H S#X 2# # 22 
eCueE3J&77889	:2r8   r   c                       e Zd ZdZ	 	 ddee   dee   ddf fdZededefd       Zed	e	de
e	   fd
       Zeddfde	dedee	   dedeee
e   f   f
dZde	de
eee
e   f      fdZde	defdZde	deee	f   fdZde	defdZde	defdZde	defdZde	de
eee
e   f      fdZde	deee
e   f   fdZ	 	 ddee	   de	de	de	fdZ xZS )Svg2RlgAttributeConverterz=A concrete attribute converter for SVG to ReportLab Graphics.Ncolor_converterfont_mapr.   c                 r    t         |           |xs | j                  | _        |xs
 t	               | _        y r   )rN   rO   identity_color_converterr   r'   	_font_map)rT   r   r   rU   s      r6   rO   z"Svg2RlgAttributeConverter.__init__  s3    
 	.O$2O2O!:%8%:r8   cc                     | S )z7A default color converter that returns the color as is.rh   )r   s    r6   r   z2Svg2RlgAttributeConverter.identity_color_converter  s	     r8   r   c                 h    t        j                  | j                         j                  dd            S )z)Split a string of attributes into a list.r   r   )shlexry   rz   r   )r   s    r6   split_attr_listz)Svg2RlgAttributeConverter.split_attr_list  s&     {{4::<//S9::r8           r   em_base	attr_namedefaultc           	         |j                  dd      j                         }|s|S d|v ro| j                  |      D cg c]  }| j                  ||||       }}g }|D ]5  }	t	        |	t
              r|j                  |	       %|j                  |	       7 |S |j                  d      r| j                  #t        j                  d       t        |dd       S |#t        j                  d       t        |dd       S |d	v r| j                  j                  }
n?|d
v r| j                  j                  }
n$t        j                  d|       t        |dd       S t        |dd       dz  |
z  S |j                  d      rt        |dd       t        z  S |j                  d      rt        |dd       S |j                  d      rt        |dd       |z  S |j                  d      rt        |dd       dz  S |j                  d      rt        |dd       |z  dz  S |j                  d      rt        |dd       |z  dz  S |j                         }t!        |      }|S c c}w )a  Convert an SVG length string to points.

        Args:
            svgAttr: The SVG length string (e.g., "10px", "5em").
            em_base: The base font size for 'em' units.
            attr_name: The name of the attribute being converted.
            default: The default value to return if the string is empty.

        Returns:
            The length in points as a float, or a list of floats for
            space-separated values.
        r   r   )r   r   r   %Nz4Unable to resolve percentage unit without a main boxz?Unable to resolve percentage unit without knowing the node name)rC   cxx1x2rE   )rD   cyy1y2rF   z.Unable to detect if node %r is width or heightd   pcptempxg      ?exr   ch)r   rz   r   convertLength
isinstancelistextendr   endswithr   r   errorr   rE   rF   r   r   )rT   r   r   r   r   textr   r   r   itemfulllengths               r6   r   z'Svg2RlgAttributeConverter.convertLength  so   & sC(..0N$;  //5	  ""Iw # E  #%F (dD)MM$'MM$'	(
 M==}}$STT#2Y'' U T#2Y''<<}}**??}}++Di T#2Y''cr#c)D00]]4 cr#d**]]4 cr##]]4 cr#g--]]4 cr#d**]]4  cr#g-11]]4  cr#g-11zz|$ks   Ic                 h    | j                  |      D cg c]  }| j                  |       c}S c c}w )z@Convert a space-separated list of lengths into a list of floats.)r   r   )rT   r   r   s      r6   convertLengthListz+Svg2RlgAttributeConverter.convertLengthList  s,    /3/C/CG/LM!""1%MMMs   /c                     t        |      S )z%Convert an opacity string to a float.r   r   s     r6   convertOpacityz(Svg2RlgAttributeConverter.convertOpacity  s    W~r8   c                 <    t         t        dj                  |d      S )z9Convert an SVG fill-rule string to a ReportLab fill rule.)nonzeroevenoddr   )r   r   r   r   s     r6   convertFillRulez)Svg2RlgAttributeConverter.convertFillRule  s"     %$
 #gr
	r8   c                    |}|r|dk(  ry|dk(  ryt        |      dv r,|d   dk(  r$t        j                  |t        |      dk(        }nt        |      d	k(  r9|d   dk(  r1t        j                  dd
|d   z  z   d
|d
   z  z   d
|d   z  z         }nt        |      dk(  rD|d   dk(  r<t        j                  dd
|d   z  z   d
|d
   z  z   d
|d   z  z   d
|d	   z  z   d      }n6t        j                  |      }|	 t	        t        |      j                         }|t        j                  d|       y| j                  |      S # t        $ r Y 5w xY w)zConvert an SVG color string to a ReportLab color object.

        Args:
            svgAttr: The SVG color string (e.g., "#FF0000", "blue").

        Returns:
            A ReportLab color object, or None if the color is invalid.
        noneNcurrentColor)   	   r   #r  )hasAlpha   r   r"         TzCan't handle color: %s)
r   r   HexColorcssParsegetattrcloneAttributeErrorr   r   r   )rT   r   r   colors       r6   convertColorz&Svg2RlgAttributeConverter.convertColor  sf    tv~>!!t947c>OOD3t9>BEY!^Q3OOC!d1g+$5DG$Ca$q'k$QREY!^Q3OOa$q'k!AQK/!d1g+=DGKE OOD)E}#FD1779E =NN3T:  ''.. & s   ;E 	EEc                     dddd|   S )z?Convert an SVG stroke-linejoin string to a ReportLab line join.r   r"   r   )miterroundbevelrh   r   s     r6   convertLineJoinz)Svg2RlgAttributeConverter.convertLineJoin+  s    Q3G<<r8   c                     dddd|   S )z=Convert an SVG stroke-linecap string to a ReportLab line cap.r   r"   r   )buttr  squarerh   r   s     r6   convertLineCapz(Svg2RlgAttributeConverter.convertLineCap/  s    A3G<<r8   c                 (    | j                  |      }|S )z<Convert an SVG stroke-dasharray string to a list of lengths.)r  )rT   r   strokeDashArrays      r6   convertDashArrayz*Svg2RlgAttributeConverter.convertDashArray3  s    009r8   c                 (    | j                  |      }|S )z4Convert an SVG stroke-dashoffset string to a length.)r   )rT   r   strokeDashOffsets      r6   convertDashOffsetz+Svg2RlgAttributeConverter.convertDashOffset8  s    --g6r8   fontAttr
weightAttr	styleAttrc                    |sy| j                  |      }g }|D ]<  }| j                  j                  |||      \  }}|r|c S |s,|j                  |       > |r|d   S t        j                  d| d| d|        t        S )aG  Convert an SVG font-family string to a registered font name.

        Args:
            fontAttr: The SVG font-family attribute string.
            weightAttr: The font-weight attribute string.
            styleAttr: The font-style attribute string.

        Returns:
            The best-matched registered font name.
        r   r   z0Unable to find a suitable font for 'font-family:z
', weight:z, style:)r   r   r(   r   r   r   r#   )rT   r,  r-  r.  
font_namesnon_exact_matchesr9   exacts           r6   convertFontFamilyz+Svg2RlgAttributeConverter.convertFontFamily=  s      ))(3
# 	4I#~~77:y Iu   !((3	4 $Q''NNB8* M$Xi[: %$r8   NNnormalr6  )r[   r\   r]   r^   r	   r   rO   staticmethodr   r_   r   r   r$   r   r   r   r  r  intr  r  r!  r%  r(  r+  r3  r`   ra   s   @r6   r   r     s   G *."&;!#; 3-; 
	; C C   ;c ;d3i ; ; +#'MM M C=	M
 M 
ud5k!	"M^N NeE4;<N6O1P Nc e s uS#X %C %C %N=s =s ==c =c = U5$u+;M5N0O 
   ud5k7I1J   #!	%%3-%% %% 	%%
 
%%r8   r   c                   l     e Zd ZdZdededdf fdZdefdZdedefd	Zdedefd
Z	deddfdZ
 xZS )NodeTrackerzA wrapper for lxml nodes to track attribute usage.

    This class wraps an lxml node and keeps a record of which attributes
    have been accessed, which is useful for debugging unused attributes.
    rI   rJ   r.   Nc                 2    t        |   |i | g | _        y r   )rN   rO   	usedAttrs)rT   rI   rJ   rU   s      r6   rO   zNodeTracker.__init__l  s    $)&)$&r8   c                 "    d| j                    dS )Nz<NodeTracker for node >)etree_elementr   s    r6   __repr__zNodeTracker.__repr__p  s    '(:(:';1==r8   r   c                     || j                   vr| j                   j                  |       | j                  j                  j	                  |d      S )z8Get an attribute value and record that it has been used.r   )r<  r   r?  r   r   rT   r   s     r6   getAttributezNodeTracker.getAttributes  s?    t~~%NN!!$'!!((,,T266r8   c                 .    t        | j                  |      S )z2Forward attribute access to the wrapped lxml node.)r  r?  rB  s     r6   __getattr__zNodeTracker.__getattr__y  s    t))400r8   r|   c                     |j                  |       }|D ]<  }|d   d   }|j                         D ]  \  }}	 || j                  j                  |<   ! > | j                  j                  dd       y# t        $ r Y Lw xY w)zApply CSS rules to the wrapped node.

        Args:
            rules: A CSSMatcher object containing the styles to apply.
        r  r"   r   r   N)matchr   r?  r   r   set)rT   r|   matchesrG  	attr_dictr   r   s          r6   r   zNodeTracker.apply_rules}  s     ++d# 	EaI&__. 	c69D&&--d3	 	0#6 " s   A00	A<;A<)r[   r\   r]   r^   r   rO   r_   r@  rC  rE  r   r`   ra   s   @r6   r:  r:  e  sg    'c 'S 'T '># >7 7 71 1 17 7 7r8   r:  c                       e Zd ZdZy)CircularRefErrorz6Exception raised for circular references in SVG files.N)r[   r\   r]   r^   rh   r8   r6   rL  rL    s    @r8   rL  c                   X    e Zd ZdZdeeej                  e   f   ddddfdZdede	fd	Z
y)
ExternalSVGz?A class to handle external SVG files referenced via xlink:href.pathrendererSvgRendererr.   Nc                     t        |      | _        t        ||j                  t	        |j
                        gz         | _        d| _        y )N)parent_svgsF)load_svg_file	root_noderQ  _parent_chainr_   source_pathrP  rendered)rT   rO  rP  s      r6   rO   zExternalSVG.__init__  sC    
 't,#h44H<P<P8Q7RR
 r8   fragmentc                     | j                   s,| j                  j                  | j                         d| _         | j                  j                  j                  |      S )zGet a defined fragment from the external SVG file.

        Args:
            fragment: The ID of the fragment to retrieve.

        Returns:
            The rendered fragment, or None if not found.
        T)rX  rP  renderrU  definitionsr   )rT   rY  s     r6   get_fragmentzExternalSVG.get_fragment  sC     }}MM  0 DM}}((,,X66r8   )r[   r\   r]   r^   r   r_   osPathLikerO   r   r]  rh   r8   r6   rN  rN    sL    I	CS))*	  	 
		7S 7S 7r8   rN  c                      e Zd ZdZ	 	 	 ddeeej                  e   f   dee	   dee
e      dee	   ddf
dZd	e	defd
Zd dedee	   ddfdZdedee	   fdZdeddfdZdede	ddfdZd dedee	   de	fdZdeddfdZdeddfdZd!d	ededefdZd!dedede	fdZd dedee	   de	fdZdeddfdZdede	fdZdede	fdZ	 	 d"dedee	   dee	   de	fdZy)#rQ  zA class to render an SVG file into a ReportLab Drawing.

    This class walks the SVG DOM and converts SVG elements into their
    corresponding ReportLab Graphics objects.
    NrO  r   rS  r   r.   c                 6   || _         |xs g | _        t        ||      | _        t	        || j                        | _        | j
                  j                         | _        i | _        t        t              | _        i | _        t               | j                  _        y )N)r   r   )rW  rV  r   attrConverterSvg2RlgShapeConvertershape_converterget_handled_shapeshandled_shapesr\  r   r   waiting_use_nodes_external_svgsrj   r   )rT   rO  r   rS  r   s        r6   rO   zSvgRenderer.__init__  s     :>(3(9r6+h
  5T4;M;MN"22EEG+- 	 79'1|$r8   svg_nodec                 4   t         j                  |      }| j                  |d      }| j                  j	                  |       | j                  |d      }| j                  j                         D ]  }t        j                  d|        |j                  d|j                  z
  |j                   |j                  z
         | j                  j                  |dd|j                   |j                  f      \  }}t#        ||      }|j%                  |       |S )	zRender an SVG node into a ReportLab Drawing.

        Args:
            svg_node: The root lxml node of the SVG document.

        Returns:
            A ReportLab Drawing object representing the SVG.
        Tdefault_box)	outermostz(Ignoring unavailable object width ID %r.r   rE   rF   defaults)r:  from_xml_rootget_boxrb  r   	renderSvgrg  keysr   debug	translaterC   rF   rD   rd  convert_length_attrsrE   r   add)	rT   ri  nodeview_box
main_groupxlinkrE   rF   drawings	            r6   r[  zSvgRenderer.render  s     ((2<<$<7""8,^^DD^9
++002 	LELLCUK	L 	Q^hoo-=

-JK,,AAgx8>>8??2S B 
v %(Jr8   rx  r   c                    |y|j                  d      }d}d}t        |      }| j                  |      }|dk(  r$| j                  |      }|j	                  |       n|dk(  rd}n|dk(  r$| j                  |      }|j	                  |       n|dk(  r=|j                  d	      }| j                  ||
      }|dk7  r|j	                  |       n|dk(  r| j                  |       n||dk(  rS| j                  |      }|j                  j                  d      r|j	                  |       n8|j                  dd       n$|dk(  r%| j                  ||
      }|j	                  |       n|dk(  r| j                  |      }n|| j                  v r|dk(  rq| j                  |      }	|	yt        |	t               rFt#               }
|	\  }}|j%                  ||
       | j'                  ||
       |j	                  |
       y|	|_        | j*                  j-                  |||      }|j                  d	      }|r/|dk7  r*|j	                  |       nd}t.        j1                  d|       |s|rz|rx|| j2                  |<   |j5                  d|i       |j                  j7                         D cg c]  \  }}d|v s| }}}t9        |      dk(  r|\  }|j5                  d|i       || j:                  j=                         v r8| j:                  j?                  |      }|D ]  \  }}| j                  ||        | jA                  |       yyc c}}w )zRender a single SVG node and add it to a parent group.

        Args:
            node: The NodeTracker object for the SVG node.
            parent: The parent ReportLab Group to add the rendered object to.
        Nr   FsvgdefsTr   r   display)clippingr  r<   symbol	_renderedr   useclipPathr-   r   zIgnoring node: %ssvgidlabelr"   group)!rC  r   get_clippathrr  rw  renderArenderGrenderStylerenderSymbolr   r   rH  	renderUserf  xlink_href_targetr   r   r   
renderNodeapply_node_attr_to_group_resolved_targetrd  convertShaper   rt  r\  setPropertiesr   r   rg  rs  rM   print_unused_attributes)rT   rx  r   nidignoredr  r   r  r  targetgrrP  img_noder   r   label_attrsr  	to_renderuse_noder  s                       r6   r  zSvgRenderer.renderNode  s    >%$$T*5=>>$'DJJtV^GS[<<%DJJtS[''	2G<<x<8D& 

4 W_T"X$$T*D {{{+

4 c*U]>>$>:DJJtZ<<%DT(((w //5>.B)/&Hh'''<11$;JJrN -3D)''44T4JD''	2G6)

4 GLL,d3t(,  % ""GS>2 .2[[->->-@QTQGqLqQQ{#q(*HU&&'78d,,1133 2266s;	'0 :OHeNN85N9:((.#  Rs   +M8Mc                      dt         dt        t            ffddt         dt        t            f fd|j                  d      }|syt        j                  d|      }|sy|j                         d	   }| j                  vrt        j                  d
|       y  j                  |         }t        |t              r|j                         \  }}}}	t               }
|
j                  ||       |
j                  ||       |
j                  ||	       |
j                  ||	       |
j                          t!        ||
       |
S t        |t"              rt        |      S |r*t        j%                  d|j&                  j(                         y)zGet the clipping path object referenced by a node's 'clip-path' attribute.

        Args:
            node: The NodeTracker object for the SVG node.

        Returns:
            A ClippingPath object, or None if no valid clipping path is found.
        r  r.   c                     | j                   D ]0  }t        |t              r
 |      c S t        |t              s.|c S  y r   )contentsr   r   r   )r  elemget_shape_from_groups     r6   r  z6SvgRenderer.get_clippath.<locals>.get_shape_from_groupO  s?      dE*/55j1K	 
 r8   rx  c                 `   | j                         D ]  }t        |      dk(  r-j                  j                  d|      }|j                  d   c S t        |      dk(  rj                  |      } |      c S t        |      dk(  rj                  j                  |      c S  |      c S  y )NrO  r   r  rect)iter_childrenr   rd  r  r  r  convertRect)rx  childr  grpr  get_shape_from_noderT   s       r6   r  z5SvgRenderer.get_clippath.<locals>.get_shape_from_nodeW  s    ++- 
6U#v- 00==feLE >>"--u%.../C/44u%///;;EBB.u55
6 r8   z	clip-pathNzurl\(#([^)]*)\)r   z)Unable to find a clipping path with id %srL   z&Unsupported shape type %s for clipping)r   r	   rC  r   rG  groupsr\  r   r   r   r   	getBoundsrc   moveTolineTo	closePathcopy_shape_propertiesr   r   rU   r[   )rT   rx  	clip_pathmrefshaper   r   r   r   cpr  r  s   `          @@r6   r  zSvgRenderer.get_clippathE  sS   	 	 		c 	hsm 	 %%k2	HH'3hhjmd&&&NNFL#D$4$4S$9:eT" #__.NBBBIIb"IIb"IIb"IIb"LLN!%,It$%00LL8%//:R:R r8   c                 :   t         j                  t        j                  kD  ry| j                  j                  |j                        j                         }|D cg c]  }||j                  vs| }}|r!t         j                  dt        |      |       yyc c}w )zPrint any attributes that were not used during rendering.

        This is a debugging helper to identify unsupported SVG attributes.

        Args:
            node: The NodeTracker object for the SVG node.
        NzUnused attrs: %s %s)r   levelloggingDEBUGrb  r   r?  rs  r<  rt  r   )rT   rx  	all_attrsr   unused_attrss        r6   r  z#SvgRenderer.print_unused_attributes  s}     <<'--'&&778J8JKPPR	)2Qd$..6PQQLL.	$N  Rs   B.Br  c                     |j                   }t        |d      \  }}}|s|r|d|xs d d|xs d dz  }|r| j                  j                  ||       yy)zApply common attributes (transform, x, y) from a node to a group.

        Args:
            node: The NodeTracker object for the SVG node.
            group: The ReportLab Group to apply the attributes to.
        )	transformrC   rD   z translate(r   z, )N)rC  maprd  applyTransformOnGroup)rT   rx  r  getAttrr  rC   rD   s          r6   r  z$SvgRenderer.apply_node_attr_to_group  sf     ##g'>?	1a;qvAhba::I  66y%H r8   c                    |j                   j                  d      xs |j                   j                  d      }|syt        j                  d|      }|ret	        j
                  ||j                  d      d   dz   d j                  d            }t        |      }t        t        j                  |            S d|v r|j                  dd      \  }}n|d}}|rt        | j                  t              st         j#                  d	|       yt$        j&                  j)                  t$        j&                  j+                  t$        j&                  j-                  | j                        |            }	t%        j.                  |	t$        j0                        sy|	| j                  k(  rd}|r	j3                  d
      r|	| j4                  v rt         j#                  d       t7               |	| j8                  vrt;        |	|       | j8                  |	<   | j8                  |	   }
|
j<                  _|r!|
j?                  |      }|I|
j@                  |fS |
j@                  tB        jE                  |
j<                        fS 	 tG        |	dd       |	S yy|rE|| jJ                  v r| | jJ                  |   fS | jL                  |   jO                  ||f       tP        S y# tH        $ r t         j#                  d|	       Y yw xY w)a  Resolve an xlink:href attribute to its target.

        The target can be an internal fragment, an external SVG file, or a
        raster image.

        Args:
            node: The NodeTracker object for the SVG node with the href attribute.
            group: The parent group, used for delayed rendering.

        Returns:
            - A tuple (renderer, node) for vector targets.
            - A PIL Image object for raster images.
            - None if the target cannot be resolved.
        z"{http://www.w3.org/1999/xlink}hrefhrefNz^data:image/(jpe?g|png);base64r   r"   asciir  zLUnable to resolve image path %r as the SVG source is not a file system path.z.svgz$Circular reference detected in file.z(Unable to read the image %s. Skipping...))r   r   r   rG  base64decodebytesspanencoder   r7   PILImageopenry   r   rW  r_   r   r   r^  rO  normpathjoindirnameaccessR_OKr   rV  rL  rh  rN  rU  r]  rP  r:  rp  r   OSErrorr\  rg  r   DELAYED)rT   rx  r  
xlink_hrefrG  
image_databytes_streamirirY  rO  ext_svgext_frags               r6   r  zSvgRenderer.xlink_href_target  s     [[__0
 %[[__V$ 	  :JG++EJJqM!,q034;;GDJ #:.L+HMM,,GHH *&,,S!4MC&Cd..4*
 77##RWW__T-=-=>DD 99T277+t'''}}V$4---LL!GH*,,t2220;D$0GD''---d3$$0#*#7#7#A#/#*#3#3X#==&//1J1J#--2   
 T1a(  0 1& 4+++T--h777 &&x077uF    LL!KTR s   5K K0/K0c                      y)z/Handle the <title> element (currently a no-op).Nrh   rT   rx  s     r6   renderTitle_zSvgRenderer.renderTitle_       r8   c                      y)z.Handle the <desc> element (currently a no-op).Nrh   r  s     r6   renderDesc_zSvgRenderer.renderDesc_  r  r8   rl  c                 &   |j                  d      }|r#| j                  j                  |      }t        | S |rLt	        |j                   d      \  }}t	        | j                  j
                  ||f      \  }}t        dd||      S t        dddd      S )a  Get the viewBox or dimensions of an SVG node.

        Args:
            svg_node: The NodeTracker for the SVG node.
            default_box: If True, use width/height as a fallback.

        Returns:
            A Box tuple representing the dimensions.
        viewBox)rE   rF   r   )rC  rb  r  rB   r  r   )rT   ri  rl  ry  rE   rF   s         r6   rq  zSvgRenderer.get_box  s     ((3));;HEH>! 5 57JKME6 2 2 @ @5&/RME6q!UF++1aAr8   rm  c                 4   | j                   j                  }|j                  dt         d      dk(  | j                   _        | j	                  |d      }| j
                  j                  }|r| j
                  j                  |       |j                  j                  d      }|j                         D ]+  }|j                  |rd| dndk(  s| j                  |       - t               }|j                         D ]  }	| j                  |	|        || j                   _        | j
                  j                  |       |s>| j                   j!                  |d	d
      \  }
}|
s|r|j#                  |
xs d|xs d       |s|r|j%                  dd       |S |rd\  }}| j                   j!                  |ddd      \  }}||j&                  |k7  r||j&                  z  }||j(                  |k7  r||j(                  z  }|j%                  |||rdndz         |S )a  Render an <svg> element into a ReportLab Group.

        Args:
            node: The NodeTracker for the <svg> element.
            outermost: True if this is the root <svg> element.

        Returns:
            A ReportLab Group containing the rendered content.
        {}spacepreserveTrk  Nz}defsr  rC   rD   r   r"   r   )r"   r"   rE   rF   r4  rn  )rd  preserve_spacerC  XML_NSrq  rb  r   r   nsmapr   iter_subtreetagr  r   r  r  rv  ru  scalerF   rE   )rT   rx  rm  _saved_preserve_spacery  
_saved_boxsvg_nsdef_noder  r  rC   rD   x_scaley_scalerE   rF   s                   r6   rr  zSvgRenderer.renderSvg  s    !% 4 4 C C6('23zA 	+ <<$<7''00
&&x0 %))+ 	'H||v"VHF 36JX&	' '') 	*EOOE5)	*.C+"":. ''<<T3LDAqAQQ/ IKK2  #GW 00EEgx+ F ME6 !hoo&? 8??2 X^^u%<(..0KK)B!CDr8   r  c                    |j                   }t        |d      \  }}t               }|r|j                  |       |j	                         D ]  }| j                  ||        |r| j                  j                  ||       |S )a  Render a <g> element into a ReportLab Group.

        Args:
            node: The NodeTracker for the <g> element.
            clipping: An optional clipping path to apply.

        Returns:
            A ReportLab Group containing the rendered content.
        )r   r  r  )rC  r  r   rw  r  r  rd  r  )rT   rx  r  r  r   r  r  r  s           r6   r  zSvgRenderer.renderGR  s~     ##G%89IWFF8'') 	.EOOE"O-	.   66y"E	r8   c                     | j                   j                  4| j                   j                  j                  |j                  xs d       yy)zBRender a <style> element by adding its content to the CSS matcher.Nr   )rb  r   r   r   r  s     r6   r  zSvgRenderer.renderStylei  s;    ''3((33DIIOD 4r8   c                 $    | j                  |      S )z/Render a <symbol> element as a ReportLab Group.r  r  s     r6   r  zSvgRenderer.renderSymboln      ||D!!r8   c                 $    | j                  |      S )z@Render an <a> element as a ReportLab Group (no linking support).r  r  s     r6   r  zSvgRenderer.renderAr  r  r8   c                 Z   |
t               }	 | j                  ||      }|yt        |t              rt        j                  d       y|t        u r|S |d   }|r|j                  |       t        |j                               dk(  r$|j                  t        j                   |             | j#                  t%        |j'                               d   |       | j)                  ||       |S # t        $ r4 |j                  j                  j                  |j                         |cY S w xY w)aD  Render a <use> element by cloning a defined element.

        Args:
            node: The NodeTracker for the <use> element.
            group: The parent group to render into.
            clipping: An optional clipping path to apply.

        Returns:
            A ReportLab Group containing the rendered content.
        Nr  z/<use> nodes cannot reference bitmap image filesr"   r   r   r  )r   r  rL  r   r?  remover   r_   r   r   r  rw  r   getchildrenr   rR   rS   r  r   r  r  )rT   rx  r  r  r  s        r6   r  zSvgRenderer.renderUsev  s     =GE	))$e)<D <c"LLJKW_L7DIIht!"a' KKd+,T//1226uE%%dE2+   	KK%%,,T-?-?@L	s   C- -:D*)D*)NNNr   Fr4  )r[   r\   r]   r^   r   r_   r^  r_  r	   r   r   rO   r   r[  r:  r  r  r  r  r  r  r  boolrB   rq  rr  r  r  r  r  r  rh   r8   r6   rQ  rQ    s    *.+/"&4CS))*4 "#4 d3i(	4
 3-4 
4*s w 6W/{ W/HSM W/T W/r? ?# ?BOK OD OI[ I I I[k [(3- [SV [z     $ 3 (4k 4d 4s 4lK 8C= C .E E E
" " ""K "C "  $"&	++ }+ 3-	+
 
+r8   rQ  c                   n    e Zd ZdZ	 ddeeej                  e   f   dee	   ddfdZ
edee   fd       Zy)	SvgShapeConverterzAn abstract class for converting SVG shapes to another format.

    Subclasses should implement `convertX` methods for each SVG shape `X`
    (e.g., `convertRect`, `convertCircle`).
    NrO  rb  r.   c                 F    |xs
 t               | _        || _        d| _        y )NF)r   rb  svg_source_filer  )rT   rO  rb  s      r6   rO   zSvgShapeConverter.__init__  s%    
 +I.G.I##r8   c                     t        |       D cg c]'  }|j                  d      s|dd j                         ) c}S c c}w )z@Return a list of SVG shape names that this converter can handle.r5   r  N)dirr   lower)clsr   s     r6   re  z$SvgShapeConverter.get_handled_shapes  s3     ,/s8QCs~~i7PABQQQs   ==r   )r[   r\   r]   r^   r   r_   r^  r_  r	   r   rO   classmethodr   re  rh   r8   r6   r  r    si     >B$CS))*$   9:$ 
	$ R49 R Rr8   r  c                   0   e Zd ZdZddededee   defdZedded	ed
e	dede
e	   f
dZdedefdZdedee   fdZdedefdZdedefdZdedee   fdZdedee   fdZdedefdZdedee   fdZdedefdZdededdfdZ	 ddedededdfdZy)rc  z?A class for converting SVG shapes to ReportLab Graphics shapes.Nr   rx  r  r.   c                 4   d|j                          } t        | |      |      }|sy|dvr| j                  ||       |j                  d      }|s|s|S t	               }|r| j                  ||       |r|j                  |       |j                  |       |S )a  Convert an SVG shape by calling the appropriate `convertX` method.

        Args:
            name: The name of the SVG shape (e.g., "rect", "circle").
            node: The lxml node for the shape.
            clipping: An optional clipping path to apply.

        Returns:
            A ReportLab shape object, or a Group if transforms or clipping
            are applied.
        r5   N)rO  polyliner   r  )
capitalizer  applyStyleOnShaperC  r   r  rw  )rT   r   rx  r  method_namer  r  r  s           r6   r  z"Svg2RlgShapeConverter.convertShape  s       123*k*4033""5$/%%k2	XLGE**9e<		(#IIeLr8   r   r   r   rJ   c          
         t        d      rj                  nfd}| j                  j                  }|j	                  ddt        |      z        }t        ||      D 	cg c]  \  }}	 | ||      |||	       c}	}S c c}	}w )ad  Convert a list of length attributes from a node.

        Args:
            node: The lxml node.
            *attrs: The names of the attributes to convert.
            em_base: The base font size for 'em' units.
            **kwargs: Can include 'defaults' for fallback values.

        Returns:
            A list of converted lengths in points.
        rC  c                 <    j                   j                  | d      S Nr   )r   r   )r   rx  s    r6   <lambda>z<Svg2RlgShapeConverter.convert_length_attrs.<locals>.<lambda>  s    dkkoodB7 r8   ro  )r   )r   r   r   )hasattrrC  rb  r   r   r   zip)
rT   rx  r   r   rJ   r  
convLengthro  r   r   s
    `        r6   rv  z*Svg2RlgShapeConverter.convert_length_attrs  s    ( t^, 7 	
 ''55
::j&3u:*=> "%UH!5
g wt}gwW
 	
 
s   "Bc                 R    | j                  |dddd      }t        |       t        | S )z2Convert an SVG <line> element to a ReportLab Line.r   r   r   r   )rv  nudge_pointsr   )rT   rx  pointss      r6   convertLinez!Svg2RlgShapeConverter.convertLine  s,    **4tT4HVV}r8   c           	          | j                  |dddddd      \  }}}}}}||dz  kD  r|dz  }||dz  kD  r|dz  }|r|s|}n|r|s|}t        ||||||      S )	z2Convert an SVG <rect> element to a ReportLab Rect.rC   rD   rE   rF   rxryr   )r  r  )rv  r   )rT   rx  rC   rD   rE   rF   r  r  s           r6   r  z!Svg2RlgShapeConverter.convertRect   s    &*&?&?#sGXtT'
#1eVR B!!BbBBAq%B266r8   c                 L    | j                  |ddd      \  }}}t        |||      S )z6Convert an SVG <circle> element to a ReportLab Circle.r   r   r)rv  r   )rT   rx  r   r   r  s        r6   convertCirclez#Svg2RlgShapeConverter.convertCircle  s-    --dD$D	Bb"a  r8   c                 Z    | j                  |dddd      \  }}}}||}}t        ||||      S )z8Convert an SVG <ellipse> element to a ReportLab Ellipse.r   r   r  r  )rv  r   )rT   rx  r   r   r  r  rE   rF   s           r6   convertEllipsez$Svg2RlgShapeConverter.convertEllipse  s<    224tT4PBBBvr2uf--r8   c                 2   |j                  d      }|j                  dd      }|j                         }t        t	        | j
                  j                  |            }t        |      dz  dk7  st        |      dk(  ryt        |       t        |      }| j                  ||       | j
                  j                  |d      dv}|rRt               }t        |      }| j                  ||       d|_        |j                  |       |j                  |       |S |S )	z:Convert an SVG <polyline> element to a ReportLab PolyLine.r  r   r   r   r   Nfill)r   r  )rC  r   ry   r   r  rb  r   r   r  r   r
  r   r   r   rX   rw  )rT   rx  r  r  has_fillr  polygons          r6   convertPolylinez%Svg2RlgShapeConverter.convertPolyline  s    ""8,S)c$,,::FCDv;?a3v;!#3VF#x.%%..tV<LP GEfoG""7D1"&GIIgIIhLr8   c                 *   |j                  d      }|j                  dd      }|j                         }t        t	        | j
                  j                  |            }t        |      dz  dk7  st        |      dk(  ryt        |       t        |      }|S )z8Convert an SVG <polygon> element to a ReportLab Polygon.r  r   r   r   r   N)
rC  r   ry   r   r  rb  r   r   r  r   )rT   rx  r  r  s       r6   convertPolygonz$Svg2RlgShapeConverter.convertPolygon6  s~    ""8,S)c$,,::FCDv;?a3v;!#3Vr8   c           	         | j                   }|j                  dt         d      }|r|dk(  }n| j                  }t	               }g }d}d}d}	d}
|j                  |d      xs t        }|j                  |d      xs t        }|j                  |d      xs t        }|j                  |||      }|j                  |d      xs t        t              }|j                  |      }| j                  |d	d
|      \  }}t        ||      D ]  \  }}}|sd\  }}d}d}d}|s| j                  |d	d
dd|      \  }	}
}}|j                  j!                  d	d      dk7  |j                  j!                  d
d      dk7  }}|t#        |t$              r|d   n|z   }|t#        |t$              r|d   n|z   }|j                  j!                  dd      }|dv r| dz  |dz  dd|   }n|j                  ||      }|j'                  t)        |||             t+        d |	|
||fD              r.|rt#        |	t$              r|	n|	g}n||z   t-        |dd       z   g}|rt#        |
t$              r|
n|
g}n||z   g}t#        |t$              r|n|g}t#        |t$              r|n|g}|d   |d   d}}}t/        j0                  |||||      D ]  \  } }!}"}#}$|$ |"d}"|#d}#|"| |t)        |||      z   n| z   }%|#|!|n|!z   }&t3        |%|&|z
   |$      }'| j5                  |'|       t7        |      dk(  r| j5                  |'|       |j9                  |'       |%}|&}|$} K|r|	|z   n||z   t-        |dd       z   }%|r|
|z   n||z   }&t3        |%|&|z
   |      }'| j5                  |'|       t7        |      dk(  r| j5                  |'|       |j9                  |'        |j;                  dd       |S )z>Convert an SVG <text> element to a ReportLab Group of Strings.r  r  r  r   font-familyfont-weight
font-style	font-sizerC   rD   r  FFdxdyr   zbaseline-shift0)r   rN   baseliner   c              3   <   K   | ]  }t        |t                y wr   )r   r   )r   r   s     r6   r   z4Svg2RlgShapeConverter.convertText.<locals>.<genexpr>  s     ES:c4(Er   Nr   tspanr"   )rb  rC  r  r  r   r   r#   r&   r%   r3  r_   r$   r   rv  iter_text_noder   r   r   r   r   r   anysum	itertoolszip_longestr   r
  r   rw  r  )(rT   rx  attrConv	xml_spacer  r  frag_lengthsdx0dy0r   r   fffwfstylefsrC   rD   subnoder   is_tailhas_xhas_yr-  r.  baseLineShiftxlistylistdxlistdylistlast_xlast_y	last_charchar_xchar_ychar_dxchar_dycharnew_xnew_yr  s(                                           r6   convertTextz!Svg2RlgShapeConverter.convertTextD  so   %%%%6('&:;	&*4N!00NW$&()()t]3H7Ht]3J7J""46L:L''B7t[1KS9J5K##B' ((sC(D1&4T>&J L	"GT7'LE5,-B,-B/0M!%!:!: "; "BB NN&&sB/25NN&&sB/25  jT&:RUCjT&:RUC#NN../?EM <<)+a"q&a P!! !) 6 6}b 6 QD"b 9: ERR4DEE",R"6BRDEWs<+<'==>E",R"6BRDEWIE)"d3")"d3",1!HeAh	>G>S>S5&&$? %:FFGWd |"#"##!> YB!??#E
 $vVLE"5EM,A*BDIE**5$7 )W4..ug>FF5M"F"F $I-%0 &+bS3|CR?P;Q1Q%*bSu(=&>E&&ud3W%0**5':uYL	\ 	B	r8   c                    |j                  d      }|syt        |      }t               }|j                  }g }g }d}d}	t	        dt        |      d      D ]4  }
||
|
dz    \  }}|dv r?|
dkD  r:|j                  d   t        k7  r$|j                  t        |j                               |dk(  r |j                  |  |d	d }n|d
k(  r |j                  |  n|dk(  rYt        |      dk\  r5|dv r|}n|d	d }|d   |d   z   |d   |d   z   }}|j                  ||       n |j                  |  |d	d }nL|dk(  r*|d	   |d   z   |d   |d   z   }}|j                  ||       n|dk(  r|j                  |d   |d          n|dk(  r|j                  |d	   |d          n|dk(  r |j                  |d	   |d   z   |d          n|dk(  r |j                  |d	   |d   |d   z          n|dk(  r |j                  |  n|dk(  rY|\  }}}}t        |      dk  s|dvr|d	d dz  \  }}}}n
|dd \  }}}}|||z
  z   |||z
  z   }}|j                  ||||||       n!|dk(  r;|d	d \  }}|\  }}}}}}|j                  ||z   ||z   ||z   ||z   ||z   ||z          n|dk(  re|\  }}}}t        |      dk  s|dvr|d	d dz  \  }}}}n
|dd \  }}}}|||z
  z   |||z
  z   }}|j                  ||||z   ||z   ||z   ||z          nw|dk(  rO|d	d \  }}|\  }}}}||f}	t        ||f||f||f      \  \  }}\  }}\  }}\  }}|j                  ||||||       n#|dk(  rm|	|	\  }}n|d	d \  }}|d	d \  }}|||z
  z   |||z
  z   }}||f}	|\  }}t        ||f||f||f      \  \  }}\  }}\  }}\  }}|j                  ||||||       n|dk(  rf|d	d \  }}|\  }}}}||z   ||z   ||z   ||z   f\  }}}}||f}	t        ||f||f||f      \  \  }}\  }}\  }}\  }}|j                  ||||||       nF|dk(  rv|	|	\  }}n|d	d \  }}|d	d \  }}|\  }}||z   ||z   }}|||z
  z   |||z
  z   }}||f}	t        ||f||f||f      \  \  }}\  }}\  }}\  }}|j                  ||||||       n|dv r|\  }}}}}}}|d	d \  }}|dk(  r
||z  }||z  }t        |      d k  st        |      d k  r|j                  ||       nwt        |||||t        |      t        |      ||	      } | D ]!  \  }}}}}}}}|j                  ||||||       # n+|dv r|j!                          nt"        j%                  d!|       |d"vrd}	|}7 t'               }!| j)                  ||       |j                  d   t        k7  r$|j                  t        |j                               |r`|j*                  Tt-        |#      }"t/        |      D ]"  }#|"j                  j1                  |#t               $ |!j3                  |"       d|_        |!j3                  |       |!S )$z2Convert an SVG <path> element to a ReportLab Path.r   Nr   r   r   )r  Mr   rV  r   Lr  )Zzr"   lHVhr   CSr  >   r^  r_  r   r   r   r   QTqt)Ar   r   g|=zSuspicious path operator: %s)ra  rc  rb  rd  r  )r   r,   r   r  r   r   	operatorsr   r   r  r  curveTor+   absr*   r8  r  r   rt  r   r
  rg   rH   reversedinsertrw  )$rT   rx  r   normPathrO  r  unclosed_subpath_pointerssubpath_startlastoplast_quadratic_cpr   r   numsstarting_pointxnynr   r   xpypx0y0xiyir   r   _r  r  phifAfSbpr  closed_pathpointers$                                       r6   convertPathz!Svg2RlgShapeConverter.convertPath  s   HHSM%a(v/1!%';?q#h-+ V	A  AE*HBZAEdnnR.@J.N)00T^^1DE SyT" &rssT" sv;!#+)6)/+A.a8.:KdSTg:UBKKB'DKK& &rssd1g-vbzDG/CBB# sDGVBZ0sF2JQ0 sF2Ja0&*=sF2Jr
T!W(<= sd#s!%BBv;?f4H&H%+BC[1_NBB%+BC[NBBrBwrBwBRRR4 sB)-&BBBR"Wb2grBwRb"r'Rs!%BBv;?f4H&H%+BC[1_NBB%+BC[NBBrBwrBwBRR"Wb2grBwRH sB!%BB%'H!5THr2hR62AR(2rFQ RRR4s$0.FB#BC[FBBrBwrBwB%'H!B 4RHr2hRQQRRQRRR4 sB!%BB!#b"r'27BG!CBB%'H!5THr2hR62AR(2rFQ RRR4s$0.FB#BC[FBBBb"r'BrBwrBwB%'H! 4RHr2hRQQRRQRRR4 z!.2+BRRB9"HB"HBr7e#s2w%'7KKB'3BBSWc"gr2B 9; =41b"b"b"RRR<= z!  ;R@--$(!FmV	p WtT*>>"+%,,S-@A$)C '6K#$=> B%%,,WjABFF;!DN
t	r8   c                 (   | j                  |dddd      \  }}}}|j                  }t        t        |      t        ||z         t        |      t        |      |      }t	        |      }|j                  d||z   dz         |j                  dd       |S )	z4Convert an SVG <image> element to a ReportLab Image.rC   rD   rE   rF   r   r   r"   r   )rv  r  r   r8  r   ru  r  )rT   rx  rC   rD   rE   rF   r-   r  s           r6   convertImagez"Svg2RlgShapeConverter.convertImagei  s    "77#sGX
1eV %%c!fc!f*os5z3v;NeAJ!+,Arr8   r  r  c                    | j                   j                  |      }|D ]X  \  }}|dk(  r$t        |t              s||f} |j                  |  0|dk(  r*t        |t
        t        f      r|df} |j                  |  _|dk(  r}t        |t              rt        |      dk(  r|j                  |       t        |      dk(  s|\  }}}|j                  ||       |j                  |       |j                  | |        |dk(  r|j                  |d       |dk(  r|j                  d|       |d	k(  r+t        |      d
k(  rt        |j                  |      |_        Bt        j                  d||       [ y)zApply an SVG transformation to a ReportLab Group.

        Args:
            transform: The SVG transform attribute string.
            group: The ReportLab Group to apply the transform to.
        r  ru  r   rotater"   r  skewXskewYmatrix   zIgnoring transform: %s %sN)rb  r   r   r   r  r8  r   ru  r   r  skewr    r  r   rt  )	rT   r  r  trr   valuesangler   r   s	            r6   r  z+Svg2RlgShapeConverter.applyTransformOnGroupv  sQ    00; 	FJBW}!&%0$f-FV${"fsEl3 $QYF(x!&%0CK14DLL([A%$*ME2rOOB+LL'OORC"-w

61%w

1f%xCK1$4"'"@8"fE5	Fr8   r  only_explicitc                 X   	 dgdddgfdgdddgfd	gd
ddgfdgdddgfdgdddgfdgdddgfdgdddgfdgdddgfdgdddgff	}g d d!d"t         t        t        gfd#gd$dt        t              gfd%gd&d'd(gff}|j
                  t        k(  r&|j                  D ]  }| j                  |||)        y*| j                  }||fD ]l  }|j
                  t        k7  r||k(  r|D ]J  \  }	}
}}g }t        |	      D ]  \  }}|j                  ||      }|d+k(  r|r!|dk(  r>t        |dd*      1t        |j                  d,d      dk7  r|j                  j                  }nH|dk(  r>t        |dd*      1t        |j                   d,d      dk7  r|j                   j                  }n||   }|d-k(  r#|j                  |j"                  d.      xs ||   }t%        |t              r |j'                  d/d+      j)                         }|j+                  |        	 t        ||      }t-        ||
 ||        M o t        |dd*      '|j                  r|j8                  |j                  _        t        |dd*      d1k(  rd*|_        y*y*# t.        t0        t2        f$ r t4        j7                  d0       Y w xY w)2a  Apply styles from an SVG node to a ReportLab shape.

        Args:
            shape: The ReportLab shape to apply styles to.
            node: The lxml node to get style attributes from.
            only_explicit: If True, only apply explicitly defined attributes.
        r!  rg   r  blackzfill-opacityfillOpacityr  r"   z	fill-rule	_fillRuler  r	  strokerX   r  zstroke-widthrW   r   r   zstroke-opacitystrokeOpacityzstroke-linejoinstrokeLineJoinr!  r/  zstroke-linecapstrokeLineCapr%  zstroke-dasharrayr'  r(  )r(  r)  r*  fontNamer3  r+  fontSizeztext-anchor
textAnchorr   start)r  Nr   alphar  r  z
!importantz"Exception during applyStyleOnShaper   )r#   r&   r%   r_   r$   rU   r   r  r
  rb  r   r   r   r  rg   r  rX   r   r   r   rz   r   setattrr  KeyErrorr   r   rt  r  )rT   r  rx  r  mappingNmappingFsubshapeacmappingsvgAttrNamesrlgAttrfuncro  svgAttrValuesindexsvgAttrNamesvgAttrValuemeths                     r6   r
  z'Svg2RlgShapeConverter.applyStyleOnShape  s8    	L X{NWI>}.>D]K):YKHZA}ouE2BQCH "24EuM2BSEJ !#46H6(S

 =#"$79KL	 ]J#>O:P9QR_lD7)<	
 ??e#!NN T&&x]&ST (+ #	GG&(W-@9@  G5gtX "*3L*A 7&E;#%;;t[#AL#r)($'>9 '{D A M '! D I+0??+@+@L'+;; '}d C O '(9(97A F! K+0+<+<+B+BL+3E?L#~5KKW=P% % ",4'3';';L"'M'S'S'U!((6374G"2t,DE7D-,@A= G#	GH 5-.:u$)$5$5EOO!5-.!3 !%E 4	 '*= GLL!EFGs   I<<)J)(J)r   r  )r[   r\   r]   r^   r_   r   r	   r  r$   r   r   rv  r   r  r   r  r   r  r   r  r$  r   r&  rT  r  r  r  r  r
  rh   r8   r6   rc  rc    s   I C 8C= TW F +	

 
 	

 
 
e
<  7 7 7!# !& !
.3 .7 .C HSM 83 8G+< j j jXw w wr  "Fs "F3 "F4 "FP $	[%[% [% 	[%
 
[%r8   rc  rO  resolve_entitiesrJ   c                 :   t        | t        j                        rt        |       } d}t        | t              rt        j
                  j                  |       d   j                         dk(  rTt        j                  | d      5 }t        | dd d      5 }t        j                  ||       ddd       ddd       | dd } d}t        | |	      }|yt        | fi |}|j                  |      }|rt	        j                  |        |S # 1 sw Y   ^xY w# 1 sw Y   bxY w)
az  Convert an SVG file to a ReportLab Drawing object.

    Args:
        path: A file path, file-like object, or pathlib.Path to the SVG file.
        resolve_entities: Whether to resolve XML entities (default False).
        **kwargs: Additional keyword arguments for the SvgRenderer.

    Returns:
        A ReportLab Drawing object, or None if the file cannot be processed.
    Fr"   z.svgzrbNr   wbT)r  )r   pathlibr   r_   r^  rO  splitextr  gzipr  shutilcopyfileobjrT  rQ  r[  r  )	rO  r  rJ   unzippedf_inf_outsvg_rootsvgRendererr|  s	            r6   svg2rlgr    s    $%4y H$!1!1$!7!:!@!@!Bg!MYYtT" 	,dDcrD,A 	,UtU+	, 	,CRyT4DEH d-f-K  *G 
		$N#	, 	, 	, 	,s$   DD(DD	
DDr  c                     | syt        |       dk  ry| d   }| d   }t        dt        |       dz
  d      D ]  }|| |   k7  s|| |dz      k7  s y | dxx   dz  cc<   y)a  Nudge the first coordinate if all coordinate pairs are identical.

    This is a workaround for a ReportLab issue where shapes of size zero
    are not rendered, even if they have a visible stroke.

    Args:
        points: A list of coordinates [x1, y1, x2, y2, ...].
    Nr  r   r"   r   g  ?)r   r   )r  rC   rD   r   s       r6   r  r    sw     
6{Qq	Aq	A1c&kAoq) q	>Q&Q-/
 	q	Y	r8   c                     t        j                  dd|      }	 t        j                  | |      }|j                         }|S # t        $ r }t
        j                  d|       Y d}~yd}~ww xY w)a  Load an SVG file and return the root lxml node.

    Args:
        path: A file path or file-like object for the SVG file.
        resolve_entities: Whether to resolve XML entities.

    Returns:
        The root lxml node of the SVG document, or None on failure.
    T)remove_commentsrecoverr  )parserzFailed to load input file! (%s)N)r!   	XMLParserparsegetroot	Exceptionr   r   )rO  r  r  docr  excs         r6   rT  rT  6  se     __d=MFkk$v.;;=
 	  6<s   'A 	A,A''A,rx  c                 ^    	 | j                   j                  d      d   S # t        $ r Y yw xY w)zReturn the name of an lxml node without the namespace prefix.

    Args:
        node: The lxml node.

    Returns:
        The node name as a string, or None if the node is invalid.
    }r   N)r  ry   r  )rx  s    r6   r   r   O  s1    xx~~c"2&& s     	,,r  r  c           	   #     K   |dk(  }| j                   r7t        | j                   |||xr t        | j                               dk(        nd}| |df | j	                         D ]  }t        |||dz         E d{     |dkD  rV|dk  xr | j                         du }| j                  rt        | j                  ||      nd}|dvr| j                  |d	f yyy7 bw)
a  Recursively iterate through a text node and its children.

    This generator yields the node, its text, and its tail text, handling
    whitespace according to the 'xml:space' attribute.

    Args:
        node: The lxml node to start iteration from.
        preserve_space: Whether to preserve whitespace.
        level: The current recursion level.

    Yields:
        A tuple of (node, text, is_tail).
    r   )strip_start	strip_endNFr"   )r  )r  r  T)	r   
clean_textr   r  r  r3  getnexttailr   )rx  r  r  level0r   r  r  r  s           r6   r3  r3  ^  s     aZF 99 	II>#d&6&6&8"9Q">		
  	 e
##% J!%uqyIIIJ qyQJ94<<>T#9	 yy tyy.IF 	
 z!++tT)) "  	Js   A9C ;C<A#C r   r  r  c                     | y| j                  dd      j                  dd      j                  dd      } |s?|r| j                         } |r| j                         } d| v r| j                  dd      } d| v r| S )ai  Clean text content according to SVG whitespace handling rules.

    Args:
        text: The text content to clean.
        preserve_space: Whether to preserve whitespace.
        strip_start: Whether to strip leading whitespace.
        strip_end: Whether to strip trailing whitespace.

    Returns:
        The cleaned text, or None if the input was None.
    Nz
r   
	z  )r   lstriprstrip)r   r  r  r  s       r6   r  r    sz    " |<<$,,T37??cJD;;=D;;=Ddl<<c*D dlKr8   source_shape
dest_shapec                     | j                         j                         D ]  \  }}	 t        |||        y# t        $ r Y "w xY w)zCopy properties from one ReportLab shape to another.

    Args:
        source_shape: The shape to copy properties from.
        dest_shape: The shape to copy properties to.
    N)rY   r   r  r  )r  r  propr   s       r6   r  r    sN     "//1779 	c	Jc*  		s   6	AAc                      ddl m}  ddlm} | j                  dt
        dt
        dt
        dt
        ffd}|| _        |j                  d	t
        dt
        dt
        dt
        ffd
}||_        y)zApply a patch to ReportLab to handle path fill rules correctly.

    This patch addresses an issue where ReportLab does not honor the
    'fill-rule' attribute of SVG paths, defaulting to 'even-odd'.
    r   )shapes)CanvasrO  	drawFuncsrJ   r.   c                 t    	 | j                   |d   j                  _         | |fi |S # t        $ r Y w xY w)Nr   )r  __self__fillModer  )rO  r  rJ   original_renderPaths      r6   patchedRenderPathz0monkeypatch_reportlab.<locals>.patchedRenderPath  sF    	-1^^IaL!!* #4=f==  		s   + 	77rT   c                     | j                   }t        |d      r|j                  | _         nt        | _          | |fi | || _         y )Nr  )	_fillModer  r  r   )rT   rO  rJ   currentoriginal_drawPaths       r6   patchedDrawPathz.monkeypatch_reportlab.<locals>.patchedDrawPath  s>    ..4$!]]DN*DN$// r8   N)reportlab.graphicsr  reportlab.pdfgen.canvasr  _renderPathr   drawPath)r  r  r  r  r  r  s       @@r6   monkeypatch_reportlabr    sv     *. ,,> > >s >s > +F!c ! ! ! ! &FOr8   )Nr6  r6  Nr5  r  )r   r,  r   )nr^   r  rR   r  r6  r  r^  r  r   r   r  collectionsr   r   ior   typingr   r   r   r	   r
   r   PILr   r  reportlab.graphics.shapesr   r   r   r   r   r   r   r   r   r   r   r   reportlab.libr   reportlab.lib.unitsr   r   reportlab.pdfbase.pdfmetricsr   r  r   r   reportlab.pdfgen.pdfimagesr   reportlab.graphics.transformr    ImportErrorru   rq   lxmlr!   fontsr#   r$   r%   r&   r'   r(   rA   r)   r?   utilsr*   r+   r,   r7   r_   r  r  objectr  	getLoggerr[   r   rB   compilefindallsplit_whitespacerH   rc   Matcherrj   r   r   ElementWrapperr:  r  rL  rN  rQ  r  rc  r_  r  r   r  rT  r   r8  r3  r  r  r  rh   r8   r6   <module>r     sz  (      	  	   /  : : !    ! . 4 @ /02
     HNN x~~ ,  $!%RR}R R 	R
 #R 8C=$R6 :B666366
396( 
0 (			8	$562::./77 4 .4 05## 5>W WtR% 2 R%j'7*++ '7T	y 	7 7@l l^R R,{%- {%~ BG$
R[[%%
&$:>$RU$g$Ne  0 BG
R[[%%
&:>c]2C HSM '* '*d '*3 '*s '*Z 	
3-  	
 c]<   !&H  {<  0//0s   I9 9JJ