o
    
&zh                     @   s  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Zddl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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* zddl+m,Z, W n e-y   ddlm,Z, Y nw ddl.m/Z/ ddl0Z0ddl1Z1ddl2m3Z3m4Z4m5Z5 ddl6m7Z7m8Z8m9Z9m:Z:m;Z; ddl6m<Z=m>Z? dEddZ<dFddZ>dZ@dZAdZBdZCdZDeE ZFeGeHZIedg dZJeKdjLZMG dd deZNG d d! d!eZOG d"d# d#e0jPZQG d$d% d%ZRG d&d' d'eRZSG d(d) d)e0jTZUG d*d+ d+eVZWG d,d- d-ZXG d.d/ d/ZYG d0d1 d1ZZG d2d3 d3eZZ[dGd5d6Z\d7d8 Z]dGd9d:Z^d;d< Z_dHd=d>Z`dId?d@ZadAdB ZbdCdD Zcec  dS )Ja  A library for reading and converting SVG.

This is a converter from SVG to RLG (ReportLab Graphics) drawings.
It converts mainly basic shapes, paths and simple text. The intended
usage is either as module within other projects:

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

or from the command-line where it is usable as an SVG to PDF converting
tool named sv2pdf (which should also handle SVG files compressed with
gzip and extension .svgz).
    N)defaultdict
