3

表と画像が混在するレポートを作成しています。画像 [実際にはグラフ] は .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.drawInlineImageself.canvas.drawImageます。これは、画像が最終的に PDF に表示されるという意味で「機能」します。なぜ動かdrawImageないのかは謎のままです。

@PedroRomano の提案 (画像が RGBA であることを確認するため) を試し、PNG の代わりに JPEG 画像を試しました。これらは違いはありませんでした。

4

2 に答える 2

1

最終的に、カスタムImageサブクラスを使用してこの問題を解決しました。

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

EPS などのベクター グラフィックス形式でグラフを保存する、JPEG として保存する、アルファ チャネルを使用する場合と使用しない場合の PNG として保存する場合、すべて違いがないように見えました。

于 2012-10-29T09:19:29.623 に答える
0

最適な解決策は、reportlabでサポートされているpostscriptのようなベクトル形式でグラフを生成することです。多くのUNIXソフトウェアでこれをすぐに実行でき、Windowsでは優れたPDFCreatorを使用できます。

グラフにラスター画像を使用する必要がある場合は、画像をJPEG形式に変換してみてください。これらは、 DCTDecodeフィルターを使用してPDFファイルに簡単に埋め込むことができます。(これは、例えばjpeg2pdf が行うことです。)

于 2012-10-22T21:28:12.003 に答える