Dynamic image creation for the web...

T

Tompa

Hi,

I would like to create images on the fly as a response to an http request.
I can do this with PIL like this (file create_gif.py):
from PIL import Image, ImageDraw

print 'Status: 200 OK'
print 'Content-type: text/html'
print
print '<HTML><HEAD><TITLE>Python Dynamic Image Creation Test</TITLE></HEAD>'
print '<BODY>'
im = Image.new("P", (600, 400))
draw = ImageDraw.Draw(im)
draw.rectangle((0, 0) + im.size, fill="blue")
im.save("images/tmp.gif");
print '<img src="/scripts/images/tmp.gif">'
print '</BODY>'


However, I would like to 1) avoid saving the image in a file on disk and
2) separate the HTLM code from the python image creation code.

Something like this is what I have in mind:
(file index.html):
<html>
<head><meta HTTP-EQUIV="content-type" CONTENT="text/html; charset=UTF-8">
<title>Python Dynamic Image Creation</title>
</head>
<IMG SRC="/scripts/create_image.py" ALT="Image created on the fly...">
</html>

and in file create_image.py:
from PIL import Image, ImageDraw, ImageFont
im = Image.new("P", (600, 400))
draw = ImageDraw.Draw(im)
draw.rectangle((0, 0) + im.size, fill="blue")


Unfortunately this does not work :-(
What is missing?

Thanks in advance!
/Tompa
 
B

Benjamin Niemann

Tompa said:
Hi,

I would like to create images on the fly as a response to an http request.
I can do this with PIL like this (file create_gif.py):
from PIL import Image, ImageDraw

print 'Status: 200 OK'
print 'Content-type: text/html'
print
print '<HTML><HEAD><TITLE>Python Dynamic Image Creation
Test</TITLE></HEAD>' print '<BODY>'
im = Image.new("P", (600, 400))
draw = ImageDraw.Draw(im)
draw.rectangle((0, 0) + im.size, fill="blue")
im.save("images/tmp.gif");
print '<img src="/scripts/images/tmp.gif">'
print '</BODY>'


However, I would like to 1) avoid saving the image in a file on disk and
2) separate the HTLM code from the python image creation code.

Something like this is what I have in mind:
(file index.html):
<html>
<head><meta HTTP-EQUIV="content-type" CONTENT="text/html; charset=UTF-8">
<title>Python Dynamic Image Creation</title>
</head>
<IMG SRC="/scripts/create_image.py" ALT="Image created on the fly...">
</html>

and in file create_image.py:
from PIL import Image, ImageDraw, ImageFont
im = Image.new("P", (600, 400))
draw = ImageDraw.Draw(im)
draw.rectangle((0, 0) + im.size, fill="blue")


Unfortunately this does not work :-(
What is missing?

You are almost there. Your create_image.py does not return anything to the
browser yet.

First return proper HTTP headers, e.g.

sys.stdout.write('Status: 200 OK\r\n')
sys.stdout.write('Content-type: image/gif\r\n')
sys.stdout.write('\r\n')

(Your prints above are mostly equivalent, but do not output the correct \r\n
as line terminator - at least on UNIX style systems. Most webservers
tolarate this, if it's coming from a CGI - but doing it right and not
relying on a certain server behaviour is not bad anyway ;)

Then check the PIL docs to find out, how to output the image to sys.stdout
(instead of writing to a file).
 
M

Max Erickson

Hi,

I would like to create images on the fly as a response to an http
request. I can do this with PIL like this (file create_gif.py):
from PIL import Image, ImageDraw

check out sparklines:

http://bitworking.org/projects/sparklines/

It is a script very similar to what you want to do.

The difference between your script and sparklines is mostly that it
sends:

print "Content-type: image/png"

instead of:

print 'Content-type: text/html'


max
 
T

Tompa

Benjamin Niemann said:
You are almost there.
I don't feel so...
Your create_image.py does not return anything to the
browser yet.
Yes, I am aware of that but I do not what to return.
First return proper HTTP headers, e.g.

sys.stdout.write('Status: 200 OK\r\n')
sys.stdout.write('Content-type: image/gif\r\n')
sys.stdout.write('\r\n')

Ok, but if possible I'd rather not return anything HTTP/HTML-related from my
create_image.py file.
Then check the PIL docs to find out, how to output the image to sys.stdout
(instead of writing to a file).
Ok, then I get this:

from PIL import Image, ImageDraw
import sys

im = Image.new("P", (600, 400))
draw = ImageDraw.Draw(im)
draw.rectangle((0, 0) + im.size, fill="blue")

sys.stdout.write('Status: 200 OK\r\n')
sys.stdout.write('Content-type: image/gif\r\n')
sys.stdout.write('\r\n')

im.save(sys.stdout, "GIF")

But this does not work.
I also tested to skip the HTTP-header stuff and just write the gif to
sys.stdout, believing that that would work. But not so...

Hmm, I'm a newbie to Python (as you already probably have noticed ;-) so I
don't know what else I should try. Any hints are welcome!

/Tompa
 
B

Benjamin Niemann

Tompa said:
I don't feel so...

Yes, I am aware of that but I do not what to return.


Ok, but if possible I'd rather not return anything HTTP/HTML-related from
my create_image.py file.

When the browser fetches the images for displaying, it performs just another
HTTP request, and you must reply with a valid HTTP response. The
Content-type header is the absolute minimum that must always be returned.
(IIRC the 'Status' can be omitted, if it's 200).
Ok, then I get this:

from PIL import Image, ImageDraw
import sys

im = Image.new("P", (600, 400))
draw = ImageDraw.Draw(im)
draw.rectangle((0, 0) + im.size, fill="blue")

sys.stdout.write('Status: 200 OK\r\n')
sys.stdout.write('Content-type: image/gif\r\n')
sys.stdout.write('\r\n')

im.save(sys.stdout, "GIF")

But this does not work.
I also tested to skip the HTTP-header stuff and just write the gif to
sys.stdout, believing that that would work. But not so...

Works perfectly here...
What does the error.log of the webserver say?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,059
Latest member
cryptoseoagencies

Latest Threads

Top