--- src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java (working copy) @@ -401,7 +401,8 @@ _notes = new Notes[notesV.size()]; for(int i=0; i<_notes.length; i++) { _notes[i] = (Notes)notesV.get(i); - + _notes[i].setSlideShow(this); + // Now supply ourselves to all the rich text runs // of this note's TextRuns TextRun[] trs = _notes[i].getTextRuns(); @@ -418,6 +419,7 @@ _slides = new Slide[slidesV.size()]; for(int i=0; i<_slides.length; i++) { _slides[i] = (Slide)slidesV.get(i); + _slides[i].setSlideShow(this); // Now supply ourselves to all the rich text runs // of this slide's TextRuns @@ -474,26 +476,40 @@ /** * Returns all the pictures attached to the SlideShow */ - public PictureData[] getPictures() throws IOException { + public PictureData[] getPictureData() { return _hslfSlideShow.getPictures(); } /** - * Return the current page size + * Return the current page size in points */ public Dimension getPageSize(){ DocumentAtom docatom = _documentRecord.getDocumentAtom(); - return new Dimension((int)docatom.getSlideSizeX(), (int)docatom.getSlideSizeY()); + int pgx = (int)docatom.getSlideSizeX()*Shape.POINT_DPI/Shape.MASTER_DPI; + int pgy = (int)docatom.getSlideSizeY()*Shape.POINT_DPI/Shape.MASTER_DPI; + return new Dimension(pgx, pgy); } - + + /** + * Chage the page size + * + * @param pgsize page size (in points) + */ + public void setPageSize(Dimension pgsize){ + DocumentAtom docatom = _documentRecord.getDocumentAtom(); + docatom.setSlideSizeX(pgsize.width*Shape.MASTER_DPI/Shape.POINT_DPI); + docatom.setSlideSizeY(pgsize.height*Shape.MASTER_DPI/Shape.POINT_DPI); + } + /** * Helper method for usermodel: Get the font collection */ protected FontCollection getFontCollection() { return _fonts; } - /** + + /** * Helper method for usermodel: Get the document record */ - protected Document getDocumentRecord() { return _documentRecord; } + public Document getDocumentRecord() { return _documentRecord; } /* =============================================================== @@ -607,6 +623,7 @@ usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW); // All done and added + slide.setSlideShow(this); return slide; } --- src/scratchpad/src/org/apache/poi/hslf/usermodel/PictureData.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/usermodel/PictureData.java (working copy) @@ -25,6 +25,7 @@ /** * A class that represents the image data contained in the Presentation. + * * * @author Yegor Kozlov */ @@ -35,6 +36,9 @@ */ public static final int HEADER_SIZE = 25; + protected static final int JPEG_HEADER = -266516832; + protected static final int PNG_HEADER = -266441216; + /** * Binary data of the picture */ @@ -118,12 +122,28 @@ */ public void setType(int format){ switch (format){ - case Picture.JPEG: LittleEndian.putInt(header, 0, -266516832); break; - case Picture.PNG: LittleEndian.putInt(header, 0, -266441216); break; + case Picture.JPEG: LittleEndian.putInt(header, 0, PictureData.JPEG_HEADER); break; + case Picture.PNG: LittleEndian.putInt(header, 0, PictureData.PNG_HEADER); break; } } /** + * Returns type of this picture. + * Must be one of the static constans defined in the Picture class. + * + * @return type of this picture. + */ + public int getType(){ + int format = 0; + int val = LittleEndian.getInt(header, 0); + switch (val){ + case PictureData.JPEG_HEADER: format = Picture.JPEG; break; + case PictureData.PNG_HEADER: format = Picture.PNG; break; + } + return format; + } + + /** * Returns the header of the Picture * * @return the header of the Picture --- src/scratchpad/src/org/apache/poi/hslf/model/Shape.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/Shape.java (working copy) @@ -22,15 +22,49 @@ import java.util.Iterator; /** + *

* Represents a Shape which is the elemental object that composes a drawing. + * This class is a wrapper around EscherSpContainer which holds all information + * about a shape in PowerPoint document. + *

+ *

+ * When you add a shape, you usually specify the dimensions of the shape and the position + * of the upper­left corner of the bounding box for the shape relative to the upper­left + * corner of the page, worksheet, or slide. Distances in the drawing layer are measured + * in points (72 points = 1 inch). + *

+ *

* * @author Yegor Kozlov */ public abstract class Shape { + /** + * In Escher absolute distances are specified in + * English Metric Units (EMUs), occasionally referred to as A units; + * there are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point. + */ + public static final int EMU_PER_INCH = 914400; public static final int EMU_PER_POINT = 12700; + public static final int EMU_PER_CENTIMETER = 360000; /** + * Master DPI (576 pixels per inch). + * Used by the reference coordinate system in PowerPoint. + */ + public static final int MASTER_DPI = 576; + + /** + * Pixels DPI (96 pixels per inch) + */ + public static final int PIXEL_DPI = 96; + + /** + * Points DPI (72 pixels per inch) + */ + public static final int POINT_DPI = 72; + + /** * Either EscherSpContainer or EscheSpgrContainer record * which holds information about this shape. */ @@ -43,6 +77,11 @@ protected Shape _parent; /** + * The Sheet this shape belongs to + */ + protected Sheet _sheet; + + /** * Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document. * * @param escherRecord EscherSpContainer container which holds information about this shape @@ -86,25 +125,25 @@ if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID); anchor = new java.awt.Rectangle(); - anchor.x = rec.getDx1(); - anchor.y = rec.getDy1(); - anchor.width = rec.getDx2() - anchor.x; - anchor.height = rec.getDy2() - anchor.y; + anchor.x = rec.getDx1()*POINT_DPI/MASTER_DPI; + anchor.y = rec.getDy1()*POINT_DPI/MASTER_DPI; + anchor.width = (rec.getDx2() - anchor.x)*POINT_DPI/MASTER_DPI; + anchor.height = (rec.getDy2() - anchor.y)*POINT_DPI/MASTER_DPI; } else { EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID); anchor = new java.awt.Rectangle(); - anchor.y = rec.getFlag(); - anchor.x = rec.getCol1(); - anchor.width = rec.getDx1() - anchor.x; - anchor.height = rec.getRow1() - anchor.y; + anchor.y = rec.getFlag()*POINT_DPI/MASTER_DPI; + anchor.x = rec.getCol1()*POINT_DPI/MASTER_DPI; + anchor.width = (rec.getDx1() - rec.getCol1())*POINT_DPI/MASTER_DPI; + anchor.height = (rec.getRow1() - rec.getFlag())*POINT_DPI/MASTER_DPI; } return anchor; } /** * Sets the anchor (the bounding box rectangle) of this shape. - * All coordinates should be expressed in Master units (576 dpi). + * All coordinates should be expressed in poitns (72 dpi). * * @param anchor new anchor */ @@ -113,17 +152,17 @@ int flags = spRecord.getFlags(); if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID); - rec.setDx1(anchor.x); - rec.setDy1(anchor.y); - rec.setDx2(anchor.width + anchor.x); - rec.setDy2(anchor.height + anchor.y); + rec.setDx1(anchor.x*MASTER_DPI/POINT_DPI); + rec.setDy1(anchor.y*MASTER_DPI/POINT_DPI); + rec.setDx2((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI); + rec.setDy2((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI); } else { EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID); - rec.setFlag((short)anchor.y); - rec.setCol1((short)anchor.x); - rec.setDx1((short)(anchor.width + anchor.x)); - rec.setRow1((short)(anchor.height + anchor.y)); + rec.setFlag((short)(anchor.y*MASTER_DPI/POINT_DPI)); + rec.setCol1((short)(anchor.x*MASTER_DPI/POINT_DPI)); + rec.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI)); + rec.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI)); } } @@ -171,11 +210,11 @@ } /** - * Set an escher property in the opt record. + * Set an escher property for this shape. * * @param opt The opt record to set the properties to. * @param propId The id of the property. One of the constants defined in EscherOptRecord. - * @param value value of the property + * @param value value of the property. If value = -1 then the property is removed. */ public static void setEscherProperty(EscherOptRecord opt, short propId, int value){ java.util.List props = opt.getEscherProperties(); @@ -198,4 +237,33 @@ public EscherContainerRecord getSpContainer(){ return _escherContainer; } + + /** + * Event which fires when a shape is inserted in the sheet. + * In some cases we need to propagate changes to upper level containers. + *
+ * Default implementation does nothing. + * + * @param sh - owning shape + */ + protected void afterInsert(Sheet sh){ + + } + + /** + * @return the SlideShow this shape belongs to + */ + public Sheet getSheet(){ + return _sheet; + } + + /** + * Assign the SlideShow this shape belongs to + * + * @param sheet owner of this shape + */ + public void setSheet(Sheet sheet){ + _sheet = sheet; + } + } --- src/scratchpad/src/org/apache/poi/hslf/model/Rectangle.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/Rectangle.java (working copy) @@ -21,39 +21,31 @@ import java.awt.*; /** - * Represents a line in a PowerPoint drawing + * Represents a rectangle shae in a PowerPoint drawing * * @author Yegor Kozlov */ -public class Rectangle extends SimpleShape { +public class Rectangle extends TextBox { protected Rectangle(EscherContainerRecord escherRecord, Shape parent){ super(escherRecord, parent); } public Rectangle(Shape parent){ - super(null, parent); - _escherContainer = createSpContainer(parent instanceof ShapeGroup); + super(parent); } public Rectangle(){ - this(null); + super(); } protected EscherContainerRecord createSpContainer(boolean isChild){ EscherContainerRecord spcont = super.createSpContainer(isChild); - spcont.setOptions((short)15); EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); short type = (ShapeTypes.Rectangle << 4) + 2; spRecord.setOptions(type); - //set default properties for a rectangle - EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); - - opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4)); - opt.sortProperties(); - return spcont; } --- src/scratchpad/src/org/apache/poi/hslf/model/ShapeTypes.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/ShapeTypes.java (working copy) @@ -82,9 +82,9 @@ public static final int Chevron = 55; public static final int Pentagon = 56; public static final int NoSmoking = 57; - public static final int Seal8 = 58; - public static final int Seal16 = 59; - public static final int Seal32 = 60; + public static final int Star8 = 58; + public static final int Star16 = 59; + public static final int Star32 = 60; public static final int WedgeRectCallout = 61; public static final int WedgeRRectCallout = 62; public static final int WedgeEllipseCallout = 63; @@ -116,7 +116,7 @@ public static final int LeftUpArrow = 89; public static final int BentUpArrow = 90; public static final int BentArrow = 91; - public static final int Seal24 = 92; + public static final int Star24 = 92; public static final int StripedRightArrow = 93; public static final int NotchedRightArrow = 94; public static final int BlockArc = 95; @@ -211,7 +211,7 @@ public static final int Moon = 184; public static final int BracketPair = 185; public static final int BracePair = 186; - public static final int Seal4 = 187; + public static final int Star4 = 187; public static final int DoubleWave = 188; public static final int ActionButtonBlank = 189; public static final int ActionButtonHome = 190; --- src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java (working copy) @@ -139,6 +139,34 @@ } public void drawString(String string, float x, float y){ + + TextBox txt = new TextBox(group); + txt.setMarginBottom(0); + txt.setMarginTop(0); + txt.setMarginLeft(0); + txt.setMarginRight(0); + txt.setText(string); + txt.setWordWrap(TextBox.WrapNone); + + if (font != null){ + txt.setFontSize(font.getSize()); + txt.setFontName(font.getName()); + //if(getColor() != null) txt.setFontColor(getColor()); + if (font.isBold()) txt.setBold(true); + if (font.isItalic()) txt.setItalic(true); + } + + txt.resizeToFitText(); + int height = (int)txt.getAnchor().getHeight(); + + /* + In powerpoint anchor of a shape is its top left corner. + Java graphics sets string coordinates by the baseline of the first character + so we need to shift down by the height of the textbox + */ + txt.moveTo((int)x, (int)(y - height)); + + group.addShape(txt); } public void fill(Shape shape){ @@ -212,7 +240,7 @@ } public void drawOval(int x, int y, int width, int height) { - Ellipse ellipse = new Ellipse(); + AutoShape ellipse = new AutoShape(ShapeTypes.Ellipse); ellipse.setAnchor(new java.awt.Rectangle(x-width/2, y-height/2, width, height)); if (stroke instanceof BasicStroke){ BasicStroke bs = (BasicStroke)stroke; --- src/scratchpad/src/org/apache/poi/hslf/model/Line.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/Line.java (working copy) @@ -107,13 +107,12 @@ EscherContainerRecord spcont = super.createSpContainer(isChild); EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); - short type = (ShapeTypes.Line << 4) + 2; + short type = (ShapeTypes.Line << 4) | 0x2; spRecord.setOptions(type); //set default properties for a line EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); - //opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4)); opt.sortProperties(); return spcont; --- src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java (working copy) @@ -23,6 +23,7 @@ import org.apache.poi.ddf.EscherDgRecord; import org.apache.poi.ddf.EscherRecord; import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.SlideShow; import java.util.ArrayList; import java.util.Iterator; @@ -39,6 +40,11 @@ public abstract class Sheet { /** + * The SlideShow this sheet belongs to + */ + private SlideShow _ppt; + + /** * Returns an array of all the TextRuns in the sheet. */ public abstract TextRun[] getTextRuns(); @@ -60,7 +66,7 @@ */ protected abstract PPDrawing getPPDrawing(); - /** + /** * For a given PPDrawing, grab all the TextRuns */ public static TextRun[] findTextRuns(PPDrawing ppdrawing) { @@ -140,8 +146,8 @@ for (Iterator it = ch.iterator(); it.hasNext();) { EscherRecord rec = (EscherRecord)it.next(); if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){ - spgr = (EscherContainerRecord)rec; - break; + spgr = (EscherContainerRecord)rec; + break; } } ch = spgr.getChildRecords(); @@ -149,7 +155,9 @@ ArrayList shapes = new ArrayList(); for (int i=1;iSlideShow
this sheet belongs to + */ + public SlideShow getSlideShow(){ + return _ppt; + } + + /** + * Assign the SlideShow this sheet belongs to + * + * @param ppt owner of this slide + */ + public void setSlideShow(SlideShow ppt){ + _ppt = ppt; + } + +} --- src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java (working copy) @@ -25,6 +25,9 @@ */ public class ShapeFactory { + /** + * Create a new shape from the data provided. + */ public static Shape createShape(EscherContainerRecord spContainer, Shape parent){ if (spContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){ return new ShapeGroup(spContainer, parent); @@ -36,6 +39,8 @@ int type = spRecord.getOptions() >> 4; switch (type){ case ShapeTypes.TextBox: + shape = new TextBox(spContainer, parent); + break; case ShapeTypes.Rectangle: shape = new Rectangle(spContainer, parent); break; @@ -45,14 +50,11 @@ case ShapeTypes.Line: shape = new Line(spContainer, parent); break; - case ShapeTypes.Ellipse: - shape = new Ellipse(spContainer, parent); - break; case ShapeTypes.NotPrimitive: shape = new ShapeGroup(spContainer, parent); break; default: - shape = new SimpleShape(spContainer, parent); + shape = new AutoShape(spContainer, parent); break; } return shape; --- src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java (working copy) @@ -273,8 +273,8 @@ TextPropCollection pCol = (TextPropCollection)pStyles.getFirst(); TextPropCollection cCol = (TextPropCollection)cStyles.getFirst(); - pCol.updateTextSize(s.length()); - cCol.updateTextSize(s.length()); + pCol.updateTextSize(s.length()+1); + cCol.updateTextSize(s.length()+1); // Recreate rich text run with first styling _rtRuns[0] = new RichTextRun(this,0,s.length(), pCol, cCol); --- src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java (working copy) @@ -29,6 +29,12 @@ */ public class SimpleShape extends Shape { + /** + * Create a SimpleShape object and initialize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ protected SimpleShape(EscherContainerRecord escherRecord, Shape parent){ super(escherRecord, parent); } @@ -102,12 +108,12 @@ } /** - * @return color of the line + * @return color of the line. If color is not set returns java.awt.Color.black */ public Color getLineColor(){ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); EscherRGBProperty prop = (EscherRGBProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__COLOR); - Color color = null; + Color color = Color.black; if (prop != null){ Color swp = new Color(prop.getRgbColor()); color = new Color(swp.getBlue(), swp.getGreen(), swp.getRed()); @@ -136,6 +142,11 @@ return prop == null ? Line.LineSolid : prop.getPropertyValue(); } + /** + * The color used to fill this shape. + * + * @param color the background color + */ public void setFillColor(Color color){ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); --- src/scratchpad/src/org/apache/poi/hslf/model/Picture.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/Picture.java (working copy) @@ -3,11 +3,14 @@ import org.apache.poi.ddf.*; import org.apache.poi.hslf.usermodel.PictureData; import org.apache.poi.hslf.usermodel.SlideShow; +import org.apache.poi.hslf.record.Document; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.List; +import java.util.Arrays; /** @@ -122,16 +125,49 @@ } /** - * Set default size of the picture + * Resize this picture to the default size. + */ + public void setDefaultSize(){ + PictureData pict = getPictureData(); + try { + BufferedImage img = ImageIO.read(new ByteArrayInputStream(pict.getData())); + setAnchor(new java.awt.Rectangle(0, 0, img.getWidth(), img.getHeight())); + } catch (IOException e){ + throw new RuntimeException(e); + } + } + + /** + * Returns the picture data for this picture. * - * @param ppt presentation which holds the picture + * @return the picture data for this picture. */ - public void setDefaultSize(SlideShow ppt) throws IOException { - int idx = getPictureIndex(); + public PictureData getPictureData(){ + SlideShow ppt = getSheet().getSlideShow(); + PictureData[] pict = ppt.getPictureData(); + Document doc = ppt.getDocumentRecord(); + EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); + EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); - PictureData pict = ppt.getPictures()[idx-1]; - BufferedImage img = ImageIO.read(new ByteArrayInputStream(pict.getData())); + List lst = bstore.getChildRecords(); + int idx = getPictureIndex()-1; + EscherBSERecord bse = (EscherBSERecord)lst.get(idx); + for ( int i = 0; i < pict.length; i++ ) { + if (Arrays.equals(bse.getUid(), pict[i].getUID())){ + return pict[i]; + } + } + return null; + } - setAnchor(new java.awt.Rectangle(0, 0, img.getWidth()*6, img.getHeight()*6)); + /** + * By default set the orininal image size + */ + protected void afterInsert(Sheet sh){ + java.awt.Rectangle anchor = getAnchor(); + if (anchor.equals(new java.awt.Rectangle())){ + setDefaultSize(); + } } + } --- src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java (working copy) @@ -27,11 +27,21 @@ */ public class ShapeGroup extends Shape{ + /** + * Create a new ShapeGroup. This constructor is used when a new shape is created. + * + */ public ShapeGroup(){ this(null, null); _escherContainer = createSpContainer(false); } + /** + * Create a ShapeGroup object and initilize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ protected ShapeGroup(EscherContainerRecord escherRecord, Shape parent){ super(escherRecord, parent); } --- src/scratchpad/src/org/apache/poi/hslf/record/TextBytesAtom.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/record/TextBytesAtom.java (working copy) @@ -56,7 +56,16 @@ /* *************** record code follows ********************** */ - /** + public TextBytesAtom(){ + _header = new byte[8]; + LittleEndian.putUShort(_header, 0, 0); + LittleEndian.putUShort(_header, 2, (int)_type); + LittleEndian.putInt(_header, 4, 0); + + _text = new byte[]{}; + } + + /** * For the TextBytes Atom */ protected TextBytesAtom(byte[] source, int start, int len) { --- src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java (working copy) @@ -128,6 +128,28 @@ /* *************** record code follows ********************** */ + /** + * Construct a new StyleTextPropAtom record + */ + public StyleTextPropAtom(){ + _header = new byte[8]; + LittleEndian.putUShort(_header, 0, 0); + LittleEndian.putUShort(_header, 2, (int)_type); + LittleEndian.putInt(_header, 4, 20); + + rawContents = new byte[]{}; + reserved = new byte[]{}; + + // Set empty linked lists, ready for when they call setParentTextSize + TextPropCollection defaultParagraphTextProps = new TextPropCollection(0, (short)0); + paragraphStyles = new LinkedList(); + paragraphStyles.add(defaultParagraphTextProps); + + TextPropCollection defaultCharacterTextProps = new TextPropCollection(0); + charStyles = new LinkedList(); + charStyles.add(defaultCharacterTextProps); + } + /** * For the Text Style Properties (StyleTextProp) Atom */ --- src/scratchpad/src/org/apache/poi/hslf/record/EscherTextboxWrapper.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/record/EscherTextboxWrapper.java (working copy) @@ -19,6 +19,7 @@ package org.apache.poi.hslf.record; import org.apache.poi.ddf.*; +import org.apache.poi.util.LittleEndian; import java.io.IOException; import java.io.OutputStream; @@ -44,10 +45,19 @@ */ public EscherTextboxRecord getEscherRecord() { return _escherRecord; } + public EscherTextboxWrapper(){ + _escherRecord = new EscherTextboxRecord(); + _escherRecord.setRecordId(EscherTextboxRecord.RECORD_ID); + _escherRecord.setOptions((short)15); + + _children = new Record[]{ + }; + } + /** * Creates the wrapper for the given DDF Escher Record and children */ - protected EscherTextboxWrapper(EscherTextboxRecord textbox) { + public EscherTextboxWrapper(EscherTextboxRecord textbox) { _escherRecord = textbox; _type = (long)_escherRecord.getRecordId(); --- src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java (working copy) @@ -262,4 +262,16 @@ dgContainer }; } + + /** + * If we add a new EscherTextbox we need to tell + * about it to the owning PPDrawing. + */ + public void addTextboxWrapper(EscherTextboxWrapper txtbox){ + EscherTextboxWrapper[] tw = new EscherTextboxWrapper[textboxWrappers.length + 1]; + System.arraycopy(textboxWrappers, 0, tw, 0, textboxWrappers.length); + tw[textboxWrappers.length] = txtbox; + textboxWrappers = tw; + } + } --- src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java (revision 392681) +++ src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java (working copy) @@ -56,7 +56,19 @@ /* *************** record code follows ********************** */ - /** + /** + * Construct a new TextHeaderAtom record + */ + public TextHeaderAtom(){ + _header = new byte[8]; + LittleEndian.putUShort(_header, 0, 0); + LittleEndian.putUShort(_header, 2, (int)_type); + LittleEndian.putInt(_header, 4, 4); + + textType = OTHER_TYPE; + } + + /** * For the TextHeader Atom */ protected TextHeaderAtom(byte[] source, int start, int len) { --- src/scratchpad/testcases/org/apache/poi/TestPOIDocument.java (revision 392681) +++ src/scratchpad/testcases/org/apache/poi/TestPOIDocument.java (working copy) @@ -57,7 +57,7 @@ FileInputStream fisHWPF = new FileInputStream(filenameHWPF); pfs2 = new POIFSFileSystem(fisHWPF); - doc2 = new HWPFDocument(pfs2); + //doc2 = new HWPFDocument(pfs2); } public void testReadProperties() throws Exception { --- src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java (revision 392681) +++ src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java (working copy) @@ -50,10 +50,37 @@ BufferedImage img = ImageIO.read(new ByteArrayInputStream(data)); assertNotNull(img); + assertEquals(Picture.PNG, pict[i].getType()); } ppt.close(); } + public void testReadPicturesForSlide() throws Exception { + + SlideShow ppt = new SlideShow(new HSLFSlideShow(filename)); + + Slide[] slide = ppt.getSlides(); + for (int i = 0; i < slide.length; i++) { + Slide sl = slide[i]; + Shape[] sh = sl.getShapes(); + for (int j = 0; j < sh.length; j++) { + Shape shape = sh[j]; + if (shape instanceof Picture){ + Picture picture = (Picture)shape; + + PictureData pictdata = picture.getPictureData(); + assertEquals(Picture.PNG, pictdata.getType()); + + //raw data. + byte[] data = pictdata.getData(); + BufferedImage img = ImageIO.read(new ByteArrayInputStream(data)); + assertNotNull(img); + } + } + + } + } + public void testSerializePictures() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(filename); PictureData[] pict = ppt.getPictures(); @@ -78,12 +105,10 @@ idx = ppt.addPicture(new File(dirname + "/clock.jpg"), Picture.JPEG); slide = ppt.createSlide(); pict = new Picture(idx); - pict.setDefaultSize(ppt); slide.addShape(pict); idx = ppt.addPicture(new File(dirname + "/painting.png"), Picture.PNG); pict = new Picture(idx); - pict.setDefaultSize(ppt); slide.addShape(pict); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -91,7 +116,7 @@ out.close(); ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()))); - assertTrue(ppt.getPictures().length == 2 ); + assertTrue(ppt.getPictureData().length == 2 ); } } --- src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java (revision 392681) +++ src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java (working copy) @@ -17,12 +17,14 @@ import junit.framework.TestCase; import org.apache.poi.hslf.usermodel.SlideShow; +import org.apache.poi.hslf.usermodel.RichTextRun; import org.apache.poi.hslf.HSLFSlideShow; import java.awt.*; import java.awt.Rectangle; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; +import java.io.FileOutputStream; /** * Test drawing shapes via Graphics2D @@ -36,21 +38,23 @@ String dirname = System.getProperty("HSLF.testdata.path"); String filename = dirname + "/empty.ppt"; ppt = new SlideShow(new HSLFSlideShow(filename)); - getClass().getResourceAsStream(""); } public void testGraphics() throws Exception { Slide slide = ppt.createSlide(); Line line = new Line(); - line.setAnchor(new Rectangle(1296, 2544, 1344, 528)); + java.awt.Rectangle lineAnchor = new java.awt.Rectangle(100, 200, 50, 60); + line.setAnchor(lineAnchor); + System.out.println(line.getAnchor()); line.setLineWidth(3); line.setLineStyle(Line.LineDashSys); line.setLineColor(Color.red); slide.addShape(line); - Ellipse ellipse = new Ellipse(); - ellipse.setAnchor(new Rectangle(4000, 1000, 1000, 1000)); + AutoShape ellipse = new AutoShape(ShapeTypes.Ellipse); + java.awt.Rectangle ellipseAnchor = new Rectangle(320, 154, 55, 111); + ellipse.setAnchor(ellipseAnchor); ellipse.setLineWidth(2); ellipse.setLineStyle(Line.LineSolid); ellipse.setLineColor(Color.green); @@ -64,17 +68,103 @@ //read ppt from byte array ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()))); - assertEquals(ppt.getSlides().length, 1); + assertEquals(1, ppt.getSlides().length); slide = ppt.getSlides()[0]; Shape[] shape = slide.getShapes(); - assertEquals(shape.length, 2); + assertEquals(2, shape.length); assertTrue(shape[0] instanceof Line); //group shape - assertEquals(shape[0].getAnchor(), new Rectangle(1296, 2544, 1344, 528)); //group shape + assertEquals(lineAnchor, shape[0].getAnchor()); //group shape - assertTrue(shape[1] instanceof Ellipse); //group shape - assertEquals(shape[1].getAnchor(), new Rectangle(4000, 1000, 1000, 1000)); //group shape + assertTrue(shape[1] instanceof AutoShape); //group shape + assertEquals(ellipseAnchor, shape[1].getAnchor()); //group shape } + /** + * Verify that we can read TextBox shapes + * @throws Exception + */ + public void testTextBoxRead() throws Exception { + String dirname = System.getProperty("HSLF.testdata.path"); + String filename = dirname + "/with_textbox.ppt"; + ppt = new SlideShow(new HSLFSlideShow(filename)); + Slide sl = ppt.getSlides()[0]; + Shape[] sh = sl.getShapes(); + for (int i = 0; i < sh.length; i++) { + assertTrue(sh[i] instanceof TextBox); + TextBox txtbox = (TextBox)sh[i]; + String text = txtbox.getText(); + assertNotNull(text); + + assertEquals(txtbox.getRichTextRuns().length, 1); + RichTextRun rt = txtbox.getRichTextRuns()[0]; + + if (text.equals("Hello, World!!!")){ + assertEquals(32, rt.getFontSize()); + assertTrue(rt.isBold()); + assertTrue(rt.isItalic()); + } else if (text.equals("I am just a poor boy")){ + assertEquals(44, rt.getFontSize()); + assertTrue(rt.isBold()); + } else if (text.equals("This is Times New Roman")){ + assertEquals(16, rt.getFontSize()); + assertTrue(rt.isBold()); + assertTrue(rt.isItalic()); + assertTrue(rt.isUnderlined()); + } else if (text.equals("Plain Text")){ + assertEquals(18, rt.getFontSize()); + } + } + } + + /** + * Verify that we can add TextBox shapes to a slide + * @throws Exception + */ + public void testTextBoxWrite() throws Exception { + ppt = new SlideShow(); + Slide sl = ppt.createSlide(); + + TextBox txtbox = new TextBox(); + txtbox.setText("Hello, World!"); + txtbox.setFontSize(42); + txtbox.setBold(true); + txtbox.setItalic(true); + + sl.addShape(txtbox); + + txtbox = new TextBox(); + txtbox.setText("Plain text in default font"); + sl.addShape(txtbox); + + assertEquals(sl.getShapes().length, 2); + + //serialize and read again + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ppt.write(out); + out.close(); + + ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()))); + sl = ppt.getSlides()[0]; + assertEquals(sl.getShapes().length, 2); + + Shape[] sh = sl.getShapes(); + for (int i = 0; i < sh.length; i++) { + assertTrue(sh[i] instanceof TextBox); + txtbox = (TextBox)sh[i]; + String text = txtbox.getText(); + assertNotNull(text); + + assertEquals(txtbox.getRichTextRuns().length, 1); + RichTextRun rt = txtbox.getRichTextRuns()[0]; + + if (text.equals("Hello, World!")){ + assertEquals(42, rt.getFontSize()); + assertTrue(rt.isBold()); + assertTrue(rt.isItalic()); + } + } + } + }