1

プロジェクトに iTextPDF + FreeMarker を使用しています。基本的に、HTML テンプレートをロードして FreeMarker で埋め、iTextPDF で PDF にレンダリングしますXMLWorker

テンプレートは次のとおりです。

<html>
    <body style="font-family; ${fontName}">
        <table>
            <tr>
                <td style="text-align: right">${timestampLabel}&nbsp;</td>
                <td><b>${timestampValue}</b></td>
            </tr>
            <tr>
                <td style="text-align: right">${errorIdLabel}&nbsp;</td>
                <td><b>${errorIdValue}</b></td>
            </tr>
            <tr>
                <td style="text-align: right">${systemIdLabel}&nbsp;</td>
                <td><b>${systemIdValue}</b></td>
            </tr>
            <tr>
                <td style="text-align: right">${descriptionLabel}&nbsp;</td>
                <td><b>${descriptionValue}</b></td>
            </tr>
        </table>
    </body>
</html>

そして、これは私のコードです:

SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

String errorId = "ERROR-01";
String systemId = "SYSTEM-01";
String description = "A SHORT DESCRIPTION OF THE ISSUE";

Map<String, String> parametersMap = new HashMap<String, String>();
parametersMap.put("fontName", fontName);  //valid font name

parametersMap.put("timestampLabel",   "   TIMESTAMP:");
parametersMap.put("errorIdLabel",     "    ERROR ID:");
parametersMap.put("systemIdLabel",    "   SYSTEM ID:");
parametersMap.put("descriptionLabel", " DESCRIPTION:");

parametersMap.put("timestampValue", DATE_FORMAT.format(new Date()));
parametersMap.put("errorIdValue", errorId);
parametersMap.put("systemIdValue", systemId);
parametersMap.put("descriptionValue", description);

FreeMarkerRenderer renderer = new FreeMarkerRenderer(); //A utility class
renderer.loadTemplate(errorTemplateFile);               //the file exists
String rendered = renderer.render(parametersMap);

File temp = File.createTempFile("document", ".pdf");
file = new FileOutputStream(temp);
Document document = new Document();

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
document.setPageSize(new Rectangle(290f, 150f));
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

document.setMargins(10, 10, 10, 10);
PdfWriter writer = PdfWriter.getInstance(document, file);
document.open();
InputStream is = new ByteArrayInputStream(rendered.getBytes());


XMLWorkerFontProvider provider = new XMLWorkerFontProvider();
provider.register(fontFile); //the file exists
FontFactory.setFontImp(provider);
byte[] errorStyle = getErrorStyleByteArray(); //returns a byte array from a css file (works)

XMLWorkerHelper helper = XMLWorkerHelper.getInstance();
helper.parseXHtml(writer, document, is, new ByteArrayInputStream(errorStyle), provider);

document.close();
file.close();

このコードは正常に動作しますが、高さが固定されていると問題が発生します。

IE では、次のように言いましょう。

errorId = "ERROR-01"
systemId = "SYSTEM-01"
description = "A SHORT DESCRIPTION OF THE ISSUE"

生成されるドキュメントは次のとおりです。

ここに画像の説明を入力

代わりに私が使用する場合

errorId = "ERROR-01"
systemId = "SYSTEM-01"
description = "A SHORT DESCRIPTION OF THE ISSUE. THIS IS MULTILINE AND IT SHOULD STAY ALL IN THE SAME PDF PAGE."

生成されるドキュメントは次のとおりです。

ここに画像の説明を入力

ご覧のとおり、最後のドキュメントには 2 つのページがあります。コンテンツの高さに応じて高さが変わるページを 1 つだけにしたいと思います。

iTextでこのようなことは可能ですか?

4

1 に答える 1

2

そのページにコンテンツを追加した後でページ サイズを変更することはできません。これを回避する 1 つの方法は、ドキュメントを 2 つのパスで作成することです。最初にドキュメントを作成してコンテンツを追加し、次にドキュメントを操作してページ サイズを変更します。すぐに答える時間があれば、それが私の最初の返事だったでしょう。

時間をかけて考えた結果、2 回のパスを必要としないより良い解決策を見つけました。HtmlAdjustPageSizeを見てください。

