How to convert UIBezierpath to SVG?
Hello,
I am trying to create a coloring app. I can read svg image and fill their backgrounds. I want to save my UIBezier paths as svg after coloring process is done. I saw the function SVGStringFromCGPaths path I could not figure out how to set AttributeSet of svg? A short explanation or a small examples would be great.
Thanks,
You'll need to explain how the "coloring process" works.
If your paths stay as SVGBezierPath instances you can just use self.SVGRepresentation.
Hello,
Thank you for your response first of all. Here is my code for coloring process. I am creating CAShapeLayers from SVGBezierPaths then fill inside of them. I want to save result of coloring process as SVG. Is there any way to convert colored CAShapeLayers to SVG?
import UIKit
import PocketSVG
class ViewController: UIViewController {
private var paths: [UIBezierPath]!
private var shapeLayerIndices = [CAShapeLayer:Int]()
private var touchedshapedLayerIndices = [CAShapeLayer:Int]()
private var shapeLayers = [CAShapeLayer]()
private var affineTransform: CGAffineTransform!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = Bundle.main.url(forResource: "simple", withExtension: "svg")!
paths = SVGBezierPath.pathsFromSVG(at: url)
let tigerLayer = CALayer()
for (index, path) in paths.enumerated() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayerIndices[shapeLayer] = index
tigerLayer.addSublayer(shapeLayer)
}
let scale = CGAffineTransform(scaleX: 1, y: 1)
let transform = CGAffineTransform(translationX: 100, y: 100)
affineTransform = scale.concatenating(transform)
tigerLayer.setAffineTransform(affineTransform)
view.layer.addSublayer(tigerLayer)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let point = touch!.location(in: self.view).applying(self.affineTransform.inverted())
guard let sublayers = self.view.layer.sublayers?[0].sublayers else { return }
self.touchedshapedLayerIndices = [CAShapeLayer:Int]()
for (_, sublayer) in sublayers.enumerated() {
if let sublayer = sublayer as? CAShapeLayer, let path = sublayer.path {
if path.contains(point) {
touchedshapedLayerIndices[sublayer] = self.shapeLayerIndices[sublayer]
}
}
}
let topShapeLayer = touchedshapedLayerIndices.max { a, b in a.value < b.value }
guard topShapeLayer != nil else {
return
}
let sublayer = topShapeLayer!.key
let index = topShapeLayer!.value
sublayer.removeFromSuperlayer()
sublayer.fillColor = UIColor.red.cgColor
self.view.layer.sublayers?[0].insertSublayer(sublayer, at: UInt32(index))
}
}
You'll have to iterate over the path array(and change its type to [SVGBezierPath]), then for each of the paths, use pathBySettingSVGAttributes: with the svg attributes you want to change. It'll return a new path reflecting the changes.
something like
let attributeSet = SVGMutableAttributeSet()
let paths = shapeLayers.map { layer in
let path = paths[shapeLayerIndices[layer]]
let newPath = path.pathBySettingSVGAttributes(["fill": layer.backgroundColor])
attributeSet.set(attributes: path.svgAttributes, forPath: newPath.CGPath)
return newPath.CGPath
}
let svgString = SVGStringFromCGPaths(updatedPaths, attributeSet)
I haven't actually compiled the above, but the general idea should work.
Thanks a lot! I will try it and share the results.
Hello,
I have tried your code. I got the error in below. I tried to give color parameter as UIColor and CgColor but neither of them worked.

Thanks,
I had the same problem, and I modified the code myself to keep it from crashing
for(NSString *key in pathAttrs) {
if(![pathAttrs[key] isKindOfClass:[NSString class]]) { // Color
[svg appendFormat:@" %@=\"%@\"", key, hexTriplet((__bridge CGColorRef)pathAttrs[key]).string()];
if (CFGetTypeID((__bridge CFTypeRef)(pathAttrs[key])) == CGColorGetTypeID()) {
float const alpha = CGColorGetAlpha((__bridge CGColorRef)pathAttrs[key]);
if(alpha < 1.0)
[svg appendFormat:@" %@-opacity=\"%.2g\"", key, alpha];
}
} else
[svg appendFormat:@" %@=\"%@\"", key, pathAttrs[key]];
}
@CodeForRabbit It'd be great if you could make a PR with that
fixed via https://github.com/pocketsvg/PocketSVG/pull/214