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

Implementation of file-embed link. #640

Merged
merged 2 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ enum LogMessageId1Param implements LogMessageId {
LOAD_COULD_NOT_INSTANTIATE_CUSTOM_XML_READER(XRLog.LOAD, "Could not instantiate custom XMLReader class for XML parsing: {}. " +
"Please check classpath. Use value 'default' in FS configuration if necessary. Will now try JDK default."),
LOAD_UNABLE_TO_LOAD_CSS_FROM_URI(XRLog.LOAD, "Unable to load CSS from {}"),
LOAD_COULD_NOT_LOAD_EMBEDDED_FILE(XRLog.LOAD, "Was not able to load an embedded file for embedding with uri {}"),
LOAD_PARSE_STYLESHEETS_TIME(XRLog.LOAD, "TIME: parse stylesheets {}ms"),
LOAD_REQUESTING_STYLESHEET_AT_URI(XRLog.LOAD, "Requesting stylesheet: {}"),
LOAD_UNRECOGNIZED_IMAGE_FORMAT_FOR_URI(XRLog.LOAD, "Unrecognized image format for: {}"),
Expand Down Expand Up @@ -161,7 +162,8 @@ enum LogMessageId1Param implements LogMessageId {
EXCEPTION_COULD_NOT_LOAD_FONT_FACE(XRLog.EXCEPTION, "Could not load @font-face font: {}"),
EXCEPTION_COULD_NOT_LOAD_DEFAULT_CSS(XRLog.EXCEPTION, "Can't load default CSS from {}. This file must be on your CLASSPATH. Please check before continuing."),
EXCEPTION_DEFAULT_USERAGENT_IS_NOT_ABLE_TO_RESOLVE_BASE_URL_FOR(XRLog.EXCEPTION, "The default NaiveUserAgent doesn't know how to resolve the base URL for {}"),
EXCEPTION_FAILED_TO_LOAD_BACKGROUND_IMAGE_AT_URI(XRLog.EXCEPTION, "Failed to load background image at uri {}");
EXCEPTION_FAILED_TO_LOAD_BACKGROUND_IMAGE_AT_URI(XRLog.EXCEPTION, "Failed to load background image at uri {}"),
EXCEPTION_COULD_NOT_LOAD_EMBEDDED_FILE(XRLog.EXCEPTION, "Was not able to create an embedded file for embedding with uri {}");

private final String where;
private final String messageFormat;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<html>
<head>
<style>
@page {
size: 200px 200px;
}
</style>
</head>
<body>
Embedded <a href="stylesheets/basic.css" download="basic.css" data-content-type="text/plain">text <br/> document</a>.
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
import java.util.stream.IntStream;

import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationFileAttachment;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination;
Expand All @@ -36,9 +40,9 @@
import org.apache.pdfbox.util.Charsets;
import org.hamcrest.CustomTypeSafeMatcher;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

import com.openhtmltopdf.outputdevice.helper.ExternalResourceControlPriority;
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import com.openhtmltopdf.testcases.TestcaseRunner;
import com.openhtmltopdf.util.Diagnostic;
Expand Down Expand Up @@ -1060,6 +1064,34 @@ public void testPr489DiagnosticConsumer() throws IOException {
.allMatch(diag -> !diag.getFormattedMessage().isEmpty()));
}

@Test
public void testIssue508FileEmbed() throws IOException {
try (PDDocument doc = run("issue-508-file-embed",
builder -> {
// File embeds are blocked by default, allow everything.
builder.useExternalResourceAccessControl((uri, type) -> true, ExternalResourceControlPriority.RUN_AFTER_RESOLVING_URI);
builder.useExternalResourceAccessControl((uri, type) -> true, ExternalResourceControlPriority.RUN_BEFORE_RESOLVING_URI);
})) {

// There should be multiple file attachment annotations because the link
// is broken into two boxes on multiple lines.
assertThat(doc.getPage(0).getAnnotations().size(), equalTo(2));

PDAnnotationFileAttachment fileAttach1 = (PDAnnotationFileAttachment) doc.getPage(0).getAnnotations().get(0);
assertThat(fileAttach1.getFile().getFile(), equalTo("basic.css"));

PDAnnotationFileAttachment fileAttach2 = (PDAnnotationFileAttachment) doc.getPage(0).getAnnotations().get(1);
assertThat(fileAttach2.getFile().getFile(), equalTo("basic.css"));

try (COSDocument cosDoc = doc.getDocument()) {
// Make sure the file is only embedded once.
List<COSObject> files = cosDoc.getObjectsByType(COSName.FILESPEC);
assertThat(files.size(), equalTo(1));
}

remove("issue-508-file-embed", doc);
}
}

// TODO:
// + More form controls.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.verapdf.pdfa.results.TestAssertion;
import org.verapdf.pdfa.results.ValidationResult;

import com.openhtmltopdf.outputdevice.helper.ExternalResourceControlPriority;
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder.PdfAConformance;

Expand Down Expand Up @@ -65,7 +66,11 @@ public boolean run(String resource, PDFAFlavour flavour, PdfAConformance conform
builder.usePdfAConformance(conform);
builder.useFont(new File("target/test/artefacts/Karla-Bold.ttf"), "TestFont");
builder.withHtmlContent(html, PdfATester.class.getResource("/html/").toString());


// File embeds are blocked by default, allow everything.
builder.useExternalResourceAccessControl((uri, type) -> true, ExternalResourceControlPriority.RUN_AFTER_RESOLVING_URI);
builder.useExternalResourceAccessControl((uri, type) -> true, ExternalResourceControlPriority.RUN_BEFORE_RESOLVING_URI);

try (InputStream colorProfile = PdfATester.class.getResourceAsStream("/colorspaces/sRGB.icc")) {
byte[] colorProfileBytes = IOUtils.toByteArray(colorProfile);
builder.useColorProfile(colorProfileBytes);
Expand Down Expand Up @@ -128,5 +133,12 @@ public void testAllInOnePdfA2a() throws Exception {
public void testAllInOnePdfA2u() throws Exception {
assertTrue(run("all-in-one", PDFAFlavour.PDFA_2_U, PdfAConformance.PDFA_2_U));
}


/**
* File embedding is allowed as of PDF/A3.
*/
@Test
public void testFileEmbedA3b() throws Exception {
assertTrue(run("file-embed", PDFAFlavour.PDFA_3_B, PdfAConformance.PDFA_3_B));
}
}
36 changes: 36 additions & 0 deletions openhtmltopdf-pdfa-testing/src/test/resources/html/file-embed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<html lang="EN-US">
<head>
<title>File embed testcase</title>
<meta name="subject" content="PDF/A3 file embed"/>
<meta name="author" content="openhtmltopdf.com team"/>
<meta name="description" content="An example for file embed"/>

<bookmarks>
<bookmark name="File embed" href="#file"/>
</bookmarks>

<style>
body {
margin: 0;
font-family: 'TestFont'; /* Font provided with builder. */
font-size: 15px;
}
</style>
</head>
<body>
<h1 id="file">File embed example</h1>

<p>
<a href="file-embed.html"
download="source.html"
data-content-type="text/html"
title="File embedded"
relationship="Source">

File embed

</a>
</p>

</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.openhtmltopdf.pdfboxout;

import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationFileAttachment;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary;

public abstract class AnnotationContainer {
public void setRectangle(PDRectangle rectangle) {
getPdAnnotation().setRectangle(rectangle);
}

public void setPrinted(boolean printed) {
getPdAnnotation().setPrinted(printed);
}

public void setQuadPoints(float[] quadPoints) {};

public abstract void setBorderStyle(PDBorderStyleDictionary styleDict);

public abstract PDAnnotation getPdAnnotation();

public static class PDAnnotationFileAttachmentContainer extends AnnotationContainer {
private final PDAnnotationFileAttachment pdAnnotationFileAttachment;

public PDAnnotationFileAttachmentContainer(PDAnnotationFileAttachment pdAnnotationFileAttachment) {
this.pdAnnotationFileAttachment = pdAnnotationFileAttachment;
}

@Override
public PDAnnotation getPdAnnotation() {
return pdAnnotationFileAttachment;
}

@Override
public void setBorderStyle(PDBorderStyleDictionary styleDict) {
pdAnnotationFileAttachment.setBorderStyle(styleDict);
}
}

public static class PDAnnotationLinkContainer extends AnnotationContainer {
private final PDAnnotationLink pdAnnotationLink;

public PDAnnotationLinkContainer(PDAnnotationLink pdAnnotationLink) {
this.pdAnnotationLink = pdAnnotationLink;
}

@Override
public PDAnnotation getPdAnnotation() {
return pdAnnotationLink;
}

@Override
public void setQuadPoints(float[] quadPoints) {
pdAnnotationLink.setQuadPoints(quadPoints);
}

@Override
public void setBorderStyle(PDBorderStyleDictionary styleDict) {
pdAnnotationLink.setBorderStyle(styleDict);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1210,17 +1210,17 @@ private static class AnnotationWithStructureParent {
PDAnnotation annotation;
}

public void addLink(Box anchor, Box target, PDAnnotationLink annotation, PDPage page) {
public void addLink(Box anchor, Box target, PDAnnotation pdAnnotation, PDPage page) {
PDStructureElement struct = getStructualElementForBox(anchor);
if (struct != null) {
// We have to append the link annotationobject reference as a kid of its associated structure element.
PDObjectReference ref = new PDObjectReference();
ref.setReferencedObject(annotation);
ref.setReferencedObject(pdAnnotation);
struct.appendKid(ref);

// We also need to save the pair so we can add it to the number tree for reverse lookup.
AnnotationWithStructureParent annotStructParentPair = new AnnotationWithStructureParent();
annotStructParentPair.annotation = annotation;
annotStructParentPair.annotation = pdAnnotation;
annotStructParentPair.structureParent = struct;

_pageItems._pageAnnotations.add(annotStructParentPair);
Expand Down
Loading