I'm trying to insert an image in the footer of my document using iText's onCloseDocument event. I have the following code:
public void onCloseDocument(PdfWriter writer, Document document) {
PdfContentByte pdfByte = writer.getDirectContent();
try {
// logo is a non-null global variable
Image theImage = new Jpeg(logo);
pdfByte.addImage(theImage, 400.0f, 0.0f, 0.0f, 400.0f, 0.0f, 0.0f);
} catch (Exception e) { e.printStackTrace(); }
}
The code throws no exceptions, but it also fails to insert the image. This identical code is used onOpenDocument to insert the same logo. The only difference between the two methods are the coordinates in pdfByte.addImage. However, I've tried quite a few different coordinations in onCloseDocument and none of them appear anywhere in my document.
Is there any troubleshooting technique for detecting content which is displayed off-page in a PDF? If not, can anyone see the problem with my onCloseDocument method?
Edit: As a followup, it seems that onDocumentClose puts its content on page document.length() + 1 (according to its API). However, I don't know how to change the page number back to document.length() and place my logo on the last page.
The solution which worked for me (the question's author) is changing onCloseDocument to onParagraphEnd (since my document only has one paragraph).
Related
I am writing an app that generates Maths worksheets for school students. It will, for example, generate 2 to 5 pages of simple Maths questions and 1 to 2 pages of answers. The PDF can be saved to file and loaded again later. Then it has a print function that can print all the pages. I want to make it skip printing the answer pages.
Is it possible to automatically identify which pages are the answer pages? I can only think of a workaround by making those answer pages have special height or width but not even sure if this works. Are there any better ways to do this?
Ok, I continued the project and used the following method: when constructing the PDF, I put the word "Answer on the top left corner with a gray rectangle surrounding it drawn with drawRect(). Then before the actual printing, I used the following code inside the PrintDocumentAdapter() class to check whether the color of the pixel 0,0 is gray or not.
#Override
public void onStart() {
if (parcelFileDescriptor != null) {
try {
pdfRenderer = new PdfRenderer(parcelFileDescriptor);
} catch (IOException e) {
e.printStackTrace();
}
}
int tempTotal = pdfRenderer.getPageCount();
Bitmap[] tempBitmap = new Bitmap[tempTotal];
finalTotal = tempTotal;
for (int pageNum = 0; pageNum < tempTotal; pageNum++) {
PdfRenderer.Page tempPage = pdfRenderer.openPage(pageNum);
tempBitmap[pageNum] = Bitmap.createBitmap(WS_WIDTH, WS_HEIGHT, Bitmap.Config.ARGB_8888);
tempPage.render(tempBitmap[pageNum], null, null, PdfRenderer.Page.RENDER_MODE_FOR_PRINT);
if (tempBitmap[pageNum].getPixel(0, 0) == Color.GRAY) {
finalTotal--;
}
tempPage.close();
}
}
It works fine. At least should cause no problem if the users only attempt to print PDF files constructed with my app. :P
Please tell me if you know a better way to do this. Thanks!
I'm currently developing an application on Android with AndroidPDFViewer : https://github.com/barteksc/AndroidPdfViewer
I want to create a functionality, when the user touch the screen, it put a point on the PDF at this location. After I want to measure the distance between 2 points but it's an other problem.
I don't understand how to do this functionality, put a point on PDF. I found this : https://github.com/barteksc/AndroidPdfViewer/issues/554
So it's possible but how ? I don't get it.
I suppose I need to create a bitmap, but I can't draw on the PDF, or put a marker.
Thanks for your time.
You have a sample file in his repo.
If you go to this location he has already created the method on how to load a pdf! Then if you go to this link you will see that he has created the class and has included good comments
Render page fragment on {#link Surface}
Page must be opened before rendering.
public void renderPage(PdfDocument doc, Surface surface, int pageIndex,
int startX, int startY, int drawSizeX, int drawSizeY) {
renderPage(doc, surface, pageIndex, startX, startY, drawSizeX, drawSizeY, false);
}
The one that you are searching is bookmark method
/** Get table of contents (bookmarks) for given document */
public List<PdfDocument.Bookmark> getTableOfContents(PdfDocument doc) {
synchronized (lock) {
List<PdfDocument.Bookmark> topLevel = new ArrayList<>();
Long first = nativeGetFirstChildBookmark(doc.mNativeDocPtr, null);
if (first != null) {
recursiveGetBookmark(topLevel, doc, first);
}
return topLevel;
}
}
However keep in mind that it might be necessary to use Async Tasks to download a pdf!
Is there a way to create a table of contents using Java PDFBox library?
The table of contents should be clickable (jump to the right page)
Thanks.
There's no simple method for doing this, but here's an approach. I haven't figured out how to attach links directly to text, so my approach means you have to draw the annotations as rectangles and the text separately. It's a bit rough around the edges, but it works.
// there are other types of destinations, choose what is appropriate
PDPageXYZDestination dest = new PDPageXYZDestination();
// the indexing is odd here. if you are doing this on the first page of the pdf
// that page is -1, the next is 0, the next is 1 and so on. odd.
dest.setPageNumber(3);
dest.setLeft(0);
dest.setTop(0); // link to top of page, this is the XYZ part
PDActionGoTo action = new PDActionGoTo();
action.setDestination(dest);
PDAnnotationLink link = new PDAnnotationLink();
link.setAction(action);
link.setDestination(dest);
PDRectangle rect = new PDRectangle();
// just making these x,y coords up for sample
rect.setLowerLeftX(72);
rect.setLowerLeftY(600);
rect.setUpperRightX(144);
rect.setUpperRightY(620);
PDPage page = // however you are getting your table of contents page, eg new PDPage() or doc.getDocumentCatalog().getAllPages().get(0)
page.getAnnotations().add(link);
PDPageContentStream stream = new PDPageContentStream(doc, page, true, true);
stream.beginText();
stream.setTextTranslation(85, 600); // made these up, have to test to see if padding is correct
stream.drawString("Page 1");
stream.endText();
stream.close();
Phew! That's a lotta code. That should get you on your way. You can make the rectangle the same color as your document background if you want it to look like they are just clicking a link, but that requires more experimentation.
I'm creating a table in iText, but I've a problem with a cell that could be divided by a diagonal line. Someone know how can I do that?
The easiest way would be via an onGenericTag handler in a PdfPageEvent.
You give the contents of that cell a generic tag via Chunk.setGenericTag(String tag), and set up a PdfPageEvent hanlder that will draw your line when that chunk is drawn.
Something like:
public class MyPdfPageEvent extends PdfPageEventHelper {
public void onGenericTag(PdfWriter writer, Document doc, Rectangle rect, String tag) {
PdfContentByte canvas = writer.getDirectContent();
canvas.saveState();
canvas.setColorStroke(Color.BLACK); // or whatever
// You can also mess with the line's thickness, endcaps, dash style, etc.
// Lots of options to play with.
canvas.moveTo(rect.getLeft(), rect.getBottom());
canvas.lineTo(rect.getRight(), rect.getTop());
canvas.stroke();
canvas.restoreState();
}
}
Well. The answer of #Mark Storer was helpful, in this case there was a cell of a table I used "PdfPCellEvent" to inherid this methods.
Thanks Mark!
I am using iText to generate Pdf Reports for data in a database...
The header of the pages of the pdfs is an image with some text on the image added dynamically, say for example date generated..
Anyone knows if we can set background images to Tables of type PdfPTable in itext..
Thanks
I know its very late but might help someone. Here is the way to do it.
Create a class BGClass, implement PdfPCellEvent and enter following method.
#Override
public void cellLayout(PdfPCell arg0, Rectangle arg1, PdfContentByte[] arg2) {
try {
PdfContentByte pdfContentByte = arg2[PdfPTable.BACKGROUNDCANVAS];
Image bgImage = Image.getInstance("URL_TO_YOUR_IMAGE");
pdfContentByte.addImage(bgImage, arg1.getWidth(), 0, 0, arg1
.getHeight(), arg1.getLeft(), arg1.getBottom());
} catch (BadElementException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
In your main class, where you are creating PDF, pdfpCell.setCellEvent(new BGClass()); where pdfpCell is the cell for which you want background image.
Prabhat's technique has a flaw or two.
A copy of the image is added to the PDF for each cell. Store the returned Image between cellLayout calls so you'll have just one copy. If you have a 10x10 table and a 10kb image, you're taking up 1mb instead of 10kb in the PDF. Ouch. And it's actually a little worse than that with the extra overhead of all those extra objects (not a lot worse, but measurable).
It must tile the image, one per cell.
You're better off going with a PdfPTableEvent. Note that if your table spans multiple pages, your event handler will be called once for each table. The heights and widths parameters are a bit funky. The first value in each is the absolute start position. The remaining values really are heights and widths. Handy, but the variable names are a tad misleading.
And keep in mind that each instance of an image means another copy of that image in your PDF. Save 'em and reuse 'em whenever you can.