I'm writing a program that takes a template PDF with a bunch of blank form fields, makes a copy of it, fills in the forms, then flattens the fields.
One of these templates has a ton of fields so writing a method that fills in all the fields results in an error that says code is too large due to the size limits on methods.
To work around this, I closed the destination file then tried to open it in another method where I could continue to fill in the fields, but this results in an error that says "(The requested operation cannot be performed on a file with a user-mapped section open)"
I ended the first method by closing the PDF, so I'm not sure what the issue is. The program will execute the first method, fill the fields but throws the error when it get to the 2nd method. Sample code below.
public void E2fill(String srcE2, String destE2) throws IOException
{
try
{
PdfDocument pdf2 = new PdfDocument(new PdfReader(destE2), new PdfWriter(dest2E2));
PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true);
Map<String, PdfFormField> fields2 = form2.getFormFields();
PdfFormField field2;
fields2.get("fieldname1").setValue(stringname1);
//lots more field fills
pdf2.close()
}
catch(Exception x)
{
System.out.println(x.getMessage());
}
}
public void E2fill2(String destE2, String dest2E2) throws IOException
{
try
{
PdfDocument pdf2 = new PdfDocument(new PdfReader(destE2), new PdfWriter(dest2E2));
PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true);
Map<String, PdfFormField> fields2 = form2.getFormFields();
PdfFormField field2;
fields2.get("fieldname546").setValue(stringname546);
//more field fills
form2.flattenFields();
pdf2.close();
}
catch(Exception x)
{
System.out.println(x.getMessage());
}
}
I suggest you try this:
public void fill(String srcE2, String destE2) {
PdfDocument pdf2 = new PdfDocument(new PdfReader(destE2), new PdfWriter(dest2E2));
PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true);
Map<String, PdfFormField> fields2 = form2.getFormFields();
E2fill(fields2);
E2fill2(fields2);
form2.flattenFields();
pdf2.close();
}
public void E2fill(Map<String, PdfFormField> fields2) throws IOException
{
fields2.get("fieldname1").setValue(stringname1);
//lots more field fills
}
public void E2fill2(PdfAcroForm form2) throws IOException {
fields2.get("fieldname546").setValue(stringname546);
//more field fills
}
Related
I'm using itext 7.1.8 and I need to add fields with the same names to pdf. I use the code like the following:
public class Main {
public static void main(String[] args) {
final PdfDocument emptyPdfDocument = createEmptyPdfDocument(pdf);
addTextField("Text_1", "Hello", emptyPdfDocument.getFirstPage(), PdfAcroForm.getAcroForm(emptyPdfDocument, true), emptyPdfDocument);
addTextField("Text_1", "Hello", emptyPdfDocument.addNewPage(), PdfAcroForm.getAcroForm(emptyPdfDocument, true), emptyPdfDocument);
savePdf(emptyPdfDocument);
}
private static void addTextField(String name, String value, PdfPage page, PdfAcroForm form, PdfDocument pdf) {
PdfFormField field = form.getField(name);
final Rectangle rect = new Rectangle(100, page.getCropBox().getHeight() - 100, 300, 20);
if (field != null) {
PdfWidgetAnnotation annotation = new PdfWidgetAnnotation(rect);
annotation.makeIndirect(pdf);
annotation.setVisibility(VISIBLE);
field.addKid(annotation);
page.addAnnotation(annotation);
return;
}
field = PdfFormField.createText(pdf, rect, name);
field.setValue(value);
field.setVisibility(VISIBLE);
page.addAnnotation(field.getWidgets().get(0));
form.addField(field, page);
}
private static PdfDocument createEmptyPdfDocument(final String pdfPath) throws IOException {
PdfWriter pdfWriter = new PdfWriter(new FileOutputStream(pdfPath));
final PdfDocument pdfDocument = new PdfDocument(pdfWriter);
pdfDocument.addNewPage();
return pdfDocument;
}
public static void savePdf(PdfDocument pdf) {
pdf.close();
}
}
but when the method addTextField has been called the second time the kids of the field are empty.
I don't understand what I'm doing wrong.
I want to convert a raster file into a shapefile. I am creating a GridCoverage2D object and want to use the execute method of Geotools PolygonExtractionProcess class but this method is not executing. I sadly cannot find any useful example usages of this class. This is my code:
try {
File rasterFile = new File("C:\\Data\\mytif.tif");
AbstractGridFormat format = GridFormatFinder.findFormat(rasterFile);
Hints hints = new Hints();
if (format instanceof GeoTiffFormat) {
hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
}
reader = format.getReader(rasterFile, hints);
GridCoverage2D coverage = reader.read(null); // It all works until this point
final PolygonExtractionProcess process = new PolygonExtractionProcess();
//System.out.println("This gets printed");
SimpleFeatureCollection sfColl = process.execute(coverage, null, Boolean.TRUE, null, null, null, null);
//System.out.println("This does not get printed anymore");
Style style = SLD.createPolygonStyle(Color.RED, null, 0.0f);
Layer layer = new FeatureLayer(sfColl, style);
map.addLayer(layer);
} catch (Exception e) {
System.err.println(e);
}
First, if all you want to do is extract vectors from a raster you could probably save using the process API completely by looking inside PolygonExtractionProcess to see how it works using the JAI.
But if you want to run a process then you should read the process tutorial which describes how they work and how to call them from your own code (this is usually used for testing). Essentially, the issue you are having comes from not understanding that processes are called from the processing engine (ProcessExecutor) which manages the input and output, and threading etc for you.
So your code should look something like this:
public class RasterToVector {
public static void main(String[] args)
throws IllegalArgumentException, IOException, InterruptedException, ExecutionException {
RasterToVector rtv = new RasterToVector();
SimpleFeatureCollection features = rtv.extract(args[0]);
Style style = SLD.createPolygonStyle(Color.RED, null, 0.0f);
Layer layer = new FeatureLayer(features, style);
MapContent map = new MapContent();
map.addLayer(layer);
JMapFrame.showMap(map);
}
org.geotools.process.Process process;
public RasterToVector() {
Name name = new NameImpl("ras", "PolygonExtraction");
process = Processors.createProcess(name);
}
private SimpleFeatureCollection extract(String filename)
throws IllegalArgumentException, IOException, InterruptedException, ExecutionException {
File rasterFile = new File(filename);
AbstractGridFormat format = GridFormatFinder.findFormat(rasterFile);
Hints hints = new Hints();
if (format instanceof GeoTiffFormat) {
hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
}
AbstractGridCoverage2DReader reader = format.getReader(rasterFile, hints);
GridCoverage2D coverage = reader.read(null);
ProcessExecutor engine = Processors.newProcessExecutor(2);
Map<String, Object> input = new KVP("data", coverage);
Progress working = engine.submit(process, input);
Map<String, Object> result = working.get();
SimpleFeatureCollection features = (SimpleFeatureCollection) result.get("result");
return features;
}
}
For a local terrain file I get the following result:
i want to generate a pdf with itext 7,but some wrong happens to us:
com.itextpdf.kernel.PdfException: Pdf indirect object belongs to other PDF document. Copy object to current pdf document.
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:195) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:185) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:115) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:187) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:115) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:187) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfOutputStream.write(PdfOutputStream.java:115) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfWriter.writeToBody(PdfWriter.java:383) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfWriter.flushObject(PdfWriter.java:289) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfDocument.flushObject(PdfDocument.java:1572) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfObject.flush(PdfObject.java:159) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfObject.flush(PdfObject.java:127) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfObjectWrapper.flush(PdfObjectWrapper.java:94) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfPage.flush(PdfPage.java:495) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfPage.flush(PdfPage.java:454) ~[kernel-7.0.2.jar:na]
at com.itextpdf.kernel.pdf.PdfDocument.close(PdfDocument.java:785) ~[kernel-7.0.2.jar:na]
at com.itextpdf.layout.Document.close(Document.java:120) ~[layout-7.0.2.jar:na]
at com.xcz.afbp.thirdparty.service.impl.GeneratePDFService.generatePDF(GeneratePDFService.java:160) ~[classes/:na]
my generate code :
public void generatePDF(CreditQueryData creditQueryData, Map<String, UserCreditContentView> contentViewMap, List<PackageCreditContentView> needRetrievedCreditContentList, File pdfFile, BigDecimal score) throws Exception {
if (!pdfFile.exists()) {
boolean x = pdfFile.createNewFile();
if (!x) {
LOG.error("生成文件出错" + pdfFile.getPath());
return;
}
}
PdfDocument pdf = new PdfDocument(new PdfWriter(new FileOutputStream(pdfFile)));
Document document = new Document(pdf, PageSize.A4);
document.setRenderer(new DocumentRenderer(document));
pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new WatermarkingEventHandler());
try {
//operate code just add tableA tableB tableC...
} catch (Exception e) {
LOG.info();
} finally {
document.close(); //exception throws here
}
}
my only style code in itext7:
private PdfFont bfChinese = null;
will be init in service constructor invoked:
public GeneratePDFService() {
String PdfFontPath = EnvironmentUtils.getClasspathFilePath("font/MSYH.TTF");
try {
bfChinese = PdfFontFactory.createFont(PdfFontPath, "Identity-H", true);
} catch (Exception e) {
e.printStackTrace();
}
}
i have tried set my font to static,but not works.
this is the place throw exception:
private void write(PdfIndirectReference indirectReference) {
if (document != null && !indirectReference.getDocument().equals(document)) {
throw new PdfException(PdfException.PdfIndirectObjectBelongsToOtherPdfDocument);
}
if (indirectReference.getRefersTo() == null) {
write(PdfNull.PDF_NULL);
} else if (indirectReference.getGenNumber() == 0) {
writeInteger(indirectReference.getObjNumber()).
writeBytes(endIndirectWithZeroGenNr);
} else {
writeInteger(indirectReference.getObjNumber()).
writeSpace().
writeInteger(indirectReference.getGenNumber()).
writeBytes(endIndirect);
}
}
it's means i have two different document ,but i do not know when i have create another document.
Thanks in advance for suggestions.
I have experienced the same problem myself (and it took me hours to discover what I was doing wrong). As it turns out, you can use a specific PdfFont instance for only one document. As soon as you use a PdfFont instance it is linked to that document, and you can no longer use it in another document.
For instance:
class ThisGoesWrong {
protected PdfFont font;
public ThisGoesWrong() {
font = PdfFontFactory.createFont(...);
}
public void createPdf() {
...
Paragraph p = new Paragraph("test").setFont(font);
document.add(p);
...
}
}
The class ThisGoesWrong creates a correct PDF the first time you call createPdf(), but it shows the exception you have when you call it a second time.
I discovered that this solves the problem:
class ThisWorksOK {
public ThisWorksOK() {
}
public void createPdf() {
...
PdfFont font = PdfFontFactory.createFont(...);
Paragraph p = new Paragraph("test").setFont(font);
document.add(p);
...
}
}
I don't know if this is a bug (it certainly feels like a bug), so I will create an internal ticket at iText Group.
To improve preformance you should reuse FontProgram:
private FontProgram bfChinese = null;
public GeneratePDFService() {
String PdfFontPath = EnvironmentUtils.getClasspathFilePath("font/MSYH.TTF");
try {
bfChinese = FontProgramFactory.createFont(PdfFontPath);
} catch (Exception e) {
e.printStackTrace();
}
}
And then:
public void createPdf() {
...
PdfFont font = PdfFontFactory.createFont(bfChinese, "Identity-H", true);
Paragraph p = new Paragraph("test").setFont(font);
document.add(p);
...
}
This is how i solved the issue.
Created an DocumentUtil class
Add a static method
public class DocumentUtils {
public static PdfFont setFont() throws Exception {
return PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN);
}
}
Use the font like:
PDfFont font = DocumentUtil.setFont();
I have been following the 'Chapter 8: Filling out interactive forms' iText example (code and pdfs at http://itextpdf.com/examples/iia.php?id=154) and have noticed a number of appearance-related issues which also manifest themselves in the example pdfs.
The example features a list of radio buttons (classic dot within a circle) and a list of checkboxes (crossed box with a red background). So far so good. However the pdf generated after programmatically filling in these fields is visually inconsistent. The radio buttons have all reverted to squares and the selected ('Spanish') has a wingdings (?) cross within it rather than a dot. The fields are all still editable. When I select a different radio button, the previously selected radio button reverts to an empty circle. The newly selected field has changed from an empty square to a dotted circle. This can also be observed with the checkboxes.
Is there any way to fill the fields whilst preserving their original appearances?
Thanks!
EDIT - Here's a simplification of the code I use :
public void buildPdf() throws Exception {
Document document = new Document(PageSize.A4);
File file = new File("/test.pdf");
final PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
document.open();
PdfPCell cell = new PdfPCell();
PdfRadioGroupTable group = new PdfRadioGroupTable("ndna", Arrays.asList("Not Available", "Not Applicable"), writer, Locale.ENGLISH, DEFAULT);
cell.addElement(group);
PdfPTable table = new PdfPTable(1);
table.addCell(cell);
cell = new PdfPCell();
cell.setCellEvent(new ActionEvent(writer, "http://localhost:8080/entrypointpdf"));
table.addCell(cell);
document.add(table);
group.addAnnotations();
document.close();
}
Here's the ActionEvent
class ActionEvent implements PdfPCellEvent {
private PdfWriter writer;
private String submissionUrl;
public ActionEvent(PdfWriter writer, String submissionUrl) {
this.writer = writer;
this.submissionUrl = submissionUrl;
}
#Override
public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
PushbuttonField submit = new PushbuttonField(writer, position, "submit") {
#Override
public PdfFormField getField() throws IOException, DocumentException {
PdfFormField field = super.getField();
field.setAction(PdfAction.createSubmitForm(submissionUrl, null, 0));
return field;
}
};
submit.setText("CLICK ME");
submit.setTextColor(BaseColor.BLUE);
submit.setFont(DEFAULT.getCalculatedBaseFont(false));
submit.setVisibility(PushbuttonField.VISIBLE);
try {
writer.addAnnotation(submit.getField());
} catch (Exception ignore) {
}
}
}
Here's the PdfRadioGroupTable
public class PdfRadioGroupTable extends PdfPTable {
private PdfWriter writer;
public PdfFormField radioGroup;
public PdfRadioGroupTable(String name, List<String> choices, PdfWriter writer, Locale locale, Font font) {
super(2);
this.writer = writer;
setWidthPercentage(100);
try {
setTotalWidth(new float[] { 14, 400 });
} catch (DocumentException ignore) {
}
radioGroup = PdfFormField.createRadioButton(writer, true);
radioGroup.setFieldName(name);
PdfPCell cell;
for (String choice : choices) {
cell = new PdfPCell();
cell.setBorder(0);
cell.setPaddingBottom(5);
cell.setUseAscender(true);
cell.setUseDescender(true);
cell.setVerticalAlignment(PdfPCell.ALIGN_CENTER);
cell.setCellEvent(new RadioCellEvent(radioGroup, choice));
addCell(cell);
cell = new PdfPCell();
cell.setBorder(0);
cell.setPaddingBottom(5);
cell.setPaddingLeft(6);
cell.setUseAscender(true);
cell.setUseDescender(true);
cell.setVerticalAlignment(PdfPCell.ALIGN_CENTER);
cell.addElement(new Phrase(choice), font));
addCell(cell);
}
}
class RadioCellEvent implements PdfPCellEvent {
protected PdfFormField radioGroup;
protected String value;
public RadioCellEvent(PdfFormField radioGroup, String value) {
this.radioGroup = radioGroup;
this.value = value;
}
#Override
public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
RadioCheckField radio = new RadioCheckField(writer, position, null, value);
radio.setChecked(false);
radio.setBorderColor(GrayColor.GRAYBLACK);
radio.setBackgroundColor(GrayColor.GRAYWHITE);
radio.setCheckType(RadioCheckField.TYPE_CIRCLE);
try {
PdfFormField field = radio.getRadioField();
writer.addAnnotation(field);
radioGroup.addKid(field);
} catch (Exception exception) {
throw new ExceptionConverter(exception);
}
}
}
}
And here's what happens on the server side when one clicks the button in the pdf (in acrobat) :
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=\"your.pdf\"");
try {
FdfReader fdf = new FdfReader(request.getInputStream());
File pdfFile = new File("/test.pdf");
InputStream is = new FileInputStream(pdfFile);
PdfReader reader = new PdfReader(is);
File resultFile = new File(System.currentTimeMillis() + "_" + pdfFile.getName());
FileOutputStream out = new FileOutputStream(resultFile);
PdfStamper stamper = new PdfStamper(reader, out);
AcroFields fields = stamper.getAcroFields();
fields.setFields(fdf);
// EXTRACT VALUES HERE
stamper.setFormFlattening(true);
stamper.close();
reader.close();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(FilesUtilities.read(resultFile));
OutputStream os = response.getOutputStream();
bos.writeTo(os);
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
So basically I generate a pdf with one radiogroup and a button. The button results in the pdf fields being imported and the idea is to send a 'receipt' back to the user in the form of the previously generated pdf containing the same fields with the user selection/values and import status fields (ok, missing, bad data, etc.) (which I have omitted in the above code as that part works fine). My problem is that the radio fields in the returned pdf don't look remotely like the editable ones in the original pdf (they don't even look like radio buttons anymore).
I tried using
fields.setFieldProperty("ndna", "setfflags", PdfFormField.FF_READ_ONLY, null);
and disabling form flattening by this results in the same alternate appearance in the returned pdf.
Your help would be most appreciated as I've been struggling with this for a while now...
Anthony
This seems to be a bug on some versions of iText. I had the same problem with iTextSharp version 5.5.5 and it was solved after I upgraded to version 5.5.9. I used "nuget" to do this. Here's a link: https://www.nuget.org/packages/iTextSharp/5.5.9
I have excel. and I create macro to the excel file to read data from other resources. the macro run every second and update its excel cells.
Now, I want to build java program to read the excel data every seconds to. I have try Apache POI, but after I check the documentation ti doesn't support reading excel file with macro.
I read from some resources Java Com Bridge (JCOB) can be used to read excel with macro. I've try, But the cell value still not updated every times I try my code.
import com.jacob.com.*;
import com.jacob.activeX.*;
public class ExcelTest {
private static ActiveXComponent xl;
private static Dispatch workbooks = null;
private static Dispatch workbook = null;
private static Dispatch sheet = null;
private static String filename = null;
private static boolean readonly = false;
public static void main(String[] args) {
String file = "D:\\tutorial\\ApachePoi\\ratesource.xls";
OpenExcel(file, false); // do not show false to open Excel
System.out.println(GetValue("B46"));
}
private static void OpenExcel(String file, boolean f) {
try {
filename = file;
xl = new ActiveXComponent("Excel.Application");
xl.setProperty("Visible", new Variant(f));
workbooks = xl.getProperty("Workbooks").toDispatch();
workbook = Dispatch.invoke(
workbooks,
"Open",
Dispatch.Method,
new Object[] { filename, new Variant(false),
new Variant(readonly) },// whether to open read-only
new int[1]).toDispatch();
} catch (Exception e) {
e.printStackTrace();
}
}
// Read value
private static String GetValue(String position) {
if (workbook == null) {
System.out.println("workbook is null");
}
sheet = Dispatch.get(workbook, "ActiveSheet").toDispatch();
Object cell = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[]{position}, new int[1]).toDispatch();
String value = Dispatch.get((Dispatch) cell, "Value").toString();
return value;
}
//1.3638356164383563
//1.3638356164383563
private static void SetValue (String position, String type, String value)
{
}
}
I am unfamiliar with an Excel engine capable of doing what you describe.
Have you considered talking to Excel instead and ask it for its values when running your spread-sheet? I believe you can do so with ODBC.
Another approach might be creating an OpenOffice version of your sheet and talk to OpenOffice instead.
One pitfall is poi don't change the value of the existing excel write to another file and you can see the difference
workbook.getSheet().getRow(1).getCell(0).setValue("test");
and write this(changed) workbook to another file
public void writeFile(String fileName) {
FileOutputStream fos;
try {
fos = new FileOutputStream(fileName);
getWorkbook().write(fos);
fos.close();
} catch (IOException e) {
System.out.println("IOException occurs");
e.printStackTrace();
}
}