Photoshop Zoomify in HTML, powered by Leaflet

I’ve been spending a lot of time with Photoshop recently… Whether it has been retouching video or images, creating panoramas, or working with my aerial photos, it has been a lot of fun. One thing that I’ve been doing is exporting really large images to the web. So far this has been a very manual process… Export from Photoshop using Zoomify. Then, since the default Zoomify renderer uses Flash (and I want this consumable on mobile devices), take the Zoomify image tiles, and put them into a custom-coded HTML experience using the Leaflet tile engine with a custom tile layer.

Leaflet is normally used for web-based mapping, but it is a perfect solution for rendering image tiles on the web. It already has touch and mouse interactions, inertial scrolling, progressive viewing, and a comprehensive API that can be extended if you so choose.

I’ve done this enough times that I figured “There has to be an easier way”… and there definitely is. I’ve created a new Zoomify template that allows you to export from Photoshop’s Zoomify feature directly to HTML, leveraging the Leaflet engine. All of the code and installation instructions are below in this post. Check out the video below to see it in action:


Here are few samples from the Zoomify output; both are the compositions that I showed in the video above. Use the mouse or touch interactions to pan and zoom on each of them.

The first is an export from a 10MP aerial panorama (4340×2325 pixels), which was created by stitching together multiple images captured with a GoPro camera and remote controlled helicopter.

Click here to view in a new window.

The second example is a massive 139MP composite image (14561×9570 pixels). I created this by stitching together 48 10mp images in Photoshop. It’s not perfect, but shows how far you can zoom into an image… some images had different exposures, some were out of focus, there is still some perspective warp, and I definitely have some bad stitching seams. This image is so huge that I actually maxed out the system RAM, and filled up all hard disk space with the memory swap file when creating it (I had over 100 Gigs of free space)!

Click here to view in a new window.


Disclaimer: This is not an official Adobe sponsored process – you will get no technical support for any issues that you may run into.

It’s really easy to get this template set up in just a few steps:

  1. Download the template code from (there is a “Download Zip” link).
  2. Extract the zip file and copy the following files to Photoshop’s Presets/Zoomify directory. On OS X, with the default configuration, these files should be located in /Applications/Adobe Photoshop CC/Presets/Zoomify/
    • L.TileLayer.Zoomify.js
    • Zoomify Leaflet HTML.zvt
    • leaflet.css
    • leaflet.js


  3. Restart Photoshop.
  4. When you have a file open that you want to export, choose File -> Export -> Zoomify export_menu
  5. Then select the “Zoomify Leaflet HTML” template that should now be in the list. Select an output location, base name, and image options, and hit “OK”. Ignore the browser width and height, since the template ignores these. Instead, it takes 100% of the width and height of the browser window.zoomify export
  6.  This will generate all of the image tiles and the HTML structure. From here, do whatever you want with it… You can modify it, put it on a server, or anything else. the file output will look something like the image below. You will have a folder that contains the generated HTML file, the Leaflet JS and CSS files, and a directory that contains the generated tiles and appropriate XML metadata.generated output

All of the code is available on github at:


Inexpensive Clamp-On GoPro Mounts

I’ve posted about GoPro cameras here before… I love mine b/c it is so versatile. You can mount it on just about anything – underwater, on the ground, or in the air. There are tons of accessories for mounting it all kinds of different ways. However, the cost of these mounts can quickly add up. The adhesive mounts are essentially 1-use mounts. Once you stick them to something, they are firmly attached, and cannot necessarily be easily reused multiple times. If you want a reusable mount, GoPro has their own clamp mount, but is also a bit pricey if you have other accessories. Here’s how you can create an inexpensive and extremely versatile clamp mount.

I already had a frame mount, and a tripod mount for the GoPro, so I already had half of the equation. (Yes, if you have to go out and purchase both of these, it’s just as much as GoPro’s clamp mount, but this approach is far more versatile when you have all of them.)

To turn this into a clamp mount, you just need to add the clamp and a mounting point, which can be purchased at a hardware store for just a few dollars. You’ll need a clamp; any size will do, you just need one big enough to put a 1/4 inch bolt through the handle. Generally, the bigger the clamp, the stronger the spring will be to hold it closed. The one I used is pretty big – you don’t necessarily need one this big. You’ll also need a 1/4 inch bolt, some washers, and some 1/4 inch nuts. I used a thumb screw with two wing nuts so that it is easy to adjust in any situation without any tools.

Clamp Mount Parts
Clamp Mount Parts

