How to fill PDF form with specific font using pdfbox? - pdf

I am trying to fill pdf form and I am able to fill it using the following approach through PDFBox library.
val pdf: PDDocument = PDDocument.load(file)
pdf.setAllSecurityToBeRemoved(true)
val docCatalog: PDDocumentCatalog = pdf.getDocumentCatalog
val acroForm: PDAcroForm = docCatalog.getAcroForm
def populateFields(inputJson: String, targetPdfPath: String): Unit = {
val valueMap: Array[Field] = gson.fromJson(inputJson, classOf[Array[Field]])
valueMap.foreach((field) => {
val pdField: PDField = acroForm.getField(field.name)
if (pdField != null) {
pdField.setValue(field.value)
} else {
println(s"No field with name ${field.name}")
}
})
pdf.save(targetPdfPath)
pdf.close()
}
The only problem is, I don't see any option to set the font before filling the pdf. Can you help me here?

You can achieve it by using these methods (note that you have to use PDFBox 1.8.15, not the newer 2.0).
// Set the field with custom font.
private void setField(String name, String value, String fontSource) throws IOException {
PDDocumentCatalog docCatalog;
PDAcroForm acroForm;
PDField field;
COSDictionary dict;
COSString defaultAppearance;
docCatalog = pdfTemplate.getDocumentCatalog();
acroForm = docCatalog.getAcroForm();
field = acroForm.getField(name);
dict = (field).getDictionary();
defaultAppearance = (COSString) dict.getDictionaryObject(COSName.DA);
if (defaultAppearance != null)
{
dict.setString(COSName.DA, "/" + fontName + " 10 Tf 0 g");
if (name.equalsIgnoreCase("Field1")) {
dict.setString(COSName.DA, "/" + fontName + " 12 Tf 0 g");
}
}
if (field instanceof PDTextbox)
{
field = new PDTextbox(acroForm, dict);
(field).setValue(value);
}
}
// Set the field with custom font.
private List<String> prepareFont(PDDocument _pdfDocument, List<PDFont> fonts) {
PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
PDResources res = acroForm.getDefaultResources();
if (res == null)
res = new PDResources();
List<String> fontNames = new ArrayList<>();
for (PDFont font: fonts)
{
fontNames.add(res.addFont(font));
}
acroForm.setDefaultResources(res);
return fontNames;
}
// Set the field with custom font.
private PDFont loadTrueTypeFont(PDDocument _pdfDocument, String resourceName) throws IOException
{
return PDTrueTypeFont.loadTTF(_pdfDocument, new File(resourceName));
}
Now, you only have to source the method setField with the name of the field, the value you want to insert and a string which is the path to the TTF font you wanna use.
Hope it helps!

Related

Traverse whole PDF and change blue color to black ( Change color of underlines as well) + iText

