NSImage Drawing / Text Rasterization Woes

Hi, All:


I've been trying to solve a problem for awhile now and can't seem to get a handle on it. My application draws complex charts and graphs with text, etc. (called a "Figure" in this app). The application must export publication-quality PDF. All drawing is done with Quartz 2D commands in -drawRect:. It seems the use of -[NSImage lockFocus] and -[NSImage unlockFocus] always consistently rasterizes the text in these images as of the introduction of +[NSImage imageWithSize:flipped:drawingHandler], so I switched all my drawing to this method.


Unfortunately, because of the time it takes these very complex (many-thousand-point graphs, for example) figures to render, the deferred drawing causes all sorts of timing issues when the figure is invalidated and waiting for its associated query to be refreshed before initiating drawing of the figures. This means that many rapid changes or even selection changes (which dump an unneeded query's cached data if it's not being viewed) cause the rendered image to use a random mix of old vs. new cached data.


So I truly believe I need to render the image immediately, when I request it, not when the system feels it's necessary. If that means I need it to do so at maximum depth/resolution/quality/whatever, so be it. But -lock/unlockFocus ruin the image by rasterizing text.


So, is there a way to simultaneously:


  1. Force the image to draw immediately (ie, be able to use -lock/unlockFocus),
  2. Avoid rasterization of anything in the image
  3. Still look good no matter what (Retina or non-) screen it's displayed on (including while zoomed in)


I'd deeply appreciate any help anyone can offer.

You're going to have to unpack this a bit. It's not clear what the role of the NSImage is (used in drawing the view that the user sees on the screen? used in creating PDFs? both?). If you're drawing in drawRect, why are lockFocus/unlockFocus involved?


If you're creating a high-quality image in drawRect, using that immediately to satisfy the current view's redrawing needs and saving it in case you need it again (for an export?), then drawRect is the wrong place to do it, I'd say. Expensive setup (creation of a complex image) is best done prior to drawRect being invoked, especially if the information is effectively to be cached anyway. drawRect itself should be thought of as time-critical.


Also, in general, if you want to control the format of an image (vector rather than raster, which seems to be what you're saying) you're better off working directly with a suitable NSImageRep subclass, instead of trying to coax NSImage into using the correct image rep behind the scenes.


Finally, it's not clear why you would expect preparation of a representation for the screen would/could be shared with the preparation of a PDF representation.


Presumably, these queries are just because I'm not following what you've already thought out, but I think you're going to need to clarify before anyone can help.

Accepted Answer

Thanks for replying. I have to apologize - I was a little rushed when I wrote all that and mistakenly mentioned -drawRect:. I've actually just solved the two main issues I was having. Here's a post-mortem:


My model object (Figure) does its own drawing (with lots of caching mechanisms) and its resulting image is used by an NSImageView on screen, and its PDF data is provided for export. Essentially, what I've discovered is that the low resolution is expected when using -lock/unlockFocus on NSImage instances. The correct behavior, which I somehow missed in the documentation the last time I visited this problem (and for a few hours this time), is to add an NSPDFImageRep to the image manually. This has resolved my resolution problem using the newer drawing handler method.


I solved the "render it now, please" issue by immediately caching the PDF data for the image (which my Figure class holds as a property now vs. an on-demand method) alongside the image itself (dumping both when the figure is invalidated and its caches are cleared, pending computation). This is called when the figure is asked to update (which does its little caching dance for ranges, labels for max label sizes for column widths, etc.), which forces the image to render when I expect it to.


So all appears to be well. Thanks again for taking the time to reply and sorry again for the too-fast posting. I'm a bit out of practice asking questions on technical forums and allowed frustration and a pending deadline to cloud my posting. ;-)

NSImage Drawing / Text Rasterization Woes
 
 
Q