Найти - Пользователи
Полная версия: Генерация pdf отчёта с помощью pisa
Начало » Python для новичков » Генерация pdf отчёта с помощью pisa
1
SoT
Необходимо сгенерировать PDF отчёт состоящий из скриншотов. Каждый скриншот должен быть на отдельной странице, внизу должно быть название страницы. Была выбрана библиотека pisa - позволяет использовать html для оформления шаблона. К сожалению исходные скриншоты могут быть разного размера, поэтому не получается выполнить требование один скриншот на страницу( он не обязан заполнять всю страницу, внизу может быть пустое место ). Как сделать с помощью html или css чтобы нижний блок под скриншотом заполнял оставшееся место страницы( Страницы формата А4 )

Вот рабочий код (все хранилось в отдельных модулях но для форума я свёл в один файлик) :

# -*- coding: utf-8 -*-
import re
import sys
import os
from datetime import date, timedelta, datetime
import requests
import lxml.html
import codecs
import ho.pisa as pisa
header = u'''
<html>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<head>
<style>
@page {
margin: 40px;
margin-left: 60px;
margin-bottom: 70px;
@frame footer {
-pdf-frame-content: footerContent;
bottom: 10px;
margin-left: 60px;
margin-right: 40px;
height: 40px;
}
}
@font-face {
font-family: courier;
src: url(fonts/Courier_New.ttf);
}
@font-face {
font-family: courier;
src: url(fonts/Courier_Bold.ttf);
font-weight: bold;
}
@font-face {
font-family: courier;
src: url(fonts/Courier_Bold_Italic.ttf);
font-weight: bold;
font-style: italic;
}
@font-face {
font-family: courier;
src: url(fonts/Courier_Italic.ttf);
font-style: italic;
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana.ttf);
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana_Bold.ttf);
font-weight: bold;
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana_Italic.ttf);
font-style: italic;
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana_Bold_Italic.ttf);
font-style: italic;
font-weight: bold;
}
img {
font-family: sans;
}
body, div {
font-family: verdana;
font-size: 14px;
color:#000;
background:#fff;
}
a[href] { color: #6da3bd; }
a[name] { color: #000000; font-size: 150%; text-decoration:none}
fieldset {border:0 solid transparent;}
input, select, textarea {
font-size: 100%;
font-family: verdana;
}
blockquote {
border-left:2px solid #bbb;
margin: .83em 10;
padding-left:15px;
clear: both;
}
ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,body,html,blockquote,fieldset,dl,dt,dd,caption {margin:0; padding:0;}
ul,ol {list-style: none;}
pre,code {font-size: 1em;}
h1, h2, h3, h4, h5, h6 {
color:#999999;
font-family: verdana;
font-weight:normal;
margin:0 0 0 0;
padding:0;
}
h1 {
font-size:162.5%;
letter-spacing:-1px;
margin-bottom:0.7em;
}
h2 {
font-size:150%;
}
h3 {
font-size: 137.5%;
}
h4 {
font-size: 120%;
}
h5 {
font-size: 110%;
}
h6 {
font-size: 100%;
}
pre {
font-size: 80%;
}
</style>
</head>
<body>
<div align="center"><img src="TEMP/header.png"></div>'''
footer = u'''
<div id="footerContent" align="right">
<hr>
Страница #<pdf:pagenumber>
</div>
</body>
</html>
'''
def go(content, filename):
    print '\n Prepare PDF...\n'
    content = header + content + footer
    #pisa.showLogging()
    pisa.CreatePDF(content.encode('UTF-8'), file(filename, 'wb'), raise_exception=False)
#f = open('1.html', 'w')
#f.write(topic)
#f.close()
content = ''
directory = './screenshots'
files = os.listdir(directory)
images = filter(lambda x: x.endswith('.png'), files)
for image in images:
    print image
    content += '<div align="center"><img src="./screenshots/' + image + '"></div><div align="center"><img src="w.png"></div>'
