表と画像が混在するレポートを作成しています。画像 [実際にはグラフ] は .png 形式でファイルシステムに保存されます。
実際に PDF をレンダリングするメソッドは次のとおりです。
def _render_report(report_data):
file_name = get_file_name() # generate random filename for report
rpt = Report(settings.MEDIA_ROOT + os.sep + file_name)
Story = []
for (an, sam, event), props in report_data.iteritems():
Story.append(Paragraph("%s - sample %s results for %s" % (an.name, sam.name, event.name), styles["Heading2"]))
data_list = [['Lab', 'Method', 'Instrument', 'Unit', 'Raw Result', 'Converted Result', 'Outlier']]
for (index, series) in props['frame'].iterrows():
data_list.append(_format([
Paragraph(Lab.objects.get(pk=series['labs']).name, styles['BodyText']),
Paragraph(Method.objects.get(pk=series['methods']).name, styles['BodyText']),
Paragraph(Instrument.objects.get(pk=series['instruments']).name, styles['BodyText']),
Paragraph(Unit.objects.get(pk=series['units']).name, styles['BodyText']),
series['raw_results'],
series['results'],
series['outlier']
]))
table = Table(data_list, colWidths=[45 * mm, 35 * mm, 35 * mm, 25 * mm, 35 * mm, 35 * mm, 35 * mm], repeatRows=1)
Story.append(table)
Story.append(PageBreak())
if props['graph'] is not None:
Story.append(Image("/tmp/%s" % props['graph'], width=10 * inch, height=6 * inch))
Story.append(PageBreak())
rpt.draw(Story, onFirstPage=setup_header_and_footer, onLaterPages=setup_header_and_footer)
return file_name
背景情報
- ページは A4 として横向きに設定されています
- 私の開発環境は virtualenv です。PIL 1.1.7 と reportlab 2.6 がインストールされ、機能している
上記で使用されている「レポート」クラスは、
SimpleDocTemplate
いくつかのデフォルトを設定するが、SimpleDocTemplate のbuild
実装に委譲する単純な薄いラッパーです。そのコードは次のとおりです。class Report(object): def __init__(self, filename, doctitle="Report", docauthor="<default>", docsubject="<default>", doccreator="<default>", orientation="landscape", size=A4): DEFAULTS = { 'leftMargin' : 10 * mm, 'rightMargin' : 10 * mm, 'bottomMargin' : 15 * mm, 'topMargin' : 36 * mm, 'pagesize' : landscape(size) if orientation == "landscape" else portrait(size), 'title' : doctitle, 'author' : docauthor, 'subject' : docsubject, 'creator' : doccreator } self.doc = SimpleDocTemplate(filename, **DEFAULTS) def draw(self, flowables, onFirstPage=setup_header_and_footer, onLaterPages=setup_header_and_footer): self.doc.build(flowables, onFirstPage=setup_header_and_footer, onLaterPages=setup_header_and_footer, canvasmaker=NumberedCanvas)
私がすでに見たもの
- イメージがディスク上に存在することを確認しました。パスは完全修飾パスです。
- PIL がインストールされており、画像を正しく読み取ることができます
- 画像に割り当てられたスペースは十分です。計算で確認しました。また、画像サイズを大きくすると、ReportLab は Image Flowable が大きすぎると文句を言います。現在の寸法が収まるはずです。
- 改ページありと改ページなしでテストしました。彼らは何の違いもないようです
問題
表、見出し、およびページ テンプレートは正常にレンダリングされますが、画像は空白です。本日、[このレポートで使用するテンプレートを設定するときに]この問題に遭遇しました。canvas.drawInlineImage(...
回避策は、の代わりに使用することでしcanvas.DrawImage(...
た。したがって、セットアップに問題があるように見えます。デバッグ方法についていくつかの指針を使用できます。
アップデート
このリンクされた質問で使用されているのと同じ回避策のバリアントを適用することができました(canvas.drawInlineImage
の代わりに使用しcanvas.drawImage
ます。次のように「イメージ」をサブクラス化しました。
class CustomImage(Image):
"""
Override - to use inline image instead; inexplicable bug with non inline images
"""
def draw(self):
lazy = self._lazy
if lazy>=2: self._lazy = 1
self.canv.drawInlineImage(self.filename,
getattr(self,'_offs_x',0),
getattr(self,'_offs_y',0),
self.drawWidth,
self.drawHeight
)
if lazy>=2:
self._img = None
self._lazy = lazy
「stock」Image クラスからの唯一の変更点は、1 行だけです。以前の場所を使用してself.canv.drawInlineImage
いself.canvas.drawImage
ます。これは、画像が最終的に PDF に表示されるという意味で「機能」します。なぜ動かdrawImage
ないのかは謎のままです。
@PedroRomano の提案 (画像が RGBA であることを確認するため) を試し、PNG の代わりに JPEG 画像を試しました。これらは違いはありませんでした。