Page 1 of 1

Examples of code for creating a new shape and adding slides

PostPosted: Sun Aug 01, 2010 11:16 am
by stu
First, let me start by saying, WOW! what a great library! I have been looking for something exactly like docx4j for over a year and I am so glad I finally found it!!
You have done a wonderful job, please keep going!!

Does anyone have any additional example code of adding simple shapes and text to a slide and then adding that slide to a presentation package??
I get the example that is provided with the code to work just fine. But it is a bit cumbersome to figure out exactly what all needs to be added explicitly versus relying on defaults in the docx4j library.
Below is what I have done this afternoon to add a single shape to the existing slide and shape in the example.
It saves out the presentation well enough, but I am still not quite to the point where PowerPoint 2007 will successfully open and show the shapes. ATM, I just get a blank slide and the message about the file being corrupted (meaning that something is still missing).
Thanks for any suggestions in advance!!


Code: Select all
    public static void make() throws Exception {
        // Where will we save our new .ppxt?
        String outputfilepath = System.getProperty("user.dir") + "/sample-docs/pptx-ags-test2.pptx";

        // Create skeletal package
        PresentationMLPackage presentationMLPackage = PresentationMLPackage.createPackage();

        // It contains a first slide; get it ..
        // TODO - add convenience methods?
        SlidePart slidePart = (SlidePart) presentationMLPackage.getParts().getParts().get(
                new PartName("/ppt/slides/slide1.xml"));

        // Create and add shape
        Shape sample = ((Shape) XmlUtils.unmarshalString(SAMPLE_SHAPE, Context.jcPML));
        slidePart.getJaxbElement().getCSld().getSpTree().getSpOrGrpSpOrGraphicFrame().add(sample);
        // Add new shape to slide from scratch ...
        List<Object> sldPart = slidePart.getJaxbElement().getCSld().getSpTree().getSpOrGrpSpOrGraphicFrame();
        // create a new shape and set its properties and contents
        Shape scratch = new Shape();
        scratch.setNvSpPr(new NvSpPr());
        scratch.getNvSpPr().setCNvPr(new CTNonVisualDrawingProps());
        scratch.getNvSpPr().getCNvPr().setId(2);
        scratch.getNvSpPr().getCNvPr().setName("roundrect2");
        scratch.getNvSpPr().setCNvSpPr(new CTNonVisualDrawingShapeProps());
        scratch.getNvSpPr().setNvPr(new NvPr());
        CTShapeProperties ctSP = new CTShapeProperties(); 
        CTPresetGeometry2D prg = new CTPresetGeometry2D();
        prg.setPrst(STShapeType.ROUND_RECT);
        prg.setAvLst(new CTGeomGuideList());
        ctSP.setPrstGeom(prg);
        ctSP.setXfrm(new CTTransform2D());
        ctSP.getXfrm().setOff(new CTPoint2D());
        ctSP.getXfrm().getOff().setX(1255000);
        ctSP.getXfrm().getOff().setY(1255000);
        ctSP.getXfrm().setExt(new CTPositiveSize2D());
        ctSP.getXfrm().getExt().setCx(1155000);
        ctSP.getXfrm().getExt().setCy(1155000);
        ctSP.setNoFill(new CTNoFillProperties());
        scratch.setSpPr(ctSP);
        CTTextBody ctTB = new CTTextBody();
        ctTB.setLstStyle(new CTTextListStyle());
        List<CTTextParagraph> p = ctTB.getP();
        CTTextParagraph ctTP = new CTTextParagraph();
        List<Object> eGTextRun = ctTP.getEGTextRun();
        eGTextRun.add("Example text run in round rect");
        scratch.setTxBody(ctTB);
        scratch.setStyle(new CTShapeStyle());
        scratch.getStyle().setLnRef(new CTStyleMatrixReference());
        scratch.getStyle().getLnRef().setSchemeClr(new CTSchemeColor());
        scratch.getStyle().setFillRef(new CTStyleMatrixReference());
        sldPart.add(scratch);

        // All done: save it
        presentationMLPackage.save(new java.io.File(outputfilepath));

        System.out.println("\n\n done .. saved " + outputfilepath);
    }
    private static String SAMPLE_SHAPE =
            "<p:sp   xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:p=\"http://schemas.openxmlformats.org/presentationml/2006/main\">" +
            "<p:nvSpPr>" +
            "<p:cNvPr id=\"4\" name=\"Title 3\" />" +
                "<p:cNvSpPr>" +
                "<a:spLocks noGrp=\"1\" />" +
                "</p:cNvSpPr>" +
                    "<p:nvPr>" +
                    "<p:ph type=\"title\" />" +
                    "</p:nvPr>" +
                "</p:nvSpPr>" +
            "<p:spPr />" +
                "<p:txBody>" +
                    "<a:bodyPr />" +
                    "<a:lstStyle />" +
                    "<a:p>" +
                        "<a:r>" +
                        "<a:rPr lang=\"en-US\" smtClean=\"0\" />" +
                        "<a:t>Hello World</a:t>" +
                        "</a:r>" +
                    "<a:endParaRPr lang=\"en-US\" />" +
                    "</a:p>" +
                "</p:txBody>" +
            "</p:sp>";
}

