Search code examples
itext

How to resize html content so it will fit in A4 pdf?


Having issue with setting content to A4 pdf because of it size. Things i've tried : overflow-wrap,word-wrap ,custom customSplitCharacter class,setting max width of html,table,body. Are there any ideas how to set pdf size so table will automatically fit into it (without scrolling)? My itext dependencies: itext7-core(7.1.13), html2pdf (3.0.2),itextpdf(5.5.13.2)

Pdfview: Text Htmlview: Text

  public byte[] testingGetPDFInByte() {
    String html = new String(testing('', 1, 1,
        Collections.emptyList()).toByteArray());

    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    WriterProperties writerProperties = new WriterProperties();
    writerProperties.addXmpMetadata();

    PdfWriter pdfWriter = new PdfWriter(baos, writerProperties);
    PdfDocument pdfDoc = new PdfDocument(pdfWriter);
    pdfDoc.setDefaultPageSize(PageSize.A4);
    FontProvider fontProvider = new DefaultFontProvider(true, true, false);
    genDocConfigProperties.getFontPaths().forEach(fontProvider::addFont);

    ConverterProperties props = new ConverterProperties();
    props.setFontProvider(fontProvider);
    props.setImmediateFlush(false);

    final com.itextpdf.layout.Document document = HtmlConverter.convertToDocument(html, pdfDoc, props);
    document.flush();
    document.close();
    return baos.toByteArray();  
}

Table part of html:

        <xsl:variable name="stl" select="'border:1px solid black;padding:5px;page-break-inside:avoid;max-width:30px;word-wrap: break-word;vertical-align:top;'" />
<table style="border-collapse: collapse;margin:5px;table-layout: fixed;">
  <tr style="{$stl}">
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">№</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Дата прибытия</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Станция отправления</span>
    </td>
    <td style="{$stl}" colspan="3">
      <span style="font-weight: bold;">СС</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Дата отправления</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Станция отправления</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Код операции</span>
    </td>
    <td style="{$stl}" colspan="3">
      <span style="font-weight: bold;">Пассажир</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Стоимость места</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Номер места</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Номер и тип привилегии</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Дата продажи</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Терминал</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">Билет</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">№ поезда</span>
    </td>
    <td style="{$stl}" rowspan="2">
      <span style="font-weight: bold;">№ вагона</span>
    </td>
  </tr>
  <tr style="{$stl}">
    <td style="{$stl}">
      <span style="font-weight: bold;">Код</span>
    </td>
    <td style="{$stl}">
      <span style="font-weight: bold;">Описание</span>
    </td>
    <td style="{$stl}">
      <span style="font-weight: bold;">Продажа</span>
    </td>
    <td style="{$stl}">
      <span style="font-weight: bold;">ФИО</span>
    </td>
    <td style="{$stl}">
      <span style="font-weight: bold;">Тип документа</span>
    </td>
    <td style="{$stl}">
      <span style="font-weight: bold;">№ документа</span>
    </td>
  </tr>
  <xsl:for-each select="responseTikets">
    <tr style="{$stl}">
      <td style="{$stl}">
        <xsl:value-of select="position()" />
      </td>


Solution

  • There may be several ways of solving your issue:

    1. Try to set specified properties for in html file.
    2. Try to use the proposed code below to suit html table in pdf with A4 page size. Here the table is scaled and put as formXObject in Canvas and fitted into rectangle with set size. So if table width increase, it should be scaled and fit the pdf page size.
    try (InputStream is = FileUtil.getInputStreamForFile(path to html file)) {
        List<IElement> iElements = HtmlConverter.convertToElements(is);
        Div div = new Div();
        
        for (IElement elem : iElements) {
            if (elem instanceof IBlockElement) {
                div.add((IBlockElement) elem);
            } else if (elem instanceof Image) {
                div.add((Image) elem);
            } else if (elem instanceof AreaBreak) {
                div.add((AreaBreak) elem);
            } else {
                Assert.fail("The #convertToElements method gave element which is unsupported as root element, it's unexpected.");
            }
        }
        PageSize pageSize = PageSize.A4;
        
        try (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(output pdf path))) {
            pdfDocument.setDefaultPageSize(pageSize);
            PdfCanvas pdfCanvas = new PdfCanvas(new PdfStream(), new PdfResources(), pdfDocument);
            try (Canvas canvas = new Canvas(pdfCanvas, new Rectangle(Float.MAX_VALUE, Float.MAX_VALUE))) {
                Rectangle htmlSize = div.createRendererSubTree().setParent(canvas.getRenderer())
                    .layout(new LayoutContext(new LayoutArea(1, new Rectangle(
                        pageSize.getWidth(),
                        pageSize.getHeight()
                    ))))
                        .getOccupiedArea()
                        .getBBox();
        
                PdfFormXObject formXObject = new PdfFormXObject(htmlSize);
                try (Canvas canvasForDiv = new Canvas(formXObject, pdfDocument)) {
                    canvasForDiv.add(div);
                }
    
                PdfPage pageNewDoc = pdfDocument.addNewPage();
                PdfCanvas canvasToAddXObject = new PdfCanvas(pageNewDoc);
               canvasToAddXObject.addXObjectFittedIntoRectangle(formXObject, fit(new Rectangle(0, 0, formXObject.getWidth(), formXObject.getHeight()), pageNewDoc.getPageSize()));
            }
        }
    }
    
    private static Rectangle fit(Rectangle img, Rectangle page) {
        float ws = page.getWidth()/img.getWidth();
        float hs =  page.getHeight()/img.getHeight();
        float scale = Math.min(ws, hs);
            
        return new Rectangle(0,page.getHeight()-img.getHeight()*scale, img.getWidth()*scale, img.getHeight()*scale);
    }
    

    Also you can use rotated page size (ex. PageSize.A4.rotate()).