maxmoriss
1/5/2016 - 10:19 PM

Script attempts to find images with equal dimensions and move it to another directory.

Script attempts to find images with equal dimensions and move it to another directory.

# -*- coding: utf-8 -*-
import os
import sys
from PIL import Image
from shutil import move
from stat import S_IWRITE
from argparse import ArgumentParser
from abc import ABCMeta, abstractmethod


class ProcessBase:
    """ Abstract base class for file processors.
    """
    __metaclass__ = ABCMeta
 
    def __init__(self):
        self.extensions = []
 
    @abstractmethod
    def processfile(self, filename):
        """ Abstract method which carries out the process on the specified file. 
        Returns True if successful, False otherwise.
        """
        pass
 
    def processdir(self, path):
        """ Recursively processes files in the specified directory matching
        the self.extensions list (case-insensitively).
        """
        filecount = 0 # Number of files successfully updated
 
        for root, dirs, files in os.walk(path):
            for file in files:
                # Check file extensions against allowed list
                lowercasefile = file.lower()
                matches = False
                for ext in self.extensions:
                    if lowercasefile.endswith('.' + ext):
                        matches = True
                        break
                if matches:
                    # File has eligible extension, so process
                    fullpath = os.path.join(root, file)
                    if self.processfile(fullpath):
                        filecount = filecount + 1
        return filecount


class ProcessImage(ProcessBase):
    """ Processor which attempts to find images with equal dimensions 
    and move it to another directory
    """
    def __init__(self, args):
        super(ProcessImage, self).__init__()
        self.extensions = ['jpg', 'jpeg', 'png']
        self.path = args.path

    def processfile(self, filename):
        # Skip read-only files
        if (not os.stat(filename)[0] & S_IWRITE):
            print 'Ignoring read-only file "%s"' % filename
            return False
        
        ok = False
        
        try:
            # Open the image
            with open(filename, 'rb') as file:
                img = Image.open(file)
        
                # Check that it's a supported format
                format = str(img.format)
                if format != 'PNG' and format != 'JPEG':
                    print 'Ignoring file "%s" with unsupported format %s' % \
                        (filename, format)
                    return False

                width, height = img.size
                if width == height:
                    destination = os.path.abspath(
                        os.path.join(self.path, 'thumbnails')
                    )
                    move(filename, destination)
                    # Successful
                    ok = True

        except Exception as e:
            sys.stderr.write('Failure whilst processing "%s": %s\n' % \
                (filename, str(e)))
        
        return ok
        

if __name__ == "__main__":
    # Argument parsing
    parser = ArgumentParser(description='Find images with equal dimensions')
    parser.add_argument(
        '--path',
         help='Directory name')
 
    args = parser.parse_args()
 
    # Construct processor requested mode
    processor = ProcessImage(args)
 
    # Run according to whether path is a file or a directory
    if os.path.isfile(args.path):
        sys.stderr.write('Supported directories only.\n')
        exit(1)
    elif os.path.isdir(args.path):
        filecount = processor.processdir(args.path)
        print '\nSuccessfully updated file count: %s' % str(filecount)
    else:
        sys.stderr.write('Invalid path "%s"\n' % args.path)
        exit(1)