diff --git a/.gitignore b/.gitignore index 082a6f8..79d7f50 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ test/out +__pycache__ diff --git a/2bit.py b/2bit.py index b6c7ecb..aa33a26 100644 --- a/2bit.py +++ b/2bit.py @@ -6,6 +6,8 @@ dither = False # End of the configuration section import PIL.Image, sys, random +sys.path.append(".") +import libbar if len(sys.argv) >= 3: outfile = sys.argv[2] if len(sys.argv) >= 4: @@ -29,8 +31,14 @@ elif bits == 1: mode = "1" # 1x1 bit unsigned integer out = PIL.Image.new(mode,image.size) colors = [int(i*255.0/(2**bits-1)) for i in range(2**bits)] +bar = libbar.IncrementalBar(max = image.height * image.width) +bar.start() +i = 0 for x in range(image.width): for y in range(image.height): + i += 1 + bar.index = i + if i % 200 == 0: bar.update() pos = (x,y) color = image.getpixel(pos) if len(color) == 4: @@ -47,3 +55,4 @@ for x in range(image.width): color[z] = colors[index] out.putpixel(pos, tuple(color)) out.save(outfile) +bar.finish() diff --git a/libbar.py b/libbar.py new file mode 100644 index 0000000..effa764 --- /dev/null +++ b/libbar.py @@ -0,0 +1,161 @@ +# This is directly copy pasted from pip +# https://github.com/pypa/pip/blob/master/pip/_vendor/progress/bar.py +# I take no credit +# + + +# +from time import time +HIDE_CURSOR = '\x1b[?25l' +SHOW_CURSOR = '\x1b[?25h' +from collections import deque +class WritelnMixin(object): + hide_cursor = False + + def __init__(self, message=None, **kwargs): + super(WritelnMixin, self).__init__(**kwargs) + if message: + self.message = message + + if self.file.isatty() and self.hide_cursor: + print(HIDE_CURSOR, end='', file=self.file) + + def clearln(self): + if self.file.isatty(): + print('\r\x1b[K', end='', file=self.file) + + def writeln(self, line): + if self.file.isatty(): + self.clearln() + print(line, end='', file=self.file) + self.file.flush() + + def finish(self): + if self.file.isatty(): + print(file=self.file) + if self.hide_cursor: + print(SHOW_CURSOR, end='', file=self.file) +class Infinite(object): + import sys + file = sys.stderr + sma_window = 10 + + def __init__(self, *args, **kwargs): + self.index = 0 + self.start_ts = time() + self._ts = self.start_ts + self._dt = deque(maxlen=self.sma_window) + for key, val in kwargs.items(): + setattr(self, key, val) + + def __getitem__(self, key): + if key.startswith('_'): + return None + return getattr(self, key, None) + + @property + def avg(self): + return sum(self._dt) / len(self._dt) if self._dt else 0 + + @property + def elapsed(self): + return int(time() - self.start_ts) + + @property + def elapsed_td(self): + return timedelta(seconds=self.elapsed) + + def update(self): + pass + + def start(self): + pass + + def finish(self): + pass + + def next(self, n=1): + if n > 0: + now = time() + dt = (now - self._ts) / n + self._dt.append(dt) + self._ts = now + + self.index = self.index + n + self.update() + + def iter(self, it): + for x in it: + yield x + self.next() + self.finish() + +class Progress(Infinite): + def __init__(self, *args, **kwargs): + super(Progress, self).__init__(*args, **kwargs) + self.max = kwargs.get('max', 100) + + @property + def eta(self): + return int(ceil(self.avg * self.remaining)) + + @property + def eta_td(self): + return timedelta(seconds=self.eta) + + @property + def percent(self): + return self.progress * 100 + + @property + def progress(self): + return min(1, self.index / self.max) + + @property + def remaining(self): + return max(self.max - self.index, 0) + + def start(self): + self.update() + + def goto(self, index): + incr = index - self.index + self.next(incr) + + def iter(self, it): + try: + self.max = len(it) + except TypeError: + pass + + for x in it: + yield x + self.next() + self.finish() +class Bar(WritelnMixin, Progress): + width = 32 + message = '' + suffix = '%(index)d/%(max)d' + bar_prefix = ' |' + bar_suffix = '| ' + empty_fill = ' ' + fill = '#' + hide_cursor = True +class IncrementalBar(Bar): + phases = (u' ', u'▏', u'▎', u'▍', u'▌', u'▋', u'▊', u'▉', u'█') + + def update(self): + nphases = len(self.phases) + expanded_length = int(nphases * self.width * self.progress) + filled_length = int(self.width * self.progress) + empty_length = self.width - filled_length + phase = expanded_length - (filled_length * nphases) + + message = self.message % self + bar = self.phases[-1] * filled_length + current = self.phases[phase] if phase > 0 else '' + empty = self.empty_fill * max(0, empty_length - len(current)) + suffix = self.suffix % self + line = ''.join([message, self.bar_prefix, bar, current, empty, + self.bar_suffix, suffix]) + self.writeln(line)