Skip to content

Commit 65c4897

Browse files
author
Samuel Huylebroeck
committed
Apply browser defaults in case of missing w or h
Apply browser default values when height or width is missing from the top-level SVG RND-1011
1 parent afd2713 commit 65c4897

File tree

13 files changed

+101
-20
lines changed

13 files changed

+101
-20
lines changed

src/main/java/com/itextpdf/svg/converter/SvgConverter.java

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ This file is part of the iText (R) project.
5454
import com.itextpdf.layout.element.Image;
5555
import com.itextpdf.styledxmlparser.IXmlParser;
5656
import com.itextpdf.styledxmlparser.css.util.CssUtils;
57+
import com.itextpdf.styledxmlparser.exceptions.StyledXMLParserException;
5758
import com.itextpdf.styledxmlparser.node.INode;
5859
import com.itextpdf.styledxmlparser.node.impl.jsoup.JsoupXmlParser;
5960
import com.itextpdf.styledxmlparser.resolver.resource.ResourceResolver;
@@ -68,12 +69,17 @@ This file is part of the iText (R) project.
6869
import com.itextpdf.svg.renderers.ISvgNodeRenderer;
6970
import com.itextpdf.svg.renderers.SvgDrawContext;
7071
import com.itextpdf.svg.renderers.impl.PdfRootSvgNodeRenderer;
72+
import com.itextpdf.svg.utils.SvgCssUtils;
73+
import org.slf4j.Logger;
74+
import org.slf4j.LoggerFactory;
75+
7176
import java.io.File;
7277
import java.io.FileInputStream;
7378
import java.io.FileOutputStream;
7479
import java.io.IOException;
7580
import java.io.InputStream;
7681
import java.io.OutputStream;
82+
import java.util.List;
7783

7884
/**
7985
* This is the main container class for static methods that do high-level
@@ -86,6 +92,9 @@ public final class SvgConverter {
8692
private SvgConverter() {
8793
}
8894

95+
private static final Logger LOGGER = LoggerFactory.getLogger(SvgConverter.class);
96+
97+
8998
private static void checkNull(Object o) {
9099
if (o == null) {
91100
throw new SvgProcessingException(SvgLogMessageConstant.PARAMETER_CANNOT_BE_NULL);
@@ -546,8 +555,12 @@ public static void createPdf(InputStream svgStream, OutputStream pdfDest, ISvgCo
546555
//Extract topmost dimensions
547556
checkNull(topSvgRenderer);
548557
checkNull(pdfDocument);
549-
float width = CssUtils.parseAbsoluteLength(topSvgRenderer.getAttribute(SvgConstants.Attributes.WIDTH));
550-
float height = CssUtils.parseAbsoluteLength(topSvgRenderer.getAttribute(SvgConstants.Attributes.HEIGHT));
558+
float width, height;
559+
560+
float[] wh = extractWidthAndHeight(topSvgRenderer);
561+
width = wh[0];
562+
height = wh[1];
563+
551564
//adjust pagesize and create new page
552565
pdfDocument.setDefaultPageSize(new PageSize(width, height));
553566
PdfPage page = pdfDocument.addNewPage();
@@ -789,9 +802,12 @@ private static PdfFormXObject convertToXObject(ISvgNodeRenderer topSvgRenderer,
789802
checkNull(topSvgRenderer);
790803
checkNull(document);
791804
checkNull(context);
805+
float width, height;
806+
807+
float[] wh = extractWidthAndHeight(topSvgRenderer);
808+
width = wh[0];
809+
height = wh[1];
792810

793-
float width = CssUtils.parseAbsoluteLength(topSvgRenderer.getAttribute(SvgConstants.Attributes.WIDTH));
794-
float height = CssUtils.parseAbsoluteLength(topSvgRenderer.getAttribute(SvgConstants.Attributes.HEIGHT));
795811
PdfFormXObject pdfForm = new PdfFormXObject(new Rectangle(0, 0, width, height));
796812
PdfCanvas canvas = new PdfCanvas(pdfForm, document);
797813

@@ -896,4 +912,61 @@ public static INode parse(InputStream stream, ISvgConverterProperties props) thr
896912
IXmlParser xmlParser = new JsoupXmlParser();
897913
return xmlParser.parse(stream, props != null ? props.getCharset() : null);
898914
}
915+
916+
/**
917+
* Extract width and height of the passed SVGNodeRenderer,
918+
* defaulting to respective viewbox values if either one is not present or
919+
* to browser default if viewbox is missing as well
920+
*
921+
* @return float[2], width is in position 0, height in position 1
922+
*/
923+
private static float[] extractWidthAndHeight(ISvgNodeRenderer topSvgRenderer) {
924+
float[] res = new float[2];
925+
boolean viewBoxPresent = false;
926+
927+
//Parse viewbox
928+
String vbString = topSvgRenderer.getAttribute(SvgConstants.Attributes.VIEWBOX);
929+
float[] values = {0, 0, 0, 0};
930+
if (vbString != null) {
931+
List<String> valueStrings = SvgCssUtils.splitValueList(vbString);
932+
values = new float[valueStrings.size()];
933+
for (int i = 0; i < values.length; i++) {
934+
values[i] = CssUtils.parseAbsoluteLength(valueStrings.get(i));
935+
}
936+
}
937+
float width, height;
938+
String wString, hString;
939+
wString = topSvgRenderer.getAttribute(SvgConstants.Attributes.WIDTH);
940+
if (wString == null) {
941+
//Log Warning
942+
LOGGER.warn(SvgLogMessageConstant.MISSING_WIDTH);
943+
if (viewBoxPresent) {
944+
width = values[2];
945+
} else {
946+
//Set to browser default
947+
width = CssUtils.parseAbsoluteLength("300px");
948+
}
949+
} else {
950+
width = CssUtils.parseAbsoluteLength(wString);
951+
}
952+
hString = topSvgRenderer.getAttribute(SvgConstants.Attributes.HEIGHT);
953+
if (hString == null) {
954+
//Log Warning
955+
LOGGER.warn(SvgLogMessageConstant.MISSING_HEIGHT);
956+
if (viewBoxPresent) {
957+
height = values[3];
958+
} else {
959+
//Set to browser default
960+
height = CssUtils.parseAbsoluteLength("150px");
961+
}
962+
} else {
963+
height = CssUtils.parseAbsoluteLength(hString);
964+
}
965+
966+
res[0] = width;
967+
res[1] = height;
968+
return res;
969+
970+
971+
}
899972
}

