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: wwdc2005-210
$eventId
ID of event: wwdc2005
$eventContentId
ID of session without event part: 210
$eventShortId
Shortened ID of event: wwdc05
$year
Year of session: 2005
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC05 • Session 210

Essential Ingredients for Mac OS X Imaging Solutions

Graphics and Media • 1:15:31

Delivering software solutions for photographic and prepress professionals? Learn how you can take advantage of Mac OS X imaging technologies to create industry-leading products. We'll cover the fine details on how to support digital cameras and scanners with Image Capture, how to ensure proper ICC color profile handling using ColorSync, and how to open/save images with metadata using ImageIO. Learn how to take your application to the next level of performance and capability.

Speaker: Werner Neubrand

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Hello everyone and welcome to session 210, the Essential Ingredients for Mac OS X Imaging Solutions. Today I will talk about some things that really come out of the box with Mac OS X. And it's basically a simple application that we want to create during this session. It's called "My Photo." No resemblance to any other package that you may know.

We will do it in a couple of steps, basically going from zero to "My Photo" in eight steps. And we will focus on a couple of technologies that are coming with Mac OS X, mainly image capture and image I/O. For image capture, it's important, of course, that whenever you want to talk with a device, you really want to get to know, is there an image capture device connected or not? We, for that MyPhoto application, we are very interested in cameras only. So how do we find out whether a camera is connected or not? Well, very simple.

We jump directly into the APIs. We have two APIs that will do that. And the first one is ICA Get Device List. And the other one is the ICA Copy Object Property Dictionary. That's on the hit list for the longest API name, but we didn't make it quite.

So, for all Image Capture APIs, it's important to remember we have two parameters. The first parameter is a parameter block, where we fill in certain information. And the second one is a callback function, which could be null. In that case, you're making a synchronous call. However, for most of the calls, I would really recommend that you are doing asynchronous calls. Very simple. It may take some time to get information back from the device.

It could be a slow USB connection, or you could have thousands of images, for example, on your iPod photo. And it takes some time to get the information back. You do not want to pluck your UI. You could do it in separate threads. Yes, that's possible. But I will show you today that you can very easily do it by just using asynchronous calls.

And here, important to notice that these calls are available on the PowerPC variant of Mac OS X, but also on the Intel. And there's really no difference for you in coding practice. If you look at the first ICA Get Device List, the first API, this API returns an opaque ICA object. Interesting thing is, it returns it always, also meaning you have no device connected. You always get back that IC object for the device list. And this is, you can see that as a root of an object hierarchy.

So if you have, for example, two cameras connected, then the hierarchy, if you look at it, would look like we have a device list object at the top and two camera ICA objects below. And in order to find out, well, how many cameras do I have connected, I'm using the second, the ICA Copy Object Property Dictionary call to return a dictionary with that information.

Now, for the device list object, this API returns a dictionary that has, for each connected device, the name, the type, whether it's camera, scanner, It has a path to the device module. It could be interesting for your application to know, oh, it's a mass storage device, so in my UI, I can actually bring up an eject button or an eject UI element. And you can, via, for example, Cocoa Calls, you can unmount the device volume. Very easy to do.

And as last thing, you'll get extra information about the connection info. For example, is it a USB or is it FireWire? Is it SCSI or whatever? The supported device types, again, both on PowerPC and Intel, are mainly mass storage and PTP. And years ago we were suggesting to all device vendors, "Hey, really think about PTP." Because PTP, the picture transfer protocol, has a lot of advantages.

Sure, it's probably very easy to implement a mass storage camera, but all you can do in that case is really, you can download the images. There's no way, nothing you can do with the device. You cannot control it. PTP, on the other side, allows you to, for example, send a message, take picture, or delete, or synchronize clock, or a couple of other things.

And actually today, for our MyPhoto app, we will use the PDP camera and we will use some of the nice commands, for example, take picture, and integrate that into the app. So let's go to the demo and just... I want to show you, we have in step one, which by the way, you can download these sources. We probably have them already if you downloaded the WWDC developer package. So step one, let me quickly go to the Nib file that we have. Should launch Interface Builder.

Thanks, okay. So, we will have a single window. In that window we will have a table view on the left side. And the right side we will put in a tab view where we can switch the content depending on what's selected in the table view. The data source and the delegate of this NS TableView is our ICA Handler class, which will be instantiated when we launch and load the Nib.

Okay, that's on interface builder. Now, let's look at the classes, the code we have. Well, we have only two source files, just the ICA handler.h and .m. And the .h file, we just have the handler, which has an outlet to a table view, a window. We keep track of the device list object, and we have an array with all the device names.