namedtuple)stringWidth)FILL_EVEN_ODDFILL_NON_ZERO)PDFImage)
_CLOSEPATHCircleDrawingEllipseGroupImageLinePathPolyLinePolygonRect
SolidShapeString)colors)picatoLength)
haveImages)mmult)etree   )bezier_arc_from_end_pointsconvert_quadratic_to_cubic_pathnormalise_svg_path)get_global_font_mapDEFAULT_FONT_NAMEDEFAULT_FONT_WEIGHTDEFAULT_FONT_STYLEDEFAULT_FONT_SIZE)register_font	find_fontnormalc                 C   s   t | ||||S N)_fonts_register_font)	font_name	font_pathweightstylerlgFontName r.   H/var/www/html/kangema/venv/lib/python3.10/site-packages/svglib/svglib.pyr$   B      r$   c                 C   s   t | ||S r'   )_fonts_find_font)r)   r+   r,   r.   r.   r/   r%   F   s   r%   z1.5.1zLGPL 3zDinu Ghermanz
2023-01-07z$http://www.w3.org/XML/1998/namespaceBox)xywidthheightz[^ \t\r\n\f]+c                       s,   e Zd ZdZ fddZ fddZ  ZS )NoStrokePathzg
    This path object never gets a stroke width whatever the properties it's
    getting assigned.
    c                    s>   | dd }t j|i | |r| jt|j d S d S )N	copy_from)popsuper__init____dict__updatecopydeepcopyselfargskwargsr8   	__class__r.   r/   r;   `   s
   zNoStrokePath.__init__c                    s6   t  j|i |}d|v rd|d< d|v rd |d< |S )NstrokeWidthr   strokeColor)r:   getPropertiesrA   rB   rC   propsrD   r.   r/   rH   f   s   zNoStrokePath.getProperties)__name__
__module____qualname____doc__r;   rH   __classcell__r.   r.   rD   r/   r7   [   s    r7   c                   @      e Zd Zdd Zdd ZdS )ClippingPathc                 O   sF   | dd }tj| g|R i | |r| jt|j d| _d S )Nr8   r   )r9   r   r;   r<   r=   r>   r?   
isClipPathr@   r.   r.   r/   r;   q   s
   
zClippingPath.__init__c                 O   s<   t j| g|R i |}d|v rd |d< d|v rd |d< |S )N	fillColorrG   )r   rH   rI   r.   r.   r/   rH   x   s   zClippingPath.getPropertiesN)rK   rL   rM   r;   rH   r.   r.   r.   r/   rQ   p       rQ   c                   @   s   e Zd Zdd ZdS )
CSSMatcherc           	      C   s   t j|ddd}|D ]4}|jr|jdkrq
t|j}t |j}dd t |jdD }||f}|D ]}| 	|| q5q
d S )NT)skip_commentsskip_whitespacezat-rulec                 S   s6   i | ]}d |v r| d d  | d d  qS ):r   r   )splitstrip.0attrr.   r.   r/   
<dictcomp>   s
     z)CSSMatcher.add_styles.<locals>.<dictcomp>;)
tinycss2parse_stylesheetpreludetype
cssselect2compile_selector_list	serializecontentrY   add_selector)	rA   style_contentrulesrule	selectorsselector_stringcontent_dictpayloadselectorr.   r.   r/   
add_styles   s    zCSSMatcher.add_stylesN)rK   rL   rM   rq   r.   r.   r.   r/   rU      s    rU   c                   @   sH   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )AttributeConverterzEAn abstract class to locate and convert attributes in a DOM instance.c                 C   s   d | _ d | _d S r'   )	css_rulesmain_boxrA   r.   r.   r/   r;      s   
zAttributeConverter.__init__c                 C   s
   || _ d S r'   )rt   )rA   rt   r.   r.   r/   set_box      
zAttributeConverter.set_boxc                 C   sd   | d}dd |D }tdd |}i }|D ]}| d\}}dd ||fD \}}|||< q|S )znTry parsing compound attribute string.

        Return a dictionary with single attributes in 'line'.
        r_   c                 S      g | ]}|  qS r.   rZ   r\   ar.   r.   r/   
<listcomp>       z;AttributeConverter.parseMultiAttributes.<locals>.<listcomp>c                 S   s   t | dkS Nr   )len)r{   r.   r.   r/   <lambda>   s    z9AttributeConverter.parseMultiAttributes.<locals>.<lambda>rX   c                 S   rx   r.   ry   )r\   sr.   r.   r/   r|      r}   )rY   filter)rA   lineattrs	new_attrsr{   kvr.   r.   r/   parseMultiAttributes   s   

z'AttributeConverter.parseMultiAttributesc                 C   s   |j dds9| jdur|| j |j dr9| |j d}| D ]\}}|ds3||j |< q%d|j d< |j |d }|rJ|dkrJ|S |jdurV| 	|j|S dS )	zSearch an attribute with some name in some node or above.

        First the node is searched, then its style attribute, then
        the search continues in the node's parent node. If no such
        attribute is found, '' is returned.
        __rules_appliedFNr,   -1 inherit)
attribgetrs   apply_rulesr   items
startswithrZ   parentfindAttr)rA   svgNodenamer   keyval
attr_valuer.   r.   r/   r      s    





zAttributeConverter.findAttrc                 C   st   i }t | dkr|| |  |jd}|r&| |}|| |j D ]\}}|dkr7|||< q+|S )zJReturn a dictionary of all attributes of svgNode or those inherited by it.gr,   )	node_name	getparentr=   getAllAttributesr   r   r   r   )rA   r   dictr,   dr   valuer.   r.   r/   r      s   

z#AttributeConverter.getAllAttributesc                 C   s   |S )zReturn attribute as is.r.   rA   svgAttrr.   r.   r/   id      zAttributeConverter.idc              	   C   st  |  }|dd }g }g }t|D ]\}}|dv r|| qtdt|dD ]c}|| ||d  }}	||d |	 }
|
  }
|
dd}
tdd|
}
zd|
v rc|td	d
 |
	dD  n|t
|
 W n	 tyt   Y q(w |d| d|	| d   ||	d d  }q(|dd	 }t|t|krtd| g S g }t|D ]\}}|||| f q|S )zParse transform attribute string.

        E.g. "scale(2) translate(10,20)"
             -> [("scale", 2), ("translate", (10,20))]
        Nz()r      r   , z[ ]+c                 s   s    | ]}t |V  qd S r'   float)r\   numr.   r.   r/   	<genexpr>  s    z6AttributeConverter.convertTransform.<locals>.<genexpr>z'Unable to parse transform expression %r)rZ   	enumerateappendranger   replaceresubtuplerY   r   
ValueErrorloggerwarning)rA   r   r   opsbracketsindicesilinbibjsublineresultopr.   r.   r/   convertTransform   s>   
 .z#AttributeConverter.convertTransformN)rK   rL   rM   rN   r;   rv   r   r   r   r   r   r.   r.   r.   r/   rr      s    rr   c                       s   e Zd ZdZd fdd	Zedd Zedd Zedd	fd
dZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zd ddZ  ZS )!Svg2RlgAttributeConverterz*A concrete SVG to RLG attribute converter.Nc                    s&   t    |p	| j| _|pt | _d S r'   )r:   r;   identity_color_convertercolor_converterr   	_font_map)rA   r   font_maprD   r.   r/   r;     s   
z"Svg2RlgAttributeConverter.__init__c                 C   s   | S r'   r.   )cr.   r.   r/   r     r   z2Svg2RlgAttributeConverter.identity_color_converterc                 C   s   t |  ddS )Nr   r   )shlexrY   rZ   r   r]   r.   r.   r/   split_attr_list   s   z)Svg2RlgAttributeConverter.split_attr_list        c                    s  | dd }|sS d|v r fdd|D S |drsjdu r6td t|dd S  du rGtd	 t|dd S  d
v rPjj}n dv rYjj	}ntd  t|dd S t|dd d | S |drt|dd t
 S |drt|dd d S |drt|dd  S |drt|dd S |drt|dd  d S |drt|dd  d S | }t|}|S )zConvert length to points.r   r   c                    s   g | ]}j | d qS ))em_base	attr_namedefaultconvertLengthr\   r   r   r   r   rA   r.   r/   r|   ,  s    z;Svg2RlgAttributeConverter.convertLength.<locals>.<listcomp>%Nz4Unable to resolve percentage unit without a main boxz?Unable to resolve percentage unit without knowing the node name)r3   cxx1x2r5   )r4   cyy1y2r6   z.Unable to detect if node %r is width or heightd   pcptg      ?empxexr   ch)r   rZ   r   endswithrt   r   errorr   r5   r6   r   r   )rA   r   r   r   r   textfulllengthr.   r   r/   r   $  sH   











z'Svg2RlgAttributeConverter.convertLengthc                    s    fdd  |D S )zConvert a list of lengths.c                    s   g | ]}  |qS r.   r   rz   ru   r.   r/   r|   X  s    z?Svg2RlgAttributeConverter.convertLengthList.<locals>.<listcomp>)r   r   r.   ru   r/   convertLengthListV  s   z+Svg2RlgAttributeConverter.convertLengthListc                 C   s   t |S r'   r   r   r.   r.   r/   convertOpacityZ  s   z(Svg2RlgAttributeConverter.convertOpacityc                 C   s   t td|dS )N)nonzeroevenoddr   )r   r   r   r   r.   r.   r/   convertFillRule]  s
   z)Svg2RlgAttributeConverter.convertFillRulec                 C   sJ  |}|r|dkr
dS |dkrdS t |dv r(|d dkr(tj|t |dkd}nlt |d	krL|d dkrLtdd
|d   d
|d
   d
|d   }nHt |dkrx|d dkrxtjdd
|d   d
|d
   d
|d   d
|d	   dd}nt|}|du rz	tt| }W n	 ty   Y nw |du rtd| dS | 	|S )z$Convert string to a RL color object.noneNcurrentColor)   	   r   #r   )hasAlpha   r   r         TzCan't handle color: %s)
r   r   HexColorcssParsegetattrcloneAttributeErrorr   r   r   )rA   r   r   colorr.   r.   r/   convertColorc  s.   04

z&Svg2RlgAttributeConverter.convertColorc                 C      dddd| S )Nr   r   r   )miterroundbevelr.   r   r.   r.   r/   convertLineJoin  r0   z)Svg2RlgAttributeConverter.convertLineJoinc                 C   r   )Nr   r   r   )buttr   squarer.   r   r.   r.   r/   convertLineCap  r0   z(Svg2RlgAttributeConverter.convertLineCapc                 C      |  |}|S r'   )r   )rA   r   strokeDashArrayr.   r.   r/   convertDashArray     
z*Svg2RlgAttributeConverter.convertDashArrayc                 C   r  r'   r   )rA   r   strokeDashOffsetr.   r.   r/   convertDashOffset  r  z+Svg2RlgAttributeConverter.convertDashOffsetr&   c                 C   sz   |sdS |  |}g }|D ]}| j|||\}}|r|  S |r&|| q|r-|d S td| d| d|  tS )Nr   r   z0Unable to find a suitable font for 'font-family:z
', weight:z, style:)r   r   r%   r   r   r   r    )rA   fontAttr
weightAttr	styleAttr
font_namesnon_exact_matchesr)   exactr.   r.   r/   convertFontFamily  s*   

z+Svg2RlgAttributeConverter.convertFontFamilyNNr&   r&   )rK   rL   rM   rN   r;   staticmethodr   r   r#   r   r   r   r   r   r   r  r  r	  r  rO   r.   r.   rD   r/   r     s"    

2!r   c                       s@   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Z  Z	S )NodeTrackerzAn object wrapper keeping track of arguments to certain method calls.

    Instances wrap an object and store all arguments to one special
    method, getAttribute(name), in a list of unique elements, usedAttrs.
    c                    s   t  j|i | g | _d S r'   )r:   r;   	usedAttrs)rA   rB   rC   rD   r.   r/   r;     s   
zNodeTracker.__init__c                 C   s   d| j  dS )Nz<NodeTracker for node >)etree_elementru   r.   r.   r/   __repr__  s   zNodeTracker.__repr__c                 C   s&   || j vr| j | | jj|dS Nr   )r  r   r  r   r   rA   r   r.   r.   r/   getAttribute  s   
zNodeTracker.getAttributec                 C   s   t | j|S r'   )r   r  r  r.   r.   r/   __getattr__  s   zNodeTracker.__getattr__c              
   C   sf   | | }|D ]"}|d d }| D ]\}}z|| jj|< W q ty(   Y qw q| jdd d S )Nr   r   r   r   )matchr   r  r   r   set)rA   rj   matchesr  	attr_dictr]   r   r.   r.   r/   r     s   
zNodeTracker.apply_rules)
rK   rL   rM   rN   r;   r  r  r  r   rO   r.   r.   rD   r/   r    s    r  c                   @   s   e Zd ZdS )CircularRefErrorN)rK   rL   rM   r.   r.   r.   r/   r!    s    r!  c                   @   rP   )ExternalSVGc                 C   s,   t || _t||j|jg d| _d| _d S )N)parent_svgsF)load_svg_file	root_nodeSvgRenderer_parent_chainsource_pathrendererrendered)rA   pathr)  r.   r.   r/   r;     s
   

zExternalSVG.__init__c                 C   s(   | j s| j| j d| _ | jj|S )NT)r*  r)  renderr%  definitionsr   )rA   fragmentr.   r.   r/   get_fragment  s   zExternalSVG.get_fragmentN)rK   rL   rM   r;   r/  r.   r.   r.   r/   r"    rT   r"  c                   @   s   e Zd ZdZd$ddZdd Zd%ddZd	d
 Zdd Zdd Z	d%ddZ
dd Zdd Zd&ddZd&ddZd%ddZdd Zdd Zd d! Zd'd"d#ZdS )(r&  zRenderer that renders an SVG file on a ReportLab Drawing instance.

    This is the base class for walking over an SVG DOM document and
    transforming it into a ReportLab Drawing instance.
    Nc                 C   s\   || _ |pg | _t||d| _t|| j| _| j | _i | _t	t
| _i | _t | j_d S )N)r   r   )r(  r'  r   attrConverterSvg2RlgShapeConvertershape_converterget_handled_shapeshandled_shapesr-  r   listwaiting_use_nodes_external_svgsrU   rs   )rA   r+  r   r#  r   r.   r.   r/   r;     s   

zSvgRenderer.__init__c           	      C   s   t |}| j|dd}| j| | j|dd}| j D ]}t	d| q|
d|j |j |j  | jj|dd|j|jfd\}}t||}|| |S )	NTdefault_box)	outermostz(Ignoring unavailable object width ID %r.r   r5   r6   defaults)r  from_xml_rootget_boxr0  rv   	renderSvgr6  keysr   debug	translater3   r6   r4   r2  convert_length_attrsr5   r
   add)	rA   svg_nodenodeview_box
main_groupxlinkr5   r6   drawingr.   r.   r/   r,    s   



zSvgRenderer.renderc                 C   s  | d}d}d }t|}| |}|dkr!| |}|| n|dkr(d}n|dkr7| |}|| n|dkrQ| d}| j||d	}|d
krP|| n|dkr[| | n|dkrw| |}|j	
drp|| nz|dd ns|dkr| j||d	}|| nb|dkr| |}nX|| jv r|dkr| |}	|	d u rd S t|	trt }
|	\}}|j||
d | ||
 ||
 d S |	|_| j|||}| d}|r|d
kr|| nd}td| |s>|r|r|| j|< |d|i dd |j	 D }t|dkr|\}|d|i || j v r7| j|}|D ]\}}| j||d q*|  | d S d S )Nr   FsvgdefsTr{   r   display)clippingr   r,   symbol	_renderedr   useclipPathimager   zIgnoring node: %ssvgidc                 S   s   g | ]
\}}d |v r|qS )labelr.   )r\   r   r   r.   r.   r/   r|   Q  s    z*SvgRenderer.renderNode.<locals>.<listcomp>r   rV  group)!r  r   get_clippathr?  rD  renderArenderGrenderStylerenderSymbolr   r   r  	renderUser4  xlink_href_target
isinstancer   r   
renderNodeapply_node_attr_to_group_resolved_targetr2  convertShaper   rA  r-  setPropertiesr   r   r6  r@  r9   print_unused_attributes)rA   rF  r   nidignoreditemr   rN  rM  targetgrr)  img_nodelabel_attrsrV  	to_renderuse_noderX  r.   r.   r/   ra    s   













zSvgRenderer.renderNodec                    s   fdd  fdd| d}|sdS td|}|s!dS | d }|jvr4td	| dS j| }t|trn|	 \}}}}	t
 }
|
|| |
|| |
||	 |
||	 |
  t||
 |
S t|trxt
|d
S |rtd|jj dS dS )zo
        Return the clipping Path object referenced by the node 'clip-path'
        attribute, if any.
        c                    s8   | j D ]}t|tr |  S t|tr|  S qd S r'   )contentsr`  r   r   )rX  elem)get_shape_from_groupr.   r/   rr  `  s   


z6SvgRenderer.get_clippath.<locals>.get_shape_from_groupc                    s   |   D ]:}t|dkrjd|}|jd   S t|dkr+|} |  S t|dkr9j|  S |  S d S )Nr+  r   rQ  rect)iter_childrenr   r2  rd  rp  r^  convertRect)rF  childrX  grprr  get_shape_from_noderA   r.   r/   ry  g  s   
z5SvgRenderer.get_clippath.<locals>.get_shape_from_nodez	clip-pathNzurl\(#([^\)]*)\)r   z)Unable to find a clipping path with id %sr8   z&Unsupported shape type %s for clipping)r  r   r  groupsr-  r   r   r`  r   	getBoundsrQ   moveTolineTo	closePathcopy_shape_propertiesr   loggingr   rE   rK   )rA   rF  	clip_pathmrefshaper   r   r   r   cpr.   rx  r/   rY  [  s8   





zSvgRenderer.get_clippathc                    sR   t jtjkrd S | j j } fdd|D }|r't dt	 | d S d S )Nc                    s   g | ]	}| j vr|qS r.   )r  r[   rF  r.   r/   r|     s    z7SvgRenderer.print_unused_attributes.<locals>.<listcomp>zUnused attrs: %s %s)
r   levelr  DEBUGr0  r   r  r@  rA  r   )rA   rF  	all_attrsunused_attrsr.   r  r/   rf    s   z#SvgRenderer.print_unused_attributesc                 C   sV   |j }t|d\}}}|s|r|d|pd d|pd d7 }|r)| j|| d S d S )N)	transformr3   r4   z translate(r   z, ))r  mapr2  applyTransformOnGroup)rA   rF  rX  getAttrr  r3   r4   r.   r.   r/   rb    s   z$SvgRenderer.apply_node_attr_to_groupc                 C   sB  |j dp|j d}|sdS td|}|r]| d }t||dd d d d}t	j
d| d	\}}t|d
}	|	| W d   n1 sQw   Y  t| |S d|v rj|dd\}
}n|d}
}|
rt| jtstd|
 dS tjtjtj| j|
}t|tjsdS || jkrd}
|
r|dr|| jv rtd t || jvrt|| | j|< | j| }|j dur|r|!|}|dur|j"|fS dS |j"t#$|j fS dS z	t%|dd W |S  t&y   td| Y dS w |r|| j'v r| | j'| fS | j(| )||f t*S dS )a  
        Return either:
            - a tuple (renderer, node) when the the xlink:href attribute targets
              a vector file or node
            - the path to an image file for any raster image targets
            - None if any problem occurs
        z"{http://www.w3.org/1999/xlink}hrefhrefNz^data:image/(jpe?g|png);base64r   r   ascii.)suffixwbr   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   r  r{  base64decodebytesspanencodetempfilemkstempopenwriteoscloserY   r`  r(  strr   r   r+  normpathjoindirnameaccessR_OKr   r'  r!  r7  r"  r%  r/  r)  r  r=  r   OSErrorr-  r6  r   DELAYED)rA   rF  rX  
