Page 1 of 1

How to add linked image to document?

PostPosted: Tue Jun 09, 2009 4:01 am
by debarcar
I know how to add embedded image as following. Could some one tell me how to add linked image?

File file = new File(fileurl);

java.io.InputStream is = new java.io.FileInputStream(file );
long length = file.length();
if (length > Integer.MAX_VALUE) {
System.out.println("File too large!!");
}
byte[] bytes = new byte[(int)length];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
System.out.println("Could not completely read file "+file.getName());
}
is.close();

String filenameHint = null;
String altText = null;
int id1 = 0;
int id2 = 1;



BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
Inline inline;

if (cx == 0) {
inline = imagePart.createImageInline(filenameHint, altText, id1, id2);
} else {
inline = imagePart.createImageInline(filenameHint, altText, id1, id2, cx);
}

// Now add the inline in w:p/w:r/w:drawing
org.docx4j.wml.ObjectFactory factory = new org.docx4j.wml.ObjectFactory();
org.docx4j.wml.P p = factory.createP();
org.docx4j.wml.R run = factory.createR();
p.getParagraphContent().add(run);
org.docx4j.wml.Drawing drawing = factory.createDrawing();
run.getRunContent().add(drawing);
drawing.getAnchorOrInline().add(inline);

wordMLPackage.getMainDocumentPart().addObject(p);

Re: How to add linked image to document?

PostPosted: Tue Jun 09, 2009 5:08 am
by jason
Assuming you already have an embedded image, you can convert it to a linked one ...

First, assuming the image's relationship is r, you need:

Code: Select all
            r.setTargetMode("External");
            r.setTarget(urlString);


Second, given the org.docx4j.wml.Drawing d, you need to change a:blip/@r:embed to a:blip/@r:link:

Code: Select all
         // Extract w:drawing/wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/@r:embed
         
         org.docx4j.dml.Inline inline = (org.docx4j.dml.Inline )d.getAnchorOrInline().get(0);
         
         org.docx4j.dml.Pic pic = inline.getGraphic().getGraphicData().getPic();
                  
         System.out.println( "*** image relationship: " +  pic.getBlipFill().getBlip().getEmbed() );
         
         if ( !pic.getBlipFill().getBlip().getEmbed().equals("") ) {
               // that method returns empty string, rather than null
            
            String relId = pic.getBlipFill().getBlip().getEmbed();
            // Add r:link
            pic.getBlipFill().getBlip().setLink(relId);
            // Remove r:embed
            pic.getBlipFill().getBlip().setEmbed(null);
            
         }


That's the basic differences.

But I'm assuming you just want to add a link to an existing image into a document you are constructing.

At present, BinaryPartAbstractImage doesn't have anything like:

Code: Select all
createLinkedImagePart(WordprocessingMLPackage wordMLPackage,
         URL url)


and createLinkedImageInline, to do this for you automatically.

But you can probably see how to add them easily, now? Please consider contributing your change back :-)

Note that Package contains:

Code: Select all
   protected HashMap<ExternalTarget, Part> externalResources
      = new HashMap<ExternalTarget, Part>();


When a document containing external parts is loaded, they are stored in there.

Code: Select all
            BinaryPart bp = getExternalResource(r.getTarget());
            pkg.getExternalResources().put(bp.getExternalTarget(), bp);         

Re: How to add linked image to document?

PostPosted: Wed Jun 10, 2009 11:22 am
by debarcar
Thanks a lot!

I will try to write the createLinkedImagePart method...When I finish, I will post it here.

Re: How to add linked image to document?