Re: Examples of code for creating a new shape and adding slides

PostPosted: Sun Aug 01, 2010 2:16 pm
by stu
:D

With enough hunting and pecking, I finally got it working to add a shape to the existing slide. Here is the code that worked. BTW, building a slide in PowerPoint that looked the way I want it to, then building each element step-by-step to match was the approach that finally got it working.

Code: Select all
    public static void make() throws Exception {
        // Where will we save our new .ppxt?
        String outputfilepath = System.getProperty("user.dir") + "/sample-docs/pptx-ags-test2.pptx";

        // Create skeletal package
        PresentationMLPackage presentationMLPackage = PresentationMLPackage.createPackage();

        // It contains a first slide; get it ..
        // TODO - add convenience methods?
        SlidePart slidePart = (SlidePart) presentationMLPackage.getParts().getParts().get(
                new PartName("/ppt/slides/slide1.xml"));

        // Create and add shape
        Shape sample = ((Shape) XmlUtils.unmarshalString(SAMPLE_SHAPE, Context.jcPML));
        slidePart.getJaxbElement().getCSld().getSpTree().getSpOrGrpSpOrGraphicFrame().add(sample);
        // Add new shape to slide from scratch ...
        List<Object> listOfSpGrpSpEtc = slidePart.getJaxbElement().getCSld().getSpTree().getSpOrGrpSpOrGraphicFrame();
        // create a new shape and set its properties and contents
        Shape scratch = new Shape();
        scratch.setNvSpPr(new NvSpPr());
        scratch.getNvSpPr().setCNvPr(new CTNonVisualDrawingProps());
        scratch.getNvSpPr().getCNvPr().setId(5);
        scratch.getNvSpPr().getCNvPr().setName("roundrect2");
        scratch.getNvSpPr().setCNvSpPr(new CTNonVisualDrawingShapeProps());
        scratch.getNvSpPr().setNvPr(new NvPr());
        CTShapeProperties ctSP = new CTShapeProperties();  //
        CTPresetGeometry2D prg = new CTPresetGeometry2D();
        prg.setPrst(STShapeType.ROUND_RECT);
        prg.setAvLst(new CTGeomGuideList());
        ctSP.setPrstGeom(prg);
        ctSP.setXfrm(new CTTransform2D());
        ctSP.getXfrm().setOff(new CTPoint2D());
        ctSP.getXfrm().getOff().setX(1255000);
        ctSP.getXfrm().getOff().setY(1255000);
        ctSP.getXfrm().setExt(new CTPositiveSize2D());
        ctSP.getXfrm().getExt().setCx(1155000);
        ctSP.getXfrm().getExt().setCy(1155000);
        ctSP.setNoFill(new CTNoFillProperties());
        scratch.setSpPr(ctSP);
        CTTextBody ctTB = new CTTextBody();
        ctTB.setBodyPr(new CTTextBodyProperties());
        ctTB.getBodyPr().setRtlCol(Boolean.TRUE);
        ctTB.getBodyPr().setAnchor(STTextAnchoringType.CTR);
        ctTB.setLstStyle(new CTTextListStyle());
        List<CTTextParagraph> p = ctTB.getP();
        CTTextParagraph ctTP = new CTTextParagraph();
        ctTP.setPPr(new CTTextParagraphProperties());
        ctTP.getPPr().setAlgn(STTextAlignType.L);
        CTRegularTextRun ctRTR = new CTRegularTextRun();
        ctRTR.setRPr(new CTTextCharacterProperties());
        ctRTR.getRPr().setLang("en-US");
        ctRTR.getRPr().setDirty(Boolean.TRUE);
        ctRTR.getRPr().setErr(Boolean.FALSE);
        ctRTR.getRPr().setSmtClean(Boolean.TRUE);
        ctRTR.getRPr().setSolidFill(new CTSolidColorFillProperties());
        ctRTR.getRPr().getSolidFill().setSchemeClr(new CTSchemeColor());
        ctRTR.getRPr().getSolidFill().getSchemeClr().setVal(STSchemeColorVal.TX_1);
        ctRTR.setT("Example text run in round rect");
        ctTP.getEGTextRun().add(ctRTR);
        ctTP.setEndParaRPr(new CTTextCharacterProperties());
        ctTP.getEndParaRPr().setLang("en-US");
        ctTP.getEndParaRPr().setDirty(Boolean.TRUE);
        ctTP.getEndParaRPr().setSolidFill(new CTSolidColorFillProperties());
        ctTP.getEndParaRPr().getSolidFill().setSchemeClr(new CTSchemeColor());
        ctTP.getEndParaRPr().getSolidFill().getSchemeClr().setVal(STSchemeColorVal.TX_1);
        p.add(ctTP);
        scratch.setTxBody(ctTB);
        scratch.setStyle(new CTShapeStyle());
        scratch.getStyle().setLnRef(new CTStyleMatrixReference());
        scratch.getStyle().getLnRef().setIdx(2);
        scratch.getStyle().getLnRef().setSchemeClr(new CTSchemeColor());
        scratch.getStyle().getLnRef().getSchemeClr().setVal(STSchemeColorVal.TX_1);
        scratch.getStyle().setFillRef(new CTStyleMatrixReference());
        scratch.getStyle().getFillRef().setIdx(1);
        scratch.getStyle().getFillRef().setSchemeClr(new CTSchemeColor());
        scratch.getStyle().getFillRef().getSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
        scratch.getStyle().setEffectRef(new CTStyleMatrixReference());
        scratch.getStyle().getEffectRef().setIdx(0);
        scratch.getStyle().getEffectRef().setSchemeClr(new CTSchemeColor());
        scratch.getStyle().getEffectRef().getSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
        scratch.getStyle().setFontRef(new CTFontReference());
        scratch.getStyle().getFontRef().setIdx(STFontCollectionIndex.MINOR);
        scratch.getStyle().getEffectRef().setSchemeClr(new CTSchemeColor());
        scratch.getStyle().getEffectRef().getSchemeClr().setVal(STSchemeColorVal.LT_1);
        listOfSpGrpSpEtc.add(scratch);

        // All done: save it
        presentationMLPackage.save(new java.io.File(outputfilepath));

        System.out.println("\n\n done .. saved " + outputfilepath);
    }

Re: Examples of code for creating a new shape and adding slides

PostPosted: Sun Aug 01, 2010 10:34 pm
by jason
Hi

2 suggestions.

First, the code for adding a slide may be found in the method:

Code: Select all
   public static PresentationMLPackage createPackage() throws InvalidFormatException {
            
      // Create a package
      PresentationMLPackage pmlPack = new PresentationMLPackage();

      // Presentation part
      MainPresentationPart pp;
      try {
         
         pp = new MainPresentationPart();
         pp.setJaxbElement(MainPresentationPart.createJaxbPresentationElement() );
         pmlPack.addTargetPart(pp);      
         
         // Slide part
         SlidePart slidePart = new SlidePart();
         pp.addSlideIdListEntry(slidePart);

         slidePart.setJaxbElement( SlidePart.createSld() );
         
         // Slide layout part
         SlideLayoutPart layoutPart = new SlideLayoutPart();
         layoutPart.setJaxbElement( SlideLayoutPart.createSldLayout() );
         
         slidePart.addTargetPart(layoutPart);
         
         // Slide Master part
         SlideMasterPart masterPart = new SlideMasterPart();
         pp.addSlideMasterIdListEntry(masterPart);

         masterPart.setJaxbElement(masterPart.createSldMaster() );
         masterPart.addSlideLayoutIdListEntry(layoutPart);
         
         layoutPart.addTargetPart(masterPart);
         
         // Theme part
         ThemePart themePart = new ThemePart(new PartName("/ppt/theme/theme1.xml"));
         java.io.InputStream is = org.docx4j.utils.ResourceUtils.getResource(
                  "org/docx4j/openpackaging/parts/PresentationML/theme.xml");
         themePart.unmarshal(is);
         
         // .. add it in 2 places ..
         masterPart.addTargetPart(themePart);
         pp.addTargetPart(themePart);
         
         
      } catch (Exception e) {
         e.printStackTrace();
         throw new InvalidFormatException("Couldn't create package", e);
      }

      // Return the new package
      return pmlPack;      
   }


