from collections import namedtuple class Pixel(namedtuple('Pixel', ['r', 'g', 'b'])): def _verify(self): if max(self.r, self.g, self.b) > 255: raise ValueError('Some component too bright.') if min(self.r, self.g, self.b) < 0: raise ValueError('Some component negative.') def _to_valid(self): return Pixel( int(max(0, min(255, self.r))), int(max(0, min(255, self.g))), int(max(0, min(255, self.b))), ) def __add__(self, other): return Pixel( self.r + other.r, self.g + other.g, self.b + other.b, ) def __mul__(self, other): if not isinstance(other, int) and not isinstance(other, float): raise ValueError('Can only multiply by number') return Pixel( other*self.r, other*self.g, other*self.b, ) def weighted_average(p1, w1, p2, w2): too_big = w1*p1 + w2*p2 coef = 1/(w1+w2) return coef * too_big class Picture: def __init__(self, data): self.pixels = data self.w = len(data[0]) self.h = len(data) @classmethod def load(cls, filename): from PIL import Image im = Image.open(filename) im = im.convert('RGB') ht = im.height wt = im.width data = [] access = im.getdata().pixel_access() for y in range(ht): line = [] for x in range(wt): line.append(Pixel(*(access[x, y]))) data.append(line) result = cls(data) assert result.w == wt assert result.h == ht return result def at(self, x, y): return self.pixels[ int(max(0, min(self.h - 1, y))) ][ int(max(0, min(self.w - 1, x))) ] def _to_pil(self): # Create int iterable # TODO: If this is slow, we should use a generator. seq = [] for line in self.pixels: for pix in line: seq.extend(pix._to_valid()) # bytes… b = bytes(seq) # PIL image from PIL import Image img = Image.frombytes('RGB', (self.w, self.h), b) return img def show(self): img = self._to_pil() img.show() def save(self, filename): img = self._to_pil() img.save(filename) class Interpolator: def interpolate(self, picture, new_h, new_w): quantum_x = picture.w / new_w quantum_y = picture.h / new_h result = [[None for _ in range(new_w)] for _ in range(new_h)] for x in range(new_w): for y in range(new_h): result[y][x] = self.get_pixel(picture, x*quantum_x, y*quantum_y, result, quantum_x, quantum_y) return Picture(result) def get_pixel(self, picture, x, y, result, quantum_x, quantum_y): raise NotImplementedError('You write this :-)')