I am using below code to remove blue colors from pdf text. It is working fine. But it is not changing underlines color, but changing text color correctly.
original file part:
Manipulated File:
As you see in above manipulated file, underline color didn't change.
I am looking fix for this thing since two weeks, can anyone help on this. Below is my change color code:
public void testChangeBlackTextToGreenDocument(String source, String filename) throws IOException {
try (InputStream resource = getClass().getResourceAsStream(source);
PdfReader pdfReader = new PdfReader(source);
OutputStream result = new FileOutputStream(filename);
PdfWriter pdfWriter = new PdfWriter(result);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter);) {
PdfCanvasEditor editor = new PdfCanvasEditor() {
#Override
protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands) {
String operatorString = operator.toString();
if (TEXT_SHOWING_OPERATORS.contains(operatorString)) {
List<PdfObject> listobj = new ArrayList<>();
listobj.add(new PdfNumber(0));
listobj.add(new PdfNumber(0));
listobj.add(new PdfNumber(0));
listobj.add(new PdfLiteral("rg"));
if (currentlyReplacedBlack == null) {
Color currentFillColor =getGraphicsState().getFillColor();
if (ColorConstants.GREEN.equals(currentFillColor) || ColorConstants.CYAN.equals(currentFillColor) || ColorConstants.BLUE.equals(currentFillColor)) {
currentlyReplacedBlack = currentFillColor;
super.write(processor, new PdfLiteral("rg"), listobj);
}
}
} else if (currentlyReplacedBlack != null) {
if (currentlyReplacedBlack instanceof DeviceCmyk) {
List<PdfObject> listobj = new ArrayList<>();
listobj.add(new PdfNumber(0));
listobj.add(new PdfNumber(0));
listobj.add(new PdfNumber(0));
listobj.add(new PdfNumber(0));
listobj.add(new PdfLiteral("k"));
super.write(processor, new PdfLiteral("k"), listobj);
} else if (currentlyReplacedBlack instanceof DeviceGray) {
List<PdfObject> listobj = new ArrayList<>();
listobj.add(new PdfNumber(0));
listobj.add(new PdfLiteral("g"));
super.write(processor, new PdfLiteral("g"), listobj);
} else {
List<PdfObject> listobj = new ArrayList<>();
listobj.add(new PdfNumber(0));
listobj.add(new PdfNumber(0));
listobj.add(new PdfNumber(0));
listobj.add(new PdfLiteral("rg"));
super.write(processor, new PdfLiteral("rg"), listobj);
}
currentlyReplacedBlack = null;
}
super.write(processor, operator, operands);
}
Color currentlyReplacedBlack = null;
final List<String> TEXT_SHOWING_OPERATORS = Arrays.asList("Tj", "'", "\"", "TJ");
};
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
editor.editPage(pdfDocument, i);
}
}
File file = new File(source);
file.delete();
}
Here is the original file.
https://raad-dev-test.s3.ap-south-1.amazonaws.com/36/2019-08-30/originalFile.pdf
Related Links:
Traverse whole PDF and change some attribute with some object in it using iText
Removing Watermark from PDF iTextSharp
Maven Dependcy Details:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.5</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.0.6</version>
</dependency>
Edited:
Accepted answer is not working for below files:
https://raad-dev-test.s3.ap-south-1.amazonaws.com/36/2019-08-30/021549Orig1s025_aprepitant_clinpharm_prea_Mac.pdf (Page 41)
https://raad-dev-test.s3.ap-south-1.amazonaws.com/36/2019-08-30/400_206494S5_avibactam_and_ceftazidine_unireview_prea_Mac.pdf (Page 60).
Please Help.
(The example code here uses iText 7 for Java. You mentioned neither the iText version nor your programming environment in tags or question text but your example code appears to indicate that this is your combination of choice.)
Replacing blue fill colors
The test you based your original code on attempts explicitly only to change text color. The "underline" in your document, though, is (as far as PDF drawing is concerned) not part of the text but instead drawn as a simple path. Thus, the underline explicitly is not touched by the original code and it has to be adapted for your task.
But actually your task, changing everything blue to black, is easier to implement than only changing the blue text, e.g.
try ( PdfReader pdfReader = new PdfReader(SOURCE_PDF);
PdfWriter pdfWriter = new PdfWriter(RESULT_PDF);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) )
{
PdfCanvasEditor editor = new PdfCanvasEditor()
{
#Override
protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
{
String operatorString = operator.toString();
if (SET_FILL_RGB.equals(operatorString) && operands.size() == 4) {
if (isApproximatelyEqual(operands.get(0), 0) &&
isApproximatelyEqual(operands.get(1), 0) &&
isApproximatelyEqual(operands.get(2), 1)) {
super.write(processor, new PdfLiteral("g"), Arrays.asList(new PdfNumber(0), new PdfLiteral("g")));
return;
}
}
super.write(processor, operator, operands);
}
boolean isApproximatelyEqual(PdfObject number, float reference) {
return number instanceof PdfNumber && Math.abs(reference - ((PdfNumber)number).floatValue()) < 0.01f;
}
final String SET_FILL_RGB = "rg";
};
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++)
{
editor.editPage(pdfDocument, i);
}
}
(ChangeColor test testChangeFillRgbBlueToBlack)
Beware, this is merely a proof-of-concept, not a final and complete solution. In particular:
It merely looks at the fill (non-stroking) colors. In your case that suffices as both your text (as usual) and your underline use fill colors only - the underline actually is not drawn as a stroked line but instead as a slim, filled rectangle.
Only RGB blue (and only such blue set using the rg instruction, not set using sc or scn, let alone blues combined out of other colors using funky blend modes) is considered. This might be an issue particularly in case of documents explicitly designed for printing (likely using CMYK colors).
PdfCanvasEditor only inspects and edits the content stream of the page itself, not the content streams of displayed form XObjects or patterns; thus, some content may not be found. It can be generalized fairly easily.
The result:
Replacing blue fill and stroke colors
Testing the code above you soon found documents in which the underlines were not changed. As it turned out, these underlines are actually drawn as stroked lines, not as filled rectangle as above.
To also properly edit such documents, therefore, you must not only edit the fill colors but also the stroke colors, e.g. like this:
try ( PdfReader pdfReader = new PdfReader(SOURCE_PDF);
PdfWriter pdfWriter = new PdfWriter(RESULT_PDF);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) )
{
PdfCanvasEditor editor = new PdfCanvasEditor()
{
#Override
protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
{
String operatorString = operator.toString();
if (SET_FILL_RGB.equals(operatorString) && operands.size() == 4) {
if (isApproximatelyEqual(operands.get(0), 0) &&
isApproximatelyEqual(operands.get(1), 0) &&
isApproximatelyEqual(operands.get(2), 1)) {
super.write(processor, new PdfLiteral("g"), Arrays.asList(new PdfNumber(0), new PdfLiteral("g")));
return;
}
}
if (SET_STROKE_RGB.equals(operatorString) && operands.size() == 4) {
if (isApproximatelyEqual(operands.get(0), 0) &&
isApproximatelyEqual(operands.get(1), 0) &&
isApproximatelyEqual(operands.get(2), 1)) {
super.write(processor, new PdfLiteral("G"), Arrays.asList(new PdfNumber(0), new PdfLiteral("G")));
return;
}
}
super.write(processor, operator, operands);
}
boolean isApproximatelyEqual(PdfObject number, float reference) {
return number instanceof PdfNumber && Math.abs(reference - ((PdfNumber)number).floatValue()) < 0.01f;
}
final String SET_FILL_RGB = "rg";
final String SET_STROKE_RGB = "RG";
};
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++)
{
editor.editPage(pdfDocument, i);
}
}
(ChangeColor tests testChangeRgbBlueToBlackControlOfNitrosamineImpuritiesInSartansRev and testChangeRgbBlueToBlackEdqmReportsIssuesOfNonComplianceWithToothMac)
The results:
and
Replacing different shades of blue from other RGB'ish color spaces
Testing the code above you again found documents in which the blue colors were not changed. As it turned out, these blue colors were not from the DeviceRGB standard RGB but instead from ICCBased colorspaces, profiled RGB color spaces to be more exact. In particular other color setting operators were used than before, sc / scn instead of rg. Furthermore, in one document not a pure blue 0 0 1 but instead a .17255 .3098 .63529 blue was used
If we assume that sc and scn instructions with three numeric arguments set some flavor of RGB colors as here (in general this is an oversimplification, Lab and other color spaces can also come with 4 components, but your documents seem RGB oriented) and are less strict in recognizing the blue color, we can generalize the code above as follows:
class AllRgbBlueToBlackConverter extends PdfCanvasEditor {
#Override
protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
{
String operatorString = operator.toString();
if (RGB_SETTER_CANDIDATES.contains(operatorString) && operands.size() == 4) {
if (isBlue(operands.get(0), operands.get(1), operands.get(2))) {
PdfNumber number0 = new PdfNumber(0);
operands.set(0, number0);
operands.set(1, number0);
operands.set(2, number0);
}
}
super.write(processor, operator, operands);
}
boolean isBlue(PdfObject red, PdfObject green, PdfObject blue) {
if (red instanceof PdfNumber && green instanceof PdfNumber && blue instanceof PdfNumber) {
float r = ((PdfNumber)red).floatValue();
float g = ((PdfNumber)green).floatValue();
float b = ((PdfNumber)blue).floatValue();
return b > .5f && r < .9f*b && g < .9f*b;
}
return false;
}
final Set<String> RGB_SETTER_CANDIDATES = new HashSet<>(Arrays.asList("rg", "RG", "sc", "SC", "scn", "SCN"));
}
(ChangeColor helper class)
Used like this
try ( PdfReader pdfReader = new PdfReader(INPUT);
PdfWriter pdfWriter = new PdfWriter(OUTPUT);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) ) {
PdfCanvasEditor editor = new AllRgbBlueToBlackConverter();
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++)
{
editor.editPage(pdfDocument, i);
}
}
we get
and

