#!/usr/bin/python """ This script helps to convert 12/16 bit raw images to 8 bit images using external tools. External tools: * raw decoding using 'dcraw' (with -S saturation support) * image manipulations using 'convert', 'mogrify' (part of imagemagick) * CA correction using 'tca_correct', 'fulla' (part of hugin) * EXIF manipulations using 'exiv2' Features: * batch processing * fast or HQ raw image decoding modes * camera white balance * gamma correction in 16bit * sharpening in 16bit * fully automatic CA correction * retain original EXIF * custom comment * easy, configurable Usage: raw2jpeg.py ${DIRECTORY}/*.${EXTENSION} Converted images appear in the same directory as original images, have the same name but different extension. ${DIRECTORY} must be writable. Example: raw2any.py ~/raw/*.DNG Copyright 2008 Michael Baranov ( michael dot baranov at gmail dot com ) Licensed under Creative Commons Attribution-Share Alike 3.0 """ # Configuration: binaries bin_dcraw = "dcraw" bin_convert = "convert" bin_mogrify = "mogrify" bin_exiv2 = "exiv2" bin_tca_correct = "tca_correct" bin_fulla = "fulla" # Configuration: processing properties prop_verbose = True prop_quick = False # True => half-resolution fast raw decoding prop_unsharp = True # True => apply unsharp mask using imagemagick (fast) prop_correct_CA = False # True => automatically correct CA with tca_correct and fulla (slow) prop_resize = True # True => resize result with imagemagick prop_format = "JPEG" # resulting image format/extension (JPEG, TIFF, PNG etc.) prop_comment = "Converted using dcraw, imagemagick, exiv2" # comment to embed, ASCII only prop_saturation = 3100 # camera-specific saturation value ( dcraw -S ). # PENTAX K10D = 2900..3100 to avoid purple highlights. prop_gamma = 2.2 # gamma value, 2.2 is common prop_unsharp_radius = 0.5 # unsharp radius -- see imagemagick prop_unsharp_sigma = 1.0 # unsharp sigma -- see imagemagick prop_unsharp_amount = 5.0 # unsharp amount -- see imagemagick prop_unsharp_threshold = 0 # unsharp threshold -- see imagemagick prop_resize_size = 1280 # max width/height of resized image -- see imagemagick # ... End of Configuration import sys, os, re, popen2, fcntl, select # building dcraw command cmd_dcraw = "" cmd_dcraw += "%s" % bin_dcraw cmd_dcraw += " -w" # camera white balance cmd_dcraw += " -S %s" % prop_saturation # camera-specific saturation if prop_quick : cmd_dcraw += " -q 0" # interpolation quality cmd_dcraw += " -h" # half-size (fast) else: cmd_dcraw += " -q 3" # interpolation quality cmd_dcraw += " -f" # interpolate as four colors to avoid artifacts (most likely VNG will be used) cmd_dcraw += " -4" # 16bit, no gamma cmd_dcraw += " -T" # write TIFF cmd_dcraw += " -c" # write to stdout cmd_dcraw += " -t 0" # do not rotate (since EXIF will be injected) if prop_verbose : cmd_dcraw += "-v " # verbose cmd_dcraw += " %s > %s" # building convert command cmd_convert = "" cmd_convert += "%s" % bin_convert cmd_convert += " %s" if prop_verbose : cmd_convert += " -verbose" # verbose cmd_convert += " -depth 16" # hint: work in 16bit if prop_unsharp : cmd_convert += " -unsharp %sx%s+%s+%s" % ( prop_unsharp_radius, prop_unsharp_sigma, prop_unsharp_amount, prop_unsharp_threshold ) cmd_convert += " -gamma %s" % prop_gamma # gamma if prop_resize : cmd_convert += " -resize %sx%s" % ( prop_resize_size, prop_resize_size ) cmd_convert += " -depth 8" # hint: work in 8bit cmd_convert += " -quality 100" # JPEG quality, unused for uncompressed formats cmd_convert += " %s" # building tca_correct command cmd_tca_correct = "" cmd_tca_correct += "%s" % bin_tca_correct cmd_tca_correct += " -o abcv" # optimize a,b,c,v params cmd_tca_correct += " %s" # building fulla command cmd_fulla = "" cmd_fulla += "%s" % bin_fulla cmd_fulla += " -r %s" # red channel params cmd_fulla += " -b %s" # blue channel params cmd_fulla += " -o %s" # output name cmd_fulla += " %s" # building mogrify command cmd_mogrify = "" cmd_mogrify += "%s" % bin_mogrify cmd_mogrify += " -strip" # strip image of color profiles cmd_mogrify += " %s" # building exiv2 command -- extract cmd_exiv2_extract = "" cmd_exiv2_extract += "%s" % bin_exiv2 cmd_exiv2_extract += " extract" cmd_exiv2_extract += " -f" # force cmd_exiv2_extract += " %s" # building exiv2 command -- insert cmd_exiv2_insert = "" cmd_exiv2_insert += "%s" % bin_exiv2 cmd_exiv2_insert += " insert" cmd_exiv2_insert += " -f" # force cmd_exiv2_insert += " -M\"set Exif.Photo.UserComment Ascii %s\"" # on-the-fly modify commant cmd_exiv2_insert += " %s" # from Python Cookbook def makeNonBlocking( fd ): fl = fcntl.fcntl( fd, fcntl.F_GETFL ) try: fcntl.fcntl( fd, fcntl.F_SETFL, fl | os.O_NDELAY ) except AttributeError: fcntl.fcntl( fd, fcntl.F_SETFL, fl | fcntl.FNDELAY ) # from Python Cookbook def runCmd( command ): child = popen2.Popen3( command, 1 ) child.tochild.close() outfile = child.fromchild outfd = outfile.fileno() errfile = child.childerr errfd = errfile.fileno() makeNonBlocking( outfd ) makeNonBlocking( errfd ) outdata = errdata = '' outeof = erreof = 0 while 1: ready = select.select( [outfd, errfd], [], [] ) if outfd in ready[0]: outchunk = outfile.read() if outchunk == '': outeof = 1 outdata = outdata + outchunk if errfd in ready[0]: errchunk = errfile.read() if errchunk == '': erreof = 1 errdata = errdata + errchunk if outeof and erreof: break select.select( [], [], [], .1 ) err = child.wait() if err != 0: raise RuntimeError, '%s failed w/ exit code %d\n%s' % ( command, err, errdata ) return outdata if len( sys.argv ) == 1: print 'Example Usage: raw2any.py ${DIRECTORY}/*.${EXTENSION}' print 'Converted images appear in the same directory as original images, have the same name \ but different extension. ${DIRECTORY} must be writable.' sys.exit() # script for raw in sys.argv[1:]: dot = raw.rfind( "." ) ext = raw[dot+1: len( raw )] filename_target = raw[0 : dot ] + "." + prop_format filename_tmp = raw[0 : dot ] + ".t0.TIFF" filename_tmp2 = raw[0 : dot ] + ".t1.TIFF" filename_exv = raw[0 : dot ] + ".exv" print '> Processing: %s -> %s' % ( raw, filename_target ) print '>> Decoding raw...' runCmd( cmd_dcraw % ( raw, filename_tmp ) ) if prop_correct_CA : print '>> Calculating CA correction params...' output = runCmd( cmd_tca_correct % ( filename_tmp ) ) ca_params = re.findall( "-r (.*) -b (.*)", output ) print '>> Applying CA correction...' runCmd( cmd_fulla % ( ca_params[0][0], ca_params[0][1], filename_tmp2, filename_tmp ) ) runCmd( "rm %s" % filename_tmp ) runCmd( "mv %s %s" % ( filename_tmp2, filename_tmp ) ) print '>> Processing...' runCmd( cmd_convert % ( filename_tmp, filename_target ) ) # apply corrections and convert to 8bpp runCmd( cmd_mogrify % ( filename_target ) ) # remove color profile(s) so that smart apps (GIMP) do not apply them again print '>> Copying EXIF...' runCmd( cmd_exiv2_extract % ( raw ) ) runCmd( cmd_exiv2_insert % ( prop_comment, filename_target ) ) print '>> Cleanup...' runCmd( "rm %s" % filename_tmp ) runCmd( "rm %s" % filename_exv )