@@ -219,74 +219,73 @@ def _gradientToSVG(
219
219
class SVGSurface (Surface ):
220
220
fileExtension = ".svg"
221
221
222
- def __init__ (self , boundingBox ):
222
+ def __init__ (self ):
223
+ self ._svgElements = None
224
+
225
+ @contextmanager
226
+ def canvas (self , boundingBox ):
223
227
x , y , xMax , yMax = boundingBox
224
228
width = xMax - x
225
229
height = yMax - y
226
- self .viewBox = x , y , width , height
230
+ self ._viewBox = x , y , width , height
227
231
transform = Transform (1 , 0 , 0 , - 1 , 0 , height + 2 * y )
228
- self ._canvas = SVGCanvas (transform )
232
+ canvas = SVGCanvas (transform )
233
+ yield canvas
234
+ self ._svgElements = canvas .elements
235
+
236
+ def saveImage (self , path ):
237
+ with open (path , "wb" ) as f :
238
+ writeSVGElements (self ._svgElements , self ._viewBox , f )
239
+
240
+
241
+ def writeSVGElements (elements , viewBox , stream ):
242
+ clipPaths = {}
243
+ gradients = {}
244
+ for fillPath , fillT , clipPath , clipT , paint , paintT in elements :
245
+ clipKey = clipPath , clipT
246
+ if clipPath is not None and clipKey not in clipPaths :
247
+ clipPaths [clipKey ] = f"clip_{ len (clipPaths )} "
248
+ gradientKey = paint , paintT
249
+ if not isinstance (paint , RGBAPaint ) and gradientKey not in gradients :
250
+ gradients [gradientKey ] = f"gradient_{ len (gradients )} "
251
+
252
+ root = ET .Element (
253
+ "svg" ,
254
+ width = formatNumber (viewBox [2 ]),
255
+ height = formatNumber (viewBox [3 ]),
256
+ preserveAspectRatio = "xMinYMin slice" ,
257
+ viewBox = " " .join (formatNumber (n ) for n in viewBox ),
258
+ version = "1.1" ,
259
+ xmlns = "http://www.w3.org/2000/svg" ,
260
+ )
229
261
230
- @property
231
- def canvas (self ):
232
- return self ._canvas
262
+ # root.attrib["xmlns:link"] = "http://www.w3.org/1999/xlink"
233
263
234
- def saveImage (self , pathOrFile ):
235
- if hasattr (pathOrFile , "write" ):
236
- self .writeSVG (pathOrFile )
237
- else :
238
- with open (pathOrFile , "wb" ) as f :
239
- self .writeSVG (f )
240
-
241
- def writeSVG (self , stream ):
242
- elements = self .canvas .elements
243
- clipPaths = {}
244
- gradients = {}
245
- for fillPath , fillT , clipPath , clipT , paint , paintT in elements :
246
- clipKey = clipPath , clipT
247
- if clipPath is not None and clipKey not in clipPaths :
248
- clipPaths [clipKey ] = f"clip_{ len (clipPaths )} "
249
- gradientKey = paint , paintT
250
- if not isinstance (paint , RGBAPaint ) and gradientKey not in gradients :
251
- gradients [gradientKey ] = f"gradient_{ len (gradients )} "
252
-
253
- root = ET .Element (
254
- "svg" ,
255
- width = formatNumber (self .viewBox [2 ]),
256
- height = formatNumber (self .viewBox [3 ]),
257
- preserveAspectRatio = "xMinYMin slice" ,
258
- viewBox = " " .join (formatNumber (n ) for n in self .viewBox ),
259
- version = "1.1" ,
260
- xmlns = "http://www.w3.org/2000/svg" ,
264
+ if gradients :
265
+ defs = ET .SubElement (root , "defs" )
266
+ for (gradient , gradientTransform ), gradientID in gradients .items ():
267
+ defs .append (gradient .toSVG (gradientID , gradientTransform ))
268
+
269
+ for (clipPath , clipTransform ), clipID in clipPaths .items ():
270
+ clipElement = ET .SubElement (root , "clipPath" , id = clipID )
271
+ ET .SubElement (
272
+ clipElement , "path" , d = clipPath , transform = formatMatrix (clipTransform )
261
273
)
262
274
263
- # root.attrib["xmlns:link"] = "http://www.w3.org/1999/xlink"
264
-
265
- if gradients :
266
- defs = ET .SubElement (root , "defs" )
267
- for (gradient , gradientTransform ), gradientID in gradients .items ():
268
- defs .append (gradient .toSVG (gradientID , gradientTransform ))
269
-
270
- for (clipPath , clipTransform ), clipID in clipPaths .items ():
271
- clipElement = ET .SubElement (root , "clipPath" , id = clipID )
272
- ET .SubElement (
273
- clipElement , "path" , d = clipPath , transform = formatMatrix (clipTransform )
274
- )
275
-
276
- for fillPath , fillT , clipPath , clipT , paint , paintT in elements :
277
- attrs = [("d" , fillPath )]
278
- if isinstance (paint , RGBAPaint ):
279
- attrs += colorToSVGAttrs (paint )
280
- else :
281
- attrs .append (("fill" , f"url(#{ gradients [paint , paintT ]} )" ))
282
- attrs .append (("transform" , formatMatrix (fillT )))
283
- if clipPath is not None :
284
- clipKey = clipPath , clipTransform
285
- attrs .append (("clip-path" , f"url(#{ clipPaths [clipKey ]} )" ))
286
- ET .SubElement (root , "path" , dict (attrs ))
287
-
288
- tree = ET .ElementTree (root )
289
- tree .write (stream , pretty_print = True , xml_declaration = True )
275
+ for fillPath , fillT , clipPath , clipT , paint , paintT in elements :
276
+ attrs = [("d" , fillPath )]
277
+ if isinstance (paint , RGBAPaint ):
278
+ attrs += colorToSVGAttrs (paint )
279
+ else :
280
+ attrs .append (("fill" , f"url(#{ gradients [paint , paintT ]} )" ))
281
+ attrs .append (("transform" , formatMatrix (fillT )))
282
+ if clipPath is not None :
283
+ clipKey = clipPath , clipTransform
284
+ attrs .append (("clip-path" , f"url(#{ clipPaths [clipKey ]} )" ))
285
+ ET .SubElement (root , "path" , dict (attrs ))
286
+
287
+ tree = ET .ElementTree (root )
288
+ tree .write (stream , pretty_print = True , xml_declaration = True )
290
289
291
290
292
291
def formatCoord (pt ):
0 commit comments