xlink_hrefr  
img_format
image_datafile_indicatorr+  fhirir.  ext_svgext_fragr.   r.   r/   r_    sr   	&

 








	zSvgRenderer.xlink_href_targetc                 C      d S r'   r.   rA   rF  r.   r.   r/   renderTitle_  r   zSvgRenderer.renderTitle_c                 C   r  r'   r.   r  r.   r.   r/   renderDesc_  r   zSvgRenderer.renderDesc_Fc                 C   s^   | d}|r| j|}t| S |r-t|j d\}}t| jj||f\}}tdd||S d S )NviewBox)r5   r6   r   )r  r0  r   r2   r  r   )rA   rE  r9  rG  r5   r6   r.   r.   r/   r>    s   
zSvgRenderer.get_boxc                 C   s~  | j j}|dt ddk| j _| j|dd}| jj}|r$| j| |j	d }|
 D ]}|j|r:d| dndkrB| | q.t }| D ]}	| |	| qJ|| j _| j| |sw| j |dd	\}
}|
sm|rw||
prd
|pud
 |s|r|dd |S |rd\}}| j j|dddd\}}|d ur|j|kr||j }|d ur|j|kr||j }||||rdnd  |S )N{}spacepreserveTr8  z}defsrL  r3   r4   r   r   r   )r   r   r5   r6   r  r;  )r2  preserve_spacer  XML_NSr>  r0  rt   rv   nsmapr   iter_subtreetagr[  r   rt  ra  rC  rB  scaler6   r5   )rA   rF  r:  _saved_preserve_spacerG  
