How to convert UIBezierpath to SVG?
firattamur opened this issue · 8 comments
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.
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 #214