diff --git a/overviewer_core/optimizeimages.py b/overviewer_core/optimizeimages.py index 174121a..69292e1 100644 --- a/overviewer_core/optimizeimages.py +++ b/overviewer_core/optimizeimages.py @@ -18,6 +18,7 @@ import subprocess import shlex import logging + class Optimizer: binaryname = "" binarynames = [] @@ -27,15 +28,16 @@ class Optimizer: def optimize(self, img): raise NotImplementedError("I can't let you do that, Dave.") - + def fire_and_forget(self, args): subprocess.check_call(args) def check_availability(self): path = os.environ.get("PATH").split(os.pathsep) - + def exists_in_path(prog): - result = filter(lambda x: os.path.exists(os.path.join(x, prog)), path) + result = filter(lambda x: os.path.exists(os.path.join(x, prog)), + path) return len(result) != 0 binaries = self.binarynames + [x + ".exe" for x in self.binarynames] @@ -44,12 +46,15 @@ class Optimizer: self.binaryname = b break else: - raise Exception("Optimization programs '%s' were not found!" % binaries) - + raise Exception("Optimization programs '%s' were not found!" % + binaries) + def is_crusher(self): - """Should return True if the optimization is lossless, i.e. none of the actual image data will be changed.""" - raise NotImplementedError("I'm so abstract I can't even say whether I'm a crusher.") - + """Should return True if the optimization is lossless, i.e. none of the + actual image data will be changed.""" + raise NotImplementedError("I'm so abstract I can't even say whether " + "I'm a crusher.") + class NonAtomicOptimizer(Optimizer): def cleanup(self, img): @@ -60,34 +65,37 @@ class NonAtomicOptimizer(Optimizer): subprocess.check_call(args) self.cleanup(img) + class PNGOptimizer: def __init__(self): raise NotImplementedError("I can't let you do that, Dave.") + class JPEGOptimizer: def __init__(self): raise NotImplementedError("I can't let you do that, Dave.") + class pngnq(NonAtomicOptimizer, PNGOptimizer): binarynames = ["pngnq-s9", "pngnq"] def __init__(self, sampling=3, dither="n"): if sampling < 1 or sampling > 10: - raise Exception("Invalid sampling value '%d' for pngnq!" % sampling) - + raise Exception("Invalid sampling value '%d' for pngnq!" % + sampling) if dither not in ["n", "f"]: raise Exception("Invalid dither method '%s' for pngnq!" % dither) - self.sampling = sampling self.dither = dither - + def optimize(self, img): if img.endswith(".tmp"): extension = ".tmp" else: extension = ".png.tmp" - args = [self.binaryname, "-s", str(self.sampling), "-f", "-e", extension, img] + args = [self.binaryname, "-s", str(self.sampling), "-f", "-e", + extension, img] # Workaround for poopbuntu 12.04 which ships an old broken pngnq if self.dither != "n": args.insert(1, "-Q") @@ -98,16 +106,18 @@ class pngnq(NonAtomicOptimizer, PNGOptimizer): def is_crusher(self): return False + class pngcrush(NonAtomicOptimizer, PNGOptimizer): binarynames = ["pngcrush"] + # really can't be bothered to add some interface for all # the pngcrush options, it sucks anyway def __init__(self, brute=False): self.brute = brute - + def optimize(self, img): args = [self.binaryname, img, img + ".tmp"] - if self.brute == True: # Was the user an idiot? + if self.brute: # Was the user an idiot? args.insert(1, "-brute") NonAtomicOptimizer.fire_and_forget(self, args, img) @@ -115,18 +125,21 @@ class pngcrush(NonAtomicOptimizer, PNGOptimizer): def is_crusher(self): return True + class optipng(Optimizer, PNGOptimizer): binarynames = ["optipng"] def __init__(self, olevel=2): self.olevel = olevel - + def optimize(self, img): - Optimizer.fire_and_forget(self, [self.binaryname, "-o" + str(self.olevel), "-quiet", img]) + Optimizer.fire_and_forget(self, [self.binaryname, "-o" + + str(self.olevel), "-quiet", img]) def is_crusher(self): return True + class advpng(Optimizer, PNGOptimizer): binarynames = ["advpng"] crusher = True @@ -135,21 +148,24 @@ class advpng(Optimizer, PNGOptimizer): self.olevel = olevel def optimize(self, img): - Optimizer.fire_and_forget(self, [self.binaryname, "-z" + str(self.olevel), "-q", img]) + Optimizer.fire_and_forget(self, [self.binaryname, "-z" + + str(self.olevel), "-q", img]) def is_crusher(self): return True + class jpegoptim(Optimizer, JPEGOptimizer): binarynames = ["jpegoptim"] crusher = True quality = None target_size = None - def __init__(self, quality = None, target_size = None): + def __init__(self, quality=None, target_size=None): if quality is not None: if quality < 0 or quality > 100: - raise Exception("Invalid target quality %d for jpegoptim" % quality) + raise Exception("Invalid target quality %d for jpegoptim" % + quality) self.quality = quality if target_size is not None: @@ -175,7 +191,6 @@ class jpegoptim(Optimizer, JPEGOptimizer): else: return True - def optimize_image(imgpath, imgformat, optimizers): for opt in optimizers: