NEF Workflow for D70s on Linux

This document describes my own workflow for processing RAW pictures from D70s to my linux computer. All steps here should work equally well on D70 and on other operating systems as long as you are able to install the software needed.

Required software (free)

Workflow

  1. Copy files from camera to computer.
  2. Run the script prenef in the directory into which you have copied the nef-files. prenef does the following:
    1. Makes all filenames lowercase
    2. Changes the _ in the filenames to a predefined number between 0 and 9
    3. Runs dcraw in cheapest mode for preview jpg pictures
    4. Extracts exif-tags from nef-files and writes them to the jpg pictures
  3. Run a jpg-viewer on the dscXXXXXpre.jpg files, configure the viewer to also move away the nef-file when you want to delete a file. If using qiv, try the qiv-command below
  4. Run runnef. It runs dcraw again with chosen settings for final pictures, transfers exif-tags and deletes the preview pictures.
  5. For pictures that need manual processing, open them in gimp with the ufraw plugin

Scripts

prenef

[Download]
#!/bin/bash
#
# First preliminary step in NEF-workflow. Makes jpg-images quick
# for selection process.
# 
# Håvard Berland   
# http://www.pvv.ntnu.no/~berland
#
# Details of this script:
#
# 1. Makes all filenames lowercase.
# 2. Changes the _ in the D70s-filenames to a chosen number between 0 and 9
# 3. Runs dcraw in cheapest mode for preview-jpg-pictures
# 4. Extracts exif-tags from nef-files and write them to preview-jpg-pictures.
# 5. Remove Orientation-exif-tag as dcraw has already rotated the picture.
#
# Next step of workflow is to run qiv, where the delete-command also
# removes the nef-file.
#
# This script performs its operations on all nef-files present
# in current directory.
#

#############################################
# User servicable parts:

digit5=0 # The fifth digit in filenames.

##############################################

# 1: Make all filenames lowercase
for file in `ls *`
	do
	newname=`echo $file | tr [A-Z] [a-z]`
	mv -u -f $file $newname
done	

# 2: Add a fifth significant digit to filenames
for file in `ls *_*.jpg *_*.nef *.bib 2>/dev/null`
         do
         newname=`echo $file | tr [_] [${digit5}]`
	 mv $file $newname
done



# 3: Dcraw in fastest mode
# 4: Exif tags
# 5: Clear exif rotation-tag.
for neffile in `ls *.nef`
	do
	echo "Processing $neffile"
	prejpgfile=${neffile%.nef}pre.jpg
	jpgfile=${neffile%.nef}.jpg
	if [ ! -f "$jpgfile" ] ; then
	    nice dcraw -h -q 0 -w -c $neffile | convert - $prejpgfile && \
		neftags2jpg $neffile $prejpgfile  && \
		jhead -norot $prejpgfile 
	else
	    echo "Skipped, $jpgfile exists"
	fi
done

runnef

[Download]
#!/bin/bash
#
# Third step in NEF-workflow. 
# 
# Håvard Berland 
# http://www.pvv.ntnu.no/~berland
#
# Details of this script:
# 
# 1. Runs dcraw in chosen default mode for finished jpg-pictures.
# 2. Extracts exif-tags from nef-files and write them to preview-jpg-pictures.
# 3. Deletes *pre.jpg files from step 1 of workflow.
# 4. Remove Orientation-exif-tag as dcraw has already rotated the picture.
#
# Usage:
# $ runnef      # will process all nef-files in current directory
# $ runnef neffile1.nef neffile2.nef # processes chosen files.

###############################################
# User servicable parts:

#dcrawoptions="-h -q 3 -w -B 2 4" 
dcrawoptions="-h -q 3 -w"
convertoptions="-quality 95 -sharpen 5"


################################################
# Function used in this script, takes one 
# nef-file as the argument.
runneffile () {
    neffile=$1
    echo -n "Processing $neffile... "
    prejpgfile=${neffile%.nef}pre.jpg
    jpgfile=${neffile%.nef}.jpg
    rm -f $prejpgfile # This file should go away now.
    if [ ! -f "$jpgfile" ] ; then
	dcraw $dcrawoptions -c $neffile \
	    | convert $convertoptions - $jpgfile && \
	    neftags2jpg $neffile $jpgfile  && \
	    jhead -norot $jpgfile && \
	    echo "done"	
    else
	echo "SKIPPED, $jpgfile exists."
    fi
}


###################################################
# Entry point of this script.

# If no arguments, process all nef-files in current dir.
if [ $# == 0 ]; then
    for neffile in `ls *.nef`
      do
      runneffile $neffile
    done
else
# If shell arguments are supplied, assume it is filenames.
    for neffile in $@
      do
      if [ !  ${neffile%.nef} == $neffile ] ; then
	  runneffile $neffile
      else
	  echo "$neffile does not have correct extension"
      fi
    done
fi


qiv-command

[Download]
#!/bin/bash
#
# Script run by qiv when a numeric key is pressed (0-9)
#
# Argument 1 ($1) is the key pressed (0-9)
# 
# Argument 2 is the filename, without full path, active when the numeric
# key was pressed.

case $1 in
# Rotate 90 degrees clockwise.
   1)
	mkdir -p .qiv-trash
	mv $2 .qiv-trash/$2
	jpegtran -copy all -rotate 90 -trim < .qiv-trash/$2  > $2 
	;;
# Rotate 90 degrees counter-clockwise.
   2) 
	mkdir -p .qiv-trash
	mv $2 .qiv-trash/$2
	jpegtran -copy all -rotate 270 -trim < .qiv-trash/$2 > $2 
	;;
# Display EXIF-info
   3)
	jhead $2
	;;
# Open current file in Gimp
   4)   ## Note: 
	## qiv *MUST NOT* be in fullscreen mode when using this, 
	## qiv will hang!
	gimp-remote --no-splash $2 &
	;;
# Open corresponding nef-file in Gimp (plugin for gimp needed)
   5)   ##Note: 
	## qiv *MUST NOT* be in fullscreen mode when using this, 
	## qiv will hang!
	jpgfile=$2
	filebase=${jpgfile%.jpg}
	filebase=${filebase%pre}
	neffile=$filebase.nef
	if [ -f $neffile ]; then
	    gimp-remote --no-splash $neffile &
	fi
	;;
# Move current jpg and nef to .qiv-select
   8)   ##
        mkdir -p .qiv-select
        jpgfile=$2
        filebase=${jpgfile%.jpg}
        filebase=${filebase%pre}
        neffile=$filebase.nef
        mv $jpgfile .qiv-select/
        mv -f $neffile .qiv-select/
	mv -f $neffile.bib .qiv-select/
        ;;
# Delete current jpg file AND corresponding nef-file.
   9) 	## Note:
        ##  Qiv 2.1 and above handles this better.
	mkdir -p .qiv-trash
	jpgfile=$2
	filebase=${jpgfile%.jpg}
	filebase=${filebase%pre}
	neffile=$filebase.nef
	mv -f $jpgfile .qiv-trash/
	mv -f $neffile .qiv-trash/	
	mv -f $neffile.bib .qiv-trash/ 2>/dev/null
	;;
# Unrecognized command, show usage
   *) 
	echo "Usage:"
	echo " 1: Rotate 90 degrees clockwise using jpegtran."
	echo " 2: Rotate 90 degrees counter-clockwise using jpegtran."
	echo " 3: Display EXIF-info using jhead."
	echo " 4: Open current file in Gimp (no fullscreen!)"
	echo " 5: Open corresponding nef-file in Gimp (plugin for gimp needed) (no fullscreen!)"

	echo " 8: Copy current jpg and nef to .qiv-select."
	echo " 9: Delete current jpg-file AND corresponding nef-file."
	exit 
	;;
esac

scale

