Find invisible text in iText - java

I am creating a PDF document of multiple pages using iText. I am adding some unique text on one of the pages in the middle of this document but making it invisible as-
Chunk chunk = new Chunk("invisible text here");
chunk.setTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_INVISIBLE, 0f, null);
com.lowagie.text.Document iTextDoc.add(new Paragraph(Element.ALIGN_JUSTIFIED, chunk));
The reason for adding this invisible text is to identify this particular page at the time of onEndPage(). But it is failing.
To achieve in the onEndPage(), I have the following code -
boolean b = (pdfWriter.getDirectContent().toString()).contains("invisible text here");
I get the value of b as false.
If I compare any other text on that page(which is visible) results b as true.
I tried to manually search the invisible text in the PDF reader and it finds the text.
What could I modify to achieve this?

It is never a good idea to assume you can recognize text in the content without elaborate parsing. The text may be split into multiple segments, encoding might not be platform's default character encoding, etc... Thus don't try something like
boolean b = (pdfWriter.getDirectContent().toString()).contains("invisible text here");
You can achieve your goal
The reason for adding this invisible text is to identify this particular page at the time of onEndPage().
much more easily. Simply add a member to your PdfPageEvent implementation, i.e. the class with your onEndPage() method, and set it where you used to add the invisible page content to the text you used to add to the page.
Now you can test that member variable directly in your onEndPage(). Don't forget to reset the variable afterwards, preferably in onEndPage() itself!

Related

Obtaining an Apache POI XSSFRichTextString from a textbox

How do I get an XSSFRichTextString from an Textbox in an excel spreadsheet using POI?
The setText() method is overloaded to set either a String or XSSFRichTextString but the getText() method only returns a String.
My approaches were as follows:-
Change just the text in the textbox but leave the formatting unchanged. I was hoping to get the string and simply change the text but there seems to be no setText method in XSSFRichTextString. It appears that you set the text in the constructor then apply formatting using methods. Using this does put the text in the textbox but it loses all formatting.
Extract the entire XSSFRichTextString, extract the Formatting, create a new RTS with the new text and apply the formatting. The problem is that while there is a setFont(Font object) method the getFont() returns only a short so I cannot seem to get the Font object and change it.
3 My last option is to set the plain text in the Textbox and then programmatically set all the font and formatting elements but this means burying the formatting in the Java code which means re-coding if the user needs to tweak the format instead of just using Excel.
Any suggestions?
Promoting some comments to an answer
You can't get a RichTextString from an Excel textbox. The storage model for formatted text in a textbox was changed from that in plain cells, mostly it seems to support extra features and kinds of formatting. Textbox text is a bit more Word-like in how it's structured / stored
However, there's good news - you can do what you want, and change some specific text in a textbox without changing the formatting!
Firstly, from your XSSFTextBox, call getTextParagraphs() to get the paragraphs
Next, call getTextRuns() to get the individual runs of text sharing the same formatting. Search through those until you find the one(s) containing the text you want to change. Finally, call XSSFTextRun.setText(String) to change the text of that run. The formatting will be unchanged

Changing the appearance of a checkbox field in iText

I need to be able to customize the checkbox fill type on demand as I render the pdf.
I must do this only with the AcroFields (pdfStamper.getAcroFields()), because I'm not creating any new fields (just modifying), and that's the only thing I have available to me in scope. I have tried about a hundred things, including the one listed below, which was my best guess on how to do this.
PdfDictionary dictionary = (PdfDictionary) acrofields.getFieldItem("ABCD").getWidget(0).get(PdfName.MK);
dictionary.put(PdfName.CA, new PdfString("8", PdfObject.TEXT_UNICODE));
ABCD is just for testing.
I am very stuck, and any help would be greatly appreciated. I am able to change the value in the dictionary, but it does not seem to have any affect when I write the pdf to a file. Other changes such as setting the checkbox to being checked/unchecked work, as well as populating text fields. So I as very surprised and confused why this is not working.
You're trying to change the caption of a check box, but it's unclear to me what you expect to see. Do you want to see the text "8"? In that case, changing the caption isn't sufficient. You also need to change the appearance. You can find the possible appearances under the /AP key. In the case of a check box, you'll find two possible appearance states under the normal appearance (/N). These XObjects define what you see when the PDF is rendered.

PDF Generation Using CSS and JAVA