go(content, 'test.pdf')
P.s. w.png это прозрачная картинка большого размера, она заполняет пространство по высоте но к сожалению с маленькими скриншотами она не может заполнить всё пространство и поэтому получаются два скриншота на одной странице.
Может можно как то сделать с помощью этого примера https://github.com/chrisglass/xhtml2pdf/blob/master/doc/usage.rst ? (у меня не получилось)
SoT
Написал рабочее решение, если кому интересно завтра выложу его
4kpt
Интересно. Давайте. Пригодится.
Я бы искал решение через odfpy, но если есть готовое, почему бы не воспользоваться.
SoT
Это грубый прототип, т.к. сами скриншоты ещё не поступили. Но в случае чего его можно легко исправить. Использовал код из примеров отсюда https://github.com/chrisglass/xhtml2pdf/blob/master/doc/usage.rst . Одной страницы на листе добиваемся генерацией через html прозрачной картинки которая будет заполнять оставшуюся высоту страницы в зависимости от разрешения вставляемого скриншота.

# -*- coding: utf-8 -*-
from xhtml2pdf import pisa             # import python module
import os
import Image
sourceHtml = ''
directory = './screenshots'
files = os.listdir(directory)
images = filter(lambda x: x.endswith('.png'), files)
first = u"""
<html>
<head>
<style>
    @page {
        
        @frame header_frame 
{            -pdf-frame-content: header_content;
            left: 100pt; width: 557pt; top: 0pt; height: 100pt;
                            }
        @frame content_frame {          
            left: 50pt; width: 512pt; top: 90pt; height: 632pt;
                            }
        @frame footer_frame {           
            -pdf-frame-content: footer_content;
            left: 250pt; width: 512pt; top: 772pt; height: 20pt;
                            }
}
@font-face {
font-family: courier;
src: url(fonts/Courier_New.ttf);
}
@font-face {
font-family: courier;
src: url(fonts/Courier_Bold.ttf);
font-weight: bold;
}
@font-face {
font-family: courier;
src: url(fonts/Courier_Bold_Italic.ttf);
font-weight: bold;
font-style: italic;
}
@font-face {
font-family: courier;
src: url(fonts/Courier_Italic.ttf);
font-style: italic;
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana.ttf);
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana_Bold.ttf);
font-weight: bold;
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana_Italic.ttf);
font-style: italic;
}
@font-face {
font-family: verdana;
src: url(fonts/Verdana_Bold_Italic.ttf);
font-style: italic;
font-weight: bold;
}
img {
font-family: sans;
}
body, div {
font-family: verdana;
font-size: 14px;
color:#000;
background:#fff;
}
</style>
</head>
<body>
    <!-- Content for Static Frame 'header_frame' -->
    <div id="header_content"><img src="logo.png"></div>
    <!-- Content for Static Frame 'footer_frame' -->
    <div id="footer_content">
Страница <pdf:pagenumber> из <pdf:pagecount>
    </div>
    <img src=
"""
middle = u""""><br/>
    <img src="mini.png" width="680" height="
"""
end = u"""
">
</body>
</html>
"""
for image in images:
    print image
    parse_height = 0
    img = Image.open(directory+'/'+image)	
    width, height = img.size
    if width > 512 :
        new_height = height / (width/512)
        if new_height < 632 :
            parse_height = 632 - new_height
    sourceHtml +=  first + '"' + directory + '/' + image + middle + str(parse_height) + end
outputFilename = "test.pdf"
# Utility function
def convertHtmlToPdf(sourceHtml, outputFilename):
    # open output file for writing (truncated binary)
    resultFile = open(outputFilename, "w+b")
    # convert HTML to PDF
    pisaStatus = pisa.CreatePDF(
            sourceHtml.encode('UTF-8'),                # the HTML to convert
            dest=resultFile)           # file handle to recieve result
    # close output file
    resultFile.close()                 # close output file
    # return True on success and False on errors
    return pisaStatus.err
# Main program
if __name__=="__main__":
    pisa.showLogging()
    convertHtmlToPdf(sourceHtml, outputFilename)

для работы требуется pisa и все зависимости к ней.

А так же важный момент - чтобы русские буквы не отображались чёрными квадратиками импортируются шрифты
SoT
а ещё есть офигенный пример с хабра http://habrahabr.ru/post/111411/ - если кто то хочет начать работать с pisa то в этом рабочем примере красиво используются почти все функции
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB