Developing an Aperture Plugin - Part 4

May 7th, 2007

Part 4 of this series is going to introduce the implementation file for our Aperture plugin. If you are new to Xcode, Cocoa, and Objective-C programming you may want to have a look at some of the really great tutorials over at CocoaDevCentral. Here you will find everything you need to get started using Xcode.

An implementation file in Objective-C is labeled with a .m extension. These are the files in Objective-C that tell the program what to do. For our purposes, we need to concern ourselves with the implementation file that was generated for us when we selected the Aperture Plugin Template. This file has been filled with all of the necessary code to get your plugin up and running. The Apple developers have even added in a few placeholders, which we can easily fill in order to get our plugin working.

By the end of this post the “Sample Project” plugin will be ready to be compiled. We will then be able to install the plugin and use it in Aperture to export images. The images will simply be exported to a folder of our choosing for now, but getting to this point is a important step. Everything we do after Aperture exports the images is up to us and the sky is the limit.

To begin, lets first have a look at our .m implementation file. Double click the .m file in your Xcode browser to open it up. At the top you will see an area in green that is used to identify this file. You may wish to fill in the part that says MyCompanyName here, but since it is just a comment, this is entirely optional.


In the picture above you will see an arrow that says “Click here!” Clicking this box once will bring up a listing of all the functions and methods defined in this file (see image below). You can easily navigate to the function you wish to work on using this box.

The first two functions we will run into are responsible for setting things up and tearing things down. Lets have a closer look.

The important thing to notice in the first function is that this is where the _exportManager object is instantiated. There is also a _progressLock object instantiated here, and below that, Apple has added a comment directing you to add your own initialization code here. For now, we can leave this function as is.

- (id)initWithAPIManager:(id<PROAPIAccessing>)apiManager
{
if (self = [super init])
{
_apiManager = apiManager;
_exportManager = [[_apiManager apiForProtocol:@protocol(ApertureExportManager)] retain];
if (!_exportManager)
return nil;

_progressLock = [[NSLock alloc] init];

// Finish your initialization here
}

return self;
}

The second function we will run into is dealloc. This function will release our objects from memory once the plugin has finished.


- (void)dealloc
{
// Release the top-level objects from the nib.
[_topLevelNibObjects makeObjectsPerformSelector:@selector(release)];
[_topLevelNibObjects release];

[_progressLock release];
[_exportManager release];

[super dealloc];
}

We can see here that the _exportManager and _progressLock objects are released from memory. Eventually, if we add our own objects to our plugin this will be the place to release them from memory as well.

The next set of functions in our .m file is labeled UI Methods. These methods will become more important in the next part of this series where we hook up the user interface. For now, we can leave them alone.

Moving down the list we come to a section of functions called Aperture UI Controls. Here we will have to write a small amount of code. An Aperture plugin is made up of two main components. The top half is where the plugin developer can design his or her own interface, but the bottom half has been designed for us by Apple. We do have a few choices to make, which will determine what types of settings and presets our plugin will expose. Here is the listing from our .m file.

#pragma mark
// Aperture UI Controls
#pragma mark Aperture UI Controls

- (BOOL)allowsOnlyPlugInPresets
{
return <#(BOOL)allowsOnlyPlugInPresets#>;
}

- (BOOL)allowsMasterExport
{
return <#(BOOL)allowsMasterExport#>;
}

- (BOOL)allowsVersionExport
{
return <#(BOOL)allowsVersionExport#>;
}

- (BOOL)wantsFileNamingControls
{
return <#(BOOL)wantsFileNamingControls#>;
}

- (void)exportManagerExportTypeDidChange
{

}

Notice that the first four functions have placeholders between < > brackets. These will need to be edited based on what we would like our plugin to do. Fortunately all we need to fill in for these functions is a YES or a NO.

The first function, allowsOnlyPluginPresets, tells our plugin whether or not we want to allow a list of presets for our plugin. For my Sample Project I am going to choose No and rewrite the code as follows.

- (BOOL)allowsOnlyPlugInPresets
{
return NO;
}

I can do the same for the next three place holders, replacing each one with a YES or a NO. For the Sample Project I am going to choose NO for allowsMasterExport, YES for allowsVersionExport and YES for wantsFileNamingControls. The wantsFileNamingControls function tells the plugin to let the user pick from a list of presets for renaming the files on export.

The next section we will look at is called Save Path Methods. These three methods will tell our plugin where and how to save our exported images files.

#pragma mark -
// Save Path Methods
#pragma mark Save/Path Methods

- (BOOL)wantsDestinationPathPrompt
{
return <#(BOOL)wantsDestinationPathPrompt#>;
}

- (NSString *)destinationPath
{
return <#(NSString *)destinationPath#>;
}

- (NSString *)defaultDirectory
{
return <#(NSString *)defaultDirectory#>;
}

For the Sample Project plugin we will keep things fairly simple. For the wantsDestinationPathPrompt we will answer YES. Because we are asking the user to specify a destination path, we simply return nil (nothing) for the destinationPath method. Finally, for the defaultDirectory method, we can choose any existing folder. This will be the initial folder the user will see when the destination dialog box pops up. Below is a listing of my modified code for the Sample Project.

#pragma mark -
// Save Path Methods
#pragma mark Save/Path Methods

- (BOOL)wantsDestinationPathPrompt
{
return YES;
}

- (NSString *)destinationPath
{
return nil;
}

- (NSString *)defaultDirectory
{
return [@"~/Desktop" stringByExpandingTildeInPath];
}

The last method tells our plugin that we want the default directory to be our user’s Desktop. Note here that this is the first time we have actually written any Objective-C code. Again, if you are unfamiliar with Objective-C, now may be a good time to head over to CocoaDevCentral for a crash course.