On the application side, we have one very nice thing you probably want to do in single-window, non-document-based applications. You want to quit whenever the last window is closed. All you have to do in Cocoa to do that is overwrite. Application should terminate after the last window is closed. Return yes, and it will handle that for you.

Let's look at our Awake from Nib call. In that, we allocate a mutable array for the device names. And the next step would be to find out what devices are connected. Well, if you go to that one, it's exactly what I told you. It's just a single API IC Get Device List. But note in this case, for the first two steps, we actually will do synchronous calls. Just get feel for the API, the way to call it, and then we will start off with asynchronous calls.

So if the ICA-GET device list returns null, no error, sorry, then the PB object is the device list object. Keep that in our data member and get the device list property dictionary. Now this dictionary Load it here. After setting up the parameter block, just use the MDeviceList object.

[Transcript missing]

Now, this is just another dictionary for each device that is connected, that's available. And all we do is we iterate, create an iterator,

[Transcript missing]

The entry with the iFill item file name to our device names. And at the end, we just say, well, table reload, so we update the table view. Now, as a data source for an NS TableView, there's one thing you have to implement, and that's the number of rows in TableView.

Note that we are always returning at least one. The reason for that is if there's no camera connected, we just don't want to have an empty table. We really want to clearly say, "Hey, there's no camera connected." And in order to do that, it's basically return one or the actual count of devices connected.

And then when asked for the object value, what we do is if we have a count, so we do have a device, then we return the item, the object at index row out of our device names. And when asked for the icon, we currently return null. If the device name "count" is zero, well then we just return the fixed string "no camera connected". So let's run this.

Well, as expected, we have no camera connected. The table view shows up as no camera connected. Now, let's quit this. Turn on the camera. And one thing that we were using in the past years, but actually today with the new Image Capture SDK that will be posted either today or tomorrow, you can download these new tools. The ICA Launcher, for example, is a small tool that shows you which of the Image Capture component is currently running.

The first one here is a faceless background application, the Image Capture extension. Now, this Image Capture extension is loaded automatically whenever there's a device connected or whenever a client would launch and make an Image Capture request. So now, if the camera is connected and I... Oh, okay, camera was not connected. So I connect the camera.

Make sure PDP is showing up. I launch this. It still says no camera connected. Well, why is that? Let's see, we can have a look at this, whenever you run into this situation. We have a new tool that's called ICA API Tester. ICA API Tester is something that lists all the Image Capture APIs in a table view, and all you do is you can select the API that you want to look at and execute it. So it's basically a single-step thing.

Now we get a device list and now we could use the ICA Copy Object Property Dictionary for that device list object. And we see there's still no device, so there's something wrong with my connection here. But this here is really executing an API at a time. And let me see.

Turning on the camera. And an interesting thing on the side here is it actually shows you the contents of the camera. So if I would do for the device list, "Execute the copy object property dictionary call again. Then you see actually what this returns. And this here is the device array I was talking about.

So that's the information that I get per device." It's very handy to have this tool around because you can really verify, is something wrong with my application or is really the connection broken or whatever. So this also means that if I run the Step 1 application here, okay, now we get correctly the D70.

Okay, let's go back to the The problem with the very first step here was, while we run and do the initial query for the device dictionary, But we will not react on any change on the bus. So you turn on the camera, turn off the camera, nothing in the application will be updated automatically. So how can we make sure that this will change? Well, there's an API called ICA Register Event Notification. If you use that, then you can register for a single specific event, for example, device added or device removed. Or you can register for all events.

So in our case where we have a device list and two cameras connected, this could actually match if camera one is, for example, a PDP camera, this camera two is a mass storage device. Then that would internally type, we have also another user space, faceless background application that takes care of the different protocols. So let's say we disconnect the PDP camera. So then the IC object for that and also the module that is running the PDP code would disappear. And by registering for these device notifications, your application will actually get notified, as we will see in step two.

So step two, what we are going to do is we, in our Awake from Nib, We will call register for device notification. Now, this registration, as I said before, could be, and we would recommend that, you would do it for all objects, all types. So specifying a zero for object and notification type simply means do it for all types.

[Transcript missing]

Now, this device notification callback will get called whenever something happens, whenever there's notification from the device module up to the clients. And the simplest case could be device added or whatever. So what we do in here is we take the RefCon that we specified on the register call, use that to go back to the ICA handler, so we do not need a global for that, and call the handler with the device notification.

For the device notification, what we do is we check the event type. And if the event type is either device removed or device added, then we just get the device list property dictionary again. We made just from step one just a slight change, because for step one we were not anticipating that we had to be called, to be saved, to be called multiple times. So we would just add device names to it over and over again.

So we clean up first, and then we loop over the device array to get the information. So that simply means if I run this, We should now have our small My Photo, which in this case it starts up with the camera connected. I turn the camera off and immediately it says "no camera connected". So, kind of easy to get to that state that we will get notified whenever there's a change in number of devices. Back to the slides, please.

Now, how do we get more information about a device? For example, it would be interesting if we look at our iPhoto. Actually, whenever you have a device connected, you will see a text saying, "Device full connected and we have 57 images to download." So, we want to do a similar thing.

So, we want to display the number of images that we have on the device, and as before, the same thing we did with the device list, ICA Copy Object Property Dictionary allows you to get information about an ICA object. And if you use that with the device object, you'll get information about the device. For example, you get, again, the name, the type, device module, the connection info, but you get additional information.

You will get the device capabilities. For example, is this device able to take pictures? Unfortunately, not all PDP cameras allow you to do that. I really hope that more vendors put that in because, really, it's a standard PDP command, and it would be so nice. You could do so many cool things if the camera would support that.

And then two important entries. These are the data array and the tree dictionary. The data array actually is a flattened out array with images, movies, and sound files. So, but just looking at that array and looking at the count of that array, you know exactly how many images do you have on that device.

For each image or for each entry you will have a name, a size, the ICE object, and a couple of flags. For example, is it locked? Is it a raw image file? And that? and so so normal case normal situation it's it's fine to just look at the data array there might be some cases where you really want to have knowledge about the structure like what folder what sub directory is this image in or are there additional files for example firmware files or depof information things that are just represented as a file on the camera file system but are not that are not images In this case, you can use the Tree Dictionary to get to that information.

One additional thing would be really nice is if you could display the same way Image Capture application does it, display an icon for that device. So how are you doing that? Well, there's a new We have a new API, ICA Copy Object Thumbnail, that will return the device thumbnail in different flavors. So you can request the thumbnail, for example, as JPEG image, as TIFF, or as the uncompressed RGB data, which is our old ICA thumbnail format.

For device icons, I would really recommend to use the TIFF flavor because it has the advantage, it has the alpha channel. And most of the camera icons that you will have are ICNS-based images with alpha information. So just drawing that, it's way easier, it looks better if you use TIFF. So let's go to the next variants of our application. And in step three, we are adding a few things to the ICA handler.

We switch, instead of having just the array of device names, we want to have an array with actually the device dictionary and also a device list array that is more or less the device array that we get from the ICA copy object property dictionary for the device object, for the device root object. What we do is we, in the device list array, so we just copy the devices.

[Transcript missing]

An item in our table view, if there was a selection, which simply means that selected row is not equal to negative one, In that case, we want to do something special. We really want to display the number of images that are on this device. And the easiest thing to do it is, as I said, is really do an IC copy object property dictionary for the device object. In this case, you notice that we are doing an asynchronous call. Simply means after We send this off, we immediately return, and UI will be responsive.

We will get called with GodDevice dictionary. GodDevice dictionary, very thin global function that just dispatches back to our ICA handler. In our ICA handler, we look at the data array. Get the count and update our UI to display ready to import so and so many images. If the count is zero, let me just say, hey, there are no images on that device.

[Transcript missing]

We know now the number of images that are on this device. We want to get the camera thumbnail. Very simple to do is just go ahead, specify as thumbnail format, you specify, oh yeah, you want to have the TIFF variant. You fill in the object, the ICA object for the device. And you call ICA copy object thumbnail.

Callback function. And callback functions are just three lines of code dispatched back to the IC object. And what we do is very simple. We want to display that. "We have a camera icon, the thumbnail, and all we do is we get the data, Out of that parameter block, allocate an NS image, initialize that with the data. We show the NSImageView, set the image, release the image, and release the data, and we're done. Now let's run this.

So, we have a camera connected and now we do select this row. And you see we have already the number of images. "And the camera icon, very nicely. So we are about ready to import." Now, in step four, we want to enhance, based on the APIs that we were talking about, we want to enhance the application just slightly.

And let me run it first, then we look at what we are doing. So same behavior. But now we want to do something special when the user double clicks. Well, what we want to do is we want to give the user the choice to select the images that are on the device. And so before downloading.