itext pdf verify if signature is visible or invisible

I am currently using Itext 5.4.4 and I would like to know if it is possible to check if a signature in my current PDF is visible or invisible. Is this possible? Or do I have to upgrade to a newer versiĆ³n of Itext?
You can do it like the code below. Other flags are easily added..
PdfReader reader; //instantiate
AcroFields acroFields = reader.getAcroFields();
Map<String, Item> fieldNames = acroFields.getFields();
Set<Entry<String, Item>> entries = fieldNames.entrySet();
Iterator<Entry<String, Item>> it = entries.iterator();
while(it.hasNext()){
Entry<String, Item> entry = it.next();
//Check flags
boolean invisible = isInvisible(entry.getValue());
boolean mandatory = isMandatory(entry.getValue());
boolean noView = isNoView(entry.getValue());
boolean hidden = isHidden(entry.getValue());
...
}
public static boolean isInvisible(Item item) {
//Add a nullcheck!
if(item.size()>0) {
PdfDictionary d = item.getMerged(0);
PdfNumber num = (PdfNumber) d.get(PdfName.F);
return num == null ? false : ((num.intValue() & PdfAnnotation.FLAGS_INVISIBLE) == PdfAnnotation.FLAGS_INVISIBLE);
}
return false;
}
public static boolean isMandatory(Item item) {
//Add a null check here!
if(item.size()>0) {
PdfDictionary d = item.getMerged(0);
PdfNumber num = (PdfNumber) d.get(PdfName.FF);
return num == null ? false : ((num.intValue() & PdfFormField.FF_REQUIRED) == PdfFormField.FF_REQUIRED);
}
return false;
}
public static boolean isNoView(Item item) {
//nullcheck!
if(item.size()>0) {
PdfDictionary d = item.getMerged(0);
PdfNumber num = (PdfNumber) d.get(PdfName.F);
return num == null ? false : ((num.intValue() & PdfAnnotation.FLAGS_NOVIEW) == PdfAnnotation.FLAGS_NOVIEW);
}
return false;
}
public static boolean isHidden(Item item) {
//Nullcheck!
if(item.size()>0) {
PdfDictionary d = item.getMerged(0);
PdfNumber num = (PdfNumber) d.get(PdfName.F);
return num == null ? false : ((num.intValue() & PdfAnnotation.FLAGS_HIDDEN) == PdfAnnotation.FLAGS_HIDDEN);
}
return false;
}

