Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
swarl opened this issue Nov 22, 2019 · 2 comments

Comments

@swarl
Copy link

swarl commented Nov 22, 2019

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

@swarl
Copy link
Author

swarl commented Jan 12, 2020

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...

@swarl
Copy link
Author

swarl commented Jan 13, 2020

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;

danfickle added a commit that referenced this issue Jan 14, 2020
This differs from browsers which will warp the aspect ratio in such circumstances (tested with Chrome/Safari). However, nearly all uses need the aspect ratio preserved. We can revisit this if we implement the object-fit property.

Thanks a lot to @swarl who provided code which inspired the test and fix for this issue, as well as reporting the problem.
@swarl swarl closed this as completed Jan 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant