Author: kiwiwings
Date: Wed May 16 20:30:53 2018
New Revision: 1831743
URL: http://svn.apache.org/viewvc?rev=1831743&view=rev
Log:
#62381 - Fix rendering of AutoShapes
Modified:
poi/site/src/documentation/content/xdocs/status.xml
poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java
poi/trunk/src/java/org/apache/poi/sl/draw/geom/Context.java
poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1831743&r1=1831742&r2=1831743&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Wed May 16 20:30:53 2018
@@ -68,6 +68,7 @@
<summary-item>Provide new ooxml-schemas-1.4.jar</summary-item>
</summary>
<actions>
+ <action dev="PD" type="fix" fixes-bug="62381" module="SL Common">Fix rendering
of AutoShapes</action>
<action dev="PD" type="fix" fixes-bug="59893" module="POI Overall">Forbid calls
to InputStream.available</action>
<action dev="PD" type="fix" fixes-bug="61905" module="HSSF">HSSFWorkbook.setActiveCell()
does not actually make the cell selected in Excel</action>
<action dev="PD" type="fix" fixes-bug="61459" module="HSLF">HSLFShape.getShapeName()
returns name of shapeType and not the shape name</action>
Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java?rev=1831743&r1=1831742&r2=1831743&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java Wed May 16 20:30:53 2018
@@ -45,8 +45,8 @@ public class DrawShape implements Drawab
* @param shape the shape to render
* @return {@code true} if HSLF implementation is used
*/
- protected static boolean isHSLF(Shape<?,?> shape) {
- return shape.getClass().getCanonicalName().toLowerCase(Locale.ROOT).contains("hslf");
+ static boolean isHSLF(Object shape) {
+ return shape.getClass().getName().toLowerCase(Locale.ROOT).contains("hslf");
}
/**
@@ -60,21 +60,19 @@ public class DrawShape implements Drawab
return;
}
- PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape;
+ final PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape;
final boolean isHSLF = isHSLF(shape);
- AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
- if (tx == null) {
- tx = new AffineTransform();
- }
- // we saw one document failing here, probably the format is slightly broken, but
- // maybe better to try to handle it more gracefully
- java.awt.Shape transformedShape = tx.createTransformedShape(ps.getAnchor());
- if(transformedShape == null) {
- return;
+ final Rectangle2D anchor = getAnchor(graphics, ps);
+
+ if (shape.getShapeName().startsWith("rotate")) {
+ System.out.println(String.format("%s x: %.3f y: %.3f cx: %.3f cy: %.3f / x: %.3f
y: %.3f cx: %.3f cy: %.3f ",
+ shape.getShapeName(), shape.getAnchor().getX(), shape.getAnchor().getY(),
+ shape.getAnchor().getWidth(), shape.getAnchor().getHeight(),
+ anchor.getX(), anchor.getY(), anchor.getWidth(), anchor.getHeight()
+ ));
}
- final Rectangle2D anchor = transformedShape.getBounds2D();
char cmds[] = isHSLF ? new char[]{ 'h','v','r' } : new char[]{ 'r','h','v' };
for (char ch : cmds) {
@@ -103,61 +101,10 @@ public class DrawShape implements Drawab
double centerX = anchor.getCenterX();
double centerY = anchor.getCenterY();
- // normalize rotation
- rotation %= 360.;
- if (rotation < 0) {
- rotation += 360.;
- }
-
- int quadrant = (((int)rotation+45)/90)%4;
- double scaleX = 1.0, scaleY = 1.0;
-
- // scale to bounding box (bug #53176)
- if (quadrant == 1 || quadrant == 3) {
- // In quadrant 1 and 3, which is basically a shape in a more or less
portrait orientation
- // (45-135 degrees and 225-315 degrees), we need to first rotate
the shape by a multiple
- // of 90 degrees and then resize the bounding box to its original
bbox. After that we can
- // rotate the shape to the exact rotation amount.
- // It's strange that you'll need to rotate the shape back and forth
again, but you can
- // think of it, as if you paint the shape on a canvas. First you
rotate the canvas, which might
- // be already (differently) scaled, so you can paint the shape in
its default orientation
- // and later on, turn it around again to compare it with its original
size ...
-
- AffineTransform txs;
- if (isHSLF) {
- txs = new AffineTransform(tx);
- } else {
- // this handling is only based on try and error ... not sure
why xslf is handled differently.
- txs = new AffineTransform();
- txs.translate(centerX, centerY);
- txs.rotate(Math.PI/2.); // actually doesn't matter if +/- 90
degrees
- txs.translate(-centerX, -centerY);
- txs.concatenate(tx);
- }
-
- txs.translate(centerX, centerY);
- txs.rotate(Math.PI/2.);
- txs.translate(-centerX, -centerY);
-
- Rectangle2D anchor2 = txs.createTransformedShape(ps.getAnchor()).getBounds2D();
-
- scaleX = safeScale(anchor.getWidth(), anchor2.getWidth());
- scaleY = safeScale(anchor.getHeight(), anchor2.getHeight());
- } else {
- quadrant = 0;
- }
// transformation is applied reversed ...
graphics.translate(centerX, centerY);
- double rot = Math.toRadians(rotation-quadrant*90.);
- if (rot != 0) {
- graphics.rotate(rot);
- }
- graphics.scale(scaleX, scaleY);
- rot = Math.toRadians(quadrant*90.);
- if (rot != 0) {
- graphics.rotate(rot);
- }
+ graphics.rotate(Math.toRadians(rotation));
graphics.translate(-centerX, -centerY);
}
break;
@@ -183,7 +130,85 @@ public class DrawShape implements Drawab
}
public static Rectangle2D getAnchor(Graphics2D graphics, PlaceableShape<?,?> shape)
{
- return getAnchor(graphics, shape.getAnchor());
+// return getAnchor(graphics, shape.getAnchor());
+
+ final boolean isHSLF = isHSLF(shape);
+ AffineTransform tx = graphics == null ? null : (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
+ if (tx == null) {
+ tx = new AffineTransform();
+ }
+
+ final double rotation = ((shape.getRotation() % 360.) + 360.) % 360.;
+ final int quadrant = (((int)rotation+45)/90)%4;
+
+ final Rectangle2D normalizedShape;
+
+ // scale to bounding box (bug #53176)
+ if (quadrant == 1 || quadrant == 3) {
+ // In a rotated quadrant 1 (=45-135 degrees) and 3 (=225-315 degrees), which
is basically a shape in a
+ // more or less portrait orientation, Powerpoint doesn't use the normal shape
anchor,
+ // but rotate it 90 degress and apply the group transformations.
+ // We try to revert that distortion and return the normalized anchor.
+ // It's strange that you'll need to rotate the shape back and forth again, but
you can
+ // think of it, as if you paint the shape on a canvas. First you rotate the canvas,
which might
+ // be already (differently) scaled, so you can paint the shape in its default
orientation
+ // and later on, turn it around again to compare it with its original size ...
+
+
+ final Rectangle2D shapeAnchor = shape.getAnchor();
+ final Rectangle2D anchorO = tx.createTransformedShape(shapeAnchor).getBounds2D();
+
+ final Rectangle2D anchorT;
+ {
+ final double centerX = anchorO.getCenterX();
+ final double centerY = anchorO.getCenterY();
+ final AffineTransform txs2 = new AffineTransform();
+
+ // this handling is only based on try and error ... not sure why h/xslf is
handled differently.
+
+ if (!isHSLF) {
+ txs2.translate(centerX, centerY);
+ txs2.quadrantRotate(1);
+ txs2.translate(-centerX, -centerY);
+ txs2.concatenate(tx);
+ }
+
+ txs2.translate(centerX, centerY);
+ txs2.quadrantRotate(3);
+ txs2.translate(-centerX, -centerY);
+
+ if (isHSLF) {
+ txs2.concatenate(tx);
+ }
+
+ anchorT = txs2.createTransformedShape(shapeAnchor).getBounds2D();
+ }
+
+ final double scaleX2 = safeScale(anchorO.getWidth(), anchorT.getWidth());
+ final double scaleY2 = safeScale(anchorO.getHeight(), anchorT.getHeight());
+
+ {
+ double centerX = shapeAnchor.getCenterX();
+ double centerY = shapeAnchor.getCenterY();
+ final AffineTransform txs2 = new AffineTransform();
+ txs2.translate(centerX, centerY);
+ // no need to rotate back and forth, just apply scaling inverted
+ txs2.scale(scaleY2, scaleX2);
+ txs2.translate(-centerX, -centerY);
+
+ normalizedShape = txs2.createTransformedShape(shapeAnchor).getBounds2D();
+ }
+ } else {
+ normalizedShape = shape.getAnchor();
+ }
+
+ if (tx.isIdentity()) {
+ return normalizedShape;
+ }
+
+
+ final java.awt.Shape anc = tx.createTransformedShape(normalizedShape);
+ return (anc != null) ? anc.getBounds2D() : normalizedShape;
}
public static Rectangle2D getAnchor(Graphics2D graphics, Rectangle2D anchor) {
Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/Context.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/Context.java?rev=1831743&r1=1831742&r2=1831743&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/Context.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/Context.java Wed May 16 20:30:53 2018
@@ -44,7 +44,8 @@ public class Context {
}
public Guide getAdjustValue(String name){
- return _props.getAdjustValue(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){
Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java?rev=1831743&r1=1831742&r2=1831743&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java Wed May 16
20:30:53 2018
@@ -65,7 +65,7 @@ implements XSLFShapeContainer, GroupShap
protected XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){
super(shape,sheet);
- _shapes = XSLFSheet.buildShapes(shape, sheet);
+ _shapes = XSLFSheet.buildShapes(shape, this);
_grpSpPr = shape.getGrpSpPr();
}
Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java?rev=1831743&r1=1831742&r2=1831743&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java Wed May 16 20:30:53
2018
@@ -105,7 +105,9 @@ implements XSLFShapeContainer, Sheet<XSL
throw new IllegalStateException("SlideShow was not found");
}
- protected static List<XSLFShape> buildShapes(CTGroupShape spTree, XSLFSheet sheet){
+ protected static List<XSLFShape> buildShapes(CTGroupShape spTree, XSLFShapeContainer
parent){
+ final XSLFSheet sheet = (parent instanceof XSLFSheet) ? (XSLFSheet)parent : ((XSLFShape)parent).getSheet();
+
List<XSLFShape> shapes = new ArrayList<>();
XmlCursor cur = spTree.newCursor();
try {
@@ -133,7 +135,7 @@ implements XSLFShapeContainer, Sheet<XSL
if (cur.toChild(PackageNamespaces.MARKUP_COMPATIBILITY, "Choice") &&
cur.toFirstChild()) {
try {
CTGroupShape grp = CTGroupShape.Factory.parse(cur.newXMLStreamReader());
- shapes.addAll(buildShapes(grp, sheet));
+ shapes.addAll(buildShapes(grp, parent));
} catch (XmlException e) {
LOG.log(POILogger.DEBUG, "unparsable alternate content", e);
}
@@ -145,6 +147,10 @@ implements XSLFShapeContainer, Sheet<XSL
cur.dispose();
}
+ for (final XSLFShape s : shapes) {
+ s.setParent(parent);
+ }
+
return shapes;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org
|