Skip to content

Commit fbc66da

Browse files
author
pavel.chermyanin
committed
Pass correct base url to SVG converter
Pass correct base url to SVG converter while parsing of an object tag. DEVSIX-2244
1 parent ea6caec commit fbc66da

File tree

43 files changed

+372
-70
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+372
-70
lines changed

src/main/java/com/itextpdf/html2pdf/LogMessageConstant.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public final class LogMessageConstant {
128128
/** The Constant UNKNOWN_MARGIN_BOX_CHILD. */
129129
public static final String UNKNOWN_MARGIN_BOX_CHILD = "Unknown margin box child";
130130
/** The Constant WORKER_UNABLE_TO_PROCESS_IT_S_TEXT_CONTENT. */
131-
public static final String WORKER_UNABLE_TO_PROCESS_IT_S_TEXT_CONTENT = "Worker of type {0} unable to process it's text content";
131+
public static final String WORKER_UNABLE_TO_PROCESS_IT_S_TEXT_CONTENT = "Worker of type {0} unable to process it`s text content";
132132
/** The Constant WORKER_UNABLE_TO_PROCESS_OTHER_WORKER. */
133133
public static final String WORKER_UNABLE_TO_PROCESS_OTHER_WORKER = "Worker of type {0} unable to process {1}";
134134

src/main/java/com/itextpdf/html2pdf/attach/impl/tags/ObjectTagWorker.java

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,28 @@ This file is part of the iText (R) project.
4545
import com.itextpdf.html2pdf.LogMessageConstant;
4646
import com.itextpdf.html2pdf.attach.ITagWorker;
4747
import com.itextpdf.html2pdf.attach.ProcessorContext;
48+
import com.itextpdf.html2pdf.attach.util.ContextMappingHelper;
4849
import com.itextpdf.html2pdf.html.AttributeConstants;
4950
import com.itextpdf.html2pdf.util.SvgProcessingUtil;
51+
import com.itextpdf.io.util.FileUtil;
5052
import com.itextpdf.io.util.MessageFormatUtil;
5153
import com.itextpdf.kernel.pdf.PdfDocument;
5254
import com.itextpdf.layout.IPropertyContainer;
5355
import com.itextpdf.layout.element.Image;
5456
import com.itextpdf.styledxmlparser.node.IElementNode;
57+
import com.itextpdf.styledxmlparser.resolver.resource.ResourceResolver;
5558
import com.itextpdf.svg.converter.SvgConverter;
5659
import com.itextpdf.svg.exceptions.SvgProcessingException;
5760
import com.itextpdf.svg.processors.ISvgProcessorResult;
5861
import com.itextpdf.svg.processors.impl.SvgConverterProperties;
59-
import org.slf4j.Logger;
60-
import org.slf4j.LoggerFactory;
6162

6263
import java.io.IOException;
6364
import java.io.InputStream;
65+
import java.net.URISyntaxException;
66+
import java.net.URL;
67+
68+
import org.slf4j.Logger;
69+
import org.slf4j.LoggerFactory;
6470

6571
/**
6672
* TagWorker class for the {@code object} element.
@@ -73,53 +79,66 @@ public class ObjectTagWorker implements ITagWorker {
7379
private static final Logger LOGGER = LoggerFactory.getLogger(ObjectTagWorker.class);
7480

7581
/**
76-
* The Svg as image.
82+
* Helper for conversion of SVG processing results.
83+
*/
84+
private final SvgProcessingUtil processUtil;
85+
86+
/**
87+
* An Outcome of the worker. The Svg as image.
7788
*/
7889
private Image image;
7990

91+
/**
92+
* Output of SVG processing. Intermediate result.
93+
*/
8094
private ISvgProcessorResult res;
8195

82-
private SvgProcessingUtil processUtil;
83-
8496
/**
8597
* Creates a new {@link ImgTagWorker} instance.
8698
*
8799
* @param element the element
88100
* @param context the context
89101
*/
90102
public ObjectTagWorker(IElementNode element, ProcessorContext context) {
91-
image = null;
92-
res = null;
93-
processUtil = new SvgProcessingUtil();
103+
this.processUtil = new SvgProcessingUtil();
104+
94105
//Retrieve object type
95106
String type = element.getAttribute(AttributeConstants.TYPE);
96107
if (isSvgImage(type)) {
97-
//Use resource resolver to retrieve the URL
98-
try (InputStream svgStream = context.getResourceResolver().retrieveResourceAsInputStream(element.getAttribute(AttributeConstants.DATA))) {
108+
String dataValue = element.getAttribute(AttributeConstants.DATA);
109+
try (InputStream svgStream = context.getResourceResolver().retrieveResourceAsInputStream(dataValue)) {
99110
if (svgStream != null) {
100-
try {
101-
SvgConverterProperties svgConverterProperties = new SvgConverterProperties();
102-
svgConverterProperties.setBaseUri(context.getBaseUri())
103-
.setFontProvider(context.getFontProvider())
104-
.setMediaDeviceDescription(context.getDeviceDescription());
105-
res = SvgConverter.parseAndProcess(svgStream, svgConverterProperties);
106-
} catch (SvgProcessingException spe) {
107-
LOGGER.error(spe.getMessage());
111+
SvgConverterProperties props =
112+
ContextMappingHelper.mapToSvgConverterProperties(context);
113+
if (!context.getResourceResolver().isDataSrc(dataValue)) {
114+
URL fullURL = context.getResourceResolver().resolveAgainstBaseUri(dataValue);
115+
String dir = FileUtil.parentDirectory(fullURL);
116+
props.setBaseUri(dir);
108117
}
118+
res = SvgConverter.parseAndProcess(svgStream, props);
109119
}
110-
} catch (IOException ie) {
111-
LOGGER.error(MessageFormatUtil.format(LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, context.getBaseUri(), element.getAttribute(AttributeConstants.DATA)));
120+
} catch (SvgProcessingException spe) {
121+
LOGGER.error(spe.getMessage());
122+
} catch (IOException | URISyntaxException ie) {
123+
LOGGER.error(MessageFormatUtil.format(LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, context
124+
.getBaseUri(), element.getAttribute(AttributeConstants.DATA), ie));
112125
}
113126
}
114127
}
115128

129+
//todo according specs 'At least one of the "data" or "type" attribute MUST be defined.'
130+
private boolean isSvgImage(String typeAttribute) {
131+
return AttributeConstants.ObjectTypes.SVGIMAGE.equals(typeAttribute);
132+
}
133+
116134
@Override
117135
public void processEnd(IElementNode element, ProcessorContext context) {
118136
if (context.getPdfDocument() != null) {
119137
PdfDocument document = context.getPdfDocument();
120138
//Create Image object
139+
121140
if (res != null) {
122-
image = processUtil.createImageFromProcessingResult(res,document);
141+
image = processUtil.createImageFromProcessingResult(res, document);
123142
}
124143

125144
} else {
@@ -141,8 +160,4 @@ public boolean processTagChild(ITagWorker childTagWorker, ProcessorContext conte
141160
public IPropertyContainer getElementResult() {
142161
return image;
143162
}
144-
145-
private boolean isSvgImage(String typeAttribute) {
146-
return typeAttribute.equals(AttributeConstants.ObjectTypes.SVGIMAGE);
147-
}
148163
}

src/main/java/com/itextpdf/html2pdf/attach/impl/tags/SvgTagWorker.java

Lines changed: 1 addition & 0 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.svg.processors.ISvgProcessorResult;
5555
import com.itextpdf.svg.processors.impl.DefaultSvgProcessor;
5656
import com.itextpdf.svg.processors.impl.SvgConverterProperties;
57+
5758
import org.slf4j.LoggerFactory;
5859

5960
/**
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.itextpdf.html2pdf.attach.util;
2+
3+
import com.itextpdf.html2pdf.attach.ProcessorContext;
4+
import com.itextpdf.svg.processors.impl.SvgConverterProperties;
5+
6+
public class ContextMappingHelper {
7+
8+
public static SvgConverterProperties mapToSvgConverterProperties(ProcessorContext context){
9+
SvgConverterProperties svgConverterProperties = new SvgConverterProperties();
10+
svgConverterProperties.setFontProvider(context.getFontProvider())
11+
.setBaseUri(context.getBaseUri())
12+
.setMediaDeviceDescription(context.getDeviceDescription());
13+
return svgConverterProperties;
14+
}
15+
}

src/main/java/com/itextpdf/html2pdf/resolver/resource/HtmlResourceResolver.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ This file is part of the iText (R) project.
4343
package com.itextpdf.html2pdf.resolver.resource;
4444

4545
import com.itextpdf.html2pdf.attach.ProcessorContext;
46+
import com.itextpdf.html2pdf.attach.util.ContextMappingHelper;
4647
import com.itextpdf.html2pdf.util.SvgProcessingUtil;
4748
import com.itextpdf.io.codec.Base64;
49+
import com.itextpdf.io.util.FileUtil;
4850
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
4951
import com.itextpdf.kernel.pdf.xobject.PdfXObject;
5052
import com.itextpdf.styledxmlparser.resolver.resource.ResourceResolver;
@@ -83,6 +85,8 @@ public HtmlResourceResolver(String baseUri, ProcessorContext context) {
8385
this.context = context;
8486
}
8587

88+
89+
8690
@Override
8791
protected PdfXObject tryResolveBase64ImageSource(String src) {
8892
String fixedSrc = src.replaceAll("\\s", "");
@@ -105,17 +109,18 @@ protected PdfXObject createImageByUrl(URL url) throws Exception {
105109
return super.createImageByUrl(url);
106110
} catch (Exception ignored) {
107111
try (InputStream is = url.openStream()) {
108-
return processAsSvg(is, context);
112+
String newRoot = FileUtil.parentDirectory(url);
113+
return processAsSvg(is, context, newRoot);
109114
}
110115
}
111116
}
112117

113-
private PdfFormXObject processAsSvg(InputStream stream, ProcessorContext context) throws IOException {
118+
private PdfFormXObject processAsSvg(InputStream stream, ProcessorContext context, String parentDir) throws IOException {
114119
SvgProcessingUtil processingUtil = new SvgProcessingUtil();
115-
SvgConverterProperties svgConverterProperties = new SvgConverterProperties();
116-
svgConverterProperties.setBaseUri(context.getBaseUri())
117-
.setFontProvider(context.getFontProvider())
118-
.setMediaDeviceDescription(context.getDeviceDescription());
120+
SvgConverterProperties svgConverterProperties = ContextMappingHelper.mapToSvgConverterProperties(context);
121+
if (parentDir != null) {
122+
svgConverterProperties.setBaseUri(parentDir);
123+
}
119124
ISvgProcessorResult res = SvgConverter.parseAndProcess(stream, svgConverterProperties);
120125
if (context.getPdfDocument() != null) {
121126
return processingUtil.createXObjectFromProcessingResult(res, context.getPdfDocument());
@@ -124,4 +129,8 @@ private PdfFormXObject processAsSvg(InputStream stream, ProcessorContext context
124129
}
125130
}
126131

132+
private PdfFormXObject processAsSvg(InputStream stream, ProcessorContext context) throws IOException {
133+
return this.processAsSvg(stream, context, null);
134+
}
135+
127136
}

src/test/java/com/itextpdf/html2pdf/Html2ElementsTest.java

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ This file is part of the iText (R) project.
5050
import com.itextpdf.layout.property.Property;
5151
import com.itextpdf.layout.property.UnitValue;
5252
import com.itextpdf.test.ExtendedITextTest;
53+
import com.itextpdf.test.annotations.LogMessage;
5354
import com.itextpdf.test.annotations.LogMessages;
5455
import com.itextpdf.test.annotations.type.IntegrationTest;
5556

@@ -78,7 +79,7 @@ public void htmlToElementsTest01() throws IOException {
7879
Assert.assertTrue(lst.size() == 1);
7980
Assert.assertTrue(lst.get(0) instanceof Paragraph);
8081
Paragraph p = (Paragraph) lst.get(0);
81-
Assert.assertEquals("Hello world!", ((Text)p.getChildren().get(0)).getText());
82+
Assert.assertEquals("Hello world!", ((Text) p.getChildren().get(0)).getText());
8283
Assert.assertEquals(12f, p.<UnitValue>getProperty(Property.FONT_SIZE).getValue(), 1e-10);
8384
}
8485

@@ -90,7 +91,7 @@ public void htmlToElementsTest02() throws IOException {
9091
Assert.assertTrue(lst.get(0) instanceof Table);
9192
Table t = (Table) lst.get(0);
9293
Assert.assertEquals(2, t.getNumberOfRows());
93-
Assert.assertEquals("123", ((Text)(((Paragraph)t.getCell(0, 0).getChildren().get(0)).getChildren().get(0))).getText());
94+
Assert.assertEquals("123", ((Text) (((Paragraph) t.getCell(0, 0).getChildren().get(0)).getChildren().get(0))).getText());
9495
Assert.assertEquals(24f, t.<UnitValue>getProperty(Property.FONT_SIZE).getValue(), 1e-10);
9596
}
9697

@@ -102,8 +103,8 @@ public void htmlToElementsTest03() throws IOException {
102103
Assert.assertTrue(lst.get(0) instanceof Paragraph);
103104
Assert.assertTrue(lst.get(1) instanceof Table);
104105
Assert.assertTrue(lst.get(2) instanceof Paragraph);
105-
Assert.assertEquals("Hello world!", ((Text)((Paragraph)lst.get(0)).getChildren().get(0)).getText());
106-
Assert.assertEquals("123", ((Text)(((Paragraph)((Table)lst.get(1)).getCell(0, 0).getChildren().get(0)).getChildren().get(0))).getText());
106+
Assert.assertEquals("Hello world!", ((Text) ((Paragraph) lst.get(0)).getChildren().get(0)).getText());
107+
Assert.assertEquals("123", ((Text) (((Paragraph) ((Table) lst.get(1)).getCell(0, 0).getChildren().get(0)).getChildren().get(0))).getText());
107108
}
108109

109110
@Test
@@ -114,8 +115,8 @@ public void htmlToElementsTest04() throws IOException {
114115
Assert.assertTrue(lst.size() == 2);
115116
Assert.assertTrue(lst.get(0) instanceof Paragraph);
116117
Assert.assertTrue(lst.get(1) instanceof Table);
117-
Assert.assertEquals("Hello world!", ((Text)((Paragraph)lst.get(0)).getChildren().get(0)).getText());
118-
Assert.assertEquals("123", ((Text)(((Paragraph)((Table)lst.get(1)).getCell(0, 0).getChildren().get(0)).getChildren().get(0))).getText());
118+
Assert.assertEquals("Hello world!", ((Text) ((Paragraph) lst.get(0)).getChildren().get(0)).getText());
119+
Assert.assertEquals("123", ((Text) (((Paragraph) ((Table) lst.get(1)).getCell(0, 0).getChildren().get(0)).getChildren().get(0))).getText());
119120
}
120121

121122
@Test
@@ -128,23 +129,21 @@ public void htmlToElementsTest05() throws IOException {
128129

129130
@Test
130131
@LogMessages(messages = {})
131-
public void htmlElementsTest06() throws IOException
132-
{
132+
public void htmlElementsTest06() throws IOException {
133133
String html = "<html>Lorem<p>Ipsum</p>Dolor<p>Sit</p></html>";
134134
List<IElement> lst = HtmlConverter.convertToElements(html);
135135
Assert.assertTrue(lst.size() == 4);
136-
for(int i=0;i<lst.size();i++)
136+
for (int i = 0; i < lst.size(); i++)
137137
Assert.assertTrue(lst.get(i) instanceof Paragraph);
138138
}
139139

140140
@Test
141141
@LogMessages(messages = {})
142-
public void htmlElementsTest07() throws IOException
143-
{
142+
public void htmlElementsTest07() throws IOException {
144143
String html = "<html>Lorem<span>Dolor</span><p>Ipsum</p><p>Sit</p></html>";
145144
List<IElement> lst = HtmlConverter.convertToElements(html);
146145
Assert.assertTrue(lst.size() == 3);
147-
for(int i=0;i<lst.size();i++)
146+
for (int i = 0; i < lst.size(); i++)
148147
Assert.assertTrue(lst.get(i) instanceof Paragraph);
149148
}
150149

@@ -168,10 +167,24 @@ public void htmlToElementsTest09() throws IOException {
168167
ConverterProperties props = new ConverterProperties();
169168
OutlineHandler outlineHandler = new OutlineHandler();
170169
outlineHandler.putTagPriorityMapping("h1", 1);
171-
outlineHandler.putTagPriorityMapping("h3",2);
170+
outlineHandler.putTagPriorityMapping("h3", 2);
172171
outlineHandler.putTagPriorityMapping("p", 3);
173172
props.setOutlineHandler(outlineHandler);
174173

175174
HtmlConverter.convertToElements(html);
176175
}
176+
177+
@Test
178+
@LogMessages(messages = {@LogMessage(messageTemplate = com.itextpdf.styledxmlparser.LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, count = 1),
179+
@LogMessage(messageTemplate = LogMessageConstant.WORKER_UNABLE_TO_PROCESS_OTHER_WORKER, count = 1),
180+
@LogMessage(messageTemplate = LogMessageConstant.PDF_DOCUMENT_NOT_PRESENT, count = 1),
181+
})
182+
public void htmlObjectMalformedUrlTest() throws IOException {
183+
String html = "<object data ='htt://as' type='image/svg+xml'></object>";
184+
List<IElement> lst = HtmlConverter.convertToElements(html);
185+
Assert.assertTrue(lst.size() == 0);
186+
}
187+
188+
189+
177190
}

src/test/java/com/itextpdf/html2pdf/Html2PdfTest.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ This file is part of the iText (R) project.
4444

4545
import com.itextpdf.io.util.UrlUtil;
4646
import com.itextpdf.kernel.utils.CompareTool;
47+
import com.itextpdf.layout.element.IElement;
4748
import com.itextpdf.test.ExtendedITextTest;
49+
import com.itextpdf.test.annotations.LogMessage;
50+
import com.itextpdf.test.annotations.LogMessages;
4851
import com.itextpdf.test.annotations.type.IntegrationTest;
4952
import org.junit.Assert;
5053
import org.junit.BeforeClass;
@@ -53,6 +56,7 @@ This file is part of the iText (R) project.
5356

5457
import java.io.File;
5558
import java.io.IOException;
59+
import java.util.List;
5660

5761
@Category(IntegrationTest.class)
5862
public class Html2PdfTest extends ExtendedITextTest {
@@ -94,7 +98,6 @@ public void helloParagraphJunkSpacesDocumentTest() throws IOException, Interrupt
9498
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "hello_paragraph_junk_spaces.pdf", sourceFolder + "cmp_hello_paragraph_junk_spaces.pdf", destinationFolder, "diff03_"));
9599
}
96100

97-
98101
@Test
99102
// TODO DEVSIX-1124
100103
public void helloParagraphNestedInTableDocumentTest() throws IOException, InterruptedException {
@@ -124,4 +127,47 @@ public void aBlockInPTagTest() throws IOException, InterruptedException {
124127
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "aBlockInPTag.pdf", sourceFolder + "cmp_aBlockInPTag.pdf", destinationFolder, "diff03_"));
125128
}
126129

130+
@Test
131+
@LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.ERROR_RESOLVING_PARENT_STYLES, count = 8)})
132+
public void base64svgTest() throws IOException, InterruptedException {
133+
HtmlConverter.convertToPdf(new File(sourceFolder + "objectTag_base64svg.html"), new File(destinationFolder + "objectTag_base64svg.pdf"));
134+
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "objectTag_base64svg.pdf", sourceFolder + "cmp_objectTag_base64svg.pdf", destinationFolder, "diff01_"));
135+
}
136+
137+
@Test
138+
@LogMessages(messages = {@LogMessage(messageTemplate = com.itextpdf.styledxmlparser.LogMessageConstant.UNABLE_TO_RETRIEVE_STREAM_WITH_GIVEN_BASE_URI, count = 1),
139+
@LogMessage(messageTemplate = LogMessageConstant.WORKER_UNABLE_TO_PROCESS_OTHER_WORKER, count = 1)})
140+
public void htmlObjectIncorrectBase64Test() throws IOException, InterruptedException {
141+
HtmlConverter.convertToPdf(new File(sourceFolder + "objectTag_incorrectBase64svg.html"), new File(destinationFolder + "objectTag_incorrectBase64svg.pdf"));
142+
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "objectTag_incorrectBase64svg.pdf", sourceFolder + "cmp_objectTag_incorrectBase64svg.pdf", destinationFolder, "diff01_"));
143+
144+
}
145+
146+
@Test
147+
@LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.WORKER_UNABLE_TO_PROCESS_IT_S_TEXT_CONTENT, count = 1),
148+
@LogMessage(messageTemplate = LogMessageConstant.WORKER_UNABLE_TO_PROCESS_OTHER_WORKER, count = 2),
149+
})
150+
public void htmlObjectAltTextTest() throws IOException, InterruptedException {
151+
//update after DEVSIX-1346
152+
HtmlConverter.convertToPdf(new File(sourceFolder + "objectTag_altText.html"), new File(destinationFolder + "objectTag_altText.pdf"));
153+
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "objectTag_altText.pdf", sourceFolder + "cmp_objectTag_altText.pdf", destinationFolder, "diff01_"));
154+
155+
}
156+
157+
@Test
158+
@LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.ERROR_RESOLVING_PARENT_STYLES, count = 8),
159+
@LogMessage(messageTemplate = LogMessageConstant.WORKER_UNABLE_TO_PROCESS_OTHER_WORKER, count = 1),})
160+
public void htmlObjectNestedObjectTest() throws IOException, InterruptedException {
161+
HtmlConverter.convertToPdf(new File(sourceFolder + "objectTag_nestedTag.html"), new File(destinationFolder + "objectTag_nestedTag.pdf"));
162+
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "objectTag_nestedTag.pdf", sourceFolder + "cmp_objectTag_nestedTag.pdf", destinationFolder, "diff01_"));
163+
164+
}
165+
166+
167+
@Test
168+
@LogMessages(messages = {@LogMessage(messageTemplate = LogMessageConstant.ERROR_RESOLVING_PARENT_STYLES, count = 8)})
169+
public void htmlImgBase64SVGTest() throws IOException, InterruptedException {
170+
HtmlConverter.convertToPdf(new File(sourceFolder + "imgTag_base64svg.html"), new File(destinationFolder + "imgTag_base64svg.pdf"));
171+
Assert.assertNull(new CompareTool().compareByContent(destinationFolder + "imgTag_base64svg.pdf", sourceFolder + "cmp_imgTag_base64svg.pdf", destinationFolder, "diff01_"));
172+
}
127173
}

0 commit comments

Comments
 (0)