From 473480fb4c407ffdb6f427f9292aa8366479258d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Thu, 22 Dec 2011 09:45:30 +1300 Subject: [PATCH] Initial commit of binvis. binvis uses space-filling curves to visualize binary files. This patch also flips some curves to make them work better with the unrolled binvis view. --- .gitignore | 1 + binvis | 137 ++++++++++++++++++++++++++++++++++++++++++++ scurve/progress.py | 10 +++- scurve/zigzag.py | 4 +- scurve/zorder.py | 2 + test/test_zorder.py | 8 +-- 6 files changed, 153 insertions(+), 9 deletions(-) create mode 100755 binvis diff --git a/.gitignore b/.gitignore index 4bca620..b81c12b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store build *.swp *.pyc diff --git a/binvis b/binvis new file mode 100755 index 0000000..bc3c83c --- /dev/null +++ b/binvis @@ -0,0 +1,137 @@ +#!/usr/bin/env python +import os.path, math, string +import scurve +from scurve import progress +import Image, ImageDraw + + +class CharHilbert: + def __init__(self, data): + self.data = data + self.csource = scurve.fromSize("hilbert", 3, 256**3) + self.step = len(self.csource)/float(256) + + def __len__(self): + return len(self.data) + + def point(self, x): + c = ord(self.data[x]) + return self.csource.point(int(c*self.step)) + + + +class CharClass: + def __init__(self, data): + self.data = data + + def __len__(self): + return len(self.data) + + def point(self, x): + c = ord(self.data[x]) + if c == 0: + return [0, 0, 0] + elif c == 255: + return [255, 255, 255] + elif chr(c) in string.printable: + return [55, 126, 184] + return [228, 26, 28] + + +def drawmap_unrolled(map, size, csource, name, prog): + prog.set_target((size**2)*4) + map = scurve.fromSize(map, 2, size**2) + c = Image.new("RGB", (size, size*4)) + cd = ImageDraw.Draw(c) + step = len(csource)/float(len(map)*4) + + sofar = 0 + for quad in range(4): + for i, p in enumerate(map): + off = (i + (quad * size**2)) + color = csource.point( + int(off * step) + ) + x, y = tuple(p) + cd.point( + (x, y + (size * quad)), + fill=tuple(color) + ) + if not sofar%100: + prog.tick(sofar) + sofar += 1 + c.save(name) + + +def drawmap_square(map, size, csource, name, prog): + prog.set_target((size**2)) + map = scurve.fromSize(map, 2, size**2) + c = Image.new("RGB", map.dimensions()) + cd = ImageDraw.Draw(c) + step = len(csource)/float(len(map)) + for i, p in enumerate(map): + color = csource.point(int(i*step)) + cd.point(tuple(p), fill=tuple(color)) + if not i%100: + prog.tick(i) + c.save(name) + + +def main(): + from optparse import OptionParser, OptionGroup + parser = OptionParser( + usage = "%prog [options] infile output", + version="%prog 0.1", + ) + parser.add_option( + "-c", "--color", action="store", + type="choice", dest="color", default="class", + choices=["class", "hilbert"] + ) + parser.add_option( + "-m", "--map", action="store", + type="str", dest="map", default="hilbert" + ) + parser.add_option( + "-s", "--size", action="store", + type="int", dest="size", default=None + ) + parser.add_option( + "-t", "--type", type="choice", + dest="type", default="unrolled", + choices=["unrolled", "square"] + ) + parser.add_option( + "-q", "--quiet", action="store_true", + dest="quiet", default=False + ) + options, args = parser.parse_args() + if len(args) != 2: + parser.error("Please specify input and output file.") + + d = file(args[0]).read() + if options.size: + size = options.size + else: + size = int(math.ceil(math.sqrt(len(d)))) + + if options.color == "class": + csource = CharClass(d) + else: + csource = CharHilbert(d) + + if options.quiet: + prog = progress.Dummy() + else: + prog = progress.Progress(None) + + if options.type == "unrolled": + drawmap_unrolled(options.map, size, csource, args[1], prog) + elif options.type == "square": + drawmap_square(options.map, size, csource, args[1], prog) + prog.clear() + + + +main() + diff --git a/scurve/progress.py b/scurve/progress.py index a808596..06f8d6e 100644 --- a/scurve/progress.py +++ b/scurve/progress.py @@ -35,10 +35,10 @@ class Progress(Inplace): def __init__(self, target, title="", width=40, stream=sys.stderr): Inplace.__init__(self, title, stream=stream) self.width, self.target = width, target - self.prev = -1 + self.prev = -1 self.startTime = None self.window = None - + def tick(self, val): if not self.stream: return @@ -65,6 +65,9 @@ def tick(self, val): ) Inplace.tick(self, s) + def set_target(self, t): + self.target = t + def restoreTerm(self): if self.window: #begin nocover @@ -86,9 +89,10 @@ def full(self): class Dummy: - def __init__(self, *args, **kwargs): pass + def __init__(self, *args, **kwargs): pass def tick(self, *args, **kwargs): pass def restoreTerm(self, *args, **kwargs): pass def clear(self, *args, **kwargs): pass def full(self, *args, **kwargs): pass + def set_target(self, *args, **kwargs): pass diff --git a/scurve/zigzag.py b/scurve/zigzag.py index 617839e..f2841fe 100644 --- a/scurve/zigzag.py +++ b/scurve/zigzag.py @@ -40,7 +40,7 @@ def dimensions(self): def index(self, p): idx = 0 flip = False - for power, i in enumerate(p): + for power, i in enumerate(reversed(list(p))): power = self.dimension-power-1 if flip: fi = self.size-i-1 @@ -64,4 +64,4 @@ def point(self, idx): p.append(v) if v%2: flip = not flip - return p + return reversed(p) diff --git a/scurve/zorder.py b/scurve/zorder.py index 0cb42d9..7c76225 100644 --- a/scurve/zorder.py +++ b/scurve/zorder.py @@ -40,6 +40,7 @@ def dimensions(self): return [2**self.bits]*self.dimension def index(self, p): + p.reverse() idx = 0 iwidth = self.bits * self.dimension for i in range(iwidth): @@ -55,4 +56,5 @@ def point(self, idx): for i in range(iwidth): b = utils.bitrange(idx, iwidth, i, i+1) << (iwidth-i-1)/self.dimension p[i%self.dimension] |= b + p.reverse() return p diff --git a/test/test_zorder.py b/test/test_zorder.py index b7e0e7e..ee2b3b5 100644 --- a/test/test_zorder.py +++ b/test/test_zorder.py @@ -10,12 +10,12 @@ def test_dimensions(self): def test_point(self): z = zorder.ZOrder(2, 2) - assert z.point(utils.bits2int([0, 1, 0, 1])) == [0, 3] + assert z.point(utils.bits2int([0, 1, 0, 1])) == [3, 0] assert z.point(utils.bits2int([0, 0, 0, 0])) == [0, 0] - assert z.point(utils.bits2int([1, 0, 0, 0])) == [2, 0] - assert z.point(utils.bits2int([1, 0, 1, 0])) == [3, 0] + assert z.point(utils.bits2int([1, 0, 0, 0])) == [0, 2] + assert z.point(utils.bits2int([1, 0, 1, 0])) == [0, 3] assert z.point(utils.bits2int([1, 1, 1, 1])) == [3, 3] - + z = zorder.ZOrder(2, 3) assert z.point(utils.bits2int([1, 1, 1, 1, 1, 1])) == [7, 7]