Updates from Yegor: New shape and picture stuff (see bug 39256)

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@393576 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2006-04-12 18:48:53 +00:00
parent 9e9dc0e4d9
commit 1bb312f416
20 changed files with 997 additions and 76 deletions

View File

@ -0,0 +1,65 @@
/* ====================================================================
Copyright 2002-2004 Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import java.awt.*;
/**
* Represents a autoshape in a PowerPoint drawing
*
* @author Yegor Kozlov
*/
public class AutoShape extends SimpleShape {
protected AutoShape(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent);
}
public AutoShape(int type, Shape parent){
super(null, parent);
_escherContainer = createSpContainer(type, parent instanceof ShapeGroup);
}
public AutoShape(int type){
this(type, null);
}
protected EscherContainerRecord createSpContainer(int shapeType, boolean isChild){
EscherContainerRecord spcont = super.createSpContainer(isChild);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
short type = (short)((shapeType << 4) | 0x2);
spRecord.setOptions(type);
//set default properties for a line
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLCOLOR, 134217732));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLBACKCOLOR, 134217728));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__NOFILLHITTEST, 1048592));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__COLOR, 134217729));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 524296));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.SHADOWSTYLE__COLOR, 134217730));
opt.sortProperties();
return spcont;
}
}

View File

@ -107,13 +107,12 @@ public class Line extends SimpleShape {
EscherContainerRecord spcont = super.createSpContainer(isChild); EscherContainerRecord spcont = super.createSpContainer(isChild);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
short type = (ShapeTypes.Line << 4) + 2; short type = (ShapeTypes.Line << 4) | 0x2;
spRecord.setOptions(type); spRecord.setOptions(type);
//set default properties for a line //set default properties for a line
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
//opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4));
opt.sortProperties(); opt.sortProperties();
return spcont; return spcont;

View File

@ -139,6 +139,34 @@ public class PPGraphics2D extends Graphics2D {
} }
public void drawString(String string, float x, float y){ 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){ public void fill(Shape shape){
@ -212,7 +240,7 @@ public class PPGraphics2D extends Graphics2D {
} }
public void drawOval(int x, int y, int width, int height) { 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)); ellipse.setAnchor(new java.awt.Rectangle(x-width/2, y-height/2, width, height));
if (stroke instanceof BasicStroke){ if (stroke instanceof BasicStroke){
BasicStroke bs = (BasicStroke)stroke; BasicStroke bs = (BasicStroke)stroke;

View File

@ -3,11 +3,14 @@ package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.*;
import org.apache.poi.hslf.usermodel.PictureData; import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow; import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.record.Document;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Arrays;
/** /**
@ -122,16 +125,49 @@ public class Picture extends SimpleShape {
} }
/** /**
* Set default size of the picture * Resize this picture to the default size.
*
* @param ppt presentation which holds the picture
*/ */
public void setDefaultSize(SlideShow ppt) throws IOException { public void setDefaultSize(){
int idx = getPictureIndex(); PictureData pict = getPictureData();
try {
PictureData pict = ppt.getPictures()[idx-1]; BufferedImage img = ImageIO.read(new ByteArrayInputStream(pict.getData()));
BufferedImage img = ImageIO.read(new ByteArrayInputStream(pict.getData())); setAnchor(new java.awt.Rectangle(0, 0, img.getWidth(), img.getHeight()));
} catch (IOException e){
setAnchor(new java.awt.Rectangle(0, 0, img.getWidth()*6, img.getHeight()*6)); throw new RuntimeException(e);
}
} }
/**
* Returns the picture data for this picture.
*
* @return the picture data for this picture.
*/
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);
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;
}
/**
* 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();
}
}
} }

View File

@ -21,39 +21,31 @@ import org.apache.poi.ddf.*;
import java.awt.*; import java.awt.*;
/** /**
* Represents a line in a PowerPoint drawing * Represents a rectangle shae in a PowerPoint drawing
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public class Rectangle extends SimpleShape { public class Rectangle extends TextBox {
protected Rectangle(EscherContainerRecord escherRecord, Shape parent){ protected Rectangle(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent); super(escherRecord, parent);
} }
public Rectangle(Shape parent){ public Rectangle(Shape parent){
super(null, parent); super(parent);
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
} }
public Rectangle(){ public Rectangle(){
this(null); super();
} }
protected EscherContainerRecord createSpContainer(boolean isChild){ protected EscherContainerRecord createSpContainer(boolean isChild){
EscherContainerRecord spcont = super.createSpContainer(isChild); EscherContainerRecord spcont = super.createSpContainer(isChild);
spcont.setOptions((short)15);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
short type = (ShapeTypes.Rectangle << 4) + 2; short type = (ShapeTypes.Rectangle << 4) + 2;
spRecord.setOptions(type); 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; return spcont;
} }

View File

@ -22,13 +22,47 @@ import java.awt.*;
import java.util.Iterator; import java.util.Iterator;
/** /**
* <p>
* Represents a Shape which is the elemental object that composes a drawing. * 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.
* </p>
* <p>
* When you add a shape, you usually specify the dimensions of the shape and the position
* of the upper<EFBFBD>left corner of the bounding box for the shape relative to the upper<EFBFBD>left
* corner of the page, worksheet, or slide. Distances in the drawing layer are measured
* in points (72 points = 1 inch).
* </p>
* <p>
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public abstract class Shape { 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_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 * Either EscherSpContainer or EscheSpgrContainer record
@ -42,6 +76,11 @@ public abstract class Shape {
*/ */
protected Shape _parent; protected Shape _parent;
/**
* The <code>Sheet</code> 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. * Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document.
* *
@ -86,25 +125,25 @@ public abstract class Shape {
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID); EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle(); anchor = new java.awt.Rectangle();
anchor.x = rec.getDx1(); anchor.x = rec.getDx1()*POINT_DPI/MASTER_DPI;
anchor.y = rec.getDy1(); anchor.y = rec.getDy1()*POINT_DPI/MASTER_DPI;
anchor.width = rec.getDx2() - anchor.x; anchor.width = (rec.getDx2() - anchor.x)*POINT_DPI/MASTER_DPI;
anchor.height = rec.getDy2() - anchor.y; anchor.height = (rec.getDy2() - anchor.y)*POINT_DPI/MASTER_DPI;
} }
else { else {
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID); EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle(); anchor = new java.awt.Rectangle();
anchor.y = rec.getFlag(); anchor.y = rec.getFlag()*POINT_DPI/MASTER_DPI;
anchor.x = rec.getCol1(); anchor.x = rec.getCol1()*POINT_DPI/MASTER_DPI;
anchor.width = rec.getDx1() - anchor.x; anchor.width = (rec.getDx1() - rec.getCol1())*POINT_DPI/MASTER_DPI;
anchor.height = rec.getRow1() - anchor.y; anchor.height = (rec.getRow1() - rec.getFlag())*POINT_DPI/MASTER_DPI;
} }
return anchor; return anchor;
} }
/** /**
* Sets the anchor (the bounding box rectangle) of this shape. * 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 * @param anchor new anchor
*/ */
@ -113,17 +152,17 @@ public abstract class Shape {
int flags = spRecord.getFlags(); int flags = spRecord.getFlags();
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID); EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
rec.setDx1(anchor.x); rec.setDx1(anchor.x*MASTER_DPI/POINT_DPI);
rec.setDy1(anchor.y); rec.setDy1(anchor.y*MASTER_DPI/POINT_DPI);
rec.setDx2(anchor.width + anchor.x); rec.setDx2((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI);
rec.setDy2(anchor.height + anchor.y); rec.setDy2((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI);
} }
else { else {
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID); EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
rec.setFlag((short)anchor.y); rec.setFlag((short)(anchor.y*MASTER_DPI/POINT_DPI));
rec.setCol1((short)anchor.x); rec.setCol1((short)(anchor.x*MASTER_DPI/POINT_DPI));
rec.setDx1((short)(anchor.width + anchor.x)); rec.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI));
rec.setRow1((short)(anchor.height + anchor.y)); rec.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI));
} }
} }
@ -171,11 +210,11 @@ public abstract class Shape {
} }
/** /**
* 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 opt The opt record to set the properties to.
* @param propId The id of the property. One of the constants defined in EscherOptRecord. * @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){ public static void setEscherProperty(EscherOptRecord opt, short propId, int value){
java.util.List props = opt.getEscherProperties(); java.util.List props = opt.getEscherProperties();
@ -198,4 +237,33 @@ public abstract class Shape {
public EscherContainerRecord getSpContainer(){ public EscherContainerRecord getSpContainer(){
return _escherContainer; 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.
* <br>
* Default implementation does nothing.
*
* @param sh - owning shape
*/
protected void afterInsert(Sheet sh){
}
/**
* @return the <code>SlideShow</code> this shape belongs to
*/
public Sheet getSheet(){
return _sheet;
}
/**
* Assign the <code>SlideShow</code> this shape belongs to
*
* @param sheet owner of this shape
*/
public void setSheet(Sheet sheet){
_sheet = sheet;
}
} }

View File

@ -25,6 +25,9 @@ import org.apache.poi.ddf.EscherContainerRecord;
*/ */
public class ShapeFactory { public class ShapeFactory {
/**
* Create a new shape from the data provided.
*/
public static Shape createShape(EscherContainerRecord spContainer, Shape parent){ public static Shape createShape(EscherContainerRecord spContainer, Shape parent){
if (spContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){ if (spContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){
return new ShapeGroup(spContainer, parent); return new ShapeGroup(spContainer, parent);
@ -36,6 +39,8 @@ public class ShapeFactory {
int type = spRecord.getOptions() >> 4; int type = spRecord.getOptions() >> 4;
switch (type){ switch (type){
case ShapeTypes.TextBox: case ShapeTypes.TextBox:
shape = new TextBox(spContainer, parent);
break;
case ShapeTypes.Rectangle: case ShapeTypes.Rectangle:
shape = new Rectangle(spContainer, parent); shape = new Rectangle(spContainer, parent);
break; break;
@ -45,14 +50,11 @@ public class ShapeFactory {
case ShapeTypes.Line: case ShapeTypes.Line:
shape = new Line(spContainer, parent); shape = new Line(spContainer, parent);
break; break;
case ShapeTypes.Ellipse:
shape = new Ellipse(spContainer, parent);
break;
case ShapeTypes.NotPrimitive: case ShapeTypes.NotPrimitive:
shape = new ShapeGroup(spContainer, parent); shape = new ShapeGroup(spContainer, parent);
break; break;
default: default:
shape = new SimpleShape(spContainer, parent); shape = new AutoShape(spContainer, parent);
break; break;
} }
return shape; return shape;

View File

@ -27,11 +27,21 @@ import java.util.List;
*/ */
public class ShapeGroup extends Shape{ public class ShapeGroup extends Shape{
/**
* Create a new ShapeGroup. This constructor is used when a new shape is created.
*
*/
public ShapeGroup(){ public ShapeGroup(){
this(null, null); this(null, null);
_escherContainer = createSpContainer(false); _escherContainer = createSpContainer(false);
} }
/**
* Create a ShapeGroup object and initilize it from the supplied Record container.
*
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
* @param parent the parent of the shape
*/
protected ShapeGroup(EscherContainerRecord escherRecord, Shape parent){ protected ShapeGroup(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent); super(escherRecord, parent);
} }

View File

@ -82,9 +82,9 @@ public class ShapeTypes {
public static final int Chevron = 55; public static final int Chevron = 55;
public static final int Pentagon = 56; public static final int Pentagon = 56;
public static final int NoSmoking = 57; public static final int NoSmoking = 57;
public static final int Seal8 = 58; public static final int Star8 = 58;
public static final int Seal16 = 59; public static final int Star16 = 59;
public static final int Seal32 = 60; public static final int Star32 = 60;
public static final int WedgeRectCallout = 61; public static final int WedgeRectCallout = 61;
public static final int WedgeRRectCallout = 62; public static final int WedgeRRectCallout = 62;
public static final int WedgeEllipseCallout = 63; public static final int WedgeEllipseCallout = 63;
@ -116,7 +116,7 @@ public class ShapeTypes {
public static final int LeftUpArrow = 89; public static final int LeftUpArrow = 89;
public static final int BentUpArrow = 90; public static final int BentUpArrow = 90;
public static final int BentArrow = 91; 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 StripedRightArrow = 93;
public static final int NotchedRightArrow = 94; public static final int NotchedRightArrow = 94;
public static final int BlockArc = 95; public static final int BlockArc = 95;
@ -211,7 +211,7 @@ public class ShapeTypes {
public static final int Moon = 184; public static final int Moon = 184;
public static final int BracketPair = 185; public static final int BracketPair = 185;
public static final int BracePair = 186; 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 DoubleWave = 188;
public static final int ActionButtonBlank = 189; public static final int ActionButtonBlank = 189;
public static final int ActionButtonHome = 190; public static final int ActionButtonHome = 190;

View File

@ -23,6 +23,7 @@ import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherDgRecord; import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherRecord; import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.SlideShow;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@ -38,6 +39,11 @@ import java.util.Vector;
public abstract class Sheet public abstract class Sheet
{ {
/**
* The <code>SlideShow</code> we belong to
*/
private SlideShow _slideShow;
/** /**
* Returns an array of all the TextRuns in the sheet. * Returns an array of all the TextRuns in the sheet.
*/ */
@ -59,7 +65,19 @@ public abstract class Sheet
* Fetch the PPDrawing from the underlying record * Fetch the PPDrawing from the underlying record
*/ */
protected abstract PPDrawing getPPDrawing(); protected abstract PPDrawing getPPDrawing();
/**
* Fetch the SlideShow we're attached to
*/
public SlideShow getSlideShow() { return _slideShow; }
/**
* Set the SlideShow we're attached to
*/
public void setSlideShow(SlideShow ss) { _slideShow = ss; }
/** /**
* For a given PPDrawing, grab all the TextRuns * For a given PPDrawing, grab all the TextRuns
*/ */
@ -149,7 +167,9 @@ public abstract class Sheet
ArrayList shapes = new ArrayList(); ArrayList shapes = new ArrayList();
for (int i=1;i<ch.size();i++) { for (int i=1;i<ch.size();i++) {
EscherContainerRecord sp = (EscherContainerRecord)ch.get(i); EscherContainerRecord sp = (EscherContainerRecord)ch.get(i);
shapes.add(ShapeFactory.createShape(sp, null)); Shape sh = ShapeFactory.createShape(sp, null);
sh.setSheet(this);
shapes.add(sh);
} }
return (Shape[])shapes.toArray(new Shape[shapes.size()]); return (Shape[])shapes.toArray(new Shape[shapes.size()]);
@ -169,5 +189,8 @@ public abstract class Sheet
EscherDgRecord dg = (EscherDgRecord)Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID); EscherDgRecord dg = (EscherDgRecord)Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
dg.setNumShapes(dg.getNumShapes()+1); dg.setNumShapes(dg.getNumShapes()+1);
shape.setSheet(this);
shape.afterInsert(this);
} }
} }

View File

@ -29,6 +29,12 @@ import java.awt.*;
*/ */
public class SimpleShape extends Shape { public class SimpleShape extends Shape {
/**
* Create a SimpleShape object and initialize it from the supplied Record container.
*
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
* @param parent the parent of the shape
*/
protected SimpleShape(EscherContainerRecord escherRecord, Shape parent){ protected SimpleShape(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent); super(escherRecord, parent);
} }
@ -102,12 +108,12 @@ public class SimpleShape extends Shape {
} }
/** /**
* @return color of the line * @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
*/ */
public Color getLineColor(){ public Color getLineColor(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherRGBProperty prop = (EscherRGBProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__COLOR); EscherRGBProperty prop = (EscherRGBProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__COLOR);
Color color = null; Color color = Color.black;
if (prop != null){ if (prop != null){
Color swp = new Color(prop.getRgbColor()); Color swp = new Color(prop.getRgbColor());
color = new Color(swp.getBlue(), swp.getGreen(), swp.getRed()); color = new Color(swp.getBlue(), swp.getGreen(), swp.getRed());
@ -136,6 +142,11 @@ public class SimpleShape extends Shape {
return prop == null ? Line.LineSolid : prop.getPropertyValue(); return prop == null ? Line.LineSolid : prop.getPropertyValue();
} }
/**
* The color used to fill this shape.
*
* @param color the background color
*/
public void setFillColor(Color color){ public void setFillColor(Color color){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();

View File

@ -0,0 +1,490 @@
/* ====================================================================
Copyright 2002-2004 Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.RichTextRun;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.io.IOException;
/**
* Represents a TextFrame shape in PowerPoint.
* <p>
* Contains the text in a text frame as well as the properties and methods
* that control alignment and anchoring of the text.
* </p>
*
* @author Yegor Kozlov
*/
public class TextBox extends SimpleShape {
/**
* How to anchor the text
*/
public static final int AnchorTop = 0;
public static final int AnchorMiddle = 1;
public static final int AnchorBottom = 2;
public static final int AnchorTopCentered = 3;
public static final int AnchorMiddleCentered = 4;
public static final int AnchorBottomCentered = 5;
public static final int AnchorTopBaseline = 6;
public static final int AnchorBottomBaseline = 7;
public static final int AnchorTopCenteredBaseline = 8;
public static final int AnchorBottomCenteredBaseline = 9;
/**
* How to wrap the text
*/
public static final int WrapSquare = 0;
public static final int WrapByPoints = 1;
public static final int WrapNone = 2;
public static final int WrapTopBottom = 3;
public static final int WrapThrough = 4;
/**
* How to align the text
*/
public static final int AlignLeft = 0;
public static final int AlignCenter = 1;
public static final int AlignRight = 2;
public static final int AlignJustify = 3;
/**
* Default font size
*/
public static final int DefaultFontSize = 24;
/**
* Low-level object which holds actual text and format data
*/
protected TextRun _txtrun;
/**
* Escher container which holds text attributes such as
* TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc.
*/
protected EscherTextboxWrapper _txtbox;
/**
* Create a TextBox object and initialize it from the supplied Record container.
*
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
* @param parent the parent of the shape
*/
protected TextBox(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent);
EscherTextboxRecord textbox = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
_txtbox = new EscherTextboxWrapper(textbox);
TextHeaderAtom tha = null;
TextBytesAtom tba = null;
StyleTextPropAtom sta = null;
Record[] child = _txtbox.getChildRecords();
for (int i = 0; i < child.length; i++) {
if (child[i] instanceof TextHeaderAtom) tha = (TextHeaderAtom)child[i];
else if (child[i] instanceof TextBytesAtom) tba = (TextBytesAtom)child[i];
else if (child[i] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)child[i];
}
_txtrun = new TextRun(tha,tba,sta);
}
/**
* Create a new TextBox. This constructor is used when a new shape is created.
*
* @param parent the parent of this Shape. For example, if this text box is a cell
* in a table then the parent is Table.
*/
public TextBox(Shape parent){
super(null, parent);
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
}
/**
* Create a new TextBox. This constructor is used when a new shape is created.
*
*/
public TextBox(){
this(null);
}
/**
* Create a new textBox and initialize internal structures
*
* @return the created <code>EscherContainerRecord</code> which holds shape data
*/
protected EscherContainerRecord createSpContainer(boolean isChild){
EscherContainerRecord spcont = super.createSpContainer(isChild);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
short type = (ShapeTypes.TextBox << 4) | 0x2;
spRecord.setOptions(type);
//set default properties for a textbox
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, 134217732);
setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, 134217728);
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 1048576);
setEscherProperty(opt, EscherProperties.LINESTYLE__COLOR, 134217729);
setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 524288);
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 134217730);
opt.sortProperties();
//create EscherTextboxWrapper
_txtbox = new EscherTextboxWrapper();
TextHeaderAtom tha = new TextHeaderAtom();
_txtbox.appendChildRecord(tha);
TextBytesAtom tba = new TextBytesAtom();
_txtbox.appendChildRecord(tba);
StyleTextPropAtom sta = new StyleTextPropAtom(0);
_txtbox.appendChildRecord(sta);
_txtrun = new TextRun(tha,tba,sta);
_txtrun.setText("");
spcont.addChildRecord(_txtbox.getEscherRecord());
return spcont;
}
/**
* Returns the text contained in this text frame.
*
* @return the text string for this textbox.
*/
public String getText(){
return _txtrun.getText();
}
/**
* Sets the text contained in this text frame.
*
* @param text the text string used by this object.
*/
public void setText(String text){
_txtrun.setText(text);
}
/**
* When a textbox is added to a sheet we need to tell upper-level
* <code>PPDrawing</code> about it.
*
* @param sh the sheet we are adding to
*/
protected void afterInsert(Sheet sh){
PPDrawing ppdrawing = sh.getPPDrawing();
ppdrawing.addTextboxWrapper(_txtbox);
// Ensure the escher layer knows about the added records
try {
_txtbox.writeOut(null);
} catch (IOException e){
throw new RuntimeException(e);
}
}
/**
* Returns the bounds of this <code>TextFrame</code>.
* <code>Note</b>, this is very primitive estimation, the precision is poor.
*
* @return the bounds of this <code>TextFrame</code>.
*/
protected Dimension getTextSize(){
FontRenderContext frc = new FontRenderContext(null, true, true);
RichTextRun rt = _txtrun.getRichTextRuns()[0];
int size = rt.getFontSize();
if (size == -1) size = TextBox.DefaultFontSize;
int style = 0;
if (rt.isBold()) style |= Font.BOLD;
if (rt.isItalic()) style |= Font.ITALIC;
String fntname = rt.getFontName();
if (fntname == null) //get the default font from Document.Environment.FontCollection
fntname = getSheet().getSlideShow().getDocumentRecord().getEnvironment().getFontCollection().getFontWithId(0);
Font font = new Font(fntname, style, size);
TextLayout layout = new TextLayout(getText(), font, frc);
int width = Math.round(layout.getAdvance());
width += getMarginLeft() + getMarginRight();
int height = Math.round(layout.getAscent());
height += getMarginTop() + getMarginBottom();
return new Dimension(width, height);
}
/**
* Adjust the size of the TextBox so it encompasses the text inside it.
*/
public void resizeToFitText(){
Dimension size = getTextSize();
java.awt.Rectangle anchor = getAnchor();
anchor.setSize(size);
setAnchor(anchor);
}
/**
* Returns the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @return the type of alignment
*/
public int getVerticalAlignment(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
return prop == null ? AlignCenter : prop.getPropertyValue();
}
/**
* Sets the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @param align - the type of alignment
*/
public void setVerticalAlignment(int align){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT, align);
}
/**
* Returns the distance (in points) between the bottom of the text frame
* and the bottom of the inscribed rectangle of the shape that contains the text.
* Default value is 1/20 inch.
*
* @return the botom margin
*/
public int getMarginBottom(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the botom margin.
* @see #getMarginBottom()
*
* @param margin the bottom margin
*/
public void setMarginBottom(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM, margin*EMU_PER_POINT);
}
/**
* Returns the distance (in EMUs) between the left edge of the text frame
* and the left edge of the inscribed rectangle of the shape that contains
* the text.
* Default value is 1/10 inch.
*
* @return the left margin
*/
public int getMarginLeft(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the left margin.
* @see #getMarginLeft()
*
* @param margin the left margin
*/
public void setMarginLeft(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT, margin*EMU_PER_POINT);
}
/**
* Returns the distance (in EMUs) between the right edge of the
* text frame and the right edge of the inscribed rectangle of the shape
* that contains the text.
* Default value is 1/10 inch.
*
* @return the right margin
*/
public int getMarginRight(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the right margin.
* @see #getMarginRight()
*
* @param margin the right margin
*/
public void setMarginRight(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT, margin*EMU_PER_POINT);
}
/**
* Returns the distance (in EMUs) between the top of the text frame
* and the top of the inscribed rectangle of the shape that contains the text.
* Default value is 1/20 inch.
*
* @return the top margin
*/
public int getMarginTop(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the top margin.
* @see #getMarginTop()
*
* @param margin the top margin
*/
public void setMarginTop(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTTOP, margin*EMU_PER_POINT);
}
/**
* Returns the value indicating word wrap.
* One of the <code>Wrap*</code> constants defined in this class.
*
* @return the value indicating word wrap
*/
public int getWordWrap(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
return prop == null ? WrapSquare : prop.getPropertyValue();
}
/**
* Specifies how the text should be wrapped
*
* @param wrap the value indicating how the text should be wrapped
*/
public void setWordWrap(int wrap){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT, wrap);
}
/**
* @return id for the text.
*/
public int getTextId(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
return prop == null ? 0 : prop.getPropertyValue();
}
/**
* Sets text ID
*
* @param id of the text
*/
public void setTextId(int id){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, id);
}
/**
* The color used to fill this shape.
*
* @param color the background color
*/
public void setBackgroundColor(Color color){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();
setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, rgb);
}
/**
* @return array of RichTextRun objects which control text formatting in this text box
*/
public RichTextRun[] getRichTextRuns(){
return _txtrun.getRichTextRuns();
}
/**
* Sets the <code>Font</code> object for this text frame
*
* @param size the size of the font
*/
public void setFontSize(int size){
RichTextRun rt = _txtrun.getRichTextRuns()[0];
rt.setFontSize(size);
}
/**
*
* @return the size of the font applied to this text shape
*/
public int getFontSize(){
RichTextRun rt = _txtrun.getRichTextRuns()[0];
return rt.getFontSize();
}
/**
* Set whether to use bold or not
*
* @param bold <code>true</code> if the text should be bold, <code>false</code> otherwise
*/
public void setBold(boolean bold){
RichTextRun rt = _txtrun.getRichTextRuns()[0];
rt.setBold(bold);
}
/**
* Set whether to use italic or not
*
* @param italic <code>true</code> if the text should be italic, <code>false</code> otherwise
*/
public void setItalic(boolean italic){
RichTextRun rt = _txtrun.getRichTextRuns()[0];
rt.setItalic(italic);
}
/**
* Set whether to use underline or not
*
* @param underline <code>true</code> if the text should be underlined, <code>false</code> otherwise
*/
public void setUnderline(boolean underline){
RichTextRun rt = _txtrun.getRichTextRuns()[0];
rt.setUnderlined(underline);
}
/**
* Sets the font of this text shape
*
* @param name the name of the font to be applied to this text shape
*/
public void setFontName(String name){
RichTextRun rt = _txtrun.getRichTextRuns()[0];
rt.setFontName(name);
}
}

View File

@ -47,7 +47,7 @@ public class EscherTextboxWrapper extends RecordContainer
/** /**
* Creates the wrapper for the given DDF Escher Record and children * Creates the wrapper for the given DDF Escher Record and children
*/ */
protected EscherTextboxWrapper(EscherTextboxRecord textbox) { public EscherTextboxWrapper(EscherTextboxRecord textbox) {
_escherRecord = textbox; _escherRecord = textbox;
_type = (long)_escherRecord.getRecordId(); _type = (long)_escherRecord.getRecordId();
@ -55,7 +55,18 @@ public class EscherTextboxWrapper extends RecordContainer
byte[] data = _escherRecord.getData(); byte[] data = _escherRecord.getData();
_children = Record.findChildRecords(data,0,data.length); _children = Record.findChildRecords(data,0,data.length);
} }
/**
* Creates a new, empty wrapper for DDF Escher Records and their children
*/
public EscherTextboxWrapper() {
_escherRecord = new EscherTextboxRecord();
_escherRecord.setRecordId(EscherTextboxRecord.RECORD_ID);
_escherRecord.setOptions((short)15);
_children = new Record[0];
}
/** /**
* Return the type of the escher record (normally in the 0xFnnn range) * Return the type of the escher record (normally in the 0xFnnn range)

View File

@ -262,4 +262,15 @@ public class PPDrawing extends RecordAtom
dgContainer dgContainer
}; };
} }
/**
* Add a new EscherTextboxWrapper to this <code>PPDrawing</code>.
*/
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;
}
} }

View File

@ -71,6 +71,18 @@ public class TextBytesAtom extends RecordAtom
_text = new byte[len-8]; _text = new byte[len-8];
System.arraycopy(source,start+8,_text,0,len-8); System.arraycopy(source,start+8,_text,0,len-8);
} }
/**
* Create an empty TextBytes Atom
*/
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[]{};
}
/** /**
* We are of type 4008 * We are of type 4008

View File

@ -75,6 +75,18 @@ public class TextHeaderAtom extends RecordAtom implements ParentAwareRecord
// Grab the type // Grab the type
textType = (int)LittleEndian.getInt(source,start+8); textType = (int)LittleEndian.getInt(source,start+8);
} }
/**
* Create a new TextHeader Atom, for an unknown type of text
*/
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;
}
/** /**
* We are of type 3999 * We are of type 3999

View File

@ -25,6 +25,7 @@ import java.security.NoSuchAlgorithmException;
/** /**
* A class that represents the image data contained in the Presentation. * A class that represents the image data contained in the Presentation.
*
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
@ -35,6 +36,9 @@ public class PictureData {
*/ */
public static final int HEADER_SIZE = 25; 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 * Binary data of the picture
*/ */
@ -118,11 +122,27 @@ public class PictureData {
*/ */
public void setType(int format){ public void setType(int format){
switch (format){ switch (format){
case Picture.JPEG: LittleEndian.putInt(header, 0, -266516832); break; case Picture.JPEG: LittleEndian.putInt(header, 0, PictureData.JPEG_HEADER); break;
case Picture.PNG: LittleEndian.putInt(header, 0, -266441216); 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 <code>Picture<code> 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 * Returns the header of the Picture
* *

View File

@ -401,6 +401,7 @@ public class SlideShow
_notes = new Notes[notesV.size()]; _notes = new Notes[notesV.size()];
for(int i=0; i<_notes.length; i++) { for(int i=0; i<_notes.length; i++) {
_notes[i] = (Notes)notesV.get(i); _notes[i] = (Notes)notesV.get(i);
_notes[i].setSlideShow(this);
// Now supply ourselves to all the rich text runs // Now supply ourselves to all the rich text runs
// of this note's TextRuns // of this note's TextRuns
@ -418,6 +419,7 @@ public class SlideShow
_slides = new Slide[slidesV.size()]; _slides = new Slide[slidesV.size()];
for(int i=0; i<_slides.length; i++) { for(int i=0; i<_slides.length; i++) {
_slides[i] = (Slide)slidesV.get(i); _slides[i] = (Slide)slidesV.get(i);
_slides[i].setSlideShow(this);
// Now supply ourselves to all the rich text runs // Now supply ourselves to all the rich text runs
// of this slide's TextRuns // of this slide's TextRuns
@ -472,9 +474,9 @@ public class SlideShow
//public MetaSheet[] getMetaSheets() { return _msheets; } //public MetaSheet[] getMetaSheets() { return _msheets; }
/** /**
* Returns all the pictures attached to the SlideShow * Returns the data of all the pictures attached to the SlideShow
*/ */
public PictureData[] getPictures() throws IOException { public PictureData[] getPictureData() {
return _hslfSlideShow.getPictures(); return _hslfSlideShow.getPictures();
} }
@ -483,7 +485,20 @@ public class SlideShow
*/ */
public Dimension getPageSize(){ public Dimension getPageSize(){
DocumentAtom docatom = _documentRecord.getDocumentAtom(); 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);
}
/**
* Change the current 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);
} }
/** /**
@ -491,9 +506,9 @@ public class SlideShow
*/ */
protected FontCollection getFontCollection() { return _fonts; } protected FontCollection getFontCollection() { return _fonts; }
/** /**
* Helper method for usermodel: Get the document record * Helper method for usermodel and model: Get the document record
*/ */
protected Document getDocumentRecord() { return _documentRecord; } public Document getDocumentRecord() { return _documentRecord; }
/* =============================================================== /* ===============================================================
@ -607,6 +622,7 @@ public class SlideShow
usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW); usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
// All done and added // All done and added
slide.setSlideShow(this);
return slide; return slide;
} }

View File

@ -17,12 +17,14 @@ package org.apache.poi.hslf.model;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hslf.usermodel.SlideShow; import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.hslf.HSLFSlideShow; import org.apache.poi.hslf.HSLFSlideShow;
import java.awt.*; import java.awt.*;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
/** /**
* Test drawing shapes via Graphics2D * Test drawing shapes via Graphics2D
@ -36,21 +38,23 @@ public class TestShapes extends TestCase {
String dirname = System.getProperty("HSLF.testdata.path"); String dirname = System.getProperty("HSLF.testdata.path");
String filename = dirname + "/empty.ppt"; String filename = dirname + "/empty.ppt";
ppt = new SlideShow(new HSLFSlideShow(filename)); ppt = new SlideShow(new HSLFSlideShow(filename));
getClass().getResourceAsStream("");
} }
public void testGraphics() throws Exception { public void testGraphics() throws Exception {
Slide slide = ppt.createSlide(); Slide slide = ppt.createSlide();
Line line = new Line(); 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.setLineWidth(3);
line.setLineStyle(Line.LineDashSys); line.setLineStyle(Line.LineDashSys);
line.setLineColor(Color.red); line.setLineColor(Color.red);
slide.addShape(line); slide.addShape(line);
Ellipse ellipse = new Ellipse(); AutoShape ellipse = new AutoShape(ShapeTypes.Ellipse);
ellipse.setAnchor(new Rectangle(4000, 1000, 1000, 1000)); java.awt.Rectangle ellipseAnchor = new Rectangle(320, 154, 55, 111);
ellipse.setAnchor(ellipseAnchor);
ellipse.setLineWidth(2); ellipse.setLineWidth(2);
ellipse.setLineStyle(Line.LineSolid); ellipse.setLineStyle(Line.LineSolid);
ellipse.setLineColor(Color.green); ellipse.setLineColor(Color.green);
@ -64,17 +68,103 @@ public class TestShapes extends TestCase {
//read ppt from byte array //read ppt from byte array
ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()))); ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));
assertEquals(ppt.getSlides().length, 1); assertEquals(1, ppt.getSlides().length);
slide = ppt.getSlides()[0]; slide = ppt.getSlides()[0];
Shape[] shape = slide.getShapes(); Shape[] shape = slide.getShapes();
assertEquals(shape.length, 2); assertEquals(2, shape.length);
assertTrue(shape[0] instanceof Line); //group shape 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 assertTrue(shape[1] instanceof AutoShape); //group shape
assertEquals(shape[1].getAnchor(), new Rectangle(4000, 1000, 1000, 1000)); //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());
}
}
} }
} }

View File

@ -50,10 +50,37 @@ public class TestPictures extends TestCase{
BufferedImage img = ImageIO.read(new ByteArrayInputStream(data)); BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
assertNotNull(img); assertNotNull(img);
assertEquals(Picture.PNG, pict[i].getType());
} }
ppt.close(); 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 { public void testSerializePictures() throws Exception {
HSLFSlideShow ppt = new HSLFSlideShow(filename); HSLFSlideShow ppt = new HSLFSlideShow(filename);
PictureData[] pict = ppt.getPictures(); PictureData[] pict = ppt.getPictures();
@ -78,12 +105,10 @@ public class TestPictures extends TestCase{
idx = ppt.addPicture(new File(dirname + "/clock.jpg"), Picture.JPEG); idx = ppt.addPicture(new File(dirname + "/clock.jpg"), Picture.JPEG);
slide = ppt.createSlide(); slide = ppt.createSlide();
pict = new Picture(idx); pict = new Picture(idx);
pict.setDefaultSize(ppt);
slide.addShape(pict); slide.addShape(pict);
idx = ppt.addPicture(new File(dirname + "/painting.png"), Picture.PNG); idx = ppt.addPicture(new File(dirname + "/painting.png"), Picture.PNG);
pict = new Picture(idx); pict = new Picture(idx);
pict.setDefaultSize(ppt);
slide.addShape(pict); slide.addShape(pict);
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
@ -91,7 +116,7 @@ public class TestPictures extends TestCase{
out.close(); out.close();
ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()))); ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));
assertTrue(ppt.getPictures().length == 2 ); assertTrue(ppt.getPictureData().length == 2 );
} }
} }