_saved_boxsvg_nsdef_noderX  rv  r3   r4   x_scaley_scaler5   r6   r.   r.   r/   r?    sD   



zSvgRenderer.renderSvgc                 C   sZ   |j }t|d\}}t }|r|| | D ]	}| j||d q|r+| j|| |S )N)r   r  rT  )r  r  r   rD  rt  ra  r2  r  )rA   rF  rN  r  r   r  rk  rv  r.   r.   r/   r[  2  s   
zSvgRenderer.renderGc                 C   s   | j j|jpd d S r  )r0  rs   rq   r   r  r.   r.   r/   r\  @  s   zSvgRenderer.renderStylec                 C   
   |  |S r'   r[  r  r.   r.   r/   r]  C  rw   zSvgRenderer.renderSymbolc                 C   r  r'   r  r  r.   r.   r/   rZ  F  s   
zSvgRenderer.renderAc                 C   s   |d u rt  }z	| j||d}W n ty#   |jj|j | Y S w |d u r*d S t|tr6t	d d S |t
u r<|S |d }|rG|| t| dkrW|t| | jt| d |d | || |S )NrW  z/<use> nodes cannot reference bitmap image filesr   r   r   rT  )r   r_  r!  r   r  remover`  r  r   r   r  rD  r   getchildrenr   r>   r?   ra  r5  rt  rb  )rA   rF  rX  rN  ri  r.   r.   r/   r^  K  s.   


zSvgRenderer.renderUse)NNNr'   Fr  )rK   rL   rM   rN   r;   r,  ra  rY  rf  rb  r_  r  r  r>  r?  r[  r\  r]  rZ  r^  r.   r.   r.   r/   r&    s$    

P7
S



+r&  c                   @   s&   e Zd ZdZdddZedd ZdS )SvgShapeConvertera;  An abstract SVG shape converter.

    Implement subclasses with methods named 'convertX(node)', where
    'X' should be the capitalised name of an SVG node element for
    shapes, like 'Rect', 'Circle', 'Line', etc.

    Each of these methods should return a shape object appropriate
    for the target format.
    Nc                 C   s   |pt  | _|| _d| _d S )NF)r   r0  svg_source_filer  )rA   r+  r0  r.   r.   r/   r;   r  s   
zSvgShapeConverter.__init__c                 C   s   dd t | D S )ztDynamically determine a list of handled shape elements based on
           convert<shape> method existence.
        c                 S   s&   g | ]}| d r|dd  qS )convertr   N)r   lower)r\   r   r.   r.   r/   r|   |  s   & z8SvgShapeConverter.get_handled_shapes.<locals>.<listcomp>)dir)clsr.   r.   r/   r3  w  s   z$SvgShapeConverter.get_handled_shapesr'   )rK   rL   rM   rN   r;   classmethodr3  r.   r.   r.   r/   r  h  s
    
	r  c                   @   s   e Zd ZdZdddZedddZdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zd ddZdS )!r1  z=Converter from SVG shapes to RLG (ReportLab Graphics) shapes.Nc                 C   s   d|   }t| ||}|sd S |dvr| || |d}|s'|s'|S t }|r2| || |r9|| || |S )Nr  )r+  polyliner   r  )
capitalizer   applyStyleOnShaper  r   r  rD  )rA   r   rF  rN  method_namer  r  rX  r.   r.   r/   rd    s    


z"Svg2RlgShapeConverter.convertShaper   c                   sT   t drjnfdd| jj |ddt| } fddt||D S )Nr  c                    s    j | dS r  )r   r   r   r  r.   r/   r     s    z<Svg2RlgShapeConverter.convert_length_attrs.<locals>.<lambda>r<  )r   c                    s$   g | ]\}} |||d qS ))r   r   r   r.   )r\   r]   r   )
convLengthr   r  r.   r/   r|     s    z>Svg2RlgShapeConverter.convert_length_attrs.<locals>.<listcomp>)hasattrr  r0  r   r   r   zip)rA   rF  r   r   rC   r<  r.   )r  r   r  rF  r/   rC    s   
z*Svg2RlgShapeConverter.convert_length_attrsc                 C   s"   |  |dddd}t| t| S )Nr   r   r   r   )rC  nudge_pointsr   )rA   rF  pointsr.   r.   r/   convertLine  s   z!Svg2RlgShapeConverter.convertLinec              	   C   sx   |  |dddddd\}}}}}}||d kr|d }||d kr%|d }|r,|s,|}n|r2|s2|}t||||||dS )	Nr3   r4   r5   r6   rxryr   )r  r  )rC  r   )rA   rF  r3   r4   r5   r6   r  r  r.   r.   r/   ru    s   z!Svg2RlgShapeConverter.convertRectc                 C   s"   |  |ddd\}}}t|||S )Nr   r   r)rC  r	   )rA   rF  r   r   r  r.   r.   r/   convertCircle  s   z#Svg2RlgShapeConverter.convertCirclec                 C   s2   |  |dddd\}}}}||}}t||||S )Nr   r   r  r  )rC  r   )rA   rF  r   r   r  r  r5   r6   r.   r.   r/   convertEllipse  s   
z$Svg2RlgShapeConverter.convertEllipsec                 C   s   | d}|dd}| }tt| jj|}t|d dks&t|dkr(d S t| t	|}| 
|| | j|ddv}|r]t }t|}| 
|| d |_|| || |S |S )Nr  r   r   r   r   fill)r   r   )r  r   rY   r5  r  r0  r   r   r  r   r  r   r   r   rG   rD  )rA   rF  r  r  has_fillrX  polygonr.   r.   r/   convertPolyline  s&   


z%Svg2RlgShapeConverter.convertPolylinec                 C   sd   | d}|dd}| }tt| jj|}t|d dks&t|dkr(d S t| t	|}|S )Nr  r   r   r   r   )
r  r   rY   r5  r  r0  r   r   r  r   )rA   rF  r  r  r.   r.   r/   convertPolygon  s   
z$Svg2RlgShapeConverter.convertPolygonc           (   	   C   s  | j }|dt d}|r|dk}n| j}t }g }d\}}d\}	}
||dp*t}||dp2t}||dp:t}|	|||}||dpKt
t}||}| j|d	d
|d\}}t||D ]\}}}|sjqad\}}d\}}d}|s| j|d	d
dd|d\}	}
}}|jd	ddk|jd
ddk}}|t|tr|d n| }|t|tr|d n| }|jdd}|dv r| d |d dd| }n|j||d}|t||| tdd |	|
||fD r|rt|	tr|	n|	g}n|| t|d d  g}|rt|
tr|
n|
g}n|| g}t|tr|n|g}t|tr*|n|g}|d |d d}}}t|||||D ]`\} }!}"}#}$|$d u rP nS|"d u rWd}"|#d u r^d}#|"| d u rl|t||| n|  }%|#|!d u rw|n|! }&t|%|&|  |$}'| |'| t|dkr| |'| ||' |%}|&}|$}qBqa|r|	| n|| t|d d  }%|r|
| n|| }&t|%|&|  |}'| |'| t|dkr| |'| ||' qa|dd |S )Nr  r  r  )r   r   font-familyfont-weight
font-style	font-sizer3   r4   r  FFr   dxdyr   zbaseline-shift0)r   r:   baseliner   c                 s   s    | ]}t |tV  qd S r'   )r`  r5  r   r.   r.   r/   r     s    z4Svg2RlgShapeConverter.convertText.<locals>.<genexpr>r   tspanr   )r0  r  r  r  r   r   r    r!   r"   r  r  r#   r   rC  iter_text_noder   r   r`  r5  r   r   anysum	itertoolszip_longestr   r  r   rD  r  )(rA   rF  attrConv	xml_spacer  rk  frag_lengthsdx0dy0r   r   fffwfstylefsr3   r4   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  r.   r.   r/   convertText  s   

