PDF 報表列印

      在〈PDF 報表列印〉中尚無留言

列印報表

報表列印是程式設計師的痛, 難寫又難調整. 在此本篇提供一個方式, 將要列印的資料先寫入pdf檔案進行編排, 然後再將整個pdf檔案列出

要讓Python能讀取寫入pdf, 需安裝reportlab套件, 此套件適用於Windows及Ubuntu

Windows : pip install reportlab
Linux : sudo pip3 install reportlab

import

開頭需先 import一些常用的套件, 如下

import copy
import time
from reportlab.lib import utils
from reportlab.lib.enums import TA_JUSTIFY, TA_CENTER, TA_LEFT
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, PageBreak, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.lineplots import LinePlot
from reportlab.graphics.widgets.markers import makeMarker

from reportlab.lib.units import inch
import reportlab.rl_config
reportlab.rl_config.warnOnMissingFontGlyphs = 0
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from reportlab.lib import fonts
import platform
from datetime import datetime

字型

Windows跟Linux的字型存放位置不一樣, 所以需先使用 platform.system()判斷作業系統, 再使用pdfmetrics.registerFont()註冊字型的位置

useros=platform.system()
if useros == "Linux":
    pdfmetrics.registerFont(TTFont('hei', '/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc')) 
else: 
    pdfmetrics.registerFont(TTFont('hei', 'simsun.ttc'))

SimpleDocTemplate

接下來使用 SimpleDocTemplate產生一個文件檔doc, 參數需傳入檔案名稱及紙張格式(A4, A5…)

doc = SimpleDocTemplate("tmp.pdf", pagesize=letter, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18)

內容

doc裏要包含的內容及格式, 使用 list 容器儲存, 此例使用 story變數. 然後再使用 doc.build(story)將資料放入 doc裏並儲存成檔案

story = []
story.append(Paragraph('富立金履歷管制系統', style_title))
story.append(Spacer(1, 15))
doc.build(story)

內容可以包含Title, 段落, 表格, 圖片等資訊, 將分別說明如下

表格

表格裏要列印的資料, 先使用二維list儲存, 再將資料使用Table置入. 表格常用的格式有FONTNAME : 字型名稱
FONTSIZE : 字型大小
GRID : 外框線
BOX : 內框線
SPAN : 要合併的儲存格
VALIGN : 垂直對齊方式, 有 TOP, MIDDLE, BOTTOM三種

每一個儲存格都有其座標, 座標格式為(行, 列), 左上角為(0,0), 第一列往右依序為(1, 0), (2, 0), (3, 0). 右下角的座標除了使用行列外, 亦可使用負數表示, 最右下角座標為(-1,-1)

data=[
    ['尺寸', info['dimension']],
    ['顏色', info['color']],
    ['版號', info['version']],
    ['半打', '{0}(KG)'.format(info['wetHalfDozen']),'一打', '{0}(KG)'.format(info['wetDozen'])],
    ['淨重', '{0}'.format(info['net'])],
    ['數量', '{0}打 {1}雙'.format(info['qtyDozen'], info['qtyPair'])]
]
t = Table(data, colWidths=[70, 150, 70, 150], rowHeights=[80,80,80,80,80, 80],
style=[
    ('FONTNAME', (0, 0), (-1, -1), 'hei'),
    ('FONTSIZE', (0, 0), (-1, -1), 20),
    ('GRID', (0, 0), (-1, -1), 1, colors.black),
    ('BOX', (0, 0), (-1, -1), 2, colors.black),
    ('SPAN', (1, 0), (3, 0)),
    ('SPAN', (1, 1), (3, 1)),
    ('SPAN', (1, 2), (3, 2)),
    ('SPAN', (1, 4), (3, 4)),
    ('SPAN', (1, 5), (3, 5)),
    ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
])
story.append(t)

完整代碼如下

import copy
import time
from reportlab.lib import utils
from reportlab.lib.enums import TA_JUSTIFY, TA_CENTER, TA_LEFT
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, PageBreak, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.lineplots import LinePlot
from reportlab.graphics.widgets.markers import makeMarker

from reportlab.lib.units import inch
import reportlab.rl_config
reportlab.rl_config.warnOnMissingFontGlyphs = 0
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from reportlab.lib import fonts
import platform
from datetime import datetime
class ResumeLabel():
    def __init__(self, info):
        useros=platform.system()

        if useros == "Linux":
            pdfmetrics.registerFont(TTFont('hei', '/usr/share/fonts-droid-fallback/truetype/DroidSansFallback.ttf'))
        else:
            pdfmetrics.registerFont(TTFont('hei', 'simsun.ttc'))

        fonts.addMapping('song', 1, 0, 'hei')
        fonts.addMapping('song', 1, 1, 'hei')
        stylesheet = getSampleStyleSheet()
        normalStyle = copy.deepcopy(stylesheet['Normal'])
        normalStyle.fontName ='hei'
        normalStyle.fontSize = 20

        doc = SimpleDocTemplate("tmp.pdf", pagesize=letter, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18)
        story = []
        styles = getSampleStyleSheet()
        styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY))

        style_title = ParagraphStyle('parrafos',
                            alignment = TA_CENTER,
                            fontSize = 24,
                            fontName="hei")

        style_left = ParagraphStyle('parrafos',
                            alignment = TA_LEFT,
                            fontSize = 12,
                            fontName="hei")

        story.append(Paragraph('Mahal履歷管制系統', style_title))
        story.append(Spacer(1, 15))

        img=Image("tmp.png", 2*inch, 0.5*inch)
        story.append(img)
        story.append(Paragraph(info["barcode"], style_title))
        story.append(Spacer(1, 12))


        story.append(Paragraph('Date : {0}'.format(datetime.now().strftime("%Y-%m-%d %H:%M:%S")), style_left))
        story.append(Spacer(1, 12))

        data=[
            ['尺寸', info['dimension']],
            ['顏色', info['color']],
            ['版號', info['version']],
            ['半打', '{0}(KG)'.format(info['wetHalfDozen']),'一打', '{0}(KG)'.format(info['wetDozen'])],
            ['淨重', '{0}'.format(info['net'])],
            ['數量', '{0}打            {1}雙'.format(info['qtyDozen'], info['qtyPair'])]
        ]
        t = Table(data, colWidths=[70, 150, 70, 150], rowHeights=[80,80,80,80,80, 80],
                  style=[
                      ('FONTNAME', (0, 0), (-1, -1), 'hei'),
                      ('FONTSIZE', (0, 0), (-1, -1), 20),
                      ('GRID', (0, 0), (-1, -1), 1, colors.black),
                      ('BOX', (0, 0), (-1, -1), 2, colors.black),
                      ('SPAN', (1, 0), (3, 0)),
                      ('SPAN', (1, 1), (3, 1)),
                      ('SPAN', (1, 2), (3, 2)),
                      ('SPAN', (1, 4), (3, 4)),
                      ('SPAN', (1, 5), (3, 5)),
                      ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
                      ])
        story.append(t)
        doc.build(story)

todo

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *