Skip to content

Instantly share code, notes, and snippets.

View almaleh's full-sized avatar
💭
Indexing...

Besher Al Maleh almaleh

💭
Indexing...
View GitHub Profile
@almaleh
almaleh / SlowCPU-based.swift
Last active July 16, 2023 05:45
Slow CPU-based Drawing
class FreedrawingImageViewCG: UIImageView {
var currentTouchPosition: CGPoint?
override func layoutSubviews() {
super.layoutSubviews()
isUserInteractionEnabled = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
@almaleh
almaleh / FastCPU-basedDrawing.swift
Last active January 17, 2019 01:39
Fast CPU-based drawing
class FreedrawingView: UIView {
// we use a multi-dimensional array to store separate lines, otherwise
// all your lines will be connected
var lines = [[CGPoint]]()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// create a new line
lines.append([CGPoint]())
}
func calculateRectBetween(lastPoint: CGPoint, newPoint: CGPoint) -> CGRect {
let originX = min(lastPoint.x, newPoint.x) - (lineWidth / 2)
let originY = min(lastPoint.y, newPoint.y) - (lineWidth / 2)
let maxX = max(lastPoint.x, newPoint.x) + (lineWidth / 2)
let maxY = max(lastPoint.y, newPoint.y) + (lineWidth / 2)
let width = maxX - originX
let height = maxY - originY
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let newTouchPoint = touches.first?.location(in: self) else { return }
var lastTouchPoint: CGPoint = .zero
if let lastIndex = lines.indices.last {
// get reference to last point
if let lastPoint = lines[lastIndex].last { lastTouchPoint = lastPoint }
// add new point
var flattenedImage: UIImage?
var line = [CGPoint]() {
didSet {
checkIfTooManyPointsIn(&line)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
flattenImage()
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else { return }
// draw the flattened image if it exists
if let image = flattenedImage {
image.draw(in: self.bounds)
}
context.setStrokeColor(lineColor.cgColor)
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let newTouchPoint = touches.first?.location(in: self) else { return }
let lastTouchPoint: CGPoint = line.last ?? .zero
line.append(newTouchPoint)
let rect = calculateRectBetween(lastPoint: lastTouchPoint, newPoint: newTouchPoint)
layer.setNeedsDisplay(rect)
}
override func draw(_ layer: CALayer, in ctx: CGContext) {
// 1
let drawingLayer = self.drawingLayer ?? CAShapeLayer()
// 2
drawingLayer.contentsScale = UIScreen.main.scale
// 3
let linePath = UIBezierPath()
// 4
for (index, point) in line.enumerated() {
if index == 0 {
func checkIfTooManyPoints() {
let maxPoints = 25
if line.count > maxPoints {
updateFlattenedLayer()
// we leave two points to ensure no gaps or sharp angles
_ = line.removeFirst(maxPoints - 2)
}
}
func updateFlattenedLayer() {
// 1
guard let drawingLayer = drawingLayer,
// 2
let optionalDrawing = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(
NSKeyedArchiver.archivedData(withRootObject: drawingLayer, requiringSecureCoding: false))
as? CAShapeLayer,
// 3
let newDrawing = optionalDrawing else { return }
// 4