2017-10-17 14 views
1

나는 3 개의 레이블 (이름, 성 및 사진)으로 간단한 PDF 문서를 만들었습니다. 그런 다음 Adobe Acrobat PRO DC를 사용하여 2 개의 '텍스트 필드'와 하나의 '이미지 필드'가있는 AcroForm 레이어를 추가했습니다. 나는 일반 Acrobat Reader가이 PDF 파일을 열고 이름, 성을 입력하여 채우고 사진을 삽입하기 위해 할 수있는 양식을 채우려면Java PDFBox를 사용하여 프로그래밍 방식으로 AcroForm 필드에 이미지를 삽입하는 방법은 무엇입니까?

enter image description here

그래서 이미지 자리 표시를 클릭 열린 대화 상자에서 사진을 선택하십시오.

enter image description here

하지만 프로그래밍 같은 일을 할 수 있습니까? Apache PDFBox 라이브러리 (버전 2.0.7)를 사용하여 양식 필드를 찾고 값을 삽입하는 간단한 Java 응용 프로그램을 만들었습니다.

난 쉽게 텍스트 편집 필드를 채울 수 있지만 이미지 삽입 할 수있는 방법을 알아낼 수 없습니다 : 나는 이상한 것은 구별 한

public class AcroFormPopulator { 