PostPosted: Wed Jul 29, 2009 11:08 am
by debarcar
public static BinaryPartAbstractImage createLinkedImagePart(WordprocessingMLPackage wordMLPackage, String fileurl) throws Exception {

ImageInfo info = null;
boolean imagePreloaderFound = true;
try {
info = getImageInfo(fileurl);
displayImageInfo(info);
} catch (org.apache.xmlgraphics.image.loader.ImageException e) {
imagePreloaderFound = false;
log.warn(e.getMessage());
}

if (imagePreloaderFound
&& (info.getMimeType().equals(ContentTypes.IMAGE_TIFF) || info.getMimeType().equals(ContentTypes.IMAGE_EMF) || info.getMimeType().equals(ContentTypes.IMAGE_WMF)
|| info.getMimeType().equals(ContentTypes.IMAGE_PNG) || info.getMimeType().equals(ContentTypes.IMAGE_JPEG) || info.getMimeType().equals(
ContentTypes.IMAGE_GIF))) {
log.debug(".. supported natively by Word");
} else {
log.debug(".. unsupported image type and insert failure...");
}
ContentTypeManager ctm = wordMLPackage.getContentTypeManager();
BinaryPartAbstractImage imagePart = (BinaryPartAbstractImage) ctm.newPartForContentType(info.getMimeType(), generateName());
log.debug("created part " + imagePart.getClass().getName() + " with name " + imagePart.getPartName().toString());

imagePart.rel = wordMLPackage.getMainDocumentPart().addTargetPart(imagePart);
imagePart.rel.setTargetMode("External");

if (new File(fileurl).isFile()) {
imagePart.rel.setTarget("file:///" + fileurl);
} else {
imagePart.rel.setTarget(fileurl);
}

imagePart.setImageInfo(info);
return imagePart;
}

added to the class BinaryPartAbstractImage...

call it:

public void addlinkedImage(String fileurl, long cx) throws Exception {


String filenameHint = (new File(fileurl)).getName();
String altText = fileurl;

int id1 = 0;
int id2 = 1;

BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createLinkedImagePart(wordMLPackage, fileurl);
Inline inline;

if (cx == 0) {
inline = imagePart.createImageInline(filenameHint, altText, id1, id2);
} else {
inline = imagePart.createImageInline(filenameHint, altText, id1, id2, cx);
}

org.docx4j.dml.Pic pic = inline.getGraphic().getGraphicData().getPic();

System.out.println( "*** image relationship: " + pic.getBlipFill().getBlip().getEmbed() );

if ( !pic.getBlipFill().getBlip().getEmbed().equals("") ) {
// that method returns empty string, rather than null

String relId = pic.getBlipFill().getBlip().getEmbed();
// Add r:link
pic.getBlipFill().getBlip().setLink(relId);
// Remove r:embed
pic.getBlipFill().getBlip().setEmbed(null);

}

// Now add the inline in w:p/w:r/w:drawing
org.docx4j.wml.ObjectFactory factory = new org.docx4j.wml.ObjectFactory();
org.docx4j.wml.P p = factory.createP();
org.docx4j.wml.R run = factory.createR();
p.getParagraphContent().add(run);
org.docx4j.wml.Drawing drawing = factory.createDrawing();
run.getRunContent().add(drawing);
drawing.getAnchorOrInline().add(inline);

wordMLPackage.getMainDocumentPart().addObject(p);

}

it is ok in my environment now...

Re: How to add linked image to document?

PostPosted: Fri Jan 01, 2010 3:44 pm
by debarcar
Hi Jason,

Would you please add this function to docx4j?

Thanks!

Re: How to add linked image to document?

PostPosted: Sat Jan 02, 2010 4:49 am
by jason
Done as http://dev.plutext.org/trac/docx4j/changeset/983

Please test.

Note that the various createImageInline methods now take a new last argument which is a boolean named link:

Code: Select all
      if (link) {
         type = "r:link";
      } else {
         type = "r:embed";
      }


Because of this, there is no need for your method addlinkedImage(String fileurl, long cx)

Re: How to add linked image to document?

PostPosted: Thu Apr 18, 2013 2:09 am
by ham_360
Hi,
Thanks for these additions. I have found that they have not been integrated to org.docx4j.convert.in.xhtml.XHTMLImporter.class however, so the importer falls over when it encounters images with web URLs...

