initial support for rendering powerpoint slides into images

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@649143 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-04-17 15:08:03 +00:00
parent 4fdf2061e6
commit dbae8942ef
28 changed files with 1334 additions and 68 deletions

View File

@ -44,6 +44,7 @@
<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>
@ -550,6 +551,53 @@
</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 &lt; 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>

View File

@ -0,0 +1,103 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.examples;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.record.TextHeaderAtom;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
/**
* Demonstrates how you can use HSLF to convert each slide into a PNG image
*
* @author Yegor Kozlov
*/
public class PPT2PNG {
public static void main(String args[]) throws Exception {
if (args.length == 0) {
usage();
return;
}
int slidenum = -1;
float scale = 1;
String file = null;
for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) {
if ("-scale".equals(args[i])){
scale = Float.parseFloat(args[++i]);
} else if ("-slide".equals(args[i])) {
slidenum = Integer.parseInt(args[++i]);
}
} else {
file = args[i];
}
}
if(file == null){
usage();
return;
}
FileInputStream is = new FileInputStream(file);
SlideShow ppt = new SlideShow(is);
is.close();
Dimension pgsize = ppt.getPageSize();
int width = (int)(pgsize.width*scale);
int height = (int)(pgsize.height*scale);
Slide[] slide = ppt.getSlides();
for (int i = 0; i < slide.length; i++) {
if (slidenum != -1 && slidenum != (i+1)) continue;
String title = slide[i].getTitle();
System.out.println("Rendering slide "+slide[i].getSlideNumber() + (title == null ? "" : ": " + title));
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, width, height));
graphics.scale((double)width/pgsize.width, (double)height/pgsize.height);
slide[i].draw(graphics);
String fname = file.replaceAll("\\.ppt", "-" + (i+1) + ".png");
FileOutputStream out = new FileOutputStream(fname);
ImageIO.write(img, "png", out);
out.close();
}
}
private static void usage(){
System.out.println("Usage: PPT2PNG [-scale <scale> -slide <num>] ppt");
}
}

View File

@ -18,6 +18,9 @@
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.
@ -102,4 +105,17 @@ public class AutoShape extends TextShape {
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);
}
}
}

View File

