如何使用CGI Python脚本在浏览器中显示PDF文件内容及其完整名称?
我想在浏览器中显示PDF文件的完整路径,同时也显示文件的内容。我的脚本有一个输入的HTML页面,用户可以在这里输入文件名并提交表单。脚本会搜索这个文件,如果在子目录中找到了,就会把文件的内容输出到浏览器,并显示文件名。我可以显示内容,但无法同时显示完整的文件名;或者如果我显示了文件名,内容就会出现乱码。请给我一些指导。
脚本 a.py:
import os
import cgi
import cgitb
cgitb.enable()
import sys
import webbrowser
def check_file_extension(display_file):
input_file = display_file
nm,file_extension = os.path.splitext(display_file)
return file_extension
form = cgi.FieldStorage()
type_of_file =''
file_nm = ''
nm =''
not_found = 3
if form.has_key("file1"):
file_nm = form["file1"].value
type_of_file = check_file_extension(file_nm)
pdf_paths = [ '/home/nancy/Documents/',]
# Change the path while executing on the server , else it will throw error 500
image_paths = [ '/home/nancy/Documents/']
if type_of_file == '.pdf':
search_paths = pdf_paths
else:
# .jpg
search_paths = image_paths
for path in search_paths:
for root, dirnames, filenames in os.walk(path):
for f in filenames:
if f == str(file_nm).strip():
absolute_path_of_file = os.path.join(root,f)
# print 'Content-type: text/html\n\n'
# print '<html><head></head><body>'
# print absolute_path_of_file
# print '</body></html>'
# print """Content-type: text/html\n\n
# <html><head>absolute_path_of_file</head><body>
# <img src=file_display.py />
# </body></html>"""
not_found = 2
if search_paths == pdf_paths:
print 'Content-type: application/pdf\n'
else:
print 'Content-type: image/jpg\n'
file_read = file(absolute_path_of_file,'rb').read()
print file_read
print 'Content-type: text/html\n\n'
print absolute_path_of_file
break
break
break
if not_found == 3:
print 'Content-type: text/html\n'
print '%s not found' % absolute_path_of_file
这个HTML页面很简单,只有一个输入框用来输入文件名。
1 个回答
这件事其实不太简单。并不是所有的网页浏览器都能直接显示PDF文件,有的会让用户下载,有的会自己显示,还有的会嵌入外部的PDF查看器,或者启动一个外部的PDF查看器。总之,没有一种统一的方法可以在所有浏览器中把PDF嵌入到HTML里,这样的话就无法同时显示其他文本和PDF内容。
一个可以在所有浏览器上都能用的解决办法是,把PDF的页面在服务器上转换成图片,然后把这些图片发送给用户。这会对服务器造成一些压力,比如处理器、内存、磁盘缓存和带宽等。
一些现代的支持HTML5的浏览器可以使用Mozilla的pdf.js在一个画布元素上渲染PDF。
对于其他浏览器,你可以尝试使用<embed>
或<object>
来调用Adobe的插件,具体可以参考Adobe的《PDF开发者博客》。
在服务器上渲染页面
要把PDF页面渲染并作为图片提供,需要在服务器上安装一些软件,以便查询页面数量并提取和渲染特定页面为图片。
可以使用pdfinfo
这个程序(来自Xpdf)来确定页面数量,或者使用libpoppler的命令行工具。将PDF文件中的页面转换为JPG图片可以用ImageMagick工具中的convert
命令。下面是一个使用这些程序的简单CGI程序:
#!/usr/bin/env python
import cgi
import cgitb; cgitb.enable()
import os
from itertools import imap
from subprocess import check_output
PDFINFO = '/usr/bin/pdfinfo'
CONVERT = '/usr/bin/convert'
DOC_ROOT = '/home/bj/Documents'
BASE_TEMPLATE = (
'Content-type: text/html\n\n'
'<html><head><title>{title}</title></head><body>{body}</body></html>'
)
PDF_PAGE_TEMPLATE = (
'<h1>{filename}</h1>'
'<p>{prev_link} {page}/{page_count} {next_link}</p>'
'<p><img src="{image_url}" style="border: solid thin gray;"></p>'
)
SCRIPT_NAME = os.environ['SCRIPT_NAME']
def create_page_url(filename, page_number, type_):
return '{0}?file={1}&page={2}&type={3}'.format(
cgi.escape(SCRIPT_NAME, True),
cgi.escape(filename, True),
page_number,
type_
)
def create_page_link(text, filename, page_number):
text = cgi.escape(text)
if page_number is None:
return '<span style="color: gray;">{0}</span>'.format(text)
else:
return '<a href="{0}">{1}</a>'.format(
create_page_url(filename, page_number, 'html'), text
)
def get_page_count(filename):
def parse_line(line):
key, _, value = line.partition(':')
return key, value.strip()
info = dict(
imap(parse_line, check_output([PDFINFO, filename]).splitlines())
)
return int(info['Pages'])
def get_page(filename, page_index):
return check_output(
[
CONVERT,
'-density', '96',
'{0}[{1}]'.format(filename, page_index),
'jpg:-'
]
)
def send_error(message):
print BASE_TEMPLATE.format(
title='Error', body='<h1>Error</h1>{0}'.format(message)
)
def send_page_html(_pdf_path, filename, page_number, page_count):
body = PDF_PAGE_TEMPLATE.format(
filename=cgi.escape(filename),
page=page_number,
page_count=page_count,
image_url=create_page_url(filename, page_number, 'jpg'),
prev_link=create_page_link(
'<<', filename, page_number - 1 if page_number > 1 else None
),
next_link=create_page_link(
'>>',
filename,
page_number + 1 if page_number < page_count else None
)
)
print BASE_TEMPLATE.format(title='PDF', body=body)
def send_page_image(pdf_path, _filename, page_number, _page_count):
image_data = get_page(pdf_path, page_number - 1)
print 'Content-type: image/jpg'
print 'Content-Length:', len(image_data)
print
print image_data
TYPE2SEND_FUNCTION = {
'html': send_page_html,
'jpg': send_page_image,
}
def main():
form = cgi.FieldStorage()
filename = form.getfirst('file')
page_number = int(form.getfirst('page', 1))
type_ = form.getfirst('type', 'html')
pdf_path = os.path.abspath(os.path.join(DOC_ROOT, filename))
if os.path.exists(pdf_path) and pdf_path.startswith(DOC_ROOT):
page_count = get_page_count(pdf_path)
page_number = min(max(1, page_number), page_count)
TYPE2SEND_FUNCTION[type_](pdf_path, filename, page_number, page_count)
else:
send_error(
'<p>PDF file <em>{0!r}</em> not found.</p>'.format(
cgi.escape(filename)
)
)
main()
还有Python的libpoppler绑定,所以可以很容易地用这个模块替换掉对外部pdfinfo
程序的调用。它还可以用来提取更多页面信息,比如PDF页面上的链接,以便为它们创建HTML图片地图。如果安装了libcairo的Python绑定,甚至可以在不使用外部进程的情况下直接渲染页面。