The last section of methods that we will need to edit is the Export Progress Methods. These methods tell the plugin to actually do the tasks related to exporting the images. The developers at Apple have added in some useful comments here. Take a look below.

#pragma mark -
// Export Process Methods
#pragma mark Export Process Methods

- (void)exportManagerShouldBeginExport
{
// You must call [_exportManager shouldBeginExport] here or elsewhere before Aperture will begin the export process
}

- (void)exportManagerWillBeginExportToPath:(NSString *)path
{

}

- (BOOL)exportManagerShouldExportImageAtIndex:(unsigned)index
{
return <#(BOOL)shouldExportImage#>;
}

- (void)exportManagerWillExportImageAtIndex:(unsigned)index
{

}

- (BOOL)exportManagerShouldWriteImageData:(NSData *)imageData toRelativePath:(NSString *)path forImageAtIndex:(unsigned)index
{
return <#(BOOL)shouldWriteDataToPath#>;
}

- (void)exportManagerDidWriteImageDataToRelativePath:(NSString *)relativePath forImageAtIndex:(unsigned)index
{

}

- (void)exportManagerDidFinishExport
{
// You must call [_exportManager shouldFinishExport] before Aperture will put away the progress window and complete the export.
// NOTE: You should assume that your plug-in will be deallocated immediately following this call. Be sure you have cleaned up
// any callbacks or running threads before calling.
}

- (void)exportManagerShouldCancelExport
{
// You must call [_exportManager shouldCancelExport] here or elsewhere before Aperture will cancel the export process
// NOTE: You should assume that your plug-in will be deallocated immediately following this call. Be sure you have cleaned up
// any callbacks or running threads before calling.
}

If we simply un-comment the function calls that have been suggested to us we will be nearly finished. For the Sample Project, I changed the code to the following.

#pragma mark -
// Export Process Methods
#pragma mark Export Process Methods

- (void)exportManagerShouldBeginExport
{
// You must call
[_exportManager shouldBeginExport];
// here or elsewhere before Aperture will begin the export process
}

- (void)exportManagerWillBeginExportToPath:(NSString *)path
{

}

- (BOOL)exportManagerShouldExportImageAtIndex:(unsigned)index
{
return YES;
}

- (void)exportManagerWillExportImageAtIndex:(unsigned)index
{

}

- (BOOL)exportManagerShouldWriteImageData:(NSData *)imageData toRelativePath:(NSString *)path forImageAtIndex:(unsigned)index
{
return YES;
}

- (void)exportManagerDidWriteImageDataToRelativePath:(NSString *)relativePath forImageAtIndex:(unsigned)index
{

}

- (void)exportManagerDidFinishExport
{
// You must call
[_exportManager shouldFinishExport];
// before Aperture will put away the progress window and complete the export.
// NOTE: You should assume that your plug-in will be deallocated immediately following this call. Be sure you have cleaned up
// any callbacks or running threads before calling.
}

- (void)exportManagerShouldCancelExport
{
// You must call
[_exportManager shouldCancelExport];
// here or elsewhere before Aperture will cancel the export process
// NOTE: You should assume that your plug-in will be deallocated immediately following this call. Be sure you have cleaned up
// any callbacks or running threads before calling.
}

Note that I still haven’t really written any code yet. I un-commented the function calls that the template suggested, and I answered two YES or NO questions with a YES.

Once we are to this point we can build and test our project in Aperture. To build the project in Xcode just click the Build button at the top of the Xcode browser. Once the build is finished, you should see a "Succeeded" label on the bottom right corner of the Xcode browser. If you see any errors, you may have forgotten to fill in a placeholder somewhere. You can check this out by clicking the Errors and Warnings tab in the Xcode browser.

If your Xcode environment is set up with the defaults, your plugin should be waiting for you in the Build subdirectory of your projects folder. If you navigate to the Release sub-folder (or Debug if you have your project set for debuging) you will find your plugin package. It should look something like the following: Sample_Project.Aperture.Export. Copy this entire folder to the following location: ~/Library/Application Support/Aperture/Plug-Ins/Export/. You can also install an Aperture plugin into the top level Library following the same path, but this will make your plugin available to all users on your machine.

Once you have copied your plugin bundle to your Aperture export folder you can luanch Aperture. By right clicking on any image you should the option to Export. This should birng up a list of all of your Aperture plugins, including the one you have just made. If you select your plugin you should see a screen similar to the following.

Notice that we have the option to select a Version preset, we can pick from a file naming preset, and there is a help button in the bottom left corner. These are all based on the values you entered in your .m file. When I click Export I see a dialog asking me wher eI would like to save the files, and low and behold the default is my Desktop. Once I pick a folder my images are exported to my destination. Congratulations, you have just built your first Aperture plugin.

Next time we will be switching over to the Email Pro plugin that I have been working on. Now that we have gotten to the point where we can export images to a folder on our computer, it’s time to add some code that will make our plugin unique. So, the first step will be to design our user interface. Stay tuned!

  1. Developing an Aperture Plugin - Part 1
  2. Developing an Aperture Plugin - Part 2
  3. Developing an Aperture Plugin - Part 3
  4. Developing an Aperture Plugin - Part 4

This entry was posted on Monday, May 7th, 2007 at 5:21 pm and is filed under Email, Email Pro, Plugins, Projects. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

One Response to “Developing an Aperture Plugin - Part 4”

  1. baba Says:

    Hi,

    good site to learn aperture plugin!

    I am trying to display the custom progress UI in my test application. Instead of displaying the aperture’s or plugin’s UI progress bar sheet, trying to display my own custom progress sheet.

    Here I am not getting how to disable the aperture’s or plugin’s UI progress bar sheet?

    waiting for your reply…


Leave a Reply