#!/usr/bin/env python # crossstitch.py # Copyright (C) 2003 Nathan Hurst # Copyright (C) 2004 Paul Mateman # Copyright (C) 2005 Cameron Morland # # 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. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #from pyx import * import os.path import Image import sys ## our symbols: sym = ""; sym += "/s0 {} bind def\n";## 0: blank sym += "/s1 { newpath 0.3 0 360 arc stroke } bind def\n";## 1: circle sym += "/s2 { newpath moveto 0.3 neg 0.3 neg rmoveto 0.6 0 rlineto 0 0.6 rlineto 0.6 neg 0 rlineto closepath stroke } bind def\n";## 2: square sym += "/s3 { newpath moveto 0.22 neg 0 rmoveto 0.45 0.26 rlineto 0 0.52 neg rlineto closepath stroke } bind def\n";## 3: ltriangle sym += "/s4 { newpath moveto 0.22 0 rmoveto 0.45 neg 0.26 rlineto 0 0.52 neg rlineto closepath stroke } bind def\n";## 4: rtriangle sym += "/s5 { newpath moveto 0.3 neg 0.2 rmoveto 0.6 0 rlineto 0 0.4 neg rmoveto 0.6 neg 0 rlineto stroke } bind def\n";## 5: = sym += "/s6 { newpath moveto 0.3 neg 0 rmoveto 0.6 0 rlineto 0.3 neg 0.3 neg rmoveto 0 0.6 rlineto stroke } bind def\n";## 6: + sym += "/s7 { newpath moveto 0.3 neg 0.3 neg rmoveto 0.6 0.6 rlineto stroke } bind def\n";## 7: slash sym += "/s8 { newpath moveto 0.3 0.3 neg rmoveto 0.6 neg 0.6 rlineto stroke } bind def\n";## 8: backslash sym += "/s9 { newpath moveto 0.3 neg 0.3 neg rmoveto 0.6 0.6 rlineto 0 0.6 neg rmoveto 0.6 neg 0.6 rlineto stroke } bind def\n";## 9: X sym += "/s10 { newpath moveto 0.2 neg 0.3 rmoveto 0 0.6 neg rlineto 0.4 0 rmoveto 0 0.6 rlineto stroke } bind def\n";## 10: || ## 11-20: copies of 1-9, scaled by 0.5 for i in range(10): sym += "/s" + str(11+i)+ " { gsave translate 0.5 0.5 scale 0 0 s"+str(i+1)+" grestore } bind def\n"; ns = 20; if len(sys.argv) != 2: print "Usage: prog file.png" assert(0) in_file = sys.argv[1] in_file_root,in_file_ext = os.path.splitext(in_file) im = Image.open(in_file) width,height = im.size transparency = -1 try: transparency = im.info["transparency"] except KeyError: pass pal_type,pal_data = im.palette.getdata() if pal_type != "RGB": print "Unable to deal with non-rgb palettes. Please send me the picture." pal_data = map(ord,pal_data) ################################################## # # compose legend for symbols <-> colour # ################################################## psl = open(in_file_root+"-colour.eps", "w"); psl.write("%!PS-Adobe-2.0 EPSF-1.2\n"); psl.write("%%Creator: xs.py\n"); psl.write("%%Pages: 1\n"); psl.write("%%BoundingBox: 35.0 35.0 " + str(36*len(pal_data)/3 +37) + " 109\n"); psl.write("%%EndComments\n\n"); psl.write("%%EndProlog\n"); psl.write("%%Page: 1 1\n"); # provide our symbols as functions to the printer psl.write(sym); psl.write("1 setlinecap 1 setlinejoin\n"); # round ends to lines psl.write("36 36 translate\n"); psl.write("36 36 scale\n"); psl.write("1 18 div setlinewidth\n"); x = 0; for i in range(len(pal_data)/3): r,g,b = map(lambda a:a/255.,tuple(pal_data[i*3:i*3+3])) psl.write(str(i) + " 0 moveto 1 0 rlineto 0 1 rlineto 1 neg 0 rlineto closepath stroke\n"); psl.write(str(i + 0.5) + " 0.5 s" + str(i) + "\n"); psl.write(str(i) + " 1 moveto 1 0 rlineto 0 1 rlineto 1 neg 0 rlineto closepath\n"); psl.write("gsave "+str(r)+" "+str(g)+" "+str(b)+" setrgbcolor fill grestore stroke\n"); psl.write("showpage\n"); psl.write("%%EOF\n"); psl.close(); if (ns < len(pal_data)/3): print "Warning: only have " + str(ns) + " colours, need " + str(len(pal_data)/3); # determine how much to scale the large picture. Make it fit on a # letter sized sheet of paper. It doesn't matter much, since we can # scale the eps file at will. if (height/10 > width/7.5) : scale = 72 * 10 / height; else : scale = 72 * 7.5 / width; thinline = 0.04; thickline = 0.12; psf = open(in_file_root+".eps", "w") psf.write("%!PS-Adobe-2.0 EPSF-1.2\n"); psf.write("%%Creator: xs.py\n"); psf.write("%%Pages: 1\n"); psf.write("%%BoundingBox: 35.0 35.0 " + str(scale*width+37) + " " + str(scale*height+37) + "\n"); psf.write("%%EndComments\n\n"); psf.write("%%EndProlog\n"); psf.write("%%Page: 1 1\n"); # provide our symbols as functions to the printer psf.write(sym); psf.write("\n"); psf.write("1 setlinecap 1 setlinejoin\n"); psf.write("36 36 translate\n"); psf.write(str(scale) + " " + str(scale) + " scale\n"); ## display the vertical grid stripes psf.write("0 1 " + str(height) + "{ "); # loop from 0 to height psf.write("dup "); # copy y value psf.write("10 mod 0 eq { "); # if it's multipl of 10... psf.write(str(thickline) + " setlinewidth "); # be thick. psf.write("}{ "); # otherwise... psf.write(str(thinline) + " setlinewidth "); # be thin. psf.write("} ifelse "); psf.write("0 exch moveto " + str(width) + " 0 rlineto stroke "); psf.write("} for\n"); ## display the horizontal grid stripes psf.write("0 1 " + str(width) + "{ "); # loop from 0 to width psf.write("dup "); # copy y value psf.write("10 mod 0 eq { "); # if it's multipl of 10... psf.write(str(thickline) + " setlinewidth "); # be thick. psf.write("}{ "); # otherwise... psf.write(str(thinline) + " setlinewidth "); # be thin. psf.write("} ifelse "); psf.write("0 moveto 0 " + str(height) + " rlineto stroke "); psf.write("} for\n"); psf.write("0.1 setlinewidth\n"); psf.write("gsave 0.5 0.5 translate\n"); # put marks at centre of squares ## draws symbol for every pixel for y in range(height): for x in range(width): psf.write(str(x) + " " + str(y) + " s" + (str(im.getpixel((x, height-y-1)) % ns)) + " "); psf.write("\n"); psf.write("grestore\n"); psf.write("showpage\n"); psf.write("%%EOF\n"); psf.close();