2

In the Video Session 506 of Apples WWDC 2012 they showed a painting app which is made for high performance drawings (so the frame rate never gets below 30).

I tried to replicate the code but get stuck on multiple points.

What I am looking for is a basic drawing app (lines, Squares, Circles, bezier paths), which performs well even after hundreds of lines have been drawn.

The basic approach is to save the drawn lines (or circles bezierpaths etc) to an image after a certain numbers of them have been drawn, and then only refresh the new drawings, therefore not having to redraw all the already drawn lines.

But somehow I never get to a higher performance. How do I need to implement this? Do I need multiple layers? And how do I manage that not all layers in a view are redrawn, but only a certain sublayer?

If someone could provide me with a short example of a few lines drawn on an layer, then saving that layer to an image, an then drawing on top of that I would really appreciate it.

Thank you for any help to recreate the iPaint application, which is unfortunately not available for download from apple.

STW
  • 44,917
  • 17
  • 105
  • 161
Aranir
  • 828
  • 1
  • 10
  • 21

2 Answers2

1

I did not look at that session, but a traditional Quartz speedup has been to use CGLayers (not CALayers). You can think of a CGLayer as a cached drawing which may or may not be a bitmap (the system decides how best to cached it). If you have a backing bitmap context, you can use that as your "image" and draw the CGLayers into that (and then discard the layers) as you see fit. Read up on CGLayer (its in the Quartz documentation) and then see if this was what they talked about in that session.

David H
  • 40,852
  • 12
  • 92
  • 138
  • 1
    That is indeed what they talked about. Download the sample code dog from the dev site. This should be in there. – W Dyson Sep 11 '12 at 11:42
  • Actually, CGLayer hasn't been touched or updated in a long time. It's been silently unloved, unfortunately: http://iosptl.com/posts/cglayer-no-longer-recommended/ – borrrden Sep 11 '12 at 12:35
  • I read the Rob Napier link (and saw your comments :-)) - what Rob said Apple did recommend was CALayer instead of a CGLayer. So this same technique I described could be used, if the size of the layers is small compared to the view size, and the anticipated "hit" rate is low, then you draw into a bit map context, create a CGImageRef, and use that to represent a "layer". Then later, in drawRect (as described by @borrrden), you hit test each layer and only draw those that are in the update rectangle. – David H Sep 11 '12 at 14:00
  • Hello @DavidH, please have a look at this http://stackoverflow.com/questions/21143614/adding-a-quadcurve-to-uibezierpath – Ranjit Jan 20 '14 at 11:14
1

That is only half of the puzzle. The other half is to only refresh the minimum possible area of the view (via setNeedsDisplayInRect:). However, I have been through many different ways of drawing via Core Graphics. The caching is fine, but I don't use it anymore. I set the update rectangle as above, and then test each path before I stroke it (testing is fast, stroking is slow). If it is inside the update box, I stroke it, otherwise I ignore it.

borrrden
  • 33,256
  • 8
  • 74
  • 109
  • I agree, this is the best practice inside the drawRect:. Its too bad about CGLayer - I used it in the past with great success, and if it was/is a viable solution you could use the hit test on it as well. – David H Sep 11 '12 at 13:55
  • @DavidH I also was using CGLayer for a while, but ultimately I stopped (for project requirements, not because of performance. The performance was actually very good). It works well in certain situations, it is just hard to predict what those situations are. – borrrden Sep 11 '12 at 14:33
  • I tried it and the performance is sufficient for the moment, although I need to flatten the image after a a certain number of lines has been drawn to keep the performance up. Additionally going to all UIBezierpaths helped the performance aswell. – Aranir Sep 24 '12 at 13:25