&





&z!Svg2RlgShapeConverter.convertTextc           $      C   s  | d}|s	d S t|}t }|j}g }g }d}d }	tdt|dD ]e}
||
|
d  \}}|dv rG|
dkrG|jd tkrG|t|j |dkrX|j	|  |dd  }n(|d	krc|j
|  n|d
krt|dkr|dv rt|}n|dd  }|d |d  |d |d  }}|	|| n|j	|  |dd  }n|dkr|d |d  |d |d  }}|
|| n|dkr|
|d |d  n|dkr|
|d |d  n|dkr|
|d |d  |d  n|dkr|
|d |d |d   n{|dkr|j|  no|dkrX|\}}}}t|dk s(|dvr5|dd  d \}}}}n
|dd  \}}}}|||  |||  }}||||||| n(|dkr|dd  \}}|\}}}}}}||| || || || || ||  n|dkr|\}}}}t|dk s|dvr|dd  d \}}}}n
|dd  \}}}}|||  |||  }}||||| || || ||  n|dkr|dd  \}}|\}}}}||f}	t||f||f||f\\}}\}}\}}\}}||||||| nq|dkrg|	d ur|	\}}n|dd  \}}|dd  \}}|||  |||  }}||f}	|\}}t||f||f||f\\}}\}}\}}\}}||||||| n|dkr|dd  \}}|\}}}}|| || || || f\}}}}||f}	t||f||f||f\\}}\}}\}}\}}||||||| n|dkr|	d ur|	\}}n|dd  \}}|dd  \}}|\}}|| || }}|||  |||  }}||f}	t||f||f||f\\}}\}}\}}\}}||||||| nm|dv rp|\}}}}}}}|dd  \}}|dkr6||7 }||7 }t|dksDt|dkrK|
|| n5t|||||||||	}|D ]\} } }}}}}}||||||| qYn|dv rz|  ntd | |d!vrd }	|}q#t }!| || |jd tkr|t|j |r|jd urt|d"}"t|D ]
}#|"j|#t q|!|" d |_|!| |!S )#Nr   r   r   r   )r  Mr   r  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)r  r  r  r  rz  )r   r   r   r  r   r   	operatorsr   r   r}  r~  curveTor   absr   r  r   rA  r   r  rS   r7   reversedinsertrD  )$rA   rF  r   normPathr+  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bp_rk  closed_pathpointerr.   r.   r/   convertPath>  s   

"
" 
 


0
(




$










z!Svg2RlgShapeConverter.convertPathc                 C   s   t s	td d S | |dddd\}}}}|j}tt|t|| t|t||}t|}|d|| d  |	dd	 |S )
NzFUnable to handle embedded images. Maybe the pillow library is missing?r3   r4   r5   r6   r   r   r   r   )
r   r   r   rC  rc  r   intr   rB  r  )rA   rF  r3   r4   r5   r6   rS  rX  r.   r.   r/   convertImage  s   $z"Svg2RlgShapeConverter.convertImagec           	      C   s4  | j |}|D ]\}}|dkrt|ts||f}|j|  q|dkr4t|ttfr.|df}|j|  q|dkrht|trCt|dkrI|	| qt|dkrg|\}}}||| |	| || |  q|dkrs|
|d q|dkr~|
d| q|d	krt|d
krt|j||_qtd|| qdS )a6  Apply an SVG transformation to a RL Group shape.

        The transformation is the value of an SVG transform attribute
        like transform="scale(1, -1) translate(10, 30)".

        rotate(<angle> [<cx> <cy>]) is equivalent to:
          translate(<cx> <cy>) rotate(<angle>) translate(-<cx> -<cy>)
        r  rB  r   rotater   r   skewXskewYmatrix   zIgnoring transform: %s %sN)r0  r   r`  r   r  r=  r   rB  r   r?  skewr   r  r   rA  )	rA   r  rX  trr   valuesangler   r   r.   r.   r/   r    s6   



z+Svg2RlgShapeConverter.applyTransformOnGroupFc                 C   s  	 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rs|jD ]
}| j|||d) qfd*S | j	}||fD ]}|jt
kr||krqz|D ]\}	}
}}g }t|	D ]j\}}|||}|d+kr|rq|dkrt|dd*d*urt|jd,ddkr|jj}n|dkrt|dd*d*urt|jd,ddkr|jj}n|| }|d-kr||jd.p|| }t|tr|d/d+ }|| qzt||}t||
||  W q tttfy    td0 Y qw qzt|dd*d*ur4|jr4|j|j_t|dd*d1krBd*|_d*S d*S )2z
        Apply styles from an SVG element to an RLG shape.
        If only_explicit is True, only attributes really present are applied.
        r  rS   r   blackzfill-opacityfillOpacityr   r   z	fill-rule	_fillRuler   r   strokerG   r   zstroke-widthrF   r   r   zstroke-opacitystrokeOpacityzstroke-linejoinstrokeLineJoinr   r  zstroke-linecapstrokeLineCapr  zstroke-dasharrayr  r  )r  r  r  fontNamer  r  fontSizeztext-anchor
textAnchorr   start)only_explicitNr   alphar   r   z
!importantz"Exception during applyStyleOnShaper   )r    r!   r"   r  r#   rE   r   rp  r  r0  r   r   r   r   rS   rT  rG   r   r`  r   rZ   r   setattrr   KeyErrorr   r   rA  rI  )rA   r  rF  rS  mappingNmappingFsubshapeacmappingsvgAttrNamesrlgAttrfuncr<  svgAttrValuesindexsvgAttrNamesvgAttrValuemethr.   r.   r/   r    sv   