Just drill a hole through the clamp handle big enough to fit the 1/4 inch thumb screw. Put a washer on either side, and tighten it with one of the wing nuts. Then put the other wing nut in the opposite direction, followed by the tripod mount. Use this second wing nut to tighten the tripod mount in the correct position. Next, just attach the “arms” that come with the GoPro, and attach the camera inside of the frame mount. Voila… you know have an extremely versatile clamp mount for the GoPro. This will also work with the waterproof enclosure.

DIY Clamp Mount
DIY Clamp Mount

Now, get out there, capture some great images and videos, and then use Creative Cloud to bring out the best in them. You can do everything from lens profile correction, horizon correction, color correction, and much, much, more on both images and videos with Photoshop, Lightroom, and all of the tools that Creative Cloud offers.

Review: Beholder Lite Gimbal For DJI Phantom Quadcopter

I recently purchased a Beholder Lite camera gimbal for my DJI Phantom quadcopter, and I am very pleased with it. Bottom line for those that don’t want to read this entire post… The Beholder Lite is hard to beat for the price, as long as you have some time to tune the gimbal.  Output video is very steady when flying reasonably, and still images are far more crisp than they are without a gimbal. The final output is not quite as good as the H3-2D Zenmuse, but it is still much more than acceptable. Plus, you can buy almost 4 Beholder Lite’s for the cost of one Zenmuse. However, when flying aggressively, there is a lot of vibration. Read more for an explanation, pros & cons, plus tips for set up and some sample videos.

DJI Phantom with Beholder Lite Gimbal
DJI Phantom with Beholder Lite Gimbal


Um… What is a camera gimbal?

First, a gimbal is: “a pivoted support that allows the rotation of an object about a single axis. A set of three gimbals, one mounted on the other with orthogonal pivot axes, may be used to allow an object mounted on the innermost gimbal to remain independent of the rotation of its support.”

Basic Gimbal (photo: Wikipedia)

A camera gimbal is a set of these gimbal supports that enables the camera’s movement to be independent from the support structure. In this case, the camera gimbal allows the camera’s orientation to be independent from the orientation of the helicopter. Check out this video for more detail:

The Beholder Lite Gimbal

The Beholder Lite gimbal is a direct-drive brushless gimbal. This means: 1) the motors are brushless motors, and 2) that the motors directly drive the support arms for the gimbal; there are no servo arms or other moving parts in the gimbal assembly. Brushless motors are faster than traditional/brushed servo motors, so they offer a smoother response and better stabilization. I have used the Phantom with no gimbal, as well as with a brushed/servo gimbal, and the brushless direct-drive gimbal is by far the best quality.

I mentioned that I am very happy with this gimbal, though it has not been without its own hiccups.


  • Very stable footage ****once properly installed and tuned****
  • Still images are more crisp
  • Videos are far more stable, though aggressive flying will cause significant vibration (this happens with all gimbals, though some more than others)
  • Very affordable compared to similar gimbals on the market.


  • Installation instructions are not very good. They are based on pictures only, and do not clearly identify motor orientation or wiring. I originally had the motors in the wrong direction, and the motor polarity reversed. This third-party post (with video) was very helpful for installation. I’ve provided additional installation details at the bottom of this post.
  • The gimbal is marketed as “ready to go” – you just assemble it and start flying. Once assembled, I had lots of vibration to the point of being unusable. I seriously considered returning it. However, I had to manually change settings before I could get some decent footage. This was both physical (in the mounting), and in software configuration. I had to adjust the output gains before the gimbal would provide stable footage (details below).
  • The vibration absorbing mounts are too soft. You will get vibration from the camera oscillating below the copter. Luckily this can be corrected but sticking some foam ear plugs inside the vibration mounts (see details below).

Both aggressive flying and high-wind environments will cause additional vibration in both the copter and gimbal, so keep those in mind when you are filming. 

Sample Video Footage

I still don’t feel like I have the gimbal settings (gains) 100% dialed-in, but I have it close enough to get some high quality footage. I have found that the 1080p@60fps video mode on the GoPro camera has the best results. 2.7K@30fps has too much rolling shutter effect for the footage to be really usable. I also have not balanced the propellors on my copter, which will also help to eliminate vibration. Here are a few samples from the camera/gimbal combination. All of this footage was captured with a GoPro Hero 3 Black Edition.

1080p@60fps with Post Processing via Adobe Premiere: I still think I can get it more stable by changing a few editing parameters and changing the sequence of my scaling and effects, but I am very happy with this output.

1080p@60fps Non-Stabilized: “Day for night” color correction, non-stabilized, GoPro with ND filter, just for fun…

2.7K@30fps with 10% Warp Stabilization The footage is far better than it is without a gimbal, but there’s still some rolling shutter effect evident (capturing Tony’s hex liftoff).