この例では、まず次のElementメソッドを使用してコンテンツをオブジェクトのリストに解析します。

public ElementList parseHtml(String html, String css) throws IOException {
    // CSS
    CSSResolver cssResolver = new StyleAttrCSSResolver();
    CssFile cssFile = XMLWorkerHelper.getCSS(new ByteArrayInputStream(css.getBytes()));
    cssResolver.addCss(cssFile);

    // HTML
    CssAppliers cssAppliers = new CssAppliersImpl(FontFactory.getFontImp());
    HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
    htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
    htmlContext.autoBookmark(false);

    // Pipelines
    ElementList elements = new ElementList();
    ElementHandlerPipeline end = new ElementHandlerPipeline(elements, null);
    HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, end);
    CssResolverPipeline cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);

    // XML Worker
    XMLWorker worker = new XMLWorker(cssPipeline, true);
    XMLParser p = new XMLParser(worker);
    p.parse(new ByteArrayInputStream(html.getBytes()));

    return elements;
}

注:このメソッドを何度もコピーして貼り付けたので、XMLWorkerHelperクラスの静的メソッドにすることにしました。次の iText リリースで利用できるようになります。

重要:私は約束したことを実行しました。このメソッドは XML Worker リリースで利用できるようになりました。

テスト目的で、StringHTML と CSS に静的な値 を使用しました。

public static final String HTML = "<table>" +
    "<tr><td class=\"ra\">TIMESTAMP</td><td><b>2014-11-28 11:06:09</b></td></tr>" +
    "<tr><td class=\"ra\">ERROR ID</td><td><b>ERROR-01</b></td></tr>" +
    "<tr><td class=\"ra\">SYSTEM ID</td><td><b>SYSTEM-01</b></td></tr>" +
    "<tr><td class=\"ra\">DESCRIPTION</td><td><b>TEST WITH A VERY, VERY LONG DESCRIPTION LINE THAT NEEDS MULTIPLE LINES</b></td></tr>" +
    "</table>";
public static final String CSS = "table {width: 200pt; } .ra { text-align: right; }";
public static final String DEST = "results/xmlworker/html_page_size.pdf";

あなたが扱っている HTML と多かれ少なかれ似ている HTML を取り上げたことがわかります。

この HTML と CSS を次のように解析しますElementList

ElementList el = parseHtml(HTML, CSS);

または、XML Worker 5.5.4 以降:

ElementList el = XMLWorkerHelper.parseToElementList(HTML, CSS);

ここまでは順調ですね。これを除いて、あなたがまだ知らなかったことは何も言っていませんel

  1. ColumnTextシミュレーション モードでリストを追加します。これColumnTextはまだどのドキュメントやライターにも関連付けられていません。これを行う唯一の目的は、垂直方向にどれだけのスペースが必要かを知ることです。
  2. ColumnTextリストを実際に追加します。これColumnTextは、シミュレーション モードで得られた結果を使用して定義したサイズのページに正確に収まります。

いくつかのコードは、私が何を意味するかを明確にします:

// I define a width of 200pt
float width = 200;
// I define the height as 10000pt (which is much more than I'll ever need)
float max = 10000;
// I create a column without a `writer` (strange, but it works)
ColumnText ct = new ColumnText(null);
ct.setSimpleColumn(new Rectangle(width, max));
for (Element e : el) {
    ct.addElement(e);
}
// I add content in simulation mode
ct.go(true);
// Now I ask the column for its Y position
float y = ct.getYLine();

上記のコードは、実際に追加されるのページ サイズと列yのサイズを定義するために使用される値の取得:DocumentColumnText

Rectangle pagesize = new Rectangle(width, max - y);
// step 1
Document document = new Document(pagesize, 0, 0, 0, 0);
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
// step 3
document.open();
// step 4
ct = new ColumnText(writer.getDirectContent());
ct.setSimpleColumn(pagesize);
for (Element e : el) {
    ct.addElement(e);
}
ct.go();
// step 5
document.close();

完全なHtmlAdjustPageSize.javaコードをダウンロードして、 の値を変更してくださいHTML。これにより、ページ サイズが異なることがわかります。

于 2014-11-30T08:58:48.703 に答える