You can see from this that adding a slide involves adding it to the main presentation part, and then setting its layout part, and if this is a new layout part, settings its master part.

Second, you can construct shapes using a sequence of JAXB operations just like you did. Another way is to
Code: Select all
      // Create and add shape
      Shape sample = ((Shape)XmlUtils.unmarshalString(SAMPLE_SHAPE, Context.jcPML) );


Either way, yes, its a good idea to use Powerpoint to create your desired shape, then inspect its XML. Having done this, it is easy to unmarshalString. Don't forget to add the namespace declaration though - see the Getting Started guide for more info.

cheers .. Jason

Re: Examples of code for creating a new shape and adding slides

PostPosted: Mon Aug 02, 2010 1:11 am
by stu
Thanks Jason!
Yes, I see how you did it in the PresentationMLPackage createPackage() method.
I have left something out though, because when I open the presentation, the first slide is blank and the second slide has all the desired shapes on it.
Here is the section where I add the second slide.
Do you see a problem??

Code: Select all
        // Create and add a new slidepart to the presentation package
        // First get Main Presentation Part and add new slide to it
        MainPresentationPart mpPart = (MainPresentationPart) presentationMLPackage.getParts().getParts().get(
                new PartName("/ppt/presentation.xml"));
        // Now create the second slide and add it in two places
        SlidePart slidePart2 = new SlidePart();
        mpPart.addSlideIdListEntry( slidePart2  );
        slidePart2.setJaxbElement( SlidePart.createSld() );
        // Last add the shapes to the second slide
        addShapesToSlide( slidePart2 );


Stu

Re: Examples of code for creating a new shape and adding slides

PostPosted: Mon Aug 02, 2010 2:22 am
by stu
Aha! Looking through the resulting XML shows that the above code doesn't quite work right.
Opening the resulting pptx file in PowerPoint gives one blank slide and one slide as desired.
I will look through the unzipped pptx file to see what the problem is.

[Note: I edited this post because I earlier thought that the code created a second slideLayout part, but not so. That occurred when I used PowerPoint to save as a flat XML file. Now I am looking through the unzipped pptx file instead. I will add to this post as I see the errors in the XML.]
:oops:

Hmmm..... In the slides part, only one slide has been added to the presentation. Maybe this is a naming problem?? Yes, Need to NOT use the default constructor (with no arguments) when making a second slide. Need to use this one instead:
Code: Select all
SlidePart slidePart2 = new SlidePart(new PartName("/ppt/slides/slide2.xml"));


Also, I need to add the target part for relating the slideLayout to the new/second slide as follows:
Code: Select all
   // Get and set slide layout part target
   SlideLayoutPart layoutPart = (SlideLayoutPart) presentationMLPackage.getParts().getParts().get(
                new PartName("/ppt/slideLayouts/slideLayout1.xml"));
   slidePart2.addTargetPart(layoutPart);


With those changes the pptx file opens just fine and shows as desired. Resulting method is:

Code: Select all
    public static void make() throws Exception {
        // Where will we save our new .ppxt?
        String outputfilepath = System.getProperty("user.dir") + "/sample-docs/pptx-ags-test3.pptx";

        // Create skeletal package
        PresentationMLPackage presentationMLPackage = PresentationMLPackage.createPackage();

        // It contains a first slide; get it ..
        // TODO - add convenience methods?
        SlidePart slidePart = (SlidePart) presentationMLPackage.getParts().getParts().get(
                new PartName("/ppt/slides/slide1.xml"));
        addShapesToSlide( slidePart);

        // Create and add a new slidepart to the presentation package
        // First get Main Presentation Part and add new slide to it
        MainPresentationPart mpPart = (MainPresentationPart) presentationMLPackage.getParts().getParts().get(
                new PartName("/ppt/presentation.xml"));
        // Now create the second slide and add it in two places
        SlidePart slidePart2 = new SlidePart(new PartName("/ppt/slides/slide2.xml"));
        mpPart.addSlideIdListEntry( slidePart2  );
        slidePart2.setJaxbElement( SlidePart.createSld() );

   // Get and set slide layout part target
   SlideLayoutPart layoutPart = (SlideLayoutPart) presentationMLPackage.getParts().getParts().get(
                new PartName("/ppt/slideLayouts/slideLayout1.xml"));
   slidePart2.addTargetPart(layoutPart);

        // Last add the shapes to the second slide
        addShapesToSlide( slidePart2 );

        // All done: save it
        presentationMLPackage.save(new java.io.File(outputfilepath));

        System.out.println("\n\n done .. saved " + outputfilepath);
    }