Media • 33:24
Aperture's extensible architecture makes it easy for photographers to integrate 3rd-party image editing plug-ins into their RAW workflow. Get introduced to the Edit API built into Aperture and learn how to develop your own plug-in to manipulate images and metadata within Aperture. See how to send metadata back to Aperture, completing the workflow loop.
Speakers: Blake Seely, Joe Howard
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
So this session is obviously all about Aperture's new image editing API and how you can get your image tools in a user's Aperture workflow and right in front of Aperture users. So here are the few things we're going to cover today. Obviously, we're going to talk about the new Aperture 2.1 SDK that has everything you need to get started, walk through how to build a new image editing plug-in, show you some of the features, what you can do, how to get image data and metadata out of Aperture, how to get image data and metadata back into Aperture, and we'll show you some sample code as well.
So first let's talk a little bit about what Aperture is for those of you who aren't familiar with Aperture. Aperture is Apple's end-to-end digital imaging, digital workflow tool. So it's designed to get images from your camera all the way through out to output, whether that be books, web, prints, anything. And in between we have a really extensive, rich set of organizational tools, library management, all kinds of ways for you to slice and dice and search, sort, filter your images.
And it's really designed to simplify the RAW workflow, which before Aperture was a much more complicated process. Obviously we work with all kinds of image types, whether it's JPEG or TIFF or Photoshop. But, you know, the goal is to really simplify the SLR RAW workflow for our users.
One of the key things about Aperture is it's a non-destructive editor. This is very important not just for how Aperture works, but it also has ramifications for how the editing API is going to work as well. So what does non-destructive mean? It means a user's making all their changes in real time and Aperture's actually making them on the fly for the user. It's not like Photoshop where we're going to make some changes and save them out to a file.
When the user clicks on an image, Aperture's actually going to read that RAW data and show it to them on the screen. And if they make an exposure adjustment, Aperture just remembers the instructions, "Okay, I'm making an exposure adjustment next time they bring up the image." And that also means you have multiple different versions of one image that's a file on disk.
So, you know, if I have this picture up here, I can make a black and white version, a cropped version, a saturated version. There's still just one file on disk, but each of the images in Aperture is actually just Aperture replying some changes in real time. And then new for 2.1 with the editing API, we actually ship a dodge and burn plug-in with the application. So users can--are already using plug-ins and get a feel for the workflow and things like that.
So what are some things you can do with the Edit API? So obviously, I mentioned Aperture has really rich metadata features and library management features. Those are available via the API. You can get all of the metadata that Aperture stores for an image. You can even send some of that metadata back into Aperture. We give you control over some features, such as stacking and importing images into the database as well.
And like we got listed up here, there's really three different plug-in types that we had in mind for Aperture. Maybe you'll come up with something new and different. But the features that we designed around were for these three things listed here. The first is a RAW decoder. Maybe you want to support a camera that Aperture doesn't currently support. Well, the API gives you access to, here's the RAW file on disk.
Go ahead and read it. Do what you want with it. Import your results back into Aperture. Or maybe you're a type of imaging plug-in that can really take advantage of the high dynamic range of RAW. Go ahead and read that file. Import your results back into Aperture. aperture.
The second type we looked at is what we call the single image or one-at-a-time case. And this is how the Dodge and Burn plug-in works. The user's going to bring it. Maybe they selected several images, but one at a time they're going to bring up the plug-in, make their changes, save, and go to the next image. And then the last type we really looked at is the multi-image or compositing. This would be something like HDR or panoramic, or maybe the user's going to select several images.
And what they want your plug-in to do is combine them all into one image and get that result back into the Aperture database. And so I mentioned non-destructive inversions before. All of these things are going to work on what we call editable versions. So let's take a look at what those are. So we had a couple goals with the editing API, and one of them is really to provide a simple API that gave you guys as much freedom as possible to do anything you wanted with these images. Not a lot of constraints on UI.
Not a lot of constraints on performance. And so what we decided to do is extend a workflow that already exists in Aperture, and that was for our external editors. For if users want to open a file in Photoshop, for example, we extended that to the editing API. So we have editable versions, and when your plug-in wants an editable version, Aperture actually takes the way that image looks on screen and writes it out to a file as is, and then we give that file to your plug-in. So we're going to do a little bit of editing here. So let's take a look at the file that we're going to be editing. So we're going to do a little bit of editing here.
So, to talk a little bit about what we just showed and some of the things that we just discussed and how Aperture works, I'm going to bring up Joe Howard and he's going to give us a quick demo. So let's switch to the demo. So at first here, we're just going to show a little bit of overview of what Aperture is in case you haven't seen it. And you see on the left here, we have a column that basically has all of the project organizations. So you have your projects, your different album types, if you have web galleries or you want to show different light tables, all your different images.
However the user wants to organize them are there. Then you can have all of the images in that album or project are going to be available in the GridView area. The selected version will show up in the viewer. Not very complex there. But you can also see that there will be some fancier features inside the GridView that we'll talk about later, like stacks, right? Where you can have the user can actually associate all the different images that say they were closely related in time like these or very similar.
And they can stack them together. And maybe you had all sorts of different shots. You want to figure out which -- the user wants to figure out which one they like the best. And they can just say, "Oh, I really like, you know, this one because the guy is making a funny face." Move that to the top of the stack.
Close it. And then all the rest of those images, they never have to see or deal with again but are still there. So that is kind of a quick overview with that. Other ways you can find information in the UI is the tab here for metadata. For the selected version, it will show you -- here is all of the metadata that the user has access to on the tabs at the bottom is where everything is at. And then another tab for the adjustment. So if they want to make large changes across the whole image, so say change the exposure or contrast, make a black and white version, anything like that, they can do that without affecting the original raw file.
Any time, the user can also go and say, "Oh, I want to duplicate this," and say, "I want to try and -- maybe dork around with, you know, little highlights and shadows." Or really make any sort of changes that they want and not have to worry about, "Oh, well, did I ruin the original image?" It's all right there.
So another thing we can show is rather than just doing large adjustments across the whole image, we now have a plug-in with Aperture 2.1 called Dodge and Burn. And this allows us to do selective adjustments. So you can go to the Images menu, Edit With, Dodge and Burn.
So in this window, you can very easily select one of the tools here, dodge, burn, saturate, blur, anything there. Set the size, how much strength you want to apply. I'm just going to make some big changes here so you can see that it's actually making a difference there. And then you can go, maybe I want to erase, did a little bit too much there.
I want to feather and make-- ease in the edges a little bit. Whatever you want to do to really-- Make selective adjustments to just part of the image, and then the user can very easily go in and save. And those changes go right back into Aperture, and the user has now made those changes. So that's our first demo. Let's switch back to slides.
All right, so that was just a quick look at what Aperture does and a little bit about versions and editable versions. So now let's talk about the SDK specifically. It's available on developer.apple.com, who I assume, if you're here, you're already members. You can just grab it there by clicking on "Apple Applications" and clicking on "Apple Applications Downloads." That should be one of the first few things in the list there.
You have to use the SDK to get started. It includes everything you need, all the headers, docs. We have project templates for Xcode, so when you go "New Project," one of the options under "Standard Apple Plug-ins" is a new "Aperture Edit" plug-in, which has all the basic code you need to get started, includes all the headers, and is set up to actually build and put your plug-in in the right location even.
So we also--you know, the API itself is in Objective-C, so you have to make your calls, you know, using Objective-C, but we included both Cocoa and Carbon samples. You know, some of you are Carbon developers, and you want to just duplicate that sample data, or if Carbon's just what you're familiar with, we included a sample there so you can take a look and get started.
Just one thing to keep in mind is, you know, Aperture's already--Apple has already stated that they're moving towards 64-bit and things like that. Just keep that in mind when you're building your plug-ins, that that's the direction the company's taking. We're not making any specific forward-looking announcements about Aperture.
Just that's Apple's stance right now. So again, built-in plug-in that we just took a look at and attached to this session on the attachment is the "Apple Appliance" plug-in. And attached to this session on the attendee website, there's also some sample code above and beyond the SDK that we'll take a look at later.
So there's one thing to mention about the actual plug-in architecture we use. How does Aperture discover plug-ins, manage its plug-ins? We use an architecture called ProPlug. Now, I only mention this-- you really don't need to worry about it. I only mention it because it does show up in the API a couple times.
The first place is when your plug-in actually gets initialized, there's a little brokering about how you actually get to talk to Aperture. The code to do that is actually part of the template and part of all the sample code, so you really don't ever have to worry about it. But if you see it, now you know what you're looking at.
And then also, in your Info.plist file, there's also some keys that say ProPlugin and that help Aperture define, you know, find your plug-in, figure out what kind of plug-in you are, what protocols you support. So you'll see ProPlug there. Again, the Info.plist file is fully documented, and it's almost all filled in for you already. So again, you don't really have to worry about it much. Just wanted to make sure I mentioned it.
So the two critical protocols, the two things you really do care about are listed here. The first is called Aperture Edit Manager. And this is, when you get an object that obeys this protocol, this is Aperture. When you make these calls, you're actually asking Aperture for information or asking Aperture to do things for you.
This is how you're going to find out which images the user had selected in their browser. This is how you're going to get thumbnails. This is how you're going to get the metadata. This is how you're going to tell Aperture, I want an editable version of this image. And this is how you're going to pass metadata back into Aperture's database. The second protocol listed here is called Aperture Edit Plug-In. And this is what you're going to implement. It's a very simple protocol. There's only two required methods on it.
If you're going to do imports into Aperture's database, you're going to need to have a very simple protocol. If you're going to do imports into Aperture's database, those are asynchronous, so there's actually two callbacks you'll need to implement in that case as well. But like I said, it's a very simple protocol, and we'll actually go over both those methods here.
So what does the actual flow of API calls in an edit session look like? This is it. Aperture's going to tell you to start the edit session, do some stuff, and then you're done. So obviously the devil's in the details in what that do stuff step is, so let's walk through what some of the specific API calls are here.
So after your plug-in gets initialized, the very first call you're going to get from Aperture is called Begin Edit Session. And this is basically the message to you to open the floodgates. You can start making any calls you want in the API here. You shouldn't be making any API calls before this, but maybe right here you can start building your UI, start getting metadata, start getting thumbnails, start doing anything you want.
The second call you're going to get is called Edit Window. And this is the key to your UI. All you have to do is return an NSWindow from this method, and that's it. It can't be nil. You do have to return a valid window, and that window should have your whole UI in it. We don't care what it looks like, how it's constructed, you know, what the UI actually is.
You just return a valid NSWindow. Aperture will put it up on screen and run it modally for you, which is another thing to keep in mind is that your plug-in, your UI events and everything you're doing will be running in a modal state. So if you do a lot of run loop work or if you do timer work, just keep in mind that those things need to work when the application is running modally.
and then we have Do Stuff. So this is going to be a little less structured. There's a bunch of different API calls you may want to make here. But the key to this step is this is where you're doing your magic to the images. Whatever your special imaging sauce is, that's what you're going to do here, mixed in with some API calls. You know, I've listed some of the features here. We're actually about to walk through some of the specific API calls that are most critical.
So, these first three methods I listed here are methods that you can call on Aperture, and they're your way to find out what does the edit session look like right now? What's going on? The first one listed here is probably the most important, and it's probably the very first call you're going to make once Aperture calls begin edit session. It's called SelectedVersionIDs, and what it is, it returns an array of unique ID strings that represent the images the user has selected.
If they have, if they selected one image and said, run your plug-in, there's going to be an array with one item in it here. If they selected 10, you're going to obviously get an array of 10 items. It doesn't matter, it's not important what's in these unique ID strings. What's important is that each one represents an image in the user's database.
And these are what you're going to be passing around to all the other API calls when you want something done. So, again, SelectedVersionIDs is probably the first thing you're going to do. EditableVersionIDs is every time that you get an editable version, the unique ID for that will show up in this method, or in the return from this method. And every time you import a new version into the database, it'll show up in this third method, ImportedVersionIDs.
So after you figure out what the user has selected, you're probably going to want to start getting some information about those images, either thumbnails to display in your UI or maybe metadata about those images so you can make some decisions based on metadata or put it in your UI as well.
So the first one with kind of a long name is Properties Without Thumbnail for Version. And you pass in one of these version strings that you got in the previous slide or from the previous calls. And then the second one is Thumbnail for Version. We give the option to get three different sizes of thumbnails depending on what you want to do.
What you'll see from a lot of plug-ins, which is a great performance tip, is instead of operating on these gigantic images right away, maybe you want to get one of the larger thumbnails and actually perform your image operations on that first. If the user doesn't need or if your plug-in doesn't need one-to-one pixel-for-pixel views of an image, this is a great way just to get up and running quickly and have your image operations go really quickly.
One thing to be careful of is these thumbnails are auto-released. So if you're doing a really tight loop, maybe you're building your UI, maybe you're examining images, be careful about getting a lot of these thumbnails in a really tight loop and not releasing them or not auto-releasing them because they will start to suck up memory pretty quick.
And then we get to probably the two most important calls in the entire API, because this is how you're going to get editable versions of images. So like Joe had the picture of the soccer player. He went to Dodge and Burn. What Dodge and Burn did is get the selected version IDs, pick one, and say, I want an editable version of this. What Aperture then does is take whatever the current appearance of that is, writes it to disk as a TIFF, and then the plug-in reads it to-- so you can do dodging and burning and painting and stuff on it.
Once you make this editable version, you're actually going to get all the properties for that new version in the return from this method. And then you would take the unique ID and use the second method, path of editable file for version. And that's the only path that your plug-in should ever be writing to, is what you get back from the second method here.
There's a fail-safe built into Aperture that if you pass in a string or a unique ID that's not actually editable, that Aperture thinks you can't write to, you'll get nil back. It won't pass you back anything here. So make sure you're calling this method, you're getting a valid path back, and that's the only file you should ever be writing your image changes back to.
So that's the basics of, you know, the most simple flow. The last thing you'll do is you'll tell Aperture when your plug-in's done. This is basically telling Aperture, "I'm ready to be released. I'm ready to be cleaned up. My plug-in's ready to go away." One caveat here, make sure you don't have anything scheduled on a run loop that will call your plug-in back later. Make sure you don't have anything running in separate threads at this point that'll call back later. As soon as you call this, Aperture will release or auto-release your plugin, and you'll get deallocated.
So that's the basics. I'm going to have Joe come back up. He's actually going to show us a little bit about getting started and show us some sample code. All right, so we're in Xcode here, and I want to start just a brand new edit plug-in. So we have a project template in the standard Apple plug-ins for Aperture Edit plug-in. And with this, you can very easily just create Oops. A new project that has a lot of the basics and the structure already filled in for you. So I just wanted to show you a couple things in this project that is already provided.
First thing is the InfoP-List. There's a little bit of setup that you actually want to do here for any plug-in that you're going to create. There's-- generally for any plug-in or any bundle, there's some information you need to provide, principal class, that kind of thing. But ProPlug, this is one of the places where you'll see that in order to determine, you know, what is the actual main plug-in class here that the ProPlug interface needs to talk to. So this is just automatically filled in with the name of the project. You can rename that, change it to something else if you want there, too. A lot of the other things, maybe you don't really want to change the group. In fact, you're not supposed to.
But you do need to provide your own unique identifier for your particular plug-in. So all you really have to do here is switch the terminal. and type uuidgen. They return, and this gives you a brand new unique identifier. You can just copy and paste this into your Info.plist, and then Aperture can then refer to your plug-in across relaunches and various things that it needs to do to keep track of your plug-in.
The other thing that we'll show you with this code is, in the test plugin, I just want to show you one little thing here. And that is the init with API manager. This is the designated initializer for a pro plug plugin class. And really, there's not a whole lot you really need to worry about here.
All we're really doing is getting the API for the Apture EditManager protocol, and then we get the EditManager object and we store that in instance variable. This is our communication with Apture, the application. So anything we need to do, we can get a hold of that through this call. And then we really don't need to worry about pro plug ever again. So that's already provided for you.
Let's see, just a second. Now, I just want to show you the sample plugin that we've created. It's called Borders and Titles. And there's just some images here that just really want to be-- have a new title on. So what we can see here is we have this cat. And it's just a great image here. And we can very easily go in and say edit with Borders and Titles. This is where your plugin will show up inside the UI.
And from here, we can do various things like change the border size and color, add any sort of text attributes that we want. So we can very easily just say, OK, I want to have a border, make it-- oh, let's make it a little more obvious here. And we can pick any color from the image. We can do anything we want there. At this point, I can also add any text. Thank you. Ah, pink's fine.
That keeps resetting. Anyways. And we can just do-- All right, and we can very easily reposition, change the font. These are attributed strings, so we can do anything to these texts that we want to, add shadows, change the size, use any custom fonts. Anything we want to do, we can very easily do to this image.
At this point now, the user's made their changes, and they're ready to commit them. So all they have to do then is click the Done button. The sheet comes down. We're making an editable version of the original file. And then you can see the original is stacked with the original version, and the changes are made.
There's one other really cool thing that we have, too, to integrate with your plug-ins is that you can actually go into the commands, customize here. This is just a feature of Aperture, but we also include your plug-ins in here. So you can very easily assign your own keystroke to-- The user can choose whatever keystroke that they want to-- want to for your plugin. Save that. And now I want to show you the code for this plug-in.
So we're inside here, and back at the API Manager call, earn it with API Manager, it's pretty much exactly the same. So again, you don't have to worry about that. The next call that's going to come is when Aperture asks for your begin edit session. And really, this is your first chance to communicate with Aperture and get any sort of information. So this is the first chance. First thing we need to do is get a hold of the selected ID, selected version ID.
So we grab the selected version IDs, and that's an array. I'm only interested in this plug-in with the primary selected version. So I grab the first one and hold onto that one for later whenever I want to use it. The next thing I want to do is actually get a thumbnail so that I can display that inside my user interface.
So I basically ask for the thumbnail for version, and I just want the thumbnail size. I don't need a little tiny one that I can use in a grid view or anything. I just want the little one, or the thumbnail. At this point, I also need to get one more bit of information.
And that is, what is the full size of the image? Because since I'm operating on a smaller version of that as the thumbnail, I need to scale whatever changes I'm going to do on my thumbnail for my preview, such that when the changes are actually applied, it will look correct. So I ask for the properties without thumbnail for version, and I get a dictionary of all the different properties I can get. There's the export key image size. This is the full size of the original master image.
And there's all sorts of different properties. Anything you want, EXIF, IPTC data, anything, it's all in there. All the keys are provided, so you can get a hold of whatever metadata information you need. Let's see. So the next thing we're going to do is when Aputure then asks for our edit window, I need to load my UI. So I basically just load a nib and return the window. Nothing too complicated there.
And then, in a week from nib, I actually want to set up the rest of the interface. So I have an outlet for my image view and some of the other UI elements, and I just initialize them to either default values or just add the thumbnail that I got from Aputure, put that in the image view, and I can do whatever I need to from there.
[Transcript missing]
Composite my changes over that and then save that file back to disk. Once that's done, all I need to do is tell the Edit Manager to end the edit session and I'm done. So, thank you. All right. Let's switch back to the slide. So a couple quick notes on what we just saw.
So the first thing I should mention is once a version is editable, Aperture won't keep making copies of it. You can keep editing that file over and over again. So it's possible that you get a version ID when the plug-in first starts, and that version ID shows up in selected versions and in editable versions. It's already there. And if you call editable versions of versions and you pass in something that's already editable, Aperture won't reduplicate that file. It'll just pass you back the information for that file, so we're not constantly creating new files in the user's library.
So let's talk about one other cool feature of the API which can be really useful, which we call metadata round-tripping. This is basically the way for you to send plug-in specific data back to Aperture. And this is a great way-- we have this feature in the Export API, and it's a really great way for you to get something specific to your plug-in back into the database.
Maybe it's something for the user that tells them what settings they used or what they did so they can search on that later. Or maybe it's something plug-in specific that you want next time the user brings up your plug-in on that image. So we actually support two different kinds of metadata in the API. The two method calls are listed here. The first is custom metadata, and that's just any string key value pairs. You know, it's any dictionary where the keys and the values are strings.
Aperture doesn't care what they are. There's really no restrictions on this. You can just pass any two pairs, and Aperture will attach that to the image for you. So that's the first thing. So that really allows you a lot of freedom to put any kind of data you want back onto an image.
And the second thing is add hierarchical keywords. So what are hierarchical keywords? So in Aperture, a keyword isn't just a string. It actually has some hierarchy to it, which means, you know, you might not just put San Francisco as a keyword on an image. It might actually be San Francisco that's sitting inside California, sitting inside the United States.
So if you just put San Francisco on an image, but the user searches for California, that image will come up because San Francisco is in the hierarchy for California. The hierarchy is really free form. The keywords don't need to already exist in the user's database when you call this method. Aperture will go ahead and add them into that user's hierarchy when you make this call.
There's a couple caveats about this call, or these two calls. The first is they're not undoable. If you make these calls and then the user decides to cancel your plug-in, that metadata that you attach will still be sitting on those images. So that's important to keep in mind.
Usually things you want to do at the end. You know, the user runs your plug-in. You've written all your image changes. You've done your thing. And now you're going to tag in some metadata so the user can know what they did or you can know what you did last time.
The other thing is they take effect immediately. So when you make these calls, that data goes into the database right away. There's no delay. Again, if the user cancels anything like that, that data is going to be in the database. So once again, I'm going to bring Joe back up real quick. And he's going to show us how we might use this in borders and titles.
So we thought with borders and titles, it would be really cool if the user could actually search for those titles that they added to the image. Since it's actual just image data that's composited, there's really not a great way to do that other than basically searching the metadata. So we're back into the borders and titles code here, and what I'm going to do is just put some code back in here that can add that metadata back.
So what I need to do here is get a list of the titles that the user has added. This is just some of the code that I had for interfacing with my controller object to get those titles. And then I join those titles together into one string, and I call one method here called addCustomMetadata, pass in the metadata dictionary that had the keys with all of the titles. That was the value.
The key is title from borders and titles. This is anything you want to add for the key. That's just what we chose here. And then to the editable versions that were created. So I can show that to you real quickly. We're back here in Aperture. And I don't know where that one image was that I added the text to, but I can just very easily search here for NinjaCat. And there's my editable version. That did change, so thank you very much.
All right, thanks, Joe. So that's the brief run-through of the Edit API. If you have any questions, any requests, you know, this is the first version of the Edit API, so if there's features you want, anything like that, here's some--here's an e-mail contact. Go ahead and e-mail Alan Schaffer.
He'll make sure the--your request gets to the right people, the right engineers. We also have a mailing list, public mailing list, that covers both of Aperture's APIs, both export and edit. If you go to list.apple.com, you can search the archives there, sign up. There's several Apple engineers on the list, so we'll be sure to get your questions answered.
And then, of course, documentation comes both with the SDK and is also on the developer site at apple.com. Immediately following the session, we will all be down in the lab. So if you're working on a plug-in, you want to show us something, if you have questions about how something works, drop down. We will try and make sure your question gets answered.
And so, that's the brief overview. The Edit API, new in Aperture 2.1. It's an Objective-C API, but beyond making the API calls in Objective-C, you can write your plug-ins whatever technology you want. You got to download the SDK to get started. It includes everything you need, headers, docs, project templates, everything. Your plug-ins get access to all of Aperture's metadata, library features directly from the API. You can read image data, whether it's RAW or anything from any image selected, and you can actually write your special sauce back to these editable versions.