I am producing PDF file using itextsharp,
I am printing 2 strings leading1 & leading2.
The problem is when ever leading1 lenght increases, its effecting leading2 and its gets trimmed.
But I want to print leading1 & leading2 in next line, if no.of characters in leading1 is increased.
Basically leading2 is hardcoded as = YOU DIDIT. But leading1 is dynamic value.
So , I just want to know how to position and wrap long-text.
Here is my code...
Can anyone help me in doing this?
PdfContentByte cb = writer.getDirectContent();
cb.saveState();
cb.beginText();
cb.setFontAndSize(baseFontMedium, 10f);
// float x = 6.4392f * commonView.INCH;
float x = 6.47f * commonView.INCH;
float y = pageSize.getHeight() - (1.13f * commonView.INCH);
cb.setCMYKColorFillF(0f, 0f, 0f, 0.77f);
cb.setTextMatrix(1, 0, 0, 1, x, y);
cb.showText(leading1);
x += new Chunk(leading1, fontMedium10Pt).getWidthPoint();
cb.setCMYKColorFillF(1f, 0f, 0f, 0f);
cb.setTextMatrix(1, 0, 0, 1, x, y);
cb.showText(leading2);
cb.endText();
cb.restoreState()
You have chosen to add text using PDF syntax at the lowest level. This means that you need to calculate the length of every single piece of text that you are adding to your document, and then distribute the text by adding it in different showText() sequences, making sure to adjust the coordinates correctly.
That is hard.
However, you have also chosen to use iText, which means that you can have iText do this work for you. For instance: if you want to add a snippet of text inside a specific rectangle, then you can define a ColumnText object, define a Rectangle, add the text as a Paragraph and go()!
PdfContentByte cb = writer.getDirectContent();
ColumnText ct = new ColumnText(cb);
ct.setSimpleColumn(new Rectangle(36, 600, 200, 800));
ct.addElement(new Paragraph("I want to add this text in a rectangle defined by the coordinates llx = 36, lly = 600, urx = 200, ury = 800"));
int status = ct.go();
Now the text "I want to add this text in a rectangle defined by the coordinates llx = 36, lly = 600, urx = 200, ury = 800" will be wrapped inside a rectangular area defined by the coordinates llx = 36, lly = 600, urx = 200, ury = 800. The status variable will give you an indication whether or not the text was fully rendered (or if it didn't fit completely).
Further reading:
How to fit a String inside a rectangle?
How can I truncate text within a bounding box?
Separating redundant code from pdf generator function
...
If this example helps you, please help me understand what I can do to make sure that other developers do not make the same mistake you made, and explain what made you write the code you wrote instead of trying ColumnText first. Your information will help me in writing a better book.
Related
I am converting POSPrint-data to a PDF. At one Point i need to strech the Text over 2 Lines, but with the width of the normal text. I'm trying to archive that like this:
CONTENT.beginText();
Matrix textMatrix = new Matrix();
textMatrix.scale(1f, 2f);
CONTENT.setTextMatrix(textMatrix);
CONTENT.newLineAtOffset(50, 50);
CONTENT.setCharacterSpacing(line.getLineSpacing());
CONTENT.showText(restOfLine);
CONTENT.endText();
sadly this results in the text not showing up at all. If i remove the lines for adding the textmatrix, or setting the matrix scale values to 1 this workes without any problem:
CONTENT.beginText();
Matrix textMatrix = new Matrix();
textMatrix.scale(1f, 1f);
CONTENT.setTextMatrix(textMatrix);
CONTENT.newLineAtOffset(50, 50);
CONTENT.setCharacterSpacing(line.getLineSpacing());
CONTENT.showText(restOfLine);
CONTENT.endText();
or
CONTENT.beginText();
CONTENT.newLineAtOffset(50, 50);
CONTENT.setCharacterSpacing(line.getLineSpacing());
CONTENT.showText(restOfLine);
CONTENT.endText();
Does anybody know why this happens?
I use PDFBox 2.0.25
If you are scaling the TextMatrix, also the position of the matrix is affected. To fix this unwanted behavior of moving the scaled text, you have to divide the textposition also by the scale.
CONTENT.beginText();
Matrix textMatrix = new Matrix();
textMatrix.scale(1f, 2f);
CONTENT.setTextMatrix(textMatrix);
CONTENT.newLineAtOffset(50, 50/2f); //devide y position by scale
CONTENT.setCharacterSpacing(line.getLineSpacing());
CONTENT.showText(restOfLine);
CONTENT.endText();
My requirement is straight, I want to create a rectangle positioned vertically and add text to it starting from bottom to going upward direction. (basically 90 degree box) in all pages of PDF
I tried achieving it using below code snap, but I want it to be enclosed within a specific dimension of box, which I cant control using this ColumnText approach
for example:
ColumnText.showTextAligned(canvas, PdfContentByte.ALIGN_LEFT, note,
.03F * pageWidth, .68F * pageHeight, 90);
For a task like yours the static convenience methods of ColumnText don't suffice, you need to actually create and parameterize a full ColumnText instance.
For example like this:
float width = Utilities.millimetersToPoints(10);
float height = Utilities.millimetersToPoints(100);
float x = Utilities.millimetersToPoints(15);
float y = Utilities.millimetersToPoints(150);
float fontHeight = Utilities.millimetersToPoints(4);
String content = "Some text to fill the box. There's nothing really to say, just a box to fill. So let's fill the box.";
PdfReader reader = new PdfReader(YOUR_SOURCE_FILE);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(new File(RESULT_FOLDER, "RotatedBoxForAbbas.pdf")));
Rectangle cropBox = reader.getCropBox(1);
PdfContentByte canvas = stamper.getOverContent(1);
canvas.concatCTM(0, 1, -1, 0, cropBox.getLeft() + x + width, cropBox.getBottom() + y);
canvas.rectangle(0, 0, height, width);
canvas.stroke();
ColumnText columnText = new ColumnText(canvas);
columnText.addText(new Chunk(content, new Font(FontFamily.HELVETICA, fontHeight)));
columnText.setLeading(fontHeight);
columnText.setSimpleColumn(2, 0, height - 4, width);
columnText.go();
stamper.close();
(AddTextBox test testRotatedBoxForAbbas)
(While this test has been created for iText 5, it should work identically with iText 2.1.7 and OpenPdf after adapting the import packages.)
You didn't mention dimensions in this question but in your previous, removed one you mentioned dimensions given in mm, so I also used millimeters here.
The result on an empty source page:
I'm playing around with the 2.0.0-SNAPSHOT, and I want to set the page to landscape and also rotate my picture. So I've done page.setRotation(90);
There seems to be a bug with using PDFBox and AffineTransform
This code doesn't do anything like I'd expect:
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));
Width and Height have to be tiny to keep the image on the page, rotate by itself squishes the image, and translate before rotate seems to scale the image huge.
Is this a bug, or am I just not understanding PDFBox?
Don't do an extra translation, instead put the translation when creating the AT. Remember that the rotation is around the bottom-left axis, so add the width w to the x-position.
PDPage page = new PDPage();
document.addPage(page);
page.setRotation(90);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
int x = 150;
int y = 300;
// draw unrotated
contentStream.drawXObject(ximage, x, y, ximage.getWidth() / 2, ximage.getHeight() / 2);
// draw 90° rotated, placed on the right of the first image
AffineTransform at = new AffineTransform(ximage.getHeight() / 2, 0, 0, ximage.getWidth() / 2, x + ximage1.getWidth(), y);
at.rotate(Math.toRadians(90));
contentStream.drawXObject(ximage, at);
This will draw the image twice, once normally and once rotated 90°, and positioned to the right. "/2" is used to scale 50%, you can of course use another factor. Note that "/2" is not used for the initial x position, because the (scaled) width is needed twice. Once to position to the old position (because of the axis!), and once to move it to the right so that the images don't overlap.
Note also that getHeight() and getWidth() are reversed, for the page rotation.
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));
Width and Height have to be tiny to keep the image on the page, rotate by itself squishes the image, and translate before rotate seems to scale the image huge.
Is this a bug, or am I just not understanding PDFBox?
It is not a bug, it simply is math. You merely have to be aware that if you have an AffineTransform at and then call at.translate(...) or at.rotate(...), you do not set the translation / rotation part of the affine transformation to the given values but instead replace your transformation by the composition of the former transformation and the translation / rotation.
This means that e.g.
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
is not the same as
AffineTransform at = new AffineTransform(w, 0, 0, h, 20.5, 21);
as you might have expected, but instead
AffineTransform at = new AffineTransform(w, 0, 0, h, 20 + w/2, 20 + h);
This is why Width and Height have to be tiny to keep the image on the page - translate(0.5, 1) pushes very far otherwise.
As the order in which you compose the transformation matters, you might be happier if you created your transformation in this order:
AffineTransform at = AffineTransform.getTranslateInstance(0.5, 1);
at.rotate(Math.toRadians(90));
af.concatenate(new AffineTransform(w, 0, 0, h, 20, 20));
PS: As Tilman said: Remember that the rotation is around the bottom-left, so this composition will rotate off-screen, too. Simply add h+20 to the x coordinate of the initial translation.
I have a pdf coordinate (x, y) as input . I need to draw a string at the given input coordinate[Eg :- (x,y)=(200,250)]. I am using pdfbox , When I am using the below method moveTextPositionByAmount I am not getting the exact position.Even i have tried with moveTo(). Please help me how to draw the string at an exact position ?
PDPageContentStream contentStream = new PDPageContentStream(document, page,true,true);
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.moveTextPositionByAmount(xindex, yindex);
contentStream.setNonStrokingColor(color);
contentStream.drawString(comment);
contentStream.stroke();
contentStream.endText();
Thanks.
Getting rid of graphic state changes from the existing page content
You use the PDPageContentStream constructor with two boolean arguments:
new PDPageContentStream(document, page,true,true);
This constructor is implemented as:
this(document, sourcePage, appendContent, compress, false);
i.e. it calls the constructor with three boolean arguments using false for the final one. This final boolean argument is documented as:
* #param resetContext Tell if the graphic context should be reseted.
Thus, you append to the page content without resetting the graphic context. This means that any changes to the current transformation matrix done in the existing page content still transforms your coordinates. To prevent that from happening you should use the PDPageContentStream constructor with three boolean arguments:
new PDPageContentStream(document, page, true, true, true);
Using this one can easily position text.
Drawing rectangles and test
The OP mentioned that he was successful drawing rectangles but not drawing text.
The following code
PDPage firstPage = allPages.get(0);
PDRectangle pageSize = firstPage.findMediaBox();
float x = 121;
float y = 305;
float w = 262;
float h = 104;
PDPageContentStream contentStream = new PDPageContentStream(document, firstPage, true, true, true);
contentStream.setNonStrokingColor(Color.yellow);
contentStream.fillRect(pageSize.getLowerLeftX() + x, pageSize.getLowerLeftY() + y, w, h);
contentStream.beginText();
contentStream.moveTextPositionByAmount(pageSize.getLowerLeftX() + x, pageSize.getLowerLeftY() + y);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.setNonStrokingColor(Color.red);
contentStream.drawString("My Text Here");
contentStream.endText();
contentStream.close();
results in
as would be expected.
Meaning of input coordinates must be explained
The OP also mentioned X:-121,Y:-305,W:-262,h:-104 as coordinates from external application in his comments.
As PDFs most often have positive coordinates inside the media box, these X and Y coordinates make no sense for PDFs in general.
Furthermore the OP was unable to share the document.
Therefore, it could not be found out whether or not those negative coordinates make sense for his special PDF.
Additionally negative values for widths and height are accepted by the rectangle drawing operations, but if used for text, they might imply that the Y coordinate does not denote the baseline, or that the text is not expected to start at X but to end there, or that the text shall be mirrored, or, or, or...
Thus, the meaning of those negative coordinates and dimensions must first be explained. Which is the origin of those coordinates, are the positive y coordinates above or below, is X,Y the lower left of the rectangle, what is the meaning of a negative width or height, where in relation to X, Y shall the string be drawn?
I found that this one worked for me .
PDPageContentStream contentStream = new PDPageContentStream(document, page,true,true);
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.moveTextPositionByAmount(xindex, yindex);
contentStream.setNonStrokingColor(color);
contentStream.drawString(comment);
contentStream.endText();
i tried to create rectangles as in the image, when i tried to create rectangles using coordinates the
two rectangles are placing one after other.
Here is the code how iam creating Rectangle.
when i give coordinates for two rectangles those are generating one after other, i want them to overlap as in the image..How can i make it?
PdfWriter writer= PdfWriter.getInstance(document, new FileOutputStream(filename));
document.open();
PdfContentByte cb = writer.getDirectContent();
Rectangle rect,rect1;
rect = new Rectangle(p1,p2,p3,p4); // CO-ORDINATES OF RECTANGLE
rect.setBorder(Rectangle.BOX);
cb.rectangle(rect);
Please take a look at the Rectangles example to find out how to create a PDF that looks like rectangles.pdf:
When creating a rectangle, you need the coordinates of the lower-left corner and the upper-right corner of the rectangle. For instance:
float llx = 36;
float lly = 700;
float urx = 200;
float ury = 806;
You already know that you need a PdfContentByte instance to draw the first rectangle:
PdfContentByte canvas = writer.getDirectContent();
Rectangle rect1 = new Rectangle(llx, lly, urx, ury);
rect1.setBackgroundColor(BaseColor.LIGHT_GRAY);
rect1.setBorder(Rectangle.BOX);
rect1.setBorderWidth(1);
canvas.rectangle(rect1);
For clarity, I have defined a background color and I've set the border width to 1 pt.
Now when you want to add an extra rectangle that overlaps the same way as described in your question, you need to change the llx and ury value. That's elementary math. For instance:
Rectangle rect2 = new Rectangle(llx + 60, lly, urx, ury - 40);
rect2.setBackgroundColor(BaseColor.DARK_GRAY);
rect2.setBorder(Rectangle.BOX);
rect2.setBorderColor(BaseColor.WHITE);
rect2.setBorderWidth(0.5f);
canvas.rectangle(rect2);
To make sure you see the difference, I've now used another background color, and I defined 0.5 pt as the border width and white as the border color.
It doesn't get any simpler than this.