Page 1 of 1

Footer image and page Numbers

PostPosted: Tue May 17, 2011 9:28 am
by infiniteConfused
Hello,
I've searched the forum and can't find any information regarding this, so maybe someone can help me. I've added an image and a pagenumber to my footer, however, I need to be able to get the image to sit behind the pagenumbers. I tried to edit my word doc to see how word is handling it, and it seems it converts the inline image to an anchor image somehow. I don't want the image to be a link, I need it embedded. When I tried to add the image as an anchor, nothing happens, but I think that is due to me not linking the image to the anchor correctly. I've attached an example of what my footer looks like. Below is my code, any help is much appreciated:

Code: Select all
   private static String getImage(String type)
   {
      if(type.equalsIgnoreCase("Header")){
         return "C:\\Temp\\Images\\Template\\CampusTemplate\\word\\media\\image2.jpeg";
      } else if(type.equalsIgnoreCase("Footer1")){
      return "C:\\Temp\\Images\\Template\\CampusTemplate\\word\\media\\image3.jpeg";
      } else if(type.equalsIgnoreCase("Footer2")){
      return "C:\\Temp\\Images\\Template\\CampusTemplate\\word\\media\\image1.jpeg";
      } else {
         return type;
      }
   }
   public static byte[] getBytes(String type) throws Exception
   {
      File file = new File(getImage(type));
      InputStream is = new 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();
      return bytes;
   }
   public static P newImage(WordprocessingMLPackage wordMLPackage, Part sourcePart, byte[] bytes, String filenameHint, String altText, int id1, int id2, String type) throws Exception
   {
      Inline inline = new Inline();
      if(sourcePart == null) {
         BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
         inline = imagePart.createImageInline( filenameHint, altText, id1, id2, false);//false is so that this is imbedded image not link
      } else {
         BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, sourcePart, bytes);
         inline = imagePart.createImageInline( filenameHint, altText, id1, id2, false);
      }

      P p = factory.createP();
      R run = factory.createR();
      p.getParagraphContent().add(run);
      if (type.equalsIgnoreCase("Header")) {
         PPr ppr = p.getPPr();
         if (ppr == null) {
            ppr = factory.createPPr();
            p.setPPr(ppr);
         }
         Jc headjust = new Jc();
         headjust.setVal(JcEnumeration.RIGHT);
         ppr.setJc(headjust);
      }
      Drawing drawing = factory.createDrawing();
      run.getRunContent().add(drawing);
      drawing.getAnchorOrInline().add(inline);

      return p;

      /*// This is where I attempted to do the anchoring
      Anchor anchor = new Anchor();
      anchor.setDistT((long) 0);
      anchor.setDistB((long) 0);
      anchor.setDistL((long) 114300);
      anchor.setDistR((long) 114300);
      anchor.setRelativeHeight(251658240);
      anchor.setBehindDoc(true);
      anchor.setLocked(false);
      anchor.setLayoutInCell(true);
      anchor.setAllowOverlap(true);
      //CTPoint2D simp = new CTPoint2D();
      //simp.setX(0);
      //simp.setY(0);
      //anchor.setSimplePos(simp);
      CTPosH posH = new CTPosH();
      posH.setRelativeFrom(STRelFromH.COLUMN);
      posH.setPosOffset(-1422);
      anchor.setPositionH(posH);
      CTPosV posV = new CTPosV();
      posV.setRelativeFrom(STRelFromV.PARAGRAPH);
      posV.setPosOffset(104652);
      anchor.setPositionV(posV);
      CTPositiveSize2D ctpos = new CTPositiveSize2D();
      ctpos.setCx(5945022);
      ctpos.setCy(307074);
      anchor.setExtent(ctpos);
      CTEffectExtent ctee = new CTEffectExtent();
      ctee.setL(19050);
      ctee.setT(0);
      ctee.setR(0);
      ctee.setB(0);
      anchor.setEffectExtent(ctee);
      anchor.setWrapNone(null);
      
      Graphic gra = inline.getGraphic(); //need to figure out how to link a graphic to anchor. or get an image
      anchor.setGraphic(gra);
      drawing.getAnchorOrInline().add(anchor);
      return p;
*/
   }
   public static Hdr getHdr(WordprocessingMLPackage wordprocessingMLPackage, Part sourcePart) throws Exception
   {
      Hdr hdr = factory.createHdr();
      hdr.getEGBlockLevelElts().add(newImage(wordprocessingMLPackage, sourcePart, getBytes("Header"), "filename", "alttext", 1, 2, "Header"));
      return hdr;
   }
   public static Ftr getFtr(WordprocessingMLPackage wordprocessingMLPackage, Part sourcePart) throws Exception
   {
      // AddPage Numbers
      CTSimpleField pgnum = factory.createCTSimpleField();
      pgnum.setInstr(" PAGE \\* MERGEFORMAT ");
      RPr RPr = factory.createRPr();
       RPr.setNoProof(new BooleanDefaultTrue());
       PPr ppr = factory.createPPr();
       Jc jc = factory.createJc();
       jc.setVal(JcEnumeration.CENTER);
       ppr.setJc(jc);
       PPrBase.Spacing pprbase = factory.createPPrBaseSpacing();
       pprbase.setBefore(BigInteger.valueOf(240));
       pprbase.setAfter(BigInteger.valueOf(0));
       ppr.setSpacing(pprbase);
      
       R run = factory.createR();
       run.getRunContent().add(RPr);
       pgnum.getParagraphContent().add(run);

       JAXBElement<CTSimpleField> fldSimple = factory.createPFldSimple(pgnum);
       P para = factory.createP();
       para.getParagraphContent().add(fldSimple);
       para.setPPr(ppr);   
       // Now add our paragraph to the footer
       Ftr ftr = factory.createFtr();
       ftr.getEGBlockLevelElts().add(para);
       ftr.getEGBlockLevelElts().add(newImage(wordprocessingMLPackage, sourcePart, getBytes("Footer2"), "filename", "alttext", 1, 2, "Footer"));
      return ftr; 
   }
   public static Relationship createHeaderFooterPart(String type) throws Exception
   {
      if(type.equalsIgnoreCase("Header")){
         HeaderPart headerPart = new HeaderPart();
         // Have to do this so that the next line can add an image
         headerPart.setPackage(outputdoc);
         headerPart.setJaxbElement(getHdr(outputdoc, headerPart));
         return outputdoc.getMainDocumentPart().addTargetPart(headerPart);
      } else if(type.equalsIgnoreCase("Footer")){
         FooterPart footerPart = new FooterPart();
         // Have to do this so that the next line can add an image
         footerPart.setPackage(outputdoc);
         footerPart.setJaxbElement(getFtr(outputdoc, footerPart));
         return outputdoc.getMainDocumentPart().addTargetPart(footerPart);
      } else {
         return new Relationship();
      }
   }
   public static void createHeaderFooterReference(String type, Relationship relationship) throws InvalidFormatException
   {
      List<SectionWrapper> sections = outputdoc.getDocumentModel().getSections();
      SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
      // There is always a section wrapper, but it might not contain a sectPr
      if (sectPr==null ) {
         sectPr = factory.createSectPr();
         outputdoc.getMainDocumentPart().addObject(sectPr);
            sections.get(sections.size() - 1).setSectPr(sectPr);
        }

      if(type.equalsIgnoreCase("Header")) {
         HeaderReference headerReference = factory.createHeaderReference();
         headerReference.setId(relationship.getId());
         headerReference.setType(HdrFtrRef.DEFAULT); //only on firstpage... this is not working right now.....
         sectPr.getEGHdrFtrReferences().add(headerReference);// add header or footer references
      } else if(type.equalsIgnoreCase("Footer")) {
         FooterReference footerReference = factory.createFooterReference();
         footerReference.setId(relationship.getId());
         footerReference.setType(HdrFtrRef.DEFAULT); //only on firstpage... this is not working right now.....
         sectPr.getEGHdrFtrReferences().add(footerReference);// add header or footer references
      }
   }

   
   
   public void printHeader(String title, String subTitle, String customerName, String timestamp, Vector<String> parameters)//SORT OF DONE
   {
                                WordprocessingMLPackage outputdoc = new WordprocessingMLPackage();
      MainDocumentPart mainDocumentPart = outputdoc.getMainDocumentPart();
      try {
         Relationship relationship = createHeaderFooterPart("Header");
         createHeaderFooterReference("Header", relationship);
      } catch (Exception e) {
         e.printStackTrace();
      }
      
}
      }

Re: Footer image and page Numbers

PostPosted: Tue May 17, 2011 7:44 pm
by jason
In your working example, you have:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
        <w:drawing>
          <wp:anchor distT="0" distB="0" distL="114300" distR="114300" simplePos="0" relativeHeight="251658240" behindDoc="1" locked="0" layoutInCell="1" allowOverlap="1">
            <wp:simplePos x="0" y="0"/>
            <wp:positionH relativeFrom="column">
              <wp:posOffset>19050</wp:posOffset>
            </wp:positionH>
            <wp:positionV relativeFrom="paragraph">
              <wp:posOffset>141605</wp:posOffset>
            </wp:positionV>
 
Parsed in 0.001 seconds, using GeSHi 1.0.8.4


Per the spec:
drawing objects can exist in two states:

Inline - The drawing object is in line with the text, and affects the line height and layout of its line (like a character glyph of similar size).

Floating - The drawing object is anchored within the text, but can be absolutely positioned in the document relative to the page.


You need this floating type (ie wp:anchor), with @behindDoc="1", and

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting

            <wp:positionV relativeFrom="paragraph">
              <wp:posOffset>141605</wp:posOffset>
            </wp:positionV>
 
Parsed in 0.000 seconds, using GeSHi 1.0.8.4


The language is a bit confusing; both wp:inline and wp:anchor images can be linked or embedded; that is controlled by whether a:blip has a @r:embed or @r:link.