@ -0,0 +1,293 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.EscherProperties;
import java.awt.geom.*;
/**
* Stores definition of auto-shapes.
* See the Office Drawing 97-2007 Binary Format Specification for details.
*
* TODO: follow the spec and define all the auto-shapes
*
* @author Yegor Kozlov
*/
public class AutoShapes {
protected static ShapeOutline[] shapes;
/**
* Return shape outline by shape type
* @param type shape type see {@link ShapeTypes}
*
* @return the shape outline
*/
public static ShapeOutline getShapeOutline(int type){
ShapeOutline outline = shapes[type];
return outline;
}
/**
* Auto-shapes are defined in the [0,21600] coordinate system.
* We need to transform it into normal slide coordinates
*
*/
public static java.awt.Shape transform(java.awt.Shape outline, Rectangle2D anchor){
AffineTransform at = new AffineTransform();
at.translate(anchor.getX(), anchor.getY());
at.scale(
1.0f/21600*anchor.getWidth(),
1.0f/21600*anchor.getHeight()
);
return at.createTransformedShape(outline);
}
static {
shapes = new ShapeOutline[255];
shapes[ShapeTypes.Rectangle] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
Rectangle2D path = new Rectangle2D.Float(0, 0, 21600, 21600);
return path;
}
};
shapes[ShapeTypes.RoundRectangle] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
RoundRectangle2D path = new RoundRectangle2D.Float(0, 0, 21600, 21600, adjval, adjval);
return path;
}
};
shapes[ShapeTypes.Ellipse] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
Ellipse2D path = new Ellipse2D.Float(0, 0, 21600, 21600);
return path;
}
};
shapes[ShapeTypes.Diamond] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
GeneralPath path = new GeneralPath();
path.moveTo(10800, 0);
path.lineTo(21600, 10800);
path.lineTo(10800, 21600);
path.lineTo(0, 10800);
path.closePath();
return path;
}
};
//m@0,l,21600r21600
shapes[ShapeTypes.IsocelesTriangle] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 10800);
GeneralPath path = new GeneralPath();
path.moveTo(adjval, 0);
path.lineTo(0, 21600);
path.lineTo(21600, 21600);
path.closePath();
return path;
}
};
shapes[ShapeTypes.RightTriangle] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
GeneralPath path = new GeneralPath();
path.moveTo(0, 0);
path.lineTo(21600, 21600);
path.lineTo(0, 21600);
path.closePath();
return path;
}
};
shapes[ShapeTypes.Parallelogram] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(adjval, 0);
path.lineTo(21600, 0);
path.lineTo(21600 - adjval, 21600);
path.lineTo(0, 21600);
path.closePath();
return path;
}
};
shapes[ShapeTypes.Trapezoid] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(0, 0);
path.lineTo(adjval, 21600);
path.lineTo(21600 - adjval, 21600);
path.lineTo(21600, 0);
path.closePath();
return path;
}
};
shapes[ShapeTypes.Hexagon] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(adjval, 0);
path.lineTo(21600 - adjval, 0);
path.lineTo(21600, 10800);
path.lineTo(21600 - adjval, 21600);
path.lineTo(adjval, 21600);
path.lineTo(0, 10800);
path.closePath();
return path;
}
};
shapes[ShapeTypes.Octagon] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 6326);
GeneralPath path = new GeneralPath();
path.moveTo(adjval, 0);
path.lineTo(21600 - adjval, 0);
path.lineTo(21600, adjval);
path.lineTo(21600, 21600-adjval);
path.lineTo(21600-adjval, 21600);
path.lineTo(adjval, 21600);
path.lineTo(0, 21600-adjval);
path.lineTo(0, adjval);
path.closePath();
return path;
}
};
shapes[ShapeTypes.Plus] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(adjval, 0);
path.lineTo(21600 - adjval, 0);
path.lineTo(21600 - adjval, adjval);
path.lineTo(21600, adjval);
path.lineTo(21600, 21600-adjval);
path.lineTo(21600-adjval, 21600-adjval);
path.lineTo(21600-adjval, 21600);
path.lineTo(adjval, 21600);
path.lineTo(adjval, 21600-adjval);
path.lineTo(0, 21600-adjval);
path.lineTo(0, adjval);
path.lineTo(adjval, adjval);
path.closePath();
return path;
}
};
shapes[ShapeTypes.Pentagon] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
GeneralPath path = new GeneralPath();
path.moveTo(10800, 0);
path.lineTo(21600, 8259);
path.lineTo(21600 - 4200, 21600);
path.lineTo(4200, 21600);
path.lineTo(0, 8259);
path.closePath();
return path;
}
};
shapes[ShapeTypes.DownArrow] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
//m0@0 l@1@0 @1,0 @2,0 @2@0,21600@0,10800,21600xe
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200);
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(0, adjval);
path.lineTo(adjval2, adjval);
path.lineTo(adjval2, 0);
path.lineTo(21600-adjval2, 0);
path.lineTo(21600-adjval2, adjval);
path.lineTo(21600, adjval);
path.lineTo(10800, 21600);
path.closePath();
return path;
}
};
shapes[ShapeTypes.UpArrow] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
//m0@0 l@1@0 @1,21600@2,21600@2@0,21600@0,10800,xe
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(0, adjval);
path.lineTo(adjval2, adjval);
path.lineTo(adjval2, 21600);
path.lineTo(21600-adjval2, 21600);
path.lineTo(21600-adjval2, adjval);
path.lineTo(21600, adjval);
path.lineTo(10800, 0);
path.closePath();
return path;
}
};
shapes[ShapeTypes.Arrow] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
//m@0, l@0@1 ,0@1,0@2@0@2@0,21600,21600,10800xe
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200);
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(adjval, 0);
path.lineTo(adjval, adjval2);
path.lineTo(0, adjval2);
path.lineTo(0, 21600-adjval2);
path.lineTo(adjval, 21600-adjval2);
path.lineTo(adjval, 21600);
path.lineTo(21600, 10800);
path.closePath();
return path;
}
};
shapes[ShapeTypes.LeftArrow] = new ShapeOutline(){
public java.awt.Shape getOutline(Shape shape){
//m@0, l@0@1,21600@1,21600@2@0@2@0,21600,,10800xe
int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400);
int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400);
GeneralPath path = new GeneralPath();
path.moveTo(adjval, 0);
path.lineTo(adjval, adjval2);
path.lineTo(21600, adjval2);
path.lineTo(21600, 21600-adjval2);
path.lineTo(adjval, 21600-adjval2);
path.lineTo(adjval, 21600);
path.lineTo(0, 10800);
path.closePath();
return path;
}
};
}
}

View File

@ -22,12 +22,10 @@ import org.apache.poi.ddf.*;
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.
@ -137,13 +135,15 @@ public class Fill {
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;
}
@ -176,7 +176,7 @@ public class Fill {
Color clr = null;
if (p1 != null && (p2val & 0x10) != 0){
int rgb = p1.getPropertyValue();
clr = shape.getColor(rgb);
clr = shape.getColor(rgb, 255);
}
return clr;
}

