title: Programatically added picture in PDF picture field not being displayed
body: <p>I have created a PDF with Adobe, which contains an image field called "logo"</p>
  
  <p>Now if i want to add a picture using PDFBox it won't be displayed in the created pdf. </p>
  
  <p>However no error message is thrown and debugging looks completely fine with a correctly created PDImageXObject object.</p>
  
  <p>The used code is mostly adapted from this <a href="https://stackoverflow.com/questions/46799087/how-to-insert-image-programmatically-in-to-acroform-field-using-java-pdfbox/46820098#46820098">question</a>:</p>
  
  <pre><code> public static void setImageField(PDDocument pdfDocument, PDAcroForm acroForm, String fieldKey, byte[] imageData)
    {
      final PDField retrievedField = acroForm.getField(fieldKey);
  
      if (!(retrievedField instanceof PDPushButton)) {
        throw new RuntimeException("The field: " + fieldKey + " is not of the correct type");
      }
  
      LOGGER.info("Received field: " + retrievedField.getPartialName()); // correct field is being logged
  
      final PDPushButton imageField = (PDPushButton) retrievedField;
      final List&lt;PDAnnotationWidget&gt; fieldWidgets = imageField.getWidgets(); // it has exactly one widget, which would be the action to set the image
  
      if (fieldWidgets == null || fieldWidgets.size() &lt;= 0) {
        throw new RuntimeException("Misconfiguration for field: " + fieldKey + ", it has no widgets(actions)");
      }
  
      final PDAnnotationWidget imageWidget = fieldWidgets.get(0);
  
      PDImageXObject imageForm;
  
      try {
        // This test data is resized to be smaller than the bounding box of the image element in the PDF. Just for testing purposes
        final String testImage = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAARUlEQVR42u3PMREAAAgEIO2fzkRvBlcPGtCVTD3QIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIXC7VGjKHva+IvAAAAAElFTkSuQmCC";
        final byte[] testData = Base64.getDecoder().decode(testImage);
        imageForm = PDImageXObject.createFromByteArray(pdfDocument, testData, "logo"); // imageForm is being populated with data and no error thrown
      }
      catch (IOException e) {
        throw new RuntimeException("Error creating Image from image data", e);
      }
  
      final float imageScaleRatio = (float) (imageForm.getHeight() / imageForm.getWidth());
  
      final PDRectangle imagePosition = getFieldArea(imageField);
      LOGGER.info("Received image position: " + imagePosition.toString());
  
      // Retrieve the height and width and position of the rectangle where the picture will be
      final float imageHeight = imagePosition.getHeight();
      LOGGER.info("Image height: " + imageHeight);
  
      final float imageWidth = imageHeight / imageScaleRatio;
      LOGGER.info("Image width: " + imageWidth);
  
      final float imageXPosition = imagePosition.getLowerLeftX();
      LOGGER.info("Image X position: " + imageXPosition);
  
      final float imageYPosition = imagePosition.getLowerLeftY();
      LOGGER.info("Image Y position: " + imageYPosition);
  
      final PDAppearanceStream documentAppearance = new PDAppearanceStream(pdfDocument);
      documentAppearance.setResources(new PDResources()); // not sure why this is done
  
      // Weird "bug" in pdfbox forces to create the contentStream always after the object to add
      try (PDPageContentStream documentContentStream = new PDPageContentStream(pdfDocument, documentAppearance)) {
        documentContentStream.drawImage(imageForm, imageXPosition, imageYPosition, imageWidth, imageHeight);
      }
      catch (IOException e) {
        throw new RuntimeException("Error drawing the picture in the document", e);
      }
  
      // Setting the boundary box is mandatory for the image field! Do not remove or the flatten call on the acroform will NPE
      documentAppearance.setBBox(new PDRectangle(imageXPosition, imageYPosition, imageWidth, imageHeight));
  
      // Apply the appearance settings of the document onto the image widget ( No border )
      setImageAppearance(imageWidget, documentAppearance);
  
      // This code is normally somewhere else but for SO copied in this method to show how the pdf is being created
      acroForm.flatten();
      AccessPermission ap = new AccessPermission();
      ap.setCanModify(false);
      ap.setCanExtractContent(false);
      ap.setCanFillInForm(false);
      ap.setCanModifyAnnotations(false);
      ap.setReadOnly();
      StandardProtectionPolicy spp = new StandardProtectionPolicy("", "", ap);
      spp.setEncryptionKeyLength(PdfBuildConstants.ENCRYPTION_KEY_LENTGH);
  
      pdfDocument.protect(spp);
      pdfDocument.save(pdfFile);
      pdfDocument.close();
    }
  
    /**
     * Applies the appearance settings of the document onto the widget to ensure a consistent look of the document.
     *
     * @param imageWidget        The {@link PDAnnotationWidget Widget} to apply the settings to
     * @param documentAppearance The {@link PDAppearanceStream Appearance settings} of the document
     */
    private static void setImageAppearance(final PDAnnotationWidget imageWidget,
                                           final PDAppearanceStream documentAppearance)
    {
      PDAppearanceDictionary widgetAppearance = imageWidget.getAppearance();
  
      if (widgetAppearance == null) {
        widgetAppearance = new PDAppearanceDictionary();
        imageWidget.setAppearance(widgetAppearance);
      }
  
      widgetAppearance.setNormalAppearance(documentAppearance);
    }
  
    /**
     * Retrieves the dimensions of the given {@link PDField Field} and creates an {@link PDRectangle Rectangle} with the
     * same dimensions.
     *
     * @param field The {@link PDField Field} to create the rectangle for
     * @return The created {@link PDRectangle Rectangle} with the dimensions of the field
     */
    private static PDRectangle getFieldArea(PDField field) {
      final COSDictionary fieldDictionary = field.getCOSObject();
  
      final COSBase fieldAreaValue = fieldDictionary.getDictionaryObject(COSName.RECT);
  
      if (!(fieldAreaValue instanceof COSArray)) {
        throw new RuntimeException("The field: " + field.getMappingName() + " has no position values");
      }
  
      final COSArray fieldAreaArray = (COSArray) fieldAreaValue;
      return new PDRectangle(fieldAreaArray);
    }
  </code></pre>
  
  <p>I also looked at other questions such as <a href="https://stackoverflow.com/questions/8521290/cant-add-an-image-to-a-pdf-using-pdfbox?rq=1">this</a>, but I can't use PDJpeg since it is not available in the current version. Additionally the original image to use can be anything from jpeg,png to gif.</p>
  
  <p>I validated that the position and dimension variables being logged have the same value as the image field in the pdf file. (properties of the field)</p>
  
  <p>UPDATE:
  Here is an example zip containing the template pdf and the generated pdf which fills in the form fields: <a href="https://www.file-upload.net/download-13732606/pdfBox-example.zip.html" rel="nofollow noreferrer">file upload</a> or <a href="https://www.dropbox.com/s/pa5q7cwqcieeusx/pdfBox-example.zip?dl=0" rel="nofollow noreferrer">Dropbox</a></p>
  
  <p>The example picture was a 50x50 png with plain green color generated from <a href="http://png-pixel.com/" rel="nofollow noreferrer">online png pixel</a></p>