Change PDF Annotation font size using itext 7

My question is a bit similar to this one : Change PDF Annotation properties using iTextSharp C#
But I want to specifically change font size of pdf annotation using iText 7. I have searched a lot online but haven't been able to find any great examples or documentation regarding this. Following is the code I have used.
static void EditAnnot(string PDF)
{
string OutPDF = #"C:\Users\AP037X\Desktop\test.pdf";
iText.Kernel.Pdf.PdfDocument pdfDoc = new iText.Kernel.Pdf.PdfDocument(new iText.Kernel.Pdf.PdfReader(PDF), new iText.Kernel.Pdf.PdfWriter(OutPDF));
iText.Kernel.Pdf.PdfDictionary pageDict = pdfDoc.GetPage(1).GetPdfObject();
iText.Kernel.Pdf.PdfArray annots = pageDict.GetAsArray(iText.Kernel.Pdf.PdfName.Annots);
if (annots != null)
{
for (int i = 0; i < annots.Size(); i++)
{
Console.WriteLine("Scan..");
if (annots.GetAsDictionary(i) == null)
{
Console.WriteLine("1");
//return;
}
iText.Kernel.Pdf.PdfString t = annots.GetAsDictionary(i).GetAsString(iText.Kernel.Pdf.PdfName.Contents);
if (t == null)
{
Console.WriteLine("2");
//return;
}
Console.WriteLine(t);
if (Convert.ToString(t).Trim() == "Change")
{
Console.WriteLine("Found");
Console.WriteLine(annots.Size());
iText.Kernel.Geom.Rectangle rect = annots.GetAsDictionary(i).GetAsRectangle(iText.Kernel.Pdf.PdfName.Rect);
iText.Kernel.Pdf.PdfString cont = new iText.Kernel.Pdf.PdfString("New String");
iText.Kernel.Pdf.Annot.PdfFreeTextAnnotation NewAnnot = new iText.Kernel.Pdf.Annot.PdfFreeTextAnnotation(rect,cont);
float[] color = { 1f,1f,0f};
NewAnnot.SetColor(color);
NewAnnot.Put(iText.Kernel.Pdf.PdfName.Contents, new iText.Kernel.Pdf.PdfString("lion"));
NewAnnot.Put(iText.Kernel.Pdf.PdfName.Font, *What to type here?*);
annots.Remove(i);
annots.Add(i, NewAnnot.GetPdfObject());
}
}
}
pdfDoc.Close();
CompressPDF(OutPDF);
}

