if (!(shape instanceof PlaceableShape)) return;\r
\r
PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape;\r
+ final boolean isHSLF = ps.getClass().getCanonicalName().toLowerCase(Locale.ROOT).contains("hslf");\r
AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);\r
if (tx == null) tx = new AffineTransform();\r
final Rectangle2D anchor = tx.createTransformedShape(ps.getAnchor()).getBounds2D();\r
\r
- // rotation\r
- double rotation = ps.getRotation();\r
- if (rotation != 0.) {\r
- // PowerPoint rotates shapes relative to the geometric center\r
- double centerX = anchor.getCenterX();\r
- double centerY = anchor.getCenterY();\r
-\r
- // normalize rotation\r
- rotation %= 360.;\r
- if (rotation < 0) rotation += 360.;\r
-\r
- int quadrant = (((int)rotation+45)/90)%4;\r
- double scaleX = 1.0, scaleY = 1.0;\r
-\r
- // scale to bounding box (bug #53176)\r
- if (quadrant == 1 || quadrant == 3) {\r
- // In quadrant 1 and 3, which is basically a shape in a more or less portrait orientation\r
- // (45-135 degrees and 225-315 degrees), we need to first rotate the shape by a multiple\r
- // of 90 degrees and then resize the bounding box to its original bbox. After that we can\r
- // rotate the shape to the exact rotation amount.\r
- // It's strange that you'll need to rotate the shape back and forth again, but you can\r
- // think of it, as if you paint the shape on a canvas. First you rotate the canvas, which might\r
- // be already (differently) scaled, so you can paint the shape in its default orientation\r
- // and later on, turn it around again to compare it with its original size ...\r
-\r
- AffineTransform txs;\r
- if (ps.getClass().getCanonicalName().toLowerCase(Locale.ROOT).contains("hslf")) {\r
- txs = new AffineTransform(tx);\r
- } else {\r
- // this handling is only based on try and error ... not sure why xslf is handled differently.\r
- txs = new AffineTransform();\r
- txs.translate(centerX, centerY);\r
- txs.rotate(Math.PI/2.); // actually doesn't matter if +/- 90 degrees\r
- txs.translate(-centerX, -centerY);\r
- txs.concatenate(tx);\r
+ char cmds[] = isHSLF ? new char[]{ 'h','v','r' } : new char[]{ 'r','h','v' };\r
+ for (char ch : cmds) {\r
+ switch (ch) {\r
+ case 'h':\r
+ //flip horizontal\r
+ if (ps.getFlipHorizontal()) {\r
+ graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());\r
+ graphics.scale(-1, 1);\r
+ graphics.translate(-anchor.getX(), -anchor.getY());\r
}\r
-\r
- txs.translate(centerX, centerY);\r
- txs.rotate(Math.PI/2.);\r
- txs.translate(-centerX, -centerY);\r
-\r
- Rectangle2D anchor2 = txs.createTransformedShape(ps.getAnchor()).getBounds2D();\r
-\r
- scaleX = safeScale(anchor.getWidth(), anchor2.getWidth());\r
- scaleY = safeScale(anchor.getHeight(), anchor2.getHeight());\r
- } else {\r
- quadrant = 0;\r
- }\r
-\r
- // transformation is applied reversed ...\r
- graphics.translate(centerX, centerY);\r
- double rot = Math.toRadians(rotation-quadrant*90.);\r
- if (rot != 0) {\r
- graphics.rotate(rot);\r
- }\r
- graphics.scale(scaleX, scaleY);\r
- rot = Math.toRadians(quadrant*90);\r
- if (rot != 0) {\r
- graphics.rotate(rot);\r
+ break;\r
+ case 'v':\r
+ //flip vertical\r
+ if (ps.getFlipVertical()) {\r
+ graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());\r
+ graphics.scale(1, -1);\r
+ graphics.translate(-anchor.getX(), -anchor.getY());\r
+ }\r
+ break;\r
+ case 'r':\r
+ // rotation\r
+ double rotation = ps.getRotation();\r
+ if (rotation != 0.) {\r
+ // PowerPoint rotates shapes relative to the geometric center\r
+ double centerX = anchor.getCenterX();\r
+ double centerY = anchor.getCenterY();\r
+\r
+ // normalize rotation\r
+ rotation %= 360.;\r
+ if (rotation < 0) rotation += 360.;\r
+\r
+ int quadrant = (((int)rotation+45)/90)%4;\r
+ double scaleX = 1.0, scaleY = 1.0;\r
+\r
+ // scale to bounding box (bug #53176)\r
+ if (quadrant == 1 || quadrant == 3) {\r
+ // In quadrant 1 and 3, which is basically a shape in a more or less portrait orientation\r
+ // (45-135 degrees and 225-315 degrees), we need to first rotate the shape by a multiple\r
+ // of 90 degrees and then resize the bounding box to its original bbox. After that we can\r
+ // rotate the shape to the exact rotation amount.\r
+ // It's strange that you'll need to rotate the shape back and forth again, but you can\r
+ // think of it, as if you paint the shape on a canvas. First you rotate the canvas, which might\r
+ // be already (differently) scaled, so you can paint the shape in its default orientation\r
+ // and later on, turn it around again to compare it with its original size ...\r
+\r
+ AffineTransform txs;\r
+ if (isHSLF) {\r
+ txs = new AffineTransform(tx);\r
+ } else {\r
+ // this handling is only based on try and error ... not sure why xslf is handled differently.\r
+ txs = new AffineTransform();\r
+ txs.translate(centerX, centerY);\r
+ txs.rotate(Math.PI/2.); // actually doesn't matter if +/- 90 degrees\r
+ txs.translate(-centerX, -centerY);\r
+ txs.concatenate(tx);\r
+ }\r
+\r
+ txs.translate(centerX, centerY);\r
+ txs.rotate(Math.PI/2.);\r
+ txs.translate(-centerX, -centerY);\r
+\r
+ Rectangle2D anchor2 = txs.createTransformedShape(ps.getAnchor()).getBounds2D();\r
+\r
+ scaleX = safeScale(anchor.getWidth(), anchor2.getWidth());\r
+ scaleY = safeScale(anchor.getHeight(), anchor2.getHeight());\r
+ } else {\r
+ quadrant = 0;\r
+ }\r
+\r
+ // transformation is applied reversed ...\r
+ graphics.translate(centerX, centerY);\r
+ double rot = Math.toRadians(rotation-quadrant*90.);\r
+ if (rot != 0) {\r
+ graphics.rotate(rot);\r
+ }\r
+ graphics.scale(scaleX, scaleY);\r
+ rot = Math.toRadians(quadrant*90);\r
+ if (rot != 0) {\r
+ graphics.rotate(rot);\r
+ }\r
+ graphics.translate(-centerX, -centerY);\r
+ }\r
+ break;\r
}\r
- graphics.translate(-centerX, -centerY);\r
- }\r
-\r
- //flip horizontal\r
- if (ps.getFlipHorizontal()) {\r
- graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());\r
- graphics.scale(-1, 1);\r
- graphics.translate(-anchor.getX(), -anchor.getY());\r
- }\r
-\r
- //flip vertical\r
- if (ps.getFlipVertical()) {\r
- graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());\r
- graphics.scale(1, -1);\r
- graphics.translate(-anchor.getX(), -anchor.getY());\r
}\r
}\r
\r
EscherArrayProperty verticesProp = new EscherArrayProperty((short)(EscherProperties.GEOMETRY__VERTICES + 0x4000), false, null);
verticesProp.setNumberOfElementsInArray(pntInfo.size());
verticesProp.setNumberOfElementsInMemory(pntInfo.size());
- verticesProp.setSizeOfElements(0xFFF0);
+ verticesProp.setSizeOfElements(8);
for (int i = 0; i < pntInfo.size(); i++) {
Point2D.Double pnt = pntInfo.get(i);
- byte[] data = new byte[4];
- LittleEndian.putShort(data, 0, (short)Units.pointsToMaster(pnt.getX() - bounds.getX()));
- LittleEndian.putShort(data, 2, (short)Units.pointsToMaster(pnt.getY() - bounds.getY()));
+ byte[] data = new byte[8];
+ LittleEndian.putInt(data, 0, Units.pointsToMaster(pnt.getX() - bounds.getX()));
+ LittleEndian.putInt(data, 4, Units.pointsToMaster(pnt.getY() - bounds.getY()));
verticesProp.setElement(i, data);
}
opt.addEscherProperty(verticesProp);
Iterator<byte[]> vertIter = verticesProp.iterator();
Iterator<byte[]> segIter = segmentsProp.iterator();
+ double xyPoints[] = new double[2];
while (vertIter.hasNext() && segIter.hasNext()) {
byte[] segElem = segIter.next();
break;
}
case moveTo: {
- byte[] p = vertIter.next();
- double x = Units.masterToPoints(LittleEndian.getShort(p, 0));
- double y = Units.masterToPoints(LittleEndian.getShort(p, 2));
+ fillPoint(vertIter.next(), xyPoints);
+ double x = xyPoints[0];
+ double y = xyPoints[1];
path.moveTo(x,y);
break;
}
case curveTo: {
- byte[] p1 = vertIter.next();
- double x1 = Units.masterToPoints(LittleEndian.getShort(p1, 0));
- double y1 = Units.masterToPoints(LittleEndian.getShort(p1, 2));
- byte[] p2 = vertIter.next();
- double x2 = Units.masterToPoints(LittleEndian.getShort(p2, 0));
- double y2 = Units.masterToPoints(LittleEndian.getShort(p2, 2));
- byte[] p3 = vertIter.next();
- double x3 = Units.masterToPoints(LittleEndian.getShort(p3, 0));
- double y3 = Units.masterToPoints(LittleEndian.getShort(p3, 2));
+ 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()) {
- byte[] p = vertIter.next();
- double x = Units.masterToPoints(LittleEndian.getShort(p, 0));
- double y = Units.masterToPoints(LittleEndian.getShort(p, 2));
+ fillPoint(vertIter.next(), xyPoints);
+ double x = xyPoints[0];
+ double y = xyPoints[1];
path.lineTo(x,y);
}
break;
return new Path2D.Double(at.createTransformedShape(path));
}
+ private void fillPoint(byte xyMaster[], double xyPoints[]) {
+ if (xyMaster == null || xyPoints == null || (xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
+ logger.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) {