Aviary Web Widget Documentation
Aviary's web widget (codename: Feather) can be embedded in any website
with just a few lines of Javascript, adding simple yet powerful image
editing to an existing workflow. The widget works in all major browsers
(Chrome, Safari, Firefox, Internet Explorer 7+) and on all devices (PCs,
laptops, iPads, smartphones) that support JavaScript and either HTML5 or
Flash. Try the demo here.
Contents
Get the widget!
Create your own with the Code
Generator.
Editor Javascript Url
See
http://feather.aviary.com/js/feather.js
("feather.js")
Note: Please always call this script directly, as there are some
server-side dependencies.
Introduction - High Level
The following describes how the editor works in your webpage in the most basic terms:
- Load feather.js
- Configure your widget instance with a configuration object
- After the DOM is ready and your instance has loaded, launch your
instance.
API Overview
The API is inspired by the jQuery plugin
pattern, wherein you pass a
configuration object of key/value pairs. This allows for the widget to
grow and introduce new features without breaking existing
implementations or being constrained by its API.
Configuration
The following configuration parameters can be specified in your iniitalization. See the example integration.
image, apiKey, and apiVersion are required
image
required
Either the image element to be edited or its ID.
Note: Make sure the DOM has loaded before attempting select an element
to pass as image, or use its ID instead. The image itself must be
located in a publicly-accessible web folder, otherwise the widget will
not work.
apiKey
required
Get your API key from the Get Key page. Saving will
not work without it!
Note: when generating your API key, provide your root domain, even if
you will be using it on subdomains.
apiVersion
required
This lets Aviary know which version of the editor to load and allows you some protection from breaking changes.
The latest editor version is 2.
appendTo
The widget will be inserted inside the element
with the DOM ID specified.
Note: For best results, this should be a <div /> element
language
The widget's UI is being localized into many languages. You can choose
from en/English (default), de/German, fr/French,
ja/Japanese, it/Italian, nl/Dutch, es/Spanish, or
ru/Russian today - but our collection is always growing, so stay
tuned if you're looking for a different option.
Note: You can also help us translate your own language! Shoot us an
email at api@aviary.com if you'd like to send
us a translation for a new language.
minimumStyling
Set to true to reduce our styles to the bare minimum in order to more easily add your own styles on top. This removes most textures, shadows, rounded corners, and gradients that can be tedious to reset.
maxSize
Set a max size of drawing canvas. See Best Practices.
noCloseButton
Set to 'true' to remove the close button.
tools
Select which editing tools you would like to display in the tools panel. We recommend either omitting tools or setting it to 'all' which will automatically give you our most up-to-date selection of recommended tools without updating your integration code.
all: selects all Aviary-recommended tools. (default)
You can also specify one or more options by name in an array or comma-separated string. Choose from our latest set of tools below:
enhance (new): Autocorrect your photo with one of four basic enhancements.
effects (new): Choose from a variety of effects and filters for your photo.
stickers: Choose from a variety of stickers you can resize and place on your photo.
orientation (new): Rotate and flip your photo in one tool.
resize: Resize the image using width and height number fields.
crop: Crop a portion of your photo. Add presets via API. Fixed-pixel cropPresets perform a resize when applied (new).
brightness: Adjust the overall image brightness.
contrast: Adjust the overall image contrast.
saturation: Adjust the overall image saturation.
sharpness (new): Blur or sharpen the overall image in one tool.
draw: Add doodle overlays with a brush.
text: Add custom, resizable text.
redeye: Remove redeye from your photo with a brush.
whiten: Whiten teeth with a brush. (Not supported in IE7-IE8)
blemish: Remove skin blemishes with a brush.
Tool Order: the order in which you list the options is the order in which
they will appear in the editor. The editor options will be paged, so put
the most important functions up front.
Legacy support: If you are using the legacy editor (apiVersion set to 1) the new tools are unavailable to you. However, you may find substitutes in the following deprecated tools.
rotate (deprecated): Rotate your photo in 90 degree increments.
flip (deprecated): Flip and mirror your photo.
colors (deprecated): Adjust the overall red, green and blue tone.
blur (deprecated) : Add a blur to the overall image.
sharpen (deprecated): Adjust the overall sharpness.
initTool
The widget can start with a specific tool open by passing its name here.
cropPresets
A comma-separated list of preset crop sizes or ratios for the crop tool.
It can be a 2-D array (with labels), a 1-D array (without labels), or a
comma-separated string (without labels). Any sizes over your maxSize
will be excluded in the UI.
Defaults:
[
'320x240','640x480','800x600','1280x1024','1600x1200',
'240x320','480x640','600x800','1024x1280','1200x1600',
'Original',
['Square', '1:1'],
'Custom',
'3:2', '3:5', '4:3', '4:6', '5:7', '8:10', '16:9'
]
You can label the presets by providing each as an array:
[
['Photo', '4:3'],
['HDTV', '16:9'],
['Avatar', '60x50']
]
We believe most resizes are based around preset sizes, and recommend the crop tool for the best control over framing your resized photo in one step.
But if you cannot predict the sizes your users will need, manually enable the resize tool.
url
This is required if the image to be edited is on a different host than
the host HTML page. Otherwise it is optional.
Note - this param should be omitted if possible. Providing it is a clue to our API
that your image is on another domain and you need to request origin-clean
data from our server which adds to image load time. It also requires that the image
at the location be publicly available as our server must download it.
postUrl
Set a location on your server for Aviary to send a server-to-server HTTP POST to on save with information about the edited photo. A publicly accessible (and not password-protected) web service should listen here. See Saving Your Work and our examples.
Aviary will make an HTTP POST to the URL
specified with the following data:
url : URL of the saved image.
postdata : any additional data specified in postUrl.
Note on security - Unfortunately we cannot guarantee an IP or range of IPs to expect due to our distributed hosting. Signing could be accomplished by clever use of postData
postData
Set data to be posted to the postUrl along with the saved file's url
(See Saving Your Work, below). Expect all data assigned to postData to be sent to your postUrl as the postdata param, which will be serialized as a string.
fileFormat
coming soon
Set the saved file format. Accepts: png, jpg, original
jpgQuality
coming soon
Set the save quality of the image as a JPG file type. Accepts a number
between 1 - 100.
onLoad
Pass a function to run once the widget has all resources ready for a
launch (such as launching as soon as possible after page load). See
Best Practices.
onReady
Pass a function to be called once the editor has finished launching and
is ready for user input.
onSave(imageID, newURL)
Pass a function to be called when the image save is complete. A This can
be used to set the image in the DOM to point to the new source.
imageID gives you an ID to reference the original image being
edited.
newURL is a link to the saved image. It will persist at this address for approximately 72 hours.
Note - this image may not yet be ready so you
will have to poll this link, or alternatively handle the hi-res image
server-side at the location specified by PostUrl.
Return false to this handler if you'd like to suppress the built-in save confirmation dialog.
onClose(isDirty)
Pass a function to be called when the editor is closed.
isDirty tells whether the editor was closed with unsaved changes.
onError(errorObj)
The API can notify you of errors and you have the option to notify the
user. They are otherwise silent.
errorObj is an object with the following properties:
code : int representing the error type. 1 corresponds to an image that could not be processed.
message : An error message you could pass along to the user.
args : This is an array of additional values that varies by error type. For example, error type 1, bad image, will send the problematic URL as the only argument in the array. This could assist in debugging or helping a user correct a specific problem.
Invocation
First, call feather.js from your web page
Next, instantiate the HTML5 editor with a configuration object:
var featherEditor = new Aviary.Feather(configObj);
Once you have created your instance (in this case, featherEditor) you have a few methods at your disposal.
launch
You can open the editor on demand using its launch method:
featherEditor.launch(overrideConfigObj);
At this point you can override any of the configuration parameters
except for theme, language and onLoad. Or, if
all required parameters are provided, you can
omit any configuration at this time.
The first two parameters define the HTML and CSS the editor will use.
onLoad is no longer valid as the editor has loaded by this time.
save
The save method lets you save progress through some separate UI, such as a button on your hosting page. It is not typically necessary, as the user can always save from within the editor at any time.
featherEditor.save();
close
You can shut down the editor programmatically with the close method.
Use with care, as this will discard any unsaved changes without prompting the user. For this reason it is commonly used onSave if at all.
May be useful when noCloseButton is set to true.
featherEditor.close();
Example
Pre-integration:
<img id="editableimage1" src="http://example.com/public/images/goat.jpg"/>
Post-integration:
<!-- Load widget code -->
<script type="text/javascript" src="http://feather.aviary.com/js/feather.js"></script>
<!-- Instantiate the widget -->
<script type="text/javascript">
var featherEditor = new Aviary.Feather({
apiKey: '1234567',
apiVersion: 2,
tools: ['draw', 'stickers'],
onSave: function(imageID, newURL) {
var img = document.getElementById(imageID);
img.src = newURL;
},
postUrl: 'http://example.com/featherposturl'
});
function launchEditor(id, src) {
featherEditor.launch({
image: id,
url: src
});
return false;
}
</script>
<!-- Add an edit button, passing the HTML id of the image
and the public URL to the image -->
<a href="#" onclick="return launchEditor('editableimage1',
'http://example.com/public/images/goat.jpg');">Edit!</a>
<!-- original line of HTML here: -->
<img id="editableimage1" src="http://example.com/public/images/goat.jpg"/>
Saving Your Work
What happens on a save
- (Client) User clicks the save button.
- (Client) The widget posts the image data along with configuration parameters to Aviary
- (Server) Aviary saves the image temporarily and sends a response back to the widget with that location.
- (Client) On this callback, the widget will call any function passed to
onSave, and then shows a confirmation dialog to the user.
- (Server) Aviary makes a HTTP POST to
postUrl.
- (Server) Your
postUrl service receives information from Aviary and can save the edited images locally.
Server-side Examples
Ruby
#url
#postdata: originalName
post "/save" do
#original photo name is postdata
orig_name = params[:postdata]
new_name = orig_name + " (edited with Aviary)"
# Retrieve a file object from the image URL
image_from_web = open(params[:url]) {|f| f.read }
# get file name from URL
file_name = params[:url].split("/").pop()
# Write the file to the local filesystem
Dir.chdir("tmp")
File.open(file_name, 'w') {|f| f.write(image_from_web) }
Dir.chdir("../")
end
PHP
<?php
$image_data = file_get_contents($_REQUEST['url']);
file_put_contents("photo.jpg",$image_data);
?>
ASP.NET
protected void Page_Load(object sender, EventArgs e)
{
string postdata = Request["postdata"]; // an encoded reference to the file that you're updating perhaps
string url = Request["url"]; // the url of the saved file
string localFileDest = "..."; // file save destination
WebClient client = new WebClient();
client.DownloadFile(url, localFileDest);
}
Best Practices
When to embed the editor in your layout and when to let it fill the screen
You should provide a <div/> element ID to the appendTo parameter when
you want full control over the editor experience
(i.e. launching the editor in your own custom lightbox). It is best suited
for more advanced integrations. Because the editor tries to fill the space alotted it,
we recommend you specify a fixed width and height in CSS, as well as a position property of
relative, absolute, or fixed
so that the container is considered a positioned element.
Do not provide an element to appendTo if you want to show larger images closer
to their native size, and/or your layout does not provide suitable space for the editor
(at least 714px wide by 400px high).
This will launch the editor in a simple lightbox that floats
above the page in z-order and temporarily darkens the rest of the page until the
editing is complete. It also offers users the most room for tools visible at once.
This is generally the recommended approach.
Larger Images
For the best user experience, please note that this lightweight editor
is meant to handle file sizes intended for web display, not original
resolutions.
If you are interested in working with the API in original
resolutions, please contact partners@aviary.com
You can use the maxSize parameter
to set the maximum size of the output image and the actual
size of the editing canvas. The
API only accepts one value that it uses to specify that max height and
width of the canvas. This prevents the canvas from getting too wide if a
taller image is rotated, for example. The default (recommended) value is 800 (800x800 pixels).
Waiting for the Widget to Initialize
Calling launch() before
the widget has loaded and initialized will have no effect. A nice
usability enhancement is to disable the "Edit" button and only enable it
onLoad. Assuming in the
examples above, the "Edit!" link has an ID of "edit-button" and a style
of "display: none":
var featherEditor = new Aviary.Feather({
onLoad: function() {
document.getElementById('edit-button').style.display = 'block';
}
});
Note: Make sure the callback function in either of these examples runs
after the DOM is ready and the edit button is accessible with
JavaScript. See jQuery's .ready() method
for more details.
Custom CSS Styling
Overriding Aviary CSS selectors
Custom CSS styling of the editor is possible. Be sure to make your overrides robust enough to supercede our own styles (usually accomplished by simply prepending body to the selector).
Blank Canvas
The minimumStyling config param can be very helpful if you plan to do heavy customization as it gives you something of a blank canvas.
Style Guide
The widget can be styled according to our public style guide, but hooking into any other markup is not supported so please limit customization to the following:
/* general font color/reset */
body .avpw *,
body .avpw a,
body .avpw a:link,
body .avpw a:hover,
body .avpw a:visited,
body .avpw a:active {
color: #444;
}
/* "gears" background behind image */
.avpw .avpw_canvas_background {
background: #121212 url(../images/gears_background.png);
}
/* brushed metal texture */
/* outermost widget body/parent */
body .avpw {
background: #efefef url(../images/metal_texture.png) 50% 0%;
}
/* small icon inside an open tool */
.avpw .avpw_current_tool_icon {
background: #efefef url(../images/metal_texture.png) 50% 25px;
}
/* popups that open within the widget */
.avpw .avpw_app_popup {
background: #efefef url(../images/metal_texture.png) 50% 25px;
}
/* footer text */
.avpw .avpw_footer_text,
.avpw .avpw_footer_text a,
.avpw .avpw_footer_text a:link,
.avpw .avpw_footer_text a:visited,
.avpw .avpw_footer_text a:hover,
.avpw .avpw_footer_text a:active {
color: #656565;
}
/* tool icons */
/* normal */
.avpw .avpw_tool_icon_image {
background-color: #efefef;
}
/* hover */
.avpw .avpw_tool_icon:hover .avpw_tool_icon_image {
background-color: #ffffff;
}
/* pressod */
.avpw .avpw_tool_icon_down .avpw_tool_icon_image,
.avpw .avpw_tool_icon_down:hover .avpw_tool_icon_image {
background-color: #e2e2e2;
}
/* tools paging inidcator */
body .avpw .avpw_page {
color: #3d3d3d;
}
body .avpw .avpw_page_selected {
color: #00a5ff;
}
/* default buttons */
body .avpw .avpw_button {
background: #efefef;
}
/* hover */
body .avpw .avpw_button:hover {
background: #ffffff;
}
/* pressod */
body .avpw .avpw_button.avpw_button_down {
background-color: #e2e2e2;
}
/* primary button
* (overriding color on these links so
* we have to be explicit)
*/
body .avpw .avpw_primary_button,
body .avpw .avpw_primary_button:link,
body .avpw .avpw_primary_button:visited,
body .avpw .avpw_primary_button:active {
background-color: #0084cc;
color: #ffffff;
}
/* +/- slider label/buttons */
body .avpw .avpw_slider_label {
color: #707070;
}
/* darker, cut-out color */
.avpw .avpw_inset_background {
background-color: #2d2d2d;
}
/* preset icons */
.avpw .avpw_preset_icon {
border-left-color: #474747;
border-right-color: #141414;
}
.avpw .avpw_preset_icon_active {
background-color: #414141;
}
/* and light blue indicator */
.avpw .avpw_preset_icon_active .avpw_preset_indicator {
background: #00a5ff;
}
/* grouped push-buttons inside tools */
.avpw .avpw_inset_button {
border-left-color: #474747;
border-right-color: #141414;
}
/* hover */
.avpw .avpw_inset_button:hover {
background-color: #2a2a2a;
}
/* pressod */
.avpw .avpw_inset_button_down {
background: #141414;
}
/* text input fields */
body .avpw .avpw_text_input {
background: #ffffff;
color: #bcbec0;
}
/* focus */
body .avpw .avpw_text_input_focused {
color: #3d3f40;
}
/* palette swapped on dark background */
.avpw .avpw_inset_background .avpw_text_input {
background: #414141;
}
/* focus */
.avpw .avpw_inset_background .avpw_text_input_focused {
color: #ffffff;
}
/* labels palette swapped on dark background */
.avpw .avpw_inset_background .avpw_label {
color: #ffffff;
}
/* lock icon */
/* 'unlocked'/default state */
.avpw .avpw_inset_button .avpw_lock_icon_top,
.avpw .avpw_inset_button .avpw_lock_icon_bottom {
background: #a3a3a3;
}
.avpw .avpw_inset_button .avpw_lock_icon_top_inner,
.avpw .avpw_inset_button .avpw_lock_icon_sep {
background: #383838;
}
/* 'locked'/down state */
.avpw .avpw_inset_button_down .avpw_lock_icon_top,
.avpw .avpw_inset_button_down .avpw_lock_icon_bottom {
background: #00a5ff;
}
.avpw .avpw_inset_button_down .avpw_lock_icon_top_inner,
.avpw .avpw_inset_button_down .avpw_lock_icon_sep {
background: #141414;
}
Getting Updates from Aviary's Development Team
If you use the widget on your site, it's very important for us to be
able to contact you. Please, please, please make sure to enter a valid
email at the time you generate an API key. We will use this email to
inform you when we are introducing new features, making any planned
layout changes, and most importantly if we need to introduce any changes
to our editor that might impact your site. We will not spam you or share
your email with any third party services.