The Proper Care And Feeding Of Husbands Free Download UPDATED

The Proper Care And Feeding Of Husbands Free Download

[This was the topic of my presentation at the NYC Cocoaheads meeting last night. I thought it would be prissy to also mail on the topic hither.]

[I've received email from Ken Ferry. Meet addendum at the bottom]

NSImage is a troublesome grade. Over the years, information technology'due south been misunderstood and driveling. I call up much of this is because of a lack of conceptual clarity in the docs and examples and the API itself can exist confusing and misleading. Add to this having to mix with CGImage and CIImage and you can end upward with a confused mess.

The way I like to call back of NSImage is that it's a semantic image. When you look at icons, they are made upwards of several versions at unlike resolutions. Technically, it'southward 4 or v images but NSImage wraps those all up into ane notion of an image. Semantically, information technology is an icon of, say, a house but underneath it's made up of several actual images of a house. The primary reason for these different versions is that some graphics practice not scale well and information technology helps to have hand tuned versions, especially for the smaller sizes. Yous tin too practice things like omit certain features in the smaller sizes to simplify the graphics and make the icon more recognizable.

1 key misunderstanding is the notion that NSImage has actual paradigm data. While there are parts of the API that bargain with a cached bitmap (more than on this beneath), NSImage itself is not based on image data. It is all-time to think of NSImage as a mediator between the image data in the diverse representations and the drawing context.

Structure3

Loading an image from a file and cartoon information technology is commonly straightforward. If there are multiple representations, NSImage will figure out the correct one to employ when drawing it. Most of this is automatic and is an important key to agreement how to utilize NSImage. As yous will come across further on, bypassing this mechanism leads to many issues with size and resolution mismatches when processing NSImages.

I've created a piddling program to help illustrate the points in this article. Since information technology also includes a new reusable course, I've included it in my NoodleKit repo. I suggest checking information technology out. Just compile and run the ImageLab target (y'all may need to set up the active executable in XCode in the projection carte). The rest of this article will exist referring to it so I recommend you run information technology while reading the rest.

When you lot launch the app, information technology will load the test paradigm. Information technology's simply a colored circumvolve. At present resize the window. You'll see that the colour changes equally you resize. The icon itself is made up of four different sized images and to make it articulate which representation is being used, I made the circle dissimilar colors for each one. Whenever the colour changes when you resize, NSImage is switching to a different representation based on the size. Hither's what the different reps await like in Preview:

original

Size is some other confusing attribute of NSImage. One matter to recollect is that size is not pixels. It represents a coordinate space. One mode to think of it is that NSImage's size is like NSView'southward frame while NSImageRep's size is like NSView's bounds. For NSImage, its size is a suggested size to depict the image in the user coordinate space. If possible, it's best to explicitly specify the destination rect.

Let's take the example of drawing some custom graphics on pinnacle of an existing icon with several representations, like cartoon a badge over your app icon. A common way to do this is to lock focus on the NSImage, practise your cartoon, unlock focus and so describe the resulting image. What -lockFocus actually does is permit you to depict into a cache. This has probably atomic number 82 to a lot of the misunderstanding that NSImage holds paradigm information. Unfortunately, there are issues with this approach. Mainly, considering there is no context most where this image will be drawn and so the resulting prototype is tied to a specific resolution. Also, you lot are editing a enshroud so none of this paradigm data is reflected in the original prototype reps and actually, from poking effectually, information technology's actually destructive in that it may stop up removing any other representations.

In our case here we are modifying an icon with dissimilar sized representations, what we end up doing is locking the resulting image into the size that happened to exist attack the original NSImage. In many cases, you may not know how and where this icon will be used but if any scaling is involved, you may end upwardly having an icon with the incorrect version being displayed. In the instance program, select "Modified (lock focus)" in the pop-up. Here it picks the 64×64 version (as indicated by the green circle) which becomes a problem when you scale the image upward as shown on the left in the image below.

lockFocus

The i on the right is a version which uses an  NSImageRep subclass (select "Modified (custom image rep)" in the pop-upward). Notice that it picks the appropriate size as you lot resize the window. Why is this the case? It'south because NSImage doesn't ask the paradigm rep to describe until the NSImage itself is drawn. At that point, you really have information about the destination, including how big it will actually appear on screen. NSImage is able to employ this context to decide the right match betwixt dissimilar sized images and the resolution of the output context. The same goes for whatever drawing code.

Subclassing NSImageRep is quite piece of cake; you simply demand to override the -draw method. I've made it even easier by providing NoodleCustomImageRep which takes a cake, allowing you to create images without creating a new bracket.

Say, though, you are drawing an image that should scale without pixellation, like cartoon a square. Surely, you can just lock focus on an NSImage and depict a square and scale that as needed? Well, Mr Smarty Pants, accept a wait at the case program. Select "Fatigued (lock focus)" in the popular-upwardly.

square

Here, you'll see odd fuzziness around the edges. What'due south going on here? It's not anti-aliasing only instead the graphics context where the image is existence drawn has image interpolation turned on. As a upshot, the AppKit is trying to interpolate the paradigm from it's original size to a much bigger size.

How practise you fix this? You could try turning off paradigm interpolation in the destination graphics context but this isn't ever possible or desirable. The better solution is just like before: use a custom paradigm rep to exercise the drawing (select "Drawn (custom paradigm rep)" from the pop-upward). Since the drawing occurs at drawing time, instead of image creation fourth dimension, it knows near the context it is cartoon into and therefore can provide your cartoon code with a context at the right resolution. The well-baked square on the right speaks for itself.

Let'southward take some other example. Say we want to take an existing image and run a Core Prototype filter on it. Somehow you lot have to convert your NSImage into a CIImage. This usually entails a game of connecting upward various methods that fit together until you got a CIImage. A common fashion to do this is:

ciImage = [CIImage imageWithData:[nsImage TIFFRepresentation]];

This dumps the whole paradigm (all of its representations) into TIFF format which is in plow, re-parsed back into data. Now, CIImage is pixel based then it ends up picking one of the representations. It'south not documented which representation is picked since there'southward no way to specify the context where it volition be drawn so there'due south a chance it won't exist the correct one. Select "Cadre Image (TIFF Rep)" in the pop-up and you lot go something like the epitome on the left (or maybe y'all won't; read on):

coreImage

Now, it doesn't look besides bad here. It took the highest res representation and used that. That said, technically, information technology's non correct. The version on the right (select "Core Image (custom rep)") shows the correct image rep being used. Also, my experience has shown that the representation chosen by the -imageWithData: method can be different on different hardware and that it ignores the size set on the original NSImage so you may non be so lucky depending on what machine your code runs on.

Fortunately, Snow Leopard introduced a new method: -CGImageForProposedRect:context:hints:. As mentioned before, when yous depict an NSImage into a context, it will automatically selection the right representation for that context. This method does basically the same thing just without the drawing part. Instead it returns a CGImage which y'all can and then use to create your CIImage:

          cgImage = [nsImage CGImageForProposedRect:&rect context:[NSGraphicsContext currentContext] hints:nil]; ciImage = [CIImage imageWithCGImage:cgImage];        

Keep in mind, though, that information technology the paradigm returned might non be the exact size you wanted. This becomes more of an issue when you are combining multiple images together in a CIImage pipeline and you need them all to be the same size. You can adapt for this by using CIImage's -imageByApplyingTransform:.

In addition to the above method, Snow Leopard introduced -bestRepresentationForRect:context:hints: which does a similar thing but returns an image rep instead. Depending on your needs, yous can use one or the other to tap NSImage's image matching logic.

Finally, a notation about performance. NSImage does go on a cache based on the drawing context. This helps for when you repeatedly depict the same prototype at the aforementioned size over and over. If you end upward sharing an NSImage beyond unlike contexts, you lot'll find that you are defeating the cache. For these cases, yous should be copying the NSImages. Retrieve that NSImages are just mediators between image data and cartoon context. NSImageReps are the actual image sources and, starting with 10.6, reps like NSBitmapImageRep practise re-create-on-write making it inexpensive to copy NSImages and their reps.

In the example app, there's a field which shows the time taken to brandish the epitome. You'll notice that when you resize the window, the cases which use a custom image rep are slower as it has to recache whereas the lockFocus cases don't since the image is static. If this becomes an result, you can turn off caching or use a stock-still resolution prototype during a live resize. Another more subtle piece of business is performance when drawing from the enshroud. If you lot click the "Redisplay" push button, it will crusade the image to be displayed once more. Since you aren't changing the size, the cached version can be used. Notice how the versions using the custom image rep are usually a smidgen faster than the lockFocus versions. I suspect what is happening is when y'all lockFocus on the image, yous lock the enshroud into a specific version and size. As a result, if yous are drawing at any other size, it has to scale the cached paradigm every time. With a custom paradigm rep, it'south cached at the exact size then the cache can be used as is.

What are the lessons here?

  1. When defining your image, you should use an NSImageRep subclass and override -draw. If you don't want to create a whole subclass just to create an image, use my NoodleCustomImageRep (included in NoodleKit) which allows you to pass in a cartoon block. Using an paradigm rep gives your drawing code better contextual information than you would go just drawing in a -lockFocus.
  2. If you follow bespeak #i, and so yous can let NSImage brand the conclusion of which representation to use. Apply  i of the drawing methods, -CGImageForProposeRect:... or -bestRepresentationForRect:... and you'll go the best sized representation for the job. Practice not presume, though, that this representation will be the bodily size you want. When drawing, it as well helps to specify the rect to draw into.
  3. Avert using -lockFocus. It doesn't produce the correct image in different contexts and tin be destructive in terms of kicking out the other reps in the NSImage. While still ok in specific circumstances, you have to know what y'all are doing.
  4. If using the same NSImage in different contexts, re-create it. In 10.six onwards, this is an cheap operation as bitmap data is re-create-on-write. Copying NSImages is is also a good thought in example some decides to use -lockFocus on the image (see #3).

If you have admission to it, I highly recommend watching the video for Ken Ferry'due south session at WWDC 2009: Session 111: NSImage in Snow Leopard (y'all may demand a developer account to view/download it). Much of this is derived from that presentation and information technology has even more than interesting $.25 about NSImage than what I've presented here.

And in case yous missed it above, y'all tin notice NoodleKit (which contains NoodleCustomImageRep equally well as the instance programme) hither.

Addendum (Apr. 18, 2011):

I received an email from Ken Ferry himself pointing out a couple things. Mainly, that as of ten.6, lock focusing doesn't draw into the enshroud anymore. Information technology creates a representation whose context is suited for the main brandish. It is even so skillful for images which are meant for that context. Also equally the NSImage context will maintain any size-to-pixel ratio that is on the master display, it can nonetheless exist used in this situation should resolution independence come into play. It's not much dissimilar than before in this respect but it's non as volatile as a cache, which I believe is the key point here.

That said, all the caveats above most using -lockFocus still hold true. Information technology'due south not so slap-up for when the image needs to be scaled or if yous have representations you want to keep (it does remove all other reps when you lock focus). Also, because the representation is tied to the motorcar, it'southward not very suitable for persisting.

DOWNLOAD HERE

Posted by: woodstant1976.blogspot.com

Post a Comment

Postagem Anterior Próxima Postagem

Iklan Banner setelah judul