3

テキストと SVG グラフを PDF にエクスポートしようとしています。iTextとbatikがこれを行うことができることがわかりました。それでやってみたのですが、グラフを入れるたびに異常に小さくなってしまいました。

私のコードに問題があるのではないかと考えたので、Vaadin のサンプルコードを試してみることにしました。

public class PdfExportDemo {

private String fontDirectory = null;
private final String baseFont = "Arial";

private PdfWriter writer;
private Document document;

private Font captionFont;
private Font normalFont;

private String svgStr;

/**
 * Writes a PDF file with some static example content plus embeds the chart
 * SVG.
 * 
 * @param pdffilename
 *            PDF's filename
 * @param svg
 *            SVG as a String
 * @return PDF File
 */
public File writePdf(String pdffilename, String svg) {
    svgStr = svg;

    document = new Document();
    document.addTitle("PDF Sample");
    document.addCreator("Vaadin");
    initFonts();

    File file = null;
    try {
        file = writeToFile(pdffilename, document);

        document.open();

        writePdfContent();

        document.close();
    } catch (DocumentException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return file;
}

/**
 * Get Font directory that will be checked for custom fonts.
 * 
 * @return Path to fonts
 */
public String getFontDirectory() {
    return fontDirectory;
}

/**
 * Set Font directory that will be checked for custom fonts.
 * 
 * @param fontDirectory
 *            Path to fonts
 */
public void setFontDirectory(String fontDirectory) {
    this.fontDirectory = fontDirectory;
}

private void initFonts() {
    if (fontDirectory != null) {
        FontFactory.registerDirectory(fontDirectory);
    }

    captionFont = FontFactory.getFont(baseFont, 10, Font.BOLD, new Color(0,
            0, 0));
    normalFont = FontFactory.getFont(baseFont, 10, Font.NORMAL, new Color(
            0, 0, 0));
}

private File writeToFile(String filename, Document document)
        throws DocumentException {
    File file = null;
    try {
        file = File.createTempFile(filename, ".pdf");
        file.deleteOnExit();
        FileOutputStream fileOut = new FileOutputStream(file);
        writer = PdfWriter.getInstance(document, fileOut);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return file;
}

private void writePdfContent() throws DocumentException, IOException {
    Paragraph caption = new Paragraph();
    caption.add(new Chunk("Vaadin Charts Export Demo PDF", captionFont));
    document.add(caption);

    Paragraph br = new Paragraph(Chunk.NEWLINE);
    document.add(br);

    Paragraph paragraph = new Paragraph();
    paragraph.add(new Chunk("This PDF is rendered with iText 2.1.7.",
            normalFont));
    document.add(paragraph);

    paragraph = new Paragraph();
    paragraph
            .add(new Chunk(
                    "Chart below is originally an SVG image created with Vaadin Charts and rendered with help of Batik SVG Toolkit.",
                    normalFont));
    document.add(paragraph);

    document.add(createSvgImage(writer.getDirectContent(), 400, 400));

    document.add(createExampleTable());
}

private PdfPTable createExampleTable() throws BadElementException {
    PdfPTable table = new PdfPTable(2);
    table.setHeaderRows(1);
    table.setWidthPercentage(100);
    table.setTotalWidth(100);

    // Add headers
    table.addCell(createHeaderCell("Browser"));
    table.addCell(createHeaderCell("Percentage"));

    // Add rows
    table.addCell(createCell("Firefox"));
    table.addCell(createCell("45.0"));
    table.addCell(createCell("IE"));
    table.addCell(createCell("26.8"));
    table.addCell(createCell("Chrome"));
    table.addCell(createCell("12.8"));
    table.addCell(createCell("Safari"));
    table.addCell(createCell("8.5"));
    table.addCell(createCell("Opera"));
    table.addCell(createCell("6.2"));
    table.addCell(createCell("Others"));
    table.addCell(createCell("0.7"));

    return table;
}

private PdfPCell createHeaderCell(String caption)
        throws BadElementException {
    Chunk chunk = new Chunk(caption, captionFont);
    Paragraph p = new Paragraph(chunk);
    p.add(Chunk.NEWLINE);
    p.add(Chunk.NEWLINE);

    PdfPCell cell = new PdfPCell(p);
    cell.setBorder(0);
    cell.setBorderWidthBottom(1);
    cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
    cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
    return cell;
}

private PdfPCell createCell(String value) throws BadElementException {
    PdfPCell cell = new PdfPCell(new Phrase(new Chunk(value, normalFont)));
    cell.setBorder(0);
    cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
    return cell;
}

private Image drawUnscaledSvg(PdfContentByte contentByte)
        throws IOException {

    // First, lets create a graphics node for the SVG image.
    GraphicsNode imageGraphics = buildBatikGraphicsNode(svgStr);

    // SVG's width and height
    float width = (float) imageGraphics.getBounds().getWidth();
    float height = (float) imageGraphics.getBounds().getHeight();

    // Create a PDF template for the SVG image
    PdfTemplate template = contentByte.createTemplate(width, height);
    // Create Graphics2D rendered object from the template
    Graphics2D graphics = template.createGraphics(width, height);
    try {
        // SVGs can have their corner at coordinates other than (0,0).
        Rectangle2D bounds = imageGraphics.getBounds();
        graphics.translate(-bounds.getX(), -bounds.getY());

        // Paint SVG GraphicsNode with the 2d-renderer.
        imageGraphics.paint(graphics);

        // Create and return a iText Image element that contains the SVG
        // image.
        return new ImgTemplate(template);
    } catch (BadElementException e) {
        throw new RuntimeException("Couldn't generate PDF from SVG", e);
    } finally {
        // Manual cleaning (optional)
        graphics.dispose();
    }
}

/**
 * Use Batik SVG Toolkit to create GraphicsNode for the target SVG.
 * <ol>
 * <li>Create SVGDocument</li>
 * <li>Create BridgeContext</li>
 * <li>Build GVT tree. Results to GraphicsNode</li>
 * </ol>
 * 
 * @param svg
 *            SVG as a String
 * @return GraphicsNode
 * @throws IOException
 *             Thrown when SVG could not be read properly.
 */
private GraphicsNode buildBatikGraphicsNode(String svg) throws IOException {
    UserAgent agent = new UserAgentAdapter();

    SVGDocument svgdoc = createSVGDocument(svg, agent);

    DocumentLoader loader = new DocumentLoader(agent);
    BridgeContext bridgeContext = new BridgeContext(agent, loader);
    bridgeContext.setDynamicState(BridgeContext.STATIC);

    GVTBuilder builder = new GVTBuilder();

    GraphicsNode imageGraphics = builder.build(bridgeContext, svgdoc);

    return imageGraphics;
}

private SVGDocument createSVGDocument(String svg, UserAgent agent)
        throws IOException {
    SVGDocumentFactory documentFactory = new SAXSVGDocumentFactory(
            agent.getXMLParserClassName(), true);

    SVGDocument svgdoc = documentFactory.createSVGDocument(null,
            new StringReader(svg));
    return svgdoc;
}

private Image createSvgImage(PdfContentByte contentByte,
        float maxPointWidth, float maxPointHeight) throws IOException {
    Image image = drawUnscaledSvg(contentByte);
    image.scaleToFit(maxPointWidth, maxPointHeight);
    return image;
}
}

しかし、これを行うと、まだ小さなグラフが表示されます。アプリのデバッグを試みましたが、グラフのサイズは実際には 10000x600 で、収まるようにスケーリングしようとしました。

そこで、手動でサイズを 400x600 のようにサイコロなしで設定してみました。SVGのサイズを強制しようとしました-サイコロはありません。大きすぎると、1x1cm の小さな箱に影ができてしまうだけだと思います。この例の出力は次のとおりです。

PDF結果

ズーム

誰かが助けてくれることを本当に願っています。

UPDATE これらの2行を削除すると:

 Rectangle2D bounds = imageGraphics.getBounds();
 graphics.translate(-bounds.getX(), -bounds.getY());

サイズをハードコードすると、ちょっとうまくいきます。しかし、画像自体はまだ巨大で、収まりきらないようです。例を参照してください: ここに画像の説明を入力

4

0 に答える 0