Re: How to add linked image to document?

PostPosted: Thu Apr 18, 2013 4:30 am
by ham_360
I guess the following changes to org.docx4j.convert.in.xhtml.XHTMLImporter.addImage(Element) would suffice

Move imagePart and inline declarations to top
Code: Select all
BinaryPartAbstractImage imagePart = null;
Inline inline = null;

Move existing imagePart and inline assignments from bottom try{} to each of the existing cases in the if / else
Code: Select all
imageBytes = ...
imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, imageBytes);
inline = imagePart.createImageInline( null, null, 0, 1, false);

Add new case for linked images, including true parameter on createImageInline
Code: Select all
} else if (e.getAttribute("src").startsWith("http:" ) ) {
   imagePart = BinaryPartAbstractImage.createLinkedImagePart(wordMLPackage, new URL(e.getAttribute("src")));
   inline = imagePart.createImageInline( null, null, 0, 1, true);
}


Note, the original imagePart and inline assignments are within a try{} block, so its probably best to just extend its reach around the whole if/elseif/else as well.

I'm not familiar with the process for making these changes to this kind of open source project though...

Re: How to add linked image to document?

PostPosted: Thu Apr 18, 2013 9:12 pm
by ham_360
I can confirm this is working locally, having followed the steps above. It is worth noting that my first test image happened to deny me access which lead me to believe web-based URL's aren't accepted by createLinkedImagePart, but this is untrue.

Re: How to add linked image to document?

PostPosted: Fri Apr 19, 2013 11:47 pm
by ham_360
So it appears that the original XHTMLImporter is indeed working for Web URLs. My bad! This whole investigation sprouted from an unfortunate choice of test image, whose server happened to deny requests from Java. The modifications above do provide some value however - the XHTMLImporter was falling over when encountering such a permissions error. With the modifications above though, the resulting rendering is instead able to complete, displaying just '[MISSING IMAGE: <url>]' in its place...

Re: How to add linked image to document?

PostPosted: Fri Nov 15, 2013 9:44 pm
by iseletkov
Hi, All!
I want to copy Image from one header to another. Simple adding drawing to content in second header leads to red cross in Word.
Do I have to create new image part?
How to get URI to embedded image (for using createLinkedImagePart) if I have drawing only?
Could you provide any example?

Thanks!

Re: How to add linked image to document?

PostPosted: Fri Nov 15, 2013 9:50 pm
by iseletkov
My objective is to get one embedded phisical image file and number of links to it from different parts of document.

Re: How to add linked image to document?

PostPosted: Sat Nov 16, 2013 7:20 am
by jason
If header1 includes an image, then header1's relationship part will include a reference to that image. You can upload a docx to the online webapp (see link above), to see this.

If you want to include that image in header2, say, then you also need a reference to the image in header2's rels part.

Re: How to add linked image to document?

PostPosted: Mon Nov 18, 2013 3:34 pm
by iseletkov
This works for me! Thanks, Jason.

There is my Java Script method to copy content from one part to another:
Code: Select all
CWordShell.prototype.CopyPart = function(oPartFrom, oPartTo)
{
    var oLV = new Object;
    oLV.aContentFrom    = oPartFrom.getContent();
    oLV.aContentTo      = oPartTo.getContent();
    //Copyes all content from one part to another
    oLV.aContentTo.addAll(oLV.aContentFrom);
    //For images we have to create new relations from oPartTo to imageParts
    oLV.oRelsPart = oPartFrom.getRelationshipsPart();
    oLV.aRels = oLV.oRelsPart.getRelationships().getRelationship();
   
    for (var i=0; i<oLV.aRels.size(); i++)
    {
        oPartTo.addTargetPart(oLV.oRelsPart.getPart(oLV.aRels.get(i)));   
    }
    return;
}