<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
- <release version="3.0.3-beta1" date="2008-04-??">
+ <release version="3.1-beta1" date="2008-04-??">
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Implemented more methods in PPGraphics2D</action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Added Freeform shape which can contain both lines and Bezier curves</action>
+ <action dev="POI-DEVELOPERS" type="fix">41071 - Improved text extraction in HSLF</action>
<action dev="POI-DEVELOPERS" type="add">30311 - Conditional Formatting - improved API, added HSSFSheetConditionalFormatting</action>
<action dev="POI-DEVELOPERS" type="fix">Update the formula parser code to use a HSSFWorkbook, rather than the low level model.Workbook, to make things cleaner and make supporting XSSF formulas in future much easier</action>
<action dev="POI-DEVELOPERS" type="fix">Fix the logger used by POIFSFileSystem, so that commons-logging isn't required when not used</action>
</section>
<section><title>HSLF for PowerPoint Documents</title>
<p>HSLF is our port of the Microsoft PowerPoint 97(-2003) file format to pure
- Java. It supports read and write capabilities of some, but not yet all
- of the core records. Please see <link
+ Java. It supports read and write capabilities. Please see <link
href="./slideshow/index.html">the HSLF project page for more
information</link>.</p>
</section>
<section><title>Files embeded in PowerPoint</title>
<p>PowerPoint does not normally store embeded files
in the OLE2 layer. Instead, they are held within records
- of the main PowerPoint file. To get at them, you need to
- find the appropriate data within the PowerPoint stream,
- and work from that.</p>
+ of the main PowerPoint file.
+ <br/>See the <link href="./../hslf/how-to-shapes.html#OLE">HSLF Tutorial</link>
+ for how to retrieve embedded OLE objects from a presentation</p>
</section>
</section>
<li><link href="#Bullets">How to create bulleted lists</link></li>
<li><link href="#Hyperlinks">Hyperlinks</link></li>
<li><link href="#Tables">Tables</link></li>
+ <li><link href="#RemoveShape">How to remove shapes</link></li>
+ <li><link href="#OLE">How to retrieve embedded OLE objects</link></li>
+ <li><link href="#Sound">How to retrieve embedded sounds</link></li>
+ <li><link href="#Freeform">How to create shapes of arbitrary geometry</link></li>
+ <li><link href="#Graphics2D">Shapes and Graphics2D</link></li>
+ <li><link href="#Render">How to convert slides into images</link></li>
</ul>
</section>
<section><title>Features</title>
</section>
<anchor id="GetShapes"/>
<section><title>How to get shapes contained in a particular slide</title>
- <p>The superclass of all shapes in HSLF is the Shape class - the elemental object that composes a drawing.
- The following pictute shows the class tree of HSLF shapes:
- </p>
- <p>
- <img src="images/hslf_shapes.gif" alt="Class Tree of HSLF Shapes" width="611" height="412"/>
- </p>
<p>
- The following fragment demonstrates how to iterate over shapes for each slide.
+ The following code demonstrates how to iterate over shapes for each slide.
</p>
<source>
SlideShow ppt = new SlideShow(new HSLFSlideShow("slideshow.ppt"));
</source>
</section>
- </section>
+ <anchor id="RemoveShape"/>
+ <section><title>How to remove shapes from a slide</title>
+ <source>
+
+ Shape[] shape = slide.getShapes();
+ for (int i = 0; i < shape.length; i++) {
+
+ //remove the shape
+ boolean ok = slide.removeShape(shape[i]);
+ if(ok){
+ //the shape was removed. Do something.
+ }
+ }
+ </source>
+ </section>
+ <anchor id="OLE"/>
+ <section><title>How to retrieve embedded OLE objects</title>
+ <source>
+
+ Shape[] shape = slide.getShapes();
+ for (int i = 0; i < shape.length; i++) {
+ if (shape[i] instanceof OLEShape) {
+ OLEShape ole = (OLEShape) shape[i];
+ ObjectData data = ole.getObjectData();
+ String name = ole.getInstanceName();
+ if ("Worksheet".equals(name)) {
+ HSSFWorkbook wb = new HSSFWorkbook(data.getData());
+ } else if ("Document".equals(name)) {
+ HWPFDocument doc = new HWPFDocument(data.getData());
+ }
+ }
+ }
+ </source>
+ </section>
+
+ <anchor id="Sound"/>
+ <section><title>How to retrieve embedded sounds</title>
+ <source>
+
+ FileInputStream is = new FileInputStream(args[0]);
+ SlideShow ppt = new SlideShow(is);
+ is.close();
+
+ SoundData[] sound = ppt.getSoundData();
+ for (int i = 0; i < sound.length; i++) {
+ //save *WAV sounds on disk
+ if(sound[i].getSoundType().equals(".WAV")){
+ FileOutputStream out = new FileOutputStream(sound[i].getSoundName());
+ out.write(sound[i].getData());
+ out.close();
+ }
+ }
+ </source>
+ </section>
+
+ <anchor id="Freeform"/>
+ <section><title>How to create shapes of arbitrary geometry</title>
+ <source>
+
+ SlideShow ppt = new SlideShow();
+ Slide slide = ppt.createSlide();
+
+ java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
+ path.moveTo(100, 100);
+ path.lineTo(200, 100);
+ path.curveTo(50, 45, 134, 22, 78, 133);
+ path.curveTo(10, 45, 134, 56, 78, 100);
+ path.lineTo(100, 200);
+ path.closePath();
+
+ Freeform shape = new Freeform();
+ shape.setPath(path);
+ slide.addShape(shape);
+ </source>
+ </section>
+
+ <anchor id="Graphics2D"/>
+ <section><title>How to draw into a slide using Graphics2D</title>
+ <warning>
+ Current implementation of the PowerPoint Graphics2D driver is not fully compliant with the java.awt.Graphics2D specification.
+ Some features like clipping, drawing of images are not yet supported.
+ </warning>
+ <source>
+ SlideShow ppt = new SlideShow();
+ Slide slide = ppt.createSlide();
+
+ //draw a simple bar graph
+ //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),
+ };
+
+ //all objects are drawn into a shape group so we need to create one
+
+ ShapeGroup group = new ShapeGroup();
+ //define position of the drawing in the slide
+ Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
+ //if you want to draw in the entire slide area then define the anchor as follows:
+ //Dimension pgsize = ppt.getPageSize();
+ //java.awt.Rectangle bounds = new java.awt.Rectangle(0, 0, pgsize.width, pgsize.height);
+
+ group.setAnchor(bounds);
+ slide.addShape(group);
+
+ //draw a simple bar chart
+ Graphics2D graphics = new PPGraphics2D(group);
+ 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);
+
+ FileOutputStream out = new FileOutputStream("hslf-graphics2d.ppt");
+ ppt.write(out);
+ out.close();
+
+ </source>
+ </section>
+
+ <anchor id="Render"/>
+ <section><title>Export PowerPoint slides into java.awt.Graphics2D</title>
+ <p>
+ HSLF provides a way to export slides into images. You can capture slides into java.awt.Graphics2D object (or any other)
+ and serialize it into a PNG or JPEG format. Please note, although HSLF attempts to render slides as close to PowerPoint as possible,
+ the output may look differently from PowerPoint due to the following reasons:
+ </p>
+ <ul>
+ <li>Java2D renders fonts differently vs PowerPoint. There are always some differences in the way the font glyphs are painted</li>
+ <li>HSLF uses java.awt.font.LineBreakMeasurer to break text into lines. PowerPoint may do it in a different way.</li>
+ <li>If a font from the presentation is not avaiable, then the JDK default font will be used.</li>
+ </ul>
+ <p>
+ Current Limitations:
+ </p>
+ <ul>
+ <li>Some types of shapes are not yet supported (WordArt, complex auto-shapes)</li>
+ <li>Only Bitmap images (PNG, JPEG, DIB) can be rendered in Java</li>
+ </ul>
+ <source>
+ FileInputStream is = new FileInputStream("slideshow.ppt");
+ SlideShow ppt = new SlideShow(is);
+ is.close();
+
+ Dimension pgsize = ppt.getPageSize();
+
+ Slide[] slide = ppt.getSlides();
+ for (int i = 0; i < slide.length; i++) {
+
+ BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
+ Graphics2D graphics = img.createGraphics();
+ //clear the drawing area
+ graphics.setPaint(Color.white);
+ graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
+
+ //render
+ slide[i].draw(graphics);
+
+ //save the output
+ FileOutputStream out = new FileOutputStream("slide-" + (i+1) + ".png");
+ javax.imageio.ImageIO.write(img, "png", out);
+ out.close();
+ }
+
+ </source>
+ </section>
+
+ </section>
</section>
</body>
</document>
<authors>
<person name="Avik Sengupta" email="avik at apache dot org"/>
<person name="Nick Burch" email="nick at apache dot org"/>
+ <person name="Yegor Kozlov" email="yegor at apache dot org"/>
</authors>
</header>
Powerpoint '97(-2007) file format. It <em>does not</em> support
the new PowerPoint 2007 .pptx file format, which is not OLE2
based.</p>
- <p>HSLF provides a way to read powerpoint presentations, and extract text from it.
- It also provides some (currently limited) edit capabilities.
+ <p>HSLF provides a way to read, create or modify PowerPoint presentations. In particular, it provides:
</p>
+ <ul>
+ <li>api for data extraction (text, pictures, embedded objects, sounds)</li>
+ <li>usermodel api for creating, reading and modifying ppt files</li>
+ </ul>
<note>
This code currently lives the
<link href="http://svn.apache.org/viewcvs.cgi/poi/trunk/src/scratchpad/">scratchpad area</link>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
- <release version="3.0.3-beta1" date="2008-04-??">
+ <release version="3.1-beta1" date="2008-04-??">
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting embedded sounds from slide show </action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Initial support for rendering slides into images</action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Support for getting OLE object data from slide show </action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Implemented more methods in PPGraphics2D</action>
+ <action dev="POI-DEVELOPERS" type="add">HSLF: Added Freeform shape which can contain both lines and Bezier curves</action>
+ <action dev="POI-DEVELOPERS" type="fix">41071 - Improved text extraction in HSLF</action>
<action dev="POI-DEVELOPERS" type="add">30311 - Conditional Formatting - improved API, added HSSFSheetConditionalFormatting</action>
<action dev="POI-DEVELOPERS" type="fix">Update the formula parser code to use a HSSFWorkbook, rather than the low level model.Workbook, to make things cleaner and make supporting XSSF formulas in future much easier</action>
<action dev="POI-DEVELOPERS" type="fix">Fix the logger used by POIFSFileSystem, so that commons-logging isn't required when not used</action>
--- /dev/null
+POI Release Guide\r
+\r
+\r
+(I) Prerequisites\r
+\r
+ 1. You should read the <a href="http://apache.org/dev/release.html">Apache Release FAQ</a>\r
+ 2. You must have shell access to people.apache.org\r
+ 3. Release manager must have his public key appended to the KEYS file checked in to SVN and the key published on one of the public key servers.\r
+ More info can be found here: <a href="http://www.apache.org/dev/release-signing.html">http://www.apache.org/dev/release-signing.html</a>\r
+ 4. You must have <a href="java.sun.com">JDK 1.4 / 1.5</a>\r
+ 5. You must have the following utilities installed on your local machine and available in your path:\r
+ * <a href="www.openssh.com">ssh</a>\r
+ * <a href="www.gnupg.org">gnupg</a>\r
+ * <a href="www.openssl.org">openssl</a>\r
+ For Windows users, install Cygwin and make sure you have the above utilities\r
+ 6. The POI build system requires two components to perform a build\r
+ * <a href="ant.apache.org">Ant</a> \r
+ * <a href="http://forrest.apache.org/">Forrest</a>. \r
+ POI 3.0.2 and 3.1 were built using Ant 1.6.2 and Forrest 0.5\r
+\r
+(II) Making release artefacts\r
+ 1. Update version id in build.xml. \r
+ 2. Tag current version. Include the current revision number in the comment\r
+\r
+{code}\r
+$ svn cp https://svn.apache.org/repos/asf/poi/trunk \\r
+https://svn.apache.org/repos/asf/poi/tags/$TAG \\r
+-m "tag r649911 as 3.1-beta1"\r
+{code}\r
+\r
+where $TAG is the release tag, for example, REL_3_1_BETA1\r
+\r
+ 3. Checkout the tagged version\r
+{code}\r
+cd tags\r
+svn checkout https://svn.apache.org/repos/asf/poi/tags/TAG\r
+{code}\r
+\r
+ 4. Merge (if required)\r
+\r
+{code}\r
+cd $TAG\r
+$ svn merge https://svn.apache.org/repos/asf/poi/tags/TAG \\r
+https://svn.apache.org/repos/asf/poi/trunk\r
+{code}\r
+\r
+ 5. Start a new section in sites.xml and status.xml. \r
+\r
+ 6. Build as if the vote had passed. The buid date must be +7 days from current.\r
+{code}\r
+ant build\r
+{code}\r
+After build you should have the following files in the build/dist:\r
+\r
+{code}\r
+poi-$TAG-$DATE.jar\r
+poi-bin-$TAG-$DATE.tar.gz\r
+poi-bin-$TAG-$DATE.zip\r
+poi-contrib-$TAG-$DATE.jar\r
+poi-scratchpad-$TAG-$DATE.jar\r
+poi-src-$TAG-$DATE.tar.gz\r
+poi-src-$TAG-$DATE.zip\r
+{code}\r
+\r
+where $TAG is the release tag specified in build.xml in the version.id property, $DATE is the release date (typically +7 days from the actual build date). \r
+ 7. Build Mavn POM files\r
+{code}\r
+ant maven-dist\r
+{code}\r
+\r
+ 8. Signing the release artifacts:\r
+{code}\r
+cd build/dist\r
+for i in *.zip ; do \r
+ gpg --armor --output $i.asc --detach-sig $i; \r
+done\r
+for i in *.gz ; do \r
+ gpg --armor --output $i.asc --detach-sig $i; \r
+done\r
+{code}\r
+\r
+Verify the signatures:\r
+\r
+{code}\r
+gpg --multifile --verify *.asc\r
+{code}\r
+\r
+ 9. Create MD5 checksums for all artifacts to be published:\r
+\r
+{code}\r
+for i in *.zip ; do \r
+ openssl md5 < $i > $i.md5\r
+done\r
+for i in *.gz ; do \r
+ openssl md5 < $i > $i.md5\r
+done\r
+{code}\r
+\r
+ 10. Upload to your area at people.apache.org.\r
+There should be two directories:\r
+main\r
+maven\r
+\r
+Make sure that the all files have read permission. \r
+\r
+ (III) After the vote:\r
+\r
+Log-in on people.apache.org\r
+\r
+1. Go to ~/POI-3.1-BETA1\r
+\r
+cd ~/POI-3.1-BETA1/main\r
+\r
+BETA and ALPHA releases:\r
+cp *-src-* /www/www.apache.org/dist/poi/dev/src\r
+cp *-bin-* /www/www.apache.org/dist/poi/dev/bin\r
+\r
+FINAL release:\r
+cp *-src-* /www/www.apache.org/dist/poi/release/src\r
+cp *-bin-* /www/www.apache.org/dist/poi/release/bin\r
+\r
+cd ~/POI-3.1-BETA1/maven\r
+\r
+cp -r org.apache.poi /www/people.apache.org/repo/m1-ibiblio-rsync-repository/\r
+cp -r poi/poms /www/people.apache.org/repo/m1-ibiblio-rsync-repository/poi\r
+\r
+\r
+2. Make sure that the files are owned by the unix group apcvs and that they are writable by this group. \r
+\r
+3. Wait for the distributions to appear on your favourite mirror\r
+\r
+4. Send announcements:\r
+ - to poi-user and poi-dev lists\r
+ - send announcements to announcement@apache.org, announcements@jakarta.apache.org\r
+\r
*/
public void setString( RichTextString string )
{
- this.string = (HSSFRichTextString) string;
+ HSSFRichTextString rtr = (HSSFRichTextString)string;
+
+ // If font is not set we must set the default one
+ if (rtr.numFormattingRuns() == 0) rtr.applyFont((short)0);
+
+ this.string = rtr;
}
/**
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.examples;\r
+\r
+import org.apache.poi.hslf.usermodel.*;\r
+import org.apache.poi.hslf.model.*;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.hwpf.HWPFDocument;\r
+import org.apache.poi.hwpf.usermodel.Range;\r
+import org.apache.poi.hwpf.usermodel.Paragraph;\r
+\r
+import java.io.*;\r
+\r
+/**\r
+ * Demonstrates how you can extract misc embedded data from a ppt file\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class DataExtraction {\r
+\r
+ public static void main(String args[]) throws Exception {\r
+\r
+ if (args.length == 0) {\r
+ usage();\r
+ return;\r
+ }\r
+\r
+ FileInputStream is = new FileInputStream(args[0]);\r
+ SlideShow ppt = new SlideShow(is);\r
+ is.close();\r
+\r
+ //extract all sound files embedded in this presentation\r
+ SoundData[] sound = ppt.getSoundData();\r
+ for (int i = 0; i < sound.length; i++) {\r
+ String type = sound[i].getSoundType(); //*.wav\r
+ String name = sound[i].getSoundName(); //typically file name\r
+ byte[] data = sound[i].getData(); //raw bytes\r
+\r
+ //save the sound on disk\r
+ FileOutputStream out = new FileOutputStream(name + type);\r
+ out.write(data);\r
+ out.close();\r
+ }\r
+\r
+ //extract embedded OLE documents\r
+ Slide[] slide = ppt.getSlides();\r
+ for (int i = 0; i < slide.length; i++) {\r
+ Shape[] shape = slide[i].getShapes();\r
+ for (int j = 0; j < shape.length; j++) {\r
+ if (shape[j] instanceof OLEShape) {\r
+ OLEShape ole = (OLEShape) shape[j];\r
+ ObjectData data = ole.getObjectData();\r
+ String name = ole.getInstanceName();\r
+ if ("Worksheet".equals(name)) {\r
+\r
+ //save xls on disk\r
+ FileOutputStream out = new FileOutputStream(name + "-("+(j)+").xls");\r
+ InputStream dis = data.getData();\r
+ byte[] chunk = new byte[2048];\r
+ int count;\r
+ while ((count = dis.read(chunk)) >= 0) {\r
+ out.write(chunk,0,count);\r
+ }\r
+ is.close();\r
+ out.close();\r
+ } else if ("Document".equals(name)) {\r
+ HWPFDocument doc = new HWPFDocument(data.getData());\r
+ //read the word document\r
+ Range r = doc.getRange(); \r
+ for(int k = 0; k < r.numParagraphs(); k++) {\r
+ Paragraph p = r.getParagraph(k);\r
+ System.out.println(p.text());\r
+ }\r
+\r
+ //save on disk\r
+ FileOutputStream out = new FileOutputStream(name + "-("+(j)+").doc");\r
+ doc.write(out);\r
+ out.close();\r
+ } else {\r
+ System.err.println("Processing " + name);\r
+ }\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ //Pictures\r
+ for (int i = 0; i < slide.length; i++) {\r
+ Shape[] shape = slide[i].getShapes();\r
+ for (int j = 0; j < shape.length; j++) {\r
+ if (shape[j] instanceof Picture) {\r
+ Picture p = (Picture) shape[j];\r
+ PictureData data = p.getPictureData();\r
+ String name = p.getPictureName();\r
+ int type = data.getType();\r
+ String ext;\r
+ switch (type) {\r
+ case Picture.JPEG:\r
+ ext = ".jpg";\r
+ break;\r
+ case Picture.PNG:\r
+ ext = ".png";\r
+ break;\r
+ case Picture.WMF:\r
+ ext = ".wmf";\r
+ break;\r
+ case Picture.EMF:\r
+ ext = ".emf";\r
+ break;\r
+ case Picture.PICT:\r
+ ext = ".pict";\r
+ break;\r
+ case Picture.DIB:\r
+ ext = ".dib";\r
+ break;\r
+ default:\r
+ continue;\r
+ }\r
+ FileOutputStream out = new FileOutputStream("pict-" + j + ext);\r
+ out.write(data.getData());\r
+ out.close();\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ private static void usage(){\r
+ System.out.println("Usage: DataExtraction ppt");\r
+ }\r
+}\r
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.examples;\r
+\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.model.*;\r
+\r
+import java.awt.*;\r
+import java.io.FileOutputStream;\r
+import java.io.FileInputStream;\r
+\r
+/**\r
+ * Demonstrates how to draw into a slide using the HSLF Graphics2D driver.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class Graphics2DDemo {\r
+\r
+ /**\r
+ * A simple bar chart demo\r
+ */\r
+ public static void main(String[] args) throws Exception {\r
+ SlideShow ppt = new SlideShow();\r
+\r
+ //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(40),\r
+ Color.green, new Integer(60),\r
+ Color.gray, new Integer(30),\r
+ Color.red, new Integer(80),\r
+ };\r
+\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
+ group.setCoordinates(new java.awt.Rectangle(0, 0, 100, 100));\r
+ slide.addShape(group);\r
+ Graphics2D graphics = new PPGraphics2D(group);\r
+\r
+ //draw a simple bar graph\r
+ int x = 10, y = 10;\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-5, y+10);\r
+ graphics.drawString(width + "%", x + width+3, y + 10);\r
+ graphics.setColor((Color)def[i]);\r
+ graphics.fill(new Rectangle(x, y, width, 10));\r
+ y += 15;\r
+ }\r
+ graphics.setColor(Color.black);\r
+ graphics.setFont(new Font("Arial", Font.BOLD, 14));\r
+ graphics.draw(group.getCoordinates());\r
+ graphics.drawString("Performance", x + 30, y + 10);\r
+\r
+ FileOutputStream out = new FileOutputStream("hslf-graphics.ppt");\r
+ ppt.write(out);\r
+ out.close();\r
+ }\r
+\r
+}\r
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.examples;\r
+\r
+import org.apache.poi.hslf.usermodel.*;\r
+import org.apache.poi.hslf.model.*;\r
+import org.apache.poi.hslf.record.TextHeaderAtom;\r
+\r
+import javax.imageio.ImageIO;\r
+import java.io.IOException;\r
+import java.io.FileOutputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.awt.*;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+/**\r
+ * Demonstrates how you can use HSLF to convert each slide into a PNG image\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class PPT2PNG {\r
+\r
+ public static void main(String args[]) throws Exception {\r
+\r
+ if (args.length == 0) {\r
+ usage();\r
+ return;\r
+ }\r
+\r
+ int slidenum = -1;\r
+ float scale = 1;\r
+ String file = null;\r
+\r
+ for (int i = 0; i < args.length; i++) {\r
+ if (args[i].startsWith("-")) {\r
+ if ("-scale".equals(args[i])){\r
+ scale = Float.parseFloat(args[++i]);\r
+ } else if ("-slide".equals(args[i])) {\r
+ slidenum = Integer.parseInt(args[++i]);\r
+ }\r
+ } else {\r
+ file = args[i];\r
+ }\r
+ }\r
+ if(file == null){\r
+ usage();\r
+ return;\r
+ }\r
+\r
+ FileInputStream is = new FileInputStream(file);\r
+ SlideShow ppt = new SlideShow(is);\r
+ is.close();\r
+\r
+ Dimension pgsize = ppt.getPageSize();\r
+ int width = (int)(pgsize.width*scale);\r
+ int height = (int)(pgsize.height*scale);\r
+\r
+ Slide[] slide = ppt.getSlides();\r
+ for (int i = 0; i < slide.length; i++) {\r
+ if (slidenum != -1 && slidenum != (i+1)) continue;\r
+\r
+ String title = slide[i].getTitle();\r
+ System.out.println("Rendering slide "+slide[i].getSlideNumber() + (title == null ? "" : ": " + title));\r
+\r
+ BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\r
+ Graphics2D graphics = img.createGraphics();\r
+ graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+ graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);\r
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);\r
+ graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);\r
+\r
+ graphics.setPaint(Color.white);\r
+ graphics.fill(new Rectangle2D.Float(0, 0, width, height));\r
+\r
+ graphics.scale((double)width/pgsize.width, (double)height/pgsize.height);\r
+\r
+ slide[i].draw(graphics);\r
+\r
+ String fname = file.replaceAll("\\.ppt", "-" + (i+1) + ".png");\r
+ FileOutputStream out = new FileOutputStream(fname);\r
+ ImageIO.write(img, "png", out);\r
+ out.close();\r
+ }\r
+ }\r
+\r
+ private static void usage(){\r
+ System.out.println("Usage: PPT2PNG [-scale <scale> -slide <num>] ppt");\r
+ }\r
+}\r
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
import org.apache.poi.POIDocument;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
import org.apache.poi.hslf.exceptions.HSLFException;
-import org.apache.poi.hslf.record.CurrentUserAtom;
-import org.apache.poi.hslf.record.ExOleObjStg;
-import org.apache.poi.hslf.record.PersistPtrHolder;
-import org.apache.poi.hslf.record.PositionDependentRecord;
-import org.apache.poi.hslf.record.Record;
-import org.apache.poi.hslf.record.UserEditAtom;
+import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.ObjectData;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.model.Shape;
private Record[] read(byte[] docstream, int usrOffset){
ArrayList lst = new ArrayList();
+ HashMap offset2id = new HashMap();
while (usrOffset != 0){
UserEditAtom usr = (UserEditAtom) Record.buildRecordAtOffset(docstream, usrOffset);
lst.add(new Integer(usrOffset));
Integer offset = (Integer)entries.get(id);
lst.add(offset);
+ offset2id.put(offset, id);
}
usrOffset = usr.getLastUserEditAtomOffset();
for (int i = 0; i < a.length; i++) {
Integer offset = (Integer)a[i];
rec[i] = (Record)Record.buildRecordAtOffset(docstream, offset.intValue());
+ if(rec[i] instanceof PersistRecord) {
+ PersistRecord psr = (PersistRecord)rec[i];
+ Integer id = (Integer)offset2id.get(offset);
+ psr.setPersistId(id.intValue());
+ }
}
return rec;
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
+import org.apache.poi.util.POILogger;
+
+import java.awt.geom.Rectangle2D;
/**
* Represents an AutoShape.
setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
}
+
+ public java.awt.Shape getOutline(){
+ ShapeOutline outline = AutoShapes.getShapeOutline(getShapeType());
+ Rectangle2D anchor = getLogicalAnchor2D();
+ if(outline == null){
+ logger.log(POILogger.WARN, "Outline not found for " + ShapeTypes.typeName(getShapeType()));
+ return anchor;
+ } else {
+ java.awt.Shape shape = outline.getOutline(this);
+ return AutoShapes.transform(shape, anchor);
+ }
+ }
+
}
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.EscherProperties;\r
+\r
+import java.awt.geom.*;\r
+\r
+/**\r
+ * Stores definition of auto-shapes.\r
+ * See the Office Drawing 97-2007 Binary Format Specification for details.\r
+ *\r
+ * TODO: follow the spec and define all the auto-shapes\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class AutoShapes {\r
+ protected static ShapeOutline[] shapes;\r
+\r
+\r
+ /**\r
+ * Return shape outline by shape type\r
+ * @param type shape type see {@link ShapeTypes}\r
+ *\r
+ * @return the shape outline\r
+ */\r
+ public static ShapeOutline getShapeOutline(int type){\r
+ ShapeOutline outline = shapes[type];\r
+ return outline;\r
+ }\r
+\r
+ /**\r
+ * Auto-shapes are defined in the [0,21600] coordinate system.\r
+ * We need to transform it into normal slide coordinates\r
+ *\r
+ */\r
+ public static java.awt.Shape transform(java.awt.Shape outline, Rectangle2D anchor){\r
+ AffineTransform at = new AffineTransform();\r
+ at.translate(anchor.getX(), anchor.getY());\r
+ at.scale(\r
+ 1.0f/21600*anchor.getWidth(),\r
+ 1.0f/21600*anchor.getHeight()\r
+ );\r
+ return at.createTransformedShape(outline);\r
+ }\r
+\r
+ static {\r
+ shapes = new ShapeOutline[255];\r
+\r
+ shapes[ShapeTypes.Rectangle] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ Rectangle2D path = new Rectangle2D.Float(0, 0, 21600, 21600);\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.RoundRectangle] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+ RoundRectangle2D path = new RoundRectangle2D.Float(0, 0, 21600, 21600, adjval, adjval);\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Ellipse] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ Ellipse2D path = new Ellipse2D.Float(0, 0, 21600, 21600);\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Diamond] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(10800, 0);\r
+ path.lineTo(21600, 10800);\r
+ path.lineTo(10800, 21600);\r
+ path.lineTo(0, 10800);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ //m@0,l,21600r21600\r
+ shapes[ShapeTypes.IsocelesTriangle] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 10800);\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(adjval, 0);\r
+ path.lineTo(0, 21600);\r
+ path.lineTo(21600, 21600);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.RightTriangle] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(0, 0);\r
+ path.lineTo(21600, 21600);\r
+ path.lineTo(0, 21600);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Parallelogram] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(adjval, 0);\r
+ path.lineTo(21600, 0);\r
+ path.lineTo(21600 - adjval, 21600);\r
+ path.lineTo(0, 21600);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Trapezoid] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(0, 0);\r
+ path.lineTo(adjval, 21600);\r
+ path.lineTo(21600 - adjval, 21600);\r
+ path.lineTo(21600, 0);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Hexagon] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(adjval, 0);\r
+ path.lineTo(21600 - adjval, 0);\r
+ path.lineTo(21600, 10800);\r
+ path.lineTo(21600 - adjval, 21600);\r
+ path.lineTo(adjval, 21600);\r
+ path.lineTo(0, 10800);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Octagon] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 6326);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(adjval, 0);\r
+ path.lineTo(21600 - adjval, 0);\r
+ path.lineTo(21600, adjval);\r
+ path.lineTo(21600, 21600-adjval);\r
+ path.lineTo(21600-adjval, 21600);\r
+ path.lineTo(adjval, 21600);\r
+ path.lineTo(0, 21600-adjval);\r
+ path.lineTo(0, adjval);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Plus] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(adjval, 0);\r
+ path.lineTo(21600 - adjval, 0);\r
+ path.lineTo(21600 - adjval, adjval);\r
+ path.lineTo(21600, adjval);\r
+ path.lineTo(21600, 21600-adjval);\r
+ path.lineTo(21600-adjval, 21600-adjval);\r
+ path.lineTo(21600-adjval, 21600);\r
+ path.lineTo(adjval, 21600);\r
+ path.lineTo(adjval, 21600-adjval);\r
+ path.lineTo(0, 21600-adjval);\r
+ path.lineTo(0, adjval);\r
+ path.lineTo(adjval, adjval);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Pentagon] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(10800, 0);\r
+ path.lineTo(21600, 8259);\r
+ path.lineTo(21600 - 4200, 21600);\r
+ path.lineTo(4200, 21600);\r
+ path.lineTo(0, 8259);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.DownArrow] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ //m0@0 l@1@0 @1,0 @2,0 @2@0,21600@0,10800,21600xe\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200);\r
+ int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(0, adjval);\r
+ path.lineTo(adjval2, adjval);\r
+ path.lineTo(adjval2, 0);\r
+ path.lineTo(21600-adjval2, 0);\r
+ path.lineTo(21600-adjval2, adjval);\r
+ path.lineTo(21600, adjval);\r
+ path.lineTo(10800, 21600);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.UpArrow] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ //m0@0 l@1@0 @1,21600@2,21600@2@0,21600@0,10800,xe\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+ int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(0, adjval);\r
+ path.lineTo(adjval2, adjval);\r
+ path.lineTo(adjval2, 21600);\r
+ path.lineTo(21600-adjval2, 21600);\r
+ path.lineTo(21600-adjval2, adjval);\r
+ path.lineTo(21600, adjval);\r
+ path.lineTo(10800, 0);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Arrow] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ //m@0, l@0@1 ,0@1,0@2@0@2@0,21600,21600,10800xe\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200);\r
+ int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(adjval, 0);\r
+ path.lineTo(adjval, adjval2);\r
+ path.lineTo(0, adjval2);\r
+ path.lineTo(0, 21600-adjval2);\r
+ path.lineTo(adjval, 21600-adjval2);\r
+ path.lineTo(adjval, 21600);\r
+ path.lineTo(21600, 10800);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.LeftArrow] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ //m@0, l@0@1,21600@1,21600@2@0@2@0,21600,,10800xe\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+ int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(adjval, 0);\r
+ path.lineTo(adjval, adjval2);\r
+ path.lineTo(21600, adjval2);\r
+ path.lineTo(21600, 21600-adjval2);\r
+ path.lineTo(adjval, 21600-adjval2);\r
+ path.lineTo(adjval, 21600);\r
+ path.lineTo(0, 10800);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.Can] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ //m10800,qx0@1l0@2qy10800,21600,21600@2l21600@1qy10800,xem0@1qy10800@0,21600@1nfe\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+\r
+ path.append(new Arc2D.Float(0, 0, 21600, adjval, 0, 180, Arc2D.OPEN), false);\r
+ path.moveTo(0, adjval/2);\r
+\r
+ path.lineTo(0, 21600 - adjval/2);\r
+ path.closePath();\r
+\r
+ path.append(new Arc2D.Float(0, 21600 - adjval, 21600, adjval, 180, 180, Arc2D.OPEN), false);\r
+ path.moveTo(21600, 21600 - adjval/2);\r
+\r
+ path.lineTo(21600, adjval/2);\r
+ path.append(new Arc2D.Float(0, 0, 21600, adjval, 180, 180, Arc2D.OPEN), false);\r
+ path.moveTo(0, adjval/2);\r
+ path.closePath();\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.LeftBrace] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ //m21600,qx10800@0l10800@2qy0@11,10800@3l10800@1qy21600,21600e\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 1800);\r
+ int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 10800);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(21600, 0);\r
+\r
+ path.append(new Arc2D.Float(10800, 0, 21600, adjval*2, 90, 90, Arc2D.OPEN), false);\r
+ path.moveTo(10800, adjval);\r
+\r
+ path.lineTo(10800, adjval2 - adjval);\r
+\r
+ path.append(new Arc2D.Float(-10800, adjval2 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false);\r
+ path.moveTo(0, adjval2);\r
+\r
+ path.append(new Arc2D.Float(-10800, adjval2, 21600, adjval*2, 0, 90, Arc2D.OPEN), false);\r
+ path.moveTo(10800, adjval2 + adjval);\r
+\r
+ path.lineTo(10800, 21600 - adjval);\r
+\r
+ path.append(new Arc2D.Float(10800, 21600 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false);\r
+\r
+ return path;\r
+ }\r
+ };\r
+\r
+ shapes[ShapeTypes.RightBrace] = new ShapeOutline(){\r
+ public java.awt.Shape getOutline(Shape shape){\r
+ //m,qx10800@0 l10800@2qy21600@11,10800@3l10800@1qy,21600e\r
+ int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 1800);\r
+ int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 10800);\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ path.moveTo(0, 0);\r
+\r
+ path.append(new Arc2D.Float(-10800, 0, 21600, adjval*2, 0, 90, Arc2D.OPEN), false);\r
+ path.moveTo(10800, adjval);\r
+\r
+ path.lineTo(10800, adjval2 - adjval);\r
+\r
+ path.append(new Arc2D.Float(10800, adjval2 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false);\r
+ path.moveTo(21600, adjval2);\r
+\r
+ path.append(new Arc2D.Float(10800, adjval2, 21600, adjval*2, 90, 90, Arc2D.OPEN), false);\r
+ path.moveTo(10800, adjval2 + adjval);\r
+\r
+ path.lineTo(10800, 21600 - adjval);\r
+\r
+ path.append(new Arc2D.Float(-10800, 21600 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false);\r
+\r
+ return path;\r
+ }\r
+ };\r
+\r
+ }\r
+}\r
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.hslf.usermodel.PictureData;
+import org.apache.poi.hslf.blip.Bitmap;
+import org.apache.poi.util.POILogger;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
/**
* Background shape
*/
public class Background extends Shape {
- protected Background(EscherContainerRecord escherRecord, Shape parent){
+ protected Background(EscherContainerRecord escherRecord, Shape parent) {
super(escherRecord, parent);
}
- protected EscherContainerRecord createSpContainer(boolean isChild){
+ protected EscherContainerRecord createSpContainer(boolean isChild) {
return null;
}
+ public void draw(Graphics2D graphics) {
+ Fill f = getFill();
+ Dimension pg = getSheet().getSlideShow().getPageSize();
+ Rectangle anchor = new Rectangle(0, 0, pg.width, pg.height);
+ switch (f.getFillType()) {
+ case Fill.FILL_SOLID:
+ Color color = f.getForegroundColor();
+ graphics.setPaint(color);
+ graphics.fill(anchor);
+ break;
+ case Fill.FILL_PICTURE:
+ PictureData data = f.getPictureData();
+ if (data instanceof Bitmap) {
+ BufferedImage img = null;
+ try {
+ img = ImageIO.read(new ByteArrayInputStream(data.getData()));
+ } catch (Exception e) {
+ logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + data.getType());
+ return;
+ }
+ Image scaledImg = img.getScaledInstance(anchor.width, anchor.height, Image.SCALE_SMOOTH);
+ graphics.drawImage(scaledImg, anchor.x, anchor.y, null);
+
+ }
+ break;
+ default:
+ logger.log(POILogger.WARN, "unsuported fill type: " + f.getFillType());
+ break;
+ }
+ }
}
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 java.awt.*;
-import java.util.*;
/**
* Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty p1 = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__FILLCOLOR);
EscherSimpleProperty p2 = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
+ EscherSimpleProperty p3 = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__FILLOPACITY);
int p2val = p2 == null ? 0 : p2.getPropertyValue();
+ int alpha = p3 == null ? 255 : ((p3.getPropertyValue() >> 8) & 0xFF);
Color clr = null;
if (p1 != null && (p2val & 0x10) != 0){
int rgb = p1.getPropertyValue();
- clr = shape.getColor(rgb);
+ clr = shape.getColor(rgb, alpha);
}
return clr;
}
Color clr = null;
if (p1 != null && (p2val & 0x10) != 0){
int rgb = p1.getPropertyValue();
- clr = shape.getColor(rgb);
+ clr = shape.getColor(rgb, 255);
}
return clr;
}
\r
import java.awt.geom.*;\r
import java.util.ArrayList;\r
+import java.util.Arrays;\r
\r
/**\r
* A "Freeform" shape.\r
* @author Yegor Kozlov\r
*/\r
public class Freeform extends AutoShape {\r
+\r
+ public static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};\r
+ public static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};\r
+ public static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};\r
+ public static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};\r
+ public static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};\r
+ public static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3}; //OpenOffice inserts 0xB3 instead of 0xAD.\r
+ public static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};\r
+ public static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};\r
+\r
/**\r
* Create a Freeform object and initialize it from the supplied Record container.\r
*\r
switch (type) {\r
case PathIterator.SEG_MOVETO:\r
pntInfo.add(new Point2D.Double(vals[0], vals[1]));\r
- segInfo.add(new byte[]{0x00, 0x40});\r
+ segInfo.add(SEGMENTINFO_MOVETO);\r
break;\r
case PathIterator.SEG_LINETO:\r
pntInfo.add(new Point2D.Double(vals[0], vals[1]));\r
- segInfo.add(new byte[]{0x00, (byte)0xAC});\r
- segInfo.add(new byte[]{0x01, 0x00 });\r
+ segInfo.add(SEGMENTINFO_LINETO);\r
+ segInfo.add(SEGMENTINFO_ESCAPE);\r
break;\r
case PathIterator.SEG_CUBICTO:\r
pntInfo.add(new Point2D.Double(vals[0], vals[1]));\r
pntInfo.add(new Point2D.Double(vals[2], vals[3]));\r
pntInfo.add(new Point2D.Double(vals[4], vals[5]));\r
- segInfo.add(new byte[]{0x00, (byte)0xAD});\r
- segInfo.add(new byte[]{0x01, 0x20 });\r
+ segInfo.add(SEGMENTINFO_CUBICTO);\r
+ segInfo.add(SEGMENTINFO_ESCAPE2);\r
break;\r
case PathIterator.SEG_QUADTO:\r
+ //TODO: figure out how to convert SEG_QUADTO into SEG_CUBICTO \r
logger.log(POILogger.WARN, "SEG_QUADTO is not supported");\r
break;\r
case PathIterator.SEG_CLOSE:\r
pntInfo.add(pntInfo.get(0));\r
- segInfo.add(new byte[]{0x00, (byte)0xAC});\r
- segInfo.add(new byte[]{0x01, 0x00 });\r
- segInfo.add(new byte[]{0x00, (byte)0xAC});\r
- segInfo.add(new byte[]{0x01, (byte)0x60});\r
+ segInfo.add(SEGMENTINFO_LINETO);\r
+ segInfo.add(SEGMENTINFO_ESCAPE);\r
+ segInfo.add(SEGMENTINFO_LINETO);\r
+ segInfo.add(SEGMENTINFO_CLOSE);\r
isClosed = true;\r
break;\r
}\r
\r
it.next();\r
}\r
- if(!isClosed) segInfo.add(new byte[]{0x00, (byte)0xAC});\r
+ if(!isClosed) segInfo.add(SEGMENTINFO_LINETO);\r
segInfo.add(new byte[]{0x00, (byte)0x80});\r
\r
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
\r
setAnchor(bounds);\r
}\r
+\r
+ /**\r
+ * Gets the freeform path\r
+ *\r
+ * @return the freeform path\r
+ */\r
+ public GeneralPath getPath(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4));\r
+\r
+ EscherArrayProperty verticesProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000));\r
+ if(verticesProp == null) verticesProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES));\r
+\r
+ EscherArrayProperty segmentsProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000));\r
+ if(segmentsProp == null) segmentsProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO));\r
+\r
+ //sanity check\r
+ if(verticesProp == null) {\r
+ logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");\r
+ return null;\r
+ }\r
+ if(segmentsProp == null) {\r
+ logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");\r
+ return null;\r
+ }\r
+\r
+ Rectangle2D bounds = getAnchor2D();\r
+ float right = (float)bounds.getX();\r
+ float bottom = (float)bounds.getY();\r
+\r
+ GeneralPath path = new GeneralPath();\r
+ int numPoints = verticesProp.getNumberOfElementsInArray();\r
+ int numSegments = segmentsProp.getNumberOfElementsInArray();\r
+ for (int i = 0, j = 0; i < numSegments && j < numPoints; i++) {\r
+ byte[] elem = segmentsProp.getElement(i);\r
+ if(Arrays.equals(elem, SEGMENTINFO_MOVETO)){\r
+ byte[] p = verticesProp.getElement(j++);\r
+ short x = LittleEndian.getShort(p, 0);\r
+ short y = LittleEndian.getShort(p, 2);\r
+ path.moveTo(\r
+ ((float)x*POINT_DPI/MASTER_DPI + right),\r
+ ((float)y*POINT_DPI/MASTER_DPI + bottom));\r
+ } else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){\r
+ i++;\r
+ byte[] p1 = verticesProp.getElement(j++);\r
+ short x1 = LittleEndian.getShort(p1, 0);\r
+ short y1 = LittleEndian.getShort(p1, 2);\r
+ byte[] p2 = verticesProp.getElement(j++);\r
+ short x2 = LittleEndian.getShort(p2, 0);\r
+ short y2 = LittleEndian.getShort(p2, 2);\r
+ byte[] p3 = verticesProp.getElement(j++);\r
+ short x3 = LittleEndian.getShort(p3, 0);\r
+ short y3 = LittleEndian.getShort(p3, 2);\r
+ path.curveTo(\r
+ ((float)x1*POINT_DPI/MASTER_DPI + right), ((float)y1*POINT_DPI/MASTER_DPI + bottom),\r
+ ((float)x2*POINT_DPI/MASTER_DPI + right), ((float)y2*POINT_DPI/MASTER_DPI + bottom),\r
+ ((float)x3*POINT_DPI/MASTER_DPI + right), ((float)y3*POINT_DPI/MASTER_DPI + bottom));\r
+\r
+ } else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){\r
+ i++;\r
+ byte[] pnext = segmentsProp.getElement(i);\r
+ if(Arrays.equals(pnext, SEGMENTINFO_ESCAPE)){\r
+ if(j + 1 < numPoints){\r
+ byte[] p = verticesProp.getElement(j++);\r
+ short x = LittleEndian.getShort(p, 0);\r
+ short y = LittleEndian.getShort(p, 2);\r
+ path.lineTo(\r
+ ((float)x*POINT_DPI/MASTER_DPI + right), ((float)y*POINT_DPI/MASTER_DPI + bottom));\r
+ }\r
+ } else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){\r
+ path.closePath();\r
+ }\r
+ }\r
+ }\r
+\r
+ return path;\r
+ }\r
+\r
+ public java.awt.Shape getOutline(){\r
+ return getPath();\r
+ }\r
}\r
import org.apache.poi.ddf.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Line2D;
+
/**
* Represents a line in a PowerPoint drawing
*
return _escherContainer;
}
+ public java.awt.Shape getOutline(){
+ Rectangle2D anchor = getLogicalAnchor2D();
+ return new Line2D.Double(anchor.getX(), anchor.getY(), anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight());
+ }
}
package org.apache.poi.hslf.model;
import org.apache.poi.hslf.record.SheetContainer;
+import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.model.textproperties.TextProp;
/**
*/
public abstract TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) ;
+
+ /**
+ * Checks if the shape is a placeholder.
+ * (placeholders aren't normal shapes, they are visible only in the Edit Master mode)
+ *
+ *
+ * @return true if the shape is a placeholder
+ */
+ public static boolean isPlaceholder(Shape shape){
+ if(!(shape instanceof TextShape)) return false;
+
+ TextShape tx = (TextShape)shape;
+ TextRun run = tx.getTextRun();
+ if(run == null) return false;
+
+ Record[] records = run._records;
+ for (int i = 0; i < records.length; i++) {
+ int type = (int)records[i].getRecordType();
+ if (type == RecordTypes.BaseTextPropAtom.typeID ||
+ type == RecordTypes.DateTimeMCAtom.typeID ||
+ type == RecordTypes.GenericDateMCAtom.typeID ||
+ type == RecordTypes.FooterMCAtom.typeID ||
+ type == RecordTypes.SlideNumberMCAtom.typeID
+ ) return true;
+
+ }
+ return false;
+ }
}
--- /dev/null
+/*\r
+* Licensed to the Apache Software Foundation (ASF) under one or more\r
+* contributor license agreements. See the NOTICE file distributed with\r
+* this work for additional information regarding copyright ownership.\r
+* The ASF licenses this file to You under the Apache License, Version 2.0\r
+* (the "License"); you may not use this file except in compliance with\r
+* the License. You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.usermodel.ObjectData;\r
+import org.apache.poi.hslf.record.ExObjList;\r
+import org.apache.poi.hslf.record.Record;\r
+import org.apache.poi.hslf.record.ExEmbed;\r
+import org.apache.poi.util.POILogger;\r
+\r
+\r
+/**\r
+ * A shape representing embedded OLE obejct.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class OLEShape extends Picture {\r
+ protected ExEmbed _exEmbed;\r
+\r
+ /**\r
+ * Create a new <code>OLEShape</code>\r
+ *\r
+ * @param idx the index of the picture\r
+ */\r
+ public OLEShape(int idx){\r
+ super(idx);\r
+ }\r
+\r
+ /**\r
+ * Create a new <code>OLEShape</code>\r
+ *\r
+ * @param idx the index of the picture\r
+ * @param parent the parent shape\r
+ */\r
+ public OLEShape(int idx, Shape parent) {\r
+ super(idx, parent);\r
+ }\r
+\r
+ /**\r
+ * Create a <code>OLEShape</code> object\r
+ *\r
+ * @param escherRecord the <code>EscherSpContainer</code> record which holds information about\r
+ * this picture in the <code>Slide</code>\r
+ * @param parent the parent shape of this picture\r
+ */\r
+ protected OLEShape(EscherContainerRecord escherRecord, Shape parent){\r
+ super(escherRecord, parent);\r
+ }\r
+\r
+ /**\r
+ * Returns unique identifier for the OLE object.\r
+ *\r
+ * @return the unique identifier for the OLE object\r
+ */\r
+ public int getObjectID(){\r
+ return getEscherProperty(EscherProperties.BLIP__PICTUREID);\r
+ }\r
+\r
+ /**\r
+ * Returns unique identifier for the OLE object.\r
+ *\r
+ * @return the unique identifier for the OLE object\r
+ */\r
+ public ObjectData getObjectData(){\r
+ SlideShow ppt = getSheet().getSlideShow();\r
+ ObjectData[] ole = ppt.getEmbeddedObjects();\r
+\r
+ //persist reference\r
+ int ref = getExEmbed().getExOleObjAtom().getObjStgDataRef();\r
+ for (int i = 0; i < ole.length; i++) {\r
+ if(ole[i].getExOleObjStg().getPersistId() == ref) return ole[i];\r
+\r
+ }\r
+ logger.log(POILogger.WARN, "OLE data not found");\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Return the record container for this embedded object.\r
+ *\r
+ * <p>\r
+ * It contains:\r
+ * 1. ExEmbedAtom.(4045)\r
+ * 2. ExOleObjAtom (4035)\r
+ * 3. CString (4026), Instance MenuName (1) used for menus and the Links dialog box.\r
+ * 4. CString (4026), Instance ProgID (2) that stores the OLE Programmatic Identifier.\r
+ * A ProgID is a string that uniquely identifies a given object.\r
+ * 5. CString (4026), Instance ClipboardName (3) that appears in the paste special dialog.\r
+ * 6. MetaFile( 4033), optional\r
+ * </p>\r
+ * @return\r
+ */\r
+ public ExEmbed getExEmbed(){\r
+ if(_exEmbed == null){\r
+ SlideShow ppt = getSheet().getSlideShow();\r
+\r
+ ExObjList lst = ppt.getDocumentRecord().getExObjList();\r
+ if(lst == null){\r
+ logger.log(POILogger.WARN, "ExObjList not found");\r
+ return null;\r
+ }\r
+\r
+ int id = getObjectID();\r
+ Record[] ch = lst.getChildRecords();\r
+ for (int i = 0; i < ch.length; i++) {\r
+ if(ch[i] instanceof ExEmbed){\r
+ ExEmbed embd = (ExEmbed)ch[i];\r
+ if( embd.getExOleObjAtom().getObjID() == id) _exEmbed = embd;\r
+ }\r
+ }\r
+ }\r
+ return _exEmbed;\r
+ }\r
+\r
+ /**\r
+ * Returns the instance name of the embedded object, e.g. "Document" or "Workbook".\r
+ *\r
+ * @return the instance name of the embedded object\r
+ */\r
+ public String getInstanceName(){\r
+ return getExEmbed().getMenuName();\r
+ }\r
+\r
+ /**\r
+ * Returns the full name of the embedded object,\r
+ * e.g. "Microsoft Word Document" or "Microsoft Office Excel Worksheet".\r
+ *\r
+ * @return the full name of the embedded object\r
+ */\r
+ public String getFullName(){\r
+ return getExEmbed().getClipboardName();\r
+ }\r
+\r
+ /**\r
+ * Returns the ProgID that stores the OLE Programmatic Identifier.\r
+ * A ProgID is a string that uniquely identifies a given object, for example,\r
+ * "Word.Document.8" or "Excel.Sheet.8".\r
+ *\r
+ * @return the ProgID\r
+ */\r
+ public String getProgID(){\r
+ return getExEmbed().getProgId();\r
+ }\r
+}\r
import java.awt.geom.*;
import java.text.AttributedCharacterIterator;
import java.util.Map;
-import java.util.ArrayList;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.POILogger;
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.hslf.exceptions.HSLFException;
import org.apache.poi.util.POILogger;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.*;
+import java.awt.geom.Rectangle2D;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Arrays;
//set default properties for a picture
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
- setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736);
+ setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x800080);
//another weird feature of powerpoint: for picture id we must add 0x4000.
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
return null;
}
+ /**
+ * Name of this picture.
+ *
+ * @return name of this picture
+ */
+ public String getPictureName(){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ EscherComplexProperty prop = (EscherComplexProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME);
+ String name = null;
+ if(prop != null){
+ try {
+ name = new String(prop.getComplexData(), "UTF-16LE");
+ int idx = name.indexOf('\u0000');
+ return idx == -1 ? name : name.substring(0, idx);
+ } catch (UnsupportedEncodingException e){
+ throw new HSLFException(e);
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Name of this picture.
+ *
+ * @param name of this picture
+ */
+ public void setPictureName(String name){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ try {
+ byte[] data = (name + '\u0000').getBytes("UTF-16LE");
+ EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.BLIP__BLIPFILENAME, false, data);
+ opt.addEscherProperty(prop);
+ } catch (UnsupportedEncodingException e){
+ throw new HSLFException(e);
+ }
+ }
+
/**
* By default set the orininal image size
*/
protected void afterInsert(Sheet sh){
+ super.afterInsert(sh);
java.awt.Rectangle anchor = getAnchor();
if (anchor.equals(new java.awt.Rectangle())){
setDefaultSize();
}
}
+ public void draw(Graphics2D graphics){
+ PictureData data = getPictureData();
+ if (data instanceof Bitmap){
+ BufferedImage img = null;
+ try {
+ img = ImageIO.read(new ByteArrayInputStream(data.getData()));
+ }
+ catch (Exception e){
+ logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + data.getType());
+ return;
+ }
+ Rectangle anchor = getAnchor();
+ Image scaledImg = img.getScaledInstance(anchor.width, anchor.height, Image.SCALE_SMOOTH);
+ graphics.drawImage(scaledImg, anchor.x, anchor.y, null);
+ } else {
+ logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + (data == null ? "NA" : data.getClass().getName()));
+ }
+ }
}
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.hslf.record.PPDrawing;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
-import java.util.Iterator;
+import java.util.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle();
- anchor = new Rectangle2D.Float(
- (float)rec.getDx1()*POINT_DPI/MASTER_DPI,
- (float)rec.getDy1()*POINT_DPI/MASTER_DPI,
- (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
- (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
- );
+ if(rec == null){
+ logger.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found");
+ EscherClientAnchorRecord clrec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
+ anchor = new java.awt.Rectangle();
+ anchor = new Rectangle2D.Float(
+ (float)clrec.getCol1()*POINT_DPI/MASTER_DPI,
+ (float)clrec.getFlag()*POINT_DPI/MASTER_DPI,
+ (float)(clrec.getDx1()-clrec.getCol1())*POINT_DPI/MASTER_DPI,
+ (float)(clrec.getRow1()-clrec.getFlag())*POINT_DPI/MASTER_DPI
+ );
+ } else {
+ anchor = new Rectangle2D.Float(
+ (float)rec.getDx1()*POINT_DPI/MASTER_DPI,
+ (float)rec.getDy1()*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
+ );
+ }
}
else {
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
return anchor;
}
+ public Rectangle2D getLogicalAnchor2D(){
+ return getAnchor2D();
+ }
+
/**
* Sets the anchor (the bounding box rectangle) of this shape.
* All coordinates should be expressed in points (72 dpi).
* @return escher property or <code>null</code> if not found.
*/
public static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
- for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
+ if(opt != null) for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
{
EscherProperty prop = (EscherProperty) iterator.next();
if (prop.getPropertyNumber() == propId)
public int getEscherProperty(short propId){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
- return prop == null ? 0 : prop.getPropertyNumber();
+ return prop == null ? 0 : prop.getPropertyValue();
+ }
+
+ /**
+ * Get the value of a simple escher property for this shape.
+ *
+ * @param propId The id of the property. One of the constants defined in EscherOptRecord.
+ */
+ public int getEscherProperty(short propId, int defaultValue){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
+ return prop == null ? defaultValue : prop.getPropertyValue();
}
/**
* @param sh - owning shape
*/
protected void afterInsert(Sheet sh){
+ PPDrawing ppdrawing = sh.getPPDrawing();
+
+ EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
+
+ EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
+
+ int id = allocateShapeId(dg);
+ setShapeId(id);
+ }
+
+ /**
+ * Allocates new shape id for the new drawing group id.
+ *
+ * @param dg EscherDgRecord of the sheet that owns the shape being created
+ *
+ * @return a new shape id.
+ */
+ protected int allocateShapeId(EscherDgRecord dg)
+ {
+ EscherDggRecord dgg = _sheet.getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
+ if(dgg == null){
+ logger.log(POILogger.ERROR, "EscherDggRecord not found");
+ return 0;
+ }
+
+ dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
+
+ // Add to existing cluster if space available
+ for (int i = 0; i < dgg.getFileIdClusters().length; i++)
+ {
+ EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
+ if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
+ {
+ int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
+ c.incrementShapeId();
+ dg.setNumShapes( dg.getNumShapes() + 1 );
+ dg.setLastMSOSPID( result );
+ if (result >= dgg.getShapeIdMax())
+ dgg.setShapeIdMax( result + 1 );
+ return result;
+ }
+ }
+ // Create new cluster
+ dgg.addCluster( dg.getDrawingGroupId(), 0 );
+ dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
+ dg.setNumShapes( dg.getNumShapes() + 1 );
+ int result = (1024 * dgg.getFileIdClusters().length);
+ dg.setLastMSOSPID( result );
+ if (result >= dgg.getShapeIdMax())
+ dgg.setShapeIdMax( result + 1 );
+ return result;
}
/**
_sheet = sheet;
}
- protected Color getColor(int rgb){
+ protected Color getColor(int rgb, int alpha){
if (rgb >= 0x8000000) {
int idx = rgb - 0x8000000;
ColorSchemeAtom ca = getSheet().getColorScheme();
if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
}
Color tmp = new Color(rgb, true);
- return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
+ return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed(), alpha);
+ }
+
+ /**
+ * @return id for the shape.
+ */
+ public int getShapeId(){
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+ return spRecord == null ? 0 : spRecord.getShapeId();
+ }
+
+ /**
+ * Sets shape ID
+ *
+ * @param id of the shape
+ */
+ public void setShapeId(int id){
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+ if(spRecord != null) spRecord.setShapeId(id);
}
/**
return Hyperlink.find(this);
}
+ public void draw(Graphics2D graphics){
+ logger.log(POILogger.INFO, "Rendering " + getShapeName());
+ }
+
+ /**
+ * Return shape outline as a java.awt.Shape object
+ *
+ * @return the shape outline
+ */
+ public java.awt.Shape getOutline(){
+ return getLogicalAnchor2D();
+ }
}
case ShapeTypes.TextBox:
shape = new TextBox(spContainer, parent);
break;
- case ShapeTypes.PictureFrame:
- shape = new Picture(spContainer, parent);
+ case ShapeTypes.PictureFrame: {
+ EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
+ EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID);
+ if(prop != null)
+ shape = new OLEShape(spContainer, parent); //presence of BLIP__PICTUREID indicates it is an embedded object
+ else
+ shape = new Picture(spContainer, parent);
break;
+ }
case ShapeTypes.Line:
shape = new Line(spContainer, parent);
break;
- case ShapeTypes.NotPrimitive:
+ case ShapeTypes.NotPrimitive: {
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
if(prop != null)
shape = new AutoShape(spContainer, parent);
}
break;
+ }
default:
shape = new AutoShape(spContainer, parent);
break;
import java.util.ArrayList;
import java.util.List;
import java.awt.geom.Rectangle2D;
+import java.awt.geom.AffineTransform;
+import java.awt.*;
/**
* Represents a group of shapes.
spgr.setRectY2((anchor.y + anchor.height)*MASTER_DPI/POINT_DPI);
}
+ /**
+ * Sets the coordinate space of this group. All children are constrained
+ * to these coordinates.
+ *
+ * @param anchor the coordinate space of this group
+ */
+ public void setCoordinates(Rectangle2D anchor){
+ EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
+ EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
+
+ int x1 = (int)Math.round(anchor.getX()*MASTER_DPI/POINT_DPI);
+ int y1 = (int)Math.round(anchor.getY()*MASTER_DPI/POINT_DPI);
+ int x2 = (int)Math.round((anchor.getX() + anchor.getWidth())*MASTER_DPI/POINT_DPI);
+ int y2 = (int)Math.round((anchor.getY() + anchor.getHeight())*MASTER_DPI/POINT_DPI);
+
+ spgr.setRectX1(x1);
+ spgr.setRectY1(y1);
+ spgr.setRectX2(x2);
+ spgr.setRectY2(y2);
+
+ }
+
+ /**
+ * Gets the coordinate space of this group. All children are constrained
+ * to these coordinates.
+ *
+ * @return the coordinate space of this group
+ */
+ public Rectangle2D getCoordinates(){
+ EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
+ EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
+
+ Rectangle2D.Float anchor = new Rectangle2D.Float();
+ anchor.x = (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI;
+ anchor.y = (float)spgr.getRectY1()*POINT_DPI/MASTER_DPI;
+ anchor.width = (float)(spgr.getRectX2() - spgr.getRectX1())*POINT_DPI/MASTER_DPI;
+ anchor.height = (float)(spgr.getRectY2() - spgr.getRectY1())*POINT_DPI/MASTER_DPI;
+
+ return anchor;
+ }
+
/**
* Create a new ShapeGroup and create an instance of <code>EscherSpgrContainer</code> which represents a group of shapes
*/
* @return the anchor of this shape group
*/
public Rectangle2D getAnchor2D(){
- EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0);
- EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(groupInfoContainer, EscherSpgrRecord.RECORD_ID);
- Rectangle2D anchor = new Rectangle2D.Float(
- (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI,
- (float)spgr.getRectY1()*POINT_DPI/MASTER_DPI,
- (float)(spgr.getRectX2() - spgr.getRectX1())*POINT_DPI/MASTER_DPI,
- (float)(spgr.getRectY2() - spgr.getRectY1())*POINT_DPI/MASTER_DPI
- );
+ EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
+ EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
+ Rectangle2D.Float anchor = new Rectangle2D.Float();
+ if(clientAnchor == null){
+ logger.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord.");
+ EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(spContainer, EscherChildAnchorRecord.RECORD_ID);
+ anchor = new Rectangle2D.Float(
+ (float)rec.getDx1()*POINT_DPI/MASTER_DPI,
+ (float)rec.getDy1()*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
+ );
+ } else {
+ anchor.x = (float)clientAnchor.getCol1()*POINT_DPI/MASTER_DPI;
+ anchor.y = (float)clientAnchor.getFlag()*POINT_DPI/MASTER_DPI;
+ anchor.width = (float)(clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ;
+ anchor.height = (float)(clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI;
+ }
return anchor;
}
public Hyperlink getHyperlink(){
return null;
}
-
+
+ public void draw(Graphics2D graphics){
+ Rectangle2D anchor = getAnchor2D();
+ Rectangle2D coords = getCoordinates();
+
+ //transform coordinates
+ AffineTransform at = graphics.getTransform();
+ /*
+ if(!anchor.equals(coords)){
+ graphics.scale(anchor.getWidth()/coords.getWidth(), anchor.getHeight()/coords.getHeight());
+
+ graphics.translate(
+ anchor.getX()*coords.getWidth()/anchor.getWidth() - coords.getX(),
+ anchor.getY()*coords.getHeight()/anchor.getHeight() - coords.getY());
+ }
+ */
+ Shape[] sh = getShapes();
+ for (int i = 0; i < sh.length; i++) {
+ sh[i].draw(graphics);
+ }
+
+ graphics.setTransform(at);
+ }
}
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+/**\r
+ * Date: Apr 17, 2008\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public interface ShapeOutline {\r
+ java.awt.Shape getOutline(Shape shape);\r
+\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+\r
+import org.apache.poi.util.POILogger;\r
+import org.apache.poi.util.POILogFactory;\r
+\r
+import java.awt.*;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+/**\r
+ * Paint a shape into java.awt.Graphics2D\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class ShapePainter {\r
+ protected static POILogger logger = POILogFactory.getLogger(ShapePainter.class);\r
+\r
+ public static void paint(SimpleShape shape, Graphics2D graphics){\r
+ Rectangle2D anchor = shape.getLogicalAnchor2D();\r
+ java.awt.Shape outline = shape.getOutline();\r
+\r
+ //flip vertical\r
+ if(shape.getFlipVertical()){\r
+ graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());\r
+ graphics.scale(1, -1);\r
+ graphics.translate(-anchor.getX(), -anchor.getY());\r
+ }\r
+ //flip horizontal\r
+ if(shape.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
+ //rotate transform\r
+ double angle = shape.getRotation();\r
+\r
+ if(angle != 0){\r
+ double centerX = anchor.getX() + anchor.getWidth()/2;\r
+ double centerY = anchor.getY() + anchor.getHeight()/2;\r
+\r
+ graphics.translate(centerX, centerY);\r
+ graphics.rotate(Math.toRadians(angle));\r
+ graphics.translate(-centerX, -centerY);\r
+ }\r
+\r
+ //fill\r
+ Color fillColor = shape.getFill().getForegroundColor();\r
+ if (fillColor != null) {\r
+ //TODO: implement gradient and texture fill patterns\r
+ graphics.setPaint(fillColor);\r
+ graphics.fill(outline);\r
+ }\r
+\r
+ //border\r
+ Color lineColor = shape.getLineColor();\r
+ if (lineColor != null){\r
+ graphics.setPaint(lineColor);\r
+ float width = (float)shape.getLineWidth();\r
+ if(width == 0) width = 0.75f;\r
+\r
+ int dashing = shape.getLineDashing();\r
+ //TODO: implement more dashing styles\r
+ float[] dashptrn = null;\r
+ switch(dashing){\r
+ case Line.PEN_SOLID:\r
+ dashptrn = null;\r
+ break;\r
+ case Line.PEN_PS_DASH:\r
+ dashptrn = new float[]{width, width};\r
+ break;\r
+ case Line.PEN_DOTGEL:\r
+ dashptrn = new float[]{width*4, width*3};\r
+ break;\r
+ default:\r
+ logger.log(POILogger.WARN, "unsupported dashing: " + dashing);\r
+ dashptrn = new float[]{width, width};\r
+ break;\r
+ }\r
+\r
+ Stroke stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dashptrn, 0.0f);\r
+ graphics.setStroke(stroke);\r
+ graphics.draw(outline);\r
+ }\r
+ }\r
+}\r
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
+import java.awt.*;
/**
* This class defines the common format of "Sheets" in a powerpoint
EscherContainerRecord spgr = (EscherContainerRecord) Shape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER);
spgr.addChildRecord(shape.getSpContainer());
- EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
- dg.setNumShapes(dg.getNumShapes() + 1);
-
- int shapeId = dg.getLastMSOSPID()+1;
- dg.setLastMSOSPID(shapeId);
-
- EscherSpRecord sp = shape.getSpContainer().getChildById(EscherSpRecord.RECORD_ID);
- if(sp != null) sp.setShapeId(shapeId);
shape.setSheet(this);
shape.afterInsert(this);
return _background;
}
+ public void draw(Graphics2D graphics){
+
+ }
}
import org.apache.poi.hslf.record.ColorSchemeAtom;
import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
/**
* An abstract simple (non-group) shape.
getFill().setForegroundColor(color);
}
+ /**
+ * Whether the shape is horizontally flipped
+ *
+ * @return whether the shape is horizontally flipped
+ */
+ public boolean getFlipHorizontal(){
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+ return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0;
+ }
+
+ /**
+ * Whether the shape is vertically flipped
+ *
+ * @return whether the shape is vertically flipped
+ */
+ public boolean getFlipVertical(){
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+ return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0;
+ }
+
+ /**
+ * Rotation angle in degrees
+ *
+ * @return rotation angle in degrees
+ */
+ public int getRotation(){
+ int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION);
+ int angle = (rot >> 16) % 360;
+
+ return angle;
+ }
+
+ public Rectangle2D getLogicalAnchor2D(){
+ Rectangle2D anchor = getAnchor2D();
+
+ //if it is a groupped shape see if we need to transform the coordinates
+ if (_parent != null){
+ Shape top = _parent;
+ while(top.getParent() != null) top = top.getParent();
+
+ Rectangle2D clientAnchor = top.getAnchor2D();
+ Rectangle2D spgrAnchor = ((ShapeGroup)top).getCoordinates();
+
+ double scalex = (double)spgrAnchor.getWidth()/clientAnchor.getWidth();
+ double scaley = (double)spgrAnchor.getHeight()/clientAnchor.getHeight();
+
+ double x = clientAnchor.getX() + (anchor.getX() - spgrAnchor.getX())/scalex;
+ double y = clientAnchor.getY() + (anchor.getY() - spgrAnchor.getY())/scaley;
+ double width = anchor.getWidth()/scalex;
+ double height = anchor.getHeight()/scaley;
+
+ anchor = new Rectangle2D.Double(x, y, width, height);
+
+ }
+
+ int angle = getRotation();
+ if(angle != 0){
+ double centerX = anchor.getX() + anchor.getWidth()/2;
+ double centerY = anchor.getY() + anchor.getHeight()/2;
+
+ AffineTransform trans = new AffineTransform();
+ trans.translate(centerX, centerY);
+ trans.rotate(Math.toRadians(angle));
+ trans.translate(-centerX, -centerY);
+
+ Rectangle2D rect = trans.createTransformedShape(anchor).getBounds2D();
+ if((anchor.getWidth() < anchor.getHeight() && rect.getWidth() > rect.getHeight()) ||
+ (anchor.getWidth() > anchor.getHeight() && rect.getWidth() < rect.getHeight()) ){
+ trans = new AffineTransform();
+ trans.translate(centerX, centerY);
+ trans.rotate(Math.PI/2);
+ trans.translate(-centerX, -centerY);
+ anchor = trans.createTransformedShape(anchor).getBounds2D();
+ }
+ }
+ return anchor;
+ }
+
+ public void draw(Graphics2D graphics){
+ AffineTransform at = graphics.getTransform();
+ ShapePainter.paint(this, graphics);
+ graphics.setTransform(at);
+ }
}
package org.apache.poi.hslf.model;
import java.util.Vector;
-import java.util.List;
-import java.util.Iterator;
-import java.util.ArrayList;
+import java.awt.*;
-import org.apache.poi.hslf.record.PPDrawing;
import org.apache.poi.hslf.record.SlideAtom;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherRecord;
/**
* This class represents a slide in a PowerPoint Document. It allows
return sa.getFollowMasterBackground();
}
- public Background getBackground() {
+ /**
+ * Sets whether this slide draws master sheet objects
+ *
+ * @param flag <code>true</code> if the slide draws master sheet objects,
+ * <code>false</code> otherwise
+ */
+ public void setFollowMasterObjects(boolean flag){
+ SlideAtom sa = getSlideRecord().getSlideAtom();
+ sa.setFollowMasterObjects(flag);
+ }
+
+ /**
+ * Whether this slide follows master color scheme
+ *
+ * @return <code>true</code> if the slide follows master color scheme,
+ * <code>false</code> otherwise
+ */
+ public boolean getFollowMasterScheme(){
+ SlideAtom sa = getSlideRecord().getSlideAtom();
+ return sa.getFollowMasterScheme();
+ }
+
+ /**
+ * Sets whether this slide draws master color scheme
+ *
+ * @param flag <code>true</code> if the slide draws master color scheme,
+ * <code>false</code> otherwise
+ */
+ public void setFollowMasterScheme(boolean flag){
+ SlideAtom sa = getSlideRecord().getSlideAtom();
+ sa.setFollowMasterScheme(flag);
+ }
+
+ /**
+ * Whether this slide draws master sheet objects
+ *
+ * @return <code>true</code> if the slide draws master sheet objects,
+ * <code>false</code> otherwise
+ */
+ public boolean getFollowMasterObjects(){
+ SlideAtom sa = getSlideRecord().getSlideAtom();
+ return sa.getFollowMasterObjects();
+ }
+
+ /**
+ * Background for this slide.
+ */
+ public Background getBackground() {
if(getFollowMasterBackground())
return getMasterSheet().getBackground();
else
return super.getBackground();
}
+
+ /**
+ * Color scheme for this slide.
+ */
+ public ColorSchemeAtom getColorScheme() {
+ if(getFollowMasterScheme()){
+ return getMasterSheet().getColorScheme();
+ }
+ return super.getColorScheme();
+ }
+
+ public void draw(Graphics2D graphics){
+ MasterSheet master = getMasterSheet();
+ if(getFollowMasterBackground()) master.getBackground().draw(graphics);
+ if(getFollowMasterObjects()){
+ Shape[] sh = master.getShapes();
+ for (int i = 0; i < sh.length; i++) {
+ if(MasterSheet.isPlaceholder(sh[i])) continue;
+
+ sh[i].draw(graphics);
+ }
+ }
+ Shape[] sh = getShapes();
+ for (int i = 0; i < sh.length; i++) {
+ sh[i].draw(graphics);
+ }
+ }
+
}
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.SlideShow;
-import org.apache.poi.hslf.record.StyleTextPropAtom.*;
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherRecord;
-
-import java.util.List;
-import java.util.Iterator;
/**
* SlideMaster determines the graphics, layout, and formatting for all the slides in a given presentation.
if (prop != null) break;
}
if (prop == null) {
- switch (txtype) {
- case TextHeaderAtom.CENTRE_BODY_TYPE:
- case TextHeaderAtom.HALF_BODY_TYPE:
- case TextHeaderAtom.QUARTER_BODY_TYPE:
- txtype = TextHeaderAtom.BODY_TYPE;
- break;
- case TextHeaderAtom.CENTER_TITLE_TYPE:
- txtype = TextHeaderAtom.TITLE_TYPE;
- break;
- default:
- return null;
+ if(isCharacter) {
+ switch (txtype) {
+ case TextHeaderAtom.CENTRE_BODY_TYPE:
+ case TextHeaderAtom.HALF_BODY_TYPE:
+ case TextHeaderAtom.QUARTER_BODY_TYPE:
+ txtype = TextHeaderAtom.BODY_TYPE;
+ break;
+ case TextHeaderAtom.CENTER_TITLE_TYPE:
+ txtype = TextHeaderAtom.TITLE_TYPE;
+ break;
+ default:
+ return null;
+ }
+ } else {
+ switch (txtype) {
+ case TextHeaderAtom.CENTRE_BODY_TYPE:
+ case TextHeaderAtom.QUARTER_BODY_TYPE:
+ txtype = TextHeaderAtom.BODY_TYPE;
+ break;
+ case TextHeaderAtom.CENTER_TITLE_TYPE:
+ txtype = TextHeaderAtom.TITLE_TYPE;
+ break;
+ default:
+ return null;
+ }
}
prop = getStyleAttribute(txtype, level, name, isCharacter);
}
}
}
}
+
+ /**
+ * Checks if the shape is a placeholder.
+ * (placeholders aren't normal shapes, they are visible only in the Edit Master mode)
+ *
+ *
+ * @return true if the shape is a placeholder
+ */
+ public static boolean isPlaceholder(Shape shape){
+ if(!(shape instanceof TextShape)) return false;
+
+ TextShape tx = (TextShape)shape;
+ TextRun run = tx.getTextRun();
+ if(run == null) return false;
+
+ Record[] records = run._records;
+ for (int i = 0; i < records.length; i++) {
+ int type = (int)records[i].getRecordType();
+ if (type == RecordTypes.OEPlaceholderAtom.typeID ||
+ type == RecordTypes.SlideNumberMCAtom.typeID ||
+ type == RecordTypes.DateTimeMCAtom.typeID ||
+ type == RecordTypes.GenericDateMCAtom.typeID ||
+ type == RecordTypes.FooterMCAtom.typeID ){
+ return true;
+
+ }
+
+ }
+ return false;
+ }
}
import java.util.*;\r
import java.util.List;\r
import java.awt.*;\r
-import java.awt.geom.Rectangle2D;\r
\r
/**\r
* Represents a table in a PowerPoint presentation\r
}\r
\r
protected void afterInsert(Sheet sh){\r
+ super.afterInsert(sh);\r
+\r
EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);\r
List lst = spCont.getChildRecords();\r
EscherOptRecord opt = (EscherOptRecord)lst.get(lst.size()-2);\r
package org.apache.poi.hslf.model;\r
\r
import org.apache.poi.ddf.*;\r
-import org.apache.poi.hslf.record.EscherTextboxWrapper;\r
import org.apache.poi.hslf.record.TextHeaderAtom;\r
-import org.apache.poi.hslf.usermodel.RichTextRun;\r
\r
import java.awt.*;\r
\r
package org.apache.poi.hslf.model;
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;
-import java.awt.font.TextLayout;
-import java.io.IOException;
/**
* Represents a TextFrame shape in PowerPoint.
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.hslf.usermodel.RichTextRun;\r
+import org.apache.poi.util.POILogger;\r
+import org.apache.poi.util.POILogFactory;\r
+\r
+import java.text.AttributedString;\r
+import java.text.AttributedCharacterIterator;\r
+import java.awt.font.TextAttribute;\r
+import java.awt.font.LineBreakMeasurer;\r
+import java.awt.font.TextLayout;\r
+import java.awt.*;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.geom.Point2D;\r
+import java.util.ArrayList;\r
+\r
+/**\r
+ * Paint text into java.awt.Graphics2D\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class TextPainter {\r
+ protected POILogger logger = POILogFactory.getLogger(this.getClass());\r
+\r
+ protected TextShape _shape;\r
+\r
+ public TextPainter(TextShape shape){\r
+ _shape = shape;\r
+ }\r
+\r
+ /**\r
+ * Convert the underlying set of rich text runs into java.text.AttributedString\r
+ */\r
+ public AttributedString getAttributedString(TextRun txrun){\r
+ String text = txrun.getText();\r
+ AttributedString at = new AttributedString(text);\r
+ RichTextRun[] rt = txrun.getRichTextRuns();\r
+ for (int i = 0; i < rt.length; i++) {\r
+ int start = rt[i].getStartIndex();\r
+ int end = rt[i].getEndIndex();\r
+ if(start == end) {\r
+ logger.log(POILogger.INFO, "Skipping RichTextRun with zero length");\r
+ continue;\r
+ }\r
+\r
+ at.addAttribute(TextAttribute.FAMILY, rt[i].getFontName(), start, end);\r
+ at.addAttribute(TextAttribute.SIZE, new Float(rt[i].getFontSize()), start, end);\r
+ at.addAttribute(TextAttribute.FOREGROUND, rt[i].getFontColor(), start, end);\r
+ if(rt[i].isBold()) at.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, start, end);\r
+ if(rt[i].isItalic()) at.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, start, end);\r
+ if(rt[i].isUnderlined()) {\r
+ at.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, start, end);\r
+ at.addAttribute(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_TWO_PIXEL, start, end);\r
+ }\r
+ if(rt[i].isStrikethrough()) at.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, start, end);\r
+ int superScript = rt[i].getSuperscript();\r
+ if(superScript != 0) at.addAttribute(TextAttribute.SUPERSCRIPT, superScript > 0 ? TextAttribute.SUPERSCRIPT_SUPER : TextAttribute.SUPERSCRIPT_SUB, start, end);\r
+\r
+ }\r
+ return at;\r
+ }\r
+\r
+ public void paint(Graphics2D graphics){\r
+ TextRun run = _shape.getTextRun();\r
+ if (run == null) return;\r
+\r
+ String text = run.getText();\r
+ if (text == null || text.equals("")) return;\r
+\r
+ AttributedString at = getAttributedString(run);\r
+\r
+ AttributedCharacterIterator it = at.getIterator();\r
+ int paragraphStart = it.getBeginIndex();\r
+ int paragraphEnd = it.getEndIndex();\r
+\r
+ Rectangle2D anchor = _shape.getLogicalAnchor2D();\r
+\r
+ float textHeight = 0;\r
+ ArrayList lines = new ArrayList();\r
+ LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());\r
+ measurer.setPosition(paragraphStart);\r
+ while (measurer.getPosition() < paragraphEnd) {\r
+ int startIndex = measurer.getPosition();\r
+ int nextBreak = text.indexOf('\n', measurer.getPosition() + 1);\r
+\r
+ boolean prStart = text.charAt(startIndex) == '\n';\r
+ if(prStart) measurer.setPosition(startIndex++);\r
+\r
+ RichTextRun rt = run.getRichTextRunAt(startIndex == text.length() ? (startIndex-1) : startIndex);\r
+ if(rt == null) {\r
+ logger.log(POILogger.WARN, "RichTextRun not found at pos" + startIndex + "; text.length: " + text.length());\r
+ break;\r
+ }\r
+\r
+ float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();\r
+ wrappingWidth -= rt.getTextOffset();\r
+\r
+ if (_shape.getWordWrap() == TextShape.WrapNone) {\r
+ wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;\r
+ }\r
+\r
+ TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1,\r
+ nextBreak == -1 ? paragraphEnd : nextBreak, true);\r
+ if (textLayout == null) {\r
+ textLayout = measurer.nextLayout((float)anchor.getWidth(),\r
+ nextBreak == -1 ? paragraphEnd : nextBreak, false);\r
+ }\r
+ if(textLayout == null){\r
+ logger.log(POILogger.WARN, "Failed to break text into lines: wrappingWidth: "+wrappingWidth+\r
+ "; text: " + rt.getText());\r
+ measurer.setPosition(rt.getEndIndex());\r
+ continue;\r
+ }\r
+ int endIndex = measurer.getPosition();\r
+\r
+ float lineHeight = (float)textLayout.getBounds().getHeight();\r
+ int linespacing = rt.getLineSpacing();\r
+ if(linespacing == 0) linespacing = 100;\r
+\r
+ TextElement el = new TextElement();\r
+ if(linespacing >= 0){\r
+ el.ascent = textLayout.getAscent()*linespacing/100;\r
+ } else {\r
+ el.ascent = -linespacing*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+ }\r
+\r
+ el._align = rt.getAlignment();\r
+ el._text = textLayout;\r
+ el._textOffset = rt.getTextOffset();\r
+\r
+ if (prStart){\r
+ int sp = rt.getSpaceBefore();\r
+ float spaceBefore;\r
+ if(sp >= 0){\r
+ spaceBefore = lineHeight * sp/100;\r
+ } else {\r
+ spaceBefore = -sp*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+ }\r
+ el.ascent += spaceBefore;\r
+ }\r
+\r
+ float descent;\r
+ if(linespacing >= 0){\r
+ descent = (textLayout.getDescent() + textLayout.getLeading())*linespacing/100;\r
+ } else {\r
+ descent = -linespacing*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+ }\r
+ if (prStart){\r
+ int sp = rt.getSpaceAfter();\r
+ float spaceAfter;\r
+ if(sp >= 0){\r
+ spaceAfter = lineHeight * sp/100;\r
+ } else {\r
+ spaceAfter = -sp*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+ }\r
+ el.ascent += spaceAfter;\r
+ }\r
+ el.descent = descent;\r
+\r
+ textHeight += el.ascent + el.descent;\r
+\r
+ if(rt.isBullet() && (prStart || startIndex == 0)){\r
+ it.setIndex(startIndex);\r
+\r
+ AttributedString bat = new AttributedString(Character.toString(rt.getBulletChar()));\r
+ Color clr = rt.getBulletColor();\r
+ if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);\r
+ else bat.addAttribute(TextAttribute.FOREGROUND, it.getAttribute(TextAttribute.FOREGROUND));\r
+ bat.addAttribute(TextAttribute.FAMILY, it.getAttribute(TextAttribute.FAMILY));\r
+ bat.addAttribute(TextAttribute.SIZE, it.getAttribute(TextAttribute.SIZE));\r
+\r
+ TextLayout bulletLayout = new TextLayout(bat.getIterator(), graphics.getFontRenderContext());\r
+ if(text.substring(startIndex, endIndex).length() > 1){\r
+ el._bullet = bulletLayout;\r
+ el._bulletOffset = rt.getBulletOffset();\r
+ }\r
+ }\r
+ lines.add(el);\r
+ }\r
+\r
+ int valign = _shape.getVerticalAlignment();\r
+ double y0 = anchor.getY();\r
+ switch (valign){\r
+ case TextShape.AnchorTopBaseline:\r
+ case TextShape.AnchorTop:\r
+ y0 += _shape.getMarginTop();\r
+ break;\r
+ case TextShape.AnchorBottom:\r
+ y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();\r
+ break;\r
+ default:\r
+ case TextShape.AnchorMiddle:\r
+ float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();\r
+ y0 += _shape.getMarginTop() + delta/2;\r
+ break;\r
+ }\r
+\r
+ //finally draw the text fragments\r
+ for (int i = 0; i < lines.size(); i++) {\r
+ TextElement elem = (TextElement)lines.get(i);\r
+ y0 += elem.ascent;\r
+\r
+ Point2D.Double pen = new Point2D.Double();\r
+ pen.y = y0;\r
+ switch (elem._align) {\r
+ default:\r
+ case TextShape.AlignLeft:\r
+ pen.x = anchor.getX() + _shape.getMarginLeft();\r
+ break;\r
+ case TextShape.AlignCenter:\r
+ pen.x = anchor.getX() + _shape.getMarginLeft() +\r
+ (anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;\r
+ break;\r
+ case TextShape.AlignRight:\r
+ pen.x = anchor.getX() + _shape.getMarginLeft() +\r
+ (anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight());\r
+ break;\r
+ }\r
+ if(elem._bullet != null){\r
+ elem._bullet.draw(graphics, (float)(pen.x + elem._bulletOffset), (float)pen.y);\r
+ }\r
+ elem._text.draw(graphics, (float)(pen.x + elem._textOffset), (float)pen.y);\r
+\r
+ y0 += elem.descent;\r
+ }\r
+ }\r
+\r
+\r
+ static class TextElement {\r
+ public TextLayout _text;\r
+ public int _textOffset;\r
+ public TextLayout _bullet;\r
+ public int _bulletOffset;\r
+ public int _align;\r
+ public float ascent, descent;\r
+ }\r
+}\r
// The messes things up on everything but a Mac, so translate
// them to \n
String text = rawText.replace('\r','\n');
+
+ //0xB acts like cariage return in page titles
+ text = text.replace((char) 0x0B, '\n');
+
return text;
}
public Hyperlink[] getHyperlinks(){
return Hyperlink.find(this);
}
+
+ /**
+ * Fetch RichTextRun at a given position
+ *
+ * @param pos 0-based index in the text
+ * @return RichTextRun or null if not found
+ */
+ public RichTextRun getRichTextRunAt(int pos){
+ for (int i = 0; i < _rtRuns.length; i++) {
+ int start = _rtRuns[i].getStartIndex();
+ int end = _rtRuns[i].getEndIndex();
+ if(pos >= start && pos < end) return _rtRuns[i];
+ }
+ return null;
+ }
+
}
* @param sh the sheet we are adding to\r
*/\r
protected void afterInsert(Sheet sh){\r
+ super.afterInsert(sh);\r
+\r
EscherTextboxWrapper _txtbox = getEscherTextboxWrapper();\r
if(_txtbox != null){\r
PPDrawing ppdrawing = sh.getPPDrawing();\r
}\r
}\r
}\r
+\r
+ public void draw(Graphics2D graphics){\r
+ AffineTransform at = graphics.getTransform();\r
+ ShapePainter.paint(this, graphics);\r
+ new TextPainter(this).paint(graphics);\r
+ graphics.setTransform(at);\r
+ }\r
+\r
}\r
*
* @author Daniel Noll
*/
-public class ExOleObjStg extends RecordAtom {
+public class ExOleObjStg extends RecordAtom implements PersistRecord {
+
+ private int _persistId; // Found from PersistPtrHolder
+
/**
* Record header.
*/
out.write(_header);
out.write(_data);
}
+
+ /**
+ * Fetch our sheet ID, as found from a PersistPtrHolder.
+ * Should match the RefId of our matching SlidePersistAtom
+ */
+ public int getPersistId() {
+ return _persistId;
+ }
+
+ /**
+ * Set our sheet ID, as found from a PersistPtrHolder
+ */
+ public void setPersistId(int id) {
+ _persistId = id;
+ }
}
private byte[] _header;
private EscherContainerRecord dggContainer;
+ //cached dgg
+ private EscherDggRecord dgg;
protected PPDrawingGroup(byte[] source, int start, int len) {
// Get the header
public EscherContainerRecord getDggContainer(){
return dggContainer;
}
+
+ public EscherDggRecord getEscherDggRecord(){
+ if(dgg == null){
+ for(Iterator it = dggContainer.getChildRecords().iterator(); it.hasNext();){
+ EscherRecord r = (EscherRecord) it.next();
+ if(r instanceof EscherDggRecord){
+ dgg = (EscherDggRecord)r;
+ break;
+ }
+ }
+ }
+ return dgg;
+ }
}
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+/**\r
+ * A record that can be referenced in PersistPtr storage.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public interface PersistRecord {\r
+\r
+ /**\r
+ * Fetch the persist ID\r
+ */\r
+ public int getPersistId();\r
+\r
+ /**\r
+ * Set the persist ID\r
+ */\r
+ public void setPersistId(int id);\r
+}\r
public static final Type List = new Type(2000,null);
public static final Type FontCollection = new Type(2005,FontCollection.class);
public static final Type BookmarkCollection = new Type(2019,null);
+ public static final Type SoundCollection = new Type(2020,SoundCollection.class);
public static final Type SoundCollAtom = new Type(2021,null);
- public static final Type Sound = new Type(2022,null);
- public static final Type SoundData = new Type(2023,null);
+ public static final Type Sound = new Type(2022,Sound.class);
+ public static final Type SoundData = new Type(2023,SoundData.class);
public static final Type BookmarkSeedAtom = new Type(2025,null);
public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class);
public static final Type ExObjRefAtom = new Type(3009,null);
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.record;\r
+\r
+import org.apache.poi.util.POILogger;\r
+\r
+import java.io.OutputStream;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * A container holding information about a sound. It contains:\r
+ * <p>\r
+ * <li>1. CString (4026), Instance 0: Name of sound (e.g. "crash")\r
+ * <li>2. CString (4026), Instance 1: Type of sound (e.g. ".wav")\r
+ * <li>3. CString (4026), Instance 2: Reference id of sound in sound collection\r
+ * <li>4. CString (4026), Instance 3, optional: Built-in id of sound, for sounds we ship. This is the id that?s in the reg file.\r
+ * <li>5. SoundData (2023), optional\r
+ * </p>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class Sound extends RecordContainer {\r
+ /**\r
+ * Record header data.\r
+ */\r
+ private byte[] _header;\r
+\r
+ // Links to our more interesting children\r
+ private CString _name;\r
+ private CString _type;\r
+ private SoundData _data;\r
+\r
+\r
+ /**\r
+ * Set things up, and find our more interesting children\r
+ *\r
+ * @param source the source data as a byte array.\r
+ * @param start the start offset into the byte array.\r
+ * @param len the length of the slice in the byte array.\r
+ */\r
+ protected Sound(byte[] source, int start, int len) {\r
+ // Grab the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Find our children\r
+ _children = Record.findChildRecords(source,start+8,len-8);\r
+ findInterestingChildren();\r
+ }\r
+\r
+ private void findInterestingChildren() {\r
+ // First child should be the ExHyperlinkAtom\r
+ if(_children[0] instanceof CString) {\r
+ _name = (CString)_children[0];\r
+ } else {\r
+ logger.log(POILogger.ERROR, "First child record wasn't a CString, was of type " + _children[0].getRecordType());\r
+ }\r
+\r
+ // Second child should be the ExOleObjAtom\r
+ if (_children[1] instanceof CString) {\r
+ _type = (CString)_children[1];\r
+ } else {\r
+ logger.log(POILogger.ERROR, "Second child record wasn't a CString, was of type " + _children[1].getRecordType());\r
+ }\r
+\r
+ for (int i = 2; i < _children.length; i++) {\r
+ if(_children[i] instanceof SoundData){\r
+ _data = (SoundData)_children[i];\r
+ break;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ /**\r
+ * Returns the type (held as a little endian in bytes 3 and 4)\r
+ * that this class handles.\r
+ *\r
+ * @return the record type.\r
+ */\r
+ public long getRecordType() {\r
+ return RecordTypes.Sound.typeID;\r
+ }\r
+\r
+ /**\r
+ * Have the contents printer out into an OutputStream, used when\r
+ * writing a file back out to disk.\r
+ *\r
+ * @param out the output stream.\r
+ * @throws java.io.IOException if there was an error writing to the stream.\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ writeOut(_header[0],_header[1],getRecordType(),_children,out);\r
+ }\r
+\r
+ /**\r
+ * Name of the sound (e.g. "crash")\r
+ *\r
+ * @return name of the sound\r
+ */\r
+ public String getSoundName(){\r
+ return _name.getText();\r
+ }\r
+\r
+ /**\r
+ * Type of the sound (e.g. ".wav")\r
+ *\r
+ * @return type of the sound\r
+ */\r
+ public String getSoundType(){\r
+ return _type.getText();\r
+ }\r
+\r
+ /**\r
+ * The sound data\r
+ *\r
+ * @return the sound data.\r
+ */\r
+ public byte[] getSoundData(){\r
+ return _data == null ? null : _data.getData();\r
+ }\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.record;\r
+\r
+import org.apache.poi.util.POILogger;\r
+\r
+import java.io.OutputStream;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * Is a container for all sound related atoms and containers. It contains:\r
+ *<li>1. SoundCollAtom (2021)\r
+ *<li>2. Sound (2022), for each sound, if any\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class SoundCollection extends RecordContainer {\r
+ /**\r
+ * Record header data.\r
+ */\r
+ private byte[] _header;\r
+\r
+ /**\r
+ * Set things up, and find our more interesting children\r
+ *\r
+ * @param source the source data as a byte array.\r
+ * @param start the start offset into the byte array.\r
+ * @param len the length of the slice in the byte array.\r
+ */\r
+ protected SoundCollection(byte[] source, int start, int len) {\r
+ // Grab the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Find our children\r
+ _children = Record.findChildRecords(source,start+8,len-8);\r
+ }\r
+\r
+ /**\r
+ * Returns the type (held as a little endian in bytes 3 and 4)\r
+ * that this class handles.\r
+ *\r
+ * @return the record type.\r
+ */\r
+ public long getRecordType() {\r
+ return RecordTypes.SoundCollection.typeID;\r
+ }\r
+\r
+ /**\r
+ * Have the contents printer out into an OutputStream, used when\r
+ * writing a file back out to disk.\r
+ *\r
+ * @param out the output stream.\r
+ * @throws java.io.IOException if there was an error writing to the stream.\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ writeOut(_header[0],_header[1],getRecordType(),_children,out);\r
+ }\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.util.zip.InflaterInputStream;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * Storage for embedded sounds.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class SoundData extends RecordAtom {\r
+\r
+ /**\r
+ * Record header.\r
+ */\r
+ private byte[] _header;\r
+\r
+ /**\r
+ * Record data.\r
+ */\r
+ private byte[] _data;\r
+\r
+ /**\r
+ * Constructs a new empty sound container.\r
+ */\r
+ protected SoundData() {\r
+ _header = new byte[8];\r
+ _data = new byte[0];\r
+\r
+ LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+ LittleEndian.putInt(_header, 4, _data.length);\r
+ }\r
+\r
+ /**\r
+ * Constructs the link related atom record from its\r
+ * source data.\r
+ *\r
+ * @param source the source data as a byte array.\r
+ * @param start the start offset into the byte array.\r
+ * @param len the length of the slice in the byte array.\r
+ */\r
+ protected SoundData(byte[] source, int start, int len) {\r
+ // Get the header.\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Get the record data.\r
+ _data = new byte[len-8];\r
+ System.arraycopy(source,start+8,_data,0,len-8);\r
+ }\r
+\r
+ /**\r
+ * Returns the sound data.\r
+ *\r
+ * @return the sound data \r
+ */\r
+ public byte[] getData() {\r
+ return _data;\r
+ }\r
+\r
+ /**\r
+ * Gets the record type.\r
+ *\r
+ * @return the record type.\r
+ */\r
+ public long getRecordType() {\r
+ return RecordTypes.SoundData.typeID;\r
+ }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk.\r
+ *\r
+ * @param out the output stream to write to.\r
+ * @throws java.io.IOException if an error occurs.\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ out.write(_header);\r
+ out.write(_data);\r
+ }\r
+}\r
new TextProp(2, 0x800000, "symbol"),
new TextProp(2, 0x20000, "font.size"),
new TextProp(4, 0x40000, "font.color"),
- new TextProp(2, 0x80000, "offset"),
+ new TextProp(2, 0x80000, "superscript"),
new TextProp(2, 0x100000, "char_unknown_1"),
new TextProp(2, 0x1000000, "char_unknown_3"),
new TextProp(2, 0x2000000, "char_unknown_4"),
public InputStream getData() {
return storage.getData();
}
+
+ /**
+ * Return the record that contains the object data.
+ *
+ * @return the record that contains the object data.
+ */
+ public ExOleObjStg getExOleObjStg() {
+ return storage;
+ }
}
/**
* Represents a run of text, all with the same style
*
- * TODO: finish all the getters and setters to the
- * font/character/paragraph properties (currently only
- * has some of them)
*/
public class RichTextRun {
/** The TextRun we belong to */
public int getLength() {
return length;
}
-
+
+ /**
+ * The beginning index, inclusive.
+ *
+ * @return the beginning index, inclusive.
+ */
+ public int getStartIndex(){
+ return startPos;
+ }
+
+ /**
+ * The ending index, exclusive.
+ *
+ * @return the ending index, exclusive.
+ */
+ public int getEndIndex(){
+ return startPos + length;
+ }
+
/**
* Fetch the text, in output suitable form
*/
// --------------- Friendly getters / setters on rich text properties -------
-
+
+ /**
+ * Is the text bold?
+ */
public boolean isBold() {
return isCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX);
}
+
+ /**
+ * Is the text bold?
+ */
public void setBold(boolean bold) {
setCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX, bold);
}
+ /**
+ * Is the text italic?
+ */
public boolean isItalic() {
return isCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX);
}
+
+ /**
+ * Is the text italic?
+ */
public void setItalic(boolean italic) {
setCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX, italic);
}
+ /**
+ * Is the text underlined?
+ */
public boolean isUnderlined() {
return isCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX);
}
+
+ /**
+ * Is the text underlined?
+ */
public void setUnderlined(boolean underlined) {
setCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX, underlined);
}
-
+
+ /**
+ * Does the text have a shadow?
+ */
+ public boolean isShadowed() {
+ return isCharFlagsTextPropVal(CharFlagsTextProp.SHADOW_IDX);
+ }
+
+ /**
+ * Does the text have a shadow?
+ */
+ public void setShadowed(boolean flag) {
+ setCharFlagsTextPropVal(CharFlagsTextProp.SHADOW_IDX, flag);
+ }
+
+ /**
+ * Is this text embossed?
+ */
+ public boolean isEmbossed() {
+ return isCharFlagsTextPropVal(CharFlagsTextProp.RELIEF_IDX);
+ }
+
+ /**
+ * Is this text embossed?
+ */
+ public void setEmbossed(boolean flag) {
+ setCharFlagsTextPropVal(CharFlagsTextProp.RELIEF_IDX, flag);
+ }
+
+ /**
+ * Gets the strikethrough flag
+ */
+ public boolean isStrikethrough() {
+ return isCharFlagsTextPropVal(CharFlagsTextProp.STRIKETHROUGH_IDX);
+ }
+
+ /**
+ * Sets the strikethrough flag
+ */
+ public void setStrikethrough(boolean flag) {
+ setCharFlagsTextPropVal(CharFlagsTextProp.STRIKETHROUGH_IDX, flag);
+ }
+
+ /**
+ * Gets the subscript/superscript option
+ *
+ * @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
+ */
+ public int getSuperscript() {
+ int val = getCharTextPropVal("superscript");
+ return val == -1 ? 0 : val;
+ }
+
+ /**
+ * Sets the subscript/superscript option
+ *
+ * @param val the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
+ */
+ public void setSuperscript(int val) {
+ setCharTextPropVal("superscript", val);
+ }
+
+ /**
+ * Gets the font size
+ */
public int getFontSize() {
return getCharTextPropVal("font.size");
}
+
+
+ /**
+ * Sets the font size
+ */
public void setFontSize(int fontSize) {
setCharTextPropVal("font.size", fontSize);
}
-
+
+ /**
+ * Gets the font index
+ */
+ public int getFontIndex() {
+ return getCharTextPropVal("font.index");
+ }
+
+ /**
+ * Sets the font index
+ */
+ public void setFontIndex(int idx) {
+ setCharTextPropVal("font.index", idx);
+ }
+
+
+ /**
+ * Sets the font name to use
+ */
public void setFontName(String fontName) {
if (slideShow == null) {
//we can't set font since slideshow is not assigned yet
setCharTextPropVal("font.index", fontIdx);
}
}
+
+ /**
+ * Gets the font name
+ */
public String getFontName() {
if (slideShow == null) {
return _fontname;
*/
public Color getFontColor() {
int rgb = getCharTextPropVal("font.color");
- if (rgb >= 0x8000000) {
- int idx = rgb % 0x8000000;
+
+ int cidx = rgb >> 24;
+ if (rgb % 0x1000000 == 0){
ColorSchemeAtom ca = parentRun.getSheet().getColorScheme();
- if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
+ if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
}
-
Color tmp = new Color(rgb, true);
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
}
/**
* Sets indentation level
*
- * @param level indentation level. Must be in the range [0, 5]
+ * @param level indentation level. Must be in the range [0, 4]
*/
public void setIndentLevel(int level) {
if(paragraphStyle != null ) paragraphStyle.setReservedField((short)level);
public int getTextOffset() {
return getParaTextPropVal("text.offset")*Shape.POINT_DPI/Shape.MASTER_DPI;
}
+
+ /**
+ * Sets the bullet size
+ */
+ public void setBulletSize(int size) {
+ setParaTextPropVal("bullet.size", size);
+ }
+
+ /**
+ * Returns the bullet size
+ */
+ public int getBulletSize() {
+ return getParaTextPropVal("bullet.size");
+ }
+
+ /**
+ * Sets the bullet color
+ */
+ public void setBulletColor(Color color) {
+ int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();
+ setParaTextPropVal("bullet.color", rgb);
+ }
+
+ /**
+ * Returns the bullet color
+ */
+ public Color getBulletColor() {
+ int rgb = getParaTextPropVal("bullet.color");
+ if(rgb == -1) return getFontColor();
+
+ int cidx = rgb >> 24;
+ if (rgb % 0x1000000 == 0){
+ ColorSchemeAtom ca = parentRun.getSheet().getColorScheme();
+ if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
+ }
+ Color tmp = new Color(rgb, true);
+ return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
+ }
+
+ /**
+ * Sets the bullet font
+ */
+ public void setBulletFont(int idx) {
+ setParaTextPropVal("bullet.font", idx);
+ }
+
+ /**
+ * Returns the bullet font
+ */
+ public int getBulletFont() {
+ return getParaTextPropVal("bullet.font");
+ }
+
+ /**
+ * Sets the line spacing.
+ * <p>
+ * If linespacing >= 0, then linespacing is a percentage of normal line height.
+ * If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates.
+ * </p>
+ */
+ public void setLineSpacing(int val) {
+ setParaTextPropVal("linespacing", val);
+ }
+
+ /**
+ * Returns the line spacing
+ * <p>
+ * If linespacing >= 0, then linespacing is a percentage of normal line height.
+ * If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates.
+ * </p>
+ *
+ * @return the spacing between lines
+ */
+ public int getLineSpacing() {
+ int val = getParaTextPropVal("linespacing");
+ return val == -1 ? 0 : val;
+ }
+
+ /**
+ * Sets spacing before a paragraph.
+ * <p>
+ * If spacebefore >= 0, then spacebefore is a percentage of normal line height.
+ * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
+ * </p>
+ */
+ public void setSpaceBefore(int val) {
+ setParaTextPropVal("spacebefore", val);
+ }
+
+ /**
+ * Returns spacing before a paragraph
+ * <p>
+ * If spacebefore >= 0, then spacebefore is a percentage of normal line height.
+ * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates.
+ * </p>
+ *
+ * @return the spacing before a paragraph
+ */
+ public int getSpaceBefore() {
+ int val = getParaTextPropVal("spacebefore");
+ return val == -1 ? 0 : val;
+ }
+
+ /**
+ * Sets spacing after a paragraph.
+ * <p>
+ * If spaceafter >= 0, then spaceafter is a percentage of normal line height.
+ * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
+ * </p>
+ */
+ public void setSpaceAfter(int val) {
+ setParaTextPropVal("spaceafter", val);
+ }
+
+ /**
+ * Returns spacing after a paragraph
+ * <p>
+ * If spaceafter >= 0, then spaceafter is a percentage of normal line height.
+ * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates.
+ * </p>
+ *
+ * @return the spacing before a paragraph
+ */
+ public int getSpaceAfter() {
+ int val = getParaTextPropVal("spaceafter");
+ return val == -1 ? 0 : val;
+ }
// --------------- Internal HSLF methods, not intended for end-user use! -------
/**
public PictureData[] getPictureData() {
return _hslfSlideShow.getPictures();
}
-
+
+ /**
+ * Returns the data of all the embedded OLE object in the SlideShow
+ */
+ public ObjectData[] getEmbeddedObjects() {
+ return _hslfSlideShow.getEmbeddedObjects();
+ }
+
+ /**
+ * Returns the data of all the embedded sounds in the SlideShow
+ */
+ public SoundData[] getSoundData() {
+ return SoundData.find(_documentRecord);
+ }
+
/**
* Return the current page size
*/
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.usermodel;\r
+\r
+import org.apache.poi.hslf.record.*;\r
+\r
+import java.util.ArrayList;\r
+\r
+/**\r
+ * A class that represents sound data embedded in a slide show.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class SoundData {\r
+ /**\r
+ * The record that contains the object data.\r
+ */\r
+ private Sound _container;\r
+\r
+ /**\r
+ * Creates the object data wrapping the record that contains the sound data.\r
+ *\r
+ * @param container the record that contains the sound data.\r
+ */\r
+ public SoundData(Sound container) {\r
+ this._container = container;\r
+ }\r
+\r
+ /**\r
+ * Name of the sound (e.g. "crash")\r
+ *\r
+ * @return name of the sound\r
+ */\r
+ public String getSoundName(){\r
+ return _container.getSoundName();\r
+ }\r
+\r
+ /**\r
+ * Type of the sound (e.g. ".wav")\r
+ *\r
+ * @return type of the sound\r
+ */\r
+ public String getSoundType(){\r
+ return _container.getSoundType();\r
+ }\r
+\r
+ /**\r
+ * Gets an input stream which returns the binary of the sound data.\r
+ *\r
+ * @return the input stream which will contain the binary of the sound data.\r
+ */\r
+ public byte[] getData() {\r
+ return _container.getSoundData();\r
+ }\r
+\r
+ /**\r
+ * Find all sound records in the supplied Document records\r
+ *\r
+ * @param document the document to find in\r
+ * @return the array with the sound data\r
+ */\r
+ public static SoundData[] find(Document document){\r
+ ArrayList lst = new ArrayList();\r
+ Record[] ch = document.getChildRecords();\r
+ for (int i = 0; i < ch.length; i++) {\r
+ if(ch[i].getRecordType() == RecordTypes.SoundCollection.typeID){\r
+ RecordContainer col = (RecordContainer)ch[i];\r
+ Record[] sr = col.getChildRecords();\r
+ for (int j = 0; j < sr.length; j++) {\r
+ if(sr[j] instanceof Sound){\r
+ lst.add(new SoundData((Sound)sr[j]));\r
+ }\r
+ }\r
+ }\r
+\r
+ }\r
+ return (SoundData[])lst.toArray(new SoundData[lst.size()]);\r
+ }\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.model;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.usermodel.RichTextRun;\r
+import org.apache.poi.hslf.HSLFSlideShow;\r
+\r
+import java.awt.*;\r
+import java.awt.Rectangle;\r
+import java.awt.geom.*;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+\r
+/**\r
+ * Test Freeform object.\r
+ * The Freeform shape is constructed from java.awt.GeneralPath.\r
+ * Check that the get/set path accessors are consistent.\r
+ * (TODO: verification of Bezier curves is more difficult due to rounding error. Figure out a test approach for that)\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestFreeform extends TestCase {\r
+\r
+ public void testClosedPath() throws Exception {\r
+\r
+ GeneralPath path1 = new GeneralPath();\r
+ path1.moveTo(100, 100);\r
+ path1.lineTo(200, 100);\r
+ path1.lineTo(200, 200);\r
+ path1.lineTo(100, 200);\r
+ path1.closePath();\r
+\r
+ Freeform p = new Freeform();\r
+ p.setPath(path1);\r
+\r
+ GeneralPath path2 = p.getPath();\r
+ assertTrue(new Area(path1).equals(new Area(path2)));\r
+ }\r
+\r
+ public void testLine() throws Exception {\r
+\r
+ GeneralPath path1 = new GeneralPath(new Line2D.Double(100, 100, 200, 100));\r
+\r
+ Freeform p = new Freeform();\r
+ p.setPath(path1);\r
+\r
+ GeneralPath path2 = p.getPath();\r
+ assertTrue(new Area(path1).equals(new Area(path2)));\r
+ }\r
+\r
+ public void testRectangle() throws Exception {\r
+\r
+ GeneralPath path1 = new GeneralPath(new Rectangle2D.Double(100, 100, 200, 50));\r
+\r
+ Freeform p = new Freeform();\r
+ p.setPath(path1);\r
+\r
+ GeneralPath path2 = p.getPath();\r
+ assertTrue(new Area(path1).equals(new Area(path2)));\r
+ }\r
+}\r
package org.apache.poi.hslf.model;\r
\r
import java.io.*;\r
+import java.util.List;\r
+import java.util.ArrayList;\r
\r
import org.apache.poi.hslf.HSLFSlideShow;\r
import org.apache.poi.hslf.usermodel.ObjectData;\r
import org.apache.poi.hslf.usermodel.PictureData;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.hssf.usermodel.HSSFSheet;\r
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;\r
+import org.apache.poi.hwpf.HWPFDocument;\r
+import org.apache.poi.hwpf.usermodel.Range;\r
+import org.apache.poi.hwpf.usermodel.Paragraph;\r
\r
import junit.framework.TestCase;\r
\r
slideShow.close();\r
}\r
}\r
+\r
+ public void testOLEShape() throws Exception {\r
+ String dirname = System.getProperty("HSLF.testdata.path");\r
+ File file = new File(dirname, "ole2-embedding-2003.ppt");\r
+ FileInputStream is = new FileInputStream(file);\r
+ SlideShow ppt = new SlideShow(is);\r
+ is.close();\r
+\r
+ Slide slide = ppt.getSlides()[0];\r
+ Shape[] sh = slide.getShapes();\r
+ int cnt = 0;\r
+ for (int i = 0; i < sh.length; i++) {\r
+ if(sh[i] instanceof OLEShape){\r
+ cnt++;\r
+ OLEShape ole = (OLEShape)sh[i];\r
+ ObjectData data = ole.getObjectData();\r
+ if("Worksheet".equals(ole.getInstanceName())){\r
+ //Voila! we created a workbook from the embedded OLE data\r
+ HSSFWorkbook wb = new HSSFWorkbook(data.getData());\r
+ HSSFSheet sheet = wb.getSheetAt(0);\r
+ //verify we can access the xls data\r
+ assertEquals(1, sheet.getRow(0).getCell((short)0).getNumericCellValue(), 0);\r
+ assertEquals(1, sheet.getRow(1).getCell((short)0).getNumericCellValue(), 0);\r
+ assertEquals(2, sheet.getRow(2).getCell((short)0).getNumericCellValue(), 0);\r
+ assertEquals(3, sheet.getRow(3).getCell((short)0).getNumericCellValue(), 0);\r
+ assertEquals(8, sheet.getRow(5).getCell((short)0).getNumericCellValue(), 0);\r
+ } else if ("Document".equals(ole.getInstanceName())){\r
+ //creating a HWPF document \r
+ HWPFDocument doc = new HWPFDocument(data.getData());\r
+ String txt = doc.getRange().getParagraph(0).text();\r
+ assertEquals("OLE embedding is thoroughly unremarkable.\r", txt);\r
+ }\r
+ }\r
+\r
+ }\r
+ assertEquals("Expected 2 OLE shapes", 2, cnt);\r
+ }\r
}\r
sl = ppt.getSlides()[0];
assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length);
}
+
+ public void testShapeId() throws IOException {
+ SlideShow ppt = new SlideShow();
+ Slide slide = ppt.createSlide();
+ Shape shape;
+
+ shape = new Line();
+ assertEquals(0, shape.getShapeId());
+ slide.addShape(shape);
+ assertTrue(shape.getShapeId() > 0);
+
+ int shapeId = shape.getShapeId();
+
+ shape = new Line();
+ assertEquals(0, shape.getShapeId());
+ slide.addShape(shape);
+ assertEquals(shapeId + 1, shape.getShapeId());
+ }
}
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.Arrays;\r
+\r
+import org.apache.poi.hslf.HSLFSlideShow;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+\r
+/**\r
+ * Tests Sound-related records: SoundCollection(2020), Sound(2022) and SoundData(2023)).\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestSound extends TestCase {\r
+ public void testRealFile() throws Exception {\r
+ String cwd = System.getProperty("HSLF.testdata.path");\r
+ FileInputStream is = new FileInputStream(new File(cwd, "sound.ppt"));\r
+ SlideShow ppt = new SlideShow(is);\r
+ is.close();\r
+\r
+ // Get the document\r
+ Document doc = ppt.getDocumentRecord();\r
+ SoundCollection soundCollection = null;\r
+ Record[] doc_ch = doc.getChildRecords();\r
+ for (int i = 0; i < doc_ch.length; i++) {\r
+ if(doc_ch[i] instanceof SoundCollection){\r
+ soundCollection = (SoundCollection)doc_ch[i];\r
+ break;\r
+ }\r
+ }\r
+ assertNotNull(soundCollection);\r
+\r
+ Sound sound = null;\r
+ Record[] sound_ch = soundCollection.getChildRecords();\r
+ int k = 0;\r
+ for (int i = 0; i < sound_ch.length; i++) {\r
+ if(sound_ch[i] instanceof Sound){\r
+ sound = (Sound)sound_ch[i];\r
+ k++;\r
+ }\r
+ }\r
+ assertNotNull(sound);\r
+ assertEquals(1, k);\r
+\r
+ assertEquals("ringin.wav", sound.getSoundName());\r
+ assertEquals(".WAV", sound.getSoundType());\r
+ assertNotNull(sound.getSoundData());\r
+\r
+ File f = new File(cwd, "ringin.wav");\r
+ int length = (int)f.length();\r
+ byte[] ref_data = new byte[length];\r
+ is = new FileInputStream(f);\r
+ is.read(ref_data);\r
+ is.close();\r
+\r
+ assertTrue(Arrays.equals(ref_data, sound.getSoundData()));\r
+\r
+ }\r
+}\r
\r
assertTrue("No Exceptions while reading file", true);\r
}\r
+\r
+ /**\r
+ * Bug 41071: Will not extract text from Powerpoint TextBoxes\r
+ */\r
+ public void test41071() throws Exception {\r
+ FileInputStream is = new FileInputStream(new File(cwd, "41071.ppt"));\r
+ SlideShow ppt = new SlideShow(is);\r
+ is.close();\r
+\r
+ Slide slide = ppt.getSlides()[0];\r
+ Shape[] sh = slide.getShapes();\r
+ assertEquals(1, sh.length);\r
+ assertTrue(sh[0] instanceof TextShape);\r
+ TextShape tx = (TextShape)sh[0];\r
+ assertEquals("Fundera, planera och involvera.", tx.getTextRun().getText());\r
+\r
+ TextRun[] run = slide.getTextRuns();\r
+ assertEquals(1, run.length);\r
+ assertEquals("Fundera, planera och involvera.", run[0].getText());\r
+ }\r
}\r
assertTrue(pdata instanceof WMF);
assertEquals(Picture.WMF, pdata.getType());
}
+
+ public void testGetPictureName() throws Exception {
+ SlideShow ppt = new SlideShow(new HSLFSlideShow(new File(cwd, "ppt_with_png.ppt").getPath()));
+ Slide slide = ppt.getSlides()[0];
+
+ Picture p = (Picture)slide.getShapes()[0]; //the first slide contains JPEG
+ assertEquals("test", p.getPictureName());
+ }
+
+ public void testSetPictureName() throws Exception {
+ SlideShow ppt = new SlideShow();
+
+ Slide slide = ppt.createSlide();
+ File img = new File(cwd, "tomcat.png");
+ int idx = ppt.addPicture(img, Picture.PNG);
+ Picture pict = new Picture(idx);
+ pict.setPictureName("tomcat.png");
+ slide.addShape(pict);
+
+ //serialize and read again
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ppt.write(out);
+ out.close();
+
+ ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
+
+ Picture p = (Picture)ppt.getSlides()[0].getShapes()[0];
+ assertEquals("tomcat.png", p.getPictureName());
+ }
}
"ROMANCE: AN ANALYSIS",
"AGENDA",
"You are an important supplier of various items that I need",
- (char)0x0B + "Although The Psycho set back my relationship process, recovery is luckily enough under way",
+ '\n' + "Although The Psycho set back my relationship process, recovery is luckily enough under way",
"Since the time that we seriously go out together, you rank highly among existing relationships",
"Although our personal interests are mostly compatible, the greatest gap exists in Sex and Shopping",
"Your physical characteristics are strong when compared with your competition",
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.usermodel;\r
+\r
+import org.apache.poi.hslf.*;\r
+import org.apache.poi.hslf.exceptions.HSLFException;\r
+import org.apache.poi.hslf.blip.*;\r
+import org.apache.poi.hslf.model.*;\r
+import junit.framework.TestCase;\r
+\r
+import java.io.*;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Test reading sound data from a ppt\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestSoundData extends TestCase{\r
+\r
+ protected File cwd;\r
+\r
+ public void setUp() throws Exception {\r
+ cwd = new File(System.getProperty("HSLF.testdata.path"));\r
+ }\r
+\r
+ /**\r
+ * Read a reference sound file from disk and compare it from the data extracted from the slide show\r
+ */ \r
+ public void testSounds() throws Exception {\r
+ //read the reference sound file\r
+ File f = new File(cwd, "ringin.wav");\r
+ int length = (int)f.length();\r
+ byte[] ref_data = new byte[length];\r
+ FileInputStream is = new FileInputStream(f);\r
+ is.read(ref_data);\r
+ is.close();\r
+\r
+ is = new FileInputStream(new File(cwd, "sound.ppt"));\r
+ SlideShow ppt = new SlideShow(is);\r
+ is.close();\r
+\r
+ SoundData[] sound = ppt.getSoundData();\r
+ assertEquals("Expected 1 sound", 1, sound.length);\r
+\r
+ assertTrue(Arrays.equals(ref_data, sound[0].getData()));\r
+ }\r
+}\r
}
assertEquals(713, rowsSeen);
}
+
+ /**
+ * Bug 28774: Excel will crash when opening xls-files with images.
+ */
+ public void test28774() {
+
+ HSSFWorkbook wb = openSample("28774.xls");
+ assertTrue("no errors reading sample xls", true);
+ writeOutAndReadBack(wb);
+ assertTrue("no errors writing sample xls", true);
+ }
}
assertEquals(HSSFTextbox.VERTICAL_ALIGNMENT_CENTER, textbox.getVerticalAlignment());\r
}\r
\r
+ /**\r
+ * Excel requires at least one format run in HSSFTextbox.\r
+ * When inserting text make sure that if font is not set we must set the default one.\r
+ */\r
+ public void testSetDeafultTextFormat() {\r
+ HSSFWorkbook wb = new HSSFWorkbook();\r
+ HSSFSheet sheet = wb.createSheet();\r
+ HSSFPatriarch patriarch = sheet.createDrawingPatriarch();\r
+\r
+ HSSFTextbox textbox1 = patriarch.createTextbox(new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)3,3));\r
+ HSSFRichTextString rt1 = new HSSFRichTextString("Hello, World!");\r
+ assertEquals(0, rt1.numFormattingRuns());\r
+ textbox1.setString(rt1);\r
+\r
+ HSSFRichTextString rt2 = textbox1.getString();\r
+ assertEquals(1, rt2.numFormattingRuns());\r
+ assertEquals(HSSFRichTextString.NO_FONT, rt2.getFontOfFormattingRun(0));\r
+ }\r
+\r
}\r