From 7bf8c0afbe73c037b199feef406e2cdf676b3467 Mon Sep 17 00:00:00 2001 From: Yegor Kozlov Date: Mon, 14 Apr 2008 09:21:57 +0000 Subject: [PATCH] misc usermodel improvements. Also added the source code for the ApacheconEU08 FFT presentation git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@647713 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hslf/examples/ApacheconEU08.java | 515 ++++++++++++++++++ .../src/org/apache/poi/hslf/model/Fill.java | 11 +- .../org/apache/poi/hslf/model/Freeform.java | 149 +++++ .../apache/poi/hslf/model/PPGraphics2D.java | 122 +---- .../org/apache/poi/hslf/model/Picture.java | 5 +- .../src/org/apache/poi/hslf/model/Shape.java | 14 +- .../org/apache/poi/hslf/model/ShapeGroup.java | 3 +- .../apache/poi/hslf/model/SimpleShape.java | 30 +- .../org/apache/poi/hslf/model/TextBox.java | 3 +- .../poi/hslf/model/TestPPGraphics2D.java | 2 +- 10 files changed, 716 insertions(+), 138 deletions(-) create mode 100755 src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java create mode 100755 src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java new file mode 100755 index 000000000..0f28c2a8c --- /dev/null +++ b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java @@ -0,0 +1,515 @@ + +/* ==================================================================== + 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.examples; + +import org.apache.poi.hslf.usermodel.*; +import org.apache.poi.hslf.model.*; +import org.apache.poi.hslf.record.TextHeaderAtom; + +import java.io.IOException; +import java.io.FileOutputStream; +import java.io.File; +import java.awt.*; + +/** + * Presentation for Fast Feather Track on ApacheconEU 2008 + * + * @author Yegor Kozlov + */ +public class ApacheconEU08 { + + public static void main(String[] args) throws IOException { + SlideShow ppt = new SlideShow(); + ppt.setPageSize(new Dimension(720, 540)); + + slide1(ppt); + slide2(ppt); + slide3(ppt); + slide4(ppt); + slide5(ppt); + slide6(ppt); + slide7(ppt); + slide8(ppt); + slide9(ppt); + slide10(ppt); + slide11(ppt); + slide12(ppt); + + FileOutputStream out = new FileOutputStream("apachecon_eu_08.ppt"); + ppt.write(out); + out.close(); + + } + + public static void slide1(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.CENTER_TITLE_TYPE); + tr1.setText("POI-HSLF"); + box1.setAnchor(new Rectangle(54, 78, 612, 115)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.setRunType(TextHeaderAtom.CENTRE_BODY_TYPE); + tr2.setText("Java API To Access Microsoft PowerPoint Format Files"); + box2.setAnchor(new Rectangle(108, 204, 504, 138)); + slide.addShape(box2); + + TextBox box3 = new TextBox(); + TextRun tr3 = box3.getTextRun(); + tr3.getRichTextRuns()[0].setFontSize(32); + box3.setHorizontalAlignment(TextBox.AlignCenter); + tr3.setText( + "Yegor Kozlov\r" + + "yegor - apache - org"); + box3.setAnchor(new Rectangle(206, 348, 310, 84)); + slide.addShape(box3); + } + + public static void slide2(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.TITLE_TYPE); + tr1.setText("What is HSLF?"); + box1.setAnchor(new Rectangle(36, 21, 648, 90)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.setRunType(TextHeaderAtom.BODY_TYPE); + tr2.setText("HorribleSLideshowFormat is the POI Project's pure Java implementation " + + "of the Powerpoint binary file format. \r" + + "POI sub-project since 2005\r" + + "Started by Nick Birch, Yegor Kozlov joined soon after"); + box2.setAnchor(new Rectangle(36, 126, 648, 356)); + slide.addShape(box2); + + + } + + public static void slide3(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.TITLE_TYPE); + tr1.setText("HSLF in a Nutshell"); + box1.setAnchor(new Rectangle(36, 15, 648, 65)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.setRunType(TextHeaderAtom.BODY_TYPE); + tr2.setText( + "HSLF provides a way to read, create and modify MS PowerPoint presentations\r" + + "Pure Java API - you don't need PowerPoint to read and write *.ppt files\r" + + "Comprehensive support of PowerPoint objects"); + tr2.getRichTextRuns()[0].setFontSize(28); + box2.setAnchor(new Rectangle(36, 80, 648, 200)); + slide.addShape(box2); + + TextBox box3 = new TextBox(); + TextRun tr3 = box3.getTextRun(); + tr3.setRunType(TextHeaderAtom.BODY_TYPE); + tr3.setText( + "Rich text\r" + + "Tables\r" + + "Shapes\r" + + "Pictures\r" + + "Master slides"); + tr3.getRichTextRuns()[0].setFontSize(24); + tr3.getRichTextRuns()[0].setIndentLevel(1); + box3.setAnchor(new Rectangle(36, 265, 648, 150)); + slide.addShape(box3); + + TextBox box4 = new TextBox(); + TextRun tr4 = box4.getTextRun(); + tr4.setRunType(TextHeaderAtom.BODY_TYPE); + tr4.setText("Access to low level data structures"); + box4.setAnchor(new Rectangle(36, 430, 648, 50)); + slide.addShape(box4); + } + + public static void slide4(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + String[][] txt1 = { + {"Note"}, + {"This presentation was created programmatically using POI HSLF"} + }; + Table table1 = new Table(2, 1); + for (int i = 0; i < txt1.length; i++) { + for (int j = 0; j < txt1[i].length; j++) { + TableCell cell = table1.getCell(i, j); + cell.setText(txt1[i][j]); + cell.getTextRun().getRichTextRuns()[0].setFontSize(10); + RichTextRun rt = cell.getTextRun().getRichTextRuns()[0]; + rt.setFontName("Arial"); + rt.setBold(true); + if(i == 0){ + rt.setFontSize(32); + rt.setFontColor(Color.white); + cell.getFill().setForegroundColor(new Color(0, 153, 204)); + } else { + rt.setFontSize(28); + cell.getFill().setForegroundColor(new Color(235, 239, 241)); + } + cell.setVerticalAlignment(TextBox.AnchorMiddle); + } + } + + Line border1 = table1.createBorder(); + border1.setLineColor(Color.black); + border1.setLineWidth(1.0); + table1.setAllBorders(border1); + + Line border2 = table1.createBorder(); + border2.setLineColor(Color.black); + border2.setLineWidth(2.0); + table1.setOutsideBorders(border2); + + table1.setColumnWidth(0, 510); + table1.setRowHeight(0, 60); + table1.setRowHeight(1, 100); + slide.addShape(table1); + + table1.moveTo(100, 100); + + TextBox box1 = new TextBox(); + box1.setHorizontalAlignment(TextBox.AlignCenter); + TextRun tr1 = box1.getTextRun(); + tr1.setText("The source code is available at\r" + + "http://people.apache.org/~yegor/apachecon_eu08/"); + RichTextRun rt = tr1.getRichTextRuns()[0]; + rt.setFontSize(24); + box1.setAnchor(new Rectangle(80, 356, 553, 65)); + slide.addShape(box1); + + } + + public static void slide5(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.TITLE_TYPE); + tr1.setText("HSLF in Action - 1\rData Extraction"); + box1.setAnchor(new Rectangle(36, 21, 648, 100)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.setRunType(TextHeaderAtom.BODY_TYPE); + tr2.setText( + "Text from slides and notes\r" + + "Images\r" + + "Shapes and their properties (type, position in the slide, color, font, etc.)"); + box2.setAnchor(new Rectangle(36, 150, 648, 300)); + slide.addShape(box2); + + + } + + public static void slide6(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.TITLE_TYPE); + tr1.setText("HSLF in Action - 2"); + box1.setAnchor(new Rectangle(36, 20, 648, 90)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.getRichTextRuns()[0].setFontSize(18); + tr2.setText("Creating a simple presentation from scratch"); + box2.setAnchor(new Rectangle(170, 100, 364, 30)); + slide.addShape(box2); + + TextBox box3 = new TextBox(); + TextRun tr3 = box3.getTextRun(); + RichTextRun rt3 = tr3.getRichTextRuns()[0]; + rt3.setFontName("Courier New"); + rt3.setFontSize(8); + tr3.setText( + " SlideShow ppt = new SlideShow();\r" + + " Slide slide = ppt.createSlide();\r" + + "\r" + + " TextBox box2 = new TextBox();\r" + + " box2.setHorizontalAlignment(TextBox.AlignCenter);\r" + + " box2.setVerticalAlignment(TextBox.AnchorMiddle);\r" + + " box2.getTextRun().setText(\"Java Code\");\r" + + " box2.getFill().setForegroundColor(new Color(187, 224, 227));\r" + + " box2.setLineColor(Color.black);\r" + + " box2.setLineWidth(0.75);\r" + + " box2.setAnchor(new Rectangle(66, 243, 170, 170));\r" + + " slide.addShape(box2);\r" + + "\r" + + " TextBox box3 = new TextBox();\r" + + " box3.setHorizontalAlignment(TextBox.AlignCenter);\r" + + " box3.setVerticalAlignment(TextBox.AnchorMiddle);\r" + + " box3.getTextRun().setText(\"*.ppt file\");\r" + + " box3.setLineWidth(0.75);\r" + + " box3.setLineColor(Color.black);\r" + + " box3.getFill().setForegroundColor(new Color(187, 224, 227));\r" + + " box3.setAnchor(new Rectangle(473, 243, 170, 170));\r" + + " slide.addShape(box3);\r" + + "\r" + + " AutoShape box4 = new AutoShape(ShapeTypes.Arrow);\r" + + " box4.getFill().setForegroundColor(new Color(187, 224, 227));\r" + + " box4.setLineWidth(0.75);\r" + + " box4.setLineColor(Color.black);\r" + + " box4.setAnchor(new Rectangle(253, 288, 198, 85));\r" + + " slide.addShape(box4);\r" + + "\r" + + " FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\r" + + " ppt.write(out);\r" + + " out.close();"); + box3.setAnchor(new Rectangle(30, 150, 618, 411)); + slide.addShape(box3); + } + + public static void slide7(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box2 = new TextBox(); + box2.setHorizontalAlignment(TextBox.AlignCenter); + box2.setVerticalAlignment(TextBox.AnchorMiddle); + box2.getTextRun().setText("Java Code"); + box2.getFill().setForegroundColor(new Color(187, 224, 227)); + box2.setLineColor(Color.black); + box2.setLineWidth(0.75); + box2.setAnchor(new Rectangle(66, 243, 170, 170)); + slide.addShape(box2); + + TextBox box3 = new TextBox(); + box3.setHorizontalAlignment(TextBox.AlignCenter); + box3.setVerticalAlignment(TextBox.AnchorMiddle); + box3.getTextRun().setText("*.ppt file"); + box3.setLineWidth(0.75); + box3.setLineColor(Color.black); + box3.getFill().setForegroundColor(new Color(187, 224, 227)); + box3.setAnchor(new Rectangle(473, 243, 170, 170)); + slide.addShape(box3); + + AutoShape box4 = new AutoShape(ShapeTypes.Arrow); + box4.getFill().setForegroundColor(new Color(187, 224, 227)); + box4.setLineWidth(0.75); + box4.setLineColor(Color.black); + box4.setAnchor(new Rectangle(253, 288, 198, 85)); + slide.addShape(box4); + } + + public static void slide8(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.TITLE_TYPE); + tr1.setText("Wait, there is more!"); + box1.setAnchor(new Rectangle(36, 21, 648, 90)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.setRunType(TextHeaderAtom.BODY_TYPE); + tr2.setText( + "Rich text\r" + + "Tables\r" + + "Pictures (JPEG, PNG, BMP, WMF, PICT)\r" + + "Comprehensive formatting features"); + box2.setAnchor(new Rectangle(36, 126, 648, 356)); + slide.addShape(box2); + } + + public static void slide9(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.TITLE_TYPE); + tr1.setText("HSLF in Action - 3"); + box1.setAnchor(new Rectangle(36, 20, 648, 50)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.getRichTextRuns()[0].setFontSize(18); + tr2.setText("PPGraphics2D: PowerPoint Graphics2D driver"); + box2.setAnchor(new Rectangle(178, 70, 387, 30)); + slide.addShape(box2); + + TextBox box3 = new TextBox(); + TextRun tr3 = box3.getTextRun(); + RichTextRun rt3 = tr3.getRichTextRuns()[0]; + rt3.setFontName("Courier New"); + rt3.setFontSize(8); + tr3.setText( + " //bar chart data. The first value is the bar color, the second is the width\r" + + " Object[] def = new Object[]{\r" + + " Color.yellow, new Integer(100),\r" + + " Color.green, new Integer(150),\r" + + " Color.gray, new Integer(75),\r" + + " Color.red, new Integer(200),\r" + + " };\r" + + "\r" + + " SlideShow ppt = new SlideShow();\r" + + " Slide slide = ppt.createSlide();\r" + + "\r" + + " ShapeGroup group = new ShapeGroup();\r" + + " //define position of the drawing in the slide\r" + + " Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);\r" + + " group.setAnchor(bounds);\r" + + " slide.addShape(group);\r" + + " Graphics2D graphics = new PPGraphics2D(group);\r" + + "\r" + + " //draw a simple bar graph\r" + + " int x = bounds.x + 50, y = bounds.y + 50;\r" + + " graphics.setFont(new Font(\"Arial\", Font.BOLD, 10));\r" + + " for (int i = 0, idx = 1; i < def.length; i+=2, idx++) {\r" + + " graphics.setColor(Color.black);\r" + + " int width = ((Integer)def[i+1]).intValue();\r" + + " graphics.drawString(\"Q\" + idx, x-20, y+20);\r" + + " graphics.drawString(width + \"%\", x + width + 10, y + 20);\r" + + " graphics.setColor((Color)def[i]);\r" + + " graphics.fill(new Rectangle(x, y, width, 30));\r" + + " y += 40;\r" + + " }\r" + + " graphics.setColor(Color.black);\r" + + " graphics.setFont(new Font(\"Arial\", Font.BOLD, 14));\r" + + " graphics.draw(bounds);\r" + + " graphics.drawString(\"Performance\", x + 70, y + 40);\r" + + "\r" + + " FileOutputStream out = new FileOutputStream(\"hslf-demo.ppt\");\r" + + " ppt.write(out);\r" + + " out.close();"); + box3.setAnchor(new Rectangle(96, 110, 499, 378)); + slide.addShape(box3); + } + + public static void slide10(SlideShow ppt) throws IOException { + //bar chart data. The first value is the bar color, the second is the width + Object[] def = new Object[]{ + Color.yellow, new Integer(100), + Color.green, new Integer(150), + Color.gray, new Integer(75), + Color.red, new Integer(200), + }; + + Slide slide = ppt.createSlide(); + + ShapeGroup group = new ShapeGroup(); + //define position of the drawing in the slide + Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300); + group.setAnchor(bounds); + slide.addShape(group); + Graphics2D graphics = new PPGraphics2D(group); + + //draw a simple bar graph + int x = bounds.x + 50, y = bounds.y + 50; + graphics.setFont(new Font("Arial", Font.BOLD, 10)); + for (int i = 0, idx = 1; i < def.length; i+=2, idx++) { + graphics.setColor(Color.black); + int width = ((Integer)def[i+1]).intValue(); + graphics.drawString("Q" + idx, x-20, y+20); + graphics.drawString(width + "%", x + width + 10, y + 20); + graphics.setColor((Color)def[i]); + graphics.fill(new Rectangle(x, y, width, 30)); + y += 40; + } + graphics.setColor(Color.black); + graphics.setFont(new Font("Arial", Font.BOLD, 14)); + graphics.draw(bounds); + graphics.drawString("Performance", x + 70, y + 40); + + } + + public static void slide11(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.TITLE_TYPE); + tr1.setText("HSLF Development Plans"); + box1.setAnchor(new Rectangle(36, 21, 648, 90)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.setRunType(TextHeaderAtom.BODY_TYPE); + tr2.setText( + "Support for more PowerPoint functionality\r" + + "Rendering slides into java.awt.Graphics2D"); + box2.setAnchor(new Rectangle(36, 126, 648, 100)); + slide.addShape(box2); + + TextBox box3 = new TextBox(); + TextRun tr3 = box3.getTextRun(); + tr3.setRunType(TextHeaderAtom.BODY_TYPE); + tr3.getRichTextRuns()[0].setIndentLevel(1); + tr3.setText( + "A way to export slides into images or other formats"); + box3.setAnchor(new Rectangle(36, 220, 648, 70)); + slide.addShape(box3); + + TextBox box4 = new TextBox(); + TextRun tr4 = box4.getTextRun(); + tr4.setRunType(TextHeaderAtom.BODY_TYPE); + tr4.setText( + "Integration with Apache FOP - Formatting Objects Processor"); + box4.setAnchor(new Rectangle(36, 290, 648, 90)); + slide.addShape(box4); + + TextBox box5 = new TextBox(); + TextRun tr5 = box5.getTextRun(); + tr5.setRunType(TextHeaderAtom.BODY_TYPE); + tr5.getRichTextRuns()[0].setIndentLevel(1); + tr5.setText( + "Transformation of XSL-FO into PPT\r" + + "PPT2PDF transcoder"); + box5.setAnchor(new Rectangle(36, 380, 648, 100)); + slide.addShape(box5); + } + + public static void slide12(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); + + TextBox box1 = new TextBox(); + TextRun tr1 = box1.getTextRun(); + tr1.setRunType(TextHeaderAtom.CENTER_TITLE_TYPE); + tr1.setText("Questions?"); + box1.setAnchor(new Rectangle(54, 167, 612, 115)); + slide.addShape(box1); + + TextBox box2 = new TextBox(); + TextRun tr2 = box2.getTextRun(); + tr2.setRunType(TextHeaderAtom.CENTRE_BODY_TYPE); + tr2.setText( + "http://poi.apache.org/hslf/\r" + + "http://people.apache.org/~yegor"); + box2.setAnchor(new Rectangle(108, 306, 504, 138)); + slide.addShape(box2); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java index f9cc43a7e..436b5188f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java @@ -23,8 +23,8 @@ import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.usermodel.PictureData; import org.apache.poi.hslf.usermodel.SlideShow; import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.util.POILogger; -import org.apache.poi.util.POILogFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.awt.*; import java.util.*; @@ -36,7 +36,7 @@ import java.util.*; */ public class Fill { // For logging - protected POILogger logger = POILogFactory.getLogger(this.getClass()); + protected Log log = LogFactory.getLog(this.getClass()); /** * Fill with a solid color @@ -154,8 +154,7 @@ public class Fill { public void setForegroundColor(Color color){ EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID); if (color == null) { - Shape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, -1); - Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150010); + Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150000); } else { int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); @@ -214,7 +213,7 @@ public class Fill { java.util.List lst = bstore.getChildRecords(); int idx = p.getPropertyValue(); if (idx == 0){ - logger.log(POILogger.ERROR, "no reference to picture data found "); + log.error("no reference to picture data found "); } else { EscherBSERecord bse = (EscherBSERecord)lst.get(idx - 1); for ( int i = 0; i < pict.length; i++ ) { diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java b/src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java new file mode 100755 index 000000000..502363346 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java @@ -0,0 +1,149 @@ +/* ==================================================================== + 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 org.apache.poi.ddf.*; +import org.apache.poi.util.LittleEndian; + +import java.awt.geom.*; +import java.util.ArrayList; + +/** + * A "Freeform" shape. + * + *

+ * Shapes drawn with the "Freeform" tool have cubic bezier curve segments in the smooth sections + * and straight-line segments in the straight sections. This object closely corresponds to java.awt.geom.GeneralPath. + *

+ * @author Yegor Kozlov + */ +public class Freeform extends AutoShape { + /** + * Create a Freeform object and initialize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected Freeform(EscherContainerRecord escherRecord, Shape parent){ + super(escherRecord, parent); + + } + + /** + * Create a new Freeform. This constructor is used when a new shape is created. + * + * @param parent the parent of this Shape. For example, if this text box is a cell + * in a table then the parent is Table. + */ + public Freeform(Shape parent){ + super(null, parent); + _escherContainer = createSpContainer(ShapeTypes.NotPrimitive, parent instanceof ShapeGroup); + } + + /** + * Create a new Freeform. This constructor is used when a new shape is created. + * + */ + public Freeform(){ + this(null); + } + + /** + * Set the shape path + * + * @param path + */ + public void setPath(GeneralPath path) + { + Rectangle2D bounds = path.getBounds2D(); + PathIterator it = path.getPathIterator(new AffineTransform()); + + ArrayList segInfo = new ArrayList(); + ArrayList pntInfo = new ArrayList(); + boolean isClosed = false; + while (!it.isDone()) { + double[] vals = new double[6]; + int type = it.currentSegment(vals); + switch (type) { + case PathIterator.SEG_MOVETO: + pntInfo.add(new Point2D.Double(vals[0], vals[1])); + segInfo.add(new byte[]{0x00, 0x40}); + break; + case PathIterator.SEG_LINETO: + pntInfo.add(new Point2D.Double(vals[0], vals[1])); + segInfo.add(new byte[]{0x00, (byte)0xAC}); + segInfo.add(new byte[]{0x01, 0x00 }); + break; + case PathIterator.SEG_CUBICTO: + pntInfo.add(new Point2D.Double(vals[0], vals[1])); + pntInfo.add(new Point2D.Double(vals[2], vals[3])); + pntInfo.add(new Point2D.Double(vals[4], vals[5])); + segInfo.add(new byte[]{0x00, (byte)0xAD}); + segInfo.add(new byte[]{0x01, 0x20 }); + break; + case PathIterator.SEG_QUADTO: + System.err.println("SEG_QUADTO is not supported"); + break; + case PathIterator.SEG_CLOSE: + pntInfo.add(pntInfo.get(0)); + segInfo.add(new byte[]{0x00, (byte)0xAC}); + segInfo.add(new byte[]{0x01, 0x00 }); + segInfo.add(new byte[]{0x00, (byte)0xAC}); + segInfo.add(new byte[]{0x01, (byte)0x60}); + isClosed = true; + break; + } + + it.next(); + } + if(!isClosed) segInfo.add(new byte[]{0x00, (byte)0xAC}); + segInfo.add(new byte[]{0x00, (byte)0x80}); + + EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4)); + + EscherArrayProperty verticesProp = new EscherArrayProperty((short)(EscherProperties.GEOMETRY__VERTICES + 0x4000), false, null); + verticesProp.setNumberOfElementsInArray(pntInfo.size()); + verticesProp.setNumberOfElementsInMemory(pntInfo.size()); + verticesProp.setSizeOfElements(0xFFF0); + for (int i = 0; i < pntInfo.size(); i++) { + Point2D.Double pnt = (Point2D.Double)pntInfo.get(i); + byte[] data = new byte[4]; + LittleEndian.putShort(data, 0, (short)((pnt.getX() - bounds.getX())*MASTER_DPI/POINT_DPI)); + LittleEndian.putShort(data, 2, (short)((pnt.getY() - bounds.getY())*MASTER_DPI/POINT_DPI)); + verticesProp.setElement(i, data); + } + opt.addEscherProperty(verticesProp); + + EscherArrayProperty segmentsProp = new EscherArrayProperty((short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000), false, null); + segmentsProp.setNumberOfElementsInArray(segInfo.size()); + segmentsProp.setNumberOfElementsInMemory(segInfo.size()); + segmentsProp.setSizeOfElements(0x2); + for (int i = 0; i < segInfo.size(); i++) { + byte[] seg = (byte[])segInfo.get(i); + segmentsProp.setElement(i, seg); + } + opt.addEscherProperty(segmentsProp); + + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__RIGHT, (int)(bounds.getWidth()*MASTER_DPI/POINT_DPI))); + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__BOTTOM, (int)(bounds.getHeight()*MASTER_DPI/POINT_DPI))); + + opt.sortProperties(); + + setAnchor(bounds); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java index 4aad44d75..cb001ccf9 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java @@ -53,11 +53,6 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { private Color background; private RenderingHints hints; - /** - * the maximum distance that the line segments used to approximate the curved segments - */ - public static final float FLATNESS = 0.1f; - /** * Construct Java Graphics object which translates graphic calls in ppt drawing layer. * @@ -218,29 +213,12 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { * @see #setComposite */ public void draw(Shape shape){ - - PathIterator it = shape.getPathIterator(transform, FLATNESS); - double[] prev = null; - double[] coords = new double[6]; - double[] first = new double[6]; - if(!it.isDone()) it.currentSegment(first); //first point - while(!it.isDone()){ - int type = it.currentSegment(coords); - if (prev != null ){ - Line line = new Line(group); - applyPaint(line); - applyStroke(line); - if (type == PathIterator.SEG_LINETO) { - line.setAnchor(new Rectangle2D.Double(prev[0], prev[1], (coords[0] - prev[0]), (coords[1] - prev[1]))); - } else if (type == PathIterator.SEG_CLOSE){ - line.setAnchor(new Rectangle2D.Double(coords[0], coords[1], (first[0] - coords[0]), (first[1] - coords[1]))); - } - group.addShape(line); - } - prev = new double[]{coords[0], coords[1]}; - it.next(); - } - + GeneralPath path = new GeneralPath(transform.createTransformedShape(shape)); + Freeform p = new Freeform(group); + p.setPath(path); + p.getFill().setForegroundColor(null); + applyStroke(p); + group.addShape(p); } /** @@ -299,7 +277,7 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { * Even if top and bottom margins are set to 0 PowerPoint * always sets extra space between the text and its bounding box. * - * Approximation height = ascent*2 works good enough in most cases + * The approximation height = ascent*2 works good enough in most cases */ float height = ascent * 2; @@ -335,28 +313,12 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { * @see #setClip */ public void fill(Shape shape){ - PathIterator it = shape.getPathIterator(transform, FLATNESS); - ArrayList pnt = new ArrayList(); - double[] coords = new double[6]; - while(!it.isDone()){ - int type = it.currentSegment(coords); - if (type != PathIterator.SEG_CLOSE) { - pnt.add(new Point2D.Double(coords[0], coords[1])); - } - it.next(); - } - if(pnt.size() > 0){ - Point2D[] points = (Point2D[])pnt.toArray(new Point2D[pnt.size()]); - Polygon p = new Polygon(group); - p.setPoints(points); - applyPaint(p); - - p.setLineColor(null); //Fills must be "No Line" - - Rectangle2D bounds = transform.createTransformedShape(shape).getBounds2D(); - p.setAnchor(bounds); - group.addShape(p); - } + GeneralPath path = new GeneralPath(transform.createTransformedShape(shape)); + Freeform p = new Freeform(group); + p.setPath(path); + applyPaint(p); + p.setLineColor(null); //Fills must be "No Line" + group.addShape(p); } /** @@ -459,11 +421,8 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { */ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight){ - AutoShape shape = new AutoShape(ShapeTypes.RoundRectangle, group); - shape.setFillColor(null); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); + RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight); + draw(rect); } /** @@ -493,11 +452,8 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { * @see java.awt.Graphics#drawOval */ public void fillOval(int x, int y, int width, int height){ - AutoShape shape = new AutoShape(ShapeTypes.Ellipse, group); - applyPaint(shape); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); + Ellipse2D oval = new Ellipse2D.Float(x, y, width, height); + fill(oval); } /** @@ -518,11 +474,9 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { */ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight){ - AutoShape shape = new AutoShape(ShapeTypes.RoundRectangle, group); - applyPaint(shape); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); + + RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight); + fill(rect); } /** @@ -563,11 +517,8 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { */ public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle){ - AutoShape shape = new AutoShape(ShapeTypes.Arc, group); - applyPaint(shape); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); + Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.PIE); + fill(arc); } /** @@ -609,11 +560,8 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { */ public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - AutoShape shape = new AutoShape(ShapeTypes.Arc, group); - shape.setFillColor(null); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); + Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN); + draw(arc); } @@ -659,11 +607,8 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { * @see java.awt.Graphics#fillOval */ public void drawOval(int x, int y, int width, int height){ - AutoShape shape = new AutoShape(ShapeTypes.Ellipse, group); - shape.setFillColor(null); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); + Ellipse2D oval = new Ellipse2D.Float(x, y, width, height); + draw(oval); } /** @@ -998,11 +943,8 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { * @see java.awt.Graphics#drawRect */ public void fillRect(int x, int y, int width, int height){ - AutoShape shape = new AutoShape(ShapeTypes.Rectangle, group); - applyPaint(shape); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); + Rectangle rect = new Rectangle(x, y, width, height); + fill(rect); } /** @@ -1022,12 +964,8 @@ public class PPGraphics2D extends Graphics2D implements Cloneable { * @see java.awt.Graphics#clearRect */ public void drawRect(int x, int y, int width, int height) { - AutoShape shape = new AutoShape(ShapeTypes.Rectangle, group); - shape.setFillColor(null); - applyStroke(shape); - shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); - group.addShape(shape); - + Rectangle rect = new Rectangle(x, y, width, height); + draw(rect); } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java index 90efd5f3e..4866779b9 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java @@ -21,7 +21,6 @@ import org.apache.poi.hslf.usermodel.PictureData; import org.apache.poi.hslf.usermodel.SlideShow; import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.blip.Bitmap; -import org.apache.poi.util.POILogger; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; @@ -179,7 +178,7 @@ public class Picture extends SimpleShape { List lst = bstore.getChildRecords(); int idx = getPictureIndex(); if (idx == 0){ - logger.log(POILogger.ERROR, "no reference to picture data found "); + log.error("no reference to picture data found "); } else { EscherBSERecord bse = (EscherBSERecord)lst.get(idx-1); for ( int i = 0; i < pict.length; i++ ) { @@ -187,7 +186,7 @@ public class Picture extends SimpleShape { return pict[i]; } } - logger.log(POILogger.ERROR, "no picture found for our BSE offset " + bse.getOffset()); + log.error("no picture found for our BSE offset " + bse.getOffset()); } return null; } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java index 2e23c5926..220a512dc 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java @@ -19,8 +19,8 @@ package org.apache.poi.hslf.model; import org.apache.poi.ddf.*; import org.apache.poi.hslf.model.ShapeTypes; import org.apache.poi.hslf.record.ColorSchemeAtom; -import org.apache.poi.util.POILogger; -import org.apache.poi.util.POILogFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.util.Iterator; import java.awt.*; @@ -45,7 +45,7 @@ import java.awt.geom.Rectangle2D; public abstract class Shape { // For logging - protected POILogger logger = POILogFactory.getLogger(this.getClass()); + protected Log log = LogFactory.getLog(this.getClass()); /** * In Escher absolute distances are specified in @@ -89,6 +89,11 @@ public abstract class Shape { */ protected Sheet _sheet; + /** + * Fill + */ + protected Fill _fill; + /** * Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document. * @@ -344,7 +349,8 @@ public abstract class Shape { * @return fill properties of this shape */ public Fill getFill(){ - return new Fill(this); + if(_fill == null) _fill = new Fill(this); + return _fill; } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java index dbcc8069c..7b79ebad9 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java @@ -18,7 +18,6 @@ package org.apache.poi.hslf.model; import org.apache.poi.ddf.*; import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.POILogger; import java.util.ArrayList; import java.util.List; @@ -71,7 +70,7 @@ public class ShapeGroup extends Shape{ } else { // Should we do anything special with these non // Container records? - logger.log(POILogger.ERROR, "Shape contained non container escher record, was " + r.getClass().getName()); + log.error("Shape contained non container escher record, was " + r.getClass().getName()); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java index 58fc33305..85d672fe8 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java @@ -187,26 +187,7 @@ public class SimpleShape extends Shape { * The color used to fill this shape. */ public Color getFillColor(){ - EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); - EscherSimpleProperty p1 = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.FILL__FILLCOLOR); - EscherSimpleProperty p2= (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); - - int p2val = p2 == null ? 0 : p2.getPropertyValue(); - - Color clr = null; - if (p1 != null && (p2val & 0x10) != 0){ - int rgb = p1.getPropertyValue(); - if (rgb >= 0x8000000) { - int idx = rgb % 0x8000000; - if(getSheet() != null) { - ColorSchemeAtom ca = getSheet().getColorScheme(); - rgb = ca.getColor(idx); - } - } - Color tmp = new Color(rgb, true); - clr = new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed()); - } - return clr; + return getFill().getForegroundColor(); } /** @@ -215,14 +196,7 @@ public class SimpleShape extends Shape { * @param color the background color */ public void setFillColor(Color color){ - EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); - if(color == null) { - setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150000); - } else { - int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); - setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, rgb); - setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150011); - } + getFill().setForegroundColor(color); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java index 1f9a489a7..8a54e079c 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java @@ -22,7 +22,6 @@ import org.apache.poi.ddf.*; import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.usermodel.RichTextRun; import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.util.POILogger; import java.awt.*; import java.awt.font.FontRenderContext; @@ -480,7 +479,7 @@ public class TextBox extends SimpleShape { } } if(_txtrun == null) { - logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx); + log.warn("text run not found for OutlineTextRefAtom.TextIndex=" + idx); } } else { int shapeId = _escherContainer.getChildById(EscherSpRecord.RECORD_ID).getShapeId(); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java index 12aca6fa3..7efe956e2 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java @@ -83,7 +83,7 @@ public class TestPPGraphics2D extends TestCase { group = (ShapeGroup)shape[0]; shape = group.getShapes(); - assertEquals(shape.length, 7); + assertEquals(shape.length, 3); } }