diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java
index 540a3a93c..3e9abacd2 100755
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/BlockBox.java
@@ -755,22 +755,22 @@ private void sizeReplacedElement(LayoutContext c, ReplacedElement re) {
cssWidth = !getStyle().isMaxWidthNone() &&
(intrinsicWidth > getCSSMaxWidth(c) || cssWidth > getCSSMaxWidth(c)) ?
getCSSMaxWidth(c) : cssWidth;
- cssWidth = getCSSMinWidth(c) > 0 && cssWidth < getCSSMinWidth(c) ?
+ cssWidth = cssWidth >= 0 && getCSSMinWidth(c) > 0 && cssWidth < getCSSMinWidth(c) ?
getCSSMinWidth(c) : cssWidth;
cssHeight = !getStyle().isMaxHeightNone() &&
(intrinsicHeight > getCSSMaxHeight(c) || cssHeight > getCSSMaxHeight(c)) ?
getCSSMaxHeight(c) : cssHeight;
- cssHeight = getCSSMinHeight(c) > 0 && cssHeight < getCSSMinHeight(c) ?
+ cssHeight = cssHeight >= 0 && getCSSMinHeight(c) > 0 && cssHeight < getCSSMinHeight(c) ?
getCSSMinHeight(c) : cssHeight;
if (getStyle().isBorderBox()) {
BorderPropertySet border = getBorder(c);
RectPropertySet padding = getPadding(c);
- cssWidth = (int) Math.max(0, cssWidth - border.width() - padding.width());
- cssHeight = (int) Math.max(0, cssHeight - border.height() - padding.height());
+ cssWidth = cssWidth < 0 ? cssWidth : (int) Math.max(0, cssWidth - border.width() - padding.width());
+ cssHeight = cssHeight < 0 ? cssHeight : (int) Math.max(0, cssHeight - border.height() - padding.height());
}
-
+
int nw;
int nh;
diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/simple/extend/ReplacedElementScaleHelper.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/simple/extend/ReplacedElementScaleHelper.java
index 3cd490f3f..b7f33d859 100644
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/simple/extend/ReplacedElementScaleHelper.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/simple/extend/ReplacedElementScaleHelper.java
@@ -17,15 +17,15 @@ public static AffineTransform createScaleTransform(double dotsPerPixel, Rectangl
int intrinsicWidth = (int) width;
int intrinsicHeight = (int) height;
- int desiredWidth = (int) (contentBounds.width / dotsPerPixel);
- int desiredHeight = (int) (contentBounds.height / dotsPerPixel);
+ int desiredWidth = (int) (contentBounds.getWidth() / dotsPerPixel);
+ int desiredHeight = (int) (contentBounds.getHeight() / dotsPerPixel);
AffineTransform scale = null;
-
+
if (width == 0 || height == 0) {
// Do nothing...
}
- else if (desiredWidth > intrinsicWidth &&
+ else if (desiredWidth > intrinsicWidth ||
desiredHeight > intrinsicHeight) {
double rw = (double) desiredWidth / width;
diff --git a/openhtmltopdf-examples/src/main/resources/demos/images/hello.pdf b/openhtmltopdf-examples/src/main/resources/demos/images/hello.pdf
new file mode 100644
index 000000000..e07de7ee3
Binary files /dev/null and b/openhtmltopdf-examples/src/main/resources/demos/images/hello.pdf differ
diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/html/pdf-linked-from-img-tag.html b/openhtmltopdf-examples/src/main/resources/visualtest/html/pdf-linked-from-img-tag.html
new file mode 100644
index 000000000..8537155d1
--- /dev/null
+++ b/openhtmltopdf-examples/src/main/resources/visualtest/html/pdf-linked-from-img-tag.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java
index f5d3d95f6..72a918222 100644
--- a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java
+++ b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/visualregressiontests/VisualRegressionTest.java
@@ -838,6 +838,12 @@ public void testSvgLinkedFromImgTag() throws IOException {
assertTrue(vt.runTest("svg-linked-from-img-tag", WITH_SVG));
}
+ @Test
+ @Ignore // Still a couple of pixels off with width (noticeable when there is a border).
+ public void testPdfLinkedFromImgTag() throws IOException {
+ assertTrue(vt.runTest("pdf-linked-from-img-tag"));
+ }
+
// TODO:
// + Elements that appear just on generated overflow pages.
// + content property (page counters, etc)
diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java
index 52d5a9cf7..70d6868d5 100644
--- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java
+++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java
@@ -39,6 +39,7 @@
import com.openhtmltopdf.pdfboxout.PdfBoxSlowOutputDevice.FontRun;
import com.openhtmltopdf.pdfboxout.PdfBoxSlowOutputDevice.Metadata;
import com.openhtmltopdf.render.*;
+import com.openhtmltopdf.simple.extend.ReplacedElementScaleHelper;
import com.openhtmltopdf.util.ArrayUtil;
import com.openhtmltopdf.util.XRLog;
import de.rototor.pdfbox.graphics2d.PdfBoxGraphics2D;
@@ -842,6 +843,34 @@ public void drawImage(FSImage fsImage, int x, int y, boolean interpolate) {
_cp.drawImage(xobject, (float) mx[4], (float) mx[5], (float) mx[0],
(float) mx[3]);
}
+
+ @Override
+ public void drawPdfAsImage(PDFormXObject _srcObject, Rectangle contentBounds, float intrinsicWidth, float intrinsicHeight) {
+ // We start with the page margins...
+ AffineTransform af = AffineTransform.getTranslateInstance(
+ getTransform().getTranslateX(),
+ (_pageHeight) - getTransform().getTranslateY());
+
+ // Then the x and y of this object...
+ af.translate(contentBounds.getX() / _dotsPerPoint, -(contentBounds.getY() / _dotsPerPoint));
+
+ float conversion = 96f / 72f;
+
+ // Scale to the desired height and width...
+ AffineTransform scale = ReplacedElementScaleHelper.createScaleTransform(_dotsPerPoint, contentBounds, intrinsicWidth / _dotsPerPoint * conversion, intrinsicHeight / _dotsPerPoint * conversion);
+ if (scale != null) {
+ af.concatenate(scale);
+ }
+
+ // And take into account the height of the drawn feature...
+ // And yes these transforms were all determined by trial and error!
+ af.translate(0, -((intrinsicHeight / _dotsPerPoint) * conversion));
+
+ _cp.saveGraphics();
+ _cp.applyPdfMatrix(af);
+ _cp.drawXForm(_srcObject);
+ _cp.restoreGraphics();
+ }
public float getDotsPerPoint() {
return _dotsPerPoint;
diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java
index 1bc5104b6..ead654683 100644
--- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java
+++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java
@@ -1,6 +1,7 @@
package com.openhtmltopdf.pdfboxout;
import java.awt.Paint;
+import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.RenderingHints.Key;
@@ -11,6 +12,7 @@
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.w3c.dom.Document;
import com.openhtmltopdf.bidi.BidiReorderer;
@@ -214,4 +216,6 @@ void drawWithGraphics(float x, float y, float width, float height,
List getMetadata();
-}
\ No newline at end of file
+ void drawPdfAsImage(PDFormXObject _src, Rectangle contentBounds, float intrinsicWidth, float intrinsicHeight);
+
+}
diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxPDFReplacedElement.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxPDFReplacedElement.java
new file mode 100644
index 000000000..f9f580f9c
--- /dev/null
+++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxPDFReplacedElement.java
@@ -0,0 +1,149 @@
+/*
+ * {{{ header & license
+ * Copyright (c) 2006 Wisconsin Court System
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * }}}
+ */
+package com.openhtmltopdf.pdfboxout;
+
+import com.openhtmltopdf.css.style.CssContext;
+import com.openhtmltopdf.layout.LayoutContext;
+import com.openhtmltopdf.layout.SharedContext;
+import com.openhtmltopdf.pdfboxout.PdfBoxLinkManager.IPdfBoxElementWithShapedLinks;
+import com.openhtmltopdf.render.BlockBox;
+import com.openhtmltopdf.render.Box;
+import com.openhtmltopdf.render.RenderingContext;
+import com.openhtmltopdf.swing.ImageMapParser;
+import com.openhtmltopdf.util.XRLog;
+
+import org.apache.pdfbox.multipdf.LayerUtility;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
+import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
+import org.w3c.dom.Element;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.io.IOException;
+import java.util.Map;
+import java.util.logging.Level;
+
+public class PdfBoxPDFReplacedElement implements PdfBoxReplacedElement, IPdfBoxElementWithShapedLinks {
+ private final PDFormXObject _srcFormObject;
+ private final float _width;
+ private final float _height;
+ private final Map _imageMap;
+ private Point _location = new Point(0, 0);
+
+ private PdfBoxPDFReplacedElement(PDFormXObject srcForm, Element e, Box box, CssContext ctx, SharedContext shared, float w, float h) {
+ this._srcFormObject = srcForm;
+ this._width = w;
+ this._height = h;
+ this._imageMap = ImageMapParser.findAndParseMap(e, shared);
+ }
+
+ private static int parsePage(Element e) {
+ if (e.getAttribute("page").isEmpty()) {
+ return 0;
+ }
+
+ try {
+ return Integer.parseInt(e.getAttribute("page")) - 1;
+ } catch (NumberFormatException e1) {
+ XRLog.exception("Unable to parse page of img tag with PDF!", e1);
+ }
+
+ return 0;
+ }
+
+ public static PdfBoxPDFReplacedElement create(PDDocument target, byte[] pdfBytes, Element e, Box box, CssContext ctx, SharedContext shared) {
+ try (PDDocument srcDocument = PDDocument.load(pdfBytes)){
+ int pageNo = parsePage(e);
+ if (pageNo >= srcDocument.getNumberOfPages()) {
+ XRLog.load(Level.WARNING, "Page does not exist for pdf in img tag. Ignoring!");
+ return null;
+ }
+
+ PDPage page = srcDocument.getPage(pageNo);
+ float width = page.getMediaBox().getWidth() * shared.getDotsPerPixel();
+ float height = page.getMediaBox().getHeight() * shared.getDotsPerPixel();
+
+ LayerUtility util = new LayerUtility(target);
+ PDFormXObject formXObject = util.importPageAsForm(srcDocument, page);
+
+ return new PdfBoxPDFReplacedElement(formXObject, e, box, ctx, shared, width, height);
+ } catch (InvalidPasswordException e1) {
+ XRLog.exception("Tried to open a password protected document as src for an img!", e1);
+ } catch (IOException e1) {
+ XRLog.exception("Could not read pdf passed as src for img element!", e1);
+ }
+
+ return null;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return (int) _width;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return (int) _height;
+ }
+
+ @Override
+ public Point getLocation() {
+ return _location;
+ }
+
+ @Override
+ public void setLocation(int x, int y) {
+ _location = new Point(x, y);
+ }
+
+ @Override
+ public Map getLinkMap() {
+ return _imageMap;
+ }
+
+ @Override
+ public void detach(LayoutContext c) {
+ }
+
+ @Override
+ public boolean isRequiresInteractivePaint() {
+ // N/A
+ return false;
+ }
+
+ @Override
+ public void paint(RenderingContext c, PdfBoxOutputDevice outputDevice, BlockBox box) {
+ Rectangle contentBounds = box.getContentAreaEdge(box.getAbsX(), box.getAbsY(), c);
+ outputDevice.drawPdfAsImage(_srcFormObject, contentBounds, getIntrinsicWidth(), getIntrinsicHeight());
+ }
+
+ @Override
+ public int getBaseline() {
+ return 0;
+ }
+
+ @Override
+ public boolean hasBaseline() {
+ return false;
+ }
+}
diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxReplacedElementFactory.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxReplacedElementFactory.java
index f0ee336a2..b8263c266 100644
--- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxReplacedElementFactory.java
+++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxReplacedElementFactory.java
@@ -30,8 +30,10 @@ public class PdfBoxReplacedElementFactory implements ReplacedElementFactory {
private final SVGDrawer _svgImpl;
private final SVGDrawer _mathmlImpl;
private final FSObjectDrawerFactory _objectDrawerFactory;
+ private final PdfBoxOutputDevice _outputDevice;
public PdfBoxReplacedElementFactory(PdfBoxOutputDevice outputDevice, SVGDrawer svgImpl, FSObjectDrawerFactory objectDrawerFactory, SVGDrawer mathmlImpl) {
+ _outputDevice = outputDevice;
_svgImpl = svgImpl;
_objectDrawerFactory = objectDrawerFactory;
_mathmlImpl = mathmlImpl;
@@ -63,6 +65,14 @@ public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box,
return new PdfBoxSVGReplacedElement(xml.getDocument().getDocumentElement(), _svgImpl, cssWidth, cssHeight, box, c, c.getSharedContext());
}
+ return null;
+ } else if (srcAttr.endsWith(".pdf")) {
+ byte[] pdfBytes = uac.getBinaryResource(srcAttr);
+
+ if (pdfBytes != null) {
+ return PdfBoxPDFReplacedElement.create(_outputDevice.getWriter(), pdfBytes, e, box, c, c.getSharedContext());
+ }
+
return null;
}
diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java
index 6fd1b790a..09671a263 100644
--- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java
+++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java
@@ -856,6 +856,11 @@ public void drawImage(FSImage fsImage, int x, int y, boolean interpolate) {
_cp.drawImage(xobject, (float) mx[4], (float) mx[5], (float) mx[0],
(float) mx[3]);
}
+
+ @Override
+ public void drawPdfAsImage(PDFormXObject _src, Rectangle contentBounds, float intrinsicWidth, float intrinsicHeight) {
+ throw new UnsupportedOperationException("Use the fast mode!");
+ }
/*
private void drawPDFAsImage(PDFAsImage image, int x, int y) {
URI uri = image.getURI();
diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java
index 4b1b80890..6c9ef5319 100644
--- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java
+++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfContentStreamAdapter.java
@@ -298,6 +298,14 @@ public void drawImage(PDImageXObject xobject, float x, float y, float w,
logAndThrow("drawImage", e);
}
}
+
+ public void drawXForm(PDFormXObject xObject) {
+ try {
+ cs.drawForm(xObject);
+ } catch (IOException e) {
+ logAndThrow("drawXForm", e);
+ }
+ }
public void setMiterLimit(float miterLimit) {
try {