View File

@ -19,7 +19,6 @@ package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.HexDump;
import java.awt.geom.*;
import java.util.ArrayList;
@ -237,4 +236,8 @@ public class Freeform extends AutoShape {
return path;
}
public java.awt.Shape getOutline(){
return getPath();
}
}

View File

@ -19,6 +19,9 @@ package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Line2D;
/**
* Represents a line in a PowerPoint drawing
*
@ -126,4 +129,8 @@ public class Line extends SimpleShape {
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());
}
}

View File

@ -17,6 +17,8 @@
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;
/**
@ -37,4 +39,32 @@ public abstract class MasterSheet extends Sheet {
*/
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;
}
}

View File

@ -17,24 +17,13 @@
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.usermodel.ObjectData;
import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.record.ExObjList;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.ExEmbed;
import org.apache.poi.hslf.blip.Bitmap;
import org.apache.poi.util.POILogger;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Arrays;
/**
* A shape representing embedded OLE obejct.

View File

@ -27,7 +27,6 @@ import java.awt.image.renderable.RenderableImage;
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;

View File

@ -26,6 +26,7 @@ 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;
@ -202,4 +203,22 @@ public class Picture extends SimpleShape {
}
}
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());
}
}
}

View File

@ -17,7 +17,6 @@
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;
@ -297,6 +296,17 @@ public abstract class Shape {
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.
@ -333,14 +343,14 @@ public abstract class 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);
}
/**
@ -364,4 +374,16 @@ public abstract class Shape {
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();
}
}

View File

@ -24,6 +24,7 @@ import org.apache.poi.hslf.record.EscherTextboxWrapper;
import java.util.ArrayList;
import java.util.List;
import java.awt.geom.Rectangle2D;
import java.awt.*;
/**
* Represents a group of shapes.
@ -223,4 +224,10 @@ public class ShapeGroup extends Shape{
return null;
}
public void draw(Graphics2D graphics){
Shape[] sh = getShapes();
for (int i = 0; i < sh.length; i++) {
sh[i].draw(graphics);
}
}
}

View File

@ -0,0 +1,27 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
/**
* Date: Apr 17, 2008
*
* @author Yegor Kozlov
*/
public interface ShapeOutline {
java.awt.Shape getOutline(Shape shape);
}

View File

@ -0,0 +1,85 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import java.awt.*;
import java.awt.geom.Rectangle2D;
/**
* Paint a shape into java.awt.Graphics2D
*
* @author Yegor Kozlov
*/
public class ShapePainter {
public static void paint(SimpleShape shape, Graphics2D graphics){
Rectangle2D anchor = shape.getAnchor2D();
java.awt.Shape outline = shape.getOutline();
//flip vertical
if(shape.getFlipVertical()){
graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());
graphics.scale(1, -1);
graphics.translate(-anchor.getX(), -anchor.getY());
}
//flip horizontal
if(shape.getFlipHorizontal()){
graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());
graphics.scale(-1, 1);
graphics.translate(-anchor.getX() , -anchor.getY());
}
//rotate transform
double angle = shape.getRotation();
if(angle != 0){
double centerX = anchor.getX() + anchor.getWidth()/2;
double centerY = anchor.getY() + anchor.getHeight()/2;
graphics.translate(centerX, centerY);
graphics.rotate(Math.toRadians(angle));
graphics.translate(-centerX, -centerY);
}
//fill
Color fillColor = shape.getFill().getForegroundColor();
if (fillColor != null) {
graphics.setPaint(fillColor);
graphics.fill(outline);
}
//border
Color lineColor = shape.getLineColor();
if (lineColor != null){
graphics.setPaint(lineColor);
float width = (float)shape.getLineWidth();
int dashing = shape.getLineDashing();
//TODO: implement more dashing styles
float[] dashptrn = null;
switch(dashing){
case Line.PEN_PS_DASH:
dashptrn = new float[]{2, 2};
break;
}
Stroke stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dashptrn, 0.0f);
graphics.setStroke(stroke);
graphics.draw(outline);
}
}
}

View File

@ -29,6 +29,7 @@ import java.util.ArrayList;
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
@ -329,4 +330,7 @@ public abstract class Sheet {
return _background;
}
public void draw(Graphics2D graphics){
}
}

View File

