Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

196 lines (164 sloc) 6.608 kb
# coding: utf8
"""
weasyprint.navigator
--------------------
A WeasyPrint-based web browser. In your web browser.
:copyright: Copyright 2011-2012 Simon Sapin and contributors, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
# Do NOT import unicode_literals here. Raw WSGI requires native strings.
from __future__ import division
import os.path
from weasyprint import HTML, CSS
from weasyprint.formatting_structure import boxes
from weasyprint.urls import url_is_absolute
from weasyprint.compat import parse_qs, base64_encode
FAVICON = os.path.join(os.path.dirname(__file__),
'tests', 'resources', 'icon.png')
STYLESHEET = CSS(string='''
:root { font-size: 10pt }
''')
def find_links(box, links, anchors):
link = box.style.link
# 'link' is inherited but redundant on text boxes
if link and not isinstance(box, boxes.TextBox):
type_, href = box.style.link
if type_ == 'internal':
href = '#' + href
else:
href = '/view/' + href
# "Border area. That's the area that hit-testing is done on."
# http://lists.w3.org/Archives/Public/www-style/2012Jun/0318.html
links.append((href,) + box.hit_area())
anchor = box.style.anchor
if anchor:
anchors.append((anchor,) + box.hit_area())
if isinstance(box, boxes.ParentBox):
for child in box.children:
find_links(child, links, anchors)
def get_pages(html):
document = html.render(enable_hinting=True, stylesheets=[STYLESHEET])
for page in document.pages:
links = []
anchors = []
find_links(page._page_box, links, anchors)
png_bytes, width, height = (
document.copy([page]).write_png(with_size=True))
data_url = 'data:image/png;base64,' + (
base64_encode(png_bytes).decode('ascii').replace('\n', ''))
yield width, height, data_url, links, anchors
def render_template(url):
parts = ['''\
<!doctype html>
<meta charset=utf-8>
<title>WeasyPrint Navigator</title>
<style>
form { position: fixed; z-index: 1; top: 8px; left: 16px; right: 0; }
nav, input { font: 24px/30px sans-serif }
input:not([type]) { background: rgba(255, 255, 255, .9); border-width: 2px;
border-radius: 6px; padding: 0 3px }
input:not([type]):focus { outline: none }
body { margin-top: 0; padding-top: 50px }
section { box-shadow: 0 0 10px 2px #aaa; margin: 25px;
position: relative; overflow: hidden; }
section a { position: absolute; display: block }
section a[href]:hover, a[href]:focus { outline: 1px dotted }
nav { margin: 25px }
</style>
<body onload="var u=document.forms[0].url; u.value || u.focus()">
<form action="/" onsubmit="
window.location.href = '/view/' + this.url.value; return false;">
<input name=url style="width: 80%" placeholder="Enter an URL to start"
value="''']
write = parts.append
if url:
html = HTML(url)
url = html.base_url
write(url)
write('" />\n<input type=submit value=Go />\n')
if url:
write('<a href="/pdf/')
write(url)
write('">PDF</a>\n')
write('</form>\n')
if url:
for width, height, data_url, links, anchors in get_pages(html):
write('<section style="width: {0}px; height: {1}px">\n'
' <img src="{2}">\n'.format(width, height, data_url))
for href, pos_x, pos_y, width, height in links:
write(' <a style="left: {0}px; top: {1}px; '
'width: {2}px; height: {3}px" href="{4}"></a>\n'
.format(pos_x, pos_y, width, height, href))
for anchor, pos_x, pos_y, width, height in anchors:
# Remove 60px to pos_y so that the real pos is below
# the address bar.
write(' <a style="left: {0}px; top: {1}px;" name="{2}"></a>\n'
.format(pos_x, pos_y - 60, anchor))
write('</section>\n')
else:
write('''
<nav>
<h2>Examples:</h2>
<ul>
<li><a href="/view/http://www.webstandards.org/files/acid2/test.html">
Acid2</a></li>
<li><a href="/view/http://www.w3.org/Style/CSS/current-work">
CSS specifications</a></li>
<li><a href="/view/http://en.wikipedia.org/">
English Wikipedia</a></li>
</ul>
</nav>
''')
return ''.join(parts).encode('utf8')
def normalize_url(url, query_string=None):
if url:
if query_string:
url += '?' + query_string
if not url_is_absolute(url):
# Default to HTTP rather than relative filenames
url = 'http://' + url
return url
def app(environ, start_response):
def make_response(body, status='200 OK', headers=(),
content_type='text/html; charset=UTF-8'):
start_response(status, [
('Content-Type', content_type),
('Content-Length', str(len(body))),
] + list(headers))
return [body]
path = environ['PATH_INFO']
if path == '/favicon.ico':
with open(FAVICON, 'rb') as fd:
return make_response(fd.read(), content_type='image/x-icon')
elif path.startswith('/pdf/') and len(path) > 5: # len('/pdf/') == 5
url = normalize_url(path[5:], environ.get('QUERY_STRING'))
body = HTML(url=url).write_pdf(stylesheets=[STYLESHEET])
filename = url.rstrip('/').rsplit('/', 1)[-1] or 'out'
return make_response(body, content_type='application/pdf',
headers=[('Content-Disposition',
'attachement; filename=%s.pdf' % filename)])
elif path.startswith('/view/'):
url = normalize_url(path[6:], environ.get('QUERY_STRING'))
return make_response(render_template(url))
elif path == '/':
args = parse_qs(environ.get('QUERY_STRING') or '')
url = normalize_url(args.get('url', [''])[0])
return make_response(render_template(url))
return make_response(b'<h1>Not Found</h1>', status='404 Not Found')
def run(port=5000):
host = '127.0.0.1'
try:
from werkzeug.serving import run_simple
except ImportError:
pass
else:
run_simple(host, port, app, use_reloader=True, use_debugger=True)
return
print('Could not import Werkzeug, running without the reloader '
'or debugger.')
from wsgiref.simple_server import make_server
server = make_server(host, port, app)
print('Listening on http://%s:%s/ ...' % (host, port))
server.serve_forever()
if __name__ == '__main__':
run()
Jump to Line
Something went wrong with that request. Please try again.