Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kiekerjan/e8fbd5622b51ad32b8c3caddb9db4902 to your computer and use it in GitHub Desktop.
Save kiekerjan/e8fbd5622b51ad32b8c3caddb9db4902 to your computer and use it in GitHub Desktop.
Do you own a DSLR? If so, do you transfer your images to your computer, then look at the JPEGs and delete the crappy ones? If you do, your RAW images may be leftover. This Python script helps you cleaning up your image folders after deleting unwanted JPEGs. See http://blog.philippklaus.de/2012/12/cleaning-leftover-raw-images-after-selecting-imag…
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Written on 2012-12-12 by Philipp Klaus <philipp.l.klaus →AT→ web.de>.
Check <https://gist.github.com/4271012> for newer versions.
Slightly adapted to include other RAW formats and to make the tool work in reverse (i.e. remove JPEGs for which no raw can be found.) The script also cleans Sidecar (.xmp) files if present.
Moved to python3 (see
"""
import argparse, os, errno, re, shutil, sys
def stderr(line):
sys.stderr.write(line + '\n')
sys.stderr.flush()
def delete(files, backup_folder=None, verbose=True):
if len(files) == 0: return
if backup_folder:
try:
os.mkdir(backup_folder)
except OSError as e:
if not e.errno == errno.EEXIST:
raise
for filename in files:
if verbose: print("Moving %s to %s." % (filename, backup_folder))
shutil.move(filename, os.path.join(backup_folder))
else:
for filename in files:
if verbose: print("Deleting %s." % (filename,))
os.remove(filename)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Cleanup of leftover raw image files (*.CR2, *.ARW), or JPG files (*.JPEG, *.JPG). It also cleans sidecar (*.XMP) files that might be present.')
parser.add_argument('-n', '--no-backup', action='store_true',
help='Don\'t backup orphaned raw images - delete them immediately.')
parser.add_argument('-r', '--reverse', action='store_true',
help='Reverse action of tool, i.e. remove JPEGs for which no RAW file can be found.')
parser.add_argument('-b', '--backup-folder', default='raw_orphans',
help='Folder to move orphaned raw images to.')
parser.add_argument('-q', '--quiet', action='store_true',
help='Silence the less important output of this tool.')
parser.add_argument('folder', metavar='CHECK_FOLDER', default='./', nargs='?',
help='Folder to check for raw images. Defaults to the current working directory')
args = parser.parse_args()
verbose = not args.quiet
raw_images, jpeg_images_bare_names, jpeg_images, raw_images_bare_names = [], [], [], []
all_files = list(os.listdir(args.folder))
# sort files into raw and jpeg files
for filename in all_files:
# The file name of raw image ends with .CR2 for Canon EOS cameras, ARW for Sony and NEF for Nikon
if re.match(r'(.*)\.(?i)(cr2|arw|nef)$', filename):
raw_images.append(filename)
raw_images_bare_names.append(os.path.splitext(filename)[0])
if re.match(r'(.*)\.[jJ][pP][eE]?[gG]$', filename):
jpeg_images.append(filename)
jpeg_images_bare_names.append(os.path.splitext(filename)[0])
# Check if there is a jpeg for each raw image
orphans = []
if args.reverse:
for jpeg_image in jpeg_images:
if os.path.splitext(jpeg_image)[0] not in raw_images_bare_names:
orphans.append(jpeg_image)
# add xmp file
xmp_file = jpeg_image + '.xmp'
if os.path.isfile(xmp_file):
orphans.append(xmp_file)
if len(jpeg_images) + len(raw_images) == 0:
if verbose: stderr("No images found. Are you sure you wanted to check '%s' for orphaned JPEG images?" %
(args.folder,))
sys.exit(2)
elif len(jpeg_images) == 0:
if verbose: print("No JPEG images found, but %i RAWs. Won't do anything now." % (
len(raw_images),))
sys.exit(0)
elif len(orphans) == 0:
if verbose: print("%i JPEG images found, and %i RAWs but no orphans. Won't do anything now." % (
len(jpeg_images), len(raw_images)))
sys.exit(0)
else:
for raw_image in raw_images:
if os.path.splitext(raw_image)[0] not in jpeg_images_bare_names:
orphans.append(raw_image)
# add xmp file
xmp_file = raw_image + '.xmp'
if os.path.isfile(xmp_file):
orphans.append(xmp_file)
if len(raw_images) + len(jpeg_images_bare_names) == 0:
if verbose: stderr("No images found. Are you sure you wanted to check '%s' for orphaned RAW images?" %
(args.folder,))
sys.exit(2)
elif len(raw_images) == 0:
if verbose: print("No RAW images found, but %i JPEGs. Won't do anything now." % (
len(jpeg_images_bare_names),))
sys.exit(0)
elif len(orphans) == 0:
if verbose: print("%i RAW images found, and %i JPEGs but no orphans. Won't do anything now." % (
len(raw_images), len(jpeg_images_bare_names)))
sys.exit(0)
backup_folder = None if args.no_backup else os.path.join(args.folder,args.backup_folder)
delete([os.path.join(args.folder,orphan) for orphan in orphans], backup_folder=backup_folder, verbose=verbose)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment