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

Annotation of /fract/mandelzoom.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (hide 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 teddy 1.1 #!/usr/bin/python
2    
3 teddy 1.9 import cgi, Image, ImageDraw, sys, math, signal, errno, os
4 teddy 1.2 from string import atoi, atof
5    
6 teddy 1.9 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 teddy 1.3 # This is to get backtrace output
13 teddy 1.2 sys.stderr = sys.stdout
14 teddy 1.1
15 teddy 1.3 # Uncomment this to get the backtrace more readable
16     #print "Content-Type: text/plain"
17     #print ""
18    
19 teddy 1.1 form= cgi.FieldStorage()
20    
21     # Image size
22     if form.has_key('width'):
23 teddy 1.2 width= atoi(form['width'].value)
24 teddy 1.1 else:
25 teddy 1.3 width= 480
26 teddy 1.1 if form.has_key('height'):
27 teddy 1.2 height= atoi(form['height'].value)
28 teddy 1.1 else:
29 teddy 1.3 height= 480
30 teddy 1.1
31     xmax, ymax = width-1, height-1 # Coordinate maximums
32    
33 teddy 1.2 # 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 teddy 1.6 cx= 0.0
38 teddy 1.2
39     if form.has_key('cy'):
40     cy= atof(form['cy'].value)
41     else:
42 teddy 1.6 cy= 0.0
43 teddy 1.2
44     if form.has_key('diag'):
45     diag= atof(form['diag'].value)
46     else:
47 teddy 1.5 diag= math.sqrt(32) # sqrt(4**2 + 4**2)
48 teddy 1.2
49 teddy 1.1 debug= form.has_key('debug')
50    
51     if form.has_key('iter'):
52 teddy 1.2 maxiter= atoi(form['iter'].value)
53 teddy 1.1 else:
54 teddy 1.5 maxiter= 270
55 teddy 1.1
56 teddy 1.2 # If type!=image, then output an HTML page, not an image
57     if not (form.has_key('type') and form['type'].value == "image"):
58 teddy 1.1 print """Content-Type: text/html
59    
60     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
61     <HTML><HEAD>
62 teddy 1.6 <TITLE>Mandelbrot Set Zoomer</TITLE>
63 teddy 1.1 </HEAD>
64     <BODY>
65 teddy 1.6 <H1>Mandelbrot Set Zoomer</H1>
66 teddy 1.1
67     <FORM ACTION="mandelzoom.cgi" METHOD=GET>
68    
69 teddy 1.2 <!-- 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 teddy 1.6 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 teddy 1.7 diagp= math.sqrt(owidth**2 + oheight**2)
84 teddy 1.6 scale= diagp/diag
85 teddy 1.7 cx= (ix/scale) + (cx - (owidth / (scale*2)))
86     cy= ((oheight-iy)/scale) + (cy - (oheight / (scale*2)))
87 teddy 1.2 if form.has_key('zoom'):
88 teddy 1.5 zoom=atof(form['zoom'].value)
89 teddy 1.2 diag=diag/zoom
90     else:
91     # If no zoom provided, don't actually zoom
92 teddy 1.6 zoom= 2.0
93 teddy 1.2 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 teddy 1.5 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 teddy 1.2 print '<OPTION',
99 teddy 1.5 if str(zv)==str(zoom):
100 teddy 1.2 print 'SELECTED',
101     print 'VALUE="%s"' % (str(zv))
102 teddy 1.3 if zv == 1:
103     print '>Pan'
104     elif zv < 1:
105 teddy 1.6 print '>Out ÷%s' % (str(1/zv))
106 teddy 1.2 else:
107 teddy 1.3 print '>In ×%s' % (str(zv))
108 teddy 1.2 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 teddy 1.1 Iterations: <INPUT TYPE=TEXT NAME="iter" MAXLENGTH="4" SIZE="3"
114     VALUE="%s">
115 teddy 1.3 Debug mode: <INPUT TYPE=CHECKBOX NAME="debug" """ % (str(width), str(height), str(maxiter)),
116 teddy 1.2 if debug:
117     print 'CHECKED>'
118     else:
119     print '>'
120 teddy 1.3 print '<INPUT TYPE=SUBMIT VALUE="Apply">'
121 teddy 1.6 for var in (("diag", diag), ("cx", cx), ("cy", cy), ("owidth", width),
122     ("oheight", height)):
123 teddy 1.5 print '<INPUT TYPE=HIDDEN NAME="%s" VALUE="%s">' % var
124 teddy 1.2 print '<INPUT TYPE=HIDDEN NAME=type VALUE="html">'
125 teddy 1.1
126 teddy 1.8 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 teddy 1.1 </BODY></HTML>"""
130     sys.exit(0)
131    
132 teddy 1.5 # 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 teddy 1.6 c1= cx - x + (cy - y) * (0+1j)
141     c2= cx + x + (cy + y) * (0+1j)
142 teddy 1.5
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 teddy 1.1
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 teddy 1.9 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 teddy 1.1
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