max-width / max-height not redering correctly in pdf when height / width set in tag
swarl opened this issue · comments
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);
}
}
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...
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;