I'm trying to render a CALayer
from SwiftSVG package (on github) as a UIImage
. It isn't working.
Source .svg file defines a viewBox 1169 x 1000.
If I add CALayer
to UIView
and add UIView
(not UIImage
) to view hierarchy, the SVG graphics are perfect, so CALayer
is fine.
I added renderer.cgContext
based drawing commands in the closure, to draw an outline around the rendering area. It worked. The resulting UIImage
had an outline drawn, proving the image renderer block itself works. Thus...
svgLayer.render()
does not render visible graphics in the produced image.
svgView.drawHierarchy()
doesn't work either (for example if I add the SVG layer as a sublayer of a view and try to render the view instead).
WORKS AND PRODUCES VALID CALAYER WITH PERFECT SVG GRAPHICS:
let viewBox : CGRect? = CGRectMake(0, 0, 116.9, 100)
let filename = (fieldKey + ".svg").lowercased()
let svgURL = gbl_svgDataUrl.appendingPathComponent(filename)
let svgLayer = CALayer(SVGURL: svgURL) { (svgLayer) in
svgLayer.fillColor = color.cgColor
if let viewBox {
svgLayer.resizeToFit(viewBox)
}
}
CAN GET DRAWN GRAPHICS INTO IMAGE BUT NOT RENDERED CALAYER OR VIEW:
let format = UIGraphicsImageRendererFormat.preferred()
format.opaque = false
let image = UIGraphicsImageRenderer(size: viewBox.size, format: format).image { renderer in
svgLayer.render(in: renderer.cgContext) // <-- DOESN'T WORK
//svgView.drawHierarchy(in: viewBox, // <-- DOESN'T WORK
// afterScreenUpdates: false)
}
I figured out a resolution. Tricky situation, so I'm answering my own question so this may come up in searches for related terms and help someone in the future
@Sweeper's comment to the question right, when trying to create a CALayer with SwiftSVG CALayer(SVGURL), it is async, and the layer can only be added to the view inside the closure. What confused me is that's different than how SwiftSVG docs (at github project main page) shows the
UIView(SVGURL:)
API, which does complete synchronously, and the view is ready when the main call completes. Therefore, I switched from usingCALayer(SVGURL:)
toUIView(SVGURL:)
to avoid async problems. And that necessitated to using view.drawHierarchy() instead of layer.render()Then I hit a Catch-22 with this line:
If I set
afterScreenUpdates:false
, I got this warning in the console:afterScreenUpdates:true
, I got this error:And with either error the SVG View would not render into the image.
I tried forcing the view to display with setNeedsLayout() and layoutIfNeeded() before image rendering, which didn't work. Neither did moving code into viewDidLayoutSubviews().
Solution:
afterScreenUpdates:true
and add a delay to avoid the 2nd error.