-
Notifications
You must be signed in to change notification settings - Fork 389
#508 add support for embedded file #509
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
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,21 +13,24 @@ | |
| import com.openhtmltopdf.util.XRLog; | ||
|
|
||
| import org.apache.pdfbox.pdmodel.PDPage; | ||
| import org.apache.pdfbox.pdmodel.PDResources; | ||
| import org.apache.pdfbox.pdmodel.common.PDRectangle; | ||
| import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; | ||
| import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; | ||
| import org.apache.pdfbox.pdmodel.interactive.action.PDAction; | ||
| import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo; | ||
| import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript; | ||
| import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI; | ||
| import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; | ||
| import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink; | ||
| import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary; | ||
| import org.apache.pdfbox.pdmodel.interactive.annotation.*; | ||
| import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination; | ||
| import org.w3c.dom.Element; | ||
|
|
||
| import java.awt.*; | ||
| import java.awt.geom.*; | ||
| import java.io.ByteArrayInputStream; | ||
| import java.io.IOException; | ||
| import java.net.URI; | ||
| import java.nio.file.Paths; | ||
| import java.util.*; | ||
| import java.util.List; | ||
| import java.util.Map.Entry; | ||
|
|
@@ -224,23 +227,57 @@ private void addUriAsLink(RenderingContext c, Box box, PDPage page, float pageHe | |
|
|
||
| PDAnnotationLink annot = new PDAnnotationLink(); | ||
| annot.setAction(action); | ||
| if (!placeAnnotation(transform, linkShape, targetArea, annot)) | ||
| if (!placeAnnotation(transform, linkShape, targetArea, new PDAnnotationLinkContainer(annot))) | ||
| return; | ||
|
|
||
| addLinkToPage(page, annot, box, target); | ||
| addLinkToPage(page, new PDAnnotationLinkContainer(annot), box, target); | ||
| } else { | ||
| XRLog.general(Level.WARNING, "Could not find valid target for link. Link href = " + uri); | ||
| } | ||
| } else if (isURI(uri)) { | ||
| PDActionURI uriAct = new PDActionURI(); | ||
| uriAct.setURI(uri); | ||
|
|
||
| Rectangle2D targetArea = checkLinkArea(page, c, box, pageHeight, transform, linkShape); | ||
| if (targetArea == null) { | ||
| return; | ||
| } | ||
| PDAnnotationLink annot = new PDAnnotationLink(); | ||
| annot.setAction(uriAct); | ||
|
|
||
| PDAnnotationLink annotationLink = new PDAnnotationLink(); | ||
| PDActionURI uriAct = new PDActionURI(); | ||
| uriAct.setURI(uri); | ||
| annotationLink.setAction(uriAct); | ||
| PDAnnotationContainer annot = new PDAnnotationLinkContainer(annotationLink); | ||
|
|
||
| if ("true".equals(elem.getAttribute("data-embed-file"))) { | ||
| byte[] file = _sharedContext.getUserAgentCallback().getBinaryResource(uri); | ||
| if (file != null) { | ||
| try { | ||
| PDComplexFileSpecification fs = new PDComplexFileSpecification(); | ||
| PDEmbeddedFile embeddedFile = new PDEmbeddedFile(_od.getWriter(), new ByteArrayInputStream(file)); | ||
| embeddedFile.setSubtype(elem.getAttribute("data-content-type") != null ? elem.getAttribute("data-content-type") : "application/octet-stream"); | ||
| fs.setEmbeddedFile(embeddedFile); | ||
| String fileName = Paths.get(uri).getFileName().toString(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't work for custom protocol handlers reliably. I think it may be better to use another attribute, possibly There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, it may fail. Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Attributes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't know about the download attribute :D . So I could remove "data-embed-file" and use the |
||
| fs.setFile(fileName); | ||
| fs.setFileUnicode(fileName); | ||
| PDAnnotationFileAttachment annotationFileAttachment = new PDAnnotationFileAttachment(); | ||
| annotationFileAttachment.setFile(fs); | ||
|
|
||
| // hide the pin icon used by various pdf reader for signaling an embedded file | ||
| PDAppearanceDictionary appearanceDictionary = new PDAppearanceDictionary(); | ||
| PDAppearanceStream appearanceStream = new PDAppearanceStream(_od.getWriter()); | ||
| appearanceStream.setResources(new PDResources()); | ||
| appearanceDictionary.setNormalAppearance(appearanceStream); | ||
| annotationFileAttachment.setAppearance(appearanceDictionary); | ||
| // | ||
|
|
||
| annot = new PDAnnotationFileAttachmentContainer(annotationFileAttachment); | ||
| } catch (IOException e) { | ||
| XRLog.exception("Was not able to create an embedded file for embedding with uri " + uri, e); | ||
| } | ||
| } else { | ||
| XRLog.general("Was not able to load file from uri for embedding" + uri); | ||
| } | ||
| } | ||
|
|
||
| if (!placeAnnotation(transform, linkShape, targetArea, annot)) | ||
| return; | ||
|
|
||
|
|
@@ -257,9 +294,60 @@ private static boolean isURI(String uri) { | |
| } | ||
| } | ||
|
|
||
| private interface PDAnnotationContainer { | ||
| default void setRectangle(PDRectangle rectangle) {getPdAnnotation().setRectangle(rectangle);}; | ||
| default void setPrinted(boolean printed) {getPdAnnotation().setPrinted(printed);}; | ||
| default void setQuadPoints(float[] quadPoints) {}; | ||
|
|
||
| void setBorderStyle(PDBorderStyleDictionary styleDict); | ||
|
|
||
| PDAnnotation getPdAnnotation(); | ||
| } | ||
|
|
||
| private static class PDAnnotationFileAttachmentContainer implements PDAnnotationContainer { | ||
| private final PDAnnotationFileAttachment pdAnnotationFileAttachment; | ||
|
|
||
| PDAnnotationFileAttachmentContainer(PDAnnotationFileAttachment pdAnnotationFileAttachment) { | ||
| this.pdAnnotationFileAttachment = pdAnnotationFileAttachment; | ||
| } | ||
|
|
||
| @Override | ||
| public PDAnnotation getPdAnnotation() { | ||
| return pdAnnotationFileAttachment; | ||
| } | ||
|
|
||
| @Override | ||
| public void setBorderStyle(PDBorderStyleDictionary styleDict) { | ||
| pdAnnotationFileAttachment.setBorderStyle(styleDict); | ||
| } | ||
| } | ||
|
|
||
| private static class PDAnnotationLinkContainer implements PDAnnotationContainer { | ||
| private final PDAnnotationLink pdAnnotationLink; | ||
|
|
||
| private 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); | ||
| } | ||
| } | ||
|
|
||
| @SuppressWarnings("BooleanMethodIsAlwaysInverted") | ||
| private boolean placeAnnotation(AffineTransform transform, Shape linkShape, Rectangle2D targetArea, | ||
| PDAnnotationLink annot) { | ||
| PDAnnotationContainer annot) { | ||
| annot.setRectangle(new PDRectangle((float) targetArea.getMinX(), (float) targetArea.getMinY(), | ||
| (float) targetArea.getWidth(), (float) targetArea.getHeight())); | ||
|
|
||
|
|
@@ -376,7 +464,7 @@ static QuadPointShape mapShapeToQuadPoints(AffineTransform transform, Shape link | |
| return result; | ||
| } | ||
|
|
||
| private void addLinkToPage(PDPage page, PDAnnotationLink annot, Box anchor, Box target) { | ||
| private void addLinkToPage(PDPage page, PDAnnotationContainer annot, Box anchor, Box target) { | ||
| PDBorderStyleDictionary styleDict = new PDBorderStyleDictionary(); | ||
| styleDict.setWidth(0); | ||
| styleDict.setStyle(PDBorderStyleDictionary.STYLE_SOLID); | ||
|
|
@@ -386,14 +474,14 @@ private void addLinkToPage(PDPage page, PDAnnotationLink annot, Box anchor, Box | |
| List<PDAnnotation> annots = page.getAnnotations(); | ||
|
|
||
| if (annots == null) { | ||
| annots = new ArrayList<PDAnnotation>(); | ||
| annots = new ArrayList<>(); | ||
| page.setAnnotations(annots); | ||
| } | ||
|
|
||
| annots.add(annot); | ||
| annots.add(annot.getPdAnnotation()); | ||
|
|
||
| if (_pdfUa != null) { | ||
| _pdfUa.addLink(anchor, target, annot, page); | ||
| _pdfUa.addLink(anchor, target, annot.getPdAnnotation(), page); | ||
| } | ||
| } catch (IOException e) { | ||
| throw new PdfContentStreamAdapter.PdfException("processLink", e); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.