Aggressive Flight: This footage is completely raw, without any post-processing or stabilization. This shows output when flying aggressively. This was *very* aggressive flight – full speed in ATTI mode. I recommend that you *never* attempt to shoot professional footage flying like this:

Sample Still Images & Compositions

Here are just a few still images and compositions captured with the Beholder Lite gimbal. You can see more on my Flickr page.

Adobe San Francisco Office
San Francisco City Hall

Installation Details

In addition to the gimbal’s manual, I strongly recommend that you read both of these posts and watch the videos for detailed installation instructions:

Pay particular attention to motor orientation and wiring. The motors look symmetrical, but their weight and operation is not. The pitch motor should have the wire coming out the side that is closest to the copter. The roll motor should have the wire coming out the side closer to the camera. If you have your motor polarity reversed, you’ll know b/c the gimbal will vibrate back and forth. This won’t hurt it, and you can just reverse the wires easily if this happens. In the picture below you can see my motor orientation:

Motor Orientation and Wiring
Motor Orientation and Wiring

Very important: make sure your gimbal is balanced. If the power is off, the GoPro should not fall in any direction. It should just stay where it is. Having it perfectly balanced is key to having smooth footage.

The rubber vibration dampeners are too soft for the gimbal. If you fly it “stock”, you will get a TON of vibration from the gimbal oscillating under the copter. Use some soft foam earplugs, roll them up, and put them inside of the dampeners. I used the cheap foam orange ones you get from any drug store, and they work great. I put one in each of the 6 vibration dampeners. Another picture below, so you can see the orange ear plugs in the dampeners:

Earplugs to Stiffen Vibration Dampeners
Earplugs to Stiffen Vibration Dampeners

Once your gimbal is powered up, if you have vibrations while the copter motor isn’t even running, then you need to adjust the gains and tune the gimbal itself. I had to do this. You can connect using a standard micro USB cable (from any Android phone), and use the software here: and drivers here: (windows only)

Not entirely necessary, but I also put Moongel in between the gimbal and the copter body to absorb vibrations, and I also put it on top of the gimbal’s gyro board to absorb vibrations that may affect gimbal orientation (see picture below).

Beholder Lite on DJI Phantom
Beholder Lite on DJI Phantom

Do not get the white wires too close to the power wires or to the motors. They are very light weight, and can get interference from power wires, motors, and motor wires. You will get inexplicable vibrations if this occurs.

One last thing… If you use zip ties on the gimbal for extra safety, keep them very loose. If you compress the dampeners, the bottom plate will hit the controller board, and cause significant interference with gimbal operation. Everything will be fine one second, then completely out of control the next.

Battery Life

Before having a gimbal, I could easily get 12+ minutes of flight time per battery. With a servo-based gimbal, I could get about 10+ minutes per battery. With the Beholder Lite, I get a max of 8 minutes per battery. I set a timer for 7 minutes, and be sure to bring it down as soon as the time goes off. However, this seems comparable to battery life with other brushless gimbals that friends/coworkers use. The decreased battery life is due to additional weight of the gimbal, plus the additional power consumption from the gimbal motors.

What Next?

Use Creative Cloud to process all of your video and images to make them the best they can be! Here are some very useful posts for processing your content with this configuration (or similar configurations)…

Videos from Russell Brown:

Videos from Colin Smith:

And have fun!

Status Tap/Scroll To Top in PhoneGap Apps on iOS

One criticism of PhoneGap apps that I sometimes hear is that they often don’t have “standard” features from the native operating system.  Little things, like iOS’s ability to scroll a container back to the top, just by tapping on the operating system’s status bar. These types of features are not hard to add to a PhoneGap application, at all. This is more of an “attention to detail” issue, not something that the platform can’t do.

Since this isn’t a feature that is applicable on all platforms, and it can vary per PhoneGap app implementation, it is not part of the core PhoneGap/Cordova download.  However, this can be very easily added via a native plugin.  Native plugins enable you to access native code, or augment the capabilities of PhoneGap for a particular platform.

Here’s proof… I just added the “scroll to top” capability to my Halloween PhoneGap app.

If you download the app from the app store today, you won’t see this yet because I literally *just* submitted it to Apple.

So how did I do this?

It wasn’t hard. The first thing to do is check and see if there was an existing native plugin that has already been created by someone in the PhoneGap/Cordova community.  It turns out, Greg pointed out one that already existed.  Since this plugin was built targeting an older version of PhoneGap, and my project was built using PhoneGap 3.0, I had a few minor updates.  Though, I was able to get everything all set up in a very short period of time.

