<li><link href="#OLE">How to retrieve embedded OLE objects</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>
</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 might 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>
--- /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.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
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 = getAnchor2D();
+ if(outline == null){
+ logger.log(POILogger.WARN, "getOutline() is not implemented 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
+\r
+}\r
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;
}
import org.apache.poi.ddf.*;\r
import org.apache.poi.util.LittleEndian;\r
import org.apache.poi.util.POILogger;\r
-import org.apache.poi.util.HexDump;\r
\r
import java.awt.geom.*;\r
import java.util.ArrayList;\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 = getAnchor2D();
+ 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;
+ }
}
package org.apache.poi.hslf.model;\r
\r
import org.apache.poi.ddf.*;\r
-import org.apache.poi.hslf.usermodel.PictureData;\r
import org.apache.poi.hslf.usermodel.SlideShow;\r
import org.apache.poi.hslf.usermodel.ObjectData;\r
-import org.apache.poi.hslf.record.Document;\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.hslf.blip.Bitmap;\r
import org.apache.poi.util.POILogger;\r
\r
-import javax.imageio.ImageIO;\r
-import java.awt.image.BufferedImage;\r
-import java.awt.*;\r
-import java.io.ByteArrayInputStream;\r
-import java.io.IOException;\r
-import java.util.List;\r
-import java.util.Arrays;\r
-\r
\r
/**\r
* A shape representing embedded OLE obejct.\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 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.util.List;
}
}
+ 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.getType());
+ }
+ }
}
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
-import org.apache.poi.hslf.model.ShapeTypes;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
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();
+ }
+
/**
* @return The shape container and it's children that can represent this
* shape.
_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 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 getAnchor2D();
+ }
}
import java.util.ArrayList;
import java.util.List;
import java.awt.geom.Rectangle2D;
+import java.awt.*;
/**
* Represents a group of shapes.
public Hyperlink getHyperlink(){
return null;
}
-
+
+ public void draw(Graphics2D graphics){
+ Shape[] sh = getShapes();
+ for (int i = 0; i < sh.length; i++) {
+ sh[i].draw(graphics);
+ }
+ }
}
--- /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 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
+\r
+ public static void paint(SimpleShape shape, Graphics2D graphics){\r
+ Rectangle2D anchor = shape.getAnchor2D();\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
+ 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
+ int dashing = shape.getLineDashing();\r
+ //TODO: implement more dashing styles\r
+ float[] dashptrn = null;\r
+ switch(dashing){\r
+ case Line.PEN_PS_DASH:\r
+ dashptrn = new float[]{2, 2};\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
return _background;
}
+ public void draw(Graphics2D graphics){
+
+ }
}
import org.apache.poi.hslf.record.ColorSchemeAtom;
import java.awt.*;
+import java.awt.geom.AffineTransform;
/**
* 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 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;
+ }
+ 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
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
+ 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) continue;\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
+ protected RichTextRun getRichTextRunAt(int pos){\r
+ RichTextRun[] rt = _shape.getTextRun().getRichTextRuns();\r
+ for (int i = 0; i < rt.length; i++) {\r
+ int start = rt[i].getStartIndex();\r
+ int end = rt[i].getEndIndex();\r
+ if(pos >= start && pos < end) return rt[i];\r
+ }\r
+ return null;\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.getAnchor2D();\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
+ RichTextRun rt = getRichTextRunAt(startIndex + 1);\r
+ if(rt == null) {\r
+ logger.log(POILogger.WARN, "RichTextRun not found at pos" + (startIndex + 1) + "; 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(wrappingWidth,\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
+ TextElement el = new TextElement();\r
+ el._startIndex = startIndex;\r
+ el._endIndex = endIndex;\r
+ el._align = rt.getAlignment();\r
+ el._text = textLayout;\r
+ el._textOffset = rt.getTextOffset();\r
+\r
+ boolean prStart = text.charAt(startIndex) == '\n' || startIndex == 0;\r
+ if (text.charAt(startIndex) == '\n'){\r
+ int spaceBefore = rt.getSpaceBefore();\r
+ if (spaceBefore != 0) {\r
+ float val = (textLayout.getAscent() + textLayout.getDescent()) * spaceBefore/100;\r
+ textHeight += val;\r
+ }\r
+ }\r
+ if(rt.isBullet() && prStart){\r
+ it.setIndex(startIndex);\r
+\r
+ AttributedString bat = new AttributedString(Character.toString(rt.getBulletChar()), it.getAttributes());\r
+ int bulletSize = rt.getBulletSize();\r
+ if (bulletSize != -1){\r
+ Float sz = (Float)bat.getIterator().getAttribute(TextAttribute.SIZE);\r
+ if(sz != null) bat.addAttribute(TextAttribute.SIZE, new Float(sz.floatValue()*bulletSize/100));\r
+ }\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
+\r
+ textHeight += textLayout.getAscent() + textLayout.getLeading();\r
+\r
+ int lineSpacing = rt.getLineSpacing();\r
+ if(lineSpacing != 0) el._spacing = textLayout.getDescent()*lineSpacing/100;\r
+ else el._spacing = textLayout.getDescent();\r
+\r
+ textHeight += el._spacing;\r
+\r
+ lines.add(el);\r
+ }\r
+\r
+ int valign = _shape.getVerticalAlignment();\r
+ double y0 = anchor.getY();\r
+ switch (valign){\r
+ case TextBox.AnchorTopBaseline:\r
+ case TextBox.AnchorTop:\r
+ y0 += _shape.getMarginTop();\r
+ break;\r
+ case TextBox.AnchorBottom:\r
+ y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();\r
+ break;\r
+ default:\r
+ case TextBox.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._text.getAscent();\r
+\r
+ Point2D.Double pen = new Point2D.Double();\r
+ pen.y = y0;\r
+ switch (elem._align) {\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
+ default:\r
+ pen.x = anchor.getX() + _shape.getMarginLeft();\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._text.getDescent();\r
+ y0 += elem._text.getLeading();\r
+\r
+ y0 += elem._spacing;\r
+ }\r
+ }\r
+\r
+\r
+ public 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 int _startIndex;\r
+ public int _endIndex;\r
+ public float _spacing;\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;
}
}\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
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"),
/**
* 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;
/**
* 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 = getCharTextPropVal("bullet.color");
+ if (rgb >= 0x8000000) {
+ int idx = rgb % 0x8000000;
+ ColorSchemeAtom ca = parentRun.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());
+ }
+
+ /**
+ * 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;
+ }
// --------------- Internal HSLF methods, not intended for end-user use! -------
/**
"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",