How to get resource names for optional content group in a pdf?

I am trying to implement functionality to allow user to add markups to existing layers in a pdf. Here is the code that I am using to draw lines on to a layer in a pdf:
PDResources resources = page.findResources();
PDPropertyList props = resources.getProperties();
COSName resourceName = getLayerResourceName("Superimposed3", resources, props);
PDPageContentStream cs1 = new PDPageContentStream(document, page, true, false);
cs1.beginMarkedContentSequence(COSName.OC, resourceName);
cs1.setStrokingColor(0, 0, 255);
cs1.setLineWidth(0.8F);
cs1.drawLine(100,100,250,200);
cs1.endMarkedContentSequence();
cs1.close();
I am using beginMarkedContentSequence instead of beginMarkedContent as I am using pdfbox 1.8 version and 2.0.5 version is not available for .net.
Here, is my function to get resource name for a layer:
private static COSName getLayerResourceName(string layerName,PDResources resources,PDPropertyList props)
{
int index = 0;
COSName resourceName = COSName.getPDFName("MC"+ index);
PDOptionalContentGroup ocg = props.getOptionalContentGroup(resourceName);
if (ocg != null && (ocg.getName() == layerName))
{
return resourceName;
}
else if (ocg == null)
{
return null;
}
else
{
resourceName = null;
index++;
bool exitFlag = false;
while (!exitFlag)
{
resourceName = COSName.getPDFName("MC" + index);
ocg = props.getOptionalContentGroup(resourceName);
if (ocg == null)
{
exitFlag = true;
resourceName = null;
}
else if (ocg.getName() == layerName)
{
exitFlag = true;
}
else
{
index++;
}
}
}
return resourceName;
}
The above functions only works for those layers which were added using the LayerUtility.appendFormAsLayer function. But it doesn't work for those layers which were created using the following code:
PDOptionalContentProperties ocprops = document.getDocumentCatalog().getOCProperties();
PDOptionalContentGroup newGroup = new PDOptionalContentGroup("Superimposed2");
PDOptionalContentGroup newGroup1 = new PDOptionalContentGroup("Superimposed3");
ocprops.addGroup(newGroup);
ocprops.addGroup(newGroup1);
So, shall I add "MC" value in properties of page myself while, creating layer, or is there another way to get resource name for such layers.

Java, edit pdf exist text with PDFBox

