/**
   * Create an image part from the provided byte array, attach it to the source part (eg the main
   * document part, a header part etc), and return it.
   *
   * <p>Works for both docx and pptx.
   *
   * <p>Knowing the MIME type allows you to avoid ImageInfo, but you'll probably also need to know
   * the image dimensions
   *
   * @param opcPackage
   * @param sourcePart
   * @param bytes
   * @param mime MIME type eg image/png
   * @return
   * @throws Exception @Since 3.0.1
   */
  public static BinaryPartAbstractImage createImagePart(
      OpcPackage opcPackage, Part sourcePart, byte[] bytes, String mime) throws Exception {

    String ext = mimeToExt(mime);
    if (mime == null || ext == null) {
      log.warn("Null or unknown mime type; image introspection required!");
      return createImagePart(opcPackage, sourcePart, bytes);
    }

    ContentTypeManager ctm = opcPackage.getContentTypeManager();

    // Ensure the relationships part exists
    if (sourcePart.getRelationshipsPart() == null) {
      RelationshipsPart.createRelationshipsPartForPart(sourcePart);
    }

    String proposedRelId = sourcePart.getRelationshipsPart().getNextId();

    BinaryPartAbstractImage imagePart =
        (BinaryPartAbstractImage)
            ctm.newPartForContentType(
                mime, createImageName(opcPackage, sourcePart, proposedRelId, ext), null);

    log.debug(
        "created part "
            + imagePart.getClass().getName()
            + " with name "
            + imagePart.getPartName().toString());

    imagePart.setBinaryData(bytes);
    imagePart.rels.add(sourcePart.addTargetPart(imagePart, proposedRelId));

    return imagePart;
  }
  /**
   * Create a linked image part, and attach it as a rel of the specified source part (eg a header
   * part).
   *
   * <p>The current behaviour is that the part is added to the package, but since the target mode of
   * the rel is external, the part is redundant.
   *
   * @param wordMLPackage
   * @param sourcePart
   * @param url
   * @return
   * @throws Exception
   */
  public static BinaryPartAbstractImage createLinkedImagePart(
      OpcPackage opcPackage, Part sourcePart, URL url) throws Exception {

    log.debug("Incoming url for linked image: " + url.toString());

    ImageInfo info =
        ensureFormatIsSupported(url, null, null, false); // final param doesn't matter in this case

    ContentTypeManager ctm = opcPackage.getContentTypeManager();
    String proposedRelId = sourcePart.getRelationshipsPart().getNextId();
    // In order to ensure unique part name,
    // idea is to use the relId, which ought to be unique
    String ext = info.getMimeType().substring(info.getMimeType().indexOf("/") + 1);

    BinaryPartAbstractImage imagePart =
        (BinaryPartAbstractImage)
            ctm.newPartForContentType(
                info.getMimeType(),
                createImageName(opcPackage, sourcePart, proposedRelId, ext),
                null);

    // NB: contents never populated

    log.debug(
        "created part "
            + imagePart.getClass().getName()
            + " with name "
            + imagePart.getPartName().toString());

    imagePart.rels.add(
        sourcePart.addTargetPart(
            imagePart)); // want to create rel with suitable name; side effect is to add part
    imagePart.getRelLast().setTargetMode("External");

    opcPackage.getExternalResources().put(imagePart.getExternalTarget(), imagePart);

    //		if (!url.getProtocol().equals("file") && new File(url.toString() ).isFile()) {
    //			imagePart.rel.setTarget("file:///" + url);
    //		} else {
    //			imagePart.rel.setTarget(url.toString());
    //		}
    imagePart.getRelLast().setTarget(url.toString());

    imagePart.setImageInfo(info);

    return imagePart;
  }
  /**
   * Create an image part from the provided filePath image, attach it to the source part (eg the
   * main document part, a header part etc), and return it.
   *
   * <p>Works for both docx and pptx.
   *
   * @param opcPackage
   * @param sourcePart
   * @param filePath
   * @return
   * @throws Exception
   */
  public static BinaryPartAbstractImage createImagePart(
      OpcPackage opcPackage, Part sourcePart, File imageFile) throws Exception {

    final byte[] locByte = new byte[1];

    // We are in the case that image is not load (no byte Array) so isLoad is false
    ImageInfo info = ensureFormatIsSupported(imageFile, locByte, false);

    ContentTypeManager ctm = opcPackage.getContentTypeManager();

    // Ensure the relationships part exists
    if (sourcePart.getRelationshipsPart() == null) {
      RelationshipsPart.createRelationshipsPartForPart(sourcePart);
    }

    String proposedRelId = sourcePart.getRelationshipsPart().getNextId();

    String ext = info.getMimeType().substring(info.getMimeType().indexOf("/") + 1);

    BinaryPartAbstractImage imagePart =
        (BinaryPartAbstractImage)
            ctm.newPartForContentType(
                info.getMimeType(),
                createImageName(opcPackage, sourcePart, proposedRelId, ext),
                null);

    log.debug(
        "created part "
            + imagePart.getClass().getName()
            + " with name "
            + imagePart.getPartName().toString());

    FileInputStream fis = new FileInputStream(imageFile);
    imagePart.setBinaryData(fis);

    imagePart.rels.add(sourcePart.addTargetPart(imagePart, proposedRelId));

    imagePart.setImageInfo(info);

    return imagePart;
  }
  /**
   * Create an image part from the provided byte array, attach it to the source part (eg the main
   * document part, a header part etc), and return it.
   *
   * <p>Works for both docx and pptx.
   *
   * <p>Note: this method creates a temp file (and attempts to delete it). That's because it uses
   * org.apache.xmlgraphics
   *
   * @param opcPackage
   * @param sourcePart
   * @param bytes
   * @return
   * @throws Exception
   */
  public static BinaryPartAbstractImage createImagePart(
      OpcPackage opcPackage, Part sourcePart, byte[] bytes) throws Exception {

    // Whatever image type this is, we're going to need
    // to know its dimensions.
    // For that we use ImageInfo, which can only
    // load an image from a URI.

    // So first, write the bytes to a temp file
    File tmpImageFile = File.createTempFile("img", ".img");

    FileOutputStream fos = new FileOutputStream(tmpImageFile);
    fos.write(bytes);
    fos.close();
    log.debug("created tmp file: " + tmpImageFile.getAbsolutePath());

    ImageInfo info = ensureFormatIsSupported(tmpImageFile, bytes, true);

    // In the absence of an exception, tmpImageFile now contains an image
    // Word will accept

    ContentTypeManager ctm = opcPackage.getContentTypeManager();

    // Ensure the relationships part exists
    if (sourcePart.getRelationshipsPart() == null) {
      RelationshipsPart.createRelationshipsPartForPart(sourcePart);
    }

    String proposedRelId = sourcePart.getRelationshipsPart().getNextId();

    String ext = info.getMimeType().substring(info.getMimeType().indexOf("/") + 1);

    //		System.out.println(ext);

    BinaryPartAbstractImage imagePart =
        (BinaryPartAbstractImage)
            ctm.newPartForContentType(
                info.getMimeType(),
                createImageName(opcPackage, sourcePart, proposedRelId, ext),
                null);

    log.debug(
        "created part "
            + imagePart.getClass().getName()
            + " with name "
            + imagePart.getPartName().toString());

    FileInputStream fis = new FileInputStream(tmpImageFile);
    imagePart.setBinaryData(fis);

    imagePart.rels.add(sourcePart.addTargetPart(imagePart, proposedRelId));

    imagePart.setImageInfo(info);

    // Delete the tmp file
    // As per http://stackoverflow.com/questions/991489/i-cant-delete-a-file-in-java
    // the following 3 lines are necessary, at least on Win 7 x64
    // Also reported on Win XP, but in my testing, the files were deleting OK anyway.
    fos = null;
    fis = null;
    if (Docx4jProperties.getProperty(
        "docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.TempFiles.ForceGC",
        true)) {
      System.gc();
    }
    if (tmpImageFile.delete()) {
      log.debug(".. deleted " + tmpImageFile.getAbsolutePath());
    } else {
      log.warn("Couldn't delete tmp file " + tmpImageFile.getAbsolutePath());
      tmpImageFile.deleteOnExit();
      // If that doesn't work, see "Clean Up Your Mess: Managing Temp Files in Java Apps"
      // at devx.com
    }

    return imagePart;
  }