This document will guide you through the process of integrating the Aviary iOS SDK into your app, as well as configuring its interface and managing its resources.
In order to follow this guide, you must have the iOS 6.0 SDK and Xcode 4.5 installed on your system. For the latest versions, please visit Apple's iOS Dev Center.
In order to use the Aviary SDK, you must be using the latest version of Apple's LLVM compiler. You should not have a problem if you're using a fresh install of Xcode 4.x, which uses this compiler by default. However, if you are working on an older project, or you have upgraded from an older version of Xcode, make sure you're not using GCC.
The minimum iOS version supported by the SDK is iOS 4.3. The many reasons for this choice include our use of ARC (Automatic Reference Counting) and our reliance on a number of Apple frameworks and libraries which require iOS 4, including libdispatch.
The SDK consists of a static library, Objective-C header files, and one or more resource bundles containing configuration files and images. The static library is a universal binary for use on iOS device and simulator architectures (armv7/7s and i386).
AviarySDK/
|-- Headers/
| |-- AFPhotoEditorContext.h
| |-- AFPhotoEditorController.h
| |-- AFPhotoEditorControllerOptions.h
| |-- AFPhotoEditorSession.h
| |-- AFPhotoEditorStyle.h
|-- Resources/
| |-- AviarySDKResources.bundle
|-- libAviarySDK.a
Note: you can view the contents of the .bundle
files we distribute, although we do not recommend or support modifying their contents.
In order to use the SDK in an existing app, you must do the following:
-
Make sure you're running the latest version of Xcode and Apple's LLVM compiler.
-
Copy the AviarySDK folder into your project (select "Create groups for any added folders" if needed).
-
Check your target's "Link Binary With Libraries" build phase. Make sure your app is being linked against
libAviarySDK.a
.Link against the following libraries and frameworks:
Accelerate.framework CoreData.framework CoreGraphics.framework Foundation.framework libsqlite3.0.dylib libz.1.2.5.dylib QuartzCore.framework StoreKit.framework UIKit.framework CoreText.framework OpenGLES.framework
-
Make sure
AviarySDKResources.bundle
is included in your target's "Copy Bundle Resources" build phase. -
Update your target's (or project's) build settings to include the following "Other Linker Flags:"
-ObjC -all_load -fobjc-arc
Note:
-fobjc-arc
is only required if you are targeting iOS 4.3. -
Include the following line to make the library available to your code:
#import "AFPhotoEditorController.h"
The simplest way to use the SDK is to create and display an instance of AFPhotoEditorController
(a UIViewController
subclass). You can present it modally, like so:
- (void)displayEditorForImage:(UIImage *)imageToEdit
{
AFPhotoEditorController *editorController = [[AFPhotoEditorController alloc] initWithImage:imageToEdit];
[editorController setDelegate:self];
[self presentViewController:editorController animated:YES completion:nil];
}
You may instead choose to display the controller in other ways, such as by presenting it within a UIPopoverController
or by manually adding it to the view hierarchy. If you choose to present the controller in such a way, you are responsible for making sure it receives the standard view controller lifecycle methods, including viewDidLoad
, viewWillAppear:
, etc. The controller may be displayed full-screen, or you may display it in a smaller portion of the screen. Note that pushing the controller onto a UINavigationController's stack is not recommended, since the SDK itself uses a subclass of UINavigationController.
At minimum, you should implement the following AFPhotoEditorControllerDelegate
methods in your presenting view controller:
- (void)photoEditor:(AFPhotoEditorController *)editor finishedWithImage:(UIImage *)image
{
// Handle the result image here
}
- (void)photoEditorCanceled:(AFPhotoEditorController *)editor
{
// Handle cancelation here
}
You are responsible for dismissing the AFPhotoEditorController
, which should typically be done in these delegate methods.
The Aviary SDK offers the ability to produce output images with resolutions up to 3 megapixels (approximately 3 times larger than the maximum output resolution provided by the AFPhotoEditorControllerDelegate
methods). Two utility classes support this functionality: AFPhotoEditorSession
and AFPhotoEditorContext
.
Each instance of AFPhotoEditorController creates a session object upon initialization, which can be accessed via the readonly session
property:
AFPhotoEditorController *photoEditor = [[AFPhotoEditorController alloc] initWithImage:image];
AFPhotoEditorSession *session = [photoEditor session];
A session object is always in one of two states: open or closed. A session is open when the SDK is initialized, and closed when the user presses the "Done" or "Cancel" button in the user interface.
Note: If you intend to use an AFPhotoEditorController's session instance, be sure to obtain a reference to the session before the controller is deallocated. Session objects do not strongly reference the controller from which they were generated, so it is okay to retain a reference to a session after the controller is no longer needed.
Session objects can be used to create instances of AFPhotoEditorContext
(see below), which can be used to replay the session onto an input image, with an optional maximum output size.
A photo editor context is an object that can be used to "replay" an editing session onto an input image. A context can be created from an instance of AFPhotoEditorSession
with an image:
AFPhotoEditorContext *context = [session createContextWithImage:image];
Or, when a maximum output size (for example, 1200x1200) is desired:
AFPhotoEditorContext *context = [session createContextWithImage:image maxSize:CGSizeMake(1200, 1200)];
The first line above creates a context that can render the session onto an input image at full resolution if the input image is no larger than 3 megapixels. If the image is larger than this size, the output image will first be downscaled (maintaining aspect ratio) so that it is no larger than 3 megapixels.
The second line above imposes a tighter restriction on the output size. If the dimensions of the image are greater than 1200px (in the above case) on a side, the image will be downscaled (maintaining aspect ratio) before processing.
Once you have created a context from a session object, you can use it to render the session onto an input image like so:
[context render:^(UIImage *result) {
// Handle the result image here.
}];
New in 2.5.0: AFPhotoEditorContext
can take advantage of GPU acceleration when the input image is small enough to be represented as an OpenGL texture. An attempt to render an image that is too big to be represented as a texture will cause the context to fall back to CPU-based rendering.
If the context is created from an open session (i.e. after initializing an AFPhotoEditorController
but before displaying it) and -render:
is called, one of two things will happen:
-
If the context is able to use the GPU, it will wait until the session is closed before rendering the output image. This is much faster and more efficient than the old CPU-based behavior.
-
If the context falls back to using the CPU, it will render operations onto the image in the background as the user applies them in the SDK (by pressing the "Apply" button).
The completion block you supply to the method above will execute regardless of whether or not the user presses the "Cancel" button. If the user successfully completed his or her session, the UIImage
passed to the completion block will be the rendered image. If the user cancels the SDK, the UIImage
passed to the block will be nil
.
Some things to note about using contexts:
-
We recommend choosing a maximum output resolution that suits the purposes of your application to provide the best experience for your users.
-
Processing large images can consume a lot of memory and time. It may be necessary to free up resources and/or display an activity indicator while a context is executing.
-
To calculate the approximate maximum amount of memory a context could use, multiply the dimensions of the output size and multiply the result by 4. For example, a context with a maximum output size of 1500x1500 will consume approximately 9mb of memory for the processing duration.
As of version 2.5.0, the SDK can seamlessly use the GPU to render high-resolution images much more quickly. In order to invoke the GPU-based code path, input images passed to AFPhotoEditorContext
must be smaller than the maximum OpenGL texture size supported on the device. Here are the approximate maximum supported texture sizes for each iOS device model:
Texture size | Device types |
---|---|
2048x2048 | iPhone 3GS, iPhone 4, iPad |
4096x4096 | iPhone 5, iPhone 4S, iPad 3, iPad 2 |
Below is some sample code for rendering a user session at the maximum supported output resolution:
AFPhotoEditorController *photoEditor = [[AFPhotoEditorController alloc] initWithImage:image];
// Capture the user's session and store it in an array
__block AFPhotoEditorSession *session = [photoEditor session];
[[self sessions] addObject:session];
// Create a context with the maximum output resolution
AFPhotoEditorContext *context = [session createContextWithImage:image];
[context render:^(UIImage *result) {
// `result` will be nil if the session is canceled, or non-nil if the session was closed successfully and rendering completed
[[self sessions] removeObject:session];
}];
The editor is customizable at runtime using four class methods of AFPhotoEditorCustomization
.
+ (void)setOptionValue:(id)obj forKey:(NSString *)key;
+ (void)setOptionValueWithBlock:(id(^)(void))block forKey:(NSString *) key;
+ (void)setOptionWithImageNamed:(NSString *)name forKey:(NSString *)key;
+ (void)removeOptionValueForKey:(NSString *)key;
The customization system is based on a cascading key system, where it is possible to set an option value for the editor as a whole and also provide different values for specific tools. Each key consists of two mandatory parts, key path and option name, and an optional modifier. A valid key takes the form <key path>.<option name>-<optional modifier>
. The option name defines the item in the editor that is affected by setting a value to the key. For example, accentColor
is an option name that represents the accent color used in the editor's various tools. The key path defines the scope of the effect that the key's value has in the editor. The list of valid key paths are as follows:
editor
editor.tool
editor.tool.wheel
editor.tool.meme
editor.tool.orientation
editor.tool.text
editor.tool.crop
editor.tool.effects
editor.tool.enhance
editor.tool.stickers
editor.tool.brush
editor.tool.brush.draw
editor.tool.brush.blemish
editor.tool.brush.whiten
editor.tool.brush.redeye
editor.tool.wheel.saturation
editor.tool.wheel.sharpness
editor.tool.wheel.contrast
editor.tool.wheel.brightness
The key path editor
defines the global scope for the editor and setting values using it will apply everywhere in the editor. Key paths are refined by appending .<new key path component>
, which narrows the scope of where the option will take effect. For example, values set with the key path editor.tool.crop
will apply only in the crop tool. If values are set with keys that contain the same option name with different key paths, ie, editor.accentColor
and editor.tool.crop.accentColor
, then the value set to the key with the more refined key path will override the values from keys with more general scope. By appending a modifier to a key, you can specify the options value in a given state. Currently, only the highlighted
modifier is supported to customize UI elements when they are in their highlighted state.
Values for a given key can be given in one of three ways. Using +setOptionValue:forKey:
sets the value for the key with a concrete object value. +setOptionValueWithBlock:forKey:
sets the value for the key by evaluating the block that is given. The block is lazily evaluated, making it useful for specifying options with values that require loading information from disk. The third method, +setOptionWithImageNamed:forKey:
is a convenience method that lazily sets the value of the key to the image with the name provided. It is also possible to remove a custom value for a given key using +removeOptionValueForKey:
.
[AFPhotoEditorCustomization setOptionValue:[UIColor redColor] forKey:@"editor.accentColor"]; // sets the global accent color to red
[AFPhotoEditorCustomization setOptionValueWithBlock:^{return [UIColor blueColor];} forKey:@"editor.tool.crop.accentColor"]; // sets the crop tool's accent color to blue
[AFPhotoEditorCustomization setOptionWithImageNamed:@"enhanceIcon.png" forKey:@"editor.tool.enhance.icon"]; // sets the enhance tool's icon
[AFPhotoEditorCustomization removeOptionValueForKey:@"editor.tool.crop.accentColor"]; // Removes the crop tool specific accent color
Values for a given option are required to be of a specific type. The requirements for each option are enumerated in the list of keys below. If the value provided for a given key do not meet the requirements, it has no effect.
In addition to defining the scope of a key's effect, the key path also defines the set of options that are available to customize. In the list of keys below, options listed under inheritable are inherited by refined key paths and those listed under non-inheritable can only be modified with the given key path.
-
-
UIColor *navigationBarCancelColor
No type restrictions. This key sets the background color of the editor's navigation bar cancel button
-
UIColor *navigationBarBackgroundColor
No type restrictions. This key sets the background color of the editor's navigation bar.
-
UIColor *navigationBarCancelTextColor
No type restrictions. This key sets the text color of the editor's navigation bar cancel button.
-
UIColor *accentColor
No type restrictions. This key sets the accent color of the tool views.
-
UIColor *backgroundColor
No type restrictions. This key sets the background color of the tool views.
-
UIColor *navigationBarTextColor
No type restrictions. This key sets the text color of the editor's navigation bar title.
-
-
-
UIColor *bottomBarButtonTextColor
No type restrictions. This key sets the color of the text of the tool names in the editor's bottom bar.
-
NSNumber *disableLocalization
An
NSNumber
representing aBOOL
value. Setting this key toYES
will disable localization of text in the editor. Defaults toNO
. -
UIColor *canvasColor
No type restrictions. This key sets the background color behind the photo being edited in the editor.
-
UIColor *pageControlUnselectedColor
No type restrictions. This key sets the color of the editor's page controls unselected state.
-
NSString *leftNavigationBarButtonTitle
An
NSString
value represented by one of the threekAFLeftNavigationTitlePreset
keys. This key sets the text of the editor's left navigation bar button. -
NSString *rightNavigationBarButtonTitle
An
NSString
value represented by one of the threekAFRightNavigationTitlePreset
keys. This key sets the text of the editor's right navigation bar button. -
NSArray *toolOrder
An
NSArray
containingNSString
values represented by one of the tool keys. This key sets the availability and the display order of tools in the editor. -
UIColor *bottomBarButtonIconColor
A non-pattern image
UIColor
. This key sets the color of each of the tool icons in the editor's bottom bar. -
NSArray *supportedOrientations
An
NSArray
containingNSNumbers
each representing a valid /UIInterfaceOrientation. This key sets the user interface orientations that the editor will support.
-
-
-
NSNumber *cellWidth
An
NSNumber
representing aFloat
with value greater than or equal to 20.0 and less than or equal to 120.0. This key sets the width of the crop preset selection cells. -
NSNumber *enableInvert
An
NSNumber
representing aBOOL
value. Setting this key toNO
will prevent crop presets to be inverted. Defaults toYES
. Presets with names, i.e.Square
, are not invertible, regardless of whether this key is set toYES
. -
NSArray *presets
An
NSArray
containingNSDictionaries
with the following key-value pairs:kAFCropPresetWidth
represents the preset's width. A valid value for this key is anNSNumber
instance representing a float.kAFCropPresetHeight
represents the preset's height. A valid value for this key is anNSNumber
instance representing a float.kAFCropPresetName
represents the preset's name. A valid value for this key is anNSString
instance. This key is optional, and when not present the preset will be named "width x height". If inverted crop is enabled, the width and height values will correspond to those of the aspect ratio being displayed.
Square
,3x2
,5x3
,4x3
,6x4
, and7x5
. -
NSNumber *enableOriginal
An
NSNumber
representing aBOOL
value. Setting this key toNO
will disable theOriginal
crop preset. Defaults toYES
. TheOriginal
crop preset constrains the crop area to photo's original aspect ratio. -
NSNumber *enableCustom
An
NSNumber
representing aBOOL
value. Setting this key toNO
will disable theOriginal
crop preset. Defaults toYES
. TheCustom
crop preset does not constrain the crop area to any specific aspect ratio.
-