Question

This is a self-answering question in gratitude to the various help I've gained off both StackOverflow and the Ray Wenderlich tutorial on drawing. I thought I'd put the various snippets together in one package.

My problem was that I wanted to do freehand drawing on a pdf larger than the iphone screen size. I therefore chose UIScrollView to handle the extra size, but as other posts have indicated, you then get into the following issues:

  • discriminating between pan/pinch and drawing
  • handling corrections to coordinates on a zoomed view

in this question Objective C: Drawing with Fingers on UIScrollView apouche gave me a great pointer to fixing the first issue. He suggested the use of custom UIPanGesturerecognizers to distinguish between drawing and scrolling. I found that the confusion over one vs two-finger scrolling was still a bit clumsy, so I used either the selection of the pencils, or a UISegmentedControl in the navigation bar, to select between pan and draw, and whether pinch would work by setting a BOOL drawActive.

Here's the viewDidLoad code:

- (void)viewDidLoad
{
    [super viewDidLoad];


    self.tempDrawImage.userInteractionEnabled =YES;
    cumTranslation = CGPointMake(0,0);
    [panDrawSelect setSelectedSegmentIndex:0];
    drawActive = NO;
    red = 0.0/255.0;
    green = 0.0/255.0;
    blue = 0.0/255.0;
    brush = 3.0;
    opacity = 1.0;

    NSURL *pdfUrl = [NSURL fileURLWithPath:loadPath];
    document = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdfUrl);
    currentPage = 1;
    CGPDFPageRef page = CGPDFDocumentGetPage(document, currentPage);
    pageRect = CGPDFPageGetBoxRect(page, kCGPDFTrimBox);
    NSLog(@"page width = %f", pageRect.size.width);
    NSLog(@"page height = %f", pageRect.size.height);
    pdfScale = self.view.frame.size.width/pageRect.size.width;
    pageRect.origin = CGPointMake(0,0);
    NSLog(@"page width = %f", pageRect.size.width);
    NSLog(@"page height = %f", pageRect.size.height);
    UIGraphicsBeginImageContext(pageRect.size);


    CGContextRef context = UIGraphicsGetCurrentContext();

    // White BG
    CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
    CGContextFillRect(context,pageRect);

    CGContextSaveGState(context);


    CGContextTranslateCTM(context, pageRect.size.width*0.75, pageRect.size.width+44);
    CGContextScaleCTM(context, 1, -1);
    CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(page, kCGPDFTrimBox, pageRect, 0, true));
    CGContextRotateCTM(context, -1.5707);
    CGContextDrawPDFPage(context, page);
    CGContextRestoreGState(context);
    UIImage *image =UIGraphicsGetImageFromCurrentImageContext();
    initImage = image;
    tempDrawImage =[[UIImageView alloc] initWithImage:image];


    //CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
    scrollView = [[UIScrollView alloc] initWithFrame:pageRect];
    scrollView.delegate = self;
    scrollView.minimumZoomScale = 0.3;
    scrollView.maximumZoomScale = 3.0;

    scrollView.contentSize= pageRect.size;
    NSLog(@"page width = %f", pageRect.size.width);
    NSLog(@"page height = %f", pageRect.size.height);

    [scrollView addSubview:tempDrawImage];
    [self.view addSubview:scrollView];
    [self.view sendSubviewToBack: scrollView];


    UIPanGestureRecognizer *Scrolling  = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onScroll:)];

    UIPinchGestureRecognizer *Zooming   = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onZoom:)];


    [scrollView addGestureRecognizer:Scrolling];
    [scrollView addGestureRecognizer:Zooming];

    // Do any additional setup after loading the view.
}


- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView

{

    return tempDrawImage;
}

I then used the following code in the onScroll method:

- (void)onScroll:(UIPanGestureRecognizer*)sender
{
    if (!drawActive) {
        CGPoint translation = [sender translationInView:self.view];
        sender.view.center = CGPointMake(sender.view.center.x + translation.x,
                                         sender.view.center.y + translation.y);
        [sender setTranslation:CGPointMake(0, 0) inView:self.view];
        cumTranslation = CGPointMake(cumTranslation.x + translation.x,
                                     cumTranslation.y + translation.y);
         }
    else {// Processing the drawing by using comparing:
        if (sender.state == UIGestureRecognizerStateBegan)
        { /* drawing began */

            mouseSwiped = NO;

            lastPoint = [sender locationInView:self.tempDrawImage];
            scaleLastPoint.x = lastPoint.x*scrollView.zoomScale;
            scaleLastPoint.y = lastPoint.y*scrollView.zoomScale;

        }

        else if (sender.state == UIGestureRecognizerStateChanged)
        { /* drawing occured */


            mouseSwiped = YES;

            CGPoint currentPoint = [sender locationInView:self.tempDrawImage];

            CGPoint scalePoint;
            scalePoint.x = currentPoint.x*scrollView.zoomScale;
            scalePoint.y = currentPoint.y*scrollView.zoomScale;

            UIGraphicsBeginImageContext(self.tempDrawImage.frame.size);
            [self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.tempDrawImage.frame.size.width, self.tempDrawImage.frame.size.height)];
            CGContextMoveToPoint(UIGraphicsGetCurrentContext(), scaleLastPoint.x, scaleLastPoint.y);
            CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), scalePoint.x, scalePoint.y);
            CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
            CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
            CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
            CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);

            CGContextStrokePath(UIGraphicsGetCurrentContext());
            self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
            [self.tempDrawImage setAlpha:opacity];
            UIGraphicsEndImageContext();

            scaleLastPoint = scalePoint;

        }
        else if (sender.state == UIGestureRecognizerStateEnded)
        { /* drawing ended */
            if(!mouseSwiped) {
                UIGraphicsBeginImageContext(self.tempDrawImage.frame.size);
                [self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.tempDrawImage.frame.size.width, self.tempDrawImage.frame.size.height)];
                CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
                CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
                CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, opacity);
                CGContextMoveToPoint(UIGraphicsGetCurrentContext(), scaleLastPoint.x, scaleLastPoint.y);
                CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), scaleLastPoint.x, scaleLastPoint.y);
                CGContextStrokePath(UIGraphicsGetCurrentContext());
                CGContextFlush(UIGraphicsGetCurrentContext());
                self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
                UIGraphicsEndImageContext();
            }}

To compensate for zoom, to ensure that the drawing annotation wasn't offset, I used the scaling included above, but highlighted here:

lastPoint = [sender locationInView:self.tempDrawImage];
                scaleLastPoint.x = lastPoint.x*scrollView.zoomScale;
                scaleLastPoint.y = lastPoint.y*scrollView.zoomScale;  
Was it helpful?

Solution

The answer is in the question itself

here is the output:

pan/zoom and draw screen

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top