So you don't have to download all the images. Just select the ones that are on the device. And for example, just select the last three, and we will update the UI. Three out of nine are selected and all that. So how do we do that? Well, for step four, there was not much to do. First thing we have to do is we have to special handle the double click on the table row. In order to do that, all you have to set up is a double action.

So this simply means when double-clicking on a row, execute this. Execute browse device. So browse device, all we do is we have a tab view. Where we switch away from the plank area and switch in to another table view where we display each image that's on the device.

And since we have now a second table view, we have to update our number of rows in table view. Now we have to handle, really to distinguish between the, is it the original one where we had the devices, or is it the one where we are showing the images? If you're looking at the one for the devices, nothing has changed.

The ones with the images, well, all we do is we just look at the data array and return the count of that. For now actually displaying the information, what we do is, if it's the main table view, nothing has changed, same as in the previous step. For the image view, in case of the row, we just return a number.

We're going to start with the string with the row number. Everything else, we make it very easy because what we do is we use the

[Transcript missing]

I'm going to do an ICA Copy Object Property Dictionary. And this here actually shows us the data array. And, well, that's the date. This here is the file size. The ICAO is the ICA object. We have the name. So all we do is we set up in our Nib file the identifier for each column to match one of these keys here. And we're done.

So very easy. Now one thing I want to mention is really when I was stressing it, you should use asynchronous calls. Another handy feature of the ICA API tester is it actually will allow you to create code for you. So instead of the run mode, you can go to the coding mode, and what you do is you just select an API, like ICA Copy Object Property Dictionary, and you can specify what flavor you want to generate the code in. So you can use the same code to create code for your app, and you can also use the same code to create code for your app.

And control slash will actually jump to the place where you have to do some modification. And actually, that's very simple to update your code. And it's, yeah, we were using that to create the different steps. And you will find it quite handy. Okay, back to the slides, please.

So step three and four, we were looking at the images, the number of images, the names. But now, actually, it would be nice to do something that the Image Capture application does. We want to have more information before downloading. So, for example, we want to get metadata. And the way to do it is use the same ICA Copy Object Property Dictionary. In this case, we're using it for an image object.

So we already had from the data array or tree dictionary, we had the name and size. Now we get the date and additional EXIF information. So, for example, we get the color space, we get the EXIF orientation, and for those who were attending session 209, where David and Luke were talking about ImageIO, yeah, you will see and you will find it more important on Mac OS X to really honor the EXIF orientation, and a lot of applications, Preview, Adobe Photoshop, and other applications just honor that. So when opening an image with an EXIF orientation, it will display correctly.

Getting to the thumbnails. Image thumbnails, well, same thing. We have the ICA object, ICA copy object thumbnail API. And you know already from the device case, it returns a thumbnail in either JPEG, TIFF, or uncompressed RGB. So for the device thumbnail, it was nice to use the TIFF variant to get the alpha channel. You'll see that for images, it is actually nice to use JPEG for a couple of reasons. First of all, it's smaller. It's the smallest of the three, size-wise.

But JPEG and TIFF actually allow you to get thumbnails of the images up to 160 pixels, where ICA Thumbnail has the limitation of 128. So if you want to have like little bit larger images, larger thumbnails in your application, I would really strongly recommend to use either JPEG or TIFF, and in the image case, really use JPEG variant. So back to the demo machine where we are going to enhance our small application.

And in step five, we want to get-- let me run it first and see what's going on. We want to get image thumbnails and more image metadata. So just selecting that looks the same. Double clicking. You see, we first get all the thumbnails and then additional information. So for example, we get the size, the color space, one means it's sRGB, whether you get information whether the flash was on or not.

If you look at the EXIF spec, you will get actually detailed information. So 31 is not only saying it was on, but also what mode the flash was, was it red eye reduction or whatever. You get information about the exposure time, the F number, model, and much more.

And then again, you can select one or multiple and then we would, in the, um, Application just updates the number of selections and we are more or less ready to download. So before I go into the code changes for step five, let me just quickly show you if we run this in our test app, just pick whatever I say object and let's do an ICA Copy Property Dictionary. It returns this array. So for example, you get the maker node and model information. You'll get creation date and time. All these numbers up front, check out the EXIF spec. These are basically the numbers that are defined in the EXIF spec.

Let's quickly look at the ICA copy object thumbnail. So if I take the same ICA object, I can get the thumbnail for this in different variants. So this, for example, is the raw format, 128 by 96 pixels width and height. And the data size, it's uncompressed, it's like 49K. If I get the same thing as a JPEG, Then, you see it's 160 by 120, but we are only using 11K. So it's larger, but uses less space.

