float width = mediabox.getWidth() - 2*margin; float startX = mediabox.getLowerLeftX() + margin; float startY = mediabox.getUpperRightY() - margin;
float width = mediabox.getWidth() - 2*margin; float startX = mediabox.getLowerLeftX() + margin; float startY = mediabox.getUpperRightY() - margin;
/** * Calculate the transform to be used when positioning the overlay. The default implementation * centers on the destination. Override this method to do your own, e.g. move to a corner, or * rotate. * * @param page The page that will get the overlay. * @param overlayMediaBox The overlay media box. * @return The affine transform to be used. */ protected AffineTransform calculateAffineTransform(PDPage page, PDRectangle overlayMediaBox) { AffineTransform at = new AffineTransform(); PDRectangle pageMediaBox = page.getMediaBox(); float hShift = (pageMediaBox.getWidth() - overlayMediaBox.getWidth()) / 2.0f; float vShift = (pageMediaBox.getHeight() - overlayMediaBox.getHeight()) / 2.0f; at.translate(hShift, vShift); return at; }
public Rectangle2D getBounds() { Point2D size = new Point2D.Double(pageSize.getWidth(), pageSize.getHeight()); // apply the underlying Graphics2D device's DPI transform and y-axis flip Matrix m = new Matrix(xform); AffineTransform dpiTransform = AffineTransform.getScaleInstance(Math.abs(m.getScalingFactorX()), Math.abs(m.getScalingFactorY())); size = dpiTransform.transform(size, size); // Flip y return new Rectangle2D.Double(minX - pageSize.getLowerLeftX() * Math.abs(m.getScalingFactorX()), size.getY() - minY - height + pageSize.getLowerLeftY() * Math.abs(m.getScalingFactorY()), width, height); } }
private void drawNote(PDAnnotationText annotation, final PDAppearanceContentStream contentStream) throws IOException { PDRectangle bbox = adjustRectAndBBox(annotation, 18, 20); contentStream.setMiterLimit(4); // get round edge the easy way. Adobe uses 4 lines with 4 arcs of radius 0.785 which is bigger. contentStream.setLineJoinStyle(1); contentStream.setLineCapStyle(0); contentStream.setLineWidth(0.61f); // value from Adobe contentStream.addRect(1, 1, bbox.getWidth() - 2, bbox.getHeight() - 2); contentStream.moveTo(bbox.getWidth() / 4, bbox.getHeight() / 7 * 2); contentStream.lineTo(bbox.getWidth() * 3 / 4 - 1, bbox.getHeight() / 7 * 2); contentStream.moveTo(bbox.getWidth() / 4, bbox.getHeight() / 7 * 3); contentStream.lineTo(bbox.getWidth() * 3 / 4 - 1, bbox.getHeight() / 7 * 3); contentStream.moveTo(bbox.getWidth() / 4, bbox.getHeight() / 7 * 4); contentStream.lineTo(bbox.getWidth() * 3 / 4 - 1, bbox.getHeight() / 7 * 4); contentStream.moveTo(bbox.getWidth() / 4, bbox.getHeight() / 7 * 5); contentStream.lineTo(bbox.getWidth() * 3 / 4 - 1, bbox.getHeight() / 7 * 5); contentStream.fillAndStroke(); }
@Override void constructAppearances() throws IOException { PDAnnotationWidget widget = this.getWidgets().get(0); if (widget != null) { // check if the signature is visible if (widget.getRectangle() == null || Float.compare(widget.getRectangle().getHeight(), 0) == 0 && Float.compare(widget.getRectangle().getWidth(), 0) == 0 || widget.isNoView() || widget.isHidden()) { return; } // TODO: implement appearance generation for signatures LOG.warn("Appearance generation for signature fields not yet implemented - you need to generate/update that manually"); } } }
/** * Get a padded rectangle. * * <p>Creates a new rectangle with padding applied to each side. * . * @param rectangle the rectangle. * @param padding the padding to apply. * @return the padded rectangle. */ PDRectangle getPaddedRectangle(PDRectangle rectangle, float padding) { return new PDRectangle(rectangle.getLowerLeftX() + padding, rectangle.getLowerLeftY() + padding, rectangle.getWidth() - 2 * padding, rectangle.getHeight() - 2 * padding); }
/** * Apply padding to a box. * * @param box box * @return the padded box. */ private PDRectangle applyPadding(PDRectangle box, float padding) { return new PDRectangle(box.getLowerLeftX() + padding, box.getLowerLeftY() + padding, box.getWidth() - 2 * padding, box.getHeight() - 2 * padding); } }
/** * This will create a translated rectangle based off of this rectangle, such * that the new rectangle retains the same dimensions(height/width), but the * lower left x,y values are zero. <br> * 100, 100, 400, 400 (llx, lly, urx, ury ) <br> * will be translated to 0,0,300,300 * * @return A new rectangle that has been translated back to the origin. */ public PDRectangle createRetranslatedRectangle() { PDRectangle retval = new PDRectangle(); retval.setUpperRightX( getWidth() ); retval.setUpperRightY( getHeight() ); return retval; }
/** * Each page of document can be different sizes. This method calculates the page size based on * the page media box. * * @param document * @param page The 1-based page number for which the page size should be calculated. * @throws IllegalArgumentException if the page argument is lower than 0. */ private void calculatePageSize(PDDocument document, int page) { if (page < 1) { throw new IllegalArgumentException("First page of pdf is 1, not " + page); } PDPage firstPage = document.getPage(page - 1); PDRectangle mediaBox = firstPage.getMediaBox(); pageHeight(mediaBox.getHeight()); pageWidth = mediaBox.getWidth(); imageSizeInPercents = 100; rotation = firstPage.getRotation() % 360; }
private void drawInsert(PDAnnotationText annotation, final PDAppearanceContentStream contentStream) throws IOException { PDRectangle bbox = adjustRectAndBBox(annotation, 17, 20); contentStream.setMiterLimit(4); contentStream.setLineJoinStyle(0); contentStream.setLineCapStyle(0); contentStream.setLineWidth(0.59f); // value from Adobe contentStream.moveTo(bbox.getWidth() / 2 - 1, bbox.getHeight() - 2); contentStream.lineTo(1, 1); contentStream.lineTo(bbox.getWidth() - 2, 1); contentStream.closeAndFillAndStroke(); }
/** * Get a rectangle enlarged by the differences. * * <p> * Creates a new rectangle with differences added to each side. If there are no valid * differences, then the original rectangle is returned. * * @param rectangle the rectangle. * @param differences the differences to apply. * @return the padded rectangle. */ PDRectangle addRectDifferences(PDRectangle rectangle, float[] differences) { if (differences == null || differences.length != 4) { return rectangle; } return new PDRectangle(rectangle.getLowerLeftX() - differences[0], rectangle.getLowerLeftY() - differences[1], rectangle.getWidth() + differences[0] + differences[2], rectangle.getHeight() + differences[1] + differences[3]); }
/** * This will find the CropBox with rotation applied, for this page by looking up the hierarchy * until it finds them. * * @return The CropBox at this level in the hierarchy. */ static PDRectangle getRotatedCropBox(PDPage page) { PDRectangle cropBox = page.getCropBox(); int rotationAngle = page.getRotation(); if (rotationAngle == 90 || rotationAngle == 270) { return new PDRectangle(cropBox.getLowerLeftY(), cropBox.getLowerLeftX(), cropBox.getHeight(), cropBox.getWidth()); } else { return cropBox; } }
/** * This will find the MediaBox with rotation applied, for this page by looking up the hierarchy * until it finds them. * * @return The MediaBox at this level in the hierarchy. */ static PDRectangle getRotatedMediaBox(PDPage page) { PDRectangle mediaBox = page.getMediaBox(); int rotationAngle = page.getRotation(); if (rotationAngle == 90 || rotationAngle == 270) { return new PDRectangle(mediaBox.getLowerLeftY(), mediaBox.getLowerLeftX(), mediaBox.getHeight(), mediaBox.getWidth()); } else { return mediaBox; } } }
private void drawStar(PDAnnotationText annotation, final PDAppearanceContentStream contentStream) throws IOException { PDRectangle bbox = adjustRectAndBBox(annotation, 20, 19); float min = Math.min(bbox.getWidth(), bbox.getHeight()); contentStream.setMiterLimit(4); contentStream.setLineJoinStyle(1); contentStream.setLineCapStyle(0); contentStream.setLineWidth(0.59f); // value from Adobe contentStream.transform(Matrix.getScaleInstance(0.001f * min / 0.8f, 0.001f * min / 0.8f)); // we get the shape of a Zapf Dingbats star (0x2605) and use that one. // Adobe uses a different font (which one?), or created the shape from scratch. GeneralPath path = PDType1Font.ZAPF_DINGBATS.getPath("a35"); addPath(contentStream, path); contentStream.fillAndStroke(); }
private void drawCheck(PDAnnotationText annotation, final PDAppearanceContentStream contentStream) throws IOException { PDRectangle bbox = adjustRectAndBBox(annotation, 20, 19); float min = Math.min(bbox.getWidth(), bbox.getHeight()); contentStream.setMiterLimit(4); contentStream.setLineJoinStyle(1); contentStream.setLineCapStyle(0); contentStream.setLineWidth(0.59f); // value from Adobe contentStream.transform(Matrix.getScaleInstance(0.001f * min / 0.8f, 0.001f * min / 0.8f)); contentStream.transform(Matrix.getTranslateInstance(0, 50)); // we get the shape of a Zapf Dingbats check (0x2714) and use that one. // Adobe uses a different font (which one?), or created the shape from scratch. GeneralPath path = PDType1Font.ZAPF_DINGBATS.getPath("a20"); addPath(contentStream, path); contentStream.fillAndStroke(); }
private void drawRightPointer(PDAnnotationText annotation, final PDAppearanceContentStream contentStream) throws IOException { PDRectangle bbox = adjustRectAndBBox(annotation, 20, 17); float min = Math.min(bbox.getWidth(), bbox.getHeight()); contentStream.setMiterLimit(4); contentStream.setLineJoinStyle(1); contentStream.setLineCapStyle(0); contentStream.setLineWidth(0.59f); // value from Adobe contentStream.transform(Matrix.getScaleInstance(0.001f * min / 0.8f, 0.001f * min / 0.8f)); contentStream.transform(Matrix.getTranslateInstance(0, 50)); // we get the shape of a Zapf Dingbats right pointer (0x27A4) and use that one. // Adobe uses a different font (which one?), or created the shape from scratch. GeneralPath path = PDType1Font.ZAPF_DINGBATS.getPath("a174"); addPath(contentStream, path); contentStream.fillAndStroke(); }
private void drawCrossHairs(PDAnnotationText annotation, final PDAppearanceContentStream contentStream) throws IOException { PDRectangle bbox = adjustRectAndBBox(annotation, 20, 20); float min = Math.min(bbox.getWidth(), bbox.getHeight()); contentStream.setMiterLimit(4); contentStream.setLineJoinStyle(0); contentStream.setLineCapStyle(0); contentStream.setLineWidth(0.61f); // value from Adobe contentStream.transform(Matrix.getScaleInstance(0.001f * min / 1.5f, 0.001f * min / 1.5f)); contentStream.transform(Matrix.getTranslateInstance(0, 50)); // we get the shape of a Symbol crosshair (0x2295) and use that one. // Adobe uses a different font (which one?), or created the shape from scratch. GeneralPath path = PDType1Font.SYMBOL.getPath("circleplus"); addPath(contentStream, path); contentStream.fillAndStroke(); }
private static void showPageNo(PDDocument document, PDPage page, String pageText) throws IOException { int fontSize = 10; try (PDPageContentStream contents = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, true)) { float pageWidth = page.getMediaBox().getWidth(); float pageHeight = page.getMediaBox().getHeight(); PDFont font = PDType1Font.HELVETICA; contents.setFont(font, fontSize); float textWidth = font.getStringWidth(pageText) / 1000 * fontSize; contents.beginText(); contents.newLineAtOffset(pageWidth / 2 - textWidth / 2, pageHeight - INCH / 2); contents.showText(pageText); contents.endText(); } } }
@Override public void injectAppearanceStreams(PDStream holderFormStream, PDStream innerFormStream, PDStream imageFormStream, COSName imageFormName, COSName imageName, COSName innerFormName, PDVisibleSignDesigner properties) throws IOException { // Use width and height of BBox as values for transformation matrix. int width = (int) this.getStructure().getFormatterRectangle().getWidth(); int height = (int) this.getStructure().getFormatterRectangle().getHeight(); String imgFormContent = "q " + width + " 0 0 " + height + " 0 0 cm /" + imageName.getName() + " Do Q\n"; String holderFormContent = "q 1 0 0 1 0 0 cm /" + innerFormName.getName() + " Do Q\n"; String innerFormContent = "q 1 0 0 1 0 0 cm /n0 Do Q q 1 0 0 1 0 0 cm /" + imageFormName.getName() + " Do Q\n"; appendRawCommands(pdfStructure.getHolderFormStream().createOutputStream(), holderFormContent); appendRawCommands(pdfStructure.getInnerFormStream().createOutputStream(), innerFormContent); appendRawCommands(pdfStructure.getImageFormStream().createOutputStream(), imgFormContent); LOG.info("Injected appearance stream to pdf"); }