Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2007-221
$eventId
ID of event: wwdc2007
$eventContentId
ID of session without event part: 221
$eventShortId
Shortened ID of event: wwdc07
$year
Year of session: 2007
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2007] [Session 221] Handling Im...

WWDC07 • Session 221

Handling Images with the Image Kit

Leopard Innovations • 1:06:12

Image Kit provides a powerful set of image-related services for Cocoa applications. Learn how Image Kit can help your application browse, view, and present common image formats using a standardized user interface. See how to use Image Kit to perform lightweight image editing and apply Core Image filter effects. Find out how Image Kit can even be used to create slideshows and take pictures with the iSight camera.

Speakers: Werner Neubrand, Thomas Goossens

Unlisted on Apple Developer site

Downloads from Apple

SD Video (260.4 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

Welcome to session 221, Dealing with the Image Kit Framework. Actually the Image Kit framework is a new framework that we have in leopard. And as the title basically says, it's an image- handling framework. So we deal with images in this framework. And the reason why we are doing this is basically, well, we get more and more images, digital cameras and so and the iPhone will be one of the sources how you can create images and you really want to deal on your computer, you want to deal with images.

So we have also more and more image handling applications. So for example, the Finder is the first one you will see when you boot up your system displaying a whole bunch of images in a single window. And now with the Quick Look technology really displaying icons for all these very nicely arranged and all that.

Then, of course, Preview, now the application that ships with the OS dealing with images. And you all know that you can open multiple images, like in a single window, browse through those images, display one, and do things with that. And of course, Image Capture and all the other bundles that we have. So what do all these applications have in common? What are they doing with images? Well, first of all, they deal with images finding and displaying, browsing the images.

And the other thing is really once you found the image that you want to, going to work with, and you want to display, then you want to bring it up in a single view. And you do that for images that are supported, for example, by the Image I/O framework. So a lower level framework dealing with all kinds of image formats such as JPEG, TIFF, PNG, and so on.

And of course, Image I/O it's getting more and more important since like higher end digital cameras produce the images in raw format, so we want to deal with those as well. And then we have, like as I said before, a whole bunch of image handling applications that display these images in the view.

So if its finding and browsing in one hand, the other hand the viewing and editing the images, then what could we do in the framework, in an image handling framework for Leopard to combine needs and have solutions for you to use in your applications, so that it will be a compelling reason to switch over to this new framework.

Well, if we look at the components that we came up with, first of all in image browser. So the goal is to have the view that you can very easily use that allows you to browse images. Second is something that you will see in applications like iChat, Account Panel, and all that, that's the picture taking part. Then displaying images, the ImageView. Then the Image Edit panel basically is set of common panels that allow you to do some image adjustments.

Then the built-in Slideshow, easy way for you to present images on a full screen. And a couple of other things that we will talk during this session. Now if we put all these components together, stir well, and then we should actually have something that you will, you can use as the Image Kit.

So the goal for this session was not to talk so much on slides, but really go into code and show you some examples and source codes that you could use in your application to make usage out of Image Kit. So the question was, like what could we do in a single session like a little bit more than an hour to produce the kind of useful application for you, and to show all the different parts of Image Kit? So we came up with an eyePhoto coding challenge. So the idea is we want to do certain things that the other iPhoto application could do.

And first thing, of course, as we said before, browsing. iPhoto has this, this, the real iPhoto has this very nice way to browse a very large library of files once you imported those. Well, we are not going into the database part, but we will produce an application that allows you to browse images.

And then we also want to import images from an "i" site, we're not talking a high-end digital camera, but we want to use either a built in, or in our case the add on "i" site. Then, of course, we want to view the image full size. We want to do some basic image manipulation.

We want to save the image out, ideally, in a way so that you open the image, maybe a JPEG, and you will be able to save it as TIFF, PNG, or whatever other format. And of course, last thing, we want to present it. So run a slideshow with the images that you imported.

Now all this really ends up in eyePhoto in six easy steps. And let's have a look at the first one, I actually want to bring up Thomas, the master of image browser.

[Thomas Goossens]

Thank you!

( Applause )

[Thomas Goossens]

Okay, so I'm Thomas Goossens, and I work on Image Kit, and especially on the image browser. So today I'm going to show how to use our image browser into a Cocoa application. And so let's start by introducing this image browser.

So the IKImageBrowserView is a view that you can use to display and to browse large amounts of images. So it lays out images in a grid like this, and user can scroll or zoom in, zoom out to browse the images. This view also come with a set of features as you will have for free.

Like for instance a graphical selection, drag and drop with reordering, accessibility, auto scrolling, type select, etc. But the major improvements this next year is now the capability to browse and preview any kind of document. So you can, of course, use the image browser to browse large amounts of images.

So here any kind of image formats supported by Image I/O such as a JPEG, TIFF, PNG, or whatever. But you can also use the IKImageBrowserView to browse your movies. And for movies the image browser supports inline preview. So you can play your movies right inside the image browser without having to switch to another application. So this is very practical to browse movies, and I will show you that in a little bit. You can also browse your PDF, so you can scroll over a large amount of PDFs and names.

But in fact they are not only some names, because if you decide to enlarge one of them by zooming in, then the image browser will redraw it to the actual size, and so this guaranteed to have the best quality to preview PDFs. And so we have a quality similar to what you will have in Preview for instance. And so you can even read the PDF directly in the browser.

And to finish you can now browse any kind of documents, thanks to Quick Look. So you can browse any kind of documents natively supported by Quick Look, such as HTML files, Contacts, Notes, Emails, Keynotes. But also if you write your own Quick Look plug-in for your own documents then you can use the IKImageBrowserView to browse your own documents in your own application.

So with image browser we really want to provide a very generic image browser so that you don't get to write your own anymore. By using this image browser you won't have to face usual issues when trying to support large amounts of data and trying to keep good performance and good quality. So the image browser is made to support large amounts of data so you won't have to worry about potential scalability issues. It is entirely run using the GPU, so it gives a very smooth and great user experience, especially on zooming and scrolling.

And to finish you won't have to deal and worry about potential memory issues, because Image Kit takes care of scheduling the memory for you by keeping less recently used images on the GPU to maximize performance. and keep older images compressed in RAM to minimize memory usage. And it automatically removes images from the memory when they are not needed anymore.

So today I am going to show how to use this image browser by creating step by step the first part of our eyePhoto application. So the first step will be to use Interface Builder to set up the interface and to add image browser to our window. So I will create a window with Interface Builder, then I will use Interface Builder to add the image browser to this window. And then we will need to embed this view, the image browser, into a scroll view to be able to scroll over the thumbnails.

Then the second step will be to implement a datasource, which will define which images should be displayed in the image browser. So datasource inside object implementing on the client's side, and it's goal is to provide the images to the image browser. So the image browser will ask the datasource for the images to layout and to display.

And when the developer wants to change the images in the image browser you just need to invoke real data on the image browser, and the image browser will automatically replace the changes of the datasource. So if you are already familiar with in NSTableView and NSOutlineView, here it's exactly the same datasource mechanism.

And implementing the datasource of the image browser is very simple, as you just need to implement two methods. So first, like for NSTableView the image browser needs to know who many images it asks to display, and this is done by returning the number of images in number of items in image browser. Then for each index the image browser will ask for an object, that will present the given image as a given index.

So here we will need to return an object in image browser itemAtIndex. And the object will return (unclear) response to the three methods. So the first one, imageUID is a unique identifier that must be different for each different images. So it can be whatever you want. It can be an absolute full path or UUID, but it must be different for two different images.

Then imageRepresentationType and imageRepresentation makes the integration of the image browser easier, because it lets you to choose your favorite image representation in the large set of possible representations. For instance, if you have a path or URL, then you can just give that to the image browser by specifying PathRepresentationType and ImageRepresentationType, and returning the path in imagRepresentation. And the image browser will do the job to load that file, create a thumbnail, and display it on the screen. So here you don't have to do anything.

And, however, if you don't have any paths, because your images doesn't exist on disk, and you only have it in memory, for instance, then you can choose to return either a CG or NSImage; a CGImageSourceRef or bitmap. So here just choose a image representation that you are more comfortable with.

And to finish you can also specify some kind of specific image representations like QTMovie and QCComposition if you want to have inline preview of your movies and compositions. You can specify QuickLookPath if you want the image browser to use Quick Look to create thumbnails of your documents. And you can also use iconRefRepresentationType if you want the image browser to use icon services to create preview of your documents, and so to display generic icons of your documents instead of for a preview. So now let's see how this looks like in Interface Builder and Xcode. Can you switch to the demo machine, please? So let me start with Interface Builder, so and I create a new Cocoa application. Let's create a window. Now I search for the IKImageBrowserView in the library.

And here it is, so you can see its the IKImageBrowserView class. I can drag and drop it to my window. Resize it so that it fit my window like that. Okay, and then just run the simulator. So as you can see by just doing that I can have a functional image browser with the graphical section working. We can change the section with the keyboard. I can also remove an image. I can, reorder also works for free. And for the moment that's all what we can do with Interface Builder, so let's do a bit more.

I can use the properties in Interface Builder to change some flavor, for instance, if I don't want shadow, or if I want an outline around the images. If I want a title in those images select title. I may also want to animate the changes of the datasource when needed.

And I can also change the default zoom value if I want to have the images bigger like that. And now I also want to be able to scroll over my images so I need to embed this view into a scroll view. Okay, I don't want horizontal scroller because it's not needed. And I change the autoresizing mask so that it fits the window. I run the simulator again.

So now I have an image browser, I can resize the window, I can scroll over my images. Now I also have titles so I can use type select to search for an image if I write ladybug, for instance. I can write tiger, okay? So autoscrolling works. Up. And so that's what I can also, yeah, delete images and now I made the changes.

And so now to continue we need to use Xcode. So, okay that. So here are the six steps of our application. I will start with the step one, of course, and that's the steps that you have in the coding at start. So let me open the first one.

And let me start by running this application, and then I will show the code that is needed to do that. With the first type of our application I can scroll over my images, but now I can also zoom out, zoom in like this, and you can see that it's not only thumbnail images are on there with best quality possible, it's a quality that you will have in preview.

I can also add other images with this button here. And for instance, if I add application directory you can see that it doesn't only support images, but in fact here generate icons. I can also; I have a nice search feature where I can search for a given file, I write iCal.

So here it's very simple, because I just filter my datasource array, and it automatically animates the changes of the datasource. I will show you that in a little bit with the codes. And I can continue to work and also reorder files, delete some items, and move other files like that.

So now let's have a look to the code. Here's the Controller of my application. I have an outlet connected to the image browser to be able to invoke real data and the image browser when I want to change the images displayed in the image browser. And then here I have an NSMutableArray that will contain the images I want to display in the image browser. And now let's have a look to the implementation of the datasource protocol. So, sorry, here it is.

Okay? So you can see that it's very straight forward, I just need to return the count of elements in my NSMutableArray, the number of items in image browser. And when the image browser asks for a given item at a given index, then I just return the object at index in my NSMutableArray. And as I said before in my slides, the objects are returned here must respond to the three methods: imageUID, imageRepresentationType, and imageRepresentation. So this object is here. It is MyImageObject. It just contains an absolute filepath.

And now the implementation of the three required methods is very simple, because I can just return this path in imageUID, and I will be sure that this path will be unique for two different images. Then in imageRepresentationType I return IKImageBrowserPathRepresentationType to tell the image browser I will just give him some paths and the image browser will load these paths itself and create thumbnails.

And so when the image browser ask for the image Representation I just give him the absolute path and I let him do the job to import it. I also implemented an optional method, which is imageTitle. And this is a title drawn under each image. So here I just returned the lastPathComponent of my absolute path to see the file name.

So now let's do something interesting by replacing IKIMageBrowserPathRepresentationType, and replacing it by IKImageBrowserQuickLook PathRepresentationType. So like this I will tell the image browser to use Quick Look to create previews of my given file path. Now let's also specifying QTMoviePaths for movies. Here I just test the extension of my files. I should test the UTI, but it's just for a demo, so that's fine.

And let's specify QCCompositionPath path for .qtz files. And now with a change just check how it be as now. So that the same application can remove the default images and how, uh storage, okay, how these files. So these files are not on images, but there is a lot of different kind of images, of documents, sorry. And so, for instance, if I search for C++ files, you can see that it's not only generic previews, but in fact the real code beyond the file.

Then I can also search for contacts. And you can see that you can use the image browser to browse forth, use image browser to create a kind of contact browser with really nice previews, thanks to Quick Look, like this. And as it supports large amount of images, let's say 300,000 images, I think it will support your contact list.

Okay, now you can, we can search for, for instance, MP3, yes, so here it displays the covers that you would have in iTunes. So I have only three MP3 then we had to convert, but that's a cover I would have in iTunes. I can search for Keynote files, and you can see that the preview for Keynote files are really nice, because they have a really good quality, thanks to Quick Look. And that's exactly what you would see by using Keynote. I can search for some emails, up, okay, and so I can preview, I can preview everything. I can preview emails, I can preview some notes.

I can search for to finish with some PDFs, because preview of PDF files really nice like for Keynote, that's the quality similar to preview here. I can also involves a lot of PDFs. And now let me show you how movies behaves in the image browser. So as I specified QTMovieRepresentationType for movies, the image browser automatically showed play control under the movies so that you can play these movies directly in the image browser. So if I click on the play button here it plays the movies directly in the image browser. I can continue to navigate while playing. I can continue to zoom in, zoom out, onto a scroll while playing the movie.

If I switch to another movie it automatically stops the previous one. So if I put in shows, some mixing issues. And that is same thing for QCCompositions. I can play, here the QCCompositions and to have a preview of QCCompositions right inside the image browser without having to switch to another application. And one more time. I can continue to, zoom in, zoom out, while playing the QCCompositions.

Okay? Can we go back to the slides please?

( Applause)

[Thomas Goossens]

So now we have a functional image browser in our eyePhoto application. So we can go to the single step of our application, which is to hide what we call a import; the import functionality to our eyePhoto application.

So image can provide another component named the picture taker. The picture taker is a simple panel to choose images to take snapshots using the iSight. And it gives some tools to enhance the image and to adjust the crop. So most of you already know and used this picture taker on tTiger, you can find this panel in a lot of application on like Setup Assistant, iChat, Address Book, and Icon Press. So users are already familiar with this panel, very, very simple to use, easy to use.

And now Leopard we provide a API for developers who want to use it in their application. So what can users do with this picture taker panel? They can choose images. They can zoom in, zoom out, move the images, the image to adjust the crop area, and now they can also apply some cool effects with parts composer. They can also take snapshots using the iSight, or any kind of devices supported by QTKit. And the image browser automatically saves recent created pictures in a kind of recent list that you can access with a specific product menu.

So using this picture taker is very straight forward, as you just need one line of code to launch it. You can launch it as three different ways. If you want to use it as a panel, then you will use beginImagePickerWithDelegate, if you want to use it as a sheet you will use beginImagePickerSheetForWindow.

For instance, Icon Press uses a picture taker as a sheet. And if you want you can also start with a pop-up recent menu. In iChat, for example, illustrates this kind of usage. So let's jointly see that in Xcode, so can we switch to the demo machine? So here is a step two of our application.

And you can see that here's the code to launch the picture taker, it's very short. I have an (IBAction) importImage: here where I get, retrieve sharing stamps of the picture taker panel using IKPictureTaker pictureTaker. Then I just, with this line of code I enable as effects. I will show you what are the effect feature in it in a little bit.

And then I launch the picture taker, so here are the separate panel with beginPictureTakerWithDelegate. And I path didEndSelector here. So didEndSelector is a method that will be invoked on the delegate. So delegate here is self. And so this method will be invoked when the user is done with the picture taker. Like, for instance, clicking on set, or by cancelling, or by closing the window. So here the delegate is self, so I implemented didEndSelector here. So this method would be invoked by the picture taker.

Here I just check the returnCode, and if it is NSOKButton that means the user validate and not cancel. So here I want to get the ouputImage from the picture taker. So simply with outputImage method I get a simple NSImage. Then I save this NSImage as a TIFF on a hard drive, and I add the new path in my datasource array, and I ask the image browser to reflect the changes on my new datasource. So let's see how it works.

Okay, so here I did a camera button, which is connected to the import image action. So when I click on it, it brings the picture taker panel. I can choose an image on my hard drive, on my other disk, like this. I can zoom in, zoom out, move the image to adjust the crop.

I can choose another image from the recent list like this. Hey, it's me. I can also take a snapshot, and I cross my finger. Hey, it works! Woo. (Laughter) So that's me. And now a new coll stuff in Leopard is capablity to add some cool QC features with an effect button here.

So it bring the effect picture, thank you, and there are several pages of effects. I can choose one of them for some effects, I can also change some properties here, for instance, the center of my effect. And then I can validate, it will invoke my didEndSelector where I get output image, and add it to my datasource. And so that's why I can see it in the image browser. All the effects are nondescriptive so you can, whenever you want, just go back and recall the original image, or choose another, a different effect like that.

And if I validate there is another image in my datasource. Okay. So can we go back to the slides?

( Applause )

[Thomas Goossens]

So now we have our eyePhoto application is able to scroll, to browse a lot of images, or other kind of documents. We can zoom in, zoom out. We have indent preview for movies and QC compositions.

And we have a nice search functionality really easy to implement as you just need to filter your NSMutableArray and just ask to reload the data. So we have, I think, a complete and fast image browser thanks to the IKImageBrowserView. We have also-- we are also able to import images, to crop images, to take snapshots using the iSight, and apply some Quartz Composer effects.

And so now I pass to, I pass back to Werner to continue to enhance our eyePhoto application with other Image Kit components. Thanks.

( Applause )

Okay, so after browsing and importing we want to view the image. Want to view the image, while we could do that by just changing the slider and fully zoom in, but when viewing an image we want to do maybe a little bit more.

So if we look at the IKImageView class itself it handles a single image in its own view. And it handles things that you take for more or less granted; you really want to have that. But sometimes it's like a little bit tricky to get that working right and efficient.

So what we want to do is we want to be able to autozoom, autoresize, all right. And so basically you resize the window, and you want to always fit the image on the screen inside the window, maybe have bars at the top or bottom, but you are not interested in kind of distorting the image.

And then, of course, you want to zoom in, so whenever you do that you want to have scroll bars and that should just work out of the box. Next thing that should work out of the box is actually handling the orientation tag, and Thomas didn't mention it for the browser, but actually it works very well.

So whenever you take a digital image from your camera, and you, instead of creating the landscape image go to portrait mode, then the image itself has the same dimension as all the landscape ones. The only thing that's different is really in the metadata. There's the orientation tag, the value from 1 to 8 that tells you how to rotate or flip the image. And of course, we want to take care of that, so we really want to show you where to go.

Then the next kind of requirement was, well, we should work with large images. Overall, that doesn't seem like a huge thing, because you could do that in the past, you just create, use Image I/O to create a CGImageRef, and no matter how big it is you just draw it.

The problem with that approach was that this CGContextDrawImage call that we are going to make may take a long, long time. So we are doing some tricks to beef up the performance so that when you deal with large images you will at least feel that it feels faster.

So in order to use this new IKImageView what do you really have to do? Well, of course, you have to set the image and there are two ways to do it. One is use Image I/O to create the CGImageSourceRef and also extract the metadata. Remember metadata is important for an orientation tag, for example. So you could do that. Or the really preferred approach is you pass in the URL. The reason why it's preferred, again you will see in a bit when we load the first images and show you how to do that.

Then getting back to the image, well, you want to save it out to disk, then really what you want to get back is a CGImageRef, and also if user has done some changes you want to get an updated version of the image properties. Let's switch to the demo machine, and let's have a look what it takes to use the IKImageView.

Now I'm going to start off with Interface Builder. Of course, Interface Builder, well, we can actually just create a single window, and that window should probably stick to the top part and you may even want to resize it a little bit, and down here we should have the Image View.

So when I drag it over you see we actually automatically create the Interface Builder block in a way that we get predefined content for the image browser view, but also for the image view. And you see the sizing is correct, so we could just run it. Then what you would expect is really, it autoresizes, because we turned on autoresizing, and it should behave that way. Now the next thing we want to do is we want to put this into a scroll view. So once that's in, then you, okay, that's when it crashes, okay, let's try that again.

So we do this, bring in the IKImageView, embed that in the scroll view. For the scroll view we have to rewire this, and then run it, and well, we do not get a scroll view. Why is that? Well, because we turned on autoresizing on the image view. Now instead of like turning off, we want, actually, let's try a couple of other things.

And one thing would be, wouldn't it be nice if we could do some basic coding without actually, without writing any code? And the way we do it is we bring up an object controller, wire that to the image view, and then take this autoresize, and what you want to do is bind it. Use bindings, bind it to our object controller, and just bind it to autoresizes.

Now by doing that, we should be able, if we run it, all of this behaves correctly. If we turn off autoresize, well, then you see the image does not no longer fit and we can scroll and have the image of the given size. Or we could go a little bit further. What we could do is also, why not have a slider to do the actual resizing? And again, this slider we could just bind it to the object controller and bind that to the zoom factor. If we run it then-- oh, it didn't take it.

Okay. If we run it we should see it and can actually add also an edit field, and actually did prepare that. If the image would sample, and the fields gone so let's do that again. Bind it to the zoom factor, let's run it. Then we see we have this and we just added the edit field, it's automatically bound to the zoom factor, there's no code involved. You can very easily get that to work. And autosize, of course, works as well. So if you autosize and now you make it smaller, okay, we see the slider changes and also the value and the edit field. So it can go to anything that should just work.

Now the interesting thing is that while we have this Cocoa simulator running, let me draw up a couple of images on this one directly. And we have a folder with large images. Like we have an image that's 10,000 by 10,000, so you see it loads kind of fast. It's really not bad, but if we like zoom in it still feels fast.

And one thing you will notice is like as we zoom in we may not have the image at full resolution, but actually while it's loading and fetching the data to get to the full resolution we can work with the image. Which is kind of nice, because then doing things like that and then changing the zoom factor I can go in and still use it.

Or another interesting image, first let's turn autosize on again, and then take a very narrow one, this one is 14,000 by 524. So if we go to autoresize there's really not much to see, but if we zoom in you will see. The image comes in and as we zoom around, you see it feels kind of snappy, and get dizzy, but it's loading the information, the image data and compressor as it needs to, which overall, I think, results in a pretty good performance.

So you do that or another TIFF image like kites. It's kind of nice. So once we have that, basically now we want to integrate this image view with the step two that we ended up with. And we could more or less try a similar thing, actually in Interface Builder. So if I drag this one over and combine these two in a split view, oh, I should, all be in the same height.

So combine these two, embed those in a split view, and make sure that the split view behaves correctly. And the only thing that I would have to do is set this one to delegate. And this only useful in the image interface for the demo, it's really, see now when I select around I can actually have an application that uses the browser on one side, and has the full size image view on the other side. And you can just select, and as Thomas was showing like rearrange and these things. It would just work.

Now you can go crazy and add a couple of other things in Interface Builder. For example, let's have just a single button saying left, and let's duplicate that, right, and then put these, connect these, and do the image rotation, we can run it and then this would just work without writing extra code. This is just an outlet that we have, an action that we can directly use. The same is true for flip, left, vertical, horizontal, or zoom in, zoom out, zoom to actual size, and all these things, but actual size is also like that.

So you could do a lot of things in Interface Builder, but actually we want to switch back to Xcode to our step three demo. And let's run the application first. Well, you see, first of all, we created a couple of nicer or better-looking icons, you have the arrangement that we have at the split view as a horizontal split view.

We still have all the features that we had before, like the searching for like just updates and behaves correctly. We do have to zoom in, zoom out, zoom to actual size, zoom to fit, or then the different orientation. And interesting thing the undo, all these things just work without writing any code.

And if we look at the code that we actually had to write in order to make it work in our application, it's actually not a lot. So if we just look at the main controller, the only thing we had to add here was, well, we wanted to have an outlet for the IKImageView.

Then on the viewing part of the controller what we were adding was like a set up, and the only thing we want to do there is like turn on autoresizing, so make sure that we, when we come up with the application we have autoresizing on no matter what was set in the file. And we initialize everything with NULL so display nothing. Then on the change of the selection in the image browser view what we want to do is get the current selection, we're going to index that back. Try to see if we have a valid first index.

Get the item and the itemRepresentation. And in our sample code we don't have to test for anything, because like we know that in this step all be returned would be a path. So what we are displaying is really, what we're getting is a file path, and we, so we create a URL with the file path and we just initialize the image with that. That's all we need.

Okay, so then for the next step, go back to the slides.

( Applause )

Now we want to edit the images. Well, there are a lot of ways to do it. We came up with the idea of having a set of floating panels that handle image adjustments. So basically you get on one part of the panel you get sliders, they all affect Core Image filters. So you could make your arrangement, make your change on one of the options, for example, you can change the brightness, or whatever. It will immediately be reflected in the image view, but it's not applied yet.

The same is true for the different effects that we present and the user can pick whatever if she wants. And the last thing we cover with the edit panels is the metadata. We just find it convenience to have like a single place, simple place, single simple place to go to in order to get all the information about an image.

So we display all the metadata, and we get that information from Image I/O, as we mentioned before, but what we really want to do is instead of having kind of meaningless values, for example, if the value for a flash could be zero up to 15 or so, which is pretty useless if you just look at it.

Zero probably means there was no flash involved, but all the other steps that do not necessarily mean that the flash did really fire. It's just like a different mode of the camera and all that. But what we really want to do in this edit panel then is have some meaningful English names, or whatever language you have chosen; names that the user would understand.

Then the nice thing when using the edit panel would be, wel they work kind of automatically with IKImageViews, if you want to use them outside the scope of an Image View, all you would have to do is implement a very simple protocol. And for the image view using the Image Edit Panel is very simple. All you do is basically you'd turn on one flag, one Boolean, saying well, on the double click open this panel. Let me show you that in step number four.

So what we did for step number four is we just go in, and for the setup editing part we just basically do the setDoubleClickOpensImageEditPanel to YES And if we run that application then it behaves the same way as before, but now double clicking just brings up this panel and I can change like on the fly, even for very large images, it should be snappy enough, change different bracket. I can go to the effect page and then to whatever we want it to apply as an affect.

Or actually I can go to the details page where I get information, different information about images. While these images that we have in here do not have, these are the standard desktop backgrounds, so they do not have a lot of metadata. But let me actually show you images that do have metadata. Oh, I guess we didn't turn on the, actually let me add this.

Oops. Oh, images with metadata. Okay, if I choose this image and go in here, actually you see this image contains GPS information, so we could actually go in and see where was this image taken, and we would go up (Applause), go up and we'll be able to see, well, yeah, that looks kind of, okay. So I believe this was really there. Then, of course all, the other metadata like general information, here's the orientation tag I was mentioning before. This, and kind of information we really want to display in a more readable way. So I think that's kind of handy.

Okay, so step number four, we have the editing part, now if you go back to the slides. What do we want to do after editing, well of course, we want to save our changes to disk. Now there are a lot of different ways you could do it. Well, of course, you use, if you're writing a Cocoa application, you just use a regular in a save panel, and then you'll want to write out the image information, image data using image I/O to disk. And very easy for Image I/O users, like all you do is you path in your T type to specify is it a JPEG or a TIFF, or whatever file formats you want.

Now the, kind of again, tricky thing is, it's, yeah, you have to allow the user to specify certain things like, what is the compression, what is the quality slider for my JPEG, what is the alpha value for my TIFF? And so we came up with the IKSaveOptions, just a set of, basically, a class, a set of utilities that allow you to use the add on panel to a save panel in a kind of efficient way. What you do whenever you want to invoke this, you call in it this panel with image properties, out of that, for example, the panel will know, the accessory view will know what the current compression for your TIFF, for example, is.

And then you pass in a UT type, so the panel will know, well, default to this type. And then all you do is you add this accessory view to the regular NSSavePanel. And then when you're done with that you can get back the image properties, the UT type that the user has chosen, separately or combined in a dictionary and the user selection. So let me show you how to do that in step number five.

So step number five, you add it, the controller saving part. And controller saving part what we had to do, well, first of all, we want to keep track of the current, the selected URL. So it's kind of convenient that we store that information off whenever the user has modified the current selection. So actually that means that in the viewing part where we were dealing with the current selection, at the end we really have to call setSelectedImageURL.

So once we have that, then we basically hook up the saveAs option. So we create a standard save panel, and we ask Image I/O for this URL, give me the UT type. Image I/O does a pretty good job by looking at the first end bytes of an image, and then determining, okay, this is a JPEG, this is a TIFF.

And what we do is we get the, from the image view, we get the image properties, we get the lastPathComponent as the file name, then we create and initialize the IKSaveOptions, and add that to the savePanel. Now, then of course, there all the standard Cocoa stuff where we begin the sheet for the directory, we pass in NULL, go to the last one and pass in the file name and all that. And what we want to get called whenever the user clicks okay.

That's the only case we evaluate here, and then we want to save the image to disk. Now saving the image to disk is more or less straight forward, all we do is we get from the save options, we get the UT type back, and this is really the one that we pass in on the CGImageDestinationCreateWithURL.

So once we have the CGImageDestination we just add the image, and that's the image that we get from the image view, which means that image has all the changes that the user made to, so it will contain the slider change for the Sepia CI filter. And then we add that and call finalize.

That should create the image on disk. And we want, of course, to add that directly to our browser, reload the browser, since we added an extra object, and then since the last one we added we want to make that also the current selection; meaning we did save it and the browser should automatically select it, so our main view should display it. So if you run this then, let's take this image here and then we can go in, we could make the change, add now, change saturation, and just do a save as.

Saving as, as you can see here, we will have all the formats that Image I/O supports. We can choose JPEG and play with the quality. We could save this one, this was an original, was a JPEG file, but we can also switch the file format, go to TIFF and say, oh, let's use LZW.

And then do a save. Now this image was saved, and down here we see we have Clown Fish.tiff. So that's fairly easy to use, the save options, and it's kind of powerful, because like you don't have to worry about all the different options that you could have, all different file formats that you could when working with Image I/O. Now the last part of our eyePhoto application, would you switch back to the slides, please? Is presenting it. Well, for that we have a simple to use Slideshow component within Image Kit. And this one works with images, PDFs, and everything else that Quick Look supports.

The data that you, or you pass it in, is pretty easy to use. I mean it's a, can be passed in as a URL, the file path, or a CGImageRef, anything, or PDF page, or a mixture of those actually. And the whole concept behind it is very similar to the datasource of tableView for the IKImageBrowserView. So what you have to do is, there are two methods that are required. One is give me the number of items, and the other one is give ItemAtIndex.

For those data types that do not contain information, for example, for the orientation that would be a CGImageRef or an NSImage. For those you could provide additional information using Image Property dictionary. But-- and actually the name, because that's the other thing, like a CGImageRef does not have or reflect the name of the original image source.

And then the datasource can have some callbacks for some, you can get called when the current selection in the image, in the Slideshow changes, when it starts and stops. So if you go back to demo six, demo sheet, step number six, we have here is on the presenting part, well, we want to run the Slideshow. So we'll if we run the application first and then see what did we change, what did we add? Well, we added a button up here to actually start the Slideshow.

And if I do that, then it should take over the entire screen, we should get our regular Slideshow panel, and then we can stop it here, and then go through. We can go to full size. We can go to the index view. Hmm, it's not working. Okay, let me see why it's not working. If we look at the code, well, we run the Slideshow by passing in a dictionary of options. And the first option that we pass in is a StartIndex.

Well, the option, the StartIndex just allows you to, well, you have like 5,000 images in your browser view, and you want to go to the Slideshow, and you want to start off with a different index, well, yeah, use the current selected one. That's what we do here. Then we run the Slideshow in a different, in a given mode. Well, if we want to do it, in our case we want to do it really with images only.

And then what we have to implement as a datasource, because we are specifying self as the datasource, then we specify the number of Slideshow items. This is just our array count. And for a given item at index we get out of our images array, get the item at index, and get the image representation, which is the path. So we are returning as the ID here, we return the path. Now we also want to respond to, like the Slideshow did, stop, so actually we want to update our current selection.

Let's do that, so again we run the Slideshow, and if we go through that, you could say that was a nice picture here, and then we stop then, we should update the main window. One other thing that we did on the last step that's kind of interesting is down here we are showing the total number of images. And actually we're not updating it for the selection, but if we use the number of bugs, or whatever, we had 2 out of 46, let me actually show you how we did that, because I thought it was also interesting, because this one was done without any code.

So if we go to the view and look at this, then we actually see it's all done through bindings. So the first one we bind to our controller seeing number of displayed items, and the second one is just the total number of items. And these were actually the two methods that we were adding to the controller to allow you to do this with this update. But it, whenever the-- current selection changes there's really no need to invoke any code to update these numbers, this happens automatically when the browser view updates and filters out our items.

Okay, so, by doing that, overall, I guess we have kind of nice application that shows the image browser view, the image view, and a couple of other components from Image Kit. And I think that's a kind of powerful application that we just built during this session. So if you go back to the slides, there's actually not much left, just to point you out again and Allan who's the 2D and 3D graphics evangelist. So if you have any questions, problems, issues, contact him.