@ -22,6 +22,7 @@ import org.apache.poi.util.LittleEndian;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import java.awt.*;
import java.awt.geom.AffineTransform;
/**
* An abstract simple (non-group) shape.
@ -199,4 +200,41 @@ public class SimpleShape extends 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);
}
}

View File

@ -21,17 +21,12 @@
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
@ -263,10 +258,85 @@ public class Slide extends Sheet
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);
}
}
}

View File

@ -21,12 +21,6 @@ import org.apache.poi.hslf.model.textproperties.TextProp;
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.
@ -82,17 +76,33 @@ public class SlideMaster extends MasterSheet {
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);
}
@ -119,4 +129,34 @@ public class SlideMaster extends MasterSheet {
}
}
}
/**
* 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;
}
}

View File

@ -23,7 +23,6 @@ import org.apache.poi.util.LittleEndian;
import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.geom.Rectangle2D;
/**
* Represents a table in a PowerPoint presentation

View File

@ -18,9 +18,7 @@
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.EscherTextboxWrapper;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.usermodel.RichTextRun;
import java.awt.*;

View File

@ -19,15 +19,6 @@
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.

View File

@ -0,0 +1,238 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import java.text.AttributedString;
import java.text.AttributedCharacterIterator;
import java.awt.font.TextAttribute;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
/**
* Paint text into java.awt.Graphics2D
*
* @author Yegor Kozlov
*/
public class TextPainter {
protected POILogger logger = POILogFactory.getLogger(this.getClass());
protected TextShape _shape;
public TextPainter(TextShape shape){
_shape = shape;
}
public AttributedString getAttributedString(TextRun txrun){
String text = txrun.getText();
AttributedString at = new AttributedString(text);
RichTextRun[] rt = txrun.getRichTextRuns();
for (int i = 0; i < rt.length; i++) {
int start = rt[i].getStartIndex();
int end = rt[i].getEndIndex();
if(start == end) continue;
at.addAttribute(TextAttribute.FAMILY, rt[i].getFontName(), start, end);
at.addAttribute(TextAttribute.SIZE, new Float(rt[i].getFontSize()), start, end);
at.addAttribute(TextAttribute.FOREGROUND, rt[i].getFontColor(), start, end);
if(rt[i].isBold()) at.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, start, end);
if(rt[i].isItalic()) at.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, start, end);
if(rt[i].isUnderlined()) {
at.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, start, end);
at.addAttribute(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_TWO_PIXEL, start, end);
}
if(rt[i].isStrikethrough()) at.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, start, end);
int superScript = rt[i].getSuperscript();
if(superScript != 0) at.addAttribute(TextAttribute.SUPERSCRIPT, superScript > 0 ? TextAttribute.SUPERSCRIPT_SUPER : TextAttribute.SUPERSCRIPT_SUB, start, end);
}
return at;
}
protected RichTextRun getRichTextRunAt(int pos){
RichTextRun[] rt = _shape.getTextRun().getRichTextRuns();
for (int i = 0; i < rt.length; i++) {
int start = rt[i].getStartIndex();
int end = rt[i].getEndIndex();
if(pos >= start && pos < end) return rt[i];
}
return null;
}
public void paint(Graphics2D graphics){
TextRun run = _shape.getTextRun();
if (run == null) return;
String text = run.getText();
if (text == null || text.equals("")) return;
AttributedString at = getAttributedString(run);
AttributedCharacterIterator it = at.getIterator();
int paragraphStart = it.getBeginIndex();
int paragraphEnd = it.getEndIndex();
Rectangle2D anchor = _shape.getAnchor2D();
float textHeight = 0;
ArrayList lines = new ArrayList();
LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());
measurer.setPosition(paragraphStart);
while (measurer.getPosition() < paragraphEnd) {
int startIndex = measurer.getPosition();
int nextBreak = text.indexOf('\n', measurer.getPosition() + 1);
RichTextRun rt = getRichTextRunAt(startIndex + 1);
if(rt == null) {
logger.log(POILogger.WARN, "RichTextRun not found at pos" + (startIndex + 1) + "; text.length: " + text.length());
break;
}
float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();
wrappingWidth -= rt.getTextOffset();
if (_shape.getWordWrap() == TextShape.WrapNone) {
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
}
TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1,
nextBreak == -1 ? paragraphEnd : nextBreak, true);
if (textLayout == null) {
textLayout = measurer.nextLayout(wrappingWidth,
nextBreak == -1 ? paragraphEnd : nextBreak, false);
}
if(textLayout == null){
logger.log(POILogger.WARN, "Failed to break text into lines: wrappingWidth: "+wrappingWidth+
"; text: " + rt.getText());
measurer.setPosition(rt.getEndIndex());
continue;
}
int endIndex = measurer.getPosition();
TextElement el = new TextElement();
el._startIndex = startIndex;
el._endIndex = endIndex;
el._align = rt.getAlignment();
el._text = textLayout;
el._textOffset = rt.getTextOffset();
boolean prStart = text.charAt(startIndex) == '\n' || startIndex == 0;
if (text.charAt(startIndex) == '\n'){
int spaceBefore = rt.getSpaceBefore();
if (spaceBefore != 0) {
float val = (textLayout.getAscent() + textLayout.getDescent()) * spaceBefore/100;
textHeight += val;
}
}
if(rt.isBullet() && prStart){
it.setIndex(startIndex);
AttributedString bat = new AttributedString(Character.toString(rt.getBulletChar()), it.getAttributes());
int bulletSize = rt.getBulletSize();
if (bulletSize != -1){
Float sz = (Float)bat.getIterator().getAttribute(TextAttribute.SIZE);
if(sz != null) bat.addAttribute(TextAttribute.SIZE, new Float(sz.floatValue()*bulletSize/100));
}
TextLayout bulletLayout = new TextLayout(bat.getIterator(), graphics.getFontRenderContext());
if(text.substring(startIndex, endIndex).length() > 1){
el._bullet = bulletLayout;
el._bulletOffset = rt.getBulletOffset();
}
}
textHeight += textLayout.getAscent() + textLayout.getLeading();
int lineSpacing = rt.getLineSpacing();
if(lineSpacing != 0) el._spacing = textLayout.getDescent()*lineSpacing/100;
else el._spacing = textLayout.getDescent();
textHeight += el._spacing;
lines.add(el);
}
int valign = _shape.getVerticalAlignment();
double y0 = anchor.getY();
switch (valign){
case TextBox.AnchorTopBaseline:
case TextBox.AnchorTop:
y0 += _shape.getMarginTop();
break;
case TextBox.AnchorBottom:
y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();
break;
default:
case TextBox.AnchorMiddle:
float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();
y0 += _shape.getMarginTop() + delta/2;
break;
}
//finally draw the text fragments
for (int i = 0; i < lines.size(); i++) {
TextElement elem = (TextElement)lines.get(i);
y0 += elem._text.getAscent();
Point2D.Double pen = new Point2D.Double();
pen.y = y0;
switch (elem._align) {
case TextShape.AlignLeft:
pen.x = anchor.getX() + _shape.getMarginLeft();
break;
case TextShape.AlignCenter:
pen.x = anchor.getX() + _shape.getMarginLeft() +
(anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
break;
case TextShape.AlignRight:
pen.x = anchor.getX() + _shape.getMarginLeft() +
(anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight());
break;
default:
pen.x = anchor.getX() + _shape.getMarginLeft();
break;
}
if(elem._bullet != null){
elem._bullet.draw(graphics, (float)(pen.x + elem._bulletOffset), (float)pen.y);
}
elem._text.draw(graphics, (float)(pen.x + elem._textOffset), (float)pen.y);
y0 += elem._text.getDescent();
y0 += elem._text.getLeading();
y0 += elem._spacing;
}
}
public static class TextElement {
public TextLayout _text;
public int _textOffset;
public TextLayout _bullet;
public int _bulletOffset;
public int _align;
public int _startIndex;
public int _endIndex;
public float _spacing;
}
}

