java - iText Fill Form / Copy Page to new Document -
i'm useing itext
fill template pdf contains acroform
. want use template create new pdf dynamically pages. idea fill template pdf, copy page written fields , add new file. main problem our customer want designe template them self. i'm not sure if try right way solve problem.
so i've created code don't work right error com.itextpdf.io.ioexception: pdf header not found.
my code
x = 1; try (pdfdocument finaldoc = new pdfdocument(new pdfwriter("c:\\users\\...final.pdf"))) { (hashmap<string, string> map : testvalues) { string path1 = "c:\\users\\.....temp.pdf" inputstream template = templatevalues.get("template"); pdfwriter writer = new pdfwriter(path1); try (pdfdocument pdfdoc = new pdfdocument(new pdfreader(template), writer)) { pdfacroform form = pdfacroform.getacroform(pdfdoc, true); (hashmap.entry<string, string> map2 : map.entryset()) { if (form.getfield(map2.getkey()) != null) { map<string, pdfformfield> fields = form.getformfields(); fields.get(map2.getkey()).setvalue(map2.getvalue()); } } } catch (ioexception | pdfexception ex) { system.err.println("ex2: " + ex.getmessage()); } if (x != 0 && (x % 5) == 0) { try (pdfdocument tempdoc = new pdfdocument(new pdfreader(path1))) { pdfpage page = tempdoc.getfirstpage(); finaldoc.addpage(page.copyto(finaldoc)); } catch (ioexception | pdfexception ex) { system.err.println("ex3: " + ex.getmessage()); } } x++; } } catch (ioexception | pdfexception ex) { system.err.println("ex: " + ex.getmessage()); }
part 1 - pdf header missing
this appears caused attempting re-read inputstream w/in loop has been read (and, depending on configuration of pdfreader, closed). solving depends on specific type of inputstream being used - if want leave simple inputstream (vs. more specific yet more capable inputstream type) you'll need first slurp bytes stream memory (e.g. bytearrayoutputstream) create pdfreaders based on bytes.
i.e.
bytearrayoutputstream templatebuffer = new bytearrayoutputstream(); while ((int c = template.read()) > 0) templatebuffer.write(c); (/* loop */) { ... pdfdocument filledinacroformtemplate = new pdfdocument(new pdfreader(new bytearrayinputstream(templatebuffer.tobytearray())), new pdfwriter(tmp)) ...
part 2 - other problems
couple of things
- make sure grab released 7.0.1 version of itext since included couple of fixes wrt/ acroform handling
- you can away using bytearrayoutputstreams temporary pdfs (vs. writing them out files) - i'll use approach in example below
- pdfdocument/pdfpage in "kernel" module, yet acroforms in "form" module (meaning pdfpage intentionally unaware of acroforms) - ipdfpageextracopier sortof bridge between modules. in order copy acroforms, need use two-arg copyto() version, passing instance of pdfpageformcopier
field names must unique in document (the "absolute" field name - i'll skip field hierarcies now). since we're looping through , adding fields template multiple times, need come strategy rename fields ensure uniqueness (the current api little bit clunky in area)
file acroformtemplate = new file("sometemplate.pdf"); map<string, string> somemapoffieldtovalues = new hashmap<>(); try ( pdfdocument finaloutput = new pdfdocument(new pdfwriter(new fileoutputstream(new file("finaloutput.pdf"))); ) { (/* looping condition */int x = 0; x < 5; x++) { // each iteration of loop, create temporary in-memory // pdf handle form field edits. bytearrayoutputstream tmp = new bytearrayoutputstream(); try ( pdfdocument filledinacroformtemplate = new pdfdocument(new pdfreader(new fileinputstream(acroformtemplate)), new pdfwriter(tmp)); ) { pdfacroform acroform = pdfacroform.getacroform(filledinacroformtemplate, true); (pdfformfield field : acroform.getformfields().values()) { if (somemapoffieldtovalues.containskey(field.getfieldname())) { field.setvalue(somemapoffieldtovalues.get(field.getfieldname())); } } // note because we're adding template multiple times // need adopt field renaming strategy ensure field // uniqueness in final document. demonstration's sake // we'll rename them prefixed w/ our loop counter list<string> fieldnames = new arraylist<>(); fieldnames.addall(acroform.getformfields().keyset()); // avoid confurrentmodification (string fieldname : fieldnames) { acroform.renamefield(fieldname, x+"_"+fieldname); } } // temp pdf needs "closed" pdf finalization // magic happen...so open new read-only version act // source merging our in-memory bucket-o-bytes try ( pdfdocument readonlyfilledinacroformtemplate = new pdfdocument(new pdfreader(new bytearrayinputstream(tmp.tobytearray()))); ) { // although pdfpage.copyto work simple pages, pdfdocument.copypagesto // more comprehensive copy (wider support copying outlines , tagged content) // it's more suitable general page-copy use. also, since we're copying acroform // content, need use pdfpageformcopier readonlyfilledinacroformtemplate.copypagesto(1, 1, finaloutput, new pdfpageformcopier()); } } }
Comments
Post a Comment