Skip to content

Instantly share code, notes, and snippets.

@EdgeCaseBerg
Last active January 2, 2016 03:29
Show Gist options
  • Select an option

  • Save EdgeCaseBerg/8244172 to your computer and use it in GitHub Desktop.

Select an option

Save EdgeCaseBerg/8244172 to your computer and use it in GitHub Desktop.
Finding Image References in source trees Recursive search for image filenames within a src tree Example Use: python image-ref.py -i /home/user/pictures -s /home/user/website/httpdocs
#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
"""
Script to find image references
Authors
-------------------------------
- Ethan J. Eldridge [01/2014]
Looks through images directory to find list of files
and then searches the src tree for references to those
images.
Output's a list of images to stdout for piping purposes.
Output is in the format:
FILENAME PARENT_DIR WIDTHxHEIGHT [REF 1, REF 2, ...]
Options:
-h, --help
Lists basic help.
-i, --img-path= [default = ../web-app/images ]
Specify the directory to find images in. The image directory must only contain images
-s, --src-tree= [default = ../]
Specifies the directory to try to find image references in
-d, --defaults
Use defaults and override other options
--absolute [default = off]
Instead of using current working directory, the paths from img-path and src-tree
are assuming to be absolute.
--no-base [default = off, -d sets True ]
Makes all output for src-tree and images be relative to their base paths.
Is off unless -d is used or the switch is given
--ext-ignore=
Enter a list of extensions to ignore, seperated by commas, with no whitespace
inbetween each extension. The dot's at the beginning of an extension are optional
"""
def usage():
print """
images.py [OPTIONS]
-h, --help print this help
-i, --img-path=<Image directory to traverse>
-s, --src-tree=<Source Tree to find references in>
-d, --defaults Use default directory paths used in example below
--absolute Use absolute directory paths, defaults to False
--no-base Remove current working directory from path names in references
--ext-ignore=<csv list of extensions to ignore in src-tree>
Examples:
python images.py -i ../web-app/images -s ../
./images.py --absolute -i /home/user/images -s /home/user/program
./images.py -d --no-base
"""
import os, sys, getopt, sets
try:
opts, args = getopt.getopt(sys.argv[1:], "dhi:s:", ["help", "img-path=", "src-tree=", "absolute", "defaults", "no-base", "ext-ignore="])
except getopt.GetoptError:
usage()
sys.exit(2)
#Defaults:
images_path = "../web-app/images"
src_tree_path = "../"
base_path = os.getcwd()
remove_base = False
ignored_extensions = [".war", ".gzip", ".sql", ".pdf"]
#If you want additional rules for files, then place the beginnings of the image name here
special_names = ["fb", "facebook","bebo","myspace","google","instagram","twitter"]
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt in ("-i", "--img-path"):
images_path = arg
elif opt in ("-s", "--src-tree"):
src_tree_path = arg
elif opt in ("--absolute"):
base_path = "/"
elif opt in ("--no-base"):
remove_base = True
elif opt in ("-d", "--defaults"):
remove_base = True
images_path = "../web-app/images"
src_tree_path = "../"
base_path = os.getcwd()
elif opt in ("--ext-ignore"):
ie = arg.split(",")
new_ignores = []
for possible_ext in ie:
if possible_ext[0] == ".":
new_ignores.append(possible_ext)
else:
new_ignores.append(".%s" % possible_ext)
ignored_extensions = new_ignores
images_path = os.path.normpath( os.path.join(base_path, images_path) )
src_tree_path = os.path.normpath( os.path.join(base_path, src_tree_path) )
deprecated_image_path = os.path.join(images_path, "deprecated")
if not os.path.exists(images_path):
print "Image Path does not exist!"
if not os.path.exists(src_tree_path):
print "Src Tree Path does not exist!"
#Mind Edge case
if len(opts) == 0:
usage()
sys.exit()
#Thank you: http://stackoverflow.com/questions/15800704/python-get-image-size-without-loading-image-into-memory
#-------------------------------------------------------------------------------
# Name: get_image_size
# Purpose: extract image dimensions given a file path using just
# core modules
#
# Author: Paulo Scardine (based on code from Emmanuel VAÏSSE),
# Ethan Eldridge (ICO)
# Created: 26/09/2013
# Copyright: (c) Paulo Scardine 2013
# Licence: MIT
#-------------------------------------------------------------------------------
import struct
class UnknownImageFormat(Exception):
pass
def get_image_size(file_path):
"""
Return (width, height) for a given img file content - no external
dependencies except the os and struct modules from core
"""
size = os.path.getsize(file_path)
with open(file_path) as input:
height = -1
width = -1
data = input.read(25)
if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
# GIFs
w, h = struct.unpack("<HH", data[6:10])
width = int(w)
height = int(h)
elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
and (data[12:16] == 'IHDR')):
# PNGs
w, h = struct.unpack(">LL", data[16:24])
width = int(w)
height = int(h)
elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
# older PNGs?
w, h = struct.unpack(">LL", data[8:16])
width = int(w)
height = int(h)
elif (size >= 2) and data.startswith('\377\330'):
# JPEG
msg = " raised while trying to decode as JPEG."
input.seek(0)
input.read(2)
b = input.read(1)
try:
while (b and ord(b) != 0xDA):
while (ord(b) != 0xFF): b = input.read(1)
while (ord(b) == 0xFF): b = input.read(1)
if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
input.read(3)
h, w = struct.unpack(">HH", input.read(4))
break
else:
input.read(int(struct.unpack(">H", input.read(2))[0])-2)
b = input.read(1)
width = int(w)
height = int(h)
except struct.error:
raise UnknownImageFormat("StructError" + msg)
except ValueError:
raise UnknownImageFormat("ValueError" + msg)
except Exception as e:
raise UnknownImageFormat(e.__class__.__name__ + msg)
elif (file_path.endswith('.ico')):
#Adding ICO handling - EJE
#see http://en.wikipedia.org/wiki/ICO_(file_format)
input.seek(0)
reserved = input.read(2)
if 0 != struct.unpack("<H", reserved )[0]:
raise UnknownImageFormat("Corrupt ICON File")
format = input.read(2)
assert 1 == struct.unpack("<H", format)[0]
num = input.read(2)
num = struct.unpack("<H", num)[0]
if num > 1:
import warnings
warnings.warn("ICO File contains more than one image")
#http://msdn.microsoft.com/en-us/library/ms997538.aspx
w = input.read(1)
h = input.read(1)
width = ord(w)
height = ord(h)
else:
raise UnknownImageFormat(
"Sorry, don't know how to get information from %s." % file_path
)
return width, height
def remove_src_path(paths):
if remove_base:
nr = set()
for ref in paths:
nr.add( ref.replace(src_tree_path, "") )
return nr
return paths
def remove_img_path(path):
if remove_base:
path = path.replace(images_path, "")
if path == "":
path = "/"
return path
class ImageEntry:
def __init__(self, name, location):
self.name = name
self.parent = location
self.references = set()
def setSize(self, dimensions):
self.width = dimensions[0]
self.height = dimensions[1]
def addReference(self, ref):
self.references.add(ref)
def __str__(self):
references = remove_src_path(self.references)
location = remove_img_path(self.parent)
return "Name: %s, Parent: %s, Dims: %dx%d References: [%s]" % (self.name, location, self.width, self.height, ",".join(references) )
def __repr__(self):
references = remove_src_path(self.references)
location = remove_img_path(self.parent)
return "%s %s %dx%d [%s]" % (self.name, location, self.width, self.height, ",".join(references))
def rec_findImgs(path, imgs=set()):
"""
Fill the imgs array with information about the images
found within the path. (Recurses directories)
"""
dirs = os.listdir( path )
for f in dirs:
if os.path.isfile(os.path.join(path, f)):
img = ImageEntry(f, path)
img.setSize( get_image_size(os.path.join(path, f)) )
imgs.add( img )
if os.path.isdir(os.path.join(path, f)):
if not f.startswith('.') and not os.path.join(path,f).__contains__(deprecated_image_path): #ignore hidden and deprecated
imgs = rec_findImgs(os.path.join(path, f), imgs)
return imgs
images = rec_findImgs(images_path, set())
def in_ignored_extensions(file_path):
ext = os.path.splitext(file_path)[1]
return ext in ignored_extensions
import re
def rec_find_refs(path, search_expressions, refs=set()):
"""
Find references to the search string within the path (recursive)
"""
dirs = os.listdir( path )
for f in dirs:
if os.path.isfile(os.path.join(path, f)):
if not in_ignored_extensions(os.path.join(path,f)):
with open(os.path.join(path,f), "r" ) as tbsearched:
line_no = 0
for line in tbsearched:
line_no += 1
for regex in search_expressions:
if regex.findall(line, re.IGNORECASE):
refs.add("%s Line %d" %(os.path.join(path,f), line_no))
if os.path.isdir(os.path.join(path, f)):
if not f.startswith('.'): #ignore hidden
refs = rec_find_refs(os.path.join(path, f), search_expressions, refs)
return refs
#Make Unused Images directory if it doesn't not exists.
#Create at base of images directory
if os.path.exists(deprecated_image_path):
print "Using directory %s for deprecated images" % deprecated_image_path
else:
try:
os.mkdir(deprecated_image_path)
print "Using directory %s for deprecated images" % deprecated_image_path
except OSError,err:
print "Couldn't make deprecated directory %s" % err.strerror
sys.exit(1)
import errno
def get_mirrored_dirs_name(base, path ):
#Replace base with deprecated base
dirs_to_make = path.replace(base, deprecated_image_path)
return dirs_to_make
possible_dyn = re.compile("(%s)" % "|".join(['^{0}'.format(nn) for nn in special_names]) , re.IGNORECASE)
for img in images:
search_expressions = []
search_expressions.append( re.compile("%s" % img.name) )
#If The image seems to be a special name then add
#In a search for /images/$ followed by network somewhere
if possible_dyn.match(img.name):
search_expressions.append( re.compile("images\/\$.*network|platform", re.IGNORECASE ) )
img.references = rec_find_refs(src_tree_path, search_expressions, set())
if len(img.references) == 0:
#Move the unreferenced image to the deprecated folder
#if it doesn't exist there already
mir_dir = get_mirrored_dirs_name(images_path, img.parent)
if not os.path.exists(mir_dir):
try:
os.makedirs(mir_dir)
except OSError, err:
if err.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
if not os.path.exists(os.path.join(mir_dir, img.name)):
os.rename(os.path.join(img.parent, img.name), os.path.join(mir_dir, img.name))
else:
print img.__repr__()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment