Article History

Hybrid workflow

Work in progress

As a photographer shooting film, I employ what is often described as a hybrid workflow. That is, I shoot film then scan it and manipulate the photos digitally.

Here I'll try to describe my process. It's taken a little while to develop and perhaps this will help others.


Firstly, I'm a Linux user. While the scanning itself is done on a separate Windows machine, I do all my real work on Linux machines.

Cinepaint started many years ago as “FilmGIMP”, a fork of The GIMP made in an effort to allow working on 16-bit (as well as floating point, etc) images. It's buggy and crude but I don't have much choice.
I use ImageMagick quite a lot; partly because I prefer command-line use for batch operations, and partly to avoid the buggy and crude Cinepaint.

I use ImageMagick in a number of ways:

  1. The convert program in a shell script or two.
  2. The PerlMagick API in my process Perl script.
  3. The Magick++ API in my CPAG tools.

CPAG stands for “CinePaint Aint the GIMP”. It's a set of programs for performing simple operations on images. I wrote them after becoming frustrated at Cinepaint crashing in the middle of manipulating a photo. They're also much faster.



I currently have access to two film scanners. The first is a Nikon Coolscan V ED. It's a dedicated film scanner that takes 35 mm film as either strips (two to six exposures each) or mounted in slide frames. It has good resolution (4000 spi) and good colour response.

The other scanner is an Epson Perfection 4490 flatbed scanner. It has a transparency adapter that moves with the scanning platform below the glass, but is only about 10 cm wide. I use it to scan 120/220 film. It can supposedly scan at 4800 spi, but the results appear quite soft. I use a film holder from


I use 4000 spi on the Nikon Coolscan. For the Epson 4490 I scan at 4800 spi (on the assumption that it's the hardware resolution) and immediately downsample to 2400 spi.

Colour spaces

I like to use wide-gamut colour spaces when scanning in the hopes of capturing as much information as possible. Of course, this necessitates 16-bit channel depth.

The NikonScan software allows the use of a few colour spaces and I have used the Adobe wide gamut RGB colour space since not long after I started using it. The Epson software only allows use of the Adobe RGB colour space. It's smaller, with only an improvement in green coverage over the pathetic sRGB colour space. But it's still better than nothing.


Scanning is a slow and boring process, so I prefer to do as little as possible before scanning in order to speed things up. In particular, I don't customise the crop or adjustments for each scan. With the Nikon I check that each frame in a strip is properly selected because the software often has trouble differentiating between frames that are dark. With the Epson I still have to select each frame in a strip. It takes longer but I have a fixed 6×6 frame and it's still fairly simple to place it around each one.

In each case I scan extra space around each frame. I only spend the time cropping and adjusting the photos I actually want to work with.


I have a shell script for processing the raw, uncompressed TIFF's produced by the vendor's scanning software.

  1. Convert to a PNG file, optionally transforming it before-hand
  2. Produce a ‘preview’ image, 25% original size (in each dimension) in the sRGB colour space for easy viewing

Both of these steps are performed with Image Magick's convert program.

Converting from an uncompressed TIFF to PNG (with compression) can save a good deal of disk space — as much as 700-800 MiB per roll of film (135-36 or 220).

The ‘optional transformations’ of step 1 are mainly used for 120/220 film scanned on the Epson 4490. Not only do I downscale the scans from 4800 to 2400 spi, but they must also be flipped because I scan with the emulsion down.

Naming conventions

Perhaps at this point I should describe my simple system of naming directories and files.

Directory structure

Each roll of film is given a directory. I catalogue my rolls by when I put them in a camera. So the directory name starts with the ISO 8601-formatted date and then the film name.


2008-10-11 Fuji Pro 160S

The post-scan shell script mentioned above creates two sub-directories — originals for the converted PNG scan files, and works for temporary files created while working on a photo. The previews are created right in the film directory for easy viewing.

One alternative was to keep the originals in the film directory and put the previews in a sub-directory. But this would have been awkward and slow with many graphical viewers that produce thumbnails on the fly. The user would have navigated to a film's directory and been greatly slowed down as the computer tried to generate thumbnails of the large original scans. The scheme I use avoids that by puting the originals in a sub-directory that does not need to be navigated through in order to quickly look at the photos on a film.

File names

In the top film directory and the originals sub-directory, the files are simply numbered. e.g 02.png.

In the works sub-directory things get a little more detailed. Because of my experiences of Cinepaint crashing in the middle of working on a photo, I tend to save each step as a separate file. This also allows me to go back to a specific stage if I don't like the results of some later work.

Thus the files have growing names with each step separated by a hypen.


  1. 02-cropped.png
  2. 02-cropped-retouched.png
  3. 02-cropped-retouched-adjusted.png

Cleaning up

Once I've selected some photos I like, I start working on them.


The first step is to crop off the rubbish around the edges. In The GIMP this is fairly simple to accomplish because the crop tool allows the coordinates to be adjusted in the dialog box (along with up-down buttons). Cinepaint only allows the box to be adjusted with the mouse, so the process is a little convoluted:

  1. Go into Image > Colors > Curves and brighten up the shadow detail to make the edges clearer. Don't worry about being too drastic, this will be undone at the end.
  2. In a zoomed-out view drag guides from the rulers to roughly where the edges are i.e top, bottom, left, and right.
  3. Zoom into 400% and adjust each guide to cut off the minimum amount while leaving a good central photo.
  4. Zoom out again. Select the crop tool and select the image bounded by the guides.
  5. Since “Snap to guides” doesn't work, now zoom in again and place the top-left and bottom-right corners of the crop on the guide lines.
  6. Before hitting the “Crop” button, hit Alt+R to revert the image. This removes the guides and undoes the drastic curves applied at the start.
  7. Now hit the “Crop” button.
  8. Save as "xx-cropped.png" in the works directory before Cinepaint crashes.

The use of revert before cropping was originally a work-around to a bug in Cinepaint. It would crash if there where guides on the image; the revert removes them. It also allows you to apply some drastic adjustments to the image in order to bring out the edges of the photo.


The second step is sometimes not needed — cleaning up dust, fluff, and scratches. This is necessary on B&W film because Digital ICE doesn't work on silver halide films. It usually works pretty well on chromogenic film (all colour, some B&W) but sometimes still misses something. Sometimes in removing a piece of fluff it leaves behind a “ghost” outline that needs to be touched up itself. Once this is done, the image is saved as "xx-cropped-retouched.png".

Adjusting levels

This stage could either be seen as the final step of cleaning up the scan, or a type of manipulation. Usually this is a fairly minor adjustment with the curves tool. The scanning software often chooses a bad black level or white level, resulting in poor contrast.


Many of my photos feature no manipulation at all (beyond adjusting levels/curves). When I have manipulated photos, it has usually comprised one or more of the following:


Once I‘m happy with a photo comes the task of processing the photo for output. Remember, all the work so far has been on the full-resolution scans. And they’re in wide colour gamuts with 16-bit components.

For web output, this involves:

  1. Scaling the image to the target size with a sharpening filter
  2. Sharpening again a little more
  3. Cropping to the exact aspect ratio
  4. Converting to the sRGB colour space with 8-bit components
  5. Encoding a JPEG file with EXIF/XMP metadata

For other forms of output, most of these steps are optional.

I originally had a shell script "png2jpeg“ for doing this task. As I added features it became too complicated, so I instead moved to a Perl script using PerlMagick. It reads a list of ”destinations" from a YAML file.


At the moment I‘ve been burning single-layer DVD-R/+R (4.4GiB) discs containing a single roll each (or several for B&W). These discs are however not big enough for some rolls I’ve shot. For instance, many of the “36” exposure rolls have in fact given me 38 or 39 exposures. It also doesn't leave room to include the ‘works’ images I have been working on ― only the original scans.

I also like to use DVDisaster to augment a disc's ISO image with reed-solomon error correction codes. It theoretically makes it possible to rescue a partially defective disc, but it also uses up all the free space on a disc's ISO image. I'd like to create multi-session discs so that new works can be added to a disc after it's been burnt.

So I‘ve come up with a scheme to use dual-layer DVD+R discs, which are coming down in price. Each dual-layer disc gives about 8GiB of space, enough for both the original scans and a good number of ’works' images.

  1. Create an ISO image of the film directory
  2. Generate an ‘error correction file’ (RS01) with dvdisaster and store it on a safe RAID (1 or 5) filesystem.
  3. Burn the image to a dual-layer disc with the multi-session flag set
  4. Occasionally bundle up the error correction files and burn them to discs of their own
  5. After new files have been added to a disc, the whole disc will have to be dumped to an ISO image so that a new error correction file can be generated

That last point might not be right. I'll have to investigate how multiple sessions work.