docx4j's BinaryPartAbstractImage class only creates wp:inline images (as opposed to wp:anchor images). This would be worth enhancing.

In the absence of that, you can create the wp:anchor in several ways; the easiest might be using XmlUtils.unmarshalString or unmarshallFromTemplate (which is what BinaryPartAbstractImage does for wp:inline).

Re: Footer image and page Numbers

PostPosted: Sat Sep 29, 2012 2:29 pm
by tstirrat
You may find this useful.

The xml contents of an inline element are similar to a lot of the elements inside an anchor element. The anchor contains those, and goes on to specify extra positional information.

So, rather than create an anchor from scratch, I used createImageInline to create an inline object and then marshall/unmarshalled this object into an anchor object. From here I can add the positional parameters.

Code: Select all
    BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, sourcePart, bytes);

    Inline inline = imagePart.createImageInline(filenameHint, altText, id1, id2, false);

    // convert the inline to an anchor (xml contents are essentially the same)
    String anchorXml = XmlUtils.marshaltoString(inline, true, false, Context.jc, Namespaces.NS_WORD12, "anchor",
        Inline.class);

    org.docx4j.dml.ObjectFactory dmlFactory = new org.docx4j.dml.ObjectFactory();
    org.docx4j.dml.wordprocessingDrawing.ObjectFactory wordDmlFactory = new org.docx4j.dml.wordprocessingDrawing.ObjectFactory();

    Anchor anchor = (Anchor) XmlUtils.unmarshalString(anchorXml, Context.jc, Anchor.class);
    anchor.setSimplePos(dmlFactory.createCTPoint2D());
    anchor.getSimplePos().setX(0L);
    anchor.getSimplePos().setY(0L);
    anchor.setSimplePosAttr(false);
    anchor.setPositionH(wordDmlFactory.createCTPosH());
    anchor.getPositionH().setAlign(STAlignH.RIGHT);
    anchor.getPositionH().setRelativeFrom(STRelFromH.MARGIN);
    anchor.setPositionV(wordDmlFactory.createCTPosV());
    anchor.getPositionV().setPosOffset(HEADER_TOP_OFFSET);
    anchor.getPositionV().setRelativeFrom(STRelFromV.PAGE);
    anchor.setWrapNone(wordDmlFactory.createCTWrapNone());

    // Now add the inline in w:p/w:r/w:drawing
    org.docx4j.wml.Drawing drawing = getObjectFactory().createDrawing();
    R run = getObjectFactory().createR();
    run.getContent().add(drawing);

    drawing.getAnchorOrInline().add(anchor);
   
    return run;


Note: from memory, I needed to specify the simple pos coordinates, even though I disabled simple pos via setSimplePosAttr(false)/

Hope this makes it simpler.