Drawing on a zoomable view
drawing, ios, uiview
Solution
This is a pretty complicated problem, that I have struggled a lot with.
I ended up converting the drawings to vector.
- draw all lines in one layer, draw all fills in another.
- Convert the line drawings to Vector, using potrace (http://potrace.sourceforge.net/)
- draw the vector using SVGKit (https://github.com/SVGKit/SVGKit) and hide the layer drawn in 1)
It is working pretty well and fairly fast, but it requires a lot of work. We have an app in our company that applies this technique:
https://itunes.apple.com/us/app/ideal-paint-hd-mormor/id569450492?mt=8.
If your only problem is performance, try taking a look at `CATiledLayer`. (also used in app mentioned above). It will increase performance tremendously (You can find a pretty good tutorial here http://www.cimgf.com/2011/03/01/subduing-catiledlayer/).
Good luck! :)
Problem
I'm working on a small drawing application, which has a basic requirement of supporting zoom-in/out. I have two main issues: Drawing doesn't appear crisp and clear, when view is zoomed/transformed. Is there a better approach, or is there a way to improve the drawing when the view is zoomed? The drawing performance is slow, when drawing on 1200 x 1200 pts canvas (on iPhone). Any chance I can improve it for large canvas sizes? Zooming Code: ``` - (void)scale:(UIPinchGestureRecognizer *)gestureRecognizer { [self adjustAnchorPointForGestureRecognizer:gestureRecognizer]; UIView *canvas = [gestureRecognizer view]; if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) { // Calculate the drawing view's size CGSize drawingViewSize = ...; // Calculate the minimum allowed tranform size // Developer's Note: I actually wanted to use the size 1/4th of the view // but self.view.frame.size doesn't return the correct (actual) width and height // It returns these values inverted i.e. width as height, and vice verse. // The reason is that the view appears to be transformed (90 degrees). // Since there's no work-around this, so for now, I'm just using fixed values. CGSize minTranformSize = CGSizeMake(100.0f, 100.0f); if ((minTranformSize.width > drawingViewSize.width) && (minTranformSize.height > drawingViewSize.height)) { minTranformSize = drawingViewSize; } // Transform the view, provided // 1. It won't scale more than the original size of the background image // 2. It won't scale less than the minimum possible transform CGSize transformedSize = CGSizeMake(canvas.frame.size.width * [gestureRecognizer scale], canvas.frame.size.height * [gestureRecognizer scale]); if ((transformedSize.width <= drawingViewSize.width) && (transformedSize.height <= drawingViewSize.height) && (transformedSize.width >= minTranformSize.width) && (transformedSize.height >= minTranformSize.height)) { canvas.transform = CGAffineTransformScale([canvas transform], [gestureRecognizer scale], [gestureRecognizer scale]); } [gestureRecognizer setScale:1.0]; } else if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { // Recenter the container view, if required (piece is smaller than the view and it's not aligned) CGSize viewSize = self.view.bounds.size; if ((canvas.frame.size.width < viewSize.width) || (canvas.frame.size.height < viewSize.height)) { canvas.center = CGPointMake(viewSize.width/2, viewSize.height/2); } // Adjust the x/y coordinates, if required (piece is larger than the view and it's moving outwards from the view) if (((canvas.frame.origin.x > 0) || (canvas.frame.origin.y > 0)) && ((canvas.frame.size.width >= viewSize.width) && (canvas.frame.size.height >= viewSize.height))) { canvas.frame = CGRectMake(0.0, 0.0, canvas.frame.size.width, canvas.frame.size.height); } canvas.frame = CGRectIntegral(canvas.frame); } } ``` Drawing Code ``` - (void)draw { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); if (self.fillColor) { [self.fillColor setFill]; [self.path fill]; } if ([self.strokeColor isEqual:[UIColor clearColor]]) { [self.path strokeWithBlendMode:kCGBlendModeClear alpha:1.0]; } else if (self.strokeColor) { [self.strokeColor setStroke]; [self.path stroke]; } CGContextRestoreGState(context); } ```