src/main/java/com/itextpdf/svg/exceptions/SvgLogMessageConstant.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public final class SvgLogMessageConstant {
6363
public static final String INVALID_PATH_D_ATTRIBUTE_OPERATORS = "Invalid operators found in path data attribute: {0}";
6464
public static final String INVALID_TRANSFORM_DECLARATION = "Transformation declaration is not formed correctly.";
6565
public static final String LOOP ="Loop detected";
66+
public static final String MISSING_WIDTH="Top Svg tag has no defined width attribute and viewbox width is not present, so browser default of 300px is used";
67+
public static final String MISSING_HEIGHT="Top Svg tag has no defined height attribute and viewbox height is not present, so browser default of 150px is used";
6668
public static final String NAMED_OBJECT_NAME_NULL_OR_EMPTY = "The name of the named object can't be null or empty.";
6769
public static final String NAMED_OBJECT_NULL = "A named object can't be null.";
6870
public static final String NOROOT = "No root found";

src/test/java/com/itextpdf/svg/renderers/impl/SimpleSvgTagSvgNodeRendererIntegrationTest.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,35 +76,24 @@ public void everythingPresentAndValidTest() throws IOException, InterruptedExcep
7676
convertAndCompareVisually(SOURCE_FOLDER, DESTINATION_FOLDER,"everythingPresentAndValid");
7777
}
7878

79-
@Test
80-
public void absentEverything() throws IOException, InterruptedException {
81-
junitExpectedException.expect(StyledXMLParserException.class);
82-
junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "null"));
83-
convertAndCompareVisually(SOURCE_FOLDER, DESTINATION_FOLDER,"absentEverything");
84-
85-
}
86-
8779
@Test
8880
public void absentHeight() throws IOException, InterruptedException {
89-
junitExpectedException.expect(StyledXMLParserException.class);
90-
junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "null"));
9181
convertAndCompareVisually(SOURCE_FOLDER, DESTINATION_FOLDER,"absentHeight");
92-
9382
}
9483

9584
@Test
9685
public void absentWidth() throws IOException, InterruptedException {
97-
junitExpectedException.expect(StyledXMLParserException.class);
98-
junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "null"));
9986
convertAndCompareVisually(SOURCE_FOLDER, DESTINATION_FOLDER,"absentWidth");
10087
}
10188

10289
@Test
10390
public void absentWidthAndHeight() throws IOException, InterruptedException {
104-
junitExpectedException.expect(StyledXMLParserException.class);
105-
junitExpectedException.expectMessage(MessageFormatUtil.format(LogMessageConstant.NAN, "null"));
10691
convertAndCompareVisually(SOURCE_FOLDER, DESTINATION_FOLDER,"absentWidthAndHeight");
92+
}
10793

94+
@Test
95+
public void absentWHViewboxPresent() throws IOException, InterruptedException {
96+
convertAndCompareVisually(SOURCE_FOLDER, DESTINATION_FOLDER,"absentWHViewboxPresent");
10897
}
10998

11099
@Test
Lines changed: 4 additions & 1 deletion
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)