2017-10-04 15 views
1

iText7을 사용하여 편집 가능한 양식 필드가있는 일부 PDF 문서를 생성 중입니다. 내 코드는 다음 코드를 사용하여 PDF 문서에 필드를 추가합니다PDF AcroForm 필드가 Acrobat에서 먼저 수정 된 다음 iText7에서 공백이됩니다.

@Override 
public void draw(DrawContext drawContext) { 
    super.draw(drawContext); 

    PdfAcroForm form = PdfAcroForm.getAcroForm(drawContext.getDocument(), true); 
    PdfFormField field = isMultiline 
      ? PdfFormField.createMultilineText(drawContext.getDocument(), getOccupiedAreaBBox(), fieldName, "") 
      : PdfFormField.createText(drawContext.getDocument(), getOccupiedAreaBBox(), fieldName, ""); 
    field.setFontSize(defaultFontSize - 1); 
    form.addField(field); 
} 

이는 iText를 사용자 정의 렌더러 클래스의 draw 방법이다.
생성 된 PDF 문서가 의도 한대로 작동합니다. Adobe Acrobat Reader에서 열어 편집 가능한 필드를 채우거나 저장 한 다음 다시 열 수 있습니다.

내 요구 사항 중 하나는 양식을 프로그래밍 방식으로 평면화 할 수있게하는 것입니다 (사람이 작성한 후 분명히) 그 후에 편집이 불가능하게됩니다.

나는이 코드를 사용하여이 작업을 수행 :

나는 PDF 리더 평탄화 된 PDF를 열 때
PdfDocument pdf = ... // Read a PDF stream and get the document object 
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, false); 
form.flattenFields(); 
pdf.close() 

지금 문제, 필드가 비어 있습니다.


좀 디버깅을했고, 나는 어도비 리더 (버전 XI)와 편집 (구원) 한 필드를 평평하게하려고하는 경우에만이 문제가 발생할 것 같습니다. 프로그래밍 방식으로 입력란을 수정하면 (예 : iText의 PdfFormField#setValue(String) 메서드를 사용하면 병합 된 PDF가 값을 잘 렌더링합니다.

Adobe Reader는 양식 필드의 일부 속성을 적절하게 병합하지 못하게 설정 한 것 같습니다. 실제로 사실입니까? 그 주위에 어떤 방법이 있습니까?
는 ---------------------- 당신에게

---------------- EDIT 감사

분명히이 문제는 Adobe Reader에서 발생합니다. 어떤 이유로 /XObject 하위 유형없이 필드 정의를 저장하며 iText7은 form.flattenFields() 메소드를 검사합니다. <</BBox [0.0 0.0 523.0 109.0 ] /Filter /FlateDecode /Length 107 /Resources <</Font <</F1 21 0 R >> >> >>

당신이 /Subtype 일부가 누락 볼 수 있듯이 : Acrobat Reader가에 의해 저장된 <</BBox [0 0 523 109 ] /Filter /FlateDecode /Length 95 /Matrix [1 0 0 1 0 0 ] /Resources <</Font <</F1 23 0 R >> >> /Subtype /Form /Type /XObject >>

:

iText7에 의해 생성 :
이 필드 문자열 이클립스 디버거에서 같이 무엇인가 . 양식 입력란을 사용 중지 할 때마다 (예 : PdfAcroForm#flattenFields() 또는 PdfFormField#setReadOnly(boolean)는 iText를이 코드와 PdfCanvas에 대한 내용을 다시 그리기를 시도합니다 리더 필드가 더이상 /XObject하지 않기 때문에, 생략됩니다

if(xObject != null && xObject.getPdfObject().get(PdfName.Subtype) != null) { 
    [...] 
    canvas.addXObject(xObject, ...); 
    } 

.

내 해결 방법은 현재 새 것으로 필드를 대체하는 것입니다 :

Map<String,PdfFormField> fields = form.getFormFields(); 
Set<String> keys = new HashSet<>(fields.keySet());  // avoids concurrent modifications 

for(String fieldName : keys) { 
    PdfFormField field = fields.get(fieldName); 
    PdfDictionary fieldObject = field.getPdfObject(); 

    PdfFormField newField = field.isMultiline() 
      ? PdfFormField.createMultilineText(pdf, fieldObject.getAsRectangle(PdfName.Rect), fieldName, 
        field.getValueAsString(), defaultFont, defaultFontSize) 
      : PdfFormField.createText(pdf, fieldObject.getAsRectangle(PdfName.Rect), fieldName, 
        field.getValueAsString(), defaultFont, defaultFontSize); 

    form.replaceField(fieldName, newField); 
} 

form.flattenFields(); 

그것은 종류의 글꼴 정보가 동적으로 설정되지 않은 경우에도 작동하지만이 another story입니다.

답변

0

결국 나는 iText RUPS으로 PDF를 열었습니다. Acrobat Reader가 하위 유형을 설정했으나 /Widget 인 것처럼 보입니다. 내가 찾은 마지막 해결 방법은 수동으로 하위 유형을 /XObject으로 설정 한 다음 form.flatten()으로 전화하는 것입니다. 또한 필드에 글꼴 정보가 보존됩니다.

하위 유형을 수동으로 변경하면 다른 것들이 손상 될 수 있습니다. 나는 PDF 전문가가 아니기 때문에 확신 할 수 없다. 그러나 지금은 하위 유형을 변경하고 곧바로 병합하기 때문에 큰 문제는 아닙니다.

이 코드의 최종 버전은 다음과 같습니다 : 의도 한대로 작동처럼

for(String fieldName : keys) { 
    PdfFormField field = fields.get(fieldName); 
    PdfDictionary fieldObject = field.getPdfObject(); 

    if(fieldObject.get(PdfName.Subtype) != PdfName.XObject) { 
     fieldObject.put(PdfName.Subtype, PdfName.XObject); 
    } 
} 

form.flattenFields(); 
pdf.close(); 

이 방법이 보인다.