z'Svg2RlgShapeConverter.applyStyleOnShaper'   r  )rK   rL   rM   rN   rd  r#   rC  r  ru  r  r  r  r  r  r<  r>  r  r  r.   r.   r.   r/   r1    s     
V +&r1  Fc           	   	   K   s   t | tjr
t| } d}t | trZtj| d  dkrZt	| d'}t	| dd d}t
|| W d   n1 s>w   Y  W d   n1 sMw   Y  | dd } d}t| |d	}|du rfdS t| fi |}||}|rzt|  |S )
z
    Convert an SVG file to an RLG Drawing object.
    `path` can be a file, a file-like, or a file path as str or pathlib.Path.
    Fr   z.svgzrbNr   r  T)resolve_entities)r`  pathlibr   r  r  r+  splitextr  gzipr  shutilcopyfileobjr$  r&  r,  r  )	r+  re  rC   unzippedf_inf_outsvg_rootsvgRendererrJ  r.   r.   r/   svg2rlgr  s&   "" 

rp  c                 C   sx   | sdS t | dk rdS | d }| d }tdt | d dD ]}|| | ks.|| |d  kr1 dS q| d  d9  < dS )z Nudge first coordinate if all coordinate pairs are identical.

    This works around reportlab's decision to hide shapes of size zero, even
    when the stroke should be visible.
    Nr   r   r   r   g  ?)r   r   )r  r3   r4   r   r.   r.   r/   r    s   r  c              
   C   s`   t jdd|d}zt j| |d}| }W |S  ty/ } ztd| W Y d }~d S d }~ww )NT)remove_commentsrecoverre  )parserzFailed to load input file! (%s))r   	XMLParserparsegetroot	Exceptionr   r   )r+  re  rs  docrn  excr.   r.   r/   r$    s   