i trying edit text with library PDFBox and don't no how. I do not know how to get stream of individual text objects, so I could edit the text and or color.
Any idea, example?
Thanks
I found editing text in pdf is not reliable, so try to clear the text with a rectangle (white/background color fill) and write the new text in the cleared position. Here is a sample code.
//to add a link in footer
//to replace a text
//to replace a link/url/href
public static void editTextorUrl(String inputFile, String outputFile)
throws IOException, COSVisitorException {
// the document
PDDocument doc = null;
try {
System.out.println(inputFile);
doc = PDDocument.load(inputFile);
List pages = doc.getDocumentCatalog().getAllPages();
for (int i = 0; i < pages.size(); i++) {
float inch = 72;
PDGamma colourRed = new PDGamma();
colourRed.setR(1);
PDGamma colourBlue = new PDGamma();
colourBlue.setB(1);
PDGamma white = new PDGamma();
white.setR(1);
white.setB(1);
white.setG(1);
PDBorderStyleDictionary borderThick = new PDBorderStyleDictionary();
borderThick.setWidth(inch / 12); // 12th inch
PDBorderStyleDictionary borderThin = new PDBorderStyleDictionary();
borderThin.setWidth(inch / 72); // 1 point
PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();
borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
borderULine.setWidth(inch / 72); // 1 point
PDPage page = (PDPage) pages.get(i);
PDFont font = PDType1Font.HELVETICA;
PDPageContentStream contentStream = new PDPageContentStream(
doc, page, true, false);
contentStream.setNonStrokingColor(Color.WHITE);
contentStream.fillRect(55, 27, 144, 17);
contentStream.setNonStrokingColor(Color.BLUE);
contentStream.beginText();
contentStream.setFont(font, 11);
contentStream.moveTextPositionByAmount(55, 37);
contentStream.drawString("www.loasoftwares.com"); //text to be replaced
contentStream.endText();
contentStream.setLineWidth(inch / 300);
contentStream.setStrokingColor(Color.BLUE);
contentStream.drawLine(55, 34, 188, 34);
contentStream.close();
PDAnnotationLink txtLink = new PDAnnotationLink();
PDRectangle position = new PDRectangle();
position.setLowerLeftX(55);
position.setLowerLeftY(27);
position.setUpperRightX(188);
position.setUpperRightY(50);
txtLink.setRectangle(position);
// add an action
PDActionURI action = new PDActionURI();
action.setURI("www.loasoftwares.com");
txtLink.setBorderStyle(borderULine);
txtLink.setAction(action);
txtLink.setColour(white);
page.getAnnotations().add(txtLink);
}
doc.save(outputFile);
} finally {
if (doc != null) {
doc.close();
}
}
}
Remark:
It works under specific circumstances (ASCII'ish font encodings + pretty long string arguments)
/**
* This is an example that will replace a string in a PDF with a new one.
*
* The example is taken from the pdf file format specification.
*
* #author Ben Litchfield
* #version $Revision: 1.3 $
*/
public class ReplaceString {
/**
* Constructor.
*/
public ReplaceString() {
super();
}
/**
* Locate a string in a PDF and replace it with a new string.
*
* #param inputFile The PDF to open.
* #param outputFile The PDF to write to.
* #param strToFind The string to find in the PDF document.
* #param message The message to write in the file.
*
* #throws IOException If there is an error writing the data.
* #throws COSVisitorException If there is an error writing the PDF.
*/
public void doIt( String inputFile, String outputFile, String strToFind, String message)
throws IOException, COSVisitorException {
// the document
PDDocument doc = null;
try
{
doc = PDDocument.load( inputFile );
List pages = doc.getDocumentCatalog().getAllPages();
for( int i=0; i<pages.size(); i++ )
{
PDPage page = (PDPage)pages.get( i );
PDStream contents = page.getContents();
PDFStreamParser parser = new PDFStreamParser(contents.getStream());
parser.parse();
List tokens = parser.getTokens();
for( int j=0; j<tokens.size(); j++ )
{
Object next = tokens.get( j );
if( next instanceof PDFOperator )
{
PDFOperator op = (PDFOperator)next;
//Tj and TJ are the two operators that display
//strings in a PDF
if( op.getOperation().equals( "Tj" ) )
{
//Tj takes one operator and that is the string
//to display so lets update that operator
COSString previous = (COSString)tokens.get( j-1 );
String string = previous.getString();
string = string.replaceFirst( strToFind, message );
previous.reset();
previous.append( string.getBytes("ISO-8859-1") );
}
else if( op.getOperation().equals( "TJ" ) )
{
COSArray previous = (COSArray)tokens.get( j-1 );
for( int k=0; k<previous.size(); k++ )
{
Object arrElement = previous.getObject( k );
if( arrElement instanceof COSString )
{
COSString cosString = (COSString)arrElement;
String string = cosString.getString();
string = string.replaceFirst( strToFind, message );
cosString.reset();
cosString.append( string.getBytes("ISO-8859-1") );
}
}
}
}
}
//now that the tokens are updated we will replace the
//page content stream.
PDStream updatedStream = new PDStream(doc);
OutputStream out = updatedStream.createOutputStream();
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens( tokens );
page.setContents( updatedStream );
}
doc.save( outputFile );
}
finally
{
if( doc != null )
{
doc.close();
}
}
}
/**
* This will open a PDF and replace a string if it finds it.
* <br />
* see usage() for commandline
*
* #param args Command line arguments.
*/
public static void main(String[] args)
{
ReplaceString app = new ReplaceString();
try
{
if( args.length != 4 )
{
app.usage();
}
else
{
app.doIt( args[0], args[1], args[2], args[3] );
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* This will print out a message telling how to use this example.
*/
private void usage()
{
System.err.println( "usage: " + this.getClass().getName() +
" <input-file> <output-file> <search-string> <Message>" );
}
}