This script uses the Python Imaging libraries to resize images in a folder and its sub-folders iteratively. The details like the directory hierarchy, current progress etc are displayed dynamically. We can optionally specify more image formats, required size etc.(See command-line argument --help). This is meant for processing large collections of images, which justifies the display of many details.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #!/usr/bin/env python
from os import *
import sys
try:
from PIL import Image
except ImportError:
print "Python image libraries not found!"
sys.exit()
# Default options
size=1024,9000
extlist=['.jpg', '.jpeg']
directory=getcwd()
getchild=False
def resize(folder, level=0):
"Does the actual image scaling action"
tick = unichr(0x2714).encode("utf-8")
dot= unichr(0x2726).encode("utf-8")
unitSegment=5 #The basic unit in the loading bar
linesPerP=1.0/unitSegment
if path.isdir(folder):
imageQue=[item for item in listdir(folder) if path.splitext(item.lower())[1] in extlist]
total=len(imageQue)
folderData=dot+' '+ folder.split(sep)[-1]
done=0
maxImageName=0 #resets to previous image name's length everytime(to clear the exact length)
for image in imageQue:
maxImageName= max(maxImageName, len(image))
percentage= int(float(done)/total*100)
#the dynamic loading bar data
sys.stdout.write( "\r{indent}{fold} [{imgno}] [{bar}] {per}% {img}".format(
indent=' '+' '*level,
fold=folderData,
imgno=str(total)+' images',
bar=('='*int(percentage*linesPerP)).ljust(int(100*linesPerP)),
per=percentage,
img= image.ljust(maxImageName) ))
sys.stdout.flush()
#the resizing process
maxImageName=len(image)
image=path.join(folder,image)
im=Image.open(image)
im.thumbnail(size, Image.ANTIALIAS)
im.save(image, im.format)
done+=1
#the completed loading bar data
sys.stdout.write( "\r{indent}{fold} [{imgno}] [{alldone}] {clear}\n".format(
indent=' '+' '*level,
fold=folderData,
alldone=tick,
imgno=str(total)+' images',
clear=' '*(6+maxImageName+int(100*linesPerP)) ))
#attacking sub directories!
if getchild:
for subfolder in listdir(folder):
resize(folder+sep+subfolder,level+5)
def invalidArgs():
print "Invalid arguments!"
sys.exit()
def parseArgs():
"Analyse the commandline parameters; Calls resize function if things are okay "
arglist=['-d','-o','-e','-c'] # -c is alone (no additional data); others work in pairs
global size
global extlist
global directory
global getchild
if '--help' in sys.argv or '--start' not in sys.argv: # --help is the show stopper :)
print """
Usage: imageresize --start [options]
Scale images to given size
* Default directory is current directory (includes subdirectories)
* Default resize option is '1024'
(scale width of image if it exceeds 1024px; retain aspect ratio)
* Default extensions are jpg, jpeg (not case-sensitive)
* Overwrites original image
Parameters:
--start begins the process
-d <path> <path> is the path to the required directory
-o '<option>' <option> can be of the following formats
'100' : scale width of image to 100px
'x60' : scale height of image to 60px
'100x60' : scale image within given bounds
(aspect ratio preserved)
-e <ext1>,<ext2>... <extn> is any valid extension (.png, .gif)
-c Scale images in sub-folders
--help Displays this help
"""
else:
sys.argv.remove('--start')
l=len(sys.argv)
i=1
while i<l:
arg=sys.argv[i]
if arg in arglist:
if arg=='-c': # -c is alone
getchild=True
i+=1
continue
elif i+1<l:
data=sys.argv[i+1]
if data in arglist or data==None:
invalidArgs() #only pairs; no odd args after -c!
elif arg=='-d':
if not path.exists(data):
print "Directory does not exist"
invalidArgs()
directory=data
elif arg=='-o':
validOptionChars=[str(letter) for letter in range(0,10)]
validOptionChars.extend(['x'])
for letter in data: #validating option string
if letter not in validOptionChars:
invalidArgs()
if 'x' in data.replace('x',''):
invalidArgs()
dim=data.split('x')
if data.startswith('x'): #scale height
height=int(dim[0])
size=height*9,height
elif 'x' not in data: #scale width
width=int(dim[0])
size=width,width*9
else: #scale to fit bounding box
size=int(dim[0]),int(dim[1])
else:
extlist.extend(data.lower().split(","))
i+=2 #Done with the pair, move on
else:
invalidArgs() #Expected data not found
else: #if a stranger is present in positions where args are expected
invalidArgs()
resize(directory) #Okies!
parseArgs() #So lets get started
|
This script came out of a need to optimize my huge image collection. Most of the digital camera images have dimensions like 4000x3200 and a size around 3MB. But we rarely need all those images in big sizes. Usually they only require dimensions that fits our desktop size. When we resize an image of 4000x3200 to fit 1024x768, the storage size is considerably reduced. This can save a lot of space when the processing is done for big collections, except those special images u want to be in the best size. This can be especially useful if you're troubled with lack of space in the hard drive. Since the whole image resizing process can take up lot of time, its desirable that the details be printed along. That is what exactly the script does!
More flexibility can be obtained if we use the script with ImageMagick program, using ImageMagick commands to resize image. This also obtains better quality images. This code can be obtained here
Commandline arguments are as follows: Scale images to given size * Default directory is current directory (includes subdirectories) * Default resize option is '1024' (scale width of image if it exceeds 1024px; retain aspect ratio) * Default extensions are jpg, jpeg (not case-sensitive) * Overwrites original image
Parameters:
--start begin the process
-d <path> <path> is the path to the required directory
-o '<option>' <option> can be of the following formats
'100' : scale width of image to 100px
'x60' : scale height of image to 60px
'100x60' : scale image within given bounds
(aspect ratio preserved)
-e <ext1>,<ext2>... <extn> is any valid extension (.png, .gif)
-c Scale images in sub-folders
--help Displays this help
Recipe will be nicer if there was no percent gauge and arguments parsed in standard way (optparse).
str.format() unavailable in my Python 2.4.5, please specify your version.
when running without parameters on Python 2.6 script started doing something in my directory. Its dangerous! When started without parameters script should write usage message instead of doing something dark with images from my disk!!
there was no code for triming apostrophe signs from -o parameters, so usage message are inconsistent.
@ Denis
I need to add many extra lines of code to make optparse print multiline help messages correctly. So I settled with the custom fewer lines of code.
I coded it using Python 2.6
The script now requires a --start argument for starting the action. Also, limited the processing of images in sub-folders by default.
The -o parameters, with or without apostrophe is received as strings. Hence it works correctly i think.
Thanks for the feedback!