*
* @author Glen Stampoultzis (glens at apache.org)
*/
+@SuppressWarnings("WeakerAccess")
public final class EscherProperties {
// Property constants
public static final short GEOMETRY__ADJUST8VALUE = 334;
public static final short GEOMETRY__ADJUST9VALUE = 335;
public static final short GEOMETRY__ADJUST10VALUE = 336;
+ public static final short GEOMETRY__PCONNECTIONSITES = 337;
+ public static final short GEOMETRY__PCONNECTIONSITESDIR = 338;
+ public static final short GEOMETRY__XLIMO = 339;
+ public static final short GEOMETRY__YLIMO = 340;
+ public static final short GEOMETRY__PADJUSTHANDLES = 341;
+ public static final short GEOMETRY__PGUIDES = 342;
+ public static final short GEOMETRY__PINSCRIBE = 343;
+ public static final short GEOMETRY__CXK = 344;
+ public static final short GEOMETRY__PFRAGMENTS = 345;
public static final short GEOMETRY__SHADOWok = 378;
public static final short GEOMETRY__3DOK = 379;
public static final short GEOMETRY__LINEOK = 380;
private static final Map<Short, EscherPropertyMetaData> properties = initProps();
+ private EscherProperties() {
+ }
+
private static Map<Short, EscherPropertyMetaData> initProps() {
Map<Short, EscherPropertyMetaData> m = new HashMap<>();
addProp(m, TRANSFORM__ROTATION, "transform.rotation");
addProp(m, GEOMETRY__ADJUST8VALUE, "geometry.adjust8value");
addProp(m, GEOMETRY__ADJUST9VALUE, "geometry.adjust9value");
addProp(m, GEOMETRY__ADJUST10VALUE, "geometry.adjust10value");
+ addProp(m, GEOMETRY__PCONNECTIONSITES, "geometry.pConnectionSites");
+ addProp(m, GEOMETRY__PCONNECTIONSITESDIR, "geometry.pConnectionSitesDir");
+ addProp(m, GEOMETRY__XLIMO, "geometry.xLimo");
+ addProp(m, GEOMETRY__YLIMO, "geometry.yLimo");
+ addProp(m, GEOMETRY__PADJUSTHANDLES, "geometry.pAdjustHandles");
+ addProp(m, GEOMETRY__PGUIDES, "geometry.pGuides");
+ addProp(m, GEOMETRY__PINSCRIBE, "geometry.pInscribe");
+ addProp(m, GEOMETRY__CXK, "geometry.cxk");
+ addProp(m, GEOMETRY__PFRAGMENTS, "geometry.pFragments");
addProp(m, GEOMETRY__SHADOWok, "geometry.shadowOK");
addProp(m, GEOMETRY__3DOK, "geometry.3dok");
addProp(m, GEOMETRY__LINEOK, "geometry.lineok");
}
private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName) {
- m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName));
+ m.put((short) s, new EscherPropertyMetaData(propName));
}
private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName, byte type) {
- m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName, type));
+ m.put((short) s, new EscherPropertyMetaData(propName, type));
}
public static String getPropertyName(short propertyId) {
- EscherPropertyMetaData o = properties.get(Short.valueOf(propertyId));
+ EscherPropertyMetaData o = properties.get(propertyId);
return o == null ? "unknown" : o.getDescription();
}
public static byte getPropertyType(short propertyId) {
- EscherPropertyMetaData escherPropertyMetaData = properties.get(Short.valueOf(propertyId));
+ EscherPropertyMetaData escherPropertyMetaData = properties.get(propertyId);
return escherPropertyMetaData == null ? 0 : escherPropertyMetaData.getType();
}
}
package org.apache.poi.sl.draw;
-import java.awt.Graphics2D;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.poi.sl.draw.geom.Outline;
-import org.apache.poi.sl.draw.geom.Path;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.sl.usermodel.FreeformShape;
+@SuppressWarnings("WeakerAccess")
public class DrawFreeformShape extends DrawAutoShape {
public DrawFreeformShape(FreeformShape<?,?> shape) {
super(shape);
}
-
- protected Collection<Outline> computeOutlines(Graphics2D graphics) {
- List<Outline> lst = new ArrayList<>();
- FreeformShape<?,?> fsh = (FreeformShape<?, ?>) getShape();
- Path2D sh = fsh.getPath();
-
- AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
- if (tx == null) {
- tx = new AffineTransform();
- }
-
- java.awt.Shape canvasShape = tx.createTransformedShape(sh);
-
- FillStyle fs = fsh.getFillStyle();
- StrokeStyle ss = fsh.getStrokeStyle();
- Path path = new Path(fs != null, ss != null);
- lst.add(new Outline(canvasShape, path));
- return lst;
- }
-
- @Override
- protected TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> getShape() {
- return (TextShape<?,? extends TextParagraph<?,?,? extends TextRun>>)shape;
- }
}
}
for (Path p : geom) {
- double w = p.getW(), h = p.getH(), scaleX = Units.toPoints(1), scaleY = scaleX;
+ double w = p.getW(), h = p.getH(), scaleX, scaleY;
if (w == -1) {
w = Units.toEMU(anchor.getWidth());
+ scaleX = Units.toPoints(1);
+ } else if (anchor.getWidth() == 0) {
+ scaleX = 1;
} else {
scaleX = anchor.getWidth() / w;
}
if (h == -1) {
h = Units.toEMU(anchor.getHeight());
+ scaleY = Units.toPoints(1);
+ } else if (anchor.getHeight() == 0) {
+ scaleY = 1;
} else {
scaleY = anchor.getHeight() / h;
}
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
+import java.util.regex.Pattern;
public class Context {
- final Map<String, Double> _ctx = new HashMap<>();
- final IAdjustableShape _props;
- final Rectangle2D _anchor;
+ private static final Pattern DOUBLE_PATTERN = Pattern.compile(
+ "[\\x00-\\x20]*[+-]?(NaN|Infinity|((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)" +
+ "([eE][+-]?(\\p{Digit}+))?)|(\\.(\\p{Digit}+)([eE][+-]?(\\p{Digit}+))?)|" +
+ "(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))" +
+ "[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*");
+
+ private final Map<String, Double> _ctx = new HashMap<>();
+ private final IAdjustableShape _props;
+ private final Rectangle2D _anchor;
public Context(CustomGeometry geom, Rectangle2D anchor, IAdjustableShape props){
_props = props;
}
}
- public Rectangle2D getShapeAnchor(){
+ Rectangle2D getShapeAnchor(){
return _anchor;
}
- public Guide getAdjustValue(String name){
+ Guide getAdjustValue(String name){
// ignore HSLF props for now ... the results with default value are usually better - see #59004
return (_props.getClass().getName().contains("hslf")) ? null : _props.getAdjustValue(name);
}
public double getValue(String key){
- if(key.matches("(\\+|-)?\\d+")){
+ if(DOUBLE_PATTERN.matcher(key).matches()){
return Double.parseDouble(key);
}
- Double val = _ctx.get(key);
// BuiltInGuide throws IllegalArgumentException if key is not defined
- return (val != null) ? val : evaluate(BuiltInGuide.valueOf("_"+key));
+ return _ctx.containsKey(key) ? _ctx.get(key) : evaluate(BuiltInGuide.valueOf("_"+key));
}
public double evaluate(Formula fmla){
P extends TextParagraph<S,P,? extends TextRun>
> extends AutoShape<S,P> {
/**
- * Gets the shape path.
- * <p>
- * The path is translated in the shape's coordinate system, i.e.
- * freeform.getPath().getBounds2D() equals to freeform.getAnchor()
- * (small discrepancies are possible due to rounding errors)
- * </p>
+ * Gets the shape path.<p>
+ *
+ * The path is translated in the shape's coordinate system, i.e.
+ * freeform.getPath2D().getBounds2D() equals to freeform.getAnchor()
+ * (small discrepancies are possible due to rounding errors)
*
* @return the path
*/
- Path2D.Double getPath();
+ Path2D getPath();
/**
* Set the shape path
* @param path shape outline
* @return the number of points written
*/
- int setPath(Path2D.Double path);
+ int setPath(Path2D path);
}
points /= MASTER_DPI;
return points;
}
-
+
public static int pointsToMaster(double points) {
points *= MASTER_DPI;
points /= POINT_DPI;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.poi.ooxml.POIXMLTypeLoader;
+import org.apache.poi.sl.draw.geom.CustomGeometry;
+import org.apache.poi.sl.draw.geom.PresetGeometries;
import org.apache.poi.sl.usermodel.FreeformShape;
import org.apache.poi.util.Beta;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.drawingml.x2006.main.CTAdjPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTCustomGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomRect;
}
@Override
- public int setPath(final Path2D.Double path) {
+ public int setPath(final Path2D path) {
final CTPath2D ctPath = CTPath2D.Factory.newInstance();
final Rectangle2D bounds = path.getBounds2D();
return numPoints;
}
+ /**
+ * @return definition of the shape geometry
+ */
+ @Override
+ public CustomGeometry getGeometry() {
+ final XmlObject xo = getShapeProperties();
+ if (!(xo instanceof CTShapeProperties)) {
+ return null;
+ }
+
+ XmlOptions xop = new XmlOptions(POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
+ xop.setSaveOuter();
+
+ XMLStreamReader staxReader = ((CTShapeProperties)xo).getCustGeom().newXMLStreamReader(xop);
+ CustomGeometry custGeo = PresetGeometries.convertCustomGeometry(staxReader);
+ try {
+ staxReader.close();
+ } catch (XMLStreamException e) {
+ LOG.log(POILogger.WARN,
+ "An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
+ }
+
+ return custGeo;
+ }
@Override
public Path2D.Double getPath() {
}
/**
- *
* @return definition of the shape geometry
*/
@Override
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
private static final File basedir = null;
private static final String files =
- "53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx";
+ "53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, " +
+ "backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx," +
+ "customGeo.pptx, customGeo.ppt";
package org.apache.poi.hslf.usermodel;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.poi.ddf.AbstractEscherOptRecord;
+import org.apache.poi.ddf.EscherArrayProperty;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.ddf.EscherProperty;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import org.apache.poi.sl.draw.binding.CTCustomGeometry2D;
+import org.apache.poi.sl.draw.binding.CTPath2D;
+import org.apache.poi.sl.draw.binding.CTPath2DArcTo;
+import org.apache.poi.sl.draw.binding.CTPath2DCubicBezierTo;
+import org.apache.poi.sl.draw.binding.CTPath2DLineTo;
+import org.apache.poi.sl.draw.binding.CTPath2DList;
+import org.apache.poi.sl.draw.binding.CTPath2DMoveTo;
+import org.apache.poi.sl.draw.binding.ObjectFactory;
+import org.apache.poi.sl.draw.geom.CustomGeometry;
+import org.apache.poi.sl.usermodel.AutoShape;
+import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.ShapeTypes;
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
/**
- * Represents an AutoShape.
- * <p>
+ * Represents an AutoShape.<p>
+ *
* AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments.
* See {@link ShapeTypes}
- * </p>
- *
- * @author Yegor Kozlov
*/
public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,HSLFTextParagraph> {
+ private static final POILogger LOG = POILogFactory.getLogger(HSLFAutoShape.class);
+
+ static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};
+ static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};
+ static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};
+ static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};
+ static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};
+ // OpenOffice inserts 0xB3 instead of 0xAD.
+ // protected static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
+ static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};
+ static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};
+
+ private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
+ private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
+
+ enum PathInfo {
+ lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
+ private final int flag;
+ PathInfo(int flag) {
+ this.flag = flag;
+ }
+ public int getFlag() {
+ return flag;
+ }
+ static PathInfo valueOf(int flag) {
+ for (PathInfo v : values()) {
+ if (v.flag == flag) {
+ return v;
+ }
+ }
+ return null;
+ }
+ }
+
+ enum EscapeInfo {
+ EXTENSION(0x0000),
+ ANGLE_ELLIPSE_TO(0x0001),
+ ANGLE_ELLIPSE(0x0002),
+ ARC_TO(0x0003),
+ ARC(0x0004),
+ CLOCKWISE_ARC_TO(0x0005),
+ CLOCKWISE_ARC(0x0006),
+ ELLIPTICAL_QUADRANT_X(0x0007),
+ ELLIPTICAL_QUADRANT_Y(0x0008),
+ QUADRATIC_BEZIER(0x0009),
+ NO_FILL(0X000A),
+ NO_LINE(0X000B),
+ AUTO_LINE(0X000C),
+ AUTO_CURVE(0X000D),
+ CORNER_LINE(0X000E),
+ CORNER_CURVE(0X000F),
+ SMOOTH_LINE(0X0010),
+ SMOOTH_CURVE(0X0011),
+ SYMMETRIC_LINE(0X0012),
+ SYMMETRIC_CURVE(0X0013),
+ FREEFORM(0X0014),
+ FILL_COLOR(0X0015),
+ LINE_COLOR(0X0016);
+
+ private final int flag;
+ EscapeInfo(int flag) {
+ this.flag = flag;
+ }
+ public int getFlag() {
+ return flag;
+ }
+ static EscapeInfo valueOf(int flag) {
+ for (EscapeInfo v : values()) {
+ if (v.flag == flag) {
+ return v;
+ }
+ }
+ return null;
+ }
+ }
protected HSLFAutoShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
super(escherRecord, parent);
}
/**
- * Gets adjust value which controls smart resizing of the auto-shape.
+ * Gets adjust value which controls smart resizing of the auto-shape.<p>
*
- * <p>
* The adjustment values are given in shape coordinates:
* the origin is at the top-left, positive-x is to the right, positive-y is down.
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
- * </p>
*
* @param idx the adjust index in the [0, 9] range
* @return the adjustment value
}
/**
- * Sets adjust value which controls smart resizing of the auto-shape.
+ * Sets adjust value which controls smart resizing of the auto-shape.<p>
*
- * <p>
* The adjustment values are given in shape coordinates:
* the origin is at the top-left, positive-x is to the right, positive-y is down.
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
- * </p>
*
* @param idx the adjust index in the [0, 9] range
* @param val the adjustment value
setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
}
+
+ @Override
+ public CustomGeometry getGeometry() {
+ return getGeometry(new Path2D.Double());
+ }
+
+ CustomGeometry getGeometry(Path2D path2D) {
+ final ObjectFactory of = new ObjectFactory();
+ final CTCustomGeometry2D cusGeo = of.createCTCustomGeometry2D();
+ cusGeo.setAvLst(of.createCTGeomGuideList());
+ cusGeo.setGdLst(of.createCTGeomGuideList());
+ cusGeo.setAhLst(of.createCTAdjustHandleList());
+ cusGeo.setCxnLst(of.createCTConnectionSiteList());
+
+ final AbstractEscherOptRecord opt = getEscherOptRecord();
+
+ EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
+ EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
+
+ // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
+
+ //sanity check
+ if(verticesProp == null) {
+ LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
+ return super.getGeometry();
+ }
+ if(segmentsProp == null) {
+ LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
+ return super.getGeometry();
+ }
+
+ final Iterator<byte[]> vertIter = verticesProp.iterator();
+ final Iterator<byte[]> segIter = segmentsProp.iterator();
+ final int[] xyPoints = new int[2];
+ boolean isClosed = false;
+
+ final CTPath2DList pathLst = of.createCTPath2DList();
+ final CTPath2D pathCT = of.createCTPath2D();
+ final List<Object> moveLst = pathCT.getCloseOrMoveToOrLnTo();
+ pathLst.getPath().add(pathCT);
+ cusGeo.setPathLst(pathLst);
+
+ while (segIter.hasNext()) {
+ byte[] segElem = segIter.next();
+ HSLFFreeformShape.PathInfo pi = getPathInfo(segElem);
+ if (pi == null) {
+ continue;
+ }
+ switch (pi) {
+ case escape: {
+ handleEscapeInfo(pathCT, path2D, segElem, vertIter);
+ break;
+ }
+ case moveTo:
+ if (vertIter.hasNext()) {
+ final CTPath2DMoveTo m = of.createCTPath2DMoveTo();
+ m.setPt(fillPoint(vertIter.next(), xyPoints));
+ moveLst.add(m);
+ path2D.moveTo(xyPoints[0], xyPoints[1]);
+ }
+ break;
+ case lineTo:
+ if (vertIter.hasNext()) {
+ final CTPath2DLineTo m = of.createCTPath2DLineTo();
+ m.setPt(fillPoint(vertIter.next(), xyPoints));
+ moveLst.add(m);
+ path2D.lineTo(xyPoints[0], xyPoints[1]);
+ }
+ break;
+ case curveTo: {
+ final CTPath2DCubicBezierTo m = of.createCTPath2DCubicBezierTo();
+ List<CTAdjPoint2D> mLst = m.getPt();
+
+ int[] pts = new int[6];
+
+ for (int i=0; vertIter.hasNext() && i<3; i++) {
+ mLst.add(fillPoint(vertIter.next(), xyPoints));
+ pts[i*2] = xyPoints[0];
+ pts[i*2+1] = xyPoints[1];
+ if (i == 2) {
+ moveLst.add(m);
+ path2D.curveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
+ }
+ }
+ break;
+ }
+ case close:
+ moveLst.add(of.createCTPath2DClose());
+ path2D.closePath();
+ isClosed = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
+ HSLFFreeformShape.ShapePath sp = HSLFFreeformShape.ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
+ if ((sp == HSLFFreeformShape.ShapePath.LINES_CLOSED || sp == HSLFFreeformShape.ShapePath.CURVES_CLOSED) && !isClosed) {
+ moveLst.add(of.createCTPath2DClose());
+ path2D.closePath();
+ }
+
+ EscherSimpleProperty geoLeft = getShapeProp(opt, EscherProperties.GEOMETRY__LEFT);
+ EscherSimpleProperty geoRight = getShapeProp(opt, EscherProperties.GEOMETRY__RIGHT);
+ EscherSimpleProperty geoTop = getShapeProp(opt, EscherProperties.GEOMETRY__TOP);
+ EscherSimpleProperty geoBottom = getShapeProp(opt, EscherProperties.GEOMETRY__BOTTOM);
+
+ final Rectangle2D bounds;
+ if (geoLeft != null && geoRight != null && geoTop != null && geoBottom != null) {
+ bounds = new Rectangle2D.Double();
+ bounds.setFrameFromDiagonal(
+ new Point2D.Double(geoLeft.getPropertyValue(), geoTop.getPropertyValue()),
+ new Point2D.Double(geoRight.getPropertyValue(), geoBottom.getPropertyValue())
+ );
+ } else {
+ bounds = path2D.getBounds2D();
+ }
+
+ pathCT.setW((int)Math.rint(bounds.getWidth()));
+ pathCT.setH((int)Math.rint(bounds.getHeight()));
+
+ return new CustomGeometry(cusGeo);
+ }
+
+ private void handleEscapeInfo(CTPath2D pathCT, Path2D path2D, byte[] segElem, Iterator<byte[]> vertIter) {
+ final ObjectFactory of = new ObjectFactory();
+ HSLFFreeformShape.EscapeInfo ei = getEscapeInfo(segElem);
+ switch (ei) {
+ case EXTENSION:
+ break;
+ case ANGLE_ELLIPSE_TO:
+ break;
+ case ANGLE_ELLIPSE:
+ break;
+ case ARC_TO: {
+ // The first two POINT values specify the bounding rectangle of the ellipse.
+ // The second two POINT values specify the radial vectors for the ellipse.
+ // The radial vectors are cast from the center of the bounding rectangle.
+ // The path starts at the POINT where the first radial vector intersects the
+ // bounding rectangle and goes to the POINT where the second radial vector
+ // intersects the bounding rectangle. The drawing direction is always counterclockwise.
+ // If the path has already been started, a line is drawn from the last POINT to
+ // the starting POINT of the arc; otherwise, a new path is started.
+ // The number of arc segments drawn equals the number of segments divided by four.
+
+ int[] r1 = new int[2], r2 = new int[2], start = new int[2], end = new int[2];
+ fillPoint(vertIter.next(), r1);
+ fillPoint(vertIter.next(), r2);
+ fillPoint(vertIter.next(), start);
+ fillPoint(vertIter.next(), end);
+
+ Arc2D arc2D = new Arc2D.Double();
+ Rectangle2D.Double bounds = new Rectangle2D.Double();
+ bounds.setFrameFromDiagonal(xy2p(r1), xy2p(r2));
+ arc2D.setFrame(bounds);
+ arc2D.setAngles(xy2p(start), xy2p(end));
+ path2D.append(arc2D, true);
+
+
+ CTPath2DArcTo arcTo = of.createCTPath2DArcTo();
+ arcTo.setHR(d2s(bounds.getHeight()/2.0));
+ arcTo.setWR(d2s(bounds.getWidth()/2.0));
+
+ arcTo.setStAng(d2s(-arc2D.getAngleStart()*60000.));
+ arcTo.setSwAng(d2s(-arc2D.getAngleExtent()*60000.));
+
+ pathCT.getCloseOrMoveToOrLnTo().add(arcTo);
+
+ break;
+ }
+ case ARC:
+ break;
+ case CLOCKWISE_ARC_TO:
+ break;
+ case CLOCKWISE_ARC:
+ break;
+ case ELLIPTICAL_QUADRANT_X:
+ break;
+ case ELLIPTICAL_QUADRANT_Y:
+ break;
+ case QUADRATIC_BEZIER:
+ break;
+ case NO_FILL:
+ break;
+ case NO_LINE:
+ break;
+ case AUTO_LINE:
+ break;
+ case AUTO_CURVE:
+ break;
+ case CORNER_LINE:
+ break;
+ case CORNER_CURVE:
+ break;
+ case SMOOTH_LINE:
+ break;
+ case SMOOTH_CURVE:
+ break;
+ case SYMMETRIC_LINE:
+ break;
+ case SYMMETRIC_CURVE:
+ break;
+ case FREEFORM:
+ break;
+ case FILL_COLOR:
+ break;
+ case LINE_COLOR:
+ break;
+ default:
+ break;
+ }
+ }
+
+ private static String d2s(double d) {
+ return Integer.toString((int)Math.rint(d));
+ }
+
+ private static Point2D xy2p(int[] xyPoints) {
+ return new Point2D.Double(xyPoints[0],xyPoints[1]);
+ }
+
+ private static HSLFFreeformShape.PathInfo getPathInfo(byte[] elem) {
+ int elemUS = LittleEndian.getUShort(elem, 0);
+ int pathInfo = PATH_INFO.getValue(elemUS);
+ return HSLFFreeformShape.PathInfo.valueOf(pathInfo);
+ }
+
+ private static HSLFFreeformShape.EscapeInfo getEscapeInfo(byte[] elem) {
+ int elemUS = LittleEndian.getUShort(elem, 0);
+ int escInfo = ESCAPE_INFO.getValue(elemUS);
+ return HSLFFreeformShape.EscapeInfo.valueOf(escInfo);
+ }
+
+
+ private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
+ T prop = getEscherProperty(opt, (short)(propId + 0x4000));
+ if (prop == null) {
+ prop = getEscherProperty(opt, propId);
+ }
+ return prop;
+ }
+
+ private CTAdjPoint2D fillPoint(byte[] xyMaster, int[] xyPoints) {
+ if (xyMaster == null || xyPoints == null) {
+ LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
+ return null;
+ }
+ if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
+ LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
+ return null;
+ }
+
+ int x, y;
+ if (xyMaster.length == 4) {
+ x = LittleEndian.getShort(xyMaster, 0);
+ y = LittleEndian.getShort(xyMaster, 2);
+ } else {
+ x = LittleEndian.getInt(xyMaster, 0);
+ y = LittleEndian.getInt(xyMaster, 4);
+ }
+
+ xyPoints[0] = x;
+ xyPoints[1] = y;
+
+ return toPoint(xyPoints);
+ }
+
+ private static CTAdjPoint2D toPoint(int[] xyPoints) {
+ CTAdjPoint2D pt = new CTAdjPoint2D();
+ pt.setX(Integer.toString(xyPoints[0]));
+ pt.setY(Integer.toString(xyPoints[1]));
+ return pt;
+ }
}
/**
* Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
*/
+@SuppressWarnings("WeakerAccess")
public final class HSLFFill {
private static final POILogger LOG = POILogFactory.getLogger(HSLFFill.class);
/**
* Fill with a solid color
*/
- public static final int FILL_SOLID = 0;
+ static final int FILL_SOLID = 0;
/**
* Fill with a pattern (bitmap)
*/
- public static final int FILL_PATTERN = 1;
+ static final int FILL_PATTERN = 1;
/**
* A texture (pattern with its own color map)
*/
- public static final int FILL_TEXTURE = 2;
+ static final int FILL_TEXTURE = 2;
/**
* Center a picture in the shape
*/
- public static final int FILL_PICTURE = 3;
+ static final int FILL_PICTURE = 3;
/**
* Shade from start to end points
*/
- public static final int FILL_SHADE = 4;
+ static final int FILL_SHADE = 4;
/**
* Shade from bounding rectangle to end point
*/
- public static final int FILL_SHADE_CENTER = 5;
+ static final int FILL_SHADE_CENTER = 5;
/**
* Shade from shape outline to end point
*/
- public static final int FILL_SHADE_SHAPE = 6;
+ static final int FILL_SHADE_SHAPE = 6;
/**
* Similar to FILL_SHADE, but the fill angle
* is additionally scaled by the aspect ratio of
* the shape. If shape is square, it is the same as FILL_SHADE
*/
- public static final int FILL_SHADE_SCALE = 7;
+ static final int FILL_SHADE_SCALE = 7;
/**
* shade to title
*/
- public static final int FILL_SHADE_TITLE = 8;
+ static final int FILL_SHADE_TITLE = 8;
/**
* Use the background fill color/pattern
*/
- public static final int FILL_BACKGROUND = 9;
+ static final int FILL_BACKGROUND = 9;
/**
* A bit that specifies whether the RecolorFillAsPicture bit is set.
private HSLFShape shape;
/**
- * Construct a <code>Fill</code> object for a shape.
+ * Construct a {@code Fill} object for a shape.
* Fill information will be read from shape's escher properties.
*
* @param shape the shape this background applies to
@Override
public ColorStyle[] getGradientColors() {
- ColorStyle cs[];
+ ColorStyle[] cs;
if (colorCnt == 0) {
cs = new ColorStyle[2];
cs[0] = wrapColor(getBackgroundColor());
cs = new ColorStyle[colorCnt];
int idx = 0;
// TODO: handle palette colors and alpha(?) value
- for (byte data[] : ep) {
+ for (byte[] data : ep) {
EscherColorRef ecr = new EscherColorRef(data, 0, 4);
cs[idx++] = wrapColor(shape.getColor(ecr));
}
@Override
public float[] getGradientFractions() {
- float frc[];
+ float[] frc;
if (colorCnt == 0) {
frc = new float[]{0, 1};
} else {
frc = new float[colorCnt];
int idx = 0;
- for (byte data[] : ep) {
+ for (byte[] data : ep) {
double pos = Units.fixedPointToDouble(LittleEndian.getInt(data, 4));
frc[idx++] = (float)pos;
}
/**
* Returns fill type.
- * Must be one of the <code>FILL_*</code> constants defined in this class.
+ * Must be one of the {@code FILL_*} constants defined in this class.
*
* @return type of fill
*/
return prop == null ? FILL_SOLID : prop.getPropertyValue();
}
- /**
- */
- protected void afterInsert(HSLFSheet sh){
+ void afterInsert(HSLFSheet sh){
AbstractEscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
if(p != null) {
}
@SuppressWarnings("resource")
- protected EscherBSERecord getEscherBSERecord(int idx){
+ EscherBSERecord getEscherBSERecord(int idx){
HSLFSheet sheet = shape.getSheet();
if(sheet == null) {
LOG.log(POILogger.DEBUG, "Fill has not yet been assigned to a sheet");
/**
* Sets fill type.
- * Must be one of the <code>FILL_*</code> constants defined in this class.
+ * Must be one of the {@code FILL_*} constants defined in this class.
*
* @param type type of the fill
*/
AbstractEscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
int propVal = (p == null) ? 0 : p.getPropertyValue();
-
+
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
? null
- : shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
+ : shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY);
}
/**
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
? null
- : shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
+ : shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY);
}
/**
}
/**
- * <code>PictureData</code> object used in a texture, pattern of picture fill.
+ * {@code PictureData} object used in a texture, pattern of picture fill.
*/
@SuppressWarnings("resource")
public HSLFPictureData getPictureData(){
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.ddf.EscherArrayProperty;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.sl.usermodel.FreeformShape;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformShape<HSLFShape,HSLFTextParagraph> {
private static final POILogger LOG = POILogFactory.getLogger(HSLFFreeformShape.class);
- private static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};
- private static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};
- private static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};
- private static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};
- private static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};
- // OpenOffice inserts 0xB3 instead of 0xAD.
- // private static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
- private static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};
- private static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};
-
- private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
- // private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
-
- enum PathInfo {
- lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
- private final int flag;
- PathInfo(int flag) {
- this.flag = flag;
- }
- public int getFlag() {
- return flag;
- }
- static PathInfo valueOf(int flag) {
- for (PathInfo v : values()) {
- if (v.flag == flag) {
- return v;
- }
- }
- return null;
- }
- }
-
- enum EscapeInfo {
- EXTENSION(0x0000),
- ANGLE_ELLIPSE_TO(0x0001),
- ANGLE_ELLIPSE(0x0002),
- ARC_TO(0x0003),
- ARC(0x0004),
- CLOCKWISE_ARC_TO(0x0005),
- CLOCKWISE_ARC(0x0006),
- ELLIPTICAL_QUADRANT_X(0x0007),
- ELLIPTICAL_QUADRANT_Y(0x0008),
- QUADRATIC_BEZIER(0x0009),
- NO_FILL(0X000A),
- NO_LINE(0X000B),
- AUTO_LINE(0X000C),
- AUTO_CURVE(0X000D),
- CORNER_LINE(0X000E),
- CORNER_CURVE(0X000F),
- SMOOTH_LINE(0X0010),
- SMOOTH_CURVE(0X0011),
- SYMMETRIC_LINE(0X0012),
- SYMMETRIC_CURVE(0X0013),
- FREEFORM(0X0014),
- FILL_COLOR(0X0015),
- LINE_COLOR(0X0016);
-
- private final int flag;
- EscapeInfo(int flag) {
- this.flag = flag;
- }
- public int getFlag() {
- return flag;
- }
- static EscapeInfo valueOf(int flag) {
- for (EscapeInfo v : values()) {
- if (v.flag == flag) {
- return v;
- }
- }
- return null;
- }
- }
enum ShapePath {
LINES(0),
}
@Override
- public int setPath(Path2D.Double path) {
+ public int setPath(Path2D path) {
Rectangle2D bounds = path.getBounds2D();
- PathIterator it = path.getPathIterator(new AffineTransform());
+ PathIterator it = path.getPathIterator(null);
List<byte[]> segInfo = new ArrayList<>();
List<Point2D.Double> pntInfo = new ArrayList<>();
}
@Override
- public Path2D.Double getPath(){
- AbstractEscherOptRecord opt = getEscherOptRecord();
-
- EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
- EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
-
- // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
- Path2D.Double path = new Path2D.Double();
+ public Path2D getPath(){
+ Path2D path2D = new Path2D.Double();
+ getGeometry(path2D);
- //sanity check
- if(verticesProp == null) {
- LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
- return path;
- }
- if(segmentsProp == null) {
- LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
- return path;
- }
-
- Iterator<byte[]> vertIter = verticesProp.iterator();
- Iterator<byte[]> segIter = segmentsProp.iterator();
- double xyPoints[] = new double[2];
-
- while (vertIter.hasNext() && segIter.hasNext()) {
- byte[] segElem = segIter.next();
- PathInfo pi = getPathInfo(segElem);
- if (pi != null) {
- switch (pi) {
- case escape: {
- // handleEscapeInfo(path, segElem, vertIter);
- break;
- }
- case moveTo: {
- fillPoint(vertIter.next(), xyPoints);
- double x = xyPoints[0];
- double y = xyPoints[1];
- path.moveTo(x, y);
- break;
- }
- case curveTo: {
- fillPoint(vertIter.next(), xyPoints);
- double x1 = xyPoints[0];
- double y1 = xyPoints[1];
- fillPoint(vertIter.next(), xyPoints);
- double x2 = xyPoints[0];
- double y2 = xyPoints[1];
- fillPoint(vertIter.next(), xyPoints);
- double x3 = xyPoints[0];
- double y3 = xyPoints[1];
- path.curveTo(x1, y1, x2, y2, x3, y3);
- break;
- }
- case lineTo:
- if (vertIter.hasNext()) {
- fillPoint(vertIter.next(), xyPoints);
- double x = xyPoints[0];
- double y = xyPoints[1];
- path.lineTo(x, y);
- }
- break;
- case close:
- path.closePath();
- break;
- default:
- break;
- }
- }
- }
-
- EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
- ShapePath sp = ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
- if (sp == ShapePath.LINES_CLOSED || sp == ShapePath.CURVES_CLOSED) {
- path.closePath();
- }
-
+ Rectangle2D bounds = path2D.getBounds2D();
Rectangle2D anchor = getAnchor();
- Rectangle2D bounds = path.getBounds2D();
AffineTransform at = new AffineTransform();
at.translate(anchor.getX(), anchor.getY());
at.scale(
anchor.getWidth()/bounds.getWidth(),
anchor.getHeight()/bounds.getHeight()
);
- return new Path2D.Double(at.createTransformedShape(path));
- }
-
- private void fillPoint(byte xyMaster[], double xyPoints[]) {
- if (xyMaster == null || xyPoints == null) {
- LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
- return;
- }
- if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
- LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
- return;
- }
-
- int x, y;
- if (xyMaster.length == 4) {
- x = LittleEndian.getShort(xyMaster, 0);
- y = LittleEndian.getShort(xyMaster, 2);
- } else {
- x = LittleEndian.getInt(xyMaster, 0);
- y = LittleEndian.getInt(xyMaster, 4);
- }
-
- xyPoints[0] = Units.masterToPoints(x);
- xyPoints[1] = Units.masterToPoints(y);
- }
-
- private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
- T prop = getEscherProperty(opt, (short)(propId + 0x4000));
- if (prop == null) {
- prop = getEscherProperty(opt, propId);
- }
- return prop;
- }
-
-// private void handleEscapeInfo(Path2D path, byte segElem[], Iterator<byte[]> vertIter) {
-// EscapeInfo ei = getEscapeInfo(segElem);
-// switch (ei) {
-// case EXTENSION:
-// break;
-// case ANGLE_ELLIPSE_TO:
-// break;
-// case ANGLE_ELLIPSE:
-// break;
-// case ARC_TO:
-// break;
-// case ARC:
-// break;
-// case CLOCKWISE_ARC_TO:
-// break;
-// case CLOCKWISE_ARC:
-// break;
-// case ELLIPTICAL_QUADRANT_X:
-// break;
-// case ELLIPTICAL_QUADRANT_Y:
-// break;
-// case QUADRATIC_BEZIER:
-// break;
-// case NO_FILL:
-// break;
-// case NO_LINE:
-// break;
-// case AUTO_LINE:
-// break;
-// case AUTO_CURVE:
-// break;
-// case CORNER_LINE:
-// break;
-// case CORNER_CURVE:
-// break;
-// case SMOOTH_LINE:
-// break;
-// case SMOOTH_CURVE:
-// break;
-// case SYMMETRIC_LINE:
-// break;
-// case SYMMETRIC_CURVE:
-// break;
-// case FREEFORM:
-// break;
-// case FILL_COLOR:
-// break;
-// case LINE_COLOR:
-// break;
-// default:
-// break;
-// }
-// }
-
- private static PathInfo getPathInfo(byte elem[]) {
- int elemUS = LittleEndian.getUShort(elem, 0);
- int pathInfo = PATH_INFO.getValue(elemUS);
- return PathInfo.valueOf(pathInfo);
+ path2D.transform(at);
+
+
+ return path2D;
}
-
-// private static EscapeInfo getEscapeInfo(byte elem[]) {
-// int elemUS = LittleEndian.getUShort(elem, 0);
-// int escInfo = ESCAPE_INFO.getValue(elemUS);
-// return EscapeInfo.valueOf(escInfo);
-// }
+
+
}
_sheet = sheet;
}
- Color getColor(short colorProperty, short opacityProperty, int defaultColor){
- AbstractEscherOptRecord opt = getEscherOptRecord();
- EscherSimpleProperty p = getEscherProperty(opt, colorProperty);
- if(p == null && defaultColor == -1) return null;
-
- int val = (p == null) ? defaultColor : p.getPropertyValue();
-
- EscherColorRef ecr = new EscherColorRef(val);
- Color col = getColor(ecr);
- if (col == null) {
- return null;
+ Color getColor(short colorProperty, short opacityProperty){
+ final AbstractEscherOptRecord opt = getEscherOptRecord();
+ final EscherSimpleProperty colProp = getEscherProperty(opt, colorProperty);
+ final Color col;
+ if (colProp == null) {
+ col = Color.WHITE;
+ } else {
+ EscherColorRef ecr = new EscherColorRef(colProp.getPropertyValue());
+ col = getColor(ecr);
+ if (col == null) {
+ return null;
+ }
}
double alpha = getAlpha(opacityProperty);
return null;
}
- Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
+ Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY);
return clr == null ? null : clr;
}
return null;
}
- Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY, -1);
+ Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY);
return clr == null ? null : clr;
}
* @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
*/
public Color getShadowColor(){
- Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY, -1);
+ Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY);
return clr == null ? Color.black : clr;
}
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
- TestBackground.class,
TestFreeform.class,
TestHeadersFooters.class,
TestHyperlink.class,
+++ /dev/null
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You 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 static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.Color;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.ddf.AbstractEscherOptRecord;
-import org.apache.poi.ddf.EscherBSERecord;
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.ddf.EscherRecord;
-import org.apache.poi.ddf.EscherSimpleProperty;
-import org.apache.poi.hslf.HSLFTestDataSamples;
-import org.apache.poi.hslf.record.Document;
-import org.apache.poi.hslf.usermodel.HSLFAutoShape;
-import org.apache.poi.hslf.usermodel.HSLFFill;
-import org.apache.poi.hslf.usermodel.HSLFPictureData;
-import org.apache.poi.hslf.usermodel.HSLFShape;
-import org.apache.poi.hslf.usermodel.HSLFSheet;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.sl.usermodel.PictureData.PictureType;
-import org.apache.poi.sl.usermodel.ShapeType;
-import org.junit.Test;
-
-
-/**
- * Test <code>Fill</code> object.
- *
- * @author Yegor Kozlov
- */
-public final class TestBackground {
- private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
-
- /**
- * Default background for slide, shape and slide master.
- */
- @Test
- public void defaults() throws IOException {
- HSLFSlideShow ppt = new HSLFSlideShow();
-
- assertEquals(HSLFFill.FILL_SOLID, ppt.getSlideMasters().get(0).getBackground().getFill().getFillType());
-
- HSLFSlide slide = ppt.createSlide();
- assertTrue(slide.getFollowMasterBackground());
- assertEquals(HSLFFill.FILL_SOLID, slide.getBackground().getFill().getFillType());
-
- HSLFShape shape = new HSLFAutoShape(ShapeType.RECT);
- assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
- ppt.close();
- }
-
- /**
- * Read fill information from an reference ppt file
- */
- @Test
- public void readBackground() throws IOException {
- HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("backgrounds.ppt");
- HSLFFill fill;
- HSLFShape shape;
-
- List<HSLFSlide> slide = ppt.getSlides();
-
- fill = slide.get(0).getBackground().getFill();
- assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
- shape = slide.get(0).getShapes().get(0);
- assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-
- fill = slide.get(1).getBackground().getFill();
- assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
- shape = slide.get(1).getShapes().get(0);
- assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
-
- fill = slide.get(2).getBackground().getFill();
- assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
- shape = slide.get(2).getShapes().get(0);
- assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
-
- fill = slide.get(3).getBackground().getFill();
- assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
- shape = slide.get(3).getShapes().get(0);
- assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
- ppt.close();
- }
-
- /**
- * Create a ppt with various fill effects
- */
- @Test
- public void backgroundPicture() throws IOException {
- HSLFSlideShow ppt1 = new HSLFSlideShow();
- HSLFSlide slide;
- HSLFFill fill;
- HSLFShape shape;
- HSLFPictureData data;
-
- //slide 1
- slide = ppt1.createSlide();
- slide.setFollowMasterBackground(false);
- fill = slide.getBackground().getFill();
- data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
- fill.setFillType(HSLFFill.FILL_PICTURE);
- fill.setPictureData(data);
-
- shape = new HSLFAutoShape(ShapeType.RECT);
- shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
- fill = shape.getFill();
- fill.setFillType(HSLFFill.FILL_SOLID);
- slide.addShape(shape);
-
- //slide 2
- slide = ppt1.createSlide();
- slide.setFollowMasterBackground(false);
- fill = slide.getBackground().getFill();
- data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
- fill.setFillType(HSLFFill.FILL_PATTERN);
- fill.setPictureData(data);
- fill.setBackgroundColor(Color.green);
- fill.setForegroundColor(Color.red);
-
- shape = new HSLFAutoShape(ShapeType.RECT);
- shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
- fill = shape.getFill();
- fill.setFillType(HSLFFill.FILL_BACKGROUND);
- slide.addShape(shape);
-
- //slide 3
- slide = ppt1.createSlide();
- slide.setFollowMasterBackground(false);
- fill = slide.getBackground().getFill();
- data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
- fill.setFillType(HSLFFill.FILL_TEXTURE);
- fill.setPictureData(data);
-
- shape = new HSLFAutoShape(ShapeType.RECT);
- shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
- fill = shape.getFill();
- fill.setFillType(HSLFFill.FILL_PICTURE);
- data = ppt1.addPicture(_slTests.readFile("clock.jpg"), PictureType.JPEG);
- fill.setPictureData(data);
- slide.addShape(shape);
-
- // slide 4
- slide = ppt1.createSlide();
- slide.setFollowMasterBackground(false);
- fill = slide.getBackground().getFill();
- fill.setFillType(HSLFFill.FILL_SHADE_CENTER);
- fill.setBackgroundColor(Color.white);
- fill.setForegroundColor(Color.darkGray);
-
- shape = new HSLFAutoShape(ShapeType.RECT);
- shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
- fill = shape.getFill();
- fill.setFillType(HSLFFill.FILL_SHADE);
- fill.setBackgroundColor(Color.red);
- fill.setForegroundColor(Color.green);
- slide.addShape(shape);
-
- //serialize and read again
- HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
- List<HSLFSlide> slides = ppt2.getSlides();
-
- fill = slides.get(0).getBackground().getFill();
- assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
- assertEquals(3, getFillPictureRefCount(slides.get(0).getBackground(), fill));
- shape = slides.get(0).getShapes().get(0);
- assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-
- fill = slides.get(1).getBackground().getFill();
- assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
- shape = slides.get(1).getShapes().get(0);
- assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
-
- fill = slides.get(2).getBackground().getFill();
- assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
- assertEquals(3, getFillPictureRefCount(slides.get(2).getBackground(), fill));
- shape = slides.get(2).getShapes().get(0);
- assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
- assertEquals(1, getFillPictureRefCount(shape, fill));
-
- fill = slides.get(3).getBackground().getFill();
- assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
- shape = slides.get(3).getShapes().get(0);
- assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
- ppt2.close();
- ppt1.close();
- }
-
- private int getFillPictureRefCount(HSLFShape shape, HSLFFill fill) {
- AbstractEscherOptRecord opt = shape.getEscherOptRecord();
- EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
- if(p != null) {
- int idx = p.getPropertyValue();
-
- HSLFSheet sheet = shape.getSheet();
- HSLFSlideShow ppt = sheet.getSlideShow();
- Document doc = ppt.getDocumentRecord();
- EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
- EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
- List<EscherRecord> lst = bstore.getChildRecords();
- return ((EscherBSERecord)lst.get(idx-1)).getRef();
- }
- return 0;
- }
-
-}
public void test54188() {
HSLFFreeformShape p = new HSLFFreeformShape();
- Path2D.Double path = p.getPath();
+ Path2D path = p.getPath();
Path2D.Double emptyPath = new Path2D.Double();
assertEquals(emptyPath.getBounds2D(), path.getBounds2D());
}
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestAddingSlides.class,
+ TestBackground.class,
TestBugs.class,
TestCounts.class,
TestMostRecentRecords.class,
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.usermodel;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.ddf.AbstractEscherOptRecord;
+import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.hslf.HSLFTestDataSamples;
+import org.apache.poi.hslf.record.Document;
+import org.apache.poi.hslf.usermodel.HSLFAutoShape;
+import org.apache.poi.hslf.usermodel.HSLFFill;
+import org.apache.poi.hslf.usermodel.HSLFPictureData;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSheet;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.junit.Test;
+
+
+/**
+ * Test <code>Fill</code> object.
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestBackground {
+ private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
+
+ /**
+ * Default background for slide, shape and slide master.
+ */
+ @Test
+ public void defaults() throws IOException {
+ HSLFSlideShow ppt = new HSLFSlideShow();
+
+ assertEquals(HSLFFill.FILL_SOLID, ppt.getSlideMasters().get(0).getBackground().getFill().getFillType());
+
+ HSLFSlide slide = ppt.createSlide();
+ assertTrue(slide.getFollowMasterBackground());
+ assertEquals(HSLFFill.FILL_SOLID, slide.getBackground().getFill().getFillType());
+
+ HSLFShape shape = new HSLFAutoShape(ShapeType.RECT);
+ assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+ ppt.close();
+ }
+
+ /**
+ * Read fill information from an reference ppt file
+ */
+ @Test
+ public void readBackground() throws IOException {
+ HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("backgrounds.ppt");
+ HSLFFill fill;
+ HSLFShape shape;
+
+ List<HSLFSlide> slide = ppt.getSlides();
+
+ fill = slide.get(0).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
+ shape = slide.get(0).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+
+ fill = slide.get(1).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
+ shape = slide.get(1).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
+
+ fill = slide.get(2).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
+ shape = slide.get(2).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
+
+ fill = slide.get(3).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
+ shape = slide.get(3).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
+ ppt.close();
+ }
+
+ /**
+ * Create a ppt with various fill effects
+ */
+ @Test
+ public void backgroundPicture() throws IOException {
+ HSLFSlideShow ppt1 = new HSLFSlideShow();
+ HSLFSlide slide;
+ HSLFFill fill;
+ HSLFShape shape;
+ HSLFPictureData data;
+
+ //slide 1
+ slide = ppt1.createSlide();
+ slide.setFollowMasterBackground(false);
+ fill = slide.getBackground().getFill();
+ data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+ fill.setFillType(HSLFFill.FILL_PICTURE);
+ fill.setPictureData(data);
+
+ shape = new HSLFAutoShape(ShapeType.RECT);
+ shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+ fill = shape.getFill();
+ fill.setFillType(HSLFFill.FILL_SOLID);
+ slide.addShape(shape);
+
+ //slide 2
+ slide = ppt1.createSlide();
+ slide.setFollowMasterBackground(false);
+ fill = slide.getBackground().getFill();
+ data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+ fill.setFillType(HSLFFill.FILL_PATTERN);
+ fill.setPictureData(data);
+ fill.setBackgroundColor(Color.green);
+ fill.setForegroundColor(Color.red);
+
+ shape = new HSLFAutoShape(ShapeType.RECT);
+ shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+ fill = shape.getFill();
+ fill.setFillType(HSLFFill.FILL_BACKGROUND);
+ slide.addShape(shape);
+
+ //slide 3
+ slide = ppt1.createSlide();
+ slide.setFollowMasterBackground(false);
+ fill = slide.getBackground().getFill();
+ data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+ fill.setFillType(HSLFFill.FILL_TEXTURE);
+ fill.setPictureData(data);
+
+ shape = new HSLFAutoShape(ShapeType.RECT);
+ shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+ fill = shape.getFill();
+ fill.setFillType(HSLFFill.FILL_PICTURE);
+ data = ppt1.addPicture(_slTests.readFile("clock.jpg"), PictureType.JPEG);
+ fill.setPictureData(data);
+ slide.addShape(shape);
+
+ // slide 4
+ slide = ppt1.createSlide();
+ slide.setFollowMasterBackground(false);
+ fill = slide.getBackground().getFill();
+ fill.setFillType(HSLFFill.FILL_SHADE_CENTER);
+ fill.setBackgroundColor(Color.white);
+ fill.setForegroundColor(Color.darkGray);
+
+ shape = new HSLFAutoShape(ShapeType.RECT);
+ shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+ fill = shape.getFill();
+ fill.setFillType(HSLFFill.FILL_SHADE);
+ fill.setBackgroundColor(Color.red);
+ fill.setForegroundColor(Color.green);
+ slide.addShape(shape);
+
+ //serialize and read again
+ HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
+ List<HSLFSlide> slides = ppt2.getSlides();
+
+ fill = slides.get(0).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
+ assertEquals(3, getFillPictureRefCount(slides.get(0).getBackground(), fill));
+ shape = slides.get(0).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+
+ fill = slides.get(1).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
+ shape = slides.get(1).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
+
+ fill = slides.get(2).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
+ assertEquals(3, getFillPictureRefCount(slides.get(2).getBackground(), fill));
+ shape = slides.get(2).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
+ assertEquals(1, getFillPictureRefCount(shape, fill));
+
+ fill = slides.get(3).getBackground().getFill();
+ assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
+ shape = slides.get(3).getShapes().get(0);
+ assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
+ ppt2.close();
+ ppt1.close();
+ }
+
+ private int getFillPictureRefCount(HSLFShape shape, HSLFFill fill) {
+ AbstractEscherOptRecord opt = shape.getEscherOptRecord();
+ EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
+ if(p != null) {
+ int idx = p.getPropertyValue();
+
+ HSLFSheet sheet = shape.getSheet();
+ HSLFSlideShow ppt = sheet.getSlideShow();
+ Document doc = ppt.getDocumentRecord();
+ EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
+ EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
+ List<EscherRecord> lst = bstore.getChildRecords();
+ return ((EscherBSERecord)lst.get(idx-1)).getRef();
+ }
+ return 0;
+ }
+
+}