1#!/usr/local/bin/python3.8
2#    crossstitch.py
3#    Copyright (C) 2003  Nathan Hurst
4#    Copyright (C) 2004  Paul Mateman
5#    Copyright (C) 2005  Cameron Morland
6#    Copyright (C) 2009  Robert Smies
7#
8#    This program is free software; you can redistribute it and/or modify
9#    it under the terms of the GNU General Public License as published by
10#    the Free Software Foundation; either version 2 of the License, or
11#    (at your option) any later version.
12#
13#    This program is distributed in the hope that it will be useful,
14#    but WITHOUT ANY WARRANTY; without even the implied warranty of
15#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16#    GNU General Public License for more details.
17#
18#    You should have received a copy of the GNU General Public License
19#    along with this program; if not, write to the Free Software
20#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
22#from pyx import *
23import os.path
24try:
25   import Image
26except:
27   import PIL.Image as Image
28import sys
29
30## our symbols:
31sym = "";
32sym += "/s0 { newpath moveto 0.3 neg 0.3 neg rmoveto 0.6 0 rlineto 0.6 neg 0.6 rlineto 0.6 0 rlineto 0.6 neg 0.6 neg rlineto stroke } bind def\n";## 0: blank
33sym += "/s1 { newpath 0.3 0 360 arc stroke } bind def\n";## 1: circle
34sym += "/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
35sym += "/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
36sym += "/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
37sym += "/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: =
38sym += "/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: +
39sym += "/s7 { newpath moveto 0.3 neg 0.3 neg rmoveto 0.6 0.6 rlineto stroke } bind def\n";## 7: slash
40sym += "/s8 { newpath moveto 0.3 0.3 neg rmoveto 0.6 neg 0.6 rlineto stroke } bind def\n";## 8: backslash
41sym += "/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
42sym += "/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: ||
43
44## 11-20: copies of 1-9, scaled by 0.5
45for i in range(11):
46   sym += "/s" + str(11+i)+ " { gsave translate 0.5 0.5 scale 0 0 s"+str(i)+" grestore } bind def\n";
47
48ns = 22;
49
50if len(sys.argv) != 2:
51    print "Usage: prog file.png"
52    exit(0)
53in_file = sys.argv[1]
54in_file_root,in_file_ext = os.path.splitext(in_file)
55im = Image.open(in_file)
56width,height = im.size
57
58transparency = -1
59try:
60    transparency = im.info["transparency"]
61except KeyError:
62    pass
63pal_type,pal_data = im.palette.getdata()
64if pal_type != "RGB":
65    print "Unable to deal with non-rgb palettes.  Please send me the picture."
66pal_data = map(ord,pal_data)
67
68##################################################
69#
70# compose legend for symbols <-> colour
71#
72##################################################
73
74psl = open(in_file_root+"-colour.eps", "w");
75psl.write("%!PS-Adobe-2.0 EPSF-1.2\n");
76psl.write("%%Creator: xs.py\n");
77psl.write("%%Pages: 1\n");
78psl.write("%%BoundingBox: 35.0 35.0 " + str(36*len(pal_data)/3 +37) + " 109\n");
79psl.write("%%EndComments\n\n");
80
81psl.write("%%EndProlog\n");
82psl.write("%%Page: 1 1\n");
83
84# provide our symbols as functions to the printer
85psl.write(sym);
86
87psl.write("1 setlinecap 1 setlinejoin\n"); # round ends to lines
88psl.write("36 36 translate\n");
89psl.write("36 36 scale\n");
90psl.write("1 18 div setlinewidth\n");
91
92x = 0;
93for i in range(len(pal_data)/3):
94    r,g,b = map(lambda a:a/255.,tuple(pal_data[i*3:i*3+3]))
95    psl.write(str(i) + " 0 moveto 1 0 rlineto 0 1 rlineto 1 neg 0 rlineto closepath stroke\n");
96    psl.write(str(i + 0.5) + " 0.5 s" + str(i) + "\n");
97    psl.write(str(i) + " 1 moveto 1 0 rlineto 0 1 rlineto 1 neg 0 rlineto closepath\n");
98    psl.write("gsave "+str(r)+" "+str(g)+" "+str(b)+" setrgbcolor fill grestore  stroke\n");
99
100psl.write("showpage\n");
101psl.write("%%EOF\n");
102psl.close();
103
104if (ns < len(pal_data)/3):
105   print "Warning: only have " + str(ns) + " colours, need " + str(len(pal_data)/3);
106
107# determine how much to scale the large picture. Make it fit on a
108# letter sized sheet of paper. It doesn't matter much, since we can
109# scale the eps file at will.
110if (height/10 > width/7.5) :
111   scale = 72 * 10 / height;
112else :
113   scale = 72 * 7.5 / width;
114
115thinline = 0.04;
116thickline = 0.12;
117
118psf = open(in_file_root+".eps", "w")
119psf.write("%!PS-Adobe-2.0 EPSF-1.2\n");
120psf.write("%%Creator: xs.py\n");
121psf.write("%%Pages: 1\n");
122psf.write("%%BoundingBox: 35.0 35.0 " +
123          str(scale*width+37) + " " + str(scale*height+37) + "\n");
124psf.write("%%EndComments\n\n");
125psf.write("%%EndProlog\n");
126psf.write("%%Page: 1 1\n");
127
128# provide our symbols as functions to the printer
129psf.write(sym);
130
131psf.write("\n");
132
133psf.write("1 setlinecap 1 setlinejoin\n");
134psf.write("36 36 translate\n");
135psf.write(str(scale) + " " + str(scale) + " scale\n");
136
137## display the vertical grid stripes
138psf.write("0 1 " + str(height) + "{ ");  # loop from 0 to height
139psf.write("dup ");                       # copy y value
140psf.write("10 mod 0 eq { ");             # if it's multipl of 10...
141psf.write(str(thickline) + " setlinewidth ");   # be thick.
142psf.write("}{ ");                        # otherwise...
143psf.write(str(thinline) + " setlinewidth ");    # be thin.
144psf.write("} ifelse ");
145psf.write("0 exch moveto " + str(width) + " 0 rlineto stroke ");
146psf.write("} for\n");
147
148## display the horizontal grid stripes
149psf.write("0 1 " + str(width) + "{ ");   # loop from 0 to width
150psf.write("dup ");                       # copy y value
151psf.write("10 mod 0 eq { ");             # if it's multipl of 10...
152psf.write(str(thickline) + " setlinewidth ");   # be thick.
153psf.write("}{ ");                        # otherwise...
154psf.write(str(thinline) + " setlinewidth "); # be thin.
155psf.write("} ifelse ");
156psf.write("0 moveto 0 " + str(height) + " rlineto stroke ");
157psf.write("} for\n");
158
159psf.write("0.1 setlinewidth\n");
160
161psf.write("gsave 0.5 0.5 translate\n");  # put marks at centre of squares
162
163## draws symbol for every pixel
164for y in range(height):
165   for x in range(width):
166      psf.write(str(x) + " " + str(y) + " s"
167                + (str(im.getpixel((x, height-y-1)) % ns)) + " ");
168   psf.write("\n");
169
170psf.write("grestore\n");
171psf.write("showpage\n");
172psf.write("%%EOF\n");
173psf.close();
174