So back to our My Photo app. And what we do in--

[Transcript missing]

Metadata we do is, whenever we were selecting, By double-clicking, executing the browse device method, whenever we were selecting a camera, we start fetching image thumbnails. Now fetching image thumbnails, all I'm doing is I look at an array that has the current thumbnails. That's the thumbnail count up to date. And the image array is just the data array out of the device dictionary, which, as I said before, has the total number of images for that device.

So if our thumbnail count, thumbnails that we already got, that's less than the image array count, which simply means we have to get more thumbnails. Then we ask for the next thumbnail. In this case, we ask for JPEG format. We put in the correct ICA object. Out of the image dictionary, which is at this thumbnail count index, execute the copy object thumbnail call and On the callback, we just dispatch back to fetch image thumbnail callback.

In case we run into an error, it should not happen, but for whatever reason, Image Capture may not create a thumbnail for a corrupted file or so. What we want to do is we just use the NS Workspace icon for file type, where we specify JPEG as file type. Just give me a generic icon, and we would add that to our thumbnail array. In case everything was working without problems, then we get the thumbnail data.

And out of the thumbnail data, we create an NS image. We add that to our array.

[Transcript missing]

After that, we start. We just call fetch image thumbnails again. Which would, in case we are not done, so image thumbnail count is still less than the number of thumbnails, we would start over again, get the thumbnail for the next IC object. But eventually that will be done, which simply means the thumbnail count will become equal to the image rate count. In that case, we start looking for metadata. So fetching metadata.

At this point, simply, that's the same thing now instead of doing it for thumbnails, we do it for metadata. So we have the metadata count of this array. If this is less than the image count, use the same array to compare against. And then instead of getting the thumbnail, we get the property dictionary. With this callback, again, dispatches to us. It's straightforward, more or less. You did it once, and you can do it very easily for the next properties to get.

So, in case there was an error, again, should not happen, we just put in or add an empty dictionary. Otherwise, we add the metadata. That we get back from this ICA Copy Object Property Dictionary call. We again reload the table view so it should now update the The metadata and ask it to do the next one.

Again, this here will eventually end, so we will be done. And whenever we are done, we're done. I mean, there's nothing else to do. So let me run it again. Just... This double click and you see there's really no need to do any threading or whatever. Just the fact that we do asynchronous calls while it's getting these. So if this camera would have like hundreds of images, it would still be able to interact. We could resize the window, we could do whatever we want, and everything would just work.

Okay, so at this point we are almost there, almost ready to download the images. If you go back to the slides, please. The next thing would just be the way, how do we really download the images? There's an API called ICEDownloadFile that does not only download images, but any other files as well. So everything that is represented by an IC object can be downloaded. All you have to do is you specify a download folder, you specify a couple of flags. For example, you can, for images, create custom icons, ICNS resources that we would add to that image file.

It could be handy if you really need the images like in column view or whatever, or list view in Finder to display these files. You can specify to rotate, and David was mentioning that in session 209, that with Tiger, beginning with Tiger, Image Capture is no longer manipulating the pixels when doing the rotate.

So all we do is we update the EXIF orientation tag. So we are not touching and we are not decompressing, recompressing the images. Because that was a complaint from a lot of customers saying, "Well, I rotate this image in the Image Capture app, then downloaded it, and then the size was different. Why is that?" All it was just because we had to decompress, recompress the image to get it done. But now, since more and more applications are really using the EXIF orientation tag, that's really no longer needed.

Other interesting options are delete after download. So whenever you want to just get in the images and want to free up the memory card on the camera, you can very easily do that by just specifying that flag. And we will, only in the case that the download was successfully done, we will delete the image.

A very nice, convenient way is really just the creation date. That simply means that we look at the exit information inside the image and update the file creation date on disk after downloading. So in Finder, you could just do a list view, sort by date, and then you know exactly when you took these images.

"Mode devices that you can use by just going into the Image Capture application and share your devices on one machine. Then you can go to another machine. And that should work for cameras pretty well, even if the machine one is your Intel box and the other one is the PowerPC variant.

So that's something we are taking care of." The download images also takes care of color management. Color management in the sense,

[Transcript missing]

In order to find out what profile that is, you just go to your utility folder, application utility, ColorSync utility, launch that, and then in the device tab, you will be able to select the camera or scanner that you have connected.