r$  c                 C   s(   z	| j dd W S  ty   Y dS w )z3Return lxml node name without the namespace prefix.}r   N)r  rY   r   r  r.   r.   r/   r     s
   r   c                 c   s    |dk}| j rt| j |||ot|  dkdnd}| |dfV  |  D ]}t|||d dE dH  q%|dkr\|dkoA|  du }| jrMt| j||dnd}|dvr^| j|d	fV  dS dS dS )
zW
    Recursively iterate through text node and its children, including node tails.
    r   )strip_start	strip_endNFr   )r  )r|  r  T)	r   
clean_textr   r  rt  r  getnexttailr   )rF  r  r  level0r   rv  r|  r  r.   r.   r/   r    s$   r  c                 C   sd   | du rdS |  dd dd dd} |s0|r|  } |r"|  } d| v r0|  dd} d| v s&| S )zCText cleaning as per https://www.w3.org/TR/SVG/text.html#WhiteSpaceNz
r   
	z  )r   lstriprstrip)r   r  r{  r|  r.   r.   r/   r}    s   r}  c              	   C   s<   |    D ]\}}zt||| W q ty   Y qw d S r'   )rH   r   rU  r   )source_shape
dest_shapepropr   r.   r.   r/   r    s   r  c                     sL   ddl m}  ddlm} |jfdd}||_| j  fdd}|| _dS )	z
    https://bitbucket.org/rptlab/reportlab/issues/95/
    ReportLab always use 'Even-Odd' filling mode for paths, this patch forces
    RL to honor the path fill rule mode (possibly 'Non-Zero Winding') instead.
    r   )Canvas)shapesc                    s8   z	| j |d j_W n	 ty   Y nw  | |fi |S r~   )rJ  __self__fillModer   )r+  	drawFuncsrC   )original_renderPathr.   r/   patchedRenderPath  s   z0monkeypatch_reportlab.<locals>.patchedRenderPathc                    s<   | j }t|dr|j| _ nt| _  | |fi | || _ d S )Nr  )	_fillModer  r  r   )rA   r+  rC   current)original_drawPathr.   r/   patchedDrawPath  s   


z.monkeypatch_reportlab.<locals>.patchedDrawPathN)reportlab.pdfgen.canvasr  reportlab.graphicsr  _renderPathdrawPath)r  r  r  r  r.   )r  r  r/   monkeypatch_reportlab  s   
r  )Nr&   r&   Nr  r  )r   r  )drN   r  r>   rh  r  r  r  rf  r   r  r   ri  collectionsr   r   reportlab.pdfbase.pdfmetricsr   r  r   r   reportlab.pdfgen.pdfimagesr   reportlab.graphics.shapesr   r	   r
   r   r   r   r   r   r   r   r   r   r   reportlab.libr   reportlab.lib.unitsr   r   reportlab.lib.utilsr   reportlab.graphics.transformr   ImportErrorlxmlr   rd   r`   utilsr   r   r   fontsr   r    r!   r"   r#   r$   r(   r%   r1   __version____license__
__author____date__r  objectr  	getLoggerrK   r   r2   compilefindallsplit_whitespacer7   rQ   MatcherrU   rr   r   ElementWrapperr  rw  r!  r"  r&  r  r1  rp  r  r$  r   r  r}  r  r  r.   r.   r.   r/   <module>   s   <


| &      
v 

	

"