View File

@ -534,6 +534,10 @@ public class TextRun
// 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;
}

View File

@ -513,4 +513,12 @@ public abstract class TextShape extends SimpleShape {
}
}
}
public void draw(Graphics2D graphics){
AffineTransform at = graphics.getTransform();
ShapePainter.paint(this, graphics);
new TextPainter(this).paint(graphics);
graphics.setTransform(at);
}
}

View File

@ -150,7 +150,7 @@ public class StyleTextPropAtom extends RecordAtom
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"),

View File

@ -37,9 +37,6 @@ import org.apache.poi.hslf.record.ColorSchemeAtom;
/**
* 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 */
@ -126,6 +123,24 @@ public class RichTextRun {
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
*/
@ -314,34 +329,142 @@ public class RichTextRun {
// --------------- 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
@ -352,6 +475,10 @@ public class RichTextRun {
setCharTextPropVal("font.index", fontIdx);
}
}
/**
* Gets the font name
*/
public String getFontName() {
if (slideShow == null) {
return _fontname;
@ -427,7 +554,7 @@ public class RichTextRun {
/**
* 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);
@ -488,6 +615,107 @@ public class RichTextRun {
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! -------
/**

View File

@ -141,7 +141,7 @@ public class TestSlideOrdering extends TestCase {
"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",