In one of my homework practices, I must start a webserver and when I access webserver's root, it executes a CGI script.
But when I open localhost:8080, this error message appears:
Error code 403.
Message: CGI script is not executable ('/cgi-bin/todolist.cgi').
Error code explanation: 403 = Request forbidden -- authorization will not help.
My server code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import getopt
import logging
import BaseHTTPServer
from CGIHTTPServer import CGIHTTPRequestHandler
import json
from DBBackend import TodoDao
# CRUD to REST conventions
# POST Create
# GET Retrieve
# PUT Update
# DELETE Delete
"""
API REST del servidor.
GET /todos - Recupera la lista de tareas (ToDos)
DELETE /todos/id - Elimina la tarea con el id especificado
POST /todos - Añade una nueva tarea con los valores especificados como parámetros
PUT /todos/id - Actualiza los valores espcificados en los parámetros para la tarea con
el id dado
Tanto los parámetros (en el cuerpo de la petición) como las respuestas son en formato JSON.
"""
logging.basicConfig(level=logging.DEBUG)
class RESTHTTPRequestHandler(CGIHTTPRequestHandler):
dao = TodoDao()
res_string = dao.tableName
res_path = "/" + res_string
def _GET(self):
if self.path == self.res_path:
tasks = self.dao.findTasks()
return {'code': 'ok', 'data': tasks}
else:
_,res,id = self.path.split("/")
int(id)
assert(res==self.res_string)
data = self.dao.retrieveTask(id)
return {'code': 'ok', 'data': data}
def _POST(self):
assert(self.path == self.res_path)
if 'Content-length' in self.headers:
data = json.loads(self.rfile.read(int(self.headers['Content-length'])))
else:
data = json.load(self.rfile)
self.dao.createTask(data)
return {'code': 'ok'}
def _PUT(self):
_,res,id = self.path.split("/")
int(id)
assert(res==self.res_string)
if 'Content-length' in self.headers:
data = json.loads(self.rfile.read(int(self.headers['Content-length'])))
else:
data = json.load(self.rfile)
self.dao.updateTask(id, data)
return {'code': 'ok'}
def _DELETE(self):
_,res,id = self.path.split("/")
int(id)
assert(res==self.res_string)
self.dao.deleteTask(id)
return {'code': 'ok'}
def _send(self, data):
response = json.dumps(data)
self.send_response(200)
self.send_header("Content-type", "application/json")
self.send_header("Content-Length", len(response))
self.end_headers()
self.wfile.write(response)
# El BaseHTTPRequestHandler no está pensado para ésto :(
def do_POST(self):
self._reroute()
def do_PUT(self):
self._reroute()
def do_GET(self):
self._reroute()
def do_DELETE(self):
self._reroute()
def _reroute(self):
try:
if self.path.startswith(self.res_path):
method_name = '_' + self.command
method = getattr(self, method_name)
try:
self._send(method())
except (ValueError, AssertionError):
self.send_error(400, "Invalid request")
except:
logging.exception("Database access error")
self.send_error(500, "DDBB error")
else:
if self.path == "/" or self.path == "/index.html":
self.path = "/cgi-bin/todolist.cgi"
method_name = 'do_' + self.command
method = getattr(CGIHTTPRequestHandler, method_name)
method(self)
except AttributeError:
self.send_error(501, "Unsupported method (%r)" % self.command)
#---- Defaults
port = "8080"
basedir = "www/"
#----
#----------------------------------------
def usage():
print "Uso: " + os.path.basename(sys.argv[0]) + " -h -p port"
print " -h Muestra este mensaje"
print " -p port Sirve en el puerto indicado (def={0})".format(port)
print " -d dirname Sirve el contenido del directorio indicado (def={0})".format(basedir)
#----------------------------------------
try:
opts, args = getopt.getopt(sys.argv[1:], "hp:d:", ["help", "port=", "dir="])
except getopt.GetoptError:
usage()
sys.exit(2)
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-p", "--port"):
port = a
if o in ("-d", "--dir"):
basedir = a
if (port == None):
usage()
sys.exit()
try:
address = ('', int(port))
except ValueError:
usage()
sys.exit(2)
httpd = BaseHTTPServer.HTTPServer(address,
RESTHTTPRequestHandler)
os.chdir(basedir)
httpd.serve_forever()
And my todolist.cgi:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cgi
import sys
import os
import datetime
import locale
# TBD: Usar el locale del cliente
locale.setlocale(locale.LC_TIME,'')
date_format = locale.nl_langinfo(locale.D_FMT)
sys.path.append(os.path.join(os.path.dirname(__file__), "../.."))
import DBBackend
print "Content-Type: text/html"
print ""
print """
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8"/>
<title>[IPM] Lista de tareas</title>
<meta name="author" content="David Cabrero"/>
<meta name="HandheldFriendly" content="true"/>
<meta name="viewport" content="width=device-width, initial-scale=1,maximun-scale=1,user-scalable=no"/>
<meta http-equiv="X-UA-Compatible" content="IE=ecdge,chrome=1">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
<![endif]-->
<link rel="stylesheet" type="text/css" href="css/default.css" />
<link rel="stylesheet" type="text/css" href="css/wide-screen.css"
media="only screen and (min-width : 1024px)" />
<script src="js/todolist.js"></script>
</head>
<body>
<header>
<h1>ToDo</h1>
</header>
<ul>
"""
fname = os.path.join(os.getcwd(), "../", DBBackend.DATABASEFILENAME)
li = """
<a href="#dialog"><li data-task-id="{0}">
<p class="desc">{1}</p>
<time datetime="{2}">{3}</time>
<p class="done" data-task-done="{4}">{5}</p>
</li></a>
"""
for task in DBBackend.TodoDao(fname).findTasks():
id = str(task['id'])
desc = task['desc'].encode('utf-8')
deadline = datetime.datetime.strptime(task['deadline'], "%Y-%m-%d")
done = task['done'] == 1
print li.format(id, desc, deadline.strftime("%Y-%m-%d"), deadline.strftime(date_format),
"yes" if done else "no", "Hecho" if done else "Sin hacer")
print """
</ul>
<div id="updateTask" class="dialog"><div>
<h1>Actualizar tarea</h1>
<form>
<p><input type="text" name="task_desc" placeholder="task description" autofocus="autofocus" /></p>
<p><input type="date" name="task_deadline" placeholder="deadline" /></p>
<p><input type="checkbox" name="task_done" /></p>
<p class="okCancel">
<button name="ok">OK</button>
<button name="cancel">Cancel</button>
</p>
</form>
</div></div>
</body>
</html>
"""
print """
"""
All the code was given by teachers (I have to do a web application), so I don't know how to start if I cannot manage to get the server working. I'm also running Windows 7 and Python for Windows (Version 2.7), hope it helps!
The problem is not in your code, but in the filesystem permissions. The cgi file must be marked execuatable. This can be done with chmod a+x todolist.cgi, from a shell in the cgi-bin directory.
OK, what you need to do to make this work under Windows is to rename your script from todolist.cgi to todolist.py and change the line in server code where it says:
self.path = "/cgi-bin/todolist.cgi"
change that to:
self.path = "/cgi-bin/todolist.py"
That should let it all work in Windows without too much fuss. It all has to do with the inner workings of CGIHTTPServer and how it handles executables. I tried various other tricks (and outright hacks like monkey-patching CGIHTTPServer.executable...) to make it work, but this seemed the simplest.
Related
I have a webpage with a login form which is processed by a python script. When I enter a name that is not found in the DB, it redirects to a login_or_signup.html page. When I enter a name that is in the DB, is should redirect to a "next_page.html" page, but it shows some code. Why does it work one way and not the other? (I have changed it to go to the login_or_signup.html page both ways and it works both ways.
Python code
#! /usr/bin/python
import cgi
import cgitb
import mysql.connector as conn
import passlib
from passlib.hash import argon2
import logging
cgitb.enable(logdir="/var/www/html",
display=False,
format='text',
)
logging.basicConfig(level=logging.INFO)
def basic_top(data):
print """Content-type:text/html\n\n
<DOCTYPE html>
<html lang=en">
<head>
<meta charset= utf-8/>
<title>Basic Version</title>
</head>
<body>"""
for d in data:
print d
print
def go_back_top(data):
redirectURL = "%s" % "/login_or_signup.html"
try:
print """Content-type:text/html\n\n
Location: %s""" % redirectURL
print """<DOCTYPE html>
<html lang="en">
<head>
<meta charset= utf-8/>"""
print " <meta http-equiv='refresh' content='0;url=%s' />" % redirectURL
print """ <title>Login</title>
</head>\n\n
<body>"""
#for d in data:
# print d
# print
print ' Redirecting... Click here if you are not redirected' % redirectURL
except:
cgi.print_exception()
print "An error occured\n\n"
print"<PRE>"
cgitb.print_exc()
def go_forwards_top(data):
redirectURL = "%s" % "/login_or_signup.html" #/next_page.html"
try:
print """Content-type:text/html\n\n
Location: %s""" % redirectURL
print """<DOCTYPE html>
<html lang="en">
<head>
<meta charset= utf-8/>"""
print " <meta http-equiv='refresh' content='0;url=%s' />" % redirectURL
print """ <title>Login</title>
</head>\n\n
<body>"""
print ' Redirecting... Click here if you are not redirected' % redirectURL
except:
cgi.print_exception()
print "An error occured\n\n"
print"<PRE>"
cgitb.print_exc()
def htmlTail():
print "</body>"
print "</html>"
def getData():
formdata = cgi.FieldStorage()
username = formdata.getvalue("username")
password = formdata.getvalue("password")
login_type = formdata.getvalue("type")
if login_type == "signup":
password_copy = formdata.getvalue("password_copy")
return username, password, password_copy, login_type
else:
return username, password, login_type
def connectDB():
db = conn.connect(user='basic_user', password='twathead', host='127.0.0.1', db="exampleDB")
cursor = db.cursor()
logging.info(cursor)
return db, cursor
def check_person(cursor, data):
username = data[0]
sql_str = "SELECT * FROM people WHERE username = '%s'" % (username)
cursor.execute(sql_str)
person = cursor.fetchone()
if person is None:
go_back_top(data)
else:
go_forwards_top(data)
#logging.info(str(conn))
#conn.close()
if __name__=="__main__":
logging.basicConfig(filename='/usr/lib/cgi-bin/example.log', level=logging.INFO)
logging.info('This message should go to the log file')
#data = ("John", "Smith")
data = getData()
#basic_top(data)
#print "login type = "
#print data[0]
db, cursor = connectDB()
check_person(cursor, data)
Html for next_page:
<DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="mystyle.css">
<title>Post Login</title>
</head>
<body style="background-color:powderblue;">
<h2>This page is currently under construction.<h2>
</body>
</html>
Open terminal, type:
service apache-htcacheclean restart
I've built a simple web server that gets a request and send a response. So when the server gets an invalid request, like "localhost/not-a-page", the server will send a response with the content of the HTML file "404.html" the webpage should display an image. So far, so good.
But when the 404 page loads up, the page can't find the image. The HTML part is correct and works offline. I've tried to move the image to serval locations, relative to the Python script, relative to the HTML. But it just can't find it. Hi I'm trying to make the server as low-level as I can, I want to learn how servers work. So I'm not using any server-related libraries. I'm using only the socket library of Python.
I'll appreciate any help to resolve this problem without using other libraries,
EDIT
Here is the relevant Python part :
import socket
import threading
import os
default_error_page = """\
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Error response</title>
</head>
<body>
<center>
<h1>Response</h1>
<p>Error code: %(code)d</p>
<p>Message: %(status)s.</p>
</center>
</body>
</html>
"""
default_header_status = "HTTP/1.1 %(code)d %(status)s\r\n"
default_header_content_type = "Content-Type: text/html; charset=utf-8\r\n\r\n"
buffer_size = 1024
def get_page(code):
page = default_error_page
if code == 200:
pass
else:
file = open(os.path.dirname(__file__) + "/www/not-found.html", 'r')
page = file.read()
return page
class BaseServer:
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_name = ""
host_name = ""
host_port = 8000 # default port
is_shutdown = False
def __init__(self, name):
self.server_name = name
def start_server(self):
thread = threading.Thread(target=self.run_server(), name=self.server_name)
thread.start()
def run_server(self):
self.server_socket.bind((self.host_name, self.host_port)) # bind to host
self.server_socket.listen()
while not self.is_shutdown:
conn, addr = self.server_socket.accept()
self.handle_request(conn, addr)
def handle_request(self, connection, address):
print(str(address[0]) + " Connected! (port " + str(address[1]) + ")")
result = self.parse_request(connection.recv(buffer_size))
if result == 0:
page = self.parse_response(200)
else:
page = self.parse_response(404)
connection.sendall(bytes(page))
def parse_request(self, data):
if len(data) == 0:
return
strings = str(bytes(data).decode('utf-8')).split('\r\n')
command, path, version = strings[0].split()
print("command - " + command)
print("path - " + path)
print("version - " + version)
status = 1
if path == "/":
status = 0
return status
def parse_response(self, code):
status = "ERROR"
if code == 200:
status = "OK"
elif code == 404:
status = "NOT FOUND"
base_header = (default_header_status % {'code': code, 'status': status})
base_content_type = default_header_content_type
# page = (default_error_page % {'code': code, 'status': status})
page = str(get_page(code))
return_string = str(base_header + base_content_type + page).encode('utf-8')
print(return_string)
return return_string
def main():
server = BaseServer("Home Server")
server.start_server()
if __name__ == "__main__":
main()
And this is the HTML:
<html>
<head>
<link rel="stylesheet" type="text/css" href="/style/main.css"/>
<style>
*{
padding:0;
margin:0;
}
body{
background-color:#ffe6b3;
}
h1{
margin-top:30px;
background-color:#ffcc66;
font-size:3em;
display:inline-block;
color:#3a0000;
}
p{
margin-top:80px;
font-size:2em;
color:#3a0000;
}
#img404{
background-image:url(../images/404.gif);
width:100%;
height:50%;
background-repeat:no-repeat;
background-position:center 20%;
}
</style>
</head>
<body>
<center>
<div class=top>
<h1>ERROR 404</h1>
</div>
<p>
Sorry, we could not find the page :(
</p>
<div id="img404">
</div>
</center>
</body>
</html>
Sorry if it's not very readable, but I'm on the phone.
Dima.
Don't use relative paths for image like ../images/img.gif. Rather use full url or url relative to the root.
http://localhost/images/img.gif - full url
/images/img.gif - path relative to root url
Figured out my problem.
After I saw the logs, I realized that the browser sends another request, for the image.
And silly me, my code is:
if path ="/":
status = 0
else:
status = 1
So for every request which is not root("/") the server will return 404.
Oops
I am trying to build a simple REST server with python SimpleHTTPServer. I am having problem reading data from the post message. Please let me know if I am doing it right.
from SimpleHTTPServer import SimpleHTTPRequestHandler
import SocketServer
import simplejson
class S(SimpleHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
print "got get request %s" % (self.path)
if self.path == '/':
self.path = '/index.html'
return SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self):
print "got post!!"
content_len = int(self.headers.getheader('content-length', 0))
post_body = self.rfile.read(content_len)
test_data = simplejson.loads(post_body)
print "post_body(%s)" % (test_data)
return SimpleHTTPRequestHandler.do_POST(self)
def run(handler_class=S, port=80):
httpd = SocketServer.TCPServer(("", port), handler_class)
print 'Starting httpd...'
httpd.serve_forever()
The index.html file
<html>
<title>JSON TEST PAGE</title>
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
JSONTest = function() {
var resultDiv = $("#resultDivContainer");
$.ajax({
url: "http://128.107.138.51:8080",
type: "POST",
data: {txt1: $("#json_text").val()},
dataType: "json",
success: function (result) {
switch (result) {
case true:
processResponse(result);
break;
default:
resultDiv.html(result);
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
};
</script>
</head>
<body>
<h1>My Web Page</h1>
<div id="resultDivContainer"></div>
<form>
<textarea name="json_text" id="json_text" rows="50" cols="80">
[{"resources": {"dut": "any_ts", "endpoint1": "endpoint", "endpoint2": "endpoint"}},
{"action": "create_conference", "serverName": "dut", "confName": "GURU_TEST"}]
</textarea>
<button type="button" onclick="JSONTest()">Generate Test</button>
</form>
</body>
</html>
The SimpleJson fails to load the json from the POST message. I am not familiar with web coding and I am not even sure if what I am doing is right for creating a simple REST API server.
I appreciate your help.
Thanks matthewatabet for the klein idea. I figured a way to implement it using BaseHTTPHandler. The code below.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import SocketServer
import simplejson
import random
class S(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
self._set_headers()
f = open("index.html", "r")
self.wfile.write(f.read())
def do_HEAD(self):
self._set_headers()
def do_POST(self):
self._set_headers()
print "in post method"
self.data_string = self.rfile.read(int(self.headers['Content-Length']))
self.send_response(200)
self.end_headers()
data = simplejson.loads(self.data_string)
with open("test123456.json", "w") as outfile:
simplejson.dump(data, outfile)
print "{}".format(data)
f = open("for_presen.py")
self.wfile.write(f.read())
return
def run(server_class=HTTPServer, handler_class=S, port=80):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print 'Starting httpd...'
httpd.serve_forever()
if __name__ == "__main__":
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
And the corresponding html page
<form action="/profile/index/sendmessage" method="post" enctype="application/x-www-form-urlencoded">
<div class="upload_form">
<dt id="message-label"><label class="optional" for="message">Enter Message</label></dt>
<dd id="message-element">
<textarea cols="80" rows="50" id="message" name="message">
[{"resources": {"dut": "any_ts", "endpoint1": "multistream_endpoint", "endpoint2": "multistream_endpoint"}},
{"action": "create_conference", "serverName": "dut", "conferenceName": "GURU_SLAVE_TS"},
{"action": "dial_out_ep", "serverName": "dut", "confName": "GURU_SLAVE_TS", "epName": "endpoint1"}
]
</textarea></dd>
<dt id="id-label"> </dt>
<dd id="id-element">
<input type="hidden" id="id" value="145198" name="id"></dd>
<dt id="send_message-label"> </dt>
<dd id="send_message-element">
<input type="submit" class="sendamessage" value="Send" id="send_message" name="send_message"></dd>
</div>
</form>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
$("input.sendamessage").click(function(event) {
event.preventDefault();
var message = $('textarea#message').val();
var id = $('input#id').val();
url = "http://128.107.138.51:8080"
var posting = $.post(url, message)
posting.done(function( data ) {
alert(message);
});
});
</script>
SimpleHTTPRequestHandler does not support POST. It's very simple indeed. Check out Klein whose server is a bit more full-featured.
There's an example of a json PUT (pretty close to POST) here:
https://pypi.python.org/pypi/klein/0.2.3
import json
from klein import Klein
class ItemStore(object):
app = Klein()
def __init__(self):
self._items = {}
#app.route('/')
def items(self, request):
request.setHeader('Content-Type', 'application/json')
return json.dumps(self._items)
#app.route('/<string:name>', methods=['PUT'])
def save_item(self, request, name):
request.setHeader('Content-Type', 'application/json')
body = json.loads(request.content.read())
self._items[name] = body
return json.dumps({'success': True})
#app.route('/<string:name>', methods=['GET'])
def get_item(self, request, name):
request.setHeader('Content-Type', 'application/json')
return json.dumps(self._items.get(name))
if __name__ == '__main__':
store = ItemStore()
store.app.run('localhost', 8080)
I have the HTMl code #http://pastie.org/8456333 as a reference ,also I have the below code where i am construcing HTML code to email ..i need inputs or suggestions on what modifcations need to be done to below code to make the table look like
the HTML code #http://pastie.org/8456333
import re
import os
import sys
import time
from email.mime.text import MIMEText
import subprocess
from subprocess import check_call,Popen,PIPE
def email (body,subject,to=None):
msg = MIMEText("%s" % body)
msg["Content-Type"] = "text/html"
msg["From"] = "cdit#company.com"
#msg["From"] = "test#company.com"
if to!=None:
to=to.strip()
#msg["To"] = "test#company.com"
msg["To"] = to
else:
msg["To"] = to
msg["Subject"] = '%s' % subject
p = Popen(["/usr/sbin/sendmail", "-t"], stdin=PIPE)
p.communicate(msg.as_string())
def manifest_table(project,branch):
global table_items
global tableProperties
table_items = table_items + "<tr><td>%s</td><td>%s</td></tr>"%(project,branch)
tableBody = """\
<style type="text/css">
%s
</style>
<table id="tfhover" class="tftable" border="1">
%s
</table>
"""%(tableProperties, table_items)
return tableBody
def main ():
i=0
global table_items
table_items = "<tr><th>Project</th><th>Branch</th></tr>"
global tableProperties
tableProperties = r"table.tftable {font-size:12px;color:#333333;width:10%;border-width: 1px;border-color: #729ea5;border-collapse: collapse;} table.tftable th {font-size:12px;background-color:#ded0b0;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;text-align:left;} table.tftable tr {background-color:#ffffff;} table.tftable td {font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;}"
project_list=['data','modem','1x','umts']
branch_list=['jb','fr','kk','choc']
for proj in project_list:
branch = branch_list[i]
mft = manifest_table(proj,branch)
i=i+1
email_body = """\
<html>
<head></head>
<body>
<p>Please find the table for the gerrits you provided:- <br>
</p>
%s
</body>
</html>
"""%(mft)
print "Emailing..."
email(email_body,"Manifest table","test#company.com")
if __name__ == '__main__':
main()
For making your table I suggest to use string.Template:
this is simple example:
from string import Template
a = Template("$name is my friend")
b=a.substitute(name="Sara")
print b
#output: Sara is my friend
So about a part of your code:
table_items = table_items + "<tr><td>%s</td><td>%s</td></tr>"%(project,branch)
you can do it better:
table_items += "<tr><td>%(p)s</td><td>%(b)s</td></tr>" % {'p':project,'b':branch}
or via string.Template:
table_items = Template("<tr><td>$p</td><td>$b</td></tr>")
table_items += table_items.substitute(p=project,b=branch)
I want to show OpenCV processed image with web interface (made with CherryPy). Code below works fine:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
cherrypy.response.headers['Content-Type'] = 'image/jpeg'
return data.tostring()
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
However: I would like to embed the image in html so I can (for example) add another image or other data to the same page.
I have tried the following code:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpeg', image)
return """ <html>
<head>
<title>CherryPy static imagl</title>
</head>
<html>
<body>
<img src=" """ + data + """:image/jpeg" />
</body>
</html>"""
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
But this gives the following error:
<img src=" """ + data + """:image/jpeg" />
TypeError: cannot concatenate 'str' and 'numpy.ndarray' objects
Converting the numpy arry to a string using the following code also does not work (it gives no error but displays only characters):
<img src=" """ + data.tostring() + """:image/jpeg" />
Anyone who can give me some more insight? Thanks in advance!
The following code does the trick :)
import cherrypy
import cv2
import base64
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
jpeg_base64 = base64.b64encode(data.tostring())
return """
<html>
<head>
<meta http-equiv="refresh" content="1" />
<title>Cherrypy webcam</title>
</head>
<html>
<body>
<img src='data:image/jpeg;base64,%s' />
<img src='data:image/jpeg;base64,%s' />
</body>
</html>
""" % (jpeg_base64, jpeg_base64)
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
This code displays the same picture two times. and the:
<meta http-equiv="refresh" content="1" />
refreshes the code every second.