Is there a way to edit vertica aligment of the text written in a PdfFormField.
The default seems to be center, I need a bottom.
With normal setValue the text is written at the center. I tried with rectangle/canvas but did not work (here the code)
PdfPage page = form.getField(key).getWidgets().get(0).getPage();
PdfCanvas pdfCanvas = new PdfCanvas(page);
PdfArray position = formFields.get(key).getWidgets().get(0).getRectangle();
double x = position.getAsNumber(0).getValue();
double y = position.getAsNumber(1).getValue();
double xWidth = position.getAsNumber(2).getValue();
double yWidth = position.getAsNumber(3).getValue();
Rectangle rectangle = new Rectangle((float) x, (float) y, (float) xWidth, (float) yWidth);
Canvas canvas = new Canvas(pdfCanvas, pdfDoc, rectangle);
Paragraph paragraph = new Paragraph(valore);
paragraph.setFont(font);
paragraph.setVerticalAlignment(VerticalAlignment.BOTTOM);
canvas.add(paragraph);
Related
I have code written using PDFBox API that highlights the words in a PDF but when I convert highlighted PDF pages to images, then whatever I have highlighted gets disappeared from the image.
Below screenshot is with highlighted text, for highlighting I have used PDFBox's PDAnnotationTextMarkup class:
Highlighted PDF Page
Below is the image after converting the pdf page to image:
Highlighted PDF Page Image after converting
Below is the code I have used for converting PDF to Image:
PDDocument document = PDDocument.load(new File(pdfFilename));
PDFRenderer pdfRenderer = new PDFRenderer(document);
int pageCounter = 0;
for (PDPage page : document.getPages())
{
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.RGB);
ImageIOUtil.writeImage(bim, pdfFilename + "-" + (pageCounter++) + ".png", 300);
}
document.close();
Please suggest what is wrong here, why PDFRenderer not able to take PDF page image along with the highlighted red box.
Below is the code I used to highlight the text in PDF:
private void highlightText(String pdfFilePath, String highlightedPdfFilePath) {
try {
// Loading an existing document
File file = new File(highlightedPdfFilePath);
if (!file.exists()) {
file = new File(pdfFilePath);
}
PDDocument document = PDDocument.load(file);
// extended PDFTextStripper class
PDFTextStripper stripper = new PDFTextHighlighter();
// Get number of pages
int number_of_pages = document.getDocumentCatalog().getPages().getCount();
// The method writeText will invoke an override version of
// writeString
Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());
stripper.writeText(document, dummy);
// Print collected information
System.out.println("tokenStream:::"+tokenStream);
System.out.println("tokenStream size::"+tokenStream.size());
System.out.println("coordinates size::"+coordinates.size());
double page_height;
double page_width;
double width, height, minx, maxx, miny, maxy;
int rotation;
// scan each page and highlitht all the words inside them
for (int page_index = 0; page_index < number_of_pages; page_index++) {
// get current page
PDPage page = document.getPage(page_index);
// Get annotations for the selected page
List<PDAnnotation> annotations = page.getAnnotations();
// Define a color to use for highlighting text
PDColor red = new PDColor(new float[] { 1, 0, 0 }, PDDeviceRGB.INSTANCE);
// Page height and width
page_height = page.getMediaBox().getHeight();
page_width = page.getMediaBox().getWidth();
// Scan collected coordinates
for (int i = 0; i < coordinates.size(); i++) {
if (!differencePgaeNumber.contains(page_index)) {
differencePgaeNumber.add(page_index);
}
// if the current coordinates are not related to the current
// page, ignore them
if ((int) coordinates.get(i)[4] != (page_index + 1))
continue;
else {
// get rotation of the page...portrait..landscape..
rotation = (int) coordinates.get(i)[7];
// page rotated of 90degrees
if (rotation == 90) {
height = coordinates.get(i)[5];
width = coordinates.get(i)[6];
width = (page_height * width) / page_width;
// define coordinates of a rectangle
maxx = coordinates.get(i)[1];
minx = coordinates.get(i)[1] - height;
miny = coordinates.get(i)[0];
maxy = coordinates.get(i)[0] + width;
} else // i should add here the cases -90/-180 degrees
{
height = coordinates.get(i)[5];
minx = coordinates.get(i)[0];
maxx = coordinates.get(i)[2];
miny = page_height - coordinates.get(i)[1];
maxy = page_height - coordinates.get(i)[3] + height;
}
// Add an annotation for each scanned word
PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(
PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
txtMark.setColor(red);
txtMark.setConstantOpacity((float) 0.3); // 30%
// transparent
PDRectangle position = new PDRectangle();
position.setLowerLeftX((float) minx);
position.setLowerLeftY((float) miny);
position.setUpperRightX((float) maxx);
position.setUpperRightY((float) ((float) maxy + height));
txtMark.setRectangle(position);
float[] quads = new float[8];
quads[0] = position.getLowerLeftX(); // x1
quads[1] = position.getUpperRightY() - 2; // y1
quads[2] = position.getUpperRightX(); // x2
quads[3] = quads[1]; // y2
quads[4] = quads[0]; // x3
quads[5] = position.getLowerLeftY() - 2; // y3
quads[6] = quads[2]; // x4
quads[7] = quads[5]; // y5
txtMark.setQuadPoints(quads);
txtMark.setContents(tokenStream.get(i).toString());
annotations.add(txtMark);
}
}
}
// Saving the document in a new file
File highlighted_doc = new File(highlightedPdfFilePath);
document.save(highlighted_doc);
document.close();
} catch (IOException e) {
System.out.println(e);
}
}
You need to construct the visual appearance of the annotation with this call:
txtMark.constructAppearances(document);
I'm trying to rotate text using pdfbox by I couldn't achieve it. I tried to set the texMatrix but my text is not rotating as intended.
Does someone have an idea of how I could turn at 90 degrees my text?
This is my code :
contentStream.beginText();
float tx = titleWidth / 2;
float ty = titleHeight / 2;
contentStream.setTextMatrix(Matrix.getTranslateInstance(tx, ty));
contentStream.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(90),tx,ty));
contentStream.setTextMatrix(Matrix.getTranslateInstance(-tx, -ty));
contentStream.newLineAtOffset(xPos, yPos);
contentStream.setFont(font, fontSize);
contentStream.showText("Tets");
contentStream.endText();
Thank You
Here's a solution that draws three pages, one with text unrotated, one with text rotated but keeping the coordinates as if planning landscape printing, and one that is what you wanted (rotated around the center of the text). My solution is close to that, it rotates around the bottom of the center of the text.
public static void main(String[] args) throws IOException
{
PDDocument doc = new PDDocument();
PDPage page1 = new PDPage();
doc.addPage(page1);
PDPage page2 = new PDPage();
doc.addPage(page2);
PDPage page3 = new PDPage();
doc.addPage(page3);
PDFont font = PDType1Font.HELVETICA;
float fontSize = 20;
int xPos = 100;
int yPos = 400;
float titleWidth = font.getStringWidth("Tets") / 1000;
float titleHeight = fontSize;
float tx = titleWidth / 2;
float ty = titleHeight / 2;
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page1))
{
contentStream.beginText();
contentStream.newLineAtOffset(xPos, yPos);
contentStream.setFont(font, fontSize);
contentStream.showText("Tets");
contentStream.endText();
}
// classic case of rotated page
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page2))
{
contentStream.beginText();
Matrix matrix = Matrix.getRotateInstance(Math.toRadians(90), 0, 0);
matrix.translate(0, -page2.getMediaBox().getWidth());
contentStream.setTextMatrix(matrix);
contentStream.newLineAtOffset(xPos, yPos);
contentStream.setFont(font, fontSize);
contentStream.showText("Tets");
contentStream.endText();
}
// rotation around text
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page3))
{
contentStream.beginText();
Matrix matrix = Matrix.getRotateInstance(Math.toRadians(90), 0, 0);
matrix.translate(0, -page3.getMediaBox().getWidth());
contentStream.setTextMatrix(matrix);
contentStream.newLineAtOffset(yPos - titleWidth / 2 - fontSize, page3.getMediaBox().getWidth() - xPos - titleWidth / 2 - fontSize);
contentStream.setFont(font, fontSize);
contentStream.showText("Tets");
contentStream.endText();
}
doc.save("saved.pdf");
doc.close();
}
This example rotates around the left baseline of the text and uses the matrix translation to position the text at the specific point.
The showText() is always positioned at 0,0, which is the position before the rotation. The matrix translation then positions the text after the rotation.
If you want another rotation point of your text relocation the text rotation position in the contentStream.newLineAtOffset(0, 0)-line
float angle = 35;
double radians = Math.toRadians(angle);
for (int x : new int[] {50,85,125, 200})
for (int y : new int[] {40, 95, 160, 300}) {
contentStream.beginText();
// Notice the post rotation position
Matrix matrix = Matrix.getRotateInstance(radians,x,y);
contentStream.setTextMatrix(matrix);
// Notice the pre rotation position
contentStream.newLineAtOffset(0, 0);
contentStream.showText(".(" + x + "," + y + ")");
contentStream.endText();
}
To get the height and the width of the text you want to rotate use font.getBoundingBox().getHeight()/1000*fontSize and font.getStringWidth(text)/1000*fontSize.
I have created a watermark text that is vertically centered.
This is the line I used
PdfPatternPainter.showTextAlignedKerned(Element.ALIGN_MIDDLE,
string, x, y, -90);
What i want to do now is to make the watermark diagonal. changing the angle value will make it diagonal, but then its x,y position is not centered anymore.
this is my current method
public static void createWaterMarkPDF(ArrayList<String> watermark, PdfReader reader, PdfStamper stamper) throws Exception {
Rectangle pageSize = reader.getPageSize(1);
final float WATERMARK_PAGE_ANGLE = 270;
BaseFont font = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
PdfPatternPainter painter = stamper.getOverContent(1).createPattern(pageSize.getWidth(), pageSize.getHeight());
painter.setColorStroke(new BaseColor(192, 192, 192));
int FONT_SIZE = 80;
painter.beginText();
painter.setTextRenderingMode(PdfPatternPainter.TEXT_RENDER_MODE_FILL);
painter.setFontAndSize(font, FONT_SIZE);
for (int i=0; i<watermark.size(); i++) {
String string = watermark.get(i);
// Values are opposite since we are doing a vertical alignment angle
float width = font.getAscentPoint(string, FONT_SIZE) + font.getDescentPoint(string, FONT_SIZE);
float height = painter.getEffectiveStringWidth(string, true);
float x = (pageSize.getWidth() - width) / 2;
if (i == 0)
x += (width * 3);
else if (i == 2)
x -= (width * 3);
painter.showTextAlignedKerned(Element.ALIGN_MIDDLE,
string, x,
Util.transformY(pageSize, (pageSize.getHeight() - height) / 2),
WATERMARK_PAGE_ANGLE);
}
painter.endText();
// Transparency of watermark
PdfGState state = new PdfGState();
state.setFillOpacity(0.1f);
for (int i=reader.getNumberOfPages(); i>0; i--) {
Rectangle thisPageSize = reader.getPageSize(i);
PdfContentByte overContent = stamper.getOverContent(i);
overContent.setColorFill(new PatternColor(painter));
overContent.setGState(state);
overContent.rectangle(thisPageSize.getLeft(), thisPageSize.getBottom(), thisPageSize.getWidth(), thisPageSize.getHeight());
overContent.fill();
}
}
it draws vertical lines and centered. watermark is an ArrayList. you can add 3 strings.
if i change the angle to , say 300 (or -60) to make it diagonal, the positioning is whacked. do i need to use an AffineTransform here? although i already tried, didnt work for me unless i lacked something here?
I'm creating a PDF and somewhere in there I want to add a JPanel.
Using PdfContentByte and PdfGraphics2D I am able to add it to the document but:
How do I position it so it's at the left margin instead of the left page edge?
How do I prevent it from showing up over other elements?
In other words: how can I put it in a Paragraph?
Code fragment:
// multiple Paragraphs
// ...
JPanel myPanel = ...
PdfContentByte canvas = writer.getDirectContent();
int origWidth = myPanel.getWidth();
int origHeight = myPanel.getHeight();
float width = document.getPageSize().getWidth() - document.leftMargin() - document.rightMargin();
double scale = width / origWidth;
Graphics2D g2 = new PdfGraphics2D(canvas, origWidth, origHeight);
g2.scale(scale, scale);
myPanel.paint(g2);
g2.dispose();
// even more Paragraphs
//...
I got it working by using a PdfTemplate and creating an Image from that.
PdfContentByte canvas = writer.getDirectContent();
int origWidth = myPanel.getWidth();
int origHeight = myPanel.getHeight();
PdfTemplate template = canvas.createTemplate(origWidth, origHeight);
Graphics2D g2 = new PdfGraphics2D(template, origWidth, origHeight);
myPanel.paint(g2);
g2.dispose();
Image image = Image.getInstance(template);
float width = document.getPageSize().getWidth() - document.leftMargin() - document.rightMargin();
image.scaleToFit(width, 1000);
document.add(image)
How can I add page number to a page in a document generated using PDFBox?
Can anybody tell me how to add page numbers to a document after I merge different PDFs? I am using the PDFBox library in Java.
This is my code and it works well but I need to add page number.
PDFMergerUtility ut = new PDFMergerUtility();
ut.addSource("c:\\pdf1.pdf");
ut.addSource("c:\\pdf2.pdf");
ut.addSource("c:\\pdf3.pdf");
ut.mergeDocuments();
You may want to look at the PDFBox sample AddMessageToEachPage.java. The central code is:
try (PDDocument doc = PDDocument.load(new File(file)))
{
PDFont font = PDType1Font.HELVETICA_BOLD;
float fontSize = 36.0f;
for( PDPage page : doc.getPages() )
{
PDRectangle pageSize = page.getMediaBox();
float stringWidth = font.getStringWidth( message )*fontSize/1000f;
// calculate to center of the page
int rotation = page.getRotation();
boolean rotate = rotation == 90 || rotation == 270;
float pageWidth = rotate ? pageSize.getHeight() : pageSize.getWidth();
float pageHeight = rotate ? pageSize.getWidth() : pageSize.getHeight();
float centerX = rotate ? pageHeight/2f : (pageWidth - stringWidth)/2f;
float centerY = rotate ? (pageWidth - stringWidth)/2f : pageHeight/2f;
// append the content to the existing stream
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page, AppendMode.APPEND, true, true))
{
contentStream.beginText();
// set font and font size
contentStream.setFont( font, fontSize );
// set text color to red
contentStream.setNonStrokingColor(255, 0, 0);
if (rotate)
{
// rotate the text according to the page rotation
contentStream.setTextMatrix(Matrix.getRotateInstance(Math.PI / 2, centerX, centerY));
}
else
{
contentStream.setTextMatrix(Matrix.getTranslateInstance(centerX, centerY));
}
contentStream.showText(message);
contentStream.endText();
}
}
doc.save( outfile );
}
The 1.8.x pendant was:
PDDocument doc = null;
try
{
doc = PDDocument.load( file );
List allPages = doc.getDocumentCatalog().getAllPages();
PDFont font = PDType1Font.HELVETICA_BOLD;
float fontSize = 36.0f;
for( int i=0; i<allPages.size(); i++ )
{
PDPage page = (PDPage)allPages.get( i );
PDRectangle pageSize = page.findMediaBox();
float stringWidth = font.getStringWidth( message )*fontSize/1000f;
// calculate to center of the page
int rotation = page.findRotation();
boolean rotate = rotation == 90 || rotation == 270;
float pageWidth = rotate ? pageSize.getHeight() : pageSize.getWidth();
float pageHeight = rotate ? pageSize.getWidth() : pageSize.getHeight();
double centeredXPosition = rotate ? pageHeight/2f : (pageWidth - stringWidth)/2f;
double centeredYPosition = rotate ? (pageWidth - stringWidth)/2f : pageHeight/2f;
// append the content to the existing stream
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true,true);
contentStream.beginText();
// set font and font size
contentStream.setFont( font, fontSize );
// set text color to red
contentStream.setNonStrokingColor(255, 0, 0);
if (rotate)
{
// rotate the text according to the page rotation
contentStream.setTextRotation(Math.PI/2, centeredXPosition, centeredYPosition);
}
else
{
contentStream.setTextTranslation(centeredXPosition, centeredYPosition);
}
contentStream.drawString( message );
contentStream.endText();
contentStream.close();
}
doc.save( outfile );
}
finally
{
if( doc != null )
{
doc.close();
}
}
Instead of the message, you can add page numbers. And instead of the center, you can use any position.
(The example can be improved, though: the MediaBox is the wrong choice, the CropBox should be used, and the page rotation handling only appears to properly handle 0° and 90°; 180° and 270° create upside-down writing.)
It is easy, try the following code
public static void addPageNumbers(PDDocument document, String numberingFormat, int offset_X, int offset_Y) throws IOException {
int page_counter = 1;
for(PDPage page : document.getPages()){
PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, false);
contentStream.beginText();
contentStream.setFont(PDType1Font.TIMES_ITALIC, 10);
PDRectangle pageSize = page.getMediaBox();
float x = pageSize.getLowerLeftX();
float y = pageSize.getLowerLeftY();
contentStream.newLineAtOffset(x+ pageSize.getWidth()-offset_X, y+offset_Y);
String text = MessageFormat.format(numberingFormat,page_counter);
contentStream.showText(text);
contentStream.endText();
contentStream.close();
++page_counter;
}
}
public static void main(String[] args) throws Exception {
File file = new File("your input pdf path");
PDDocument document = PDDocument.load(file);
addPageNumbers(document,"Page {0}",60,18);
document.save(new File("output pdf path"));
document.close();
}