Last month we went on vacations to a place with medium light pollution. It was also meteor shower season;
the Perseids were peaking that week. So I decided to try some astro-photography. I bought a cheap barn
door tracker, but it didn't arrive before we left, so I had to change my plans of
taking Milky Way pictures.

I went for the other extreme; instead of steady stars, why not star trails?
Luckily, my Nikon D7200 already has Interval Timer Shooting, so it was only a matter of setting it up
correctly[^1] and let it take as many pictures as long as it still has power. You can say that was the
easy part. The hard part was to do the stacking.

The way you stack star trail photos is that you combine them in
[Lighten mode](https://www.w3.org/TR/SVGCompositing/#comp-op-property). Ihad already used that technique
to produce
[this photo](https://dionecanali.hd.free.fr/~mdione/anotherg/misc/?imageLightboxIndex=2019-11-28-004.jpg)
Gimp
can do it, if you load all the images as layers and then set each layer _by hand_ with a lighten mode.
The _by hand_ part is the hard part. My first attempt gave me only 58 photos, so it was not _that_ bad,
but the repetitiveness of the task (select a layer, change the mode, iterate, a mouse only operation)
asked for automation. Unluckily there is not a good way to generate a file that gimp can load with all
that info prefilled; its native format, XCF, is binary, and embeds all the images, so 58x12Mpx4 channels
equals 2784MB! Plus metadata... The second attempt yielded 250+ photos. Stacking _that one_ was
_tedious_, and the outcome (because of some technical reasons) was not that great.


Why not programmatically? I asked around what good Python modules that could do composition operation
and I was pointed to GTK, but the API didn't look very friendly (to me it looks like it's more aimed to
implement things
like Inscape than GIMP). I looked for a second time and found
[BlendModes](https://github.com/FHPythonUtils/BlendModes/). That lead to a short script, but it was
_slow_, and consumed lots of RAM. I didn't look into the code, but it's probably implemented in pure
Python and might be doing some things wrong.

Third time's the charm: I found [Image Blender](https://github.com/psd-tools/image-blender/). It's
written in
Cython, so it's mostly readable _and_ fast, at least fast enough. I simply modified the original code
and got this:

```python
#! /usr/bin/python3

import sys
from PIL import Image
import image_blender

in_files = sys.argv[1:-1]
out_file = sys.argv[-1]
count = len(in_files)

out_data = None

for index, in_file in enumerate(in_files):
    print(f"[{index+1}/{count}] {in_file}")
    in_image = Image.open(in_file).convert(mode='RGBA')

    if out_data is None:
        out_data = Image.new('RGBA', in_image.size)

    new_out = Image.frombytes('RGBA', in_image.size, image_blender.lighten(out_data.tobytes(), in_image.tobytes()))

    in_image.close()
    out_data.close()

    out_data = new_out

out_data.convert('RGB').save(out_file)
```

Not pretty, but it does the work and fast enough! Faster than selecting 250+ layers in GIMP just to
change the Mode :)

[^1]: I made myself a checklist, not complete:

      * Make sure the battery is full; use spare if needed.
      * Setup tripod with ballast for stability.
      * Large photo size (12Mp in my case).
      * Fine detail (I don't shoot RAW, don't have much time and expertise for developing photos, so low JPEG
      compression level).
      * No noise reduction.
      * VR off.
      * ISO between 400 and 1600; I think I took most with 800.
* Manual Shooting Mode, 30s exposure[^2]:, f as wide as possible; I used f/11.
      * Manual Focus.
      * Focus aiming at the brightest star, lens' zoom at peak (140mm in my case), then open back at the
      desired focal length, recompose.


[^2]: I wonder why all the cameras I have only allow exposures of up to 30s before going into bulb mode?