Here’s what I did:

  1. I forked the existing plugin.
  2. Added plugin.xml metadata so the plugin can be included via PhoneGap & Cordova CLI tools.
  3. Added logic in the JavaScript so that it auto-initializes – you no longer have to manually initialize the plugin.
  4. Moved the native Objective-C initialization logic into a background thread.

Now that I’ve done this, and pushed it to github, you can include it into your own PhoneGap projects with a single command using the PhoneGap CLI:

[code]phonegap local plugin add[/code]

Then, in your PhoneGap application, you just have to add an event listener for the “statusTap” event, which is triggered when the user taps on the operating system’s status bar.  It is literally this simple:

[js]window.addEventListener("statusTap", function() {
alert("status tap");

This just shows an alert that the status bar was tapped. If you want to animate specific containers, you have to do this manually yourself via JavaScript. Again, that isn’t hard to do. Here’s an excerpt that I used from the Halloween app, using jQuery syntax:

[js]window.addEventListener("statusTap", function() {
var target = $("#scroller");

//disable touch scroll to kill existing inertial movement
‘-webkit-overflow-scrolling’ : ‘auto’,
‘overflow-y’ : ‘hidden’

target.animate({ scrollTop: 0}, 300, "swing", function(){

//re-enable touch scrolling
‘-webkit-overflow-scrolling’ : ‘touch’,
‘overflow-y’ : ‘scroll’

This disables touch scrolling to kill any inertial scrolling in progress, animates the scroll to top, then re-enables touch scrolling once the animation is complete.

That’s it…  Go check out the code, fork it, or use it in your own project:


New Version of My Halloween PhoneGap App

With Halloween less than a month away, I figured it’s about time to update my “Instant Halloween” PhoneGap sound effects app. I’m happy to say that the latest version is now out for both iOS and Android. It has a few new sounds, a new UI style, and has been updated for iOS 7. I also updated the low latency audio plugin so it now supports PhoneGap 3.0 method signatures and supports the command line tooling for installation.

halloweenThis app is fantastic for scaring people… Just hook it up to really loud speakers, and start playing the sounds to your heart’s content. It’s got everything from background/ambient loops to maniacal laughter, screams, ghosts, zombies, and other spooky sound effects.

It is available now, for FREE, for both iOS (5.0+) and Android (4.0+).


So what has changed in this version?

First, I updated the app to support iOS 7. For the most part, this is a non-issue. PhoneGap apps are based on web standards, and HTML/JS/CSS work pretty much everywhere. However, you do have to account for a few minor changes. One is that the OS status bar now sits over top of the application. You’ll need to update your UI on iOS 7, so there are no UI issues. Check out this post from Christophe Coenraets for details regarding creating PhoneGap apps for iOS 7.

iOS 7 also introduces some new UI design paradigms and guidelines. I simplified the user interface, got rid of all textures, and tried to make things as simple and minimalistic and native-feeling as possible. I also got rid of iScroll for touch-based scrolling – both the iOS and Android versions now use native inertial based scrolling from the operating system. This is the reason that the new Android version is only Android 4.0 and later, but it is also the reason that the app feels much closer to a fully native experience.

I updated the low latency audio native plugin to support PhoneGap PhoneGap 3. There were two parts to this: First, there is the updated method signature on the native interfaces. I just took the old plugin, and updated it for the new method signature. The new method signature was actually introduced a while back, but I never updated the plugin for it. Second, I added the appropriate XML metadata to enable CLI-based installation of the plugin for both iOS and Android. Take a look at the PhoneGap documentation for details on creating PhoneGap native plugins and plugin.xml.  Also check out this tutorial from Holly Schinsky for help creating native plugins for Android.

You can check out the full source code for the low latency audio native plugin for both iOS and Android, plus the plugin.xml specification on github at:

To include it in your own PhoneGap 3.0 (or later) projects, you can just add it from the PhoneGap command line interface:

[code]phonegap local plugin add[/code]

Of course, as with all of my PhoneGap apps, this one is open source too. You can check out the full app source (minus the audio assets) at:

In the process, I also ran into an unexpected issue with Android deployment… Back in the spring I had a corrupted hard drive. I was able to recover *most* of my data, and I thought I had all of my app signing keys. It turns out that for Android, your apps must not only have the same signing keys, but also the same key store when you sign the APK files, or else Google won’t let you distribute the Android APK file as an update; it must be a new app. It turns out that I had recovered the key, but not the keystore. So, I had no choice but to distribute it as a new app.

Go download the free apps, get the source code, and start building your own PhoneGap apps today!