Purely Functional Photoshop

One of the first things you learn about Photoshop--or any similarly styled image editor--is to use layers for everything. Don't modify existing images if you can help it. If you have a photo of a house and want to do some virtual landscaping, put each tree in its own layer. Want to add some text labels? More layers.

The reason is straightforward: you're keeping your options open. You can change the image without overwriting pixels in a destructive way. If you need to save out a version of the image without labels, just hide that layer first. Maybe it's better if the labels are slightly translucent? Don't change the text; set the opacity of the layer.

This stuff about non-destructive operations sounds like something from a functional programming tutorial. It's easy to imagine how all this layer manipulation could look behind the scenes. Here's a list of layers using Erlang notation:

[House, MapleTree, AshTree, Labels]

If you want to get rid of the label layer, return a new list:

[House, MapleTree, AshTree]

Or to reverse the order of the trees, make another new list:

[House, AshTree, MapleTree, Labels]

Again, nothing is being modified. Each of these simple manipulations returns a brand new list. Performance-wise there are no worries no matter how much data House represents. Each version of the list is referencing the same data, so nothing is being copied. In Erlang, each of these alternate list transformations creates three or four conses (six or eight memory cells total), which is completely irrelevant.

Now what about changing the opacity of the labels layer? Realistically, a layer should be a dictionary of some sort, maybe a property list:

[{name,"labels"},...]

If one of the possible properties is opacity, then the goal is to return a new list where the layer looks like this:

[{name,"labels"},{opacity,0.8}]

Is this all overly obvious and simplistic? Maybe, especially if you have a functional programming background, but it's an interesting example for a couple of reasons. Non-destructive manipulations are the natural approach; there's no need to keep saying "I know, I know, this may seem awkward, but bear with me, okay?" It also shows the most practical reason for using a language like Erlang, Haskell, or Lisp: so you can easily work with symbolic descriptions of data instead of the raw data itself.

permalink August 8, 2013

previously