And you can see what profile was registered for that device. You can override that, so if you want to use your own profile that you did create. Then we will use that. And we will have a special handling for EXIF 2.2 files, where the file itself has enough information to generate a ColorSync profile automatically. So let's go back to the demo machine and then in step six we are now really adding the download functionality.

And we want to do it in two different ways. One is have a download all. So if you just-- Let's run it. And you noticed I was adding now already a little bit more towards the final My Photo. So you will have later on the library or if you want you can do your own last role implementation. And so we have the camera. And on this mode, we can just press the import to download all the files or, as I said before, double-click, select an image, And you can import this one. And you see it actually did work.

Or at least it brought up a progress bar, and there was something going on. Now, it does not open the file and nothing else yet. But if we go to our...

[Transcript missing]

Six images. And this time it takes a little bit longer because previous time these images were already on disk and Image Capture is smart enough, not double downloading image files, just checks, oh, is there an image with the same name, same exif creation date? If that's the case, then there's no need to download it again, and it just skips those. But now we see the six images that were selected are downloaded and are on our hard drive.

Okay, so what do we have to do? Well, for the import all case, What we do is we look again at our data array, and then we put everything In a special mutable set, mutable index set, all the indices that we are going to import. Well, in this case, it's basically all indices in the range zero up to the count.

And we will update some progress information. For example, you saw that we are displaying a text while downloading, and we have a progress indicator while downloading. So we set this up. And then we just call import images. Now this is very similar to the import selected, except the way to get to the indices is different. In this case, all we do is we ask the table view, give me an NS index set of selected rows.

And we use that, store that in our data member, set up the progress handling, and call in to import images. In import images, all we do is, well, we have the index set. This is basically a mutable set. It has all the indices of the outstanding downloads. Simply meaning, if the count of that one is zero, then we are done. We have everything downloaded. Simply meaning, if the count of that one is zero, then we are done. We have everything downloaded. Simply meaning, if the count of that one is zero, then we are done. We have everything downloaded. Which points to our tilde/pictures/myphoto.

[Transcript missing]

We specify the IC object and we specify our options. In this case, the only options that we have are really the Create Custom Icon. So in Finder, we will see the custom icon. And we really want to adjust the creation date. So in Finder, you would see that I took these images yesterday.

And then we call ICA download file, specify a callback proc. Callback proc, same thing as before for all asynchronous calls. We just patch back to the ICA handler. And in this case, all we do is, like, the file was downloaded. And what we want to do is update the UI.

We, uh, the progress indicator, just increment that by one, and the string value, we just want to display the number of images remaining. And call the next import images. Remember that was... This is done until the count gets down to zero. In this case, we are going to hide the progress indicator and also the progress text.

Okay, so up until this point, we are able to display connected devices. We are able to display the images on those devices. User can select what files to download. User can actually download the files. Now, if you go back to the slides, Next thing that would be kind of nice is really controlling the device. So for example, how do you tell the device to take a picture? Well, there's an ICA Object Send Message API that allows you to do various things. For example, it allows you, if the device supports it, to send an ICA message, "Camera, capture new image" message.

The interesting thing about this way of talking to the device is really the IC object send message call will return immediately. So it will not wait until the camera has the image and is done processing the image, saved it on the internal memory card. It will return immediately. And you will get a notification whenever that's done.

[Transcript missing]

For example, a lot of vendors are going to the PDP over IP protocol to have kind of airport wireless 8211-based devices where you can go around, pair that with your computer, go around, take pictures, and the computer will actually get notified, oh, there's a new picture.

So all you have to do in order to work with this model is you have to register for event notification. So you have to be prepared that there's an ICA object added message sent to your application. And you can update the UI. You can add an extra entry. And now, step seven, we will enhance the application. And I'll show you how to do that. So let's run it first.

And it should look like exactly the same way as before. But notice that when I select the camera, there's a new "Take Picture" button. The "Take Picture" button just brings up a new window. And it actually allows you to, and I can show you how the setup looks up here. So I can go to this button here and say take picture. That's not bright enough, it is.

Can you actually bring up the light a little bit? Yep. I think it doesn't want to.

[Transcript missing]

Take a picture and it actually updates the screen. And now just imagine you do that with your wireless camera. You have a 30-inch display, or maybe a set of 30-inch displays, and then just walk around, take pictures. That would be a really nice way to entertain people at a party or so.

Okay. Now, interesting thing. See, I turn off the camera, and this window goes away. And so what did we do in order to get that to work? First of all, when getting the device dictionary, we have to check the capability array. Basically find out what does this camera support.

Does it support take picture? And this capability array is just encoded the OS types, in this case the KICA message camera capture new image. If that's part of that array, then we... "We unhide the take picture button, so we show it and the user can select it. Now if the user selects it, then all we do is we use a new class, we have a new ICA take picture handler. We're asked to show the UI. Show the UI is kind of straightforward because we get passed in an ICA device object.

We load the new bundle, that's the window that we are going to display. Keep reference to the device object. Go with that window to kind of full screen. So we get the main screen's visible frame, set the Windows frame to that, and make it key and order front. Then, next thing is really we register for event notification.

And whenever the user presses now the "Take Picture" button, we send off a message to this device object, "I see message camera capture new image." And as callback, we actually ignore it because there's nothing useful that comes back from that API. I told you that IC object send message returns immediately and the image is still not captured at that point.

[Transcript missing]

We look at the event type of event object added. We get notified when the image was saved. In this case, we just download. But notice also here that in case of the event device removed, we actually want to close the window because it makes no sense to keep that window up when there's no device connected. So let's look at the download object.

Very similar to what we had before, except in this case we just download to the temp folder. And since we do not want to fill up in this mode, we do not want to fill up the memory card, what we do is just specify the lead after download.

Once the image was downloaded, again, the small wrapper, the... Callback. Once the image was downloaded, what we do is we create a reference to the downloaded file, FS-Spec, make a path out of it. And create an NS image, initialize that with the contents of file. And all we do is we have an image view in that window and set the image and we release the image and we're done. Okay, so we can handle take picture. Go back to the slides, please.

What do we have to do to work with RAW files? Now, more and more camera vendors are using RAW files, and a lot of users are going to use RAW files because quality seems to be better. So how do we handle these? Well, the good news is we don't care about that because there's a new ImageIO framework that ships with Tiger, and that takes care of a lot of things.

For example, with applications like Image Capture, Preview, Safari or so, they are able to, by just using ImageIO framework, they are Automatically supporting file formats, image file formats like TIFF, JPEG, and all these, but also camera RAW files. Automatically supporting file formats, image file formats like TIFF, JPEG, and all these, but also camera RAW files.

We just use ImageIO to create CG image refs for us, and we just display those. ImageIO does not only deal with the actual image data, but also supports metadata. So all kind of metadata variants are supported. And the really cool thing about that is it's the same set of APIs no matter what image file format you have. So all kind of metadata variants are supported. And the really cool thing about that is it's the same set of APIs no matter what image file format you have.

Main things, reading and writing in ImageIO. For both variants, they have special objects like CG image source. The image source can be created by passing in a URL or some data that you have or a CG data provider. And I just want to point out, because in step eight, we are going to use ImageIO to display images that we just downloaded. We mainly focus on the image source, create image at index. Which just gives you, for a given image source, a CG image ref pack.

A very nice and powerful, as we will see, API is the Create Thumbnail Ad Index. Because it allows you for all images, even those that do not have originally embedded a thumbnail, it allows you to create a thumbnail. And there are some nice options that you can pass in.

For example, you can specify, create this thumbnail with this maximum size. And we'll see that we are using that for thumbnails that are a little bit larger than what you would expect, larger than the 160 pixels or whatever. And the other nice thing really is getting to all the metadata.

On the writing side, actually our step 8 is not going to support writing, but after looking at the samples from session 209, you will be very surprised how little code is needed and you can very easily add that, integrate that into this app and you have your full functional image browsing, editing, and exporting application.

So let's go to step 8 and Let's see how ImageIO framework can help us to display images that are inside our download folder. Well, first of all, we have two new classes that we are going to use. One is a file browser view, and the other one is an image view.

For the file browser view, what we do is whenever there's a table view selection that changes in our main table. So remember, that was the table where we have the camera and then the last role and library. So whenever we are not selecting a device, then we switch our main tab.

[Transcript missing]

So the File Browser view, when created, actually just has in images just a mutable dictionary that's empty and gets filled in update files. The folder we are interested in is "My Photo". We ask the file manager for the contents at this path. In this array, we get a list of all the files inside that path.

The images that we already have imported are in M-images. So we get all keys and create a mutable set with all the keys, with all the file names that we already have. And now we just do two things. We remove the images that are no longer on disk, because the user may have in Finder removed something. And we're going to add images that are on disk, but not in our internal data structure, in our My Images.

After that, the only thing we do is, doing it really lazily, in DrawRect, we blindly draw all thumbnails. Now, really, you have to know this is not like shipping code because this could really be optimized. What we do is, like, we iterate over all the images and we are not taking care of, for example, is this thumbnail visible? So we are drawing always all the thumbnails. You, in your shipping application, hopefully will test the rect that will get passed in to the draw rect and draw only those thumbnails that are inside that one.

So, in case we look at the M-Images object for that current name, if our dictionary The M-Images dictionary has already an entry. And we are fine. But we start off, as we said, we do a lazy initialization. We start off with no entries, no information about a given file. So what we want to do is we want to get information and get the thumbnail for a file. And we use ImageIO to do that.

So what we basically do is we get a URL, create an image source with that URL, And now we use the Create CG Image Source Create Thumbnail at Index. Note that we specify a couple of things. For example, we specify the maximum pixel size. "Which is just defined that we have somewhere, and in our case I guess it's 600 or so. So, a fairly large one." Then, this one here is very interesting because it helps you to just draw a thumbnail without A need to look at the EXIF orientation tag.

So for thumbnails, you get that for free. You will get the thumbnail. The image will be rotated in a way so that it looks correct. And in our case, we always want to create it, even though the image itself may have an embedded thumbnail, we always want to create it because our max pixel size is very large.

Now, when we have that, on the drawing side, well, all we do is, like, we get the icon, Get the thumbnail. Since we have our browsing view flipped, we just have to set up the CTM to take care of that. So we flip and offset that and draw the image.

One nice thing we can easily do is actually we can allow the user to change the thumbnail size. So if I run this, I see, oh, these are the images that we have in our download folder, and yes, we are able to resize. And it's speed-wise okay, but it could be faster when just taking care of. I mean, there's really no need to display more than one thumbnail in this case, if I have enlarged it, something like that.

But you will also see that the thumbnail, this, the first one here, is auto-rotated. So, without doing anything, just specifying that option, everything is handled correctly. Now, On a double click, so mouse down, double click, what I want to do is I want to find out in a loop what thumbnail that was, and then ask the ICA handler, show the image.

So, show the image, for the handler simply means go yet to another tab, "Hide the thumbnail slider and call back into the file browser view, show image at index, which just sets up a path, has an image view, and now we are back to our original image view, sets the image path, and very simple, use ImageIO, CG image source create with URL. We use a dictionary where we specify "yes", do cache this image, and allow float. We create the CG image. We'll cover the fine details on how to support digital cameras and scanner with ImageIO.

Learn how to take your application to the next level of performance and capability. So we create that, the properties. We just keep a reference to the image, the metadata, and draw it. When drawing, all we do is we draw the background with gray, and now draw the actual image.

And actually, this is the same code that you get from the Image app from session 2.9. So I will not talk much about this. The only change I made can be useful in your app is if you want to have a little bit faster live resizing, what you can do is actually you can take advantage of the notifications that your view gets when the user starts live resizing.

And there is a "will start live resize" and "view did end live resize." We just keep a flag and at the end of "did end" we just re-display. Now in our drawing code, we just honor that flag. If we are in a live resizing mode, then what we could do is set the interpolation quality to none, which actually allows for a little bit faster drawing. Thank you.

You will notice that, for example, I double-click on this one, that while I'm doing this, it's actually pretty snappy, but if I release it, then it's very fast, it's a very small image, but whenever I release the mouse button, done with the resizing, then you would see it redraws with better interpolation quality. Okay, so I guess this is from zero to my photo in eight steps, and let's quickly go back to the slides.

We have some more samples for you. Actually, the new Image Capture SDK will be posted either today or tomorrow. Hopefully, really by the end of this week you will have the new SDK that has not only the tools that I was showing, but also some interesting new samples, for example the time lapse, which is... Just focusing on the same things we did, but for cameras that allow, like PDP camera, that allow to take pictures, what it really does, it takes the picture, saves it off, and creates a quick time movie out of it. And if you have enough time, I will quickly show you the movie that we did last year from WWC, the event on campus. And the other new sample code is the Copy Machine, which is a small scanning app.

It can be used as a real copy machine because it takes care of the button press that you have on your scanner. You can press a button on your scanner. This small application will get launched if you specify it in the Image Capture application. Launch this app when this button is pressed. And what it does, it makes a full scan and prints it out. You have the sample code for that. And then the last thing I want to mention is really Image Capture and Automata. They are two acts. And... It's very easy to do.

So for more information, I just have to refer to the developer page. Related sessions, well, as I mentioned before, session 209. Unfortunately, that was already just before this one. Then there's lab tomorrow and on Friday the graphics and imaging feedback session. For any kind of questions, go over to Travis. And I guess we go to Q&A and one more.