#!/usr/bin/env python
# -*- coding: utf-8 -*-

# CCraig :: Star Trails
# Copyright Christopher Craig 2010
# Licence GPL

"""
Combines multiple images to make Star Trails.
Takes files from Directory substituting integers from 
  Start to End into Filebase (defaults to Nikon format jpegs). 

Mode sets the layer mode for the individual images.
- Addition gives you the closest approximation to what you would have gotten
  if you had left the shutter open for a single long exposure.
- Lighten is much more tolerant of background light.

Threshold is used to control ambient light.  Set to a number that 
suppresses light polution but captures the star trails. 
(lower gives lighter skies, higher gives spotty trails).

Dark Frame is the frame you shot with the lens cap on at the end of the shoot.

If Combine Images is turned off you get two layers for each frame shot 
(one for the frame and one for the dark frame, plus a mask if you're 
using a threshold) which could quickly eat up memory.

If a file is missing the script will continue silently.  If a file
exists but fails to load an error will be thrown.
"""

from gimpfu import *
import os

# i18n
#
import gettext
locale_directory = gimp.locale_directory 
gettext.install( "gimp20-ccraig", locale_directory, unicode=True )

#
description = _("""Combines multiple images to make Star Trails.""")
help=description

def assemble_images( 
  dirname, filebase,
  start, end, 
  mode, thresh, darkframe,
  combine): 

  baseimage = darkframelayer = None
  for i in range(start, end+1):
    # build image filename
    imagefn = os.path.join(dirname, filebase % i)

    if not os.path.exists(imagefn): continue
    if baseimage is None:
      # we don't have an image yet, load this one as the base
      try:
        baseimage=pdb.gimp_file_load(imagefn, imagefn)
      except:
        pdb.gimp_message("Cannot load file %s" % imagefn)
        return
      baseimage.filename = ""
      baseimage.disable_undo()
      h,w=baseimage.height,baseimage.width
      gimp.Display(baseimage)
      if darkframe:
        # build initial dark frame layer
        darkframelayer = pdb.gimp_file_load_layer(baseimage, darkframe)
        darkframelayer.mode = SUBTRACT_MODE
        if mode==0: baseimage.add_layer(darkframelayer, 0)
      continue

    # we do have an image already, add remaining images as layers
    try:
      nl = pdb.gimp_file_load_layer(baseimage, imagefn)
    except:
      pdb.gimp_message("Cannot load file %s" % imagefn)
      return

    if mode==0:
      nl.mode=ADDITION_MODE
    else:
      nl.mode = LIGHTEN_ONLY_MODE
    baseimage.add_layer(nl, 0)

    # build layer mask
    if thresh: 
      mask = nl.create_mask(ADD_COPY_MASK)
      nl.add_mask(mask)
      pdb.gimp_threshold(mask, thresh, 255)

    if darkframe and mode==0:
      # copy the dark frame subtraction
      dl = darkframelayer.copy()
      baseimage.add_layer(dl, 0)
      
    if combine:
      baseimage.flatten()
    gimp.displays_flush()

  if darkframe and mode==1:
      # copy the dark frame last in lighten mode
      dl = darkframelayer.copy()
      baseimage.add_layer(dl,0)
      if combine:
        baseimage.flatten()
      gimp.displays_flush()

  baseimage.enable_undo()
    

    

register(
  "StarTrails",
  description,
  help,
  "Christopher Craig",
  "GPL License",
  "2010",
  _("Star Trails"),
  "",
  [
    (PF_DIRNAME, "directory", _("Directory"), os.getcwd() ),
    (PF_STRING, "filebase", _("File base (printf format)"), "DSC_%.4d.jpg" ),
    (PF_INT, "start", _("Start Number"), "1" ),
    (PF_INT, "end", _("End Number"), "1000"),
    (PF_OPTION, "mode", _("Combine Mode"), 0, ["Addition", "Lighten"]),
    (PF_INT, "thresh", _("Threshold"), "0"),
    (PF_FILENAME, "darkframe", _("Dark Frame"), ""),
    (PF_TOGGLE, "combine", _("Combine Layers"), True),
  ],
  [],
  assemble_images,
  menu="<Image>/Filters/Combine",
  domain=( "gimp20-ccraig", locale_directory )         
  )

main()
