/[cvs]/fract/mandelzoom.cgi
ViewVC logotype

Contents of /fract/mandelzoom.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Tue Jun 19 22:27:27 2001 UTC (22 years, 10 months ago) by teddy
Branch: MAIN
Changes since 1.8: +14 -2 lines
Time out and show the image after 55 seconds even if we're not done
with drawing it.  This is better than letting the web server time out
and show nothing at all.

1 #!/usr/bin/python
2
3 import cgi, Image, ImageDraw, sys, math, signal, errno, os
4 from string import atoi, atof
5
6 def handler(signum, frame):
7 raise os.error, (errno.ETIME, "Timer expired")
8
9 signal.alarm(55)
10 signal.signal(signal.SIGALRM, handler)
11
12 # This is to get backtrace output
13 sys.stderr = sys.stdout
14
15 # Uncomment this to get the backtrace more readable
16 #print "Content-Type: text/plain"
17 #print ""
18
19 form= cgi.FieldStorage()
20
21 # Image size
22 if form.has_key('width'):
23 width= atoi(form['width'].value)
24 else:
25 width= 480
26 if form.has_key('height'):
27 height= atoi(form['height'].value)
28 else:
29 height= 480
30
31 xmax, ymax = width-1, height-1 # Coordinate maximums
32
33 # Complex number in center of image is (cx+cy*j)
34 if form.has_key('cx'):
35 cx= atof(form['cx'].value)
36 else:
37 cx= 0.0
38
39 if form.has_key('cy'):
40 cy= atof(form['cy'].value)
41 else:
42 cy= 0.0
43
44 if form.has_key('diag'):
45 diag= atof(form['diag'].value)
46 else:
47 diag= math.sqrt(32) # sqrt(4**2 + 4**2)
48
49 debug= form.has_key('debug')
50
51 if form.has_key('iter'):
52 maxiter= atoi(form['iter'].value)
53 else:
54 maxiter= 270
55
56 # If type!=image, then output an HTML page, not an image
57 if not (form.has_key('type') and form['type'].value == "image"):
58 print """Content-Type: text/html
59
60 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
61 <HTML><HEAD>
62 <TITLE>Mandelbrot Set Zoomer</TITLE>
63 </HEAD>
64 <BODY>
65 <H1>Mandelbrot Set Zoomer</H1>
66
67 <FORM ACTION="mandelzoom.cgi" METHOD=GET>
68
69 <!-- implies TYPE=SUBMIT -->"""
70 print '<INPUT TYPE=IMAGE NAME="image"',
71 print 'WIDTH="%s"' % (str(width)),
72 print 'HEIGHT="%s"' % (str(height)),
73 if debug:
74 ds="&debug=on"
75 else:
76 ds=""
77 if form.has_key('image.x') and form.has_key('image.y'):
78 # Adjust cx and cy
79 ix= atof(form['image.x'].value)
80 iy= atof(form['image.y'].value)
81 owidth= atof(form['owidth'].value)
82 oheight= atof(form['oheight'].value)
83 diagp= math.sqrt(owidth**2 + oheight**2)
84 scale= diagp/diag
85 cx= (ix/scale) + (cx - (owidth / (scale*2)))
86 cy= ((oheight-iy)/scale) + (cy - (oheight / (scale*2)))
87 if form.has_key('zoom'):
88 zoom=atof(form['zoom'].value)
89 diag=diag/zoom
90 else:
91 # If no zoom provided, don't actually zoom
92 zoom= 2.0
93 print 'SRC="mandelzoom.cgi?type=image&width=%s&height=%s&iter=%s%s&diag=%s&cx=%s&cy=%s"' % (str(width), str(height), str(maxiter), ds, str(diag), str(cx), str(cy)),
94 print 'ALIGN=BOTTOM HEIGHT="%s"' % (str(height)),
95 print 'WIDTH="%s"><P>' % (str(width))
96 print 'Zoom: <SELECT NAME="zoom">'
97 for zv in [1.0/5, 1.0/3, 1.0/2, 1.0/1.5, 1.0, 1.5, 2.0, 3.0, 5.0]:
98 print '<OPTION',
99 if str(zv)==str(zoom):
100 print 'SELECTED',
101 print 'VALUE="%s"' % (str(zv))
102 if zv == 1:
103 print '>Pan'
104 elif zv < 1:
105 print '>Out ÷%s' % (str(1/zv))
106 else:
107 print '>In ×%s' % (str(zv))
108 print '</SELECT>'
109 print """Width: <INPUT TYPE=TEXT NAME="width" MAXLENGTH="4" SIZE="3"
110 VALUE="%s">
111 Height: <INPUT TYPE=TEXT NAME="height" MAXLENGTH="4" SIZE="3"
112 VALUE="%s">
113 Iterations: <INPUT TYPE=TEXT NAME="iter" MAXLENGTH="4" SIZE="3"
114 VALUE="%s">
115 Debug mode: <INPUT TYPE=CHECKBOX NAME="debug" """ % (str(width), str(height), str(maxiter)),
116 if debug:
117 print 'CHECKED>'
118 else:
119 print '>'
120 print '<INPUT TYPE=SUBMIT VALUE="Apply">'
121 for var in (("diag", diag), ("cx", cx), ("cy", cy), ("owidth", width),
122 ("oheight", height)):
123 print '<INPUT TYPE=HIDDEN NAME="%s" VALUE="%s">' % var
124 print '<INPUT TYPE=HIDDEN NAME=type VALUE="html">'
125
126 print """</FORM><P>
127 After changing any settings, don't forget to change the "Zoom" setting
128 to "Pan" if you don't want to zoom when applying them.
129 </BODY></HTML>"""
130 sys.exit(0)
131
132 # Figure out c1 and c2 from width, height, diag, cx, and cy.
133 # Diagonal in pixels
134 diagp= math.sqrt(width**2 + height**2)
135 # Scale between pixels and coordinates
136 scale= diagp/diag
137 x= (width/2.0)/scale
138 y= (height/2.0)/scale
139
140 c1= cx - x + (cy - y) * (0+1j)
141 c2= cx + x + (cy + y) * (0+1j)
142
143 #print width, height, diag, cx, cy, diagp, scale, x, y, c1, c2
144 #sys.exit(0)
145
146 #c1, c2 = (-2+2j), (2-2j) # Corner coordinates
147
148 # Force c1 to be upper left and c2 to be lower right
149 c1, c2= complex(min(c1.real, c2.real), max(c1.imag, c2.imag)), \
150 complex(max(c1.real, c2.real), min(c1.imag, c2.imag))
151
152 mandel= Image.new("L", (width, height))
153 draw= ImageDraw.Draw(mandel)
154
155 def drawrect((x1, y1), (x2, y2)):
156 "Draw a rectangle defined by the corners (x1, y1) and (x2, y2)."
157 color= plot(x1, y1) # Plot the upper left corner
158 # Should we cut this rectangle and recurse into the pieces?
159 cut= 0
160 ## Plot the edges and at the same time check if they are all the
161 ## same color.
162 # Upper edge (left to right)
163 x, y= x1+1, y1
164 while x<=x2:
165 if color<>plot(x, y):
166 cut= 1
167 x= x+1
168 # Right edge (top to bottom)
169 x, y= x2, y1+1
170 while y<=y2:
171 if color<>plot(x, y):
172 cut= 1
173 y= y+1
174 # Bottom edge (right to left)
175 x, y= x2-1, y2
176 while x>=x1:
177 if color<>plot(x, y):
178 cut= 1
179 x= x-1
180 # Left edge (bottom to top)
181 x, y= x1, y2-1
182 while y>y1:
183 if color<>plot(x, y):
184 cut= 1
185 y= y-1
186 # If our rectangle is too small to have an inside, we have now
187 # plotted every pixel in it.
188 if x2-x1<=1 or y2-y1<=1:
189 return
190 if cut: # If we're cutting the rectangle
191 if x2-x1 > y2-y1: # If it's wider than high
192 # Cut vertically
193 xc= ((x2-x1)/2)+x1
194 drawrect((x1, y1), (xc, y2))
195 drawrect((xc, y1), (x2, y2))
196 else: # if it's higher than wide
197 # Cut horizontally
198 yc= ((y2-y1)/2)+y1
199 drawrect((x1, y1), (x2, yc))
200 drawrect((x1, yc), (x2, y2))
201 else:
202 # If we're not cutting, it was the same color along the edge
203 if not debug:
204 # Fill in the rectangle
205 draw.rectangle([x1, y1, x2, y2], fill= color)
206 if yorig >= 0: # The x axis is visible on image
207 # Fill in the mirror rectangle
208 # Mirror y1 and y2 over yorig, but keep within image
209 y1m= max(0, min(2*yorig-y1, ymax))
210 y2m= max(0, min(2*yorig-y2, ymax))
211 draw.rectangle([x1, y1m, x2, y2m], fill= color)
212
213 def constant(x, y):
214 creal= (float(x)/xmax)*(c2.real - c1.real)+c1.real
215 cimag= (float(y)/ymax)*(c2.imag - c1.imag)+c1.imag
216 return complex(creal, cimag)
217
218 def plot(x, y):
219 c= constant(x, y)
220 z= i= 0
221 color= mandel.getpixel((x, y))
222 if color<>0:
223 return color
224 while i<maxiter and abs(z)<2:
225 z= z**2+c
226 i= i+1
227 color= 16*i%256
228 if i>=maxiter or color==0:
229 if debug:
230 color= 255
231 else:
232 color= 1
233 try:
234 mandel.putpixel((x, y), color)
235 if yorig >= 0: # The x axis is visible on image
236 ym= 2*yorig-y # ym is y mirrored over yorig
237 if ym >= 0 and ym <= ymax:
238 # ym is on the image
239 mandel.putpixel((x, ym), color)
240 except IndexError, the_error:
241 print "coord", x, y, xm, ym
242 raise IndexError, the_error
243 return color
244
245 # Initial default values
246 yfrom= 0
247 yto= ymax
248 yorig= -1 # The pixel coordinate of the x axis; negative means not on image
249
250 # Check if we should do mirroring
251 if c1.imag > 0 and c2.imag < 0: # the x axis is visible
252 yorig= int((-c1.imag/(c2.imag-c1.imag))*height) # pixel pos. of x axis
253 if c1.imag < abs(c2.imag): # the x axis is closer to top than bottom
254 yfrom= yorig # Begin at x axis
255 else:
256 yto= yorig # End at x axis
257
258 try:
259 drawrect((0, yfrom), (xmax, yto))
260 except os.error, the_error:
261 if the_error[0] != errno.ETIME:
262 raise os.error, the_error
263
264 signal.alarm(0)
265
266 print "Content-type: image/png"
267 print
268 mandel.save(sys.stdout, "PNG")

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26