iText - Java Android - Adding fields to existing pdf

情到浓时终转凉″ 提交于 2020-01-06 01:57:29

问题


I'm trying to add interactive fields to an existing PDF, i use a PdfReader and a PdfStamper to do this, and when i open it on my tablet, everything is ok. However, when I want to open it on my computer, there are no fields.

This is a sample of my code, I have more than one field for each page but i only printed two fields here:

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();
        }
     }
}

Do you have an idea why my created PDF is good on my Tablet and not on my Computer (same when i want to send it by mail)? If so, do you know how to manage this problem?

Thank you, Corentin


回答1:


There actually are two issues in your code,

  1. you create the fields with empty names:

    cellFillFieldPage1.setCellEvent(new MyCellField("", 1));
    ...
    cellCheckBoxPage2.setCellEvent(new CheckboxCellEvent("", false, 2));
    

    First of all fields need to have a name. And furthermore, even if the empty name was an allowed choice for a name, two fields with the same name are considered to be two representations of the same abstract field which hardly works out if one is a text field and the other a checkbox field.

    As soon as you name those fields with non-empty, different names, you'll see that you have fields on Adobe Reader DC/Win: You can tab through them with the TAB key and change their values. Unfortunately, though, they are borderless and, therefore, hard to spot if empty. This is because

  2. you don't set border colors for your fields. iText, consequently, creates the form field appearance streams without borders.

    You can set the border color like this:

    ...
    final TextField textField = new TextField(writer, rectangle, fieldname);
    textField.setBorderColor(BaseColor.BLACK);
    ...
    RadioCheckField checkbox = new RadioCheckField(writer, rect, name, "Yes");
    checkbox.setBorderColor(BaseColor.BLACK);
    ...
    

    Having done so, you get the fields with black borders...


If you wonder why different viewers (even by the same company with the same name) behave different here...

  1. Some PDF viewers recognize early that they couldn't properly handle fields with empty names and, therefore, don't even show them while other viewers recognize that later when trying to save or post the form, or don't recognize it at all, producing broken outputs.

  2. PDF viewers are allowed to ignore appearance streams of form fields (actually of annotations in general) and create their own appearances; thus, in the case at hand they may ignore the borderless appearance generated by iText and draw one with a visible border.



来源:https://stackoverflow.com/questions/35630320/itext-java-android-adding-fields-to-existing-pdf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!