Graphics and Media • 1:04:10
ImageKit is a new robust framework providing many powerful imaging services which you can easily incorporate into your application. Discover how to add zoom, rotate, and filter capabilities with the new image viewer. Take advantage of fast image browsing, leverage the new picture taker and display image slideshows with ease. This is a must-experience session for developers looking to take advantage of powerful imaging services in their applications.
Speakers: Werner Neubrand, Thomas Goossens
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good morning everyone. Welcome to session 203, an introduction to ImageKit. My name is Werner Neubrand and I'm one of the ImageKit engineers. Throughout this session we want to cover a couple of questions like what is ImageKit, why is Apple doing something like that, and how can you use it, and how did we implement it? So ImageKit, to answer the first question, is really a new framework that we are going to introduce in Mac OS X Leopard. It's an image handling framework, so everything related to images might fit into this new framework.
Well, if you look at today's digital content, we see actually more and more. So we see more and more images. There are more and more digital cameras. Cell phones are capable of taking images. Even on the iPod you can store your digital images and look at those and work with them later on.
In addition to the digital content, we also see more and more digital applications. Like if you look at our iLife Suite and Aperture, for example. But there's much more. I mean all the hundreds of applications that are out there, like shareware to full-blown packages that deal with images.
So we were asking ourselves, like inside Apple, we have applications that do have common needs. And what are these common needs? Well, one is really finding and browsing images. So if you look at iPhoto, iPhoto is capable of handling, similar to Aperture, a large set of images. And the user wants to browse these.
You want to display all the images as thumbnails in a very efficient, fast way. And ideally, that should be easy to use. And even if you look at the new mail application, the new mail application with the create stationary function has a way to import to browse iPhoto library and again, one need is you have a lot of images, you want to browse those.
Another thing that they have in common is that you display a single image and you want to edit the single image. So images, and we are relying with this new framework ImageKit, we are relying on ImageIO that was introduced in Mac OS X Tiger. So this great framework deals with all kind of image formats. So JPEG to TIFF, GIF, and even RAW files.
Now, applications like, again, aperture, eye photo, and even the free preview application allow you to display these images. And not only displaying, but you can also do editing. It could be in a very limited way. Preview has just a couple of sliders where you can change a couple of parameters to actually see eye core image filters. Or more advanced editing in aperture and eye photo.
Now, if we look at these two basic needs, This actually might be a great book title. Actually, it is out there. You can buy it. But I think it's not a great idea to let you and also us inside Apple reinvent the wheel again and again. So really we want to create a set of functions, set of components that might be reusable throughout different applications.
And really bundle all these things together. So create something that can be used throughout, within Apple and hopefully within your application. Now, the new ImageKit framework is based on known and existing and new technologies within Apple. So we are using Quartz, OpenGL, Core Image, and the wonderful new Core Animation framework.
If you look at the overall picture, I guess like we are part of graphics and media, so we are sitting on top of all these and using those services. But we're also using a lot of the application frameworks like Cocoa and all our new APIs are Objective-C based.
If we look at the different components that we have, again, looking at the different needs, looking at the different components, well, the first component we have is an image view. If we look at the different components that we have, again, looking at the different needs, looking at the different components, well, the first component we have is an image view. If we look at the different components that we have, again, looking at the different needs, looking at the different components, well, the first component we have is an image view.
We do support, and if you look at all our new MacBook Pros or MacBooks, they all come with a built-in eyesight. So we do support that as well. So applications today like Address Book, iChat, Access Panel, and so on, they all use this built-in camera. But in the past, they had all their own implementation. So now with ImageKit, we can all come back and produce a lot of code throughout these applications, but also make it available to you so very easily you can take advantage of a picture taker.
Then the slideshow which was built in to make OS X Tiger and used by various apps. We also make that as part of the ImageKit framework. And actually we have a couple of others. So let's look at the overall picture. We merge all these things, all these components, put that into the ImageKit, and let's go to the first component, the image view.
The image view, the definition could be like an image view object displays a single image in a frame and can optionally allow a user to drag in an image. Well, this might sound familiar to you because if you look at the definition of an NS image view, it's very similar. So what is different? First of all, we are On purpose not using NSImage as an initializer to that image view. We are using CG ImageRef and metadata and the properties or you pass in the URL.
We have additional functions that a regular image viewer does not have, like support for zoom and rotation. and we do handle user selections for copying and cropping. And you can be sure that we will have a little bit more whatever tiger, sorry, whatever leopard ships. So the current choices that you have today for displaying images is NSImageView in a regular UI window or panel that you have where you display an icon or so.
Then NSImageView is actually the perfect choice. It's robust, it's lightweight, and you were using that in the past, great. If you have no need to edit the image or zoom or manipulate the image otherwise, NSImageView is perfect. You could do your own window class and do everything on your own. But really with Leopard we want to give you a third choice and use the IKImageView that, as you will see, will be very easy to use and it's quite powerful.
So the APIs that we have for this new class, one is setting the image. Well, as I mentioned before, we rely on you passing in a CG image ref and property dictionary, basically the metadata for that image. Where do you get those from? Very easy, you get those from ImageIO.
For certain type of files, it could make sense to use a URL. And actually you can do that with all files, but it makes a lot of sense to do that with raw images. The reason for that is that there can be some special raw processing can be done even before getting to the CG image ref. So you're losing a little bit The internal magic whenever you just create the CG image first and then pass in the image with the dictionary. So ideally for raw files I would highly recommend to use the URL.
Now, there should also be a way to get back the image, and you do that. In this case, you always get back a CG image ref. And you can ask for the metadata for that image. And both of these, again, put that into a CG image destination method and use image I/O to write it out to disk.
The image has some properties. The image view has some properties. Now look at that declaration and really we are using with this new class also new features of the objective C2O language. So we're using property, which means that in order to access, like for example, the delegate, you could just do view.delegate equal to this. Or in order to get it, you can say my delegate equal to view.delegate. Or hiding behind this is really also accesses like you can ask for the delegate or set delegate. You'll see that in the sample code in a little bit.
So we have a delegate, we have a zoom factor, and rotation angle. And we have a couple of actions. Actions are related to zooming and rotation. So there's for example an easy way to do a zoom to fit. Just one single call and the view will make sure that the image that you passed in will just display in a zoom to fit mode.
And we do support a couple of tools. This number is like the basic set right now, and we may have more tool modes in the future. And again, the current tool mode is a property. So it can query the mode or set it very easily. And mainly we have the move tool so you can pan around.
You have a selection tool for doing copies. We have a selection tool for doing a crop. The UI is slightly different, as you will see in a bit. And we do support an easy way to do rotation. So actually let me go to the demo machine and show you this IK image view in action.
[Transcript missing]
Okay, we have the same thing on demo A, if you could fix demo C. So let me start with a simple application. And we display an image that we have in the resource, or actually in the bundle path of that application. You see we have zooming and a kind of really smooth animation do that and internally as you can imagine we are using the new core animation classes and so it's very easy to do this with coordination because actually the the code that I need to write in order to do this this this animated zoom is nothing so all I have to do is like I have a start state a gold state and basically set the the frame to a new value and what will happen is it does it automatically. So very easy to do this.
Now we can go back to the machine. So again, the animation for this really comes for free. There's no code to write, and it just happens automatically. And then we have the 90-key rotations. We have the panning tool, we have a selection tool. To do a copy and a selection tool to do a crop.
You see we have a slight different user interface. Again, these things are all done using core animation. So that simply means that when I switch the tool-- now watch this-- it really fades out slightly. And again, there's no magic behind that. It's just switching the tool mode, get rid of a layer, and the animation happens automatically.
And then we thought it would be nice to have a kind of nice rotation mode. And we do display an overhead display. We display the current rotation angle and the delta. And you see when I rotate the image, the overall image size grows because we do not want to crop.
And again, just another core animation layer in the back shows us if we would save the image right now, we would get an image of that size, so the overall size. And nice thing is also like if I do this and do a copy and would launch preview, it Do here a new from clipboard, then yes, I do get an alpha image. So we do the right thing in this case as well.
Okay, so let's look at how much code is really involved in doing this. Well, it's only a single file and that's about all it is. Well, this is just the collapsed state. Let's look what's really behind it. So on the wake from Nib, what we do is we get our path to the image. We create the URL and do a self-open image with an URL. And then we do some customization. For example, and here again, look at the new Objective-C 2.0 syntax where we do set the current tool mode and the delegate using the dot notation.
Opening an image URL is not too complicated because we are using ImageIO. So what we do is create an image source with the URL. Then ask the image source to create an image at index. If you get that image, then we want to copy the properties. And actually for later on, we also get the type. So that's your T-type. For example, public.tiff.
And if we got the image, then we want to update the image view and update the window title. So that's all it takes to display the image. Now, a couple of things. The tool mode When I select one of the segmented controls, it's very easy to set because all I have to do is directly set the tool mode and the view will update and do the right thing. And this here is just a test whether we do the tool mode setting from a menu or segmented control directly.
Zooming is also not too complicated because all we do is like, K0 is a zoom out, so we just change the zoom factor, zoom in the same, actual size, just a single method call, and zoom to fit, just a single method call. And one thing I didn't show you is really we do also support the open panel so you can open an image directly if you want.
An interesting way is, an interesting method that I want to show you is this. Because right now we have no automatic resizing the image whenever the window size changes. So what did I have to do in order to make that work? Well, in theory I just have to call image view "zoom to fit".
But you see I'm doing a little bit more. So what is all that? This is actually just telling the core animation framework, do not animate this. Because there are cases where you want to change a state from A to B and you do not want any animations. And that's basically what you will see whenever you resize the window. If the view would resize with animation, it would look really odd a little bit. Okay, so that's the image view. Now back to the presentation.
Let's look at the image edit panel. The edit panel is just a regular NS panel. It's a floating panel that handles image adjustments. And the current version just displays the sliders and fields that we are using in the current version of preview. The panel has a second mode, second tab that you can go into to display an effect script. So we have an image effect picker where you can just select a couple of, or an effect of a predefined one and then apply that to the image.
And the last tab is for metadata. So it's an easy way to display metadata, especially useful whenever you have images from digital cameras that really have a bunch of metadata. Or whenever you decide to really use IPTC tags inside the image to add keywords. So you can very easily access that.
Now the nice thing, the Edit Panel works very easily, seamlessly with Nike ImageView. Or works with anything that you have that just implements an image edit panel data source protocol. And it's fairly easy to use because in case of the IK image view, all you have to do is set one property.
For example, open the panel on a double click and whenever you use that property, then double clicking on the image will just bring up the image panel. If you want to do it manually, you can very easily do that. And all it takes is you get a shared instance of the Edit Panel, you set the data source. And then he would say, make key and order front, and then you would see the panel.
For the data source, there are a couple of methods that you have to implement. Actually, two are required. One is you have to be able to return the entire image. And you have to accept a new image, ideally with metadata. Optional methods are: if you're dealing with very large images and you want to use the effects picker, then if you already have a thumbnail within your application, then we would just ask you, "Give me the thumbnail of this minimum size." And if you have it, fine. If not, then we would just fall back taking the entire image and scale it down and we will display it.
[Transcript missing]
So the same application and there's only one line code change in this app. And that's basically whenever I double click, we will bring up this panel. Now this panel just does some basic corrections. And I guess for this one, it's pretty good to see the sharpness working. And yes, you can do all kind of image manipulations directly in here. Or you can switch to the effects panel and pick a predefined one.
And here you see we have just a minimum set of metadata. Again, if this image would have come from your digital camera, there's probably a rich set of metadata like camera model and all these kind of things. So this is fairly easy to use and might be quite handy to have this. And so we actually were thinking also, where else can we use it? And let me quickly open TextEdit.
So regular text edit, I drag in an image and again, wouldn't it be nice if I could do some basic image manipulation in a text edit? Actually, in the hopefully shipping version of Leopard we will have that and we will have things like, yeah, I can rotate and again here we do get some animation that we probably do not want so we should take that off and disable core animation to animate the moving.
And yes, I can go in and I should be able to do a crop, get the image and I should also be able to do some manipulation directly within text edits and that should just work. Okay, back to the slides please. And now it's time to talk about image browser and I hand over to Thomas.
THOMAS GOSSINS: OK, so I'm Thomas Goossens, and I'm working on the ImageBrother for ImageKit. So the ImageBrother is a view to display and to browse images. So displaying images is a usual task needed by a lot of applications. For instance, on Mac, applications like Spotlight, iPhoto, Aperture, of course, and also Mail, Preview, Media Browser for iLife and Pro Apps, and a lot of third-party applications, they sometimes need to browse and to find images.
So in the past, if you wanted to browse images in your app, you had to create your own browser. And it needed a lot of code and efforts to do that. So with this new image browser, you We provide a simple class to developers who want to browse images in their application.
So the image browser lays out images within a grid, and then users can scroll and zoom in, zoom out to browse the content. This view supports selection, so users can select one or more images with keyboard or with a graphical selection. And the API provides simple delegate methods to ease the drag and drop implementation. So it's really easy to create a simple application where users can select pictures, drag images from the browser, or drop images into the browser, or simply use the drag and drop to reorder images inside the browser.
So here is the appearance of the image browser. In this screenshot, it displays images with outline, shadows, titles, and subtitles. But in fact, the appearance is really customizable. You can, for instance, choose the decorations you want to see. So, for instance, remove shadows or outlines. You can also remove titles and subtitles.
You can change colors for text, background, outlines, selections. And you can also adjust the margins if you want to see more images at the same time, for instance. So there is a lot of implementations of similar views and developers are always facing the same issues when they want to handle large amounts of images and keep good performances and high image quality.
In fact, this kind of views are hard to make efficient because it needs a lot of code to create efficient image caching, thumbnails with multiple resolutions, threads for rendering images with the best quality, and a lot of details like events handling, selection, drag and drop, auto scroll, accessibility, and a lot of important details like that. So with this image browser, we want to provide through a simple API an efficient and generic browser that can handle large amounts of images. And to be generic and flexible, the API uses a data source mechanism similar to the NS TableView API.
So the data source is an object implemented by the client of the API, and its role is to provide the content to display. So concretely, the image browser will ask the images to layout and to display to the data source. And when the client of the API wants the image browser to reflect the changes, You just have to invoke reload data and then the image browser will automatically reflect the changes and display the new image set. And the data source protocol of the ImageBrother is really easy to implement as only two methods are required.
So first, like for a usual NS table view, the image browser needs to know how many images it has to lay out and to display. So this is done by returning the image count in number of items in image browser. And then for each index, the image browser will ask for an object that represents each item.
So in the second step, this item object needs to respond to these three methods. First, Image UID is an identifier that has to be different for each different images. It can be, for instance, an absolute file path, a URL, a database index, or anything else. It just has to be different for each different images.
Then, image representation type and image representation make the integration of the image browser easier as it lets developers to choose their favorite image representation in a large set of possible representations. For instance, if an item represents a file path or URL, you can just return this file path or this URL and the image browser will do the job to load it and display it when needed.
However, if an item has no file path and/or no URL, you can here choose the image representation, your favorite image representation, so you can just return either an NSImage or CGImageRef or another image representation. So here, this is more flexible and you can choose your favorite image representation. And also, if you know that an item is a movie or a QC composition, you can just specify it and then the image browser will display a play control under the items so that users know this item can be played.
So the ImageBrowser supports this kind of format. So for this kind of media, you can just return a path or an instance of this media, and the ImageBrowser will be able to lay out and display and manage it for you. However, if you want to browse another kind of media, you will have to convert it to an image or one of these media on your side before giving it to the image browser. For instance, if you want to browse HTML documents, You will have to create previews of each HTML file on your site and then provide images to the image browser. So now, let me show you a demo. So hopefully it will work. Switch on computer A.
Hey, it works. Cool. So here I have a sample application which demonstrates a really basic use of the image browser. So here I can add images by drag and drop or with the open panel here. And in fact, when I do that, I just add the selected file path to my data source, which is just, in fact, a simple NSMutable array. Then I ask the image browser to reflect my changes.
So you can see that first it displays some placeholders and the image browser automatically starts to import the images. So then I can scroll down a bit and you can see that the new images that appear while scrolling are automatically imported. Then I can select a picture, for instance, and start zooming zoom out. Okay. And so you can see that the image browser takes care of keeping the focus on the selected image.
So internally, the ImageBrowser uses thumbnails with multiple resolutions to have good performances while zooming. And also, when I stop to move, there is a thread that takes care of rendering the images with the best quality. So these two techniques guarantee we have both the best performances, but also the best image quality.
Then I can customize the appearance. I can remove shadow or add outlines, add titles and subtitles. So here with the selection. I can also minimize margins if I want to see more images at the same time. So here I can have more images. OK. And I can also change colors if I want to have, for instance, a more pro app look. So here I change colors for outlines and selection and also background and placeholders.
Okay, so let's get the first appearance. And now to illustrate the data source mechanism, I added here a search field. And when I add a letter in it, I just filter my data source. So just filter my NSMutable array. And I just keep the items that match my search field value. So for instance, if I add a L, OK, you can see that the image browser reflects the changes of my data source.
And it can also compute the differences between the previous state of the data source and the next step of the data source and animate the transition. For instance, I write Leopard. Okay, I can zoom in to see my layer-pal image. Can remove my letters. And recover my previous images.
And in fact, all operations applied on the data source are handled in the same way. So for instance, if I remove items from my data source array and then ask the image browser to reflect my changes, it will animate the transitions automatically. And that's the same for reordering. So if I just move items from my data source array to another location, it can animate the transition like that.
[Transcript missing]
So you have seen how the image browser handles images, but you can also handle other kinds of media. So here I can add some movies. Okay, quick time. So here there is a play control under the items. So you can directly click on the play button here, and it starts to play the movie directly inside the browser.
So it's very practical. You don't have to switch to another application to play the movie. And you can also click on a second movie, and it automatically stops the previous one to avoid potential sound mixing. So you don't have to stop the previous one manually. It's done automatically.
Okay, that's the same for QC compositions. So here are some QC compositions. Okay, so I can select one, zoom in, and play the QC composition directly inside the image browser. So that's the same, you can play another one, and this one for instance. Okay, and so you can continue, of course, to browse while playing. And if you click in the background, it stops. The browser also handles PDF.
So here it uses, in this sample, it uses the first page story as the preview. So you can see here are some PDF. And if an item is not an image, not a PDF, not a quiz composition, and not a movie, then the ImageBrother uses Icon3f as a fallback.
So for instance, if I add my application folder here, which doesn't contain any images, it will use the same icons as a finder. So you can use, for instance, the image browser to browse some applications. And here you can use the search field to look for a cool application. Maybe the best one is Calculator.
So you can zoom in, zoom out, of course, and you can configure the double-click behavior. So here, just to launch the application, then remove my letters and find my application folder like this. And now just a last example just to show that the ImageBrowser can handle large amounts of images. So here I have a small library of images. I have almost 6,000 images.
So I can scroll very smoothly, select a picture, zoom in, zoom out very quickly. And in fact, so here is a small library, but the image browser supports 250,000 images. I tried more, but my hardware was full then, so. It should support your entire library of images. So now go back to the slides, please.
So to sum up, the image browser will provide a simple API to browse large amounts of images, movies, and more. So you can use this image browser very easily. So now I would like to introduce another component of ImageKit. You already know this component, and you have all already been using this component since a long time. But now it will be public for Leopard. So this component is the picture taker. So picture taker is a simple panel that you can use to choose an image or take a picture and crop images to usually create body pictures.
So it is a very simple interface where users can choose an image on his hard drive or take a snapshot. And then there is a tool to zoom in, zoom out, and move the image to adjust the area that will crop. So you have seen this picture taker in iChat, address book, MacBuddy, account press, and server kit. But now we have just one common implementation, and we have a simple API for developers.
So the API is very short and very simple. And so here is a sample code that illustrates that. So in this sample code, it uses its name, ImagePicker, for some historical reasons. But in the Leopold, it will be renamed to PictureTaker. So first, you will have to retrieve an instance of the PictureTaker here using ImagePicker class methods of the IKImagePicker class.
And once you have this instance, you just have to invoke BeginImagePicker with delegate on a selector. And this will launch the PictureTaker panel. And when it's done, the PictureTaker will invoke your selector on your delegate object. And that's usually where you retrieve the output image to update your interface or do what you want.
So yes, dirty jump to the demo. So computer, OK. So with the same application, jump on the picture taker. Example. So here I have a usual image view. And when I click on it, I invoke BigID ImagePicker with Delegate and that launch the picture take your panel. So here is the picture taker panel.
I can zoom in, zoom out, move the image to adjust the crop area. I have here a choose button where I can choose an image on disk. So let's choose an image here. OK, so there's a lot of images, so open panel takes some time. Okay, so here's another image. I can take a picture using this camera button here. So there's a countdown and a flash at the end.
Can zoom in, zoom out. And then validate. And when I validate, the picture taker invokes my selector on my delegate object, and that's where I retrieve the output image and update my NS image view like this. So here is the crop result. So go back to the slides, please.
So you have seen how to use the picture takeer panel as a panel, but you can also use it as a sheet or start with a recent pop-up menu. For instance, iChat illustrates this kind of usage. So the picture taker manages a recent list for you. So this recent list contains your last edited crop.
So, one more time, it's really easy to use. If you use the rest of our previous sample code, it's still the same, and you just have to choose one of these three methods to launch the picture taker as a panel, as a sheet, or with the rest on the pop-up menu. So I just want to show the recent pop-up menu.
So, recent pop-up, okay. So here is the recent pop-up menu. It contains my last edited crop. So you can click on an icon and you can see my previous crop. And you can also read it a previous crop and in that case you start from the original image but with the previous crop parameters. So you can just update the previous crop by for instance zooming a bit, validate again, and it updates my previous crop.
And now something that we will add in LeapHard. We want to add the capability to add some effects, some filters applied on the image. So this is just a prototype for now. So it will-- your UI may change a bit and be as well. So here, just to show an example, so here is an effect button. And by clicking on it, it will bring a kind of effect picture like that. Yeah, that's nice.
And-- And so you can select an effect, for example, sepia here. You can continue, of course, to adjust the crop area. And these effects are non-destructive, so you can revert to the original image at will or choose another effect like this. Continue to scroll. And you can also take a picture with an effect applied. So OK. Okay, so that's not my real face. So I can of course remove my effect or choose another effect, for instance this one, and then validate and I will have my cropped image with my filters applied on it. So go back to the slides.
So the picture taker panel is a really simple UI, both for users who want to use it and for developers who want to integrate it in their application. Now I pass back to Werner. Thanks. Okay, so what components are missing? One of them is slideshow. And you may know slideshow really from Tiger. The slideshow was used in applications like Preview, Mail, Spotlight, and even Finder was using it.
Interesting thing was really, like we got a lot of bugs against preview saying, well, preview in full screen mode should do this and this, or this and this, or does not handle that and that. Actually, it was not part of preview. It was really an own framework. Back then it was private, and we really want to make it public in Leopard. So the goal is, make it simple.
So the tiger version was using images and was also supporting PDFs. What about the other stuff like HTML and all that? Actually for Leopard we have a solution for that. We are going to use the new QuickLook framework. And the one version of the slideshow on the seat actually does support that. So you can actually pass in an HTML file or a text file and slideshow should do the right thing.
The data that you pass in can be really passed in in different formats. NSURL, a file path, an NSImage, PDF page, and actually many more. The protocol that we are going to use is very simple, very similar to an NS TableView data source or the IK Image Browser data source.
So for the API, it's actually very simple. It's like you get a shared instance of the slideshow. In order to start and stop the slideshow, well, at least you should start it. The user may stop it with the cancel button on the overhead display. In order to start it, you have to pass in an instance of the data source and a couple of options.
Why do you need options? Well, for example, you could say, well, start the slideshow with a given index. You don't have to start with the beginning of your array of files or images. Or you could say, use the slideshow in autoplay mode with a given autoplay delay. So you have an influence, I mean, you have a way to override that.
There are a couple of methods that might be quite handy. One, for example, is the reload data. And you can think of it like if you would browse, want to display in a slideshow, something that really, at the beginning of the slideshow, does not know how many images you would have.
For example, you are browsing a webpage and you want to display images from there directly. So in the middle you could say, well, reload data, so update the image count or item count. And if you want to use, for example, the image I/O progressive loading of a file, of an image, you can also use that and then update a given image of the slideshow.
As a data source, you can always query the slideshow. What is the current image or item on display? And slideshow does support exporting to another application. Currently, the tiger version and the first implementation of the leopard one does support iPhoto. So if you have iPhoto installed on your system, we will display an extra iPhoto item icon. And you, by clicking on that, can add the current image to the iPhoto library.
The slideshow data source protocol is hopefully very simple because all you have to do is you have to specify the number of items and you have to respond to give me the item at index. And as you can see here, we're just getting back an ID. So as I mentioned before, you can pass back a CG image ref, or an NS image, or URL, or a string, a path, or a PDF page.
There are some optional methods. Some of them are just delegate notifications where, for example, you will get notified when the slideshow is about to start, when it will start, or when the slideshow did stop, or change the current index. And what's also quite handy to use is, and for you to implement, would be the name of slideshow item at index.
Reason for that is whenever you're using like an NSImage or a CGImageRef as your item, then that item does not contain any metadata. For example, it doesn't contain a name. And in our index mode, we really want to display all the names. So that's an easy way, convenient way, to use one of those data types, NSImage, CGImageRef. and still have the name on display.
And then the slideshow will also ask you if you implement this method, should I enable the export to an application button? If you do not implement that method, then if iPhoto is installed, we actually will enable that button automatically for you. And actually, let me do a demo of the slideshow.
Okay, so I can start a small application. It just shows you how to use a slideshow in kind of different ways. First way is what we do is we pass in a URL to a PDF file. As you can see, the PDF file is displayed and this is done using PDFKit and actually I switched to the index mode and we get only one page. Why is that? Well, I was just passing in an NSURL. In that case, in that mode, we would take just the first page but I can still go through the entire document. You can zoom up, go down, and quit.
If I would pass individual pages, To that, we should see the same document. But now when I go to the index mode, we really get all the pages. So we get thumbnails of all the pages. And we do this using, again, core animation. And we can scroll up, scroll down, select the one page, and go back to the image. Actually, to that PDF page.
Now what works for PDF pages works also for images. And the small demo app is just reusing a couple of images that you usually have on your disk. It's just like a couple of screen saver images. So we can specify, oh, let me start the slideshow with just 50 images.
Now, We can manually go back and forth and you see one minor change we did is really when you use the key forward and backward, we are not bringing up the head-up display again because that was kind of complained in the past. If you want to do a presentation using the slideshow, you would always get that panel showing up.
So back forward is really done now without bringing this up. Now let's go to the index mode. And first again you see we do handle way more images. Thank you. Again, there's not that many, so maybe we should go back and do this. Okay, let's try, I don't know, 200.
And now if we go to the index mode, you see it's pretty fast to bring it up, but for those images that are not loaded yet, you will see we display a placeholder and a spinning animated progress indicator in there. This is all done using core animation and as Peter was showing yesterday, like transitions between These different images, they are all very smooth, very nicely using core animation. Nothing special to implement. It's really cool, really nice feature.
And again, this should really scale pretty well, so if I would do this same thing with a thousand images, hopefully we get the same experience. It should really come up pretty quickly and yeah, it should update. Go to the end, go to the top. So this really nicely animated and again, if you look at the code for implementing this slideshow feature, you would be surprised. It's shockingly little code that's needed due to a core animation. OK, so let's quit that and go back to the slides, please.
Now the next component is really something that a lot of developers have to deal with. Like you would use the image browser to browse the whole set of images. You would then open an image up in a window. You may do some manipulation, and then you want to save it.
Now, for doing the save, you really want to present a little bit more than just a standard save panel. What you really want to do is you want to present the different file formats that your application does support and maybe a couple of options for these file formats. For example, whenever you are going to save an image as a TIFF, you may want to specify the compression. You want to have a quality slider for JPEG files. You want to have, for example, an encrypt or not box when saving to PDF file.
Now, again, instead of reinventing the wheel and letting all pieces within Apple and also your applications do it again over and over, we decided to have support for that within ImageKit. And the usage is straightforward. It's basically an IK Save Options class that you have. And you would initialize that class with image properties and a UT type for your image.
You T-tap for your image. We did that actually in the first example. So we got it from ImageIO. It's needed so that we can bring up the safe panel with whatever the original image was set to. So if you open a JPEG, you probably want to use JPEG as the initial setting in the safe panel.
Once you have this IK Save Options initialized, then all you have to do is you have to attach it to a regular save panel. If you have a document-based application method called, I guess it's prepare save panel, where you would do that, you get passed in a save panel, so you would just initialize this IK Save Options, attach it to the save panel. If it's a non-document-based application, then all you have to do is create a save panel, get the standard one, and attach the save options to it.
And then whenever you are done, the user is done using it, clicks OK, then you can query the image properties, you can query the image UT type that the user has chosen, and you get back a dictionary with other user selections. For example, in case of So let me quickly show you how this works.
We go back to our standard application and what we do is, okay, let's do this and let's rotate it a little bit and now we want to save it. Now we see the original image was a JPEG, so this here comes up with JPEG setting. I'm going to go to the desktop. So we could save it as a JPEG. But what's actually more fun in this case is really save it into an image format that does support alpha. So either let's choose PNG and we save the image.
And we got an earring PNG. If we double click on that, we should get it in preview exactly the same way you would expect it. And yes, it does have the alpha. You don't have to worry about that. This is fully supported. And let's quickly look at the code for that. It's really not that complicated.
So, you have to implement in our... So this is just the same standard file that we had before. And... And what we have to do is on the save list, we get the standard NS save panel. We create our save options. Pass in the UD type that we got from ImageIO. Then we tell the save options, add yourself to the-- as an accessory view to the save panel. And then we just run the save panel. That's straightforward. Not a lot of code to write.
Here's a little bit more on the actual saving part. And the actual saving part is done only if the OK button is pressed. And then we ask our image view, give me back the current image. If we have the image, then we use ImageIO to . So how are we doing that? Get the path.
From the sheet, create a URL, create a CG image destination ref, initialize that with the URL. If we have an image destination ref, then what we do is we Create a dictionary with the current image properties that we got back from the save options. In this case we want to say, we really want to save it with alpha.
Then we add the image to the CG image destination. And then we call finalize. Release the image destination and that's it. That's all it takes to save into any file format. So ImageIO takes care of all that. Important thing really is you have to specify the UT type. And again, you get that in the current user selection. And, yeah, you can now support all image file formats that ImageO supports. Back to the slides, please.
And there's a little bit more to ImageKit, but actually the next one, the filter browser, is something where we go really deep into core image support, where we have a way to specify, to select one of the really large amount of core image filters. And actually it's not only just picking one, but also picking one and allowing you to display and actually modify the core image filter.
But this is really covered not as part of ImageKit, it's, I highly recommend session 210, developing with core image. So now we're at the end of this presentation. I just want to point out any questions related to 2D and 3D graphics, please send them over to Alan. I want to point out we have our core animation and ImageKit lab this afternoon.