Add FreeText Annotations programmatically (Java)

I have a PDFDoc, which is created from a pdf and merged with a FDFDoc. The merging, flattening and return of a new PDF File works fine.
Now i want to add the same FreeText Annotation to every page (Is to be be added depending on existing annotations at several positions in the future).
Since setLineColor is broken (https://groups.google.com/forum/#!topic/pdfnet-sdk/Xsq2Bat1ZcY) i’m trying to achive the Fontsize and Color by creating an Appearance and setting it on the Annotation.
I have worked through the sample code for Annotations and ElementBuilder, but i cannot get the Fontsize and Font Color to work. Also my text is streched to fill the 30x30 Box, which is not what i want.
I have attached a Pdf Document which was produced by the following code.

`
public InputStream merge(InputStream document, InputStream annotations) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PDFDoc pdfDoc = null;
try {
FDFDoc fdfDoc = FDFDoc.createFromXFDF(IOUtils.toString(annotations, “UTF-8”));
pdfDoc = openDocument(document);
pdfDoc.fdfMerge(fdfDoc);

String text = “some text”;
Obj indexAppearance = createIndexAppearance(pdfDoc, text);

for (PageIterator itr = pdfDoc.getPageIterator(); itr.hasNext():wink: {
Page page = (Page) (itr.next());

//Size 30x30, location doesn’t matter at this point.
Rect indexAnnotRect = new Rect(70, 770, 100, 800);
FreeText indexAnnot = FreeText.create(pdfDoc, indexAnnotRect);

indexAnnot.setAppearance(indexAppearance);
page.annotPushBack(indexAnnot);
}

pdfDoc.flattenAnnotations(false);
pdfDoc.save(baos, 0, null);
return new ByteArrayInputStream(baos.toByteArray());
} catch (PDFNetException | IOException e) {
throw new RuntimeException(“PDF-Document konnte nicht erstellt werden.”, e);
} finally {
closeDocument(pdfDoc);
}
}

private Obj createIndexAppearance(PDFDoc pdfDoc, String text) throws PDFNetException {
ElementBuilder builder = new ElementBuilder();
ElementWriter writer = new ElementWriter();
Element element;

writer.begin(pdfDoc);

//Font Size does not work
element = builder.createTextBegin(Font.create(pdfDoc, Font.e_times_roman), 8);
writer.writeElement(element);
element = builder.createTextRun(text);

//Setting text color does not work
element.getGState().setFillColor(new ColorPt(0,1,1));

Rect bbox = element.getBBox();
writer.writeElement(element);

element = builder.createTextEnd();
writer.writeElement(element);

Obj stm = writer.end();
builder.destroy();
writer.destroy();
stm.putRect(“BBox”, bbox.getX1(), bbox.getY1(), bbox.getX2(), bbox.getY2());
stm.putName(“Subtype”, “Text”);
return stm;
}
`

document-merge.pdf (9.21 KB)

I was finally able to solve all my problems on my own.

  • Color works by setting the ColorSpace to RGB
  • FontSize works by setting the Textmatrix
    It was a bit tricky to find out the boundingBox of the added FreeText Annotation in combination with the positioning.
    It adds to every annotation in the xfdf file another freetext with some text to it.

Here is some working sample code:

`
private final static double fontSize = 8;
private final static int font = Font.e_helvetica;
public InputStream merge(InputStream document, InputStream annotations) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PDFDoc pdfDoc = null;
try {
FDFDoc fdfDoc = FDFDoc.createFromXFDF(IOUtils.toString(annotations, “UTF-8”));
pdfDoc = openDocument(document);
pdfDoc.fdfMerge(fdfDoc);

for (PageIterator itr = pdfDoc.getPageIterator(); itr.hasNext():wink: {
Page page = (Page) (itr.next());

int numAnnots = page.getNumAnnots();
for (int i = 0; i < numAnnots; ++i) {
Annot annot = page.getAnnot(i);
if (annot.isValid() == false) {
continue;
}

//todo: get color and text depending on annot
String farbe = “green”;
String text = “eine index annotation”;
double[] bbox = annot.getRect().get();
//top left corner of existing annotation is the reference point
FreeText indexAnnot = createIndexAnnotation(pdfDoc, new double[]{bbox[0], bbox[3]}, text, farbe);
page.annotPushBack(indexAnnot);
}
}

pdfDoc.flattenAnnotations(false);
pdfDoc.save(baos, 0, null);
return new ByteArrayInputStream(baos.toByteArray());
} catch (PDFNetException | IOException e) {
throw new RuntimeException(“PDF-Document konnte nicht erstellt werden.”, e);
} finally {
closeDocument(pdfDoc);
}
}
private FreeText createIndexAnnotation(PDFDoc pdfDoc, double[] refPunkt, String text, String farbe)
throws PDFNetException {
ColorPt color;
switch (farbe.toLowerCase()) {
case “red”:
color = new ColorPt(1, 0, 0);
break;
case “green”:
color = new ColorPt(0, 1, 0);
break;
case “blue”:
color = new ColorPt(0, 0, 1);
break;
default:
//black
color = new ColorPt(0, 0, 0);
break;
}

// create indexAppearance with width and height
Appearance appearance = createIndexAppearance(pdfDoc, text, color);

// Position left below reference point
Rect position =
new Rect(refPunkt[0] - appearance.width, refPunkt[1] - appearance.height, refPunkt[0], refPunkt[1]);
FreeText indexAnnot = FreeText.create(pdfDoc, position);
indexAnnot.setAppearance(appearance.indexAppearance);
return indexAnnot;
}

private Appearance createIndexAppearance(PDFDoc pdfDoc, String text, ColorPt colorPt)
throws PDFNetException {
double width;
double height;
String[] textInLines = text.split(" ");
ElementBuilder builder = new ElementBuilder();
ElementWriter writer = new ElementWriter();
Element element;

writer.begin(pdfDoc);

element = builder.createTextBegin(Font.create(pdfDoc, font), fontSize);
writer.writeElement(element);

// Set color and Text Matrix on first line
element = builder.createTextRun(textInLines[0]);
height = element.getBBox().getHeight();
width = element.getBBox().getWidth();
// No Scaling. move by height*(numberOfLines -1) + a little depending on fontsize
element.setTextMatrix(1, 0, 0, 1, 0, height * (textInLines.length - 1) + fontSize * 0.1875);
GState gState = element.getGState();
gState.setFillColorSpace(ColorSpace.createDeviceRGB());
gState.setFillColor(colorPt);
gState.setLeading(fontSize);
writer.writeElement(element);

//additional lines. add height, get maximum width
for (int i = 1; i < textInLines.length; i++) {
writer.writeElement(builder.createTextNewLine());
element = builder.createTextRun(textInLines[i]);
if (element.getBBox().getWidth() > width) {
width = element.getBBox().getWidth();
}
height += element.getBBox().getHeight();
writer.writeElement(element);
}

element = builder.createTextEnd();
writer.writeElement(element);

Obj indexAppearance = writer.end();
builder.destroy();
writer.destroy();
indexAppearance.putRect(“BBox”, 0, 0, width, height);
indexAppearance.putName(“Subtype”, “Text”);
return new Appearance(indexAppearance, width, height);
}

private final class Appearance {
private Obj indexAppearance;
private double width, height;

public Appearance(Obj indexAppearance, double width, double height) {
this.indexAppearance = indexAppearance;
this.width = width;
this.height = height;
}
}
`

Hi, the SetLineColor and font size issue has been fixed, and starting tomorrow you can download a nightly build with it.

http://www.pdftron.com/nightly/?p=stable/