Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

RenderableShape.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.xslf.usermodel;
  20. import org.apache.poi.openxml4j.opc.PackagePart;
  21. import org.apache.poi.openxml4j.opc.PackageRelationship;
  22. import org.apache.poi.util.Internal;
  23. import org.apache.poi.util.Units;
  24. import org.apache.poi.xslf.model.PropertyFetcher;
  25. import org.apache.poi.xslf.model.geom.Context;
  26. import org.apache.poi.xslf.model.geom.CustomGeometry;
  27. import org.apache.poi.xslf.model.geom.Guide;
  28. import org.apache.poi.xslf.model.geom.IAdjustableShape;
  29. import org.apache.poi.xslf.model.geom.Outline;
  30. import org.apache.poi.xslf.model.geom.Path;
  31. import org.apache.xmlbeans.XmlObject;
  32. import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
  33. import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
  34. import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
  35. import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties;
  36. import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientStop;
  37. import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
  38. import org.openxmlformats.schemas.drawingml.x2006.main.CTNoFillProperties;
  39. import org.openxmlformats.schemas.drawingml.x2006.main.CTPathShadeProperties;
  40. import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
  41. import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
  42. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
  43. import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
  44. import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
  45. import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
  46. import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
  47. import java.awt.AlphaComposite;
  48. import java.awt.BasicStroke;
  49. import java.awt.Color;
  50. import java.awt.GradientPaint;
  51. import java.awt.Graphics2D;
  52. import java.awt.Paint;
  53. import java.awt.Shape;
  54. import java.awt.Stroke;
  55. import java.awt.TexturePaint;
  56. import java.awt.geom.AffineTransform;
  57. import java.awt.geom.Point2D;
  58. import java.awt.geom.Rectangle2D;
  59. import java.awt.image.BufferedImage;
  60. import java.lang.reflect.Constructor;
  61. import java.util.ArrayList;
  62. import java.util.Arrays;
  63. import java.util.Collection;
  64. import java.util.Comparator;
  65. import java.util.List;
  66. /**
  67. * Encapsulates logic to translate DrawingML objects to Java2D
  68. */
  69. @Internal
  70. class RenderableShape {
  71. public final static Color NO_PAINT = new Color(0xFF, 0xFF, 0xFF, 0);
  72. private XSLFSimpleShape _shape;
  73. public RenderableShape(XSLFSimpleShape shape){
  74. _shape = shape;
  75. }
  76. /**
  77. * Convert shape fill into java.awt.Paint. The result is either Color or
  78. * TexturePaint or GradientPaint or null
  79. *
  80. * @param graphics the target graphics
  81. * @param obj the xml to read. Must contain elements from the EG_ColorChoice group:
  82. * <code>
  83. * a:scrgbClr RGB Color Model - Percentage Variant
  84. * a:srgbClr RGB Color Model - Hex Variant
  85. * a:hslClr Hue, Saturation, Luminance Color Model
  86. * a:sysClr System Color
  87. * a:schemeClr Scheme Color
  88. * a:prstClr Preset Color
  89. * </code>
  90. *
  91. * @param phClr context color
  92. * @param parentPart the parent package part. Any external references (images, etc.) are resolved relative to it.
  93. *
  94. * @return the applied Paint or null if none was applied
  95. */
  96. public Paint selectPaint(Graphics2D graphics, XmlObject obj, CTSchemeColor phClr, PackagePart parentPart) {
  97. XSLFTheme theme = _shape.getSheet().getTheme();
  98. Rectangle2D anchor = _shape.getAnchor();
  99. Paint paint = null;
  100. if (obj instanceof CTNoFillProperties) {
  101. paint = NO_PAINT;
  102. }
  103. else if (obj instanceof CTSolidColorFillProperties) {
  104. CTSolidColorFillProperties solidFill = (CTSolidColorFillProperties) obj;
  105. XSLFColor c = new XSLFColor(solidFill, theme, phClr);
  106. paint = c.getColor();
  107. }
  108. else if (obj instanceof CTBlipFillProperties) {
  109. CTBlipFillProperties blipFill = (CTBlipFillProperties)obj;
  110. paint = createTexturePaint(blipFill, graphics, parentPart);
  111. }
  112. else if (obj instanceof CTGradientFillProperties) {
  113. CTGradientFillProperties gradFill = (CTGradientFillProperties) obj;
  114. if (gradFill.isSetLin()) {
  115. paint = createLinearGradientPaint(graphics, gradFill, anchor, theme, phClr);
  116. } else if (gradFill.isSetPath()){
  117. CTPathShadeProperties ps = gradFill.getPath();
  118. if(ps.getPath() == STPathShadeType.CIRCLE){
  119. paint = createRadialGradientPaint(gradFill, anchor, theme, phClr);
  120. } else if (ps.getPath() == STPathShadeType.SHAPE){
  121. paint = toRadialGradientPaint(gradFill, anchor, theme, phClr);
  122. }
  123. }
  124. }
  125. return paint;
  126. }
  127. private Paint createTexturePaint(CTBlipFillProperties blipFill, Graphics2D graphics,
  128. PackagePart parentPart){
  129. Paint paint = null;
  130. CTBlip blip = blipFill.getBlip();
  131. String blipId = blip.getEmbed();
  132. PackageRelationship rel = parentPart.getRelationship(blipId);
  133. if (rel != null) {
  134. XSLFImageRendener renderer = null;
  135. if (graphics != null)
  136. renderer = (XSLFImageRendener) graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER);
  137. if (renderer == null) renderer = new XSLFImageRendener();
  138. try {
  139. BufferedImage img = renderer.readImage(parentPart.getRelatedPart(rel));
  140. if (blip.sizeOfAlphaModFixArray() > 0) {
  141. float alpha = blip.getAlphaModFixArray(0).getAmt() / 100000.f;
  142. AlphaComposite ac = AlphaComposite.getInstance(
  143. AlphaComposite.SRC_OVER, alpha);
  144. if (graphics != null) graphics.setComposite(ac);
  145. }
  146. if(img != null) {
  147. paint = new TexturePaint(
  148. img, new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
  149. }
  150. }
  151. catch (Exception e) {
  152. e.printStackTrace();
  153. }
  154. }
  155. return paint;
  156. }
  157. private Paint createLinearGradientPaint(
  158. Graphics2D graphics,
  159. CTGradientFillProperties gradFill, Rectangle2D anchor,
  160. XSLFTheme theme, CTSchemeColor phClr) {
  161. double angle = gradFill.getLin().getAng() / 60000;
  162. CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
  163. Arrays.sort(gs, new Comparator<CTGradientStop>() {
  164. public int compare(CTGradientStop o1, CTGradientStop o2) {
  165. Integer pos1 = o1.getPos();
  166. Integer pos2 = o2.getPos();
  167. return pos1.compareTo(pos2);
  168. }
  169. });
  170. Color[] colors = new Color[gs.length];
  171. float[] fractions = new float[gs.length];
  172. AffineTransform at = AffineTransform.getRotateInstance(
  173. Math.toRadians(angle),
  174. anchor.getX() + anchor.getWidth() / 2,
  175. anchor.getY() + anchor.getHeight() / 2);
  176. double diagonal = Math.sqrt(anchor.getHeight() * anchor.getHeight() + anchor.getWidth() * anchor.getWidth());
  177. Point2D p1 = new Point2D.Double(anchor.getX() + anchor.getWidth() / 2 - diagonal / 2,
  178. anchor.getY() + anchor.getHeight() / 2);
  179. p1 = at.transform(p1, null);
  180. Point2D p2 = new Point2D.Double(anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight() / 2);
  181. p2 = at.transform(p2, null);
  182. snapToAnchor(p1, anchor);
  183. snapToAnchor(p2, anchor);
  184. for (int i = 0; i < gs.length; i++) {
  185. CTGradientStop stop = gs[i];
  186. colors[i] = new XSLFColor(stop, theme, phClr).getColor();
  187. fractions[i] = stop.getPos() / 100000.f;
  188. }
  189. AffineTransform grAt = new AffineTransform();
  190. if(gradFill.isSetRotWithShape() || !gradFill.getRotWithShape()) {
  191. double rotation = _shape.getRotation();
  192. if (rotation != 0.) {
  193. double centerX = anchor.getX() + anchor.getWidth() / 2;
  194. double centerY = anchor.getY() + anchor.getHeight() / 2;
  195. grAt.translate(centerX, centerY);
  196. grAt.rotate(Math.toRadians(-rotation));
  197. grAt.translate(-centerX, -centerY);
  198. }
  199. }
  200. // Trick to return GradientPaint on JDK 1.5 and LinearGradientPaint on JDK 1.6+
  201. Paint paint;
  202. try {
  203. Class clz = Class.forName("java.awt.LinearGradientPaint");
  204. Class clzCycleMethod = Class.forName("java.awt.MultipleGradientPaint$CycleMethod");
  205. Class clzColorSpaceType = Class.forName("java.awt.MultipleGradientPaint$ColorSpaceType");
  206. Constructor c =
  207. clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class,
  208. clzCycleMethod, clzColorSpaceType, AffineTransform.class);
  209. paint = (Paint) c.newInstance(p1, p2, fractions, colors,
  210. Enum.valueOf(clzCycleMethod, "NO_CYCLE"),
  211. Enum.valueOf(clzColorSpaceType, "SRGB"), grAt);
  212. } catch (ClassNotFoundException e) {
  213. paint = new GradientPaint(p1, colors[0], p2, colors[colors.length - 1]);
  214. } catch (Exception e) {
  215. throw new RuntimeException(e);
  216. }
  217. return paint;
  218. }
  219. /**
  220. * gradients with type=shape are enot supported by Java graphics.
  221. * We approximate it with a radial gradient.
  222. */
  223. private static Paint toRadialGradientPaint(
  224. CTGradientFillProperties gradFill, Rectangle2D anchor,
  225. XSLFTheme theme, CTSchemeColor phClr) {
  226. CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
  227. Arrays.sort(gs, new Comparator<CTGradientStop>() {
  228. public int compare(CTGradientStop o1, CTGradientStop o2) {
  229. Integer pos1 = o1.getPos();
  230. Integer pos2 = o2.getPos();
  231. return pos1.compareTo(pos2);
  232. }
  233. });
  234. gs[1].setPos(50000);
  235. CTGradientFillProperties g = CTGradientFillProperties.Factory.newInstance();
  236. g.set(gradFill);
  237. g.getGsLst().setGsArray(new CTGradientStop[]{gs[0], gs[1]});
  238. return createRadialGradientPaint(g, anchor, theme, phClr);
  239. }
  240. private static Paint createRadialGradientPaint(
  241. CTGradientFillProperties gradFill, Rectangle2D anchor,
  242. XSLFTheme theme, CTSchemeColor phClr) {
  243. CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
  244. Point2D pCenter = new Point2D.Double(anchor.getX() + anchor.getWidth()/2,
  245. anchor.getY() + anchor.getHeight()/2);
  246. float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
  247. Arrays.sort(gs, new Comparator<CTGradientStop>() {
  248. public int compare(CTGradientStop o1, CTGradientStop o2) {
  249. Integer pos1 = o1.getPos();
  250. Integer pos2 = o2.getPos();
  251. return pos1.compareTo(pos2);
  252. }
  253. });
  254. Color[] colors = new Color[gs.length];
  255. float[] fractions = new float[gs.length];
  256. for (int i = 0; i < gs.length; i++) {
  257. CTGradientStop stop = gs[i];
  258. colors[i] = new XSLFColor(stop, theme, phClr).getColor();
  259. fractions[i] = stop.getPos() / 100000.f;
  260. }
  261. // Trick to return GradientPaint on JDK 1.5 and RadialGradientPaint on JDK 1.6+
  262. Paint paint;
  263. try {
  264. Class clz = Class.forName("java.awt.RadialGradientPaint");
  265. Constructor c =
  266. clz.getConstructor(Point2D.class, float.class,
  267. float[].class, Color[].class);
  268. paint = (Paint) c.newInstance(pCenter, radius, fractions, colors);
  269. } catch (ClassNotFoundException e) {
  270. // the result on JDK 1.5 is incorrect, but it is better than nothing
  271. paint = new GradientPaint(
  272. new Point2D.Double(anchor.getX(), anchor.getY()),
  273. colors[0], pCenter, colors[colors.length - 1]);
  274. } catch (Exception e) {
  275. throw new RuntimeException(e);
  276. }
  277. return paint;
  278. }
  279. private static void snapToAnchor(Point2D p, Rectangle2D anchor) {
  280. if (p.getX() < anchor.getX()) {
  281. p.setLocation(anchor.getX(), p.getY());
  282. } else if (p.getX() > (anchor.getX() + anchor.getWidth())) {
  283. p.setLocation(anchor.getX() + anchor.getWidth(), p.getY());
  284. }
  285. if (p.getY() < anchor.getY()) {
  286. p.setLocation(p.getX(), anchor.getY());
  287. } else if (p.getY() > (anchor.getY() + anchor.getHeight())) {
  288. p.setLocation(p.getX(), anchor.getY() + anchor.getHeight());
  289. }
  290. }
  291. @SuppressWarnings("deprecation") // getXYZArray() array accessors are deprecated
  292. Paint getPaint(Graphics2D graphics, XmlObject spPr, CTSchemeColor phClr) {
  293. Paint paint = null;
  294. for (XmlObject obj : spPr.selectPath("*")) {
  295. paint = selectPaint(graphics, obj, phClr, _shape.getSheet().getPackagePart());
  296. if(paint != null) break;
  297. }
  298. return paint == NO_PAINT ? null : paint;
  299. }
  300. /**
  301. * fetch shape fill as a java.awt.Paint
  302. *
  303. * @return either Color or GradientPaint or TexturePaint or null
  304. */
  305. Paint getFillPaint(final Graphics2D graphics) {
  306. PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>() {
  307. public boolean fetch(XSLFSimpleShape shape) {
  308. CTShapeProperties spPr = shape.getSpPr();
  309. if (spPr.isSetNoFill()) {
  310. setValue(RenderableShape.NO_PAINT); // use it as 'nofill' value
  311. return true;
  312. }
  313. Paint paint = getPaint(graphics, spPr, null);
  314. if (paint != null) {
  315. setValue(paint);
  316. return true;
  317. }
  318. return false;
  319. }
  320. };
  321. _shape.fetchShapeProperty(fetcher);
  322. Paint paint = fetcher.getValue();
  323. if (paint == null) {
  324. // fill color was not found, check if it is defined in the theme
  325. CTShapeStyle style = _shape.getSpStyle();
  326. if (style != null) {
  327. // get a reference to a fill style within the style matrix.
  328. CTStyleMatrixReference fillRef = style.getFillRef();
  329. // The idx attribute refers to the index of a fill style or
  330. // background fill style within the presentation's style matrix, defined by the fmtScheme element.
  331. // value of 0 or 1000 indicates no background,
  332. // values 1-999 refer to the index of a fill style within the fillStyleLst element
  333. // values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
  334. int idx = (int)fillRef.getIdx();
  335. CTSchemeColor phClr = fillRef.getSchemeClr();
  336. XSLFSheet sheet = _shape.getSheet();
  337. XSLFTheme theme = sheet.getTheme();
  338. XmlObject fillProps = null;
  339. if(idx >= 1 && idx <= 999){
  340. fillProps = theme.getXmlObject().
  341. getThemeElements().getFmtScheme().getFillStyleLst().selectPath("*")[idx - 1];
  342. } else if (idx >= 1001 ){
  343. fillProps = theme.getXmlObject().
  344. getThemeElements().getFmtScheme().getBgFillStyleLst().selectPath("*")[idx - 1001];
  345. }
  346. if(fillProps != null) {
  347. paint = selectPaint(graphics, fillProps, phClr, sheet.getPackagePart());
  348. }
  349. }
  350. }
  351. return paint == RenderableShape.NO_PAINT ? null : paint;
  352. }
  353. public Paint getLinePaint(final Graphics2D graphics) {
  354. PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>() {
  355. public boolean fetch(XSLFSimpleShape shape) {
  356. CTLineProperties spPr = shape.getSpPr().getLn();
  357. if (spPr != null) {
  358. if (spPr.isSetNoFill()) {
  359. setValue(NO_PAINT); // use it as 'nofill' value
  360. return true;
  361. }
  362. Paint paint = getPaint(graphics, spPr, null);
  363. if (paint != null) {
  364. setValue(paint);
  365. return true;
  366. }
  367. }
  368. return false;
  369. }
  370. };
  371. _shape.fetchShapeProperty(fetcher);
  372. Paint paint = fetcher.getValue();
  373. if (paint == null) {
  374. // line color was not found, check if it is defined in the theme
  375. CTShapeStyle style = _shape.getSpStyle();
  376. if (style != null) {
  377. // get a reference to a line style within the style matrix.
  378. CTStyleMatrixReference lnRef = style.getLnRef();
  379. int idx = (int)lnRef.getIdx();
  380. CTSchemeColor phClr = lnRef.getSchemeClr();
  381. if(idx > 0){
  382. XSLFTheme theme = _shape.getSheet().getTheme();
  383. XmlObject lnProps = theme.getXmlObject().
  384. getThemeElements().getFmtScheme().getLnStyleLst().selectPath("*")[idx - 1];
  385. paint = getPaint(graphics, lnProps, phClr);
  386. }
  387. }
  388. }
  389. return paint == NO_PAINT ? null : paint;
  390. }
  391. /**
  392. * convert PPT dash into java.awt.BasicStroke
  393. *
  394. * The mapping is derived empirically on PowerPoint 2010
  395. */
  396. private static float[] getDashPattern(LineDash lineDash, float lineWidth) {
  397. float[] dash = null;
  398. switch (lineDash) {
  399. case SYS_DOT:
  400. dash = new float[]{lineWidth, lineWidth};
  401. break;
  402. case SYS_DASH:
  403. dash = new float[]{2 * lineWidth, 2 * lineWidth};
  404. break;
  405. case DASH:
  406. dash = new float[]{3 * lineWidth, 4 * lineWidth};
  407. break;
  408. case DASH_DOT:
  409. dash = new float[]{4 * lineWidth, 3 * lineWidth, lineWidth,
  410. 3 * lineWidth};
  411. break;
  412. case LG_DASH:
  413. dash = new float[]{8 * lineWidth, 3 * lineWidth};
  414. break;
  415. case LG_DASH_DOT:
  416. dash = new float[]{8 * lineWidth, 3 * lineWidth, lineWidth,
  417. 3 * lineWidth};
  418. break;
  419. case LG_DASH_DOT_DOT:
  420. dash = new float[]{8 * lineWidth, 3 * lineWidth, lineWidth,
  421. 3 * lineWidth, lineWidth, 3 * lineWidth};
  422. break;
  423. }
  424. return dash;
  425. }
  426. public Stroke applyStroke(Graphics2D graphics) {
  427. float lineWidth = (float) _shape.getLineWidth();
  428. if(lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt
  429. Number fontScale = (Number)graphics.getRenderingHint(XSLFRenderingHint.GROUP_SCALE);
  430. if(fontScale != null) lineWidth *= fontScale.floatValue();
  431. LineDash lineDash = _shape.getLineDash();
  432. float[] dash = null;
  433. float dash_phase = 0;
  434. if (lineDash != null) {
  435. dash = getDashPattern(lineDash, lineWidth);
  436. }
  437. int cap = BasicStroke.CAP_BUTT;
  438. LineCap lineCap = _shape.getLineCap();
  439. if (lineCap != null) {
  440. switch (lineCap) {
  441. case ROUND:
  442. cap = BasicStroke.CAP_ROUND;
  443. break;
  444. case SQUARE:
  445. cap = BasicStroke.CAP_SQUARE;
  446. break;
  447. default:
  448. cap = BasicStroke.CAP_BUTT;
  449. break;
  450. }
  451. }
  452. int meter = BasicStroke.JOIN_ROUND;
  453. Stroke stroke = new BasicStroke(lineWidth, cap, meter, Math.max(1, lineWidth), dash,
  454. dash_phase);
  455. graphics.setStroke(stroke);
  456. return stroke;
  457. }
  458. public void render(Graphics2D graphics){
  459. Collection<Outline> elems = computeOutlines();
  460. // shadow
  461. XSLFShadow shadow = _shape.getShadow();
  462. // first fill
  463. Paint fill = getFillPaint(graphics);
  464. Paint line = getLinePaint(graphics);
  465. applyStroke(graphics); // the stroke applies both to the shadow and the shape
  466. // first paint the shadow
  467. if(shadow != null) for(Outline o : elems){
  468. if(o.getPath().isFilled()){
  469. if(fill != null) shadow.fill(graphics, o.getOutline());
  470. else if(line != null) shadow.draw(graphics, o.getOutline());
  471. }
  472. }
  473. // then fill the shape interior
  474. if(fill != null) for(Outline o : elems){
  475. if(o.getPath().isFilled()){
  476. graphics.setPaint(fill);
  477. graphics.fill(o.getOutline());
  478. }
  479. }
  480. // then draw any content within this shape (text, image, etc.)
  481. _shape.drawContent(graphics);
  482. // then stroke the shape outline
  483. if(line != null) for(Outline o : elems){
  484. if(o.getPath().isStroked()){
  485. graphics.setPaint(line);
  486. graphics.draw(o.getOutline());
  487. }
  488. }
  489. }
  490. private Collection<Outline> computeOutlines() {
  491. Collection<Outline> lst = new ArrayList<Outline>();
  492. CustomGeometry geom = _shape.getGeometry();
  493. if(geom == null) {
  494. return lst;
  495. }
  496. Rectangle2D anchor = _shape.getAnchor();
  497. for (Path p : geom) {
  498. double w = p.getW() == -1 ? anchor.getWidth() * Units.EMU_PER_POINT : p.getW();
  499. double h = p.getH() == -1 ? anchor.getHeight() * Units.EMU_PER_POINT : p.getH();
  500. // the guides in the shape definitions are all defined relative to each other,
  501. // so we build the path starting from (0,0).
  502. final Rectangle2D pathAnchor = new Rectangle2D.Double(
  503. 0,
  504. 0,
  505. w,
  506. h
  507. );
  508. Context ctx = new Context(geom, pathAnchor, new IAdjustableShape() {
  509. public Guide getAdjustValue(String name) {
  510. CTPresetGeometry2D prst = _shape.getSpPr().getPrstGeom();
  511. if (prst.isSetAvLst()) {
  512. for (CTGeomGuide g : prst.getAvLst().getGdList()) {
  513. if (g.getName().equals(name)) {
  514. return new Guide(g);
  515. }
  516. }
  517. }
  518. return null;
  519. }
  520. }) ;
  521. Shape gp = p.getPath(ctx);
  522. // translate the result to the canvas coordinates in points
  523. AffineTransform at = new AffineTransform();
  524. at.translate(anchor.getX(), anchor.getY());
  525. double scaleX, scaleY;
  526. if (p.getW() != -1) {
  527. scaleX = anchor.getWidth() / p.getW();
  528. } else {
  529. scaleX = 1.0 / Units.EMU_PER_POINT;
  530. }
  531. if (p.getH() != -1) {
  532. scaleY = anchor.getHeight() / p.getH();
  533. } else {
  534. scaleY = 1.0 / Units.EMU_PER_POINT;
  535. }
  536. at.scale(scaleX, scaleY);
  537. Shape canvasShape = at.createTransformedShape(gp);
  538. lst.add(new Outline(canvasShape, p));
  539. }
  540. return lst;
  541. }
  542. }