danfickle / openhtmltopdf

An HTML to PDF library for the JVM. Based on Flying Saucer and Apache PDF-BOX 2. With SVG image support. Now also with accessible PDF support (WCAG, Section 508, PDF/UA)!

Home Page:https://danfickle.github.io/pdf-templates/index.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

max-width / max-height not redering correctly in pdf when height / width set in tag

swarl opened this issue · comments

commented

Version: 1.0.1

When in a html image tag the properties height and width are specified and css styles max-width (and max-height) is added, then the image is not rendered correctly in the pdf.

Reproduce with:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.LinkedHashMap;

import org.apache.commons.io.FileUtils;
import org.junit.Test;

import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
[...]
   @Test
   public void shouldAnswerWithTrue() throws URISyntaxException, IOException {

      String htmlContent = "<html>\n"
         + "<head>\n"
         + "    <style>\n"
         + "        img {\n"
         + "            max-height: 885px;\n"
         + "            max-width: 690px;\n"
         + "        }\n"
         + "    </style>\n"
         + "</head>\n"
         + "<body>\n"
         + "<div class=\"content\">\n"
         + "    <div>"
         + "        <p><span><span>Inline image:</span></span></p>\n"
         + "        <img height=\"310\" src=\"file:_2019-11-22_11-34-28.png\" width=\"700\"/>\n"
         //         + "        <img height=\"3301\" src=\"file:_2019-11-22_11-34-28.png\" width=\"1462\"/>\n"
         + "    </div>\n"
         + "</div>\n"
         + "</body>\n"
         + "</html>";

      try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
         PdfRendererBuilder builder = new PdfRendererBuilder();
         builder.usePdfAConformance(PdfRendererBuilder.PdfAConformance.PDFA_2_A);

         builder
            .withHtmlContent(htmlContent, "./")
            .useFastMode()
            .toStream(outputStream).run();
         FileUtils.writeByteArrayToFile(new File("test.pdf"), outputStream.toByteArray());
      } catch (Exception e) {
         throw new IllegalStateException(e.getMessage(), e);
      }
   }

_2019-11-22_11-34-28
test.pdf

commented

To repoduce: https://github.com/swarl/html2pdf.git
Problem seem to be in BlockBox.sizeReplacedElement :

        boolean haveExactDims = cssWidth >= 0 && cssHeight >= 0;
        
        int intrinsicWidth = re.getIntrinsicWidth();
        int intrinsicHeight = re.getIntrinsicHeight();
        
        cssWidth = !getStyle().isMaxWidthNone() && 
                (intrinsicWidth > getCSSMaxWidth(c) || cssWidth > getCSSMaxWidth(c)) ? 
                          getCSSMaxWidth(c) : cssWidth;
        [...]
        
        cssHeight = !getStyle().isMaxHeightNone() &&
                (intrinsicHeight > getCSSMaxHeight(c) || cssHeight > getCSSMaxHeight(c)) ?
                          getCSSMaxHeight(c) : cssHeight;
        [...]

        int nw;
        int nh;
        
        if (cssWidth > 0 && cssHeight > 0) {
            if (haveExactDims) {
                // We only warp the aspect ratio if we have explicit width and height values.
                nw = cssWidth;
                nh = cssHeight;
            } [...]
       }

Here max-width and max-height are applied without any conversion. So this only would work if both values are in the same aspect ratio as the picture...

commented

This would need to be something like this:

        boolean maxWidthApplied = false;
        if (!getStyle().isMaxWidthNone() &&
                (intrinsicWidth > getCSSMaxWidth(c) || cssWidth > getCSSMaxWidth(c))) {
            maxWidthApplied = true;
            cssWidth = getCSSMaxWidth(c);
            cssHeight = (int) ((double) intrinsicHeight / ((double) intrinsicWidth / (double) getCSSMaxWidth(c)));
        }

        cssWidth = cssWidth >= 0 && getCSSMinWidth(c) > 0 && cssWidth < getCSSMinWidth(c) ?
                getCSSMinWidth(c) : cssWidth;

        if (!getStyle().isMaxHeightNone() &&
                (intrinsicHeight > getCSSMaxHeight(c) && !maxWidthApplied || cssHeight > getCSSMaxHeight(c))) {
            cssWidth = (int) ((double) cssWidth / ((double) cssHeight / (double) getCSSMaxHeight(c)));
            cssHeight = getCSSMaxHeight(c);
        }

        cssHeight = cssHeight >= 0 && getCSSMinHeight(c) > 0 && cssHeight < getCSSMinHeight(c) ?
                getCSSMinHeight(c) : cssHeight;