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.
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 added a new font for my project in java. However upon rendering it the text size is always at 1 it appears. The text basically appears as just a few little lines. I tried this with multiple fonts and they all did it. This is my code.
public static void intializeFonts(){
try{
File font = new File("C:/The Woods/Fonts/script.ttf");
Font scriptFontU = Font.createFont(Font.TRUETYPE_FONT, font);
Font scriptFont = scriptFontU.deriveFont(20);
script = new TrueTypeFont(scriptFont, false);
} catch(Exception e){
System.out.println("Error Loading Font");
}
}
This is also what I am using to render it if this helps.
g.setFont(Fonts.script);
g.drawString("Weight: "+ItemContainer.getWeight()+"lbs", 30, 600);
Any help would be great. Thank You.
When you call scriptFontU.deriveFont(20), you are calling Font.deriveFont(int). In this function, the first argument is an integer representing a style. Instead, you want to call Font.deriveFont(float), which takes a size and leaves the style unchanged. You can do this by calling scriptFontU.deriveFont(20.0), or equivalent; or call Font.deriveFont(int, float) as scriptFontU.deriveFont(Font.PLAIN, 20.0) to make it unambiguous.
I am using JTextPane as a table cell renderer to display rich text. When the text is too long to fit inside a cell, it is truncated. I would like to mimic the JLabel behavior, i.e. show ellipsis (...) to alert the user that part of the text is not visible. Has anyone done this before?
Solution I ended up adopting, with help from StanislavL. The algorithm works by chopping off one character at a time off the end of StyledDocument, appending "..." and comparing resulting preferred width to table cell width. This is inefficient, especially in case of very long strings, but not a problem in my case. Can be optimized. The following goes into your renderer's getTableCellRendererComponent
m_dummyTextPane.setDocument(doc);
m_dummyTextPane.setSize(Short.MAX_VALUE, table.getRowHeight());
int width = m_dummyTextPane.getPreferredSize().width;
int start = doc.getLength() - 1;
while(width >= table.getColumnModel().getColumn(col).getWidth() && start>0) {
try {
doc.remove(Math.min(start, doc.getLength()),
doc.getLength() - Math.min(start, doc.getLength()));
doc.insertString(start, "...", null);
} catch (BadLocationException e) {
e.printStackTrace();
break;
}
start--;
width = m_dummyTextPane.getPreferredSize().width;
}
You can use this http://java-sl.com/tip_text_height_measuring.html to measure content for the fixed width. If it requires more space than available just paint something over the JTextPane.
I like the trashgod's idea with scroll too. (+1)
If a scroll bar is an acceptable alternative, but space is at a premium, you may be able to specify a JComponent.sizeVariant, as discussed in Resizing a Component and Using Client Properties.
I did it by just overriding the paint() and getToolTipText() methods, to put it in the tooltip if it's too long:
public void paint(Graphics g)
{
frc=((Graphics2D)g).getFontRenderContext();
super.paint(g);
}
public String getToolTipText(MouseEvent e)
{
String tip=null;
java.awt.Point p=e.getPoint();
int colnum=columnModel.getColumnIndexAtX(p.x);
int rowIndex=rowAtPoint(p);
String field=(String)getModel().getValueAt(rowIndex, colnum);
if (getColumnModel().getColumn(colnum).getWidth()< getFont().getStringBounds(field,frc).getWidth())
{
int i=0;
StringBuffer buf=new StringBuffer("<html>");
while (i<field.length())
{
buf.append(field.substring(i, Math.min(field.length(),i+100)));
buf.append("<br>");
i+=100;
}
tip=buf.toString();
}
return tip;
}
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).
What is the general approach with Java swing to update a textarea with lines of text (say from a Thread) and then have the text caret flow to the bottom of the textarea as text is being added. Also update the scrollbar so that it is at the bottom.
I was thinking that I would have a stringbuffer and append text to that and then set the string in the textarea and position the scrollbar at the bottom.
Use append() to add the text, then setCaretPosition() to make sure you scroll with it.
myTextPane.append(textFromSomewhere);
myTextPane.setCaretPosition(myTextPane.getDocument().getLength());
The append() method doesn't do what you want?
And although you didn't ask: when you're generating something in a background thread, be sure to use SwingUtilities.invokeLater() to update your components.
From another thread, you should use java.awt.EventQueue.invokeLater to get on the EDT and then everything works.
So:
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
Document doc = text.getDocument();
int origLen = doc.getLength()
try {
doc.insertString(origLen, msg, null);
} catch (BadLocationException exc) {
// Odd APIs forces us to deal with this nonsense.
IndexOutOfBoundsException wrapExc = new IndexOutOfBoundsException();
wrapExc.initCause(exc);
throw wrapExc;
}
// IIRC, Position is a bit odd and
if (origLen == 0) {
text.setCaretPosition(doc.getLength());
}
}});
Should anyone read the API docs for JTextArea.append it claims to be thread-safe. JDK7 removes that unlikely claim (reminder: threading is hard). As a rule, in Swing I tend to always go straight for the model/Document.
I believe if the caret is at the end it should get moved on after an append. The only exception is if there is no text, because of the strange API. If it has been moved, then we probably don't want to update it after the append.
Note: If multiple threads are doing this, you don't necessarily know which will get there first.
If you are updating from a Thread, dont forget to use SwingWorker or some other AWT Thread-safe approach.
You can update the scrollbar without reading doc.length with:
scrollbar.setValue(scrollbar.getMaximum());
Update (wrapped into Invoke later, code from Tom Hawtin)
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
try {
textArea.append(msg);
} catch (BadLocationException exc) {
// Odd APIs forces us to deal with this nonsense.
IndexOutOfBoundsException wrapExc = new IndexOutOfBoundsException();
wrapExc.initCause(exc);
throw wrapExc;
}
JScrollBar bar = scrollPane.getVerticalScrollBar();
bar.setValue(bar.getMaximum());
}});