I am generating a PDF comprised of multiple tables and I want to know if there is a certain way by which I can get to know if the table size will exceed the PDF page size or not. I am using the information to decide wether I will generate the PDF in portrait or landscape mode. Would it be possible to get this size?
know if the table size will exceed the PDF page size
The table size is determined from your XHTML Table Content (rows, columns, headers, footers, etc), plus your CSS doc(s) (width, height and border properties).
The rendering engine (ITextRenderer) only knows your table size, and whether it will fit within a page after it's applied CSS, as part of the process of converting XHTML to rendered output.
So, if you were to query ITextRenderer for this information, you would need to:
Create an ITextRenderer instance, pass your Document in via renderer.setDocument(), and then apply the CSS via renderer.layout(), causing all of the layout calculations to occur based upon the original page orientation
Query somehow to determine if the table fits on the page
If it doesn't, switch between portrait/landscape. But this means changing to a new CSS, setup for a different page shape:
Pick a new CSS, appropriate for the new page orientation and set it within your document
Create a new ITextRenderer instance, pass your Document in via renderer.setDocument(), and then apply the CSS via renderer.layout(), causing all of the layout calculations to occur based upon the new page orientation.
Create PDF output via renderer.createPDF().
Problems:
This is inefficient and inelegant processing.
This is doing things the wrong way around. Controlling page layout should be part of the design process, and should be reflected in (a) the content generated (XHTML) and (b) the formatting (CSS). If that's done correctly, there should be no need to do render-time magic to reformat the entire page.
At step (2), there's no simple query interface that will simply tell you if your table fits within a page. Instead, you have to query the formatted output blocks, and try to work out for yourself where your table is and whether it fits in a page. E.g.:
BlockBox root = renderer.getRootBox();
List pageList = root.getLayer().getPages()
PageBox page = (PageBox)pageList.get(2);
List childBoxList = page.getChildren();
Box childBox = (Box)childBoxList.get(0);
// etc... until you locate your table
At step (4), ITextRenderer expects your CSS to be linked from within your XHTML document. That means you first need to modify your XHTML source, then you need to resubmit it to ITextRenderer.
Suggested Alternative:
Do a wireframe/sketch design with 2 scenarios - one for portrait & one for landscape
Determine the size of elements/rows/columns under the 2 scenarios
Determine the condition logic under which you would use each scenario, portrait v landscape. E.g. if I the number of rows is X and the number of columns is Y - then use landscape, ...
Now create the two CSS files
Now, when you generate your XHTML, use the condition logic to link to the correct CSS

Making words different colors in JTextField/JTextPane/?

I'm trying and failing to understand how to use Java's text editor components to colorize text as you insert it. I don't want or need a fully featured syntax highlighting library.
Basically, I have a JTextField (or some other JText... component), and a list of words. I want any words in the field that appear in the list to be red, and the rest of the words be green. So for example, if "fire" is in the list, "fir" would appear green and "fire" would appear red.
I've tried using a JTextPane and a DefaultStyledDocument, using a KeyListener to go over the text in the document and using AbstractStyledDocument.replace to replace the existing words with versions that have the correct attributes. This didn't do anything. What am I doing wrong?
Neither JTextPane nor JTextField isn't able to present formatted text, i.e text having more than one format. For text-editor-like capabilities like you'd find in WordPad or HTML, the component to use is the JEditorPane or its descendant, JTextPane.
The simplest thing you can do is set the ContentType of the JEditorPane to "text/html" and simply set its text to a string containing HTML. The Java structured text components are surprisingly competent with HTML; you can display tables and/or DIVs, and there is support for much of CSS2. Simplest to do your styles inline, but you can even do external style hrefs.
If you want to get fancy programmatically, you can access the DocumentModel and create text from spans of text each having their own formatting. The DocumentModel works essentially like a programmable text editor.
EDIT: Re-reading your question, I see my answer doesn't quite address it. Since you want multi-colored text JEditorPane is your only option; but rather than just piping in pre-colored text via HTML or such, you'll have to put a listener on your document model to catch changes introduced when you type; and after every document change you'll want to examine the text (again from the Document model) for text that should or should not be highlighted, and you'll want to apply formatting to certain runs of text.
There are devils in the details, but this should get you started.

Selecting specified text in an HTML formatted JEditorPane

I am displaying text in a Java JEditorPane using HTML to fomrat the text. I am also designing a search function that finds text in the JEditorPane selects the text and then scrolls to it. My problem is creating an algorithim that will actually specify the beginning and ending position for the selection.
If I simply retrieve the text using myeditorpane.getText(), then find the search string in the result, the wrong selection start and end positions are calculated with the wrong text being selected (the tags are throwing the calculation off). I tried removing the html tags by executing a replace all function text.().replaceAll("\<.*?>","") before searching for the text (this replace all removes all text in between the tags) but still the wrong selection points are calculated (although I'm getting close :-)).
Does anyone have an easy way to do this?
Thanks,
Elliott
You probably want to be working with the underlying Document, rather than the raw text, as suggested in this HighlightExample.
You need to find the start location of the text. I guess something like:
int offset = editorPane().getDocument().getText().indexof(...);
Then to scroll you can use:
editorPane.scrollRectToVisible( editorPane.viewToModel(offset) );
Read up on Text and New Lines for more info.

Categories