This post last updated August 19, 2015, to reflect changes from Martin.js v0.3.1.
With Martin.js officially out of beta, I thought I’d show off some of its niftier capabilities. Martin.js can do basic photo editing, like you would do in Photoshop, but with a few lines of code, you can also manipulate photos interactively, and animate, all in browser*.
*Of course, for best results, view in Chrome.
Adjust the levels:
← Dark | Light → ← Black & White | Vibrant →
In the above example, I’m just calling two built-in methods — .lighten() and .saturate() and adjusting the amount based on the slider. These methods create Effects that are applied to a canvas layer and can be stacked on top of each other. Read more about Effects in Martin.js.
In addition to the built-in Effects, it’s relatively easy to create your own — it just takes a little knowledge of how pixel data is displayed on the screen. Each pixel contains four values that describe how it’s displayed: red, green, blue, and alpha (transparency).
By looping through all the pixels in a photo (which sounds overwhelming, but can actually be done relatively quickly), you can not only retrieve the rgba values, but also manipulate them. Martin.js comes with an easy way to do this — the .loop() method.
A trivial but impactful example would be to overwrite the pixel’s red value to be 255 (the maximum, on a scale of 0-255). To do this, we first have to register this as a new effect, and then apply it to our canvas.
An effect can also be applied interactively when the user mouses over the photo, creating a spotlight.
The key in the above example is to remove and re-apply the spotlight with each mousemove. Otherwise, the Effect will act recursively, quickly turning every pixel black. Read more about Events in Martin.js.
A number of effects from Photoshop or other photo editing programs can easily be recreated, for example the gradient map.
A gradient map will clamp outlying color values to a predetermined range. If your map is from blue to yellow, then dark values will appear blue, light values will appear yellow, and anything between will be coerced to that spectrum (that is, greenish, as in the above example).
A gradient map can also invert a photo, mapping dark to light and vice-versa. And while it can completely invert the image, as in the immediate above example, it can also invert some values but not others, as in the example above that, where red is inverted but blue and green are left untouched.
Effects can change based on data other than user interaction and existing pixel data, such as time. By using requestAnimationFrame(), we can easily make animations from photos.
In the above example, a new .rainbow()Effect takes a time parameter, which is incremented with each available animation frame. It loops and increases the pixel’s red, green, and blue values, lightening them. The amount it lightens each value depends on the pixel’s x value (in any pixel column, they are all being lightened by the same amount) and on the time. However, red, green, and blue all act differently based on the time parameter — the blue “wave” is faster than green, which is faster than red — causing the rainbow-like color shifts we see.