iText - Java Android - 向现有 pdf 添加字段
iText - Java Android - Adding fields to existing pdf
我正在尝试向现有 PDF 添加交互字段,我使用 PdfReader 和 PdfStamper 来执行此操作,当我在平板电脑上打开它时,一切正常。但是,当我想在我的电脑上打开它时,没有字段。
这是我的代码示例,每一页都有多个字段,但我在这里只打印了两个字段:
public class SelfNoteFragment extends Fragment {
private PdfStamper pdfStamper;
class MyCellField implements PdfPCellEvent {
protected String fieldname;
protected int page;
public MyCellField(String fieldname, int page) {
this.fieldname = fieldname;
this.page = page;
}
public void cellLayout(PdfPCell cell, Rectangle rectangle, PdfContentByte[] canvases) {
final PdfWriter writer = canvases[0].getPdfWriter();
final TextField textField = new TextField(writer, rectangle, fieldname);
try {
final PdfFormField field = textField.getTextField();
pdfStamper.addAnnotation(field, page);
} catch (final IOException ioe) {
throw new ExceptionConverter(ioe);
} catch (final DocumentException de) {
throw new ExceptionConverter(de);
}
}
}
class CheckboxCellEvent implements PdfPCellEvent {
protected String name;
protected boolean check;
protected int page;
public CheckboxCellEvent(String name, boolean check, int page) {
this.check = check;
this.name = name;
this.page = page;
}
public void cellLayout(PdfPCell cell, Rectangle position,
PdfContentByte[] canvases) {
PdfWriter writer = canvases[0].getPdfWriter();
float x = position.getLeft();
float y = position.getBottom();
Rectangle rect = new Rectangle(x-5, y-5, x+5, y+5);
RadioCheckField checkbox = new RadioCheckField(
writer, rect, name, "Yes");
checkbox.setCheckType(RadioCheckField.TYPE_CROSS);
checkbox.setChecked(check);
try {
pdfStamper.addAnnotation(checkbox.getCheckField(), page);
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
}
private void createPdf(int idPrevision) throws FileNotFoundException, DocumentException {
try {
PdfReader pdfReader = new PdfReader("/storage/emulated/0/Documents/fiche_chantier2.pdf");
//Create time stamp
Date date = new Date() ;
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(date);
File pdfFolder = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), "Prevision_");
if (!pdfFolder.exists()) {
pdfFolder.mkdir();
}
File myFile = new File(pdfFolder + timeStamp + ".pdf");
OutputStream output = new FileOutputStream(myFile);
this.pdfStamper = new PdfStamper(pdfReader, output);
PdfContentByte canvas1;
PdfContentByte canvas2;
canvas1 = pdfStamper.getOverContent(1);
canvas2 = pdfStamper.getOverContent(2);
PdfPCell cellFillFieldPage1 = new PdfPCell();
cellFillFieldPage1.setCellEvent(new MyCellField("", 1));
cellFillFieldPage1.setFixedHeight(15);
cellFillFieldPage1.setBorder(Rectangle.NO_BORDER);
cellFillFieldPage1.setVerticalAlignment(Element.ALIGN_MIDDLE);
PdfPCell cellCheckBoxPage2 = new PdfPCell();
cellCheckBoxPage2.setCellEvent(new CheckboxCellEvent("", false, 2));
cellCheckBoxPage2.setBorder(Rectangle.NO_BORDER);
// ************** PAGE 1 ************** //
// SET TABLE
PdfPTable tableSection1Page1 = new PdfPTable(1);
tableSection1Page1.setTotalWidth(136);
tableSection1Page1.setWidthPercentage(100.0f);
tableSection1Page1.setLockedWidth(true);
// ADD CELLS TO TABLE
tableSection1Page1.addCell(cellFillFieldPage1);
// PRINT TABLES
tableSection1Page1.writeSelectedRows(0, -1, 165, 730, canvas1);
// ************ PAGE 2 ************ //
// SET TABLES
PdfPTable tableSection1Page2 = new PdfPTable(1);
tableSection1Page2.setTotalWidth(10);
tableSection1Page2.setWidthPercentage(100.0f);
tableSection1Page2.setLockedWidth(true);
// ADD CELLS TO TABLE
tableSection1Page2.addCell(cellCheckBoxPage2);
// PRINT TABLES
tableSection1Page2.writeSelectedRows(0, -1, 182, 736, canvas2);
// I tried this, but it didn't change anything
pdfStamper.setFormFlattening(false);
pdfStamper.close();
pdfReader.close();
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
您知道为什么我创建的 PDF 在我的平板电脑上很好用而不在我的电脑上很好用吗(当我想通过邮件发送它时也是如此)?如果是这样,您知道如何解决这个问题吗?
谢谢,
科伦廷
你的代码实际上有两个问题,
您创建了空名称的字段:
cellFillFieldPage1.setCellEvent(new MyCellField("", 1));
...
cellCheckBoxPage2.setCellEvent(new CheckboxCellEvent("", false, 2));
首先,所有字段都需要有一个名称。此外,即使空名称是允许的名称选择,具有相同名称的两个字段也被认为是同一抽象字段的两种表示形式,如果一个是文本字段而另一个是复选框字段,则很难解决这个问题。
只要您用非空的不同名称命名这些字段,您就会看到 Adobe 上有字段 Reader DC/Win:您可以使用 TAB 键在它们之间切换并改变他们的价值观。但不幸的是,它们是无边界的,因此,如果是空的,则很难发现。这是因为
您没有为字段设置边框颜色。因此,iText 创建了无边框的表单字段外观流。
您可以这样设置边框颜色:
...
final TextField textField = new TextField(writer, rectangle, fieldname);
textField.setBorderColor(BaseColor.BLACK);
...
RadioCheckField checkbox = new RadioCheckField(writer, rect, name, "Yes");
checkbox.setBorderColor(BaseColor.BLACK);
...
这样做之后,您会得到带有黑色边框的字段...
如果您想知道为什么不同的观众(即使是同一家公司的同名观众)在这里表现不同...
一些 PDF 查看器很早就意识到他们无法正确处理空名称的字段,因此甚至不显示它们,而其他查看器稍后在尝试保存或 post 形式,或者根本不认识它,产生损坏的输出。
PDF 查看器可以忽略表单字段的外观流(实际上是一般的注释)并创建自己的外观;因此,在手头的情况下,他们可能会忽略 iText 生成的无边框外观并绘制一个带有可见边框的外观。
我正在尝试向现有 PDF 添加交互字段,我使用 PdfReader 和 PdfStamper 来执行此操作,当我在平板电脑上打开它时,一切正常。但是,当我想在我的电脑上打开它时,没有字段。
这是我的代码示例,每一页都有多个字段,但我在这里只打印了两个字段:
public class SelfNoteFragment extends Fragment {
private PdfStamper pdfStamper;
class MyCellField implements PdfPCellEvent {
protected String fieldname;
protected int page;
public MyCellField(String fieldname, int page) {
this.fieldname = fieldname;
this.page = page;
}
public void cellLayout(PdfPCell cell, Rectangle rectangle, PdfContentByte[] canvases) {
final PdfWriter writer = canvases[0].getPdfWriter();
final TextField textField = new TextField(writer, rectangle, fieldname);
try {
final PdfFormField field = textField.getTextField();
pdfStamper.addAnnotation(field, page);
} catch (final IOException ioe) {
throw new ExceptionConverter(ioe);
} catch (final DocumentException de) {
throw new ExceptionConverter(de);
}
}
}
class CheckboxCellEvent implements PdfPCellEvent {
protected String name;
protected boolean check;
protected int page;
public CheckboxCellEvent(String name, boolean check, int page) {
this.check = check;
this.name = name;
this.page = page;
}
public void cellLayout(PdfPCell cell, Rectangle position,
PdfContentByte[] canvases) {
PdfWriter writer = canvases[0].getPdfWriter();
float x = position.getLeft();
float y = position.getBottom();
Rectangle rect = new Rectangle(x-5, y-5, x+5, y+5);
RadioCheckField checkbox = new RadioCheckField(
writer, rect, name, "Yes");
checkbox.setCheckType(RadioCheckField.TYPE_CROSS);
checkbox.setChecked(check);
try {
pdfStamper.addAnnotation(checkbox.getCheckField(), page);
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
}
private void createPdf(int idPrevision) throws FileNotFoundException, DocumentException {
try {
PdfReader pdfReader = new PdfReader("/storage/emulated/0/Documents/fiche_chantier2.pdf");
//Create time stamp
Date date = new Date() ;
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(date);
File pdfFolder = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), "Prevision_");
if (!pdfFolder.exists()) {
pdfFolder.mkdir();
}
File myFile = new File(pdfFolder + timeStamp + ".pdf");
OutputStream output = new FileOutputStream(myFile);
this.pdfStamper = new PdfStamper(pdfReader, output);
PdfContentByte canvas1;
PdfContentByte canvas2;
canvas1 = pdfStamper.getOverContent(1);
canvas2 = pdfStamper.getOverContent(2);
PdfPCell cellFillFieldPage1 = new PdfPCell();
cellFillFieldPage1.setCellEvent(new MyCellField("", 1));
cellFillFieldPage1.setFixedHeight(15);
cellFillFieldPage1.setBorder(Rectangle.NO_BORDER);
cellFillFieldPage1.setVerticalAlignment(Element.ALIGN_MIDDLE);
PdfPCell cellCheckBoxPage2 = new PdfPCell();
cellCheckBoxPage2.setCellEvent(new CheckboxCellEvent("", false, 2));
cellCheckBoxPage2.setBorder(Rectangle.NO_BORDER);
// ************** PAGE 1 ************** //
// SET TABLE
PdfPTable tableSection1Page1 = new PdfPTable(1);
tableSection1Page1.setTotalWidth(136);
tableSection1Page1.setWidthPercentage(100.0f);
tableSection1Page1.setLockedWidth(true);
// ADD CELLS TO TABLE
tableSection1Page1.addCell(cellFillFieldPage1);
// PRINT TABLES
tableSection1Page1.writeSelectedRows(0, -1, 165, 730, canvas1);
// ************ PAGE 2 ************ //
// SET TABLES
PdfPTable tableSection1Page2 = new PdfPTable(1);
tableSection1Page2.setTotalWidth(10);
tableSection1Page2.setWidthPercentage(100.0f);
tableSection1Page2.setLockedWidth(true);
// ADD CELLS TO TABLE
tableSection1Page2.addCell(cellCheckBoxPage2);
// PRINT TABLES
tableSection1Page2.writeSelectedRows(0, -1, 182, 736, canvas2);
// I tried this, but it didn't change anything
pdfStamper.setFormFlattening(false);
pdfStamper.close();
pdfReader.close();
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
您知道为什么我创建的 PDF 在我的平板电脑上很好用而不在我的电脑上很好用吗(当我想通过邮件发送它时也是如此)?如果是这样,您知道如何解决这个问题吗?
谢谢, 科伦廷
你的代码实际上有两个问题,
您创建了空名称的字段:
cellFillFieldPage1.setCellEvent(new MyCellField("", 1)); ... cellCheckBoxPage2.setCellEvent(new CheckboxCellEvent("", false, 2));
首先,所有字段都需要有一个名称。此外,即使空名称是允许的名称选择,具有相同名称的两个字段也被认为是同一抽象字段的两种表示形式,如果一个是文本字段而另一个是复选框字段,则很难解决这个问题。
只要您用非空的不同名称命名这些字段,您就会看到 Adobe 上有字段 Reader DC/Win:您可以使用 TAB 键在它们之间切换并改变他们的价值观。但不幸的是,它们是无边界的,因此,如果是空的,则很难发现。这是因为
您没有为字段设置边框颜色。因此,iText 创建了无边框的表单字段外观流。
您可以这样设置边框颜色:
... final TextField textField = new TextField(writer, rectangle, fieldname); textField.setBorderColor(BaseColor.BLACK); ... RadioCheckField checkbox = new RadioCheckField(writer, rect, name, "Yes"); checkbox.setBorderColor(BaseColor.BLACK); ...
这样做之后,您会得到带有黑色边框的字段...
如果您想知道为什么不同的观众(即使是同一家公司的同名观众)在这里表现不同...
一些 PDF 查看器很早就意识到他们无法正确处理空名称的字段,因此甚至不显示它们,而其他查看器稍后在尝试保存或 post 形式,或者根本不认识它,产生损坏的输出。
PDF 查看器可以忽略表单字段的外观流(实际上是一般的注释)并创建自己的外观;因此,在手头的情况下,他们可能会忽略 iText 生成的无边框外观并绘制一个带有可见边框的外观。