#!/usr/bin/env python ################################################### # dotgenerator.py # # Copyright (C) 2002 Simon Budig. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. import random, sys from math import pi, sqrt, floor, sin, cos ################################################### # Bildobjekte (laden) class Image: def get_pixel (self, x, y): if x < 0 or y < 0 or x >= self.width or y >= self.height: return 0 return self.pixels [y * self.rowstride + x] def subsample (self, x, y): x0 = int (floor (x)) y0 = int (floor (y)) dx = x - x0 dy = y - y0 return ( (1-dx)*(1-dy)*self.get_pixel ( x0, y0) + dx *(1-dy)*self.get_pixel (x0+1, y0) + (1-dx)* dy *self.get_pixel ( x0, y0+1) + dx * dy *self.get_pixel (x0+1, y0+1) ) class PGMImage(Image): def __init__ (self, filename): f = open (filename).readlines () data = (' '.join ([i for i in f if i.strip()[0] != '#'])).split () if data[0] != 'P2': raise "Not an Ascii-PGM-Image" self.width = int (data[1]) self.height = int (data[2]) self.rowstride = self.width depth = float (data[3]) self.pixels = [1 - int(i)/depth for i in data[4:] ] class GradientImage(Image): def __init__ (self, width, height): self.width = width self.height = height self.rowstride = self.width self.pixels = [1 - float(i)/(width-1) for i in range (width) ] * height ################################################### # Bilder rausschreiben class ImageWriter: def __init__ (self, filename = None): self.x0 = 20 self.y0 = 822 self.width = 555 self.height = -802 if filename: self.file = open ("filename", "w") else: self.file = sys.stdout class PSWriter (ImageWriter): def header (self): self.file.write ("%!PS-Adobe-3.0\n" "\n" "0 setgray\n") def footer (self): self.file.write ("showpage\n") def rect (self, xc, yc, rx, ry, angle=45): angle = angle / 180.0 * pi self.file.write ("newpath\n" "%f %f moveto\n" "%f %f rlineto\n" "%f %f rlineto\n" "%f %f rlineto\n" "closepath\n" "fill\n" % (xc - rx * cos(angle) + ry * sin(angle), yc - rx * sin(angle) - ry * cos(angle), 2 * rx * cos(angle), 2 * rx * sin (angle), 2 * -ry * sin(angle), 2 * ry * cos (angle), - 2 * rx * cos(angle), - 2 * rx * sin (angle))) def ellipse (self, xc, yc, rx, ry, angle=45): self.file.write ("gsave\n" "%f %f translate\n" "%f rotate\n" "%f %f scale\n" "newpath\n" "0 0 1 0 360 arc\n" "closepath\n" "fill\n" "grestore\n" % (xc, yc, angle, rx, ry)) class SKWriter (ImageWriter): def header (self): self.file.write ("##Sketch 1 2\n" "document()\n" "layout('A4',0)\n" "layer('Layer 1',1,1,0,0,(0,0,0))\n" "guidelayer('Guide Lines',1,0,0,1,(0,0,1))\n" "grid((0,0,20,20),0,(0,0,1),'Grid')\n" "layer('Rasterlayer',1,1,0,0,(0,0,0))\n" "G()\n" ) def footer (self): self.file.write ("G_()\n") def rect (self, xc, yc, rx, ry, angle=45): angle = angle / 180.0 * pi self.file.write ("fp((0,0,0))\n" "le()\n" "lw(1)\n" "r(%f,%f,%f,%f,%f,%f)\n" % (2 * rx * cos(angle), 2 * rx * sin (angle), 2 * -ry * sin(angle), 2 * ry * cos (angle), xc - rx * cos(angle) + ry * sin(angle), yc - rx * sin(angle) - ry * cos(angle))) def ellipse (self, xc, yc, rx, ry, angle=45): angle = angle / 180.0 * pi self.file.write ("fp((0,0,0))\n" "le()\n" "lw(1)\n" "e(%f,%f,%f,%f,%f,%f)\n" % (rx * cos(angle), rx * sin (angle), -ry * sin(angle), ry * cos (angle), xc, yc)) ################################################### # verschiedene Punktanordnungen class Pattern: def __init__ (self, image, writer, pointfunc, dotscale=1): self.image = image self.writer = writer self.pointfunc = pointfunc self.dotscale = dotscale self.points = [] self.xratio = float (writer.width) / image.width self.yratio = float (writer.height) / image.height self.ratio = min (abs (self.xratio), abs (self.yratio)) self.xratio = self.xratio / abs (self.xratio) * self.ratio self.yratio = self.yratio / abs (self.yratio) * self.ratio self.offx = writer.x0 + (writer.width - image.width * self.xratio) / 2.0 self.offy = writer.y0 + (writer.height - image.height * self.yratio) / 2.0 def make (self, width=100, x0=0, y0=0): if not self.points: self.getpoints () self.writer.header () for point in self.points: transpoint = ( self.offx + point[0] * self.xratio, self.offy + point[1] * self.yratio, point[2] ) brightness = self.image.subsample (point[0], point[1]) if brightness >= 0.02: self.pointfunc (transpoint[0], transpoint[1], transpoint[2], brightness, self.ratio / 2.0 * self.dotscale, self.writer) self.writer.footer () class RectGrid (Pattern): def getpoints (self): self.points = [] for y in range (self.image.height): for x in range (self.image.width): self.points.append ((x, y, 0)) class HexGrid (Pattern): def getpoints (self): self.points = [] y = 0 count = 0 while round (y, 1) <= self.image.height: x = (count % 2) * 0.5 while round (x, 1) <= self.image.width: self.points.append ((x, y, 0)) x += 1 y += sqrt (0.75) count += 1 class CenterCircles (Pattern): def getpoints (self): self.points = [] x = float (self.image.width) / 2 y = float (self.image.height) / 2 self.points.append ((x, y, 0)) for r in range (1, 1 + int (sqrt (x*x + y*y))): for i in range (r*6): self.points.append ((x + r * sin (float (i) / (r * 6) * 2 * pi), y + r * cos (float (i) / (r * 6) * 2 * pi), float (i) / (r * 6) * 360)) ################################################### # verschiedene Punktformen def round_dots (x, y, angle, brightness, radius, writer): writer.ellipse (x, y, sqrt (brightness) * radius, sqrt (brightness) * radius, 0) def squares (x, y, angle, brightness, radius, writer): writer.rect (x, y, sqrt (brightness) * radius, sqrt (brightness) * radius, angle) def rotating_squares (x, y, angle, brightness, radius, writer): writer.rect (x, y, brightness * radius * sqrt (2), brightness * radius * sqrt (2), angle + brightness * 90) def random_ellipses (x, y, angle, brightness, radius, writer): writer.ellipse (x, y, 2 * radius - brightness**2 * radius * sqrt(2), 0.05 * radius + brightness**2 * radius * sqrt(2), random.random () * 180) ######################################## # Hauptprogramm if __name__ == '__main__': writer = PSWriter() image = PGMImage ("flower.pgm") # image = GradientImage (50,50) p = CenterCircles (image, writer, squares, 1.08) # p = HexGrid (image, writer, round_dots, 1 / cos (30.0 / 180 * pi)) # p = RectGrid (image, writer, round_dots, sqrt (2)) p.make ()