-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How can I save and restore drawings from the canvas? #21
Comments
see #18 |
issue #18 help in save as image. But I want to restore the same drawing and user can select the drawing and remove it like Google keep. |
Ohh I get it. Sorry, I misread your question. This is an issue I've been working on for a while. Doing it the image way is simple, but is not really a great solution because you can't edit it anymore. |
Thank you for sharing. |
Let me know if you find a solution that we could use for the library. Would be a great addition :) |
I've been able to accomplish this by storing the |
What exactly did you manage to store? Using Pathology? |
I build my own simple drawing app which temporary stores the lines as structs (similar to your approach). I made those line struct codable therefore I can export the array of line structs as JSON. I retrieve the drawing by decoding the JSON to the array of line structs and updating the view. I tested a drawing with roughly 2000 CGPoints and it took less than a second to display the drawing in the UIView. Let me know if you have any questions! |
@lucashoeft sounds great! Would you like to share your implementation? Did you use SwiftyDraw for your app or some other library/custom solution? |
Yeah, sure. I followed the tutorial on YT: https://www.youtube.com/watch?v=E2NTCmEsdSE (it's a three part series) so I did not use SwiftyDraw, but complexity should be similar The structs (simplified): struct Canvas: Codable {
var lines: [Line]
}
struct Line: Codable {
var points: [CGPoint]
var color: String
var strokeWidth: Float
var strokeOpacity: Float
var lineStyle: String
} The User Input in the UIView var canvas = Canvas()
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
canvas.lines?.forEach { (line) in
context.setStrokeColor(UIColor.init(hex: line.color)?.cgColor ?? UIColor.black.cgColor)
context.setLineWidth(line.strokeWidth)
context.setLineCap(.round)
context.setLineJoin(.round)
for (i, p) in line.points.enumerated() {
if i == 0 {
context.move(to: p)
} else {
context.addLine(to: p)
}
}
context.strokePath()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
canvas.lines?.append(Line(points: [], color: strokeColor, strokeWidth: strokeWidth, strokeOpacity: strokeOpacity, lineStyle: "Line"))
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else { return }
guard var lastLine = canvas.lines?.popLast() else { return }
lastLine.points.append(point)
canvas.lines?.append(lastLine)
setNeedsDisplay()
} The export functions (the conversion to string is optional as I wanted to use strings for testing saving/retrieving locally): func getDrawing() -> String {
let jsonEncoder = JSONEncoder()
let jsonData = try! jsonEncoder.encode(canvas)
if let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) {
return jsonString
} else {
return ""
}
}
func setDrawing(jsonString: String) {
let jsonDecoder = JSONDecoder()
let retrievedCanvas = try! jsonDecoder.decode(Canvas.self, from: jsonString.data(using: .utf8)!)
canvas = retrievedCanvas
setNeedsDisplay()
} |
@lucashoeft thanks for sharing! the implementation of the drawing logic looks pretty similar as far as I can tell. I will try to integrate this into SwiftyDraw and see if I can get it to work. Will keep you posted :) |
Yikes. Forgot to follow up on this. Sorry guys. Looks like @lucashoeft has the right idea. |
@EvanCooper9 you can still share what you've done if you'd like. We can compare the approaches and see which one works best for SwiftyDraw :) |
@lucashoeft I've checked out your code above. Regarding the drawing itself: when drawing really fast, the lines get very choppy. Any idea how to deal with that? |
It's because of the "simple" drawing function (it only connects the detected touches/points with direct lines.. for (i, p) in line.points.enumerated() {
if i == 0 {
context.move(to: p)
} else {
context.addLine(to: p)
}
}
context.strokePath() In SwiftyDraw, MidPoints get calculated and added to the array of points to have more entries to display a smoother line. I'm not sure if it is |
@lucashoeft I figured that, but how do we combine the two approaches? The thing is that |
I have same issue. I solve it by converting CGmutablePath to UIBezierPath to store in Coredata.then convert again UIbaizerPath to CGmutablePath to display on SwiftyDrawView. Following is Code to Store CGmutablePath in Coredata :
Following is code to Create CGmutablePath From UIbaizerPath
following is extension to get Pathelement From UIbaizerPath
|
Cool, thanks @bhaveshbc for sharing. Does your code:
|
|
Cool, then I'll try it out and merge into the repo if suitable. |
So I just tried to implement your code and I have a couple of questions:
Would appreciate your help on this! |
HI @LinusGeffarth sorry for late response.
https://www.dropbox.com/s/adswe9z4cl6cbq3/DemoMLView%2019.zip?dl=0 |
@bhaveshbc so far I've not been able to get your code running. Would you mind forking the project and creating a PR? That'd be really helpful! |
@kwccheng hey, see my comment from above about why that does not work as one would expect... |
What do you mean by that? |
I've managed to convert CGMutablePath to Data (and base64). // encoding
let cgMutablePath = line.path
let uiBazierPath = UIBezierPath(cgPath: cgMutablePath)
let data = try? NSKeyedArchiver.archivedData(withRootObject: uiBaizerPath, requiringSecureCoding: false)
let base64String = data?.base64EncodedString() // decoding
let data = Data(base64Encoded: base64String)
let uiBaizerPath = try! NSKeyedUnarchiver.unarchivedObject(ofClass: UIBezierPath.self, from: data)
let cgMutablePath = uiBaizerPath.cgPath as! CGMutablePath I used this code to send/receive SwiftyDraw Lines using Firebase Realtime Database. |
@blu3mo thanks for you contribution. How fast is the de-/encoding though? Can you load very many lines at a high speed? |
It took about 0.01s for encoding, 0.005s for decoding + presenting the drawing below. (156 strokes) |
Cool. Can you open a PR? |
Could you check my PR? |
I think this issue can be closed. |
How can I save the drawing to a database and later on give the possibility to edit or add new content to the same drawing?
The text was updated successfully, but these errors were encountered: