Understanding TextPosition getTextMatrix() method in pdfBox 2.0.3 - pdfbox
I am trying to discover the character positioning inside the pdf pages. I have implemented a class TextPosition which extends PDFTextStripper, and I have used setSortByPosition(true) to arrange the charactersByArticle according to page structure. I have a pdf (here is the link, refer to page 10) in which I have both landscape and potrait characters. My TextPosition class has all the sorted characters at every page. Now when I see page 10, The landscape characters come after the potrait characters order. Here is the code:
public static void main( String[] args ) throws IOException
{
TextExtractor textExtractor = new TextExtractor("C:\\Users\\prabhjot.rai\\Desktop\\Demo\\sbet201601.pdf");
PDFPage page = textExtractor.getPages().get(10);
for (List<TextPosition> article: page.getCharactersByArticle()) {
for (TextPosition text: article) {
System.out.print(text.getUnicode() + " ");
System.out.print(text.getX() + " ");
System.out.print(text.getTextMatrix() + " ");
System.out.println();
}
}
}
And here is the last lines of page 10 output:
1 406.46 [7.787,0.0,0.0,7.7706,406.46,64.9355]
4 410.64938 [7.787,0.0,0.0,7.7706,410.64938,64.9355]
Y 250.9882 [7.787,0.0,0.0,7.7706,250.9882,46.5761]
E 256.3768 [7.787,0.0,0.0,7.7706,256.3768,46.5761]
A 261.7654 [7.787,0.0,0.0,7.7706,261.7654,46.5761]
R 267.15402 [7.787,0.0,0.0,7.7706,267.15402,46.5761]
P 94.1495 [0.0,7.7706,-7.787,0.0,94.1495,118.1203]
e 94.1495 [0.0,7.7706,-7.787,0.0,94.1495,123.499886]
r 94.1495 [0.0,7.7706,-7.787,0.0,94.1495,127.680466]
c 94.1495 [0.0,7.7706,-7.787,0.0,94.1495,130.07147]
e 94.1495 [0.0,7.7706,-7.787,0.0,94.1495,134.25516]
n 94.1495 [0.0,7.7706,-7.787,0.0,94.1495,138.43575]
t 94.1495 [0.0,7.7706,-7.787,0.0,94.1495,142.61633]
9 486.465 [0.0,7.98,-7.98,0.0,486.465,37.2]
486.465 [0.0,7.98,-7.98,0.0,486.465,41.220325]
486.465 [0.0,7.98,-7.98,0.0,486.465,43.199364]
| 486.465 [0.0,7.98,-7.98,0.0,486.465,45.178402]
486.465 [0.0,7.98,-7.98,0.0,486.465,46.678642]
486.465 [0.0,7.98,-7.98,0.0,486.465,48.838825]
N 486.465 [0.0,7.98,-7.98,0.0,486.465,50.817863]
F 486.465 [0.0,7.98,-7.98,0.0,486.465,56.579422]
I 486.465 [0.0,7.98,-7.98,0.0,486.465,61.016304]
B 486.465 [0.0,7.98,-7.98,0.0,486.465,63.65609]
486.465 [0.0,7.98,-7.98,0.0,486.465,68.99631]
S 486.465 [0.0,7.98,-7.98,0.0,486.465,71.09585]
m 486.465 [0.0,7.98,-7.98,0.0,486.465,75.53273]
a 486.465 [0.0,7.98,-7.98,0.0,486.465,81.59274]
l 486.465 [0.0,7.98,-7.98,0.0,486.465,85.135864]
l 486.465 [0.0,7.98,-7.98,0.0,486.465,87.3543]
486.465 [0.0,7.98,-7.98,0.0,486.465,89.57274]
B 486.465 [0.0,7.98,-7.98,0.0,486.465,91.79278]
u 486.465 [0.0,7.98,-7.98,0.0,486.465,97.132996]
s 486.465 [0.0,7.98,-7.98,0.0,486.465,101.15252]
i 486.465 [0.0,7.98,-7.98,0.0,486.465,104.2727]
n 486.465 [0.0,7.98,-7.98,0.0,486.465,106.491135]
e 486.465 [0.0,7.98,-7.98,0.0,486.465,110.51146]
s 486.465 [0.0,7.98,-7.98,0.0,486.465,114.05458]
s 486.465 [0.0,7.98,-7.98,0.0,486.465,117.17476]
486.465 [0.0,7.98,-7.98,0.0,486.465,120.294136]
E 486.465 [0.0,7.98,-7.98,0.0,486.465,122.334625]
c 486.465 [0.0,7.98,-7.98,0.0,486.465,127.19444]
o 486.465 [0.0,7.98,-7.98,0.0,486.465,130.73756]
n 486.465 [0.0,7.98,-7.98,0.0,486.465,134.75789]
o 486.465 [0.0,7.98,-7.98,0.0,486.465,138.77742]
m 486.465 [0.0,7.98,-7.98,0.0,486.465,142.79774]
i 486.465 [0.0,7.98,-7.98,0.0,486.465,148.85776]
c 486.465 [0.0,7.98,-7.98,0.0,486.465,151.0762]
486.465 [0.0,7.98,-7.98,0.0,486.465,154.61932]
T 486.465 [0.0,7.98,-7.98,0.0,486.465,156.71886]
r 486.465 [0.0,7.98,-7.98,0.0,486.465,161.57947]
e 486.465 [0.0,7.98,-7.98,0.0,486.465,164.21924]
n 486.465 [0.0,7.98,-7.98,0.0,486.465,167.76236]
d 486.465 [0.0,7.98,-7.98,0.0,486.465,171.78268]
s 486.465 [0.0,7.98,-7.98,0.0,486.465,175.80222]
486.465 [0.0,7.98,-7.98,0.0,486.465,178.9224]
486.465 [0.0,7.98,-7.98,0.0,486.465,180.84238]
486.465 [0.0,7.98,-7.98,0.0,486.465,182.82141]
M 486.465 [0.0,7.98,-7.98,0.0,486.465,184.8]
o 486.465 [0.0,7.98,-7.98,0.0,486.465,191.46011]
n 486.465 [0.0,7.98,-7.98,0.0,486.465,195.48204]
t 486.465 [0.0,7.98,-7.98,0.0,486.465,199.50397]
h 486.465 [0.0,7.98,-7.98,0.0,486.465,201.72401]
l 486.465 [0.0,7.98,-7.98,0.0,486.465,205.74594]
y 486.465 [0.0,7.98,-7.98,0.0,486.465,207.96599]
486.465 [0.0,7.98,-7.98,0.0,486.465,211.50592]
R 486.465 [0.0,7.98,-7.98,0.0,486.465,213.48495]
e 486.465 [0.0,7.98,-7.98,0.0,486.465,218.34477]
p 486.465 [0.0,7.98,-7.98,0.0,486.465,221.8847]
o 486.465 [0.0,7.98,-7.98,0.0,486.465,225.90663]
r 486.465 [0.0,7.98,-7.98,0.0,486.465,229.92856]
t 486.465 [0.0,7.98,-7.98,0.0,486.465,233.04794]
I can definitely see that the getTextMatrix() yields different matrix for both landscape and potrait characters. (Potrait: [7.787,0.0,0.0,7.7706,406.46,64.9355], Landscape: [0.0,7.7706,-7.787,0.0,94.1495,118.1203], landscape starts with zero at first place in matrix). I want to understand the matrix more so that I can make a clear distinction between two types. I referred the documentation but couldn't comprehend much. Can anyone share some article or thoughts on this?
Related
AWK - Adding new line based on text in previous line?
So I have some database table info in a file that looks like this: 2.6 G 7.7 G abc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G abc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G abc-def-ghi_2021-09-21_random_letters_random_numbers 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-def_2021-09-28_random_letters_random_numbers 55.1 K 165.3 K jkl-ghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-ghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-ghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-ghi-def_2021-09-26_random_letters_random_numbers Basically, I need it to look like this: 2.6 G 7.7 G qabc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G qabc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G qabc-def-ghi_2021-09-21_random_letters_random_numbers 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-wwwdef_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-wwwdef_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-wwwdef_2021-09-28_random_letters_random_numbers 55.1 K 165.3 K jkl-deghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-deghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-deghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-deghi-def_2021-09-26_random_letters_random_numbers Where there is a new line after the start of each unique table-name prefix. Right now I'm having to do all of this manually for hundreds of table names. Also, if there is a way to count how many times each table name occurs, that would be great too. Here is the code I got so far #Cyrus: awk 'BEGIN{FS="[ _]+"} NR==1{last=$(NF-1)} NR>1 && last!=$(NF-1){printf RS} {last=$(NF-1); print}' test2.txt Here is the output 2.6 G 7.7 G abc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G abc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G abc-def-ghi_2021-09-21_random_letters_random_numbers 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-def_2021-09-28_random_letters_random_numbers 55.1 K 165.3 K jkl-ghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-ghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-ghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-ghi-def_2021-09-26_random_letters_random_numbers This command works for table names like these: 2.6 G 7.7 G abc-def-ghi_2021-09-19 2.6 G 7.7 G abc-def-ghi_2021-09-20 2.6 G 7.8 G abc-def-ghi_2021-09-21 18.9 G 56.8 G def-abc-def_2021-09-21 110.3 M 331.0 M ghi-abc-def_2021-09-21 110.3 M 331.0 M ghi-abc-def_2021-09-27 110.4 M 331.2 M ghi-abc-def_2021-09-28 55.1 K 165.3 K jkl-ghi-def_2021-09-20 50.7 K 152.1 K jkl-ghi-def_2021-09-24 49.6 K 148.8 K jkl-ghi-def_2021-09-25 48.6 K 138.8 K jkl-ghi-def_2021-09-26
Seems like you can just do: awk 'last && $5 != last { print count; count=0 } {last = $5; count++ } 1' FS='[ _]*' eg: $ cat input 2.6 G 7.7 G abc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G abc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G abc-def-ghi_2021-09-21_random_letters_random_numbers 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-def_2021-09-28_random_letters_random_numbers 55.1 K 165.3 K jkl-ghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-ghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-ghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-ghi-def_2021-09-26_random_letters_random_numbers $ awk 'last && $5 != last { print count; count=0 } {last = $5; count++ } 1' FS='[ _]*' input 2.6 G 7.7 G abc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G abc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G abc-def-ghi_2021-09-21_random_letters_random_numbers 3 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 1 110.3 M 331.0 M ghi-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-def_2021-09-28_random_letters_random_numbers 3 55.1 K 165.3 K jkl-ghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-ghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-ghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-ghi-def_2021-09-26_random_letters_random_numbers
$ awk -F'[[:space:]_]+' '(NR>1) && ($5 != prev){print ""} {print; prev=$5}' file 2.6 G 7.7 G abc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G abc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G abc-def-ghi_2021-09-21_random_letters_random_numbers 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-def_2021-09-28_random_letters_random_numbers 55.1 K 165.3 K jkl-ghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-ghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-ghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-ghi-def_2021-09-26_random_letters_random_numbers $ awk -F'[[:space:]_]+' '(NR>1) && ($5 != prev){print cnt; cnt=0} {print; prev=$5; cnt++} END{if (cnt) print cnt}' file 2.6 G 7.7 G abc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G abc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G abc-def-ghi_2021-09-21_random_letters_random_numbers 3 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 1 110.3 M 331.0 M ghi-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-def_2021-09-28_random_letters_random_numbers 3 55.1 K 165.3 K jkl-ghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-ghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-ghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-ghi-def_2021-09-26_random_letters_random_numbers 4 The if (cnt) in the END sections is just so you don't print a null string or zero if the input file is empty.
Assumptions: all input lines have a total of 5 space-delimited fields that look like: #.# {G,K,M} #.# {G,K,M} <table-name-prefix>_YYYY-MM-DD_random_letters_random_numbers input file has already been sorted by <table-name-prefix> objective is to add a blank line to the output before we process a line with a new/different <table-name-prefix> OP mentions keeping track of how many times each unique <table-name-prefix> is seen, but since there's no mention of what to do with said number I'll just print it on the new 'blank' line (for now) expected output is to look like the 2nd block of data provided in the question (with proviso that <table-name-prefix> counts are placed in the 'blank' lines) One awk idea: awk '{ split($5,arr,"_") # split field #5 on "_" delimiter tabname=arr[1] # grab table name if (tabname != prevname && prevname != "" ) { # if this is a new table name then ... printf "%s\n", count # print a new line with a count of the last table name and then ... count=0 } print # print current line count++ # increment count for table name prevname = tabname # keep track of previous table name } END { printf "%s\n", count } # flush last table name count to stdout ' test2.txt This generates: 2.6 G 7.7 G abc-def-ghi_2021-09-19_random_letters_random_numbers 2.6 G 7.7 G abc-def-ghi_2021-09-20_random_letters_random_numbers 2.6 G 7.8 G abc-def-ghi_2021-09-21_random_letters_random_numbers 3 18.9 G 56.8 G def-abc-def_2021-09-21_random_letters_random_numbers 1 110.3 M 331.0 M ghi-abc-def_2021-09-21_random_letters_random_numbers 110.3 M 331.0 M ghi-abc-def_2021-09-27_random_letters_random_numbers 110.4 M 331.2 M ghi-abc-def_2021-09-28_random_letters_random_numbers 3 55.1 K 165.3 K jkl-ghi-def_2021-09-20_random_letters_random_numbers 50.7 K 152.1 K jkl-ghi-def_2021-09-24_random_letters_random_numbers 49.6 K 148.8 K jkl-ghi-def_2021-09-25_random_letters_random_numbers 48.6 K 138.8 K jkl-ghi-def_2021-09-26_random_letters_random_numbers 4
How to convince the typechecker that the types in the where clause match the toplevel type?
I'm trying to convince the type checker that the type specified in the where clause matches one of the types of the top level function. For example: interface SomeInterface (e: Type -> Type) where label : e l -> l f : (SomeInterface e) => e l -> c f x = ?hole_f where g : e l g = ?hole_g The type of ?hole_g should be e l, but the typechecker is unable to match the l type in g : e l to the l type in the toplevel f : (SomeInterface e) => e l -> c type. So according to the typechecker the type of ?hole_g is e l1 One way to fix this is to include l as a separate type variable in the toplevel function f, like this: f : (SomeInterface e) => e l -> l -> c f x _ = ?hole_f where g : e l g = ?hole_g Notice that the l in the toplevel function is completely neglected due to the _. But the typechecker is now somehow convinced that the type variable of ?hole_g is e l, like the toplevel type. My two questions are: 1) Why is the typechecker unable to "link" the types of function g to f? 2) How can i fix this without including an extra type variable?
f : (SomeInterface e) => e l -> c f x {l} = ?hole_f_1 where g : e l g = ?hole_g Does this do what you want? I believe since e l is a type, you can still get the implicit information about the l part.
Edit text in file(UTF16)
I want replace 1 word in text file (file format is not .txt) file Unicode is (UTF16) few text example: I D = " f f 0 3 4 a 9 2 - d d 9 f - 4 3 7 4 - a 8 a d - f 5 5 4 0 0 2 a 4 1 9 b " I S S U E _ D A T E = " 2 0 1 7 - 0 2 - 1 6 T 1 7 : 2 9 : 1 8 . 9 7 0 2 2 9 4 Z " S E Q U E N C E = " 0 " M A N A G I N G _ A P P L I C A T I O N _ T O K E N = " " > < L I C E N S E P U B L I C _ I D = " 3 A A - U J F - 8 K P " U S E R N A M E = " N d a G 6 Z T w u v I X Z B i t h 8 g o d d Q x E r x 0 + O g M c t 0 2 3 f X K O E w = " P A S S W O R D = " F 9 b n 6 b v w l f I 5 Z A 2 t h M h 9 d d s x Q L w = " T Y P E = " T R I A L " F L A G S = " 4 " D I S P L A Y _ N A M E = I want change T R I A L to other word
It's not too hard to modify your text file. Use the IO class to assign it to a text file, then use String.Replace(oldValue As String, newValue As String) to change your string. Then use IO again to save the string to the file. This should work so long as your file isn't open and being used in another program - regardless of file extensions. An example, to help you, could be something such as this: Dim myFileContents as String = IO.File.ReadAllText("Path\To\My\File\File.extension") myFileContents = myFileContents.Replace("T R I A L", "Some other word") IO.File.WriteAllText("Path\To\My\File\File.extension", myFileContents) Modify the contents to suit your situation - however, this is only a basic implementation. Additionally, it is important to note that String.Replace() will change all occurrences of your word to the new word.
Access the page of a .pdf I load (using pdfbox) (and i'm using RPG)
I am trying to modify a .pdf that I load using PDFBOX. I am using RPG and I have found the Java code to access a page from a loaded .pdf PDPage page = (pdpage)pdDoc.getDocumentCatalog().getallPages().get(0) The other code I have seen is List pages = doc.getDocumentCatalog().getAllPages(); PDPage page = (PDPage)pages.get( i ); The problem I am having is translating that code to RPG. The code I have right now is just to load my .pdf template create a document catalog and create my list and save it (the XLEnvVar is where I'm getting my classpath). /free XLSEnvVar(); // Load an existing PDF myPath = jstring_new('/tmp/PDFtemplate.pdf'); File = File_new(myPath); myDocument = PDdocument_load(File); myCatalog = PDDocumentCatalog_new(myDocument); myList = getAllPages(myCatalog); // Done with this file, so save it myFile = jstring_new('/tmp/PDFBox-demo.pdf'); PDDocument_save(myDocument:myFile); // Close the document object in memory to free all allocated space PDDocument_close(myDocument); // Done *INLR = *On; /end-free get prototype D get... D PR D EXTPROC(*JAVA: D 'java.util.List': D 'get') ORIGINAL POST ABOVE I thought I would post my PDFBOX program so there is another example of using PDFBOX in RPG out here on the interwebs. This is a fully working example (It uses my companies service programs and the SQL is just an example shell so if someone were to use this they would have to change those. But I explained what those service programs are doing so you can use your own companies service programs or write the code to do what those service programs do). Fell free to take this and post it elsewhere just leave the "written by" block. Hope this helps anyone working with PDFBOX. h/include QCpySrc,HSpecStd //***************************************************************** // Written By: Phillip Simmons Date: 05 20, 2013 * // Special thanks to Spencer (co-worker) * // and dhanuxp (code400 forums) and * // http://wiki.midrange.com/index.php/PDFBox * // for the intial example that I started with. * // * // Purpose: Load a pdf template, modify the template * // then save the modified document. Using PDFBOX * / //***************************************************************** /Include QCPYSRC,xCommandP //Service program to return path on IFS /Include QCPYSRC,GETIFSPTHP //Service program to return document name /Include QCPYSRC,GETIFSNAMP //Service program for document to adopt authority of the //folder above /Include qcpysrc,ifsadoptp //*************************************************************** // Data structure for SQL statement * //*************************************************************** D Rcd DS qualified D EMPLID LIKE(EMPLID) D LNAME 90A VARYING D ADDR1 LIKE(ADDR1) D ADDR2 LIKE(ADDR2) D CSZ 50A VARYING D SDS D ProgramName 1 10 //**************************************************************** // Prototypes for PDFBOX * // Full documentation of PDFBox is available at * // http://pdfbox.apache.org/index.html * // Api Docs http://pdfbox.apache.org/apidocs/ * //**************************************************************** /Copy QSYSINC/QRPGLESRC,JNI *Classpath D XLSEnvVar PR extpgm('XLSENVVAR') *----------------------------------------------------------------- * Global Constants D DEFAULT_USERSPACE_UNIT_DPI... D C 72 * Page sizes in mm D PAGE_SIZE_A0 S Like(PDRectangle) D PAGE_SIZE_A1 S Like(PDRectangle) D PAGE_SIZE_A2 S Like(PDRectangle) D PAGE_SIZE_A3 S Like(PDRectangle) D PAGE_SIZE_A4 S Like(PDRectangle) D PAGE_SIZE_A5 S Like(PDRectangle) D PAGE_SIZE_A6 S Like(PDRectangle) D PAGE_SIZE_A0_LANDSCAPE... D S Like(PDRectangle) D PAGE_SIZE_A1_LANDSCAPE... D S Like(PDRectangle) D PAGE_SIZE_A2_LANDSCAPE... D S Like(PDRectangle) D PAGE_SIZE_A3_LANDSCAPE... D S Like(PDRectangle) D PAGE_SIZE_A4_LANDSCAPE... D S Like(PDRectangle) D PAGE_SIZE_A5_LANDSCAPE... D S Like(PDRectangle) D PAGE_SIZE_A6_LANDSCAPE... D S Like(PDRectangle) D PAGE_WIDTH_A0 C 841 D PAGE_HEIGHT_A0 C 1189 D PAGE_WIDTH_A1 C 594 D PAGE_HEIGHT_A1 C 841 D PAGE_WIDTH_A2 C 420 D PAGE_HEIGHT_A2 C 594 D PAGE_WIDTH_A3 C 297 D PAGE_HEIGHT_A3 C 420 *210 orginal size D PAGE_WIDTH_A4 C 216 *297 orginal size D PAGE_HEIGHT_A4 C 279 D PAGE_WIDTH_A5 C 148 D PAGE_HEIGHT_A5 C 210 D PAGE_WIDTH_A6 C 105 D PAGE_HEIGHT_A6 C 148 *American pages slightly different size than ISO standard *----------------------------------------------------------------- * PDRectangle D PDRectangleClass... D C 'org.apache.pdfbox.pdmodel.common.PD- D Rectangle' D PDRectangle S O CLASS(*JAVA:PDRectangleClass) * PDRectangle() D PDRectangle_new... D PR like(PDRectangle) D EXTPROC(*JAVA: D PDRectangleClass: D *CONSTRUCTOR) D width like(jfloat) Value D height like(jfloat) Value *----------------------------------------------------------------- *PDDocumentCatalog D DocumentCatalog... D S O CLASS(*JAVA : D PDDocumentCatalogClass) D PDDocumentCatalogClass... D C 'org.apache.pdfbox.pdmodel.PDDocumen- D tCatalog' D getDocumentCatalog... D PR O CLASS(*JAVA : D PDDocumentCatalogClass) D EXTPROC(*JAVA : D PDDocumentClass: 'getDocumen+ D tCatalog' ) * D getAllPages PR O CLASS(*JAVA : 'java.util.List' ) D EXTPROC(*JAVA : D PDDocumentCatalogClass : 'get+ D AllPages' ) *----------------------------------------------------------------- *java.lang.String D jStringClass... D C 'java.lang.String' D jstring_new PR like(jString) D EXTPROC(*JAVA D :jStringClass D :*CONSTRUCTOR) D create_from 1024A Varying const *----------------------------------------------------------------- *PDDocument D PDDocumentClass... D C 'org.apache.pdfbox.pdmodel.PDDocumen- D t' D PDDocument S O CLASS(*JAVA:PDDocumentClass) * PDDocument() D PDDocument_new... D PR like(PDDocument) D EXTPROC(*JAVA: D PDDocumentClass: D *CONSTRUCTOR) * PDDocument.addPage() D PDDocument_addPage... D PR D EXTPROC(*JAVA: D PDDocumentClass: D 'addPage') D ppage like(PDPage) *PDDocument.load() D PDDocument_load... D PR like(PDDocument) D EXTPROC(*JAVA : PDDocumentClass: D 'load' ) D STATIC D path like(jstring) D PDDocument_save... D PR EXTPROC(*JAVA : PDDocumentClass: D 'save' ) D savepath like(jstring) * D importPage PR O CLASS(*JAVA : 'org.apache.pdfbox.p+ D dmodel.PDPage' ) D EXTPROC(*JAVA : 'org.apache.pdfbox+ D .pdmodel.PDDocument' : 'importPage+ D ' ) D* Parameter prototype declaration for Java type: PDPage D PDpage like(PDPage) * PDDocument.close() D PDDocument_close... D PR D EXTPROC(*JAVA: D PDDocumentClass: D 'close') *----------------------------------------------------------------- * Font Classes D PDFontClass C 'org.apache.pdfbox.pdmodel.font.PDFo- D nt' D PDFont S O CLASS(*JAVA:PDFontClass) *----------------------------------------------------------------- * PDPage D PDPageClass C 'org.apache.pdfbox.pdmodel.PDPage' D PDPage S O CLASS(*JAVA:PDPageClass) D PDPage_get PR O CLASS(*JAVA : 'java.lang.Object' ) D EXTPROC(*JAVA : 'java.util.List' : D 'get' ) D indexNo 10I 0 VALUE *----------------------------------------------------------------- * PDType1Font D PDType1FontClass... D C 'org.apache.pdfbox.pdmodel.font.PDTy- D pe1Font' D PDType1Font S O CLASS(*JAVA:PDType1FontClass) * PDType1Font() D PDType1Font_new... D PR like(PDType1Font) D EXTPROC(*JAVA: D PDType1FontClass: D *CONSTRUCTOR) D fontname like(jString) Options(*Omit) * PDType1Font.getStandardFont D PDType1Font_getStandardFont... D PR like(PDType1Font) D EXTPROC(*JAVA: D PDType1FontClass: D 'getStandardFont') D STATIC D fontname like(jString) *----------------------------------------------------------------- * PDPageContentStream D PDPageContentStreamClass... D C 'org.apache.pdfbox.pdmodel.edit.PDPa- D geContentStream' D PDPageContentStream... D S O CLASS(*JAVA: D PDPageContentStreamClass) * PDPageContentStream() D PDPageContentStream_new... D PR like(PDPageContentStream) D EXTPROC(*JAVA: D PDPageContentStreamClass: D *CONSTRUCTOR) D pdocument like(PDDocument) D ppage like(PDPage) D appendcontent N value D compress N value * PDPageContentStream.beginText() D PDPageContentStream_beginText... D PR D EXTPROC(*JAVA: D PDPageContentStreamClass: D 'beginText') * PDPageContentStream.setFont() D PDPageContentStream_setFont... D PR D EXTPROC(*JAVA: D PDPageContentStreamClass: D 'setFont') D font like(PDFont) D fontSize like(jfloat) Value * PDPageContentStream.moveTextPositionByAmount() D PDPageContentStream_moveTextPositionByAmount... D PR D EXTPROC(*JAVA: D PDPageContentStreamClass: D 'moveTextPositionByAmount') D x like(jfloat) Value D y like(jfloat) Value * PDPageContentStream.drawString() D PDPageContentStream_drawString... D PR D EXTPROC(*JAVA: D PDPageContentStreamClass: D 'drawString') D text like(jstring) * PDPageContentStream.endText() D PDPageContentStream_endText... D PR D EXTPROC(*JAVA: D PDPageContentStreamClass: D 'endText') * PDPageContentStream.close() D PDPageContentStream_close... D PR D EXTPROC(*JAVA: D PDPageContentStreamClass: D 'close') *----------------------------------------------------------------- * java.awt.Color D jColorClass... D C 'java.awt.Color' D jColor S O CLASS(*JAVA: D jColorClass) // new Color(int, int, int) D jColor_new_fromIntRGB... D PR like(jColor) D EXTPROC(*JAVA D :jColorClass D :*CONSTRUCTOR) D R like(jint) value D G like(jint) value D B like(jint) value * PDPageContentStream.setNonStrokingColor(java.awt.Color color) D PDPageContentStream_setNonStrokingColor... D PR D EXTPROC(*JAVA: D PDPageContentStreamClass: D 'setNonStrokingColor') D color like(jColor) *----------------------------------------------------------------- * Utilities D mmToUnits PR Like(jfloat) D pmm Like(jfloat) Value D createPageSizes... D PR *----------------------------------------------------------------- *PDFBOX variables D myFontName S like(jstring) D myFont S like(PDType1Font) D myPageContent S like(PDPageContentStream) D myColor S like(jColor) D sourceDoc S like(PDDocument) D targetDoc S like(PDDocument) D DocumentCat S like(DocumentCatalog) D pdf_path1 S like(jstring) D pdf_save S like(jstring) D myPage S like(PDPage) D newPage S like(PDPage) D myAllPages S O CLASS(*JAVA : 'java.util.List' ) D importPageRet S like(PDPage) *RPG variables D DocName S 255A VARYING D pageNumber S 10I 0 D Tdate S d D Cdate S 10 VARYING D tempsave S 150 VARYING D tempload S 150 VARYING D Directorys S 150 VARYING D Directoryl S 150 VARYING D CDirectory S 150 VARYING D loadstring S 150 VARYING D checkstring S 150 VARYING D SqlStm S 1000A VARYING D Q S 1A INZ(x'7D') D Cmds S 1500A Varying D Cmdl S 1500A Varying D*-------------------------------------------------- D* Procedure name: addText D* Purpose: D* Returns: D* Parameter: myText D*-------------------------------------------------- D addText PR D myText 5000A VARYING CONST D indent 10I 0 CONST D offset 10I 0 CONST * D myString S like(jstring) /free Tdate = %Date(); Cdate = %char(Tdate:*usa/); //The page of the loaded pdf that I am going to want to retrieve pageNumber = 0; //Contains the classpath XLSENVVAR(); //GETIFSPTH AND GETIFSNAM are service programs that my company uses //to get the path for a document. Further down in PDF_path1(loadstring) //you can pass a hardcoded string ex PDF_path1('/tmp/demodoc.pdf'); // Get the requested template file DocName = %Trim(GETIFSPTH(ProgramName:1)) + %Trim(GETIFSNAM(ProgramName:1)); //Directory the file will be moved into Directoryl = %Trim(GETIFSPTH(ProgramName:2)); //getting path to load the pdf document checkstring = %Trim(GETIFSPTH(ProgramName:3)) + %Trim(GETIFSNAM(ProgramName:3)); //Check to see if template already exists if it does dlt it //this is needed because later when I move the document to its final //destination if the document to be moved already exists the move will //fail. This will cause a modified template to be left behind and when //the program is ran later the earlier cpy obj will fail and I will //load an already modified templete. CallP(E) xCommand('DEL OBJLNK('+Q+%Trim(checkstring)+Q+')'); //String to pass to xcommand() Cmdl = 'CPY OBJ(' +Q + %trim(DocName) +Q + ')' + ' TODIR(' +Q + %trim(Directoryl) +Q + ')'; xcommand(Cmdl); //Create a blank pdf document. This will be the page to be modified. targetDoc = PDDocument_new(); //getting path to load the pdf document loadstring = %Trim(GETIFSPTH(ProgramName:3)) + %Trim(GETIFSNAM(ProgramName:3)); //The string that holds the path for where the pdf template is pdf_path1 = jstring_new(loadstring); //Load the pdf document sourceDoc = PDDocument_load(pdf_path1); //Get the document catalog DocumentCat = getDocumentCatalog(sourceDoc); //Get the list of pages myAllPages = getAllPages(DocumentCat); //Get the specific page I want myPage = PDPage_get(myAllPages:pageNumber); sqlstm = 'SELECT EMPLID,LNAME, ADDR1' + ' ADDR2, CSZ' ' from empmst'; Exec SQL Prepare S1 From :SqlStm; Exec SQL Declare Rcd Cursor for S1; Exec SQL Open Rcd; Exec SQL Fetch Rcd into :Rcd; Dow SQLCOD = 0; //Import and copy to a new page. This is the page to be used //in the content stream. importpageret = importpage(targetdoc:myPage); // Create a content stream so we can add content to the page // Modifying an existing page so append is *ON // Compression is *Off myPageContent = PDPageContentStream_new(targetdoc:importpageret: *ON:*Off); //Adding text to preloaded pdf addtext(Rcd.EMPLID :23 :240); addtext(Rcd.LNAME :23 :231); addtext(Rcd.ADDR1 :23 : 227); addtext(Rcd.ADDR2 :23 : 223); addtext(Rcd.CSZ :23 : 219); addtext(Cdate :180 : 240); EXEC SQL Fetch Rcd into :Rcd; ENDDO; //Temparaly saving to /tmp then will move with mov command tempsave = %Trim(GETIFSPTH(ProgramName:3)) + %Trim(GETIFSNAM(ProgramName:3)); //The string that holds the path for where the pdf will be saved pdf_save = jstring_new(tempsave); //Done with the file, so save it PDDocument_save(targetDoc : pdf_save); // Close the document object in memory to free all allocated space PDDocument_close(sourceDoc); PDDocument_close(targetDoc); //Create the directory that the file will be moved to CDirectory = %Trim(GETIFSPTH(ProgramName:4))+ %char(%subdt(%date():*YEARS)); xcommand('CRTDIR DIR(' +Q + CDIRECTORY +Q +')'); //retrieve the path the file will be saved to Directorys = %Trim(GETIFSPTH(ProgramName:4)) + %char(%subdt(%date():*YEARS)) + '/' + %Trim(GETIFSNAM(ProgramName:4)); //move the file to the correct directory Cmds = 'MOV OBJ(' +Q + tempsave +Q + ')' + ' TOOBJ(' +Q + %trim(Directorys)+ Q + ')'; xcommand(Cmds); //Adopt the auth of the folder ifsadopt(Directorys); Exec SQL Close Rcd; *Inlr = *On; /end-free * mmToUnits P mmToUnits B D Pi Like(jfloat) D pmm value like(jfloat) D funits S Like(jfloat) /free funits = 1 / (25.4) * DEFAULT_USERSPACE_UNIT_DPI * pmm; return funits; /end-free P mmToUnits E * creatPageSizes P createPageSizes... P B D Pi /free PAGE_SIZE_A0 = PDRectangle_new(mmToUnits(PAGE_WIDTH_A0): mmToUnits(PAGE_HEIGHT_A0)); PAGE_SIZE_A1 = PDRectangle_new(mmToUnits(PAGE_WIDTH_A1): mmToUnits(PAGE_HEIGHT_A1)); PAGE_SIZE_A2 = PDRectangle_new(mmToUnits(PAGE_WIDTH_A2): mmToUnits(PAGE_HEIGHT_A2)); PAGE_SIZE_A3 = PDRectangle_new(mmToUnits(PAGE_WIDTH_A3): mmToUnits(PAGE_HEIGHT_A3)); PAGE_SIZE_A4 = PDRectangle_new(mmToUnits(PAGE_WIDTH_A4): mmToUnits(PAGE_HEIGHT_A4)); PAGE_SIZE_A5 = PDRectangle_new(mmToUnits(PAGE_WIDTH_A5): mmToUnits(PAGE_HEIGHT_A5)); PAGE_SIZE_A6 = PDRectangle_new(mmToUnits(PAGE_WIDTH_A6): mmToUnits(PAGE_HEIGHT_A6)); PAGE_SIZE_A0_LANDSCAPE = PDRectangle_new(mmToUnits(PAGE_HEIGHT_A0): mmToUnits(PAGE_WIDTH_A0)); PAGE_SIZE_A1_LANDSCAPE = PDRectangle_new(mmToUnits(PAGE_HEIGHT_A1): mmToUnits(PAGE_WIDTH_A1)); PAGE_SIZE_A2_LANDSCAPE = PDRectangle_new(mmToUnits(PAGE_HEIGHT_A2): mmToUnits(PAGE_WIDTH_A2)); PAGE_SIZE_A3_LANDSCAPE = PDRectangle_new(mmToUnits(PAGE_HEIGHT_A3): mmToUnits(PAGE_WIDTH_A3)); PAGE_SIZE_A4_LANDSCAPE = PDRectangle_new(mmToUnits(PAGE_HEIGHT_A4): mmToUnits(PAGE_WIDTH_A4)); PAGE_SIZE_A5_LANDSCAPE = PDRectangle_new(mmToUnits(PAGE_HEIGHT_A5): mmToUnits(PAGE_WIDTH_A5)); PAGE_SIZE_A6_LANDSCAPE = PDRectangle_new(mmToUnits(PAGE_HEIGHT_A6): mmToUnits(PAGE_WIDTH_A6)); return; /end-free P E * * P*-------------------------------------------------- P* Procedure name: addText P* Purpose: Write text to a PDPage P* Returns: P* Parameter: myText P*-------------------------------------------------- P addText B D addText PI D myText 5000A VARYING CONST D indent 10I 0 CONST D offset 10I 0 CONST * D myString S like(jstring) /FREE // Set font type myFontName = jstring_new('Times-Roman'); myFont = PDType1Font_getStandardFont(myFontName); PDPageContentStream_setFont(myPageContent:myFont:10); // Set the color of the font to add // This isn't needed if writing to a blank page but since // adding text to a loaded page need to set the color of the text. myColor = jColor_new_fromIntRGB(0:0:0); PDPageContentStream_setNonStrokingColor(myPageContent:myColor); // Prepare to write text to the content stream PDPageContentStream_beginText(myPageContent); // Move the cursor possition,indent is x mm from left of page // offset x mm from bottom of page. PDPageContentStream_moveTextPositionByAmount(myPageContent: mmtounits(indent):mmtounits(offset)); // Create the text string we want to write myString = jstring_new(myText); // Write the string to the content stream PDPageContentStream_drawString(myPageContent:myString); // We are done writing text to this content stream PDPageContentStream_endText(myPageContent); //We are done with this content stream PDPageContentStream_close(myPageContent); /END-FREE P addText E Thought I would add a couple of comments after reading my code. I have to make a new folder for each year. That is what the crtdir is doing. If the directory already exists that is fine the contents in the already created directory are safe, the crtdir doesn't overwrite the directory. The reason that I am loading the template from one location to /tmp and then saving to /tmp before moving again is when I was working with PDFBOX the jstring_new(' ') was maxing out at 30 characters (including / and spaces and . ). so myString = jstring_new('/tmp/2013/myreportnamethatistoolong.pdf') that string is 39 characters long and that string will become truncated. olong.pdf will be lost when I make the string. I can make a string with rpg code and pass that string to jString_new() and be longer than 30 characters and it works.
You will want your List.get() to return org.apache.pdfbox.pdmodel.PDPage RPG is strongly typed, so we can't cast the same way Java can. Instead, we create the prototype to return the object we want to manipulate. Along those lines, you may end up using get() to retrieve several different kind of List elements. RPG doesn't do overloading either. What I'd do is create a separate get() prototype for each object I'd handle. So I'd have a getPage() and a getThread() and so on. Each one would be 'java.util.List:get' but return a different object type. The RPG list at www.midrange.com is another good source for help with RPG.
iTextSharp: reading radio button, check box states from a non-form PDF
I have a pdf document (created by a 3rd party using RealObjects PDFreactor), which is not a form. I'm trying to extract information from that PDF using iTextSharp. I'm able to extract all the plain text (using SimpleTextExtractionStrategy), but there is some information that is represented with radio buttons, which does not come across in the plain text extracted. I'm a complete beginner with iTextSharp, so I might be overlooking something very simple. PdfReader.AcroForm returns null, and PdfReader.AcroFields.Fields has 0 keys. How can I figure out the state of radio buttons and checkboxes throughout the document? The documents all have the same structure, so I don't really need the radio buttons & checkboxes to be labelled; just having a list of items, and knowing whether they are checked or not would be sufficient. I've confirmed that the radio buttons are not just images using this approach. I made a feeble attempt at finding all the BTN objects on a page by modifying the code to extract images, but I apparently messed up because it doesn't return anything on a page that contains radio buttons: private List<PdfObject> GetBTNFromPdfDict(PdfDictionary dict, PdfReader doc) { List<PdfObject> objects = new List<PdfObject>(); foreach (PdfName name in dict.Keys) { PdfObject obj = dict.Get(name); PdfDictionary tg = PdfReader.GetPdfObject(obj) as PdfDictionary; if (null != tg) { PdfName subtype = (PdfName)(PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE))); if (obj.IsIndirect()) { if (PdfName.BTN.Equals(subtype)) { int xrefIdx = ((PRIndirectReference)obj).Number; PdfObject pdfObj = doc.GetPdfObject(xrefIdx); objects.Add(pdfObj); } else if (PdfName.FORM.Equals(subtype) || PdfName.GROUP.Equals(subtype)) { objects.AddRange(GetBTNFromPdfDict(tg, doc)); } } else objects.AddRange(GetBTNFromPdfDict(tg, doc)); } } return objects; } I also looked at the content for the page using PdfContentReaderTool; the output didn't include any BTN, so I'm not sure what is going on. Here's the output (I replaced all the lines of text with [TEXT]). Just looking at the content stream section, it seems trivial to extract all strings (everything between brackets followed by Tj), but I can't seem to figure out radio buttons and checkboxes. (I had to abridge the output, the question was too long) ==============Page 2==================== - - - - - Dictionary - - - - - - (/Type=/Page, /TrimBox=System.Collections.Generic.List`1[iTextSharp.text.pdf.PdfObject], /Contents=Stream, /Parent=Dictionary of type: /Pages, /Group=Dictionary of type: /Group, /BleedBox=System.Collections.Generic.List`1[iTextSharp.text.pdf.PdfObject], /Resources=Dictionary, /MediaBox=System.Collections.Generic.List`1[iTextSharp.text.pdf.PdfObject]) Subdictionary /Parent = (/Count=10, /Type=/Pages, /Parent=Dictionary of type: /Pages, /Kids=System.Collections.Generic.List`1[iTextSharp.text.pdf.PdfObject]) Subdictionary /Parent = (/Count=39, /Type=/Pages, /ITXT=2.1.6, /Kids=System.Collections.Generic.List`1[iTextSharp.text.pdf.PdfObject]) Subdictionary /Group = (/Type=/Group, /S=/Transparency, /CS=/DeviceRGB) Subdictionary /Resources = (/ColorSpace=Dictionary, /ProcSet=System.Collections.Generic.List`1[iTextSharp.text.pdf.PdfObject], /Font=Dictionary) Subdictionary /ColorSpace = (/CS=/DeviceRGB) Subdictionary /Font = (/F1=Dictionary of type: /Font, /F3=Dictionary of type: /Font, /F2=Dictionary of type: /Font, /F4=Dictionary of type: /Font) Subdictionary /F1 = (/Type=/Font, /BaseFont=/Helvetica, /Subtype=/Type1, /Encoding=/WinAnsiEncoding) Subdictionary /F3 = (/Type=/Font, /BaseFont=/Times-Bold, /Subtype=/Type1, /Encoding=/WinAnsiEncoding) Subdictionary /F2 = (/Type=/Font, /BaseFont=/Times-Roman, /Subtype=/Type1, /Encoding=/WinAnsiEncoding) Subdictionary /F4 = (/Type=/Font, /BaseFont=/Times-Italic, /Subtype=/Type1, /Encoding=/WinAnsiEncoding) - - - - - XObject Summary - - - - - - No XObjects - - - - - Content Stream - - - - - - q BT 36 805.89 Td ET Q q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 1 w 2 J 0 j 10 M []0 d q q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0 841.89 m 595.29 841.89 l 595.29 0 l 0 0 l 0 841.89 l h W n 0 0 0 rg BT /F1 233.33 Tf 0.03 0 0 0.03 540.69 4.71 Tm 12.63 Tc (TEXT)Tj 0 Tc ET BT /F1 233.33 Tf 0.03 0 0 0.03 129.18 4.71 Tm 11.37 Tc (TEXT)Tj 0 Tc ET 0.8 0.8 0.8 rg 15 826.89 m 580.29 826.89 l 580.29 494.79 l 15 494.79 l 15 826.89 l h f 0 0 0 rg 20.1 826.89 m 575.16 826.89 l 574.41 826.14 l 20.85 826.14 l h f 20.85 495.54 m 574.41 495.54 l 575.16 494.79 l 20.1 494.79 l h f 20.1 826.89 m 20.85 826.14 l 20.85 495.54 l 20.1 494.79 l h f 574.41 826.14 m 575.16 826.89 l 575.16 494.79 l 574.41 495.54 l h f 1 1 1 rg 20.85 826.14 m 574.41 826.14 l 574.41 495.54 l 20.85 495.54 l 20.85 826.14 l h f 0 0 0 rg 28.35 818.64 m 566.91 818.64 l 566.91 799.14 l 28.35 799.14 l 28.35 818.64 l h f 1 1 1 rg BT /F3 350 Tf 0.03 0 0 0.03 31.35 804.69 Tm 6.52 Tc (I. )Tj 0 Tc ET BT /F3 350 Tf 0.03 0 0 0.03 41.07 804.69 Tm 27.57 Tc (TEXT)Tj 0 Tc ET 0 0 0 rg BT /F2 300 Tf 0.03 0 0 0.03 28.35 789.54 Tm ( )Tj ET 28.35 787.14 m 566.91 787.14 l 566.16 786.39 l 29.1 786.39 l h f 29.1 728.64 m 566.16 728.64 l 566.91 727.89 l 28.35 727.89 l h f 28.35 787.14 m 29.1 786.39 l 29.1 728.64 l 28.35 727.89 l h f 566.16 786.39 m 566.91 787.14 l 566.91 727.89 l 566.16 728.64 l h f 29.1 729.39 m 296.88 729.39 l 297.63 728.64 l 29.1 728.64 l h f 296.88 786.39 m 297.63 786.39 l 297.63 728.64 l 296.88 729.39 l h f BT /F2 250 Tf 0.03 0 0 0.03 32.1 775.14 Tm 19.36 Tc (TEXT)Tj 0 Tc ET 0.37647 0.37647 0.37647 rg 32.1 772.89 m 293.88 772.89 l 292.38 771.39 l 33.6 771.39 l h f 0.87843 0.87843 0.87843 rg 292.38 771.39 m 293.88 772.89 l 293.88 744.39 l 292.38 745.14 l h f 0.37647 0.37647 0.37647 rg 32.1 772.89 m 33.6 771.39 l 33.6 745.14 l 32.1 744.39 l h f 0 0 0 rg 33.6 745.14 m 292.38 745.14 l 293.88 744.39 l 32.1 744.39 l h f 1 1 1 rg 33.6 771.39 m 292.38 771.39 l 292.38 745.14 l 33.6 745.14 l 33.6 771.39 l h f q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 33.72 766.14 m 287.13 766.14 l 287.13 750.39 l 33.72 750.39 l 33.72 766.14 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 33.72 766.14 m 33.72 750.39 l 287.13 750.39 l 287.13 766.14 l h W n 1 1 1 rg 33.72 766.14 m 287.13 766.14 l 287.13 750.39 l 33.72 750.39 l 33.72 766.14 l h f 33.72 766.14 m 287.13 766.14 l 287.13 750.39 l 33.72 750.39 l 33.72 766.14 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 33.72 766.14 m 33.72 750.39 l 287.13 750.39 l 287.13 766.14 l h W n 0 0 0 rg BT /F2 18 Tf 0.74973 0 0 0.75 33.72 753.31 Tm 2.02 Tc (TEXT)Tj 0 Tc ET BT /F2 18 Tf 0.74973 0 0 0.75 76.53 753.31 Tm ( )Tj ET BT /F2 18 Tf 0.74973 0 0 0.75 80.63 753.31 Tm 1.85 Tc (TEXT)Tj 0 Tc ET Q Q Q Q Q Q 0 0 0 rg 297.63 729.39 m 566.16 729.39 l 566.16 728.64 l 297.63 728.64 l h f BT /F2 250 Tf 0.03 0 0 0.03 300.63 775.14 Tm 18.42 Tc (TEXT)Tj 0 Tc ET 0.37647 0.37647 0.37647 rg 300.63 772.89 m 563.16 772.89 l 561.66 771.39 l 302.13 771.39 l h f 0.87843 0.87843 0.87843 rg 561.66 771.39 m 563.16 772.89 l 563.16 744.39 l 561.66 745.14 l h f 0.37647 0.37647 0.37647 rg 300.63 772.89 m 302.13 771.39 l 302.13 745.14 l 300.63 744.39 l h f 0 0 0 rg 302.13 745.14 m 561.66 745.14 l 563.16 744.39 l 300.63 744.39 l h f 1 1 1 rg 302.13 771.39 m 561.66 771.39 l 561.66 745.14 l 302.13 745.14 l 302.13 771.39 l h f q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 302.25 766.14 m 556.41 766.14 l 556.41 750.39 l 302.25 750.39 l 302.25 766.14 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 302.25 766.14 m 302.25 750.39 l 556.41 750.39 l 556.41 766.14 l h W n 1 1 1 rg 302.25 766.14 m 556.41 766.14 l 556.41 750.39 l 302.25 750.39 l 302.25 766.14 l h f 302.25 766.14 m 556.41 766.14 l 556.41 750.39 l 302.25 750.39 l 302.25 766.14 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 302.25 766.14 m 302.25 750.39 l 556.41 750.39 l 556.41 766.14 l h W n 0 0 0 rg BT /F2 18 Tf 0.74973 0 0 0.75 302.25 753.31 Tm 1.42 Tc (TEXT)Tj 0 Tc ET BT /F2 18 Tf 0.74973 0 0 0.75 344.3 753.31 Tm ( )Tj ET BT /F2 18 Tf 0.74973 0 0 0.75 348.4 753.31 Tm 1.8 Tc (TEXT)Tj 0 Tc ET BT /F2 18 Tf 0.74973 0 0 0.75 431.64 753.31 Tm ( )Tj ET BT /F2 18 Tf 0.74973 0 0 0.75 435.75 753.31 Tm 1.23 Tc (TEXT)Tj 0 Tc ET Q Q Q Q Q Q 0 0 0 rg 28.35 727.89 m 566.91 727.89 l 566.16 727.14 l 29.1 727.14 l h f 29.1 503.79 m 566.16 503.79 l 566.91 503.04 l 28.35 503.04 l h f 28.35 727.89 m 29.1 727.14 l 29.1 503.79 l 28.35 503.04 l h f 566.16 727.14 m 566.91 727.89 l 566.91 503.04 l 566.16 503.79 l h f 29.1 670.14 m 296.88 670.14 l 297.63 669.39 l 29.1 669.39 l h f 296.88 727.14 m 297.63 727.14 l 297.63 669.39 l 296.88 670.14 l h f BT /F2 250 Tf 0.03 0 0 0.03 32.1 715.89 Tm 19.68 Tc (TEXT )Tj 0 Tc ET 0.37647 0.37647 0.37647 rg 32.1 713.64 m 293.88 713.64 l 292.38 712.14 l 33.6 712.14 l h f 0.87843 0.87843 0.87843 rg 292.38 712.14 m 293.88 713.64 l 293.88 685.14 l 292.38 685.89 l h f 0.37647 0.37647 0.37647 rg 32.1 713.64 m 33.6 712.14 l 33.6 685.89 l 32.1 685.14 l h f 0 0 0 rg 33.6 685.89 m 292.38 685.89 l 293.88 685.14 l 32.1 685.14 l h f 1 1 1 rg 33.6 712.14 m 292.38 712.14 l 292.38 685.89 l 33.6 685.89 l 33.6 712.14 l h f q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 33.72 706.89 m 287.13 706.89 l 287.13 691.14 l 33.72 691.14 l 33.72 706.89 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 33.72 706.89 m 33.72 691.14 l 287.13 691.14 l 287.13 706.89 l h W n 1 1 1 rg 33.72 706.89 m 287.13 706.89 l 287.13 691.14 l 33.72 691.14 l 33.72 706.89 l h f 33.72 706.89 m 287.13 706.89 l 287.13 691.14 l 33.72 691.14 l 33.72 706.89 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 33.72 706.89 m 33.72 691.14 l 287.13 691.14 l 287.13 706.89 l h W n 0 0 0 rg BT /F2 18 Tf 0.74973 0 0 0.75 33.72 694.06 Tm 1.8 Tc (TEXT)Tj 0 Tc ET BT /F2 18 Tf 0.74973 0 0 0.75 77.19 694.06 Tm ( )Tj ET BT /F2 18 Tf 0.74973 0 0 0.75 81.3 694.06 Tm 1.89 Tc (TEXT)Tj 0 Tc ET Q Q Q Q Q Q 0 0 0 rg 297.63 670.14 m 566.16 670.14 l 566.16 669.39 l 297.63 669.39 l h f BT /F2 250 Tf 0.03 0 0 0.03 300.63 715.89 Tm 22.9 Tc (TEXT )Tj 0 Tc ET 0.37647 0.37647 0.37647 rg 300.63 713.64 m 563.16 713.64 l 561.66 712.14 l 302.13 712.14 l h f 0.87843 0.87843 0.87843 rg 561.66 712.14 m 563.16 713.64 l 563.16 685.14 l 561.66 685.89 l h f 0.37647 0.37647 0.37647 rg 300.63 713.64 m 302.13 712.14 l 302.13 685.89 l 300.63 685.14 l h f 0 0 0 rg 302.13 685.89 m 561.66 685.89 l 563.16 685.14 l 300.63 685.14 l h f 1 1 1 rg 302.13 712.14 m 561.66 712.14 l 561.66 685.89 l 302.13 685.89 l 302.13 712.14 l h f q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 302.25 706.89 m 556.41 706.89 l 556.41 691.14 l 302.25 691.14 l 302.25 706.89 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 302.25 706.89 m 302.25 691.14 l 556.41 691.14 l 556.41 706.89 l h W n 1 1 1 rg 302.25 706.89 m 556.41 706.89 l 556.41 691.14 l 302.25 691.14 l 302.25 706.89 l h f 302.25 706.89 m 556.41 706.89 l 556.41 691.14 l 302.25 691.14 l 302.25 706.89 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.74987 w 2 J 0 j 10 M []0 d q 302.25 706.89 m 302.25 691.14 l 556.41 691.14 l 556.41 706.89 l h W n Q Q Q Q Q Q 0 0 0 rg 29.1 504.54 m 566.16 504.54 l 566.16 503.79 l 29.1 503.79 l h f 0.86667 0.86667 0.86667 rg 29.1 669.39 m 566.16 669.39 l 566.16 504.54 l 29.1 504.54 l 29.1 669.39 l h f 0 0 0 rg BT /F2 250 Tf 0.03 0 0 0.03 32.1 658.14 Tm 19.96 Tc (TEXT)Tj 0 Tc ET q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 54.6 647.46 m 61.35 647.46 l 61.35 640.71 l 54.6 640.71 l 54.6 647.46 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.75 w 2 J 0 j 10 M []0 d q 54.6 647.46 m 54.6 640.71 l 61.35 640.71 l 61.35 647.46 l h W n Q Q Q q 47.85 654.21 m 68.1 654.21 l 68.1 633.96 l 47.85 633.96 l 47.85 654.21 l h W n 1 1 1 rg 61.35 644.08 m 61.35 642.22 59.84 640.71 57.97 640.71 c 56.11 640.71 54.6 642.22 54.6 644.08 c 54.6 645.95 56.11 647.46 57.97 647.46 c 59.84 647.46 61.35 645.95 61.35 644.08 c h f Q q 47.85 654.21 m 68.1 654.21 l 68.1 633.96 l 47.85 633.96 l 47.85 654.21 l h W n 0 0 0 rg 57.97 646.71 m 59.42 646.71 60.6 645.53 60.6 644.08 c 60.6 642.64 59.42 641.46 57.97 641.46 c 56.53 641.46 55.35 642.64 55.35 644.08 c 55.35 645.53 56.53 646.71 57.97 646.71 c h 57.97 647.46 m 56.11 647.46 54.6 645.95 54.6 644.08 c 54.6 642.22 56.11 640.71 57.97 640.71 c 59.84 640.71 61.35 642.22 61.35 644.08 c 61.35 645.95 59.84 647.46 57.97 647.46 c h f Q Q BT /F2 250 Tf 0.03 0 0 0.03 64.35 642.39 Tm 21.62 Tc (TEXT)Tj 0 Tc ET q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 54.6 630.39 m 61.35 630.39 l 61.35 623.64 l 54.6 623.64 l 54.6 630.39 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.75 w 2 J 0 j 10 M []0 d q 54.6 630.39 m 54.6 623.64 l 61.35 623.64 l 61.35 630.39 l h W n Q Q Q q 47.85 637.14 m 68.1 637.14 l 68.1 616.89 l 47.85 616.89 l 47.85 637.14 l h W n 1 1 1 rg 61.35 627.01 m 61.35 625.15 59.84 623.64 57.97 623.64 c 56.11 623.64 54.6 625.15 54.6 627.01 c 54.6 628.88 56.11 630.39 57.97 630.39 c 59.84 630.39 61.35 628.88 61.35 627.01 c h f Q q 47.85 637.14 m 68.1 637.14 l 68.1 616.89 l 47.85 616.89 l 47.85 637.14 l h W n 0 0 0 rg 57.97 629.64 m 59.42 629.64 60.6 628.46 60.6 627.01 c 60.6 625.57 59.42 624.39 57.97 624.39 c 56.53 624.39 55.35 625.57 55.35 627.01 c 55.35 628.46 56.53 629.64 57.97 629.64 c h 57.97 630.39 m 56.11 630.39 54.6 628.88 54.6 627.01 c 54.6 625.15 56.11 623.64 57.97 623.64 c 59.84 623.64 61.35 625.15 61.35 627.01 c 61.35 628.88 59.84 630.39 57.97 630.39 c h f 59.66 627.01 m 59.66 626.08 58.91 625.33 57.97 625.33 c 57.04 625.33 56.29 626.08 56.29 627.01 c 56.29 627.95 57.04 628.7 57.97 628.7 c 58.91 628.7 59.66 627.95 59.66 627.01 c h f Q Q BT /F2 250 Tf 0.03 0 0 0.03 64.35 625.32 Tm 18.25 Tc (TEXT)Tj 0 Tc ET q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 65.1 610.32 m 71.85 610.32 l 71.85 603.57 l 65.1 603.57 l 65.1 610.32 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.75 w 2 J 0 j 10 M []0 d q 65.1 610.32 m 65.1 603.57 l 71.85 603.57 l 71.85 610.32 l h W n Q Q Q q 58.35 617.07 m 78.6 617.07 l 78.6 596.82 l 58.35 596.82 l 58.35 617.07 l h W n 1 1 1 rg 71.85 606.94 m 71.85 605.08 70.34 603.57 68.47 603.57 c 66.61 603.57 65.1 605.08 65.1 606.94 c 65.1 608.81 66.61 610.32 68.47 610.32 c 70.34 610.32 71.85 608.81 71.85 606.94 c h f Q q 58.35 617.07 m 78.6 617.07 l 78.6 596.82 l 58.35 596.82 l 58.35 617.07 l h W n 0 0 0 rg 68.47 609.57 m 69.92 609.57 71.1 608.39 71.1 606.94 c 71.1 605.5 69.92 604.32 68.47 604.32 c 67.03 604.32 65.85 605.5 65.85 606.94 c 65.85 608.39 67.03 609.57 68.47 609.57 c h 68.47 610.32 m 66.61 610.32 65.1 608.81 65.1 606.94 c 65.1 605.08 66.61 603.57 68.47 603.57 c 70.34 603.57 71.85 605.08 71.85 606.94 c 71.85 608.81 70.34 610.32 68.47 610.32 c h f 70.16 606.94 m 70.16 606.01 69.41 605.26 68.47 605.26 c 67.54 605.26 66.79 606.01 66.79 606.94 c 66.79 607.88 67.54 608.63 68.47 608.63 c 69.41 608.63 70.16 607.88 70.16 606.94 c h f Q Q BT /F2 250 Tf 0.03 0 0 0.03 74.85 605.25 Tm 21.69 Tc ( TEXT)Tj 0 Tc ET BT /F2 250 Tf 0.03 0 0 0.03 399.88 605.25 Tm ( )Tj ET q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 65.1 593.25 m 71.85 593.25 l 71.85 586.5 l 65.1 586.5 l 65.1 593.25 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.75 w 2 J 0 j 10 M []0 d q 65.1 593.25 m 65.1 586.5 l 71.85 586.5 l 71.85 593.25 l h W n Q Q Q q 58.35 600 m 78.6 600 l 78.6 579.75 l 58.35 579.75 l 58.35 600 l h W n 1 1 1 rg 71.85 589.87 m 71.85 588.01 70.34 586.5 68.47 586.5 c 66.61 586.5 65.1 588.01 65.1 589.87 c 65.1 591.74 66.61 593.25 68.47 593.25 c 70.34 593.25 71.85 591.74 71.85 589.87 c h f Q q 58.35 600 m 78.6 600 l 78.6 579.75 l 58.35 579.75 l 58.35 600 l h W n 0 0 0 rg 68.47 592.5 m 69.92 592.5 71.1 591.32 71.1 589.87 c 71.1 588.43 69.92 587.25 68.47 587.25 c 67.03 587.25 65.85 588.43 65.85 589.87 c 65.85 591.32 67.03 592.5 68.47 592.5 c h 68.47 593.25 m 66.61 593.25 65.1 591.74 65.1 589.87 c 65.1 588.01 66.61 586.5 68.47 586.5 c 70.34 586.5 71.85 588.01 71.85 589.87 c 71.85 591.74 70.34 593.25 68.47 593.25 c h f Q Q BT /F2 250 Tf 0.03 0 0 0.03 74.85 588.18 Tm 23.16 Tc ( TEXT)Tj 0 Tc ET BT /F2 250 Tf 0.03 0 0 0.03 407.97 588.18 Tm ( )Tj ET q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 65.1 576.18 m 71.85 576.18 l 71.85 569.43 l 65.1 569.43 l 65.1 576.18 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.75 w 2 J 0 j 10 M []0 d q 65.1 576.18 m 65.1 569.43 l 71.85 569.43 l 71.85 576.18 l h W n Q Q Q q 58.35 582.93 m 78.6 582.93 l 78.6 562.68 l 58.35 562.68 l 58.35 582.93 l h W n 1 1 1 rg 71.85 572.8 m 71.85 570.94 70.34 569.43 68.47 569.43 c 66.61 569.43 65.1 570.94 65.1 572.8 c 65.1 574.67 66.61 576.18 68.47 576.18 c 70.34 576.18 71.85 574.67 71.85 572.8 c h f Q q 58.35 582.93 m 78.6 582.93 l 78.6 562.68 l 58.35 562.68 l 58.35 582.93 l h W n 0 0 0 rg 68.47 575.43 m 69.92 575.43 71.1 574.25 71.1 572.8 c 71.1 571.36 69.92 570.18 68.47 570.18 c 67.03 570.18 65.85 571.36 65.85 572.8 c 65.85 574.25 67.03 575.43 68.47 575.43 c h 68.47 576.18 m 66.61 576.18 65.1 574.67 65.1 572.8 c 65.1 570.94 66.61 569.43 68.47 569.43 c 70.34 569.43 71.85 570.94 71.85 572.8 c 71.85 574.67 70.34 576.18 68.47 576.18 c h f Q Q BT /F2 250 Tf 0.03 0 0 0.03 74.85 571.11 Tm 23.08 Tc ( TEXT )Tj 0 Tc ET BT /F2 250 Tf 0.03 0 0 0.03 78 560.04 Tm 23.94 Tc (TEXT )Tj 0 Tc ET BT /F4 250 Tf 0.03 0 0 0.03 168.51 560.04 Tm 26.34 Tc (TEXT)Tj 0 Tc ET BT /F2 250 Tf 0.03 0 0 0.03 183.81 560.04 Tm 22.63 Tc (TEXT)Tj 0 Tc ET BT /F2 250 Tf 0.03 0 0 0.03 78 539.97 Tm 20.99 Tc (TEXT)Tj 0 Tc ET 0.37647 0.37647 0.37647 rg 111.57 558.54 m 179.94 558.54 l 178.44 557.04 l 113.07 557.04 l h f 0.87843 0.87843 0.87843 rg 178.44 557.04 m 179.94 558.54 l 179.94 530.04 l 178.44 530.79 l h f 0.37647 0.37647 0.37647 rg 111.57 558.54 m 113.07 557.04 l 113.07 530.79 l 111.57 530.04 l h f 0 0 0 rg 113.07 530.79 m 178.44 530.79 l 179.94 530.04 l 111.57 530.04 l h f 1 1 1 rg 113.07 557.04 m 178.44 557.04 l 178.44 530.79 l 113.07 530.79 l 113.07 557.04 l h f q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.03 w 2 J 0 j 10 M []0 d q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 113.19 551.79 m 173.19 551.79 l 173.19 536.04 l 113.19 536.04 l 113.19 551.79 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.75 w 2 J 0 j 10 M []0 d q 113.19 551.79 m 113.19 536.04 l 173.19 536.04 l 173.19 551.79 l h W n 1 1 1 rg 113.19 551.79 m 173.19 551.79 l 173.19 536.04 l 113.19 536.04 l 113.19 551.79 l h f 113.19 551.79 m 173.19 551.79 l 173.19 536.04 l 113.19 536.04 l 113.19 551.79 l h W n q 0 841.89 m 0 0 l 595.29 0 l 595.29 841.89 l h W n 0.75 w 2 J 0 j 10 M []0 d q 113.19 551.79 m 113.19 536.04 l 173.19 536.04 l 173.19 551.79 l h W n Q Q Q Q Q Q 0 0 0 rg BT /F2 250 Tf 0.03 0 0 0.03 179.94 539.97 Tm (TEXT)Tj ET BT /F2 250 Tf 0.03 0 0 0.03 197.04 539.97 Tm 20.99 Tc (TEXT)Tj 0 Tc ET 0.37647 0.37647 0.37647 rg 230.61 558.54 m 298.98 558.54 l 297.48 557.04 l 232.11 557.04 l h f 0.87843 0.87843 0.87843 rg 297.48 557.04 m 298.98 558.54 l 298.98 530.04 l 297.48 530.79 l h f 0.37647 0.37647 0.37647 rg 230.61 558.54 m 232.11 557.04 l 232.11 530.79 l 230.61 530.04 l h f 0 0 0 rg 232.11 530.79 m 297.48 530.79 l 298.98 530.04 l 230.61 530.04 l h f <snip!>
I figured this out, at least for the documents I'm dealing with. This is not a generic solution that would work with all sorts of pdf documents. In my case, I was dealing a software-generated pdf, which always produced the same 'graphic paths' for checkboxes and radio buttons. Thus, I was able to use some regexes on each page's content: private string GetPageContent(PdfReader pdfReader, int page) { StringBuilder sb = new StringBuilder(); // from http://www.java2s.com/Open-Source/CSharp/PDF/iTextSharp/iTextSharp/text/pdf/parser/PdfContentReaderTool.cs.htm RandomAccessFileOrArray f = pdfReader.SafeFile; byte[] contentBytes = pdfReader.GetPageContent(page, f); f.Close(); foreach (byte b in contentBytes) sb.Append((char)b); return sb.ToString(); } For example, an unchecked radio button always looked like this: 1 1 1 rg 61.35 644.08 m 61.35 642.22 59.84 640.71 57.97 640.71 c 56.11 640.71 54.6 642.22 54.6 644.08 c 54.6 645.95 56.11 647.46 57.97 647.46 c 59.84 647.46 61.35 645.95 61.35 644.08 c h f Q q 47.85 654.21 m 68.1 654.21 l 68.1 633.96 l 47.85 633.96 l 47.85 654.21 l h W n 0 0 0 rg 57.97 646.71 m 59.42 646.71 60.6 645.53 60.6 644.08 c 60.6 642.64 59.42 641.46 57.97 641.46 c 56.53 641.46 55.35 642.64 55.35 644.08 c 55.35 645.53 56.53 646.71 57.97 646.71 c h 57.97 647.46 m 56.11 647.46 54.6 645.95 54.6 644.08 c 54.6 642.22 56.11 640.71 57.97 640.71 c 59.84 640.71 61.35 642.22 61.35 644.08 c 61.35 645.95 59.84 647.46 57.97 647.46 c h f 3 concentric circles, while a checked radio button always had 4 concentric circles. The annotation always followed the concentric circles. Similarly for checkboxes.