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:
parent
577b3e084f
commit
f5c9d3023f
@ -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 < 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>
|
||||
|
103
src/scratchpad/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java
Executable file
103
src/scratchpad/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java
Executable 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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
293
src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java
Executable file
293
src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java
Executable 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
src/scratchpad/src/org/apache/poi/hslf/model/ShapeOutline.java
Executable file
27
src/scratchpad/src/org/apache/poi/hslf/model/ShapeOutline.java
Executable 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);
|
||||
|
||||
}
|
85
src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java
Executable file
85
src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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){
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,6 +76,7 @@ public class SlideMaster extends MasterSheet {
|
||||
if (prop != null) break;
|
||||
}
|
||||
if (prop == null) {
|
||||
if(isCharacter) {
|
||||
switch (txtype) {
|
||||
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
||||
case TextHeaderAtom.HALF_BODY_TYPE:
|
||||
@ -94,6 +89,21 @@ public class SlideMaster extends MasterSheet {
|
||||
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);
|
||||
}
|
||||
return prop;
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.*;
|
||||
|
||||
|
@ -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.
|
||||
|
238
src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
Executable file
238
src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
Executable 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -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! -------
|
||||
|
||||
/**
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user