    public static void main(String[] args) { 

     AcroFormPopulator abd = new AcroFormPopulator(); 
     try { 
      abd.populateAndCopy("test.pdf", "generated.pdf"); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void populateAndCopy(String originalPdf, String targetPdf) throws IOException { 
     File file = new File(originalPdf); 

     PDDocument document = PDDocument.load(file); 
     PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm(); 

     Map<String, String> data = new HashMap<>(); 
     data.put("firstName", "Mike"); 
     data.put("lastName", "Taylor"); 
     data.put("photo_af_image", "photo.jpeg"); 

     for (Map.Entry<String, String> item : data.entrySet()) { 
      PDField field = acroForm.getField(item.getKey()); 
      if (field != null) { 

       if (field instanceof PDTextField) { 
        field.setValue(item.getValue()); 

       } else if (field instanceof PDPushButton) { 
        File imageFile = new File(item.getValue()); 

        PDPushButton pdPushButton = (PDPushButton) field; 
        // do not see way to isert image 

       } else { 
        System.err.println("No field found with name:" + item.getKey()); 
       } 
      } else { 
       System.err.println("No field found with name:" + item.getKey()); 
      } 
     } 

     document.save(targetPdf); 
     document.close(); 
     System.out.println("Populated!"); 
    } 
} 

- 그것은 내가 이미지 필드를 추가 있다고 아크로뱃 프로 DC에서, 그러나 유일한 필드는 생성 된 이름으로 얻을 : 'photo_af_image'는 button 유형입니다 - PDPushButton (그 이유는 (instanceof PDPushButton)),하지만 Image와는 아무 관련이 없습니다.

Acrobat Pro DC로 만든 상자의 크기에 맞게 이미지를 AcroForm 'photo_af_image'필드에 어떻게 삽입합니까?

답변

2

나는 마침내 멋진 해결책을 발견하고 구축했다.이 솔루션의 목표는 다음과 같습니다

  1. 비 프로그래머에 의해 수행 될 수 있으며, 낮은 수준의 PDF 구조를 조작 을 필요로하지 않는 간단한 도구를 사용하여 텍스트 및 이미지 플레이스 홀더 형태의 층을 만들;
  2. 삽입 된 이미지의 크기는 간단한 도구를 사용하여 양식 작성자가 결정합니다. 크기는 높이에 따라 조정되지만 폭은 비율에 따라 조정됩니다.

acroForm 자리로 이미지를 삽입 아래 솔루션의 주요 아이디어는 다음과 같습니다

  1. 당신이 acroForm 계층을 반복하고 자리 표시 자 이름을 해당 와 버튼을 찾을 수있다;
  2. 발견 된 필드가 PDPushButton 유형 인 경우 첫 번째 위젯을 가져옵니다.
  3. 이미지 파일에서 PDImageXObject를 만듭니다.
  4. PDImageXObject를 사용하여 PDAppearanceStream을 만들고 동일한 x 값을 & y로 설정하고 높이와 너비를 자리 표시 자 높이와 일치하도록 조정합니다.
  5. 이 PDAppearanceStream을 위젯으로 설정하십시오.
  6. 선택적 acroform 메인 에 누워 병합 문서를 평평하게 할 수있는 하나 여기

입니다 코드 :

import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.util.Date; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import javax.imageio.ImageIO; 

import org.apache.pdfbox.cos.COSArray; 
import org.apache.pdfbox.cos.COSDictionary; 
import org.apache.pdfbox.cos.COSName; 
import org.apache.pdfbox.pdmodel.PDDocument; 
import org.apache.pdfbox.pdmodel.PDPageContentStream; 
import org.apache.pdfbox.pdmodel.PDResources; 
import org.apache.pdfbox.pdmodel.common.PDRectangle; 
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory; 
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; 
import org.apache.pdfbox.pdmodel.interactive.action.PDAction; 
import org.apache.pdfbox.pdmodel.interactive.action.PDActionHide; 
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; 
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; 
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; 
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; 
import org.apache.pdfbox.pdmodel.interactive.form.PDField; 
import org.apache.pdfbox.pdmodel.interactive.form.PDPushButton; 
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField; 

public class AcroFormPopulator { 

    public static void main(String[] args) { 
     AcroFormPopulator abd = new AcroFormPopulator(); 
     try { 
      Map<String, String> data = new HashMap<>(); 
      data.put("firstName", "Mike"); 
      data.put("lastName", "Taylor"); 
      data.put("dateTime", (new Date()).toString()); 
      data.put("photo_af_image", "photo1.jpg"); 
      data.put("photo2_af_image", "photo2.jpg"); 
      data.put("photo3_af_image", "photo3.jpg"); 

      abd.populateAndCopy("test.pdf", "generated.pdf", data); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void populateAndCopy(String originalPdf, String targetPdf, Map<String, String> data) throws IOException { 
     File file = new File(originalPdf); 
     PDDocument document = PDDocument.load(file); 
     PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm(); 

     for (Map.Entry<String, String> item : data.entrySet()) { 
      String key = item.getKey(); 
      PDField field = acroForm.getField(key); 
      if (field != null) { 
       System.out.print("Form field with placeholder name: '" + key + "' found"); 

       if (field instanceof PDTextField) { 
        System.out.println("(type: " + field.getClass().getSimpleName() + ")"); 
        field.setValue(item.getValue()); 
        System.out.println("value is set to: '" + item.getValue() + "'"); 

       } else if (field instanceof PDPushButton) { 
        System.out.println("(type: " + field.getClass().getSimpleName() + ")"); 
        PDPushButton pdPushButton = (PDPushButton) field; 

        List<PDAnnotationWidget> widgets = pdPushButton.getWidgets(); 
        if (widgets != null && widgets.size() > 0) { 
         PDAnnotationWidget annotationWidget = widgets.get(0); // just need one widget 

         String filePath = item.getValue(); 
         File imageFile = new File(filePath); 

         if (imageFile.exists()) { 
          /* 
          * BufferedImage bufferedImage = ImageIO.read(imageFile); 
          * PDImageXObject pdImageXObject = LosslessFactory.createFromImage(document, bufferedImage); 
          */ 
          PDImageXObject pdImageXObject = PDImageXObject.createFromFile(filePath, document); 
          float imageScaleRatio = (float) pdImageXObject.getHeight()/(float) pdImageXObject.getWidth(); 

          PDRectangle buttonPosition = getFieldArea(pdPushButton); 
          float height = buttonPosition.getHeight(); 
          float width = height/imageScaleRatio; 
          float x = buttonPosition.getLowerLeftX(); 
          float y = buttonPosition.getLowerLeftY(); 

          PDAppearanceStream pdAppearanceStream = new PDAppearanceStream(document); 
          pdAppearanceStream.setResources(new PDResources()); 
          try (PDPageContentStream pdPageContentStream = new PDPageContentStream(document, pdAppearanceStream)) { 
           pdPageContentStream.drawImage(pdImageXObject, x, y, width, height); 
          } 
          pdAppearanceStream.setBBox(new PDRectangle(x, y, width, height)); 

          PDAppearanceDictionary pdAppearanceDictionary = annotationWidget.getAppearance(); 
          if (pdAppearanceDictionary == null) { 
           pdAppearanceDictionary = new PDAppearanceDictionary(); 
           annotationWidget.setAppearance(pdAppearanceDictionary); 
          } 

          pdAppearanceDictionary.setNormalAppearance(pdAppearanceStream); 
          System.out.println("Image '" + filePath + "' inserted"); 

         } else { 
          System.err.println("File " + filePath + " not found"); 
         } 
        } else { 
         System.err.println("Missconfiguration of placeholder: '" + key + "' - no widgets(actions) found"); 
        } 
       } else { 
        System.err.print("Unexpected form field type found with placeholder name: '" + key + "'"); 
       } 
      } else { 
       System.err.println("No field found with name:" + key); 
      } 
     } 

     // you can optionally flatten the document to merge acroform lay to main one 
     acroForm.flatten(); 

     document.save(targetPdf); 
     document.close(); 
     System.out.println("Done"); 
    } 

    private PDRectangle getFieldArea(PDField field) { 
     COSDictionary fieldDict = field.getCOSObject(); 
     COSArray fieldAreaArray = (COSArray) fieldDict.getDictionaryObject(COSName.RECT); 
     return new PDRectangle(fieldAreaArray); 
    } 
} 

이 코드는 당신이 향상시킬 수있는 더 나은 솔루션 또는 무언가가 있으면 알려 주시기 바랍니다 .