collection imports

I added a little filter automation to my photo import pipeline tonight. I download everything from my phone to a library on my laptop. During post authoring I use geeqie to select images, which I save to a collection named after the post slug. I would then open all those in gimp and apply auto level adjustments, overwriting the original files. Finally I had a make target in my blog repo to import those images where nikola wants them:

.PHONY: collection/%
collection/%:
    sed -e '/^#/d' -e 's|$(LIBRARY)||' ~/var/geeqie/collections/$*.gqv \
        | env -C $(LIBRARY) xargs cp --parents -t $(CURDIR)/images

Tonight I was focused on eliminating the manual gimp work and not overwriting the originals. I wound up with a little python script that does the geeqie collection parsing and histogram stretching for each entry:

#!/usr/bin/env python3

import argparse
import os
import pathlib
import sys

import PIL.Image
import PIL.ImageOps

# https://forum.doom9.org/showthread.php?p=1323266
# http://www.fmwconcepts.com/imagemagick/autocolor/index.php


def parse_args(argv):

    parser = argparse.ArgumentParser()

    parser.add_argument("root")
    parser.add_argument("collection")

    return parser.parse_args(argv)


def strip(line):
    return line.strip()


def entries(line):
    return line.startswith('"') and line.endswith('"')


def autocontrast(ifname, ofname):

    img = PIL.Image.open(ifname)

    transposed = PIL.ImageOps.exif_transpose(img)
    output = PIL.ImageOps.autocontrast(transposed, cutoff=1.0)

    output.save(ofname)

    print(ofname)


def main():

    args = parse_args(sys.argv[1:])

    root = os.path.expanduser(args.root)

    with open(os.path.expanduser(args.collection), "r") as fin:

        for line in filter(entries, map(strip, fin.readlines())):

            ifname = pathlib.PurePosixPath(line[1:-1])
            ofname = "images" / ifname.relative_to(root)

            os.makedirs(ofname.parent, exist_ok=True)
            autocontrast(str(ifname), str(ofname))


if __name__ == "__main__":
    main()

That also includes rotating per the exif orientation, which gimp was doing automatically for me, and creating the output parent directory, which cp --parents was doing. The blog source installs as a python package, so now the make target looks like this:

.PHONY: collection/%
collection/%:
    @python -m digestorium.autocontrast $(LIBRARY) ~/var/geeqie/collections/$*.gqv

For the sake of testing I created a collection with this image of Teemo from his birthday. Neurotic as I am I also added a specific target for copying the original image untouched so I could display them side by side. Of course I had to pick an example where the effect is hardly noticeable, but twice the Teemo is hardly a bad thing.

This makes it generally awkward for comparing side by side, so I need to think about that. At least when I was doing this manually I could fiddle with the preview. It also implies that the filtering will always be done, which isn't necessarily the case. I've had a few images that I've not bothered with because the originals were looking better. I also like the idea of integrating with nikola/doit instead of having the Makefile. I might try first converting from the geeqie collection format to something like nikola's gallery metadata, with an enhancement to let me specify which, if any, filters to apply per image during build time.