Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing on a zoomable view

I'm working on a small drawing application, which has a basic requirement of supporting zoom-in/out. I have two main issues:

  1. 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?

  2. 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);
}
like image 703
Mustafa Avatar asked Aug 12 '13 07:08

Mustafa


People also ask

Can I sketch on Zoom?

Using an iPad to draw or annotate. Zoom includes a built-in collaborative digital whiteboard that an instructor and students can draw on together in real-time. It works with a mouse, touchpad, or touch screen on most devices (Windows, Mac, Linux, Android, iPad, but NOT iPhone).

Can the host see who is drawing on Zoom?

How to Know Who Is Scribbling in Zoom. To know who is currently annotating in Zoom, you need to enable a setting for the same. Only the person who initiated the sharing process can enable the setting. After it is enabled, all the participants can see the name of the person who is drawing.


1 Answers

This is a pretty complicated problem, that I have struggled a lot with.

I ended up converting the drawings to vector.

  1. draw all lines in one layer, draw all fills in another.
  2. Convert the line drawings to Vector, using potrace (http://potrace.sourceforge.net/)
  3. 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! :)

like image 87
EsbenB Avatar answered Nov 15 '22 05:11

EsbenB