[Download]
#!/bin/bash
#
# Scales pictures to either web-size or thumb-size using
# ImageMagick's convert-command.
#
# Håvard Berland
# http://www.pvv.ntnu.no/~berland/
#
# Scaling is skipped if scaled file already exists and is newer
# than original file.
#
# This script is designed for this example picture hierarchy:
#  2005--+- 01 
#        `- 01-trip
#  2006--+- 01 
#        +- 02 
#        `- 03 
# and will generate the structure
#  web--+-2005--+- 01 
#       |       `- 01-trip
#       `-2006--+- 01 
#               +- 02 
#               `- 03 
# although nothing of this is enforced or difficult to change.
#
# When launching the script, ensure your working directory is at the top
# level of your hierarchy.

# To force scaling (if you have changed options), do 
# $ find scaled/web -type f -exec touch -d "19800101" {} \;
# (this is preferred over 'rm -rf web')
#
# Current option-sets for ImageMagick's convert requires
# ImageMagick version 6 and upwards.

# If no directories are supplied, use this wildcard pattern:
allsubdirspattern="*20??"

ulimit -d 300000

usage () {
    echo "Scales pictures for use on web, thumbs, etc."
    echo "\$ scale -web       # Scales all pictures to web-resolution"
    echo "\$ scale -thumb     # Scales all pictures to thumbs-resolution"
    echo "\$ scale -web 2004  # Scales all pictures in directory 2004 to web"
}


# Add more option sets here if needed.
if [ "$1" == "-web" ] ; then
    dir='scaled/web'
    size="800x600"
    convertoptions="-quality 90 -strip"
    unsharpen="-unsharp 0.3x0.6+1.3"
    shift
elif [ "$1" == "-thumb" ] ; then
    dir='scaled/thumbs'
    size="500x85"
    convertoptions="-quality 70 -strip"
    unsharpen="-unsharp 0.3x0.6+1.3"
    shift
elif [ "$1" == "-tv" ] ; then
	dir='scaled/tv'
	size="1366x768"
	convertoptions="-quality 85 -strip"
	unsharpen="-unsharp 0.3x1+2"
	shift
elif [ "$1" == "-nokia" ] ; then
	dir='scaled/nokia'
	size="300x300"
	convertoptions="-quality 92 -strip"
	unsharpen="-unsharp 0.3x0.6+1.3"
	shift
else
    usage
    exit 1
fi

mkdir -p $dir

#######################################
# Function to process one subdirectory:
#
# Converts all jpg-files in chosen subdir,
# preserves arbitrary directory structures.
dosubdir () {
    subdir=$1
   
    if [ "Darwin" == `uname -s` ] ; then
	XARGS="xargs -I % mkdir -p $dir/%"
    else
	XARGS="xargs --replace mkdir -p $dir/{}"
    fi
 
    # Duplicate directory structure with exceptions for safety:
    # (there is a risk of infinite recursion here)
    find $subdir -type d \
	| grep -v -e $dir -e .qiv-trash -e .xvpics \
	| $XARGS ; 

    
    files=`find $subdir -name *.jpg  | grep -v .qiv- | wc -l`
    filecounter=0
    echo "Doing subdir $subdir"
    for filename in `find $subdir -name *.jpg | grep -v qiv-trash | grep -v xvpics` ; do
	filecounter=$((filecounter+1))
	echo -n " $filecounter / $files   $filename                "

	if [ ! -f "$dir/$filename" -o "$filename" -nt "$dir/$filename" ] ; then
	    convert -geometry $size $convertoptions $unsharpen \
		"$filename" "$dir/$filename" || rm -f "$dir/$filename"
	fi
	echo -e "\r\c"
    done
    echo
}

########################################
# Entry point of script


# If no arguments, process all subdirs
if [ $# == 0 ]; then
    for subdir in `ls -d $allsubdirspattern`
      do
      dosubdir $subdir
    done
else
    # If any (remaining) shell arguments, assume it is subdirectories
    for subdir in $@
      do
      if [ -d $subdir ] ; then
	  dosubdir $subdir
      else
	  echo "$subdir not found"
      fi
    done
fi

Håvard Berland