Fixed TextRun handling and various junit tests

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1684773 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-06-10 22:23:47 +00:00
parent d1f9035400
commit 4acc6a84a1
58 changed files with 976 additions and 1036 deletions

View File

@ -146,10 +146,10 @@ public final class ApacheconEU08 {
{"Note"},
{"This presentation was created programmatically using POI HSLF"}
};
Table table1 = new Table(2, 1);
HSLFTable table1 = new HSLFTable(2, 1);
for (int i = 0; i < txt1.length; i++) {
for (int j = 0; j < txt1[i].length; j++) {
TableCell cell = table1.getCell(i, j);
HSLFTableCell cell = table1.getCell(i, j);
cell.setText(txt1[i][j]);
HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
rt.setFontSize(10);

View File

@ -50,7 +50,7 @@ public final class Graphics2DDemo {
//define position of the drawing in the slide
Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300);
group.setAnchor(bounds);
group.setCoordinates(new java.awt.Rectangle(0, 0, 100, 100));
group.setInteriorAnchor(new java.awt.Rectangle(0, 0, 100, 100));
slide.addShape(group);
Graphics2D graphics = new PPGraphics2D(group);
@ -68,7 +68,7 @@ public final class Graphics2DDemo {
}
graphics.setColor(Color.black);
graphics.setFont(new Font("Arial", Font.BOLD, 14));
graphics.draw(group.getCoordinates());
graphics.draw(group.getInteriorAnchor());
graphics.drawString("Performance", x + 30, y + 10);
FileOutputStream out = new FileOutputStream("hslf-graphics.ppt");

View File

@ -49,10 +49,10 @@ public final class TableDemo {
HSLFSlide slide = ppt.createSlide();
//six rows, two columns
Table table1 = new Table(6, 2);
HSLFTable table1 = new HSLFTable(6, 2);
for (int i = 0; i < txt1.length; i++) {
for (int j = 0; j < txt1[i].length; j++) {
TableCell cell = table1.getCell(i, j);
HSLFTableCell cell = table1.getCell(i, j);
HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
rt.setFontFamily("Arial");
rt.setFontSize(10);
@ -88,10 +88,10 @@ public final class TableDemo {
};
//two rows, one column
Table table2 = new Table(2, 1);
HSLFTable table2 = new HSLFTable(2, 1);
for (int i = 0; i < txt2.length; i++) {
for (int j = 0; j < txt2[i].length; j++) {
TableCell cell = table2.getCell(i, j);
HSLFTableCell cell = table2.getCell(i, j);
HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
rt.setFontSize(10);
rt.setFontFamily("Arial");

View File

@ -40,13 +40,26 @@ public class EscherChildAnchorRecord
private int field_4_dy2;
public int fillFields(byte[] data, int offset, EscherRecordFactory recordFactory) {
/*int bytesRemaining =*/ readHeader( data, offset );
int bytesRemaining = readHeader( data, offset );
int pos = offset + 8;
int size = 0;
field_1_dx1 = LittleEndian.getInt( data, pos + size );size+=4;
field_2_dy1 = LittleEndian.getInt( data, pos + size );size+=4;
field_3_dx2 = LittleEndian.getInt( data, pos + size );size+=4;
field_4_dy2 = LittleEndian.getInt( data, pos + size );size+=4;
switch (bytesRemaining) {
case 16: // RectStruct
field_1_dx1 = LittleEndian.getInt( data, pos + size );size+=4;
field_2_dy1 = LittleEndian.getInt( data, pos + size );size+=4;
field_3_dx2 = LittleEndian.getInt( data, pos + size );size+=4;
field_4_dy2 = LittleEndian.getInt( data, pos + size );size+=4;
break;
case 8: // SmallRectStruct
field_1_dx1 = LittleEndian.getShort( data, pos + size );size+=2;
field_2_dy1 = LittleEndian.getShort( data, pos + size );size+=2;
field_3_dx2 = LittleEndian.getShort( data, pos + size );size+=2;
field_4_dy2 = LittleEndian.getShort( data, pos + size );size+=2;
break;
default:
throw new RuntimeException("Invalid EscherChildAnchorRecord - neither 8 nor 16 bytes.");
}
return 8 + size;
}
@ -58,8 +71,8 @@ public class EscherChildAnchorRecord
LittleEndian.putInt( data, pos, getRecordSize()-8 ); pos += 4;
LittleEndian.putInt( data, pos, field_1_dx1 ); pos += 4;
LittleEndian.putInt( data, pos, field_2_dy1 ); pos += 4;
LittleEndian.putInt( data, pos, field_3_dx2 ); pos += 4;
LittleEndian.putInt( data, pos, field_4_dy2 ); pos += 4;
LittleEndian.putInt( data, pos, field_3_dx2 ); pos += 4;
LittleEndian.putInt( data, pos, field_4_dy2 ); pos += 4;
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
return pos - offset;

View File

@ -507,7 +507,7 @@ public final class EscherProperties {
addProp(m, SHADOWSTYLE__ORIGINX, "shadowstyle.originx");
addProp(m, SHADOWSTYLE__ORIGINY, "shadowstyle.originy");
addProp(m, SHADOWSTYLE__SHADOW, "shadowstyle.shadow");
addProp(m, SHADOWSTYLE__SHADOWOBSURED, "shadowstyle.shadowobsured");
addProp(m, SHADOWSTYLE__SHADOWOBSURED, "shadowstyle.shadowobscured");
addProp(m, PERSPECTIVE__TYPE, "perspective.type");
addProp(m, PERSPECTIVE__OFFSETX, "perspective.offsetx");
addProp(m, PERSPECTIVE__OFFSETY, "perspective.offsety");

View File

@ -17,6 +17,7 @@
package org.apache.poi.ddf;
import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.RecordFormatException;
@ -32,7 +33,7 @@ import org.apache.poi.util.RecordFormatException;
*/
public class EscherTextboxRecord extends EscherRecord
{
public static final short RECORD_ID = (short)0xF00D;
public static final short RECORD_ID = (short)RecordTypes.EscherClientTextbox;
public static final String RECORD_DESCRIPTION = "msofbtClientTextbox";
private static final byte[] NO_BYTES = new byte[0];

View File

@ -28,6 +28,7 @@ import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.Arrays;
import java.util.Map;
public class DummyGraphics2d
@ -262,7 +263,7 @@ public class DummyGraphics2d
public void setPaint( Paint paint )
{
System.out.println( "setPain(Paint):" );
System.out.println( "setPaint(Paint):" );
System.out.println( "paint = " + paint );
g2D.setPaint( paint );
}
@ -285,7 +286,19 @@ public class DummyGraphics2d
public void setStroke(Stroke s)
{
System.out.println( "setStroke(Stoke):" );
System.out.println( "s = " + s );
if (s instanceof BasicStroke) {
BasicStroke bs = (BasicStroke)s;
StringBuilder str = new StringBuilder("s = BasicStroke(");
str.append("dash[]: "+Arrays.toString(bs.getDashArray())+", ");
str.append("dashPhase: "+bs.getDashPhase()+", ");
str.append("endCap: "+bs.getEndCap()+", ");
str.append("lineJoin: "+bs.getLineJoin()+", ");
str.append("width: "+bs.getLineWidth()+", ");
str.append("miterLimit: "+bs.getMiterLimit()+")");
System.out.println(str.toString());
} else {
System.out.println( "s = " + s );
}
g2D.setStroke( s );
}

View File

@ -25,8 +25,7 @@ import java.util.List;
import java.util.regex.Pattern;
import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.sl.usermodel.ShapeGroup;
import org.apache.poi.sl.usermodel.GroupShape;
import org.apache.poi.util.*;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
@ -38,7 +37,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.*;
* @author Yegor Kozlov
*/
@Beta
public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, ShapeGroup<XSLFShape> {
public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, GroupShape<XSLFShape> {
private static POILogger _logger = POILogFactory.getLogger(XSLFGroupShape.class);
private final List<XSLFShape> _shapes;
@ -118,7 +117,7 @@ public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, Sha
* used for calculations of grouping, scaling, and rotation
* behavior of shapes placed within a group.
*/
public void setInteriorAnchor(Rectangle2D anchor){
public void setInteriorAnchor(Rectangle2D anchor) {
CTGroupTransform2D xfrm = getSafeXfrm();
CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff();
long x = Units.toEMU(anchor.getX());

View File

@ -169,6 +169,7 @@ public class XSLFPictureShape extends XSLFSimpleShape implements PictureShape {
return id;
}
@Override
public Insets getClipping(){
CTPicture ct = (CTPicture)getXmlObject();
CTRelativeRect r = ct.getBlipFill().getSrcRect();

View File

@ -481,6 +481,7 @@ public abstract class XSLFSheet extends POIXMLDocumentPart implements XSLFShapeC
*
* @param graphics
*/
@Override
public void draw(Graphics2D graphics){
DrawFactory drawFact = DrawFactory.getInstance(graphics);
Drawable draw = drawFact.getDrawable(this);

View File

@ -21,7 +21,6 @@ import java.io.IOException;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.usermodel.Notes;
import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlException;

View File

@ -1,95 +0,0 @@
/* ====================================================================
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.blip;
import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFPictureShape;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
/* ====================================================================
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.
==================================================================== */
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
/**
* Creates BufferedImage using javax.imageio.ImageIO and draws it in the specified graphics.
*
* @author Yegor Kozlov.
*/
public final class BitmapPainter implements ImagePainter {
protected POILogger logger = POILogFactory.getLogger(this.getClass());
public void paint(Graphics2D graphics, HSLFPictureData pict, HSLFPictureShape parent) {
BufferedImage img;
try {
img = ImageIO.read(new ByteArrayInputStream(pict.getData()));
} catch (Exception e) {
logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + pict.getType());
return;
}
boolean isClipped = true;
Insets clip = parent.getBlipClip();
if (clip == null) {
isClipped = false;
clip = new Insets(0,0,0,0);
}
int iw = img.getWidth();
int ih = img.getHeight();
Rectangle anchor = parent.getLogicalAnchor2D().getBounds();
double cw = (100000-clip.left-clip.right) / 100000.0;
double ch = (100000-clip.top-clip.bottom) / 100000.0;
double sx = anchor.getWidth()/(iw*cw);
double sy = anchor.getHeight()/(ih*ch);
double tx = anchor.getX()-(iw*sx*clip.left/100000.0);
double ty = anchor.getY()-(ih*sy*clip.top/100000.0);
AffineTransform at = new AffineTransform(sx, 0, 0, sy, tx, ty) ;
Shape clipOld = graphics.getClip();
if (isClipped) graphics.clip(anchor.getBounds2D());
graphics.drawRenderedImage(img, at);
graphics.setClip(clipOld);
}
}

View File

@ -1,72 +0,0 @@
/* ====================================================================
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.blip;
import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFPictureShape;
import java.awt.*;
/**
* A common interface for objects that can render ppt picture data.
* <p>
* Subclasses can redefine it and use third-party libraries for actual rendering,
* for example, Bitmaps can be rendered using javax.imageio.* , WMF can be rendered using Apache Batik,
* PICT can be rendered using Apple QuickTime API for Java, etc.
* </p>
*
* A typical usage is as follows:
* <code>
* public WMFPaiter implements ImagePainter{
* public void paint(Graphics2D graphics, PictureData pict, Picture parent){
* DataInputStream is = new DataInputStream(new ByteArrayInputStream(pict.getData()));
* org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore wmfStore =
* new org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore();
* try {
* wmfStore.read(is);
* } catch (IOException e){
* return;
* }
*
* Rectangle anchor = parent.getAnchor();
* float scale = (float)anchor.width/wmfStore.getWidthPixels();
*
* org.apache.batik.transcoder.wmf.tosvg.WMFPainter painter =
* new org.apache.batik.transcoder.wmf.tosvg.WMFPainter(wmfStore, 0, 0, scale);
* graphics.translate(anchor.x, anchor.y);
* painter.paint(graphics);
* }
* }
* PictureData.setImagePainter(Picture.WMF, new WMFPaiter());
* ...
* </code>
* Subsequent calls of Slide.draw(Graphics gr) will use WMFPaiter for WMF images.
*
* @author Yegor Kozlov.
*/
public interface ImagePainter {
/**
* Paints the specified picture data
*
* @param graphics the graphics to paintb into
* @param pict the data to paint
* @param parent the shapes that owns the picture data
*/
public void paint(Graphics2D graphics, HSLFPictureData pict, HSLFPictureShape parent);
}

View File

@ -247,8 +247,8 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor {
// Table text
for (HSLFShape shape : slide.getShapes()){
if (shape instanceof Table){
extractTableText(ret, (Table)shape);
if (shape instanceof HSLFTable){
extractTableText(ret, (HSLFTable)shape);
}
}
// Slide footer, if set
@ -305,10 +305,10 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor {
return ret.toString();
}
private void extractTableText(StringBuffer ret, Table table) {
private void extractTableText(StringBuffer ret, HSLFTable table) {
for (int row = 0; row < table.getNumberOfRows(); row++){
for (int col = 0; col < table.getNumberOfColumns(); col++){
TableCell cell = table.getCell(row, col);
HSLFTableCell cell = table.getCell(row, col);
//defensive null checks; don't know if they're necessary
if (cell != null){
String txt = cell.getText();

View File

@ -22,8 +22,8 @@ import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Line2D;
import java.awt.geom.*;
import java.util.ArrayList;
/**
* Represents a line in a PowerPoint drawing
@ -69,4 +69,63 @@ public final class Line extends HSLFSimpleShape {
Rectangle2D anchor = getLogicalAnchor2D();
return new Line2D.Double(anchor.getX(), anchor.getY(), anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight());
}
/**
*
* @return 'absolute' anchor of this shape relative to the parent sheet
*
* @deprecated TODO: remove the whole class, should work with preset geometries instead
*/
public Rectangle2D getLogicalAnchor2D(){
Rectangle2D anchor = getAnchor2D();
//if it is a groupped shape see if we need to transform the coordinates
if (getParent() != null){
ArrayList<HSLFGroupShape> lst = new ArrayList<HSLFGroupShape>();
for (ShapeContainer<HSLFShape> parent=this.getParent();
parent instanceof HSLFGroupShape;
parent = ((HSLFGroupShape)parent).getParent()) {
lst.add(0, (HSLFGroupShape)parent);
}
AffineTransform tx = new AffineTransform();
for(HSLFGroupShape prnt : lst) {
Rectangle2D exterior = prnt.getAnchor2D();
Rectangle2D interior = prnt.getInteriorAnchor();
double scaleX = exterior.getWidth() / interior.getWidth();
double scaleY = exterior.getHeight() / interior.getHeight();
tx.translate(exterior.getX(), exterior.getY());
tx.scale(scaleX, scaleY);
tx.translate(-interior.getX(), -interior.getY());
}
anchor = tx.createTransformedShape(anchor).getBounds2D();
}
double angle = getRotation();
if(angle != 0.){
double centerX = anchor.getX() + anchor.getWidth()/2;
double centerY = anchor.getY() + anchor.getHeight()/2;
AffineTransform trans = new AffineTransform();
trans.translate(centerX, centerY);
trans.rotate(Math.toRadians(angle));
trans.translate(-centerX, -centerY);
Rectangle2D rect = trans.createTransformedShape(anchor).getBounds2D();
if((anchor.getWidth() < anchor.getHeight() && rect.getWidth() > rect.getHeight()) ||
(anchor.getWidth() > anchor.getHeight() && rect.getWidth() < rect.getHeight()) ){
trans = new AffineTransform();
trans.translate(centerX, centerY);
trans.rotate(Math.PI/2);
trans.translate(-centerX, -centerY);
anchor = trans.createTransformedShape(anchor).getBounds2D();
}
}
return anchor;
}
}

View File

@ -285,6 +285,7 @@ public class TextPropCollection {
* Clones the given text properties
*/
public void copy(TextPropCollection other) {
if (this == other) return;
this.charactersCovered = other.charactersCovered;
this.indentLevel = other.indentLevel;
this.maskSpecial = other.maskSpecial;

View File

@ -87,9 +87,7 @@ public final class EscherTextboxWrapper extends RecordContainer {
// Grab the children's data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for(int i=0; i<_children.length; i++) {
_children[i].writeOut(baos);
}
for (Record r : _children) r.writeOut(baos);
byte[] data = baos.toByteArray();
// Save in the escher layer

View File

@ -97,7 +97,7 @@ public final class PPDrawing extends RecordAtom {
findEscherChildren(erf, contents, 8, len-8, escherChildren);
this.childRecords = escherChildren.toArray(new EscherRecord[escherChildren.size()]);
if (1 == this.childRecords.length && (short)0xf002 == this.childRecords[0].getRecordId() && this.childRecords[0] instanceof EscherContainerRecord) {
if (1 == this.childRecords.length && (short)RecordTypes.EscherDgContainer == this.childRecords[0].getRecordId() && this.childRecords[0] instanceof EscherContainerRecord) {
this.textboxWrappers = findInDgContainer((EscherContainerRecord) this.childRecords[0]);
} else {
// Find and EscherTextboxRecord's, and wrap them up
@ -106,37 +106,30 @@ public final class PPDrawing extends RecordAtom {
this.textboxWrappers = textboxes.toArray(new EscherTextboxWrapper[textboxes.size()]);
}
}
private EscherTextboxWrapper[] findInDgContainer(final EscherContainerRecord escherContainerF002) {
private EscherTextboxWrapper[] findInDgContainer(final EscherContainerRecord dgContainer) {
final List<EscherTextboxWrapper> found = new LinkedList<EscherTextboxWrapper>();
final EscherContainerRecord SpgrContainer = findFirstEscherContainerRecordOfType((short)0xf003, escherContainerF002);
final EscherContainerRecord[] escherContainersF004 = findAllEscherContainerRecordOfType((short)0xf004, SpgrContainer);
for (EscherContainerRecord spContainer : escherContainersF004) {
final EscherContainerRecord spgrContainer = findFirstEscherContainerRecordOfType((short)RecordTypes.EscherSpgrContainer, dgContainer);
final EscherContainerRecord[] spContainers = findAllEscherContainerRecordOfType((short)RecordTypes.EscherSpContainer, spgrContainer);
for (EscherContainerRecord spContainer : spContainers) {
StyleTextProp9Atom nineAtom = findInSpContainer(spContainer);
EscherSpRecord sp = null;
final EscherRecord escherContainerF00A = findFirstEscherRecordOfType((short)0xf00a, spContainer);
if (null != escherContainerF00A) {
if (escherContainerF00A instanceof EscherSpRecord) {
sp = (EscherSpRecord) escherContainerF00A;
}
}
final EscherRecord escherContainerF00D = findFirstEscherRecordOfType((short)0xf00d, spContainer);
if (null == escherContainerF00D) { continue; }
if (escherContainerF00D instanceof EscherTextboxRecord) {
EscherTextboxRecord tbr = (EscherTextboxRecord) escherContainerF00D;
EscherTextboxWrapper w = new EscherTextboxWrapper(tbr);
w.setStyleTextProp9Atom(nineAtom);
if (null != sp) {
w.setShapeId(sp.getShapeId());
}
found.add(w);
EscherSpRecord sp = (EscherSpRecord)findFirstEscherRecordOfType((short)RecordTypes.EscherSp, spContainer);
EscherTextboxRecord clientTextbox = (EscherTextboxRecord)findFirstEscherRecordOfType((short)RecordTypes.EscherClientTextbox, spContainer);
if (null == clientTextbox) { continue; }
EscherTextboxWrapper w = new EscherTextboxWrapper(clientTextbox);
w.setStyleTextProp9Atom(nineAtom);
if (null != sp) {
w.setShapeId(sp.getShapeId());
}
found.add(w);
}
return found.toArray(new EscherTextboxWrapper[found.size()]);
}
private StyleTextProp9Atom findInSpContainer(final EscherContainerRecord spContainer) {
final EscherContainerRecord escherContainerF011 = findFirstEscherContainerRecordOfType((short)0xf011, spContainer);
if (null == escherContainerF011) { return null; }
final EscherContainerRecord escherContainer1388 = findFirstEscherContainerRecordOfType((short)0x1388, escherContainerF011);
EscherContainerRecord clientData = findFirstEscherContainerRecordOfType((short)RecordTypes.EscherClientData, spContainer);
if (null == clientData) { return null; }
final EscherContainerRecord escherContainer1388 = findFirstEscherContainerRecordOfType((short)0x1388, clientData);
if (null == escherContainer1388) { return null; }
final EscherContainerRecord escherContainer138A = findFirstEscherContainerRecordOfType((short)0x138A, escherContainer1388);
if (null == escherContainer138A) { return null; }

View File

@ -294,7 +294,7 @@ public abstract class RecordContainer extends Record
// Write out our header, less the size
mout.write(new byte[] {headerA,headerB});
byte[] typeB = new byte[2];
LittleEndian.putShort(typeB,(short)type);
LittleEndian.putShort(typeB, 0, (short)type);
mout.write(typeB);
mout.write(new byte[4]);
@ -320,7 +320,7 @@ public abstract class RecordContainer extends Record
// Write out our header, less the size
baos.write(new byte[] {headerA,headerB});
byte[] typeB = new byte[2];
LittleEndian.putShort(typeB,(short)type);
LittleEndian.putShort(typeB,0,(short)type);
baos.write(typeB);
baos.write(new byte[] {0,0,0,0});

View File

@ -93,8 +93,6 @@ public final class SlideListWithText extends RecordContainer {
}
int clen = endPos - i - 1;
boolean emptySet = false;
if(clen == 0) { emptySet = true; }
// Create a SlideAtomsSets, not caring if they're empty
//if(emptySet) { continue; }
@ -149,7 +147,7 @@ public final class SlideListWithText extends RecordContainer {
}
public void setInstance(int inst){
LittleEndian.putShort(_header, (short)((inst << 4) | 0xF));
LittleEndian.putShort(_header, 0, (short)((inst << 4) | 0xF));
}
/**

View File

@ -128,9 +128,10 @@ public final class HSLFFill {
};
}
case FILL_PICTURE: {
final HSLFPictureData pd = getPictureData();
if (pd == null) break;
return new TexturePaint() {
final HSLFPictureData pd = getPictureData();
public InputStream getImageData() {
return new ByteArrayInputStream(pd.getData());
}

View File

@ -21,8 +21,7 @@ import java.awt.geom.Rectangle2D;
import java.util.*;
import org.apache.poi.ddf.*;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
@ -31,7 +30,7 @@ import org.apache.poi.util.POILogger;
*
* @author Yegor Kozlov
*/
public class HSLFGroupShape extends HSLFShape implements ShapeContainer<HSLFShape> {
public class HSLFGroupShape extends HSLFShape implements GroupShape<HSLFShape> {
/**
* Create a new ShapeGroup. This constructor is used when a new shape is created.
@ -87,13 +86,8 @@ public class HSLFGroupShape extends HSLFShape implements ShapeContainer<HSLFShap
spgr.setRectY2((anchor.y + anchor.height)*MASTER_DPI/POINT_DPI);
}
/**
* Sets the coordinate space of this group. All children are constrained
* to these coordinates.
*
* @param anchor the coordinate space of this group
*/
public void setCoordinates(Rectangle2D anchor){
@Override
public void setInteriorAnchor(Rectangle2D anchor){
EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
int x1 = (int)Math.round(anchor.getX()*MASTER_DPI/POINT_DPI);
@ -108,22 +102,14 @@ public class HSLFGroupShape extends HSLFShape implements ShapeContainer<HSLFShap
}
/**
* Gets the coordinate space of this group. All children are constrained
* to these coordinates.
*
* @return the coordinate space of this group
*/
public Rectangle2D getCoordinates(){
EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
Rectangle2D.Float anchor = new Rectangle2D.Float();
anchor.x = (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI;
anchor.y = (float)spgr.getRectY1()*POINT_DPI/MASTER_DPI;
anchor.width = (float)(spgr.getRectX2() - spgr.getRectX1())*POINT_DPI/MASTER_DPI;
anchor.height = (float)(spgr.getRectY2() - spgr.getRectY1())*POINT_DPI/MASTER_DPI;
return anchor;
@Override
public Rectangle2D getInteriorAnchor(){
EscherSpgrRecord rec = getEscherChild(EscherSpgrRecord.RECORD_ID);
double x = rec.getRectX1()*POINT_DPI/MASTER_DPI;
double y = rec.getRectY1()*POINT_DPI/MASTER_DPI;
double width = (rec.getRectX2()-rec.getRectX1())*POINT_DPI/MASTER_DPI;
double height = (rec.getRectY2()-rec.getRectY1())*POINT_DPI/MASTER_DPI;
return new Rectangle2D.Double(x,y,width,height);
}
/**
@ -199,21 +185,21 @@ public class HSLFGroupShape extends HSLFShape implements ShapeContainer<HSLFShap
*/
public Rectangle2D getAnchor2D(){
EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
Rectangle2D.Float anchor = new Rectangle2D.Float();
Rectangle2D anchor;
if(clientAnchor == null){
logger.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord.");
EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID);
anchor = new Rectangle2D.Float(
(float)rec.getDx1()*POINT_DPI/MASTER_DPI,
(float)rec.getDy1()*POINT_DPI/MASTER_DPI,
(float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
(float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
);
double x = rec.getDx1()*POINT_DPI/MASTER_DPI;
double y = rec.getDy1()*POINT_DPI/MASTER_DPI;
double width = (rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI;
double height = (rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI;
anchor = new Rectangle2D.Double(x,y,width,height);
} else {
anchor.x = (float)clientAnchor.getCol1()*POINT_DPI/MASTER_DPI;
anchor.y = (float)clientAnchor.getFlag()*POINT_DPI/MASTER_DPI;
anchor.width = (float)(clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ;
anchor.height = (float)(clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI;
double x = clientAnchor.getCol1()*POINT_DPI/MASTER_DPI;
double y = clientAnchor.getFlag()*POINT_DPI/MASTER_DPI;
double width = (clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ;
double height = (clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI;
anchor = new Rectangle2D.Double(x,y,width,height);
}
return anchor;

View File

@ -35,7 +35,7 @@ import org.apache.poi.util.POILogger;
public final class HSLFNotes extends HSLFSheet implements Notes<HSLFShape, HSLFSlideShow> {
protected static POILogger logger = POILogFactory.getLogger(HSLFNotes.class);
private List<List<HSLFTextParagraph>> _runs;
private List<List<HSLFTextParagraph>> _paragraphs = new ArrayList<List<HSLFTextParagraph>>();
/**
* Constructs a Notes Sheet from the given Notes record.
@ -49,13 +49,16 @@ public final class HSLFNotes extends HSLFSheet implements Notes<HSLFShape, HSLFS
// Now, build up TextRuns from pairs of TextHeaderAtom and
// one of TextBytesAtom or TextCharsAtom, found inside
// EscherTextboxWrapper's in the PPDrawing
_runs = HSLFTextParagraph.findTextParagraphs(getPPDrawing());
if (_runs.isEmpty()) {
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
if (!_paragraphs.contains(l)) _paragraphs.add(l);
}
if (_paragraphs.isEmpty()) {
logger.log(POILogger.WARN, "No text records found for notes sheet");
}
// Set the sheet on each TextRun
for (List<HSLFTextParagraph> ltp : _runs) {
for (List<HSLFTextParagraph> ltp : _paragraphs) {
for (HSLFTextParagraph tp : ltp) {
tp.supplySheet(this);
}
@ -67,7 +70,7 @@ public final class HSLFNotes extends HSLFSheet implements Notes<HSLFShape, HSLFS
*/
@Override
public List<List<HSLFTextParagraph>> getTextParagraphs() {
return _runs;
return _paragraphs;
}
/**

View File

@ -17,31 +17,22 @@
package org.apache.poi.hslf.usermodel;
import java.awt.Graphics2D;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import org.apache.poi.hslf.blip.BitmapPainter;
import org.apache.poi.hslf.blip.DIB;
import org.apache.poi.hslf.blip.EMF;
import org.apache.poi.hslf.blip.ImagePainter;
import org.apache.poi.hslf.blip.JPEG;
import org.apache.poi.hslf.blip.PICT;
import org.apache.poi.hslf.blip.PNG;
import org.apache.poi.hslf.blip.WMF;
import org.apache.poi.hslf.blip.*;
import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.util.*;
/**
* A class that represents image data contained in a slide show.
*
* @author Yegor Kozlov
*/
public abstract class HSLFPictureData {
public abstract class HSLFPictureData implements PictureData {
protected POILogger logger = POILogFactory.getLogger(this.getClass());
@ -91,13 +82,6 @@ public abstract class HSLFPictureData {
*/
protected abstract int getSignature();
protected static final ImagePainter[] painters = new ImagePainter[8];
static {
HSLFPictureData.setImagePainter(HSLFPictureShape.PNG, new BitmapPainter());
HSLFPictureData.setImagePainter(HSLFPictureShape.JPEG, new BitmapPainter());
HSLFPictureData.setImagePainter(HSLFPictureShape.DIB, new BitmapPainter());
}
/**
* Returns the raw binary data of this Picture excluding the first 8 bytes
* which hold image signature and size of the image data.
@ -233,31 +217,4 @@ public abstract class HSLFPictureData {
public int getSize(){
return getData().length;
}
public void draw(Graphics2D graphics, HSLFPictureShape parent){
ImagePainter painter = painters[getType()];
if(painter != null) painter.paint(graphics, this, parent);
else logger.log(POILogger.WARN, "Rendering is not supported: " + getClass().getName());
}
/**
* Register ImagePainter for the specified image type
*
* @param type image type, must be one of the static constants defined in the <code>Picture<code> class.
* @param painter
*/
public static void setImagePainter(int type, ImagePainter painter){
painters[type] = painter;
}
/**
* Return ImagePainter for the specified image type
*
* @param type blip type, must be one of the static constants defined in the <code>Picture<code> class.
* @return ImagePainter for the specified image type
*/
public static ImagePainter getImagePainter(int type){
return painters[type];
}
}

View File

@ -28,8 +28,7 @@ import javax.imageio.ImageIO;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.blip.Bitmap;
import org.apache.poi.hslf.record.Document;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.util.*;
@ -38,7 +37,7 @@ import org.apache.poi.util.*;
*
* @author Yegor Kozlov
*/
public class HSLFPictureShape extends HSLFSimpleShape {
public class HSLFPictureShape extends HSLFSimpleShape implements PictureShape {
/**
* Windows Enhanced Metafile (EMF)
@ -165,11 +164,7 @@ public class HSLFPictureShape extends HSLFSimpleShape {
}
}
/**
* Returns the picture data for this picture.
*
* @return the picture data for this picture.
*/
@Override
public HSLFPictureData getPictureData(){
HSLFSlideShow ppt = getSheet().getSlideShow();
HSLFPictureData[] pict = ppt.getPictureData();
@ -247,13 +242,11 @@ public class HSLFPictureShape extends HSLFSimpleShape {
}
/**
* Returns the clipping values as percent ratio relatively to the image size.
* The anchor specified by {@link #getLogicalAnchor2D()} is the displayed size,
* i.e. the size of the already clipped image
*
* @return the clipping as insets converted/scaled to 100000 (=100%)
*/
public Insets getBlipClip() {
@Override
public Insets getClipping() {
EscherOptRecord opt = getEscherOptRecord();
double top = getFractProp(opt, EscherProperties.BLIP__CROPFROMTOP);

View File

@ -165,14 +165,12 @@ public abstract class HSLFShape implements Shape {
public Rectangle2D getAnchor2D(){
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
int flags = spRecord.getFlags();
Rectangle2D anchor=null;
Rectangle2D anchor;
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle();
if(rec == null){
logger.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found");
EscherClientAnchorRecord clrec = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle();
anchor = new Rectangle2D.Float(
(float)clrec.getCol1()*POINT_DPI/MASTER_DPI,
(float)clrec.getFlag()*POINT_DPI/MASTER_DPI,
@ -187,10 +185,8 @@ public abstract class HSLFShape implements Shape {
(float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
);
}
}
else {
} else {
EscherClientAnchorRecord rec = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle();
anchor = new Rectangle2D.Float(
(float)rec.getCol1()*POINT_DPI/MASTER_DPI,
(float)rec.getFlag()*POINT_DPI/MASTER_DPI,
@ -201,10 +197,6 @@ public abstract class HSLFShape implements Shape {
return anchor;
}
public Rectangle2D getLogicalAnchor2D(){
return getAnchor2D();
}
/**
* Sets the anchor (the bounding box rectangle) of this shape.
* All coordinates should be expressed in points (72 dpi).
@ -262,8 +254,9 @@ public abstract class HSLFShape implements Shape {
* @return escher property or <code>null</code> if not found.
*/
public static <T extends EscherProperty> T getEscherProperty(EscherOptRecord opt, int propId){
return opt.lookup(propId);
}
if (opt == null) return null;
return opt.lookup(propId);
}
/**
* Set an escher property for this shape.
@ -475,15 +468,6 @@ public abstract class HSLFShape implements Shape {
logger.log(POILogger.INFO, "Rendering " + getShapeName());
}
/**
* Return shape outline as a java.awt.Shape object
*
* @return the shape outline
*/
public java.awt.Shape getOutline(){
return getLogicalAnchor2D();
}
public EscherOptRecord getEscherOptRecord() {
EscherOptRecord opt = getEscherChild(EscherOptRecord.RECORD_ID);
if (opt == null) {
@ -516,8 +500,7 @@ public abstract class HSLFShape implements Shape {
public double getRotation(){
int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION);
double angle = Units.fixedPointToDouble(rot) % 360.0;
return angle;
return Units.fixedPointToDouble(rot);
}
public void setRotation(double theta){

View File

@ -69,7 +69,7 @@ public final class HSLFShapeFactory {
List<EscherProperty> props = f.createProperties( opt.serialize(), 8, opt.getInstance() );
EscherSimpleProperty p = (EscherSimpleProperty)props.get(0);
if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){
group = new Table(spContainer, parent);
group = new HSLFTable(spContainer, parent);
} else {
group = new HSLFGroupShape(spContainer, parent);
}

View File

@ -22,6 +22,8 @@ import java.util.*;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.*;
import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.Sheet;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -288,8 +290,11 @@ public abstract class HSLFSheet implements Sheet<HSLFShape,HSLFSlideShow> {
return _background;
}
public void draw(Graphics2D graphics){
@Override
public void draw(Graphics2D graphics) {
DrawFactory drawFact = DrawFactory.getInstance(graphics);
Drawable draw = drawFact.getDrawable(this);
draw.draw(graphics);
}
/**

View File

@ -18,16 +18,15 @@
package org.apache.poi.hslf.usermodel;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.*;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.draw.geom.*;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
import org.apache.poi.util.LittleEndian;
@ -196,7 +195,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape {
public StrokeStyle getStrokeStyle(){
return new StrokeStyle() {
public PaintStyle getPaint() {
return null;
return DrawPaint.createSolidPaint(HSLFSimpleShape.this.getLineColor());
}
public LineCap getLineCap() {
@ -204,15 +203,15 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape {
}
public LineDash getLineDash() {
return null;
return HSLFSimpleShape.this.getLineDashing();
}
public LineCompound getLineCompound() {
return null;
return HSLFSimpleShape.this.getLineCompound();
}
public double getLineWidth() {
return 0;
return HSLFSimpleShape.this.getLineWidth();
}
};
@ -234,61 +233,6 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape {
getFill().setForegroundColor(color);
}
/**
*
* @return 'absolute' anchor of this shape relative to the parent sheet
*/
public Rectangle2D getLogicalAnchor2D(){
Rectangle2D anchor = getAnchor2D();
//if it is a groupped shape see if we need to transform the coordinates
if (getParent() != null){
ArrayList<HSLFGroupShape> lst = new ArrayList<HSLFGroupShape>();
for (ShapeContainer<HSLFShape> parent=this.getParent();
parent instanceof HSLFGroupShape;
parent = ((HSLFGroupShape)parent).getParent()) {
lst.add(0, (HSLFGroupShape)parent);
}
AffineTransform tx = new AffineTransform();
for(HSLFGroupShape prnt : lst) {
Rectangle2D exterior = prnt.getAnchor2D();
Rectangle2D interior = prnt.getCoordinates();
double scaleX = exterior.getWidth() / interior.getWidth();
double scaleY = exterior.getHeight() / interior.getHeight();
tx.translate(exterior.getX(), exterior.getY());
tx.scale(scaleX, scaleY);
tx.translate(-interior.getX(), -interior.getY());
}
anchor = tx.createTransformedShape(anchor).getBounds2D();
}
double angle = getRotation();
if(angle != 0.){
double centerX = anchor.getX() + anchor.getWidth()/2;
double centerY = anchor.getY() + anchor.getHeight()/2;
AffineTransform trans = new AffineTransform();
trans.translate(centerX, centerY);
trans.rotate(Math.toRadians(angle));
trans.translate(-centerX, -centerY);
Rectangle2D rect = trans.createTransformedShape(anchor).getBounds2D();
if((anchor.getWidth() < anchor.getHeight() && rect.getWidth() > rect.getHeight()) ||
(anchor.getWidth() > anchor.getHeight() && rect.getWidth() < rect.getHeight()) ){
trans = new AffineTransform();
trans.translate(centerX, centerY);
trans.rotate(Math.PI/2);
trans.translate(-centerX, -centerY);
anchor = trans.createTransformedShape(anchor).getBounds2D();
}
}
return anchor;
}
/**
* Find a record in the underlying EscherClientDataRecord
*
@ -424,11 +368,6 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape {
return (adjval == -1) ? null : new Guide(name, "val "+adjval);
}
public LineDecoration getLineDecoration() {
// TODO Auto-generated method stub
return null;
}
public CustomGeometry getGeometry() {
ShapeType st = getShapeType();
String name = st.getOoxmlName();
@ -442,11 +381,89 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape {
return geom;
}
public Shadow getShadow() {
// TODO Auto-generated method stub
return null;
public double getShadowAngle() {
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.SHADOWSTYLE__OFFSETX);
int offX = (prop == null) ? 0 : prop.getPropertyValue();
prop = getEscherProperty(opt, EscherProperties.SHADOWSTYLE__OFFSETY);
int offY = (prop == null) ? 0 : prop.getPropertyValue();
return Math.toDegrees(Math.atan2(offY, offX));
}
public double getShadowDistance() {
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.SHADOWSTYLE__OFFSETX);
int offX = (prop == null) ? 0 : prop.getPropertyValue();
prop = getEscherProperty(opt, EscherProperties.SHADOWSTYLE__OFFSETY);
int offY = (prop == null) ? 0 : prop.getPropertyValue();
return Units.toPoints((long)Math.hypot(offX, offY));
}
/**
* @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
*/
public Color getShadowColor(){
Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY, -1);
return clr == null ? Color.black : clr;
}
public Shadow getShadow() {
EscherOptRecord opt = getEscherOptRecord();
EscherProperty shadowType = opt.lookup(EscherProperties.SHADOWSTYLE__TYPE);
if (shadowType == null) return null;
return new Shadow(){
public SimpleShape getShadowParent() {
return HSLFSimpleShape.this;
}
public double getDistance() {
return getShadowDistance();
}
public double getAngle() {
return getShadowAngle();
}
public double getBlur() {
// TODO Auto-generated method stub
return 0;
}
public SolidPaint getFillStyle() {
return DrawPaint.createSolidPaint(getShadowColor());
}
};
}
public LineDecoration getLineDecoration() {
return new LineDecoration() {
public DecorationShape getHeadShape() {
return DecorationShape.NONE;
}
public DecorationSize getHeadWidth() {
return DecorationSize.MEDIUM;
}
public DecorationSize getHeadLength() {
return DecorationSize.MEDIUM;
}
public DecorationShape getTailShape() {
return DecorationShape.NONE;
}
public DecorationSize getTailWidth() {
return DecorationSize.MEDIUM;
}
public DecorationSize getTailLength() {
return DecorationSize.MEDIUM;
}
};
}
}

View File

@ -72,7 +72,9 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFSl
}
// Grab text from slide's PPDrawing
_paragraphs.addAll(HSLFTextParagraph.findTextParagraphs(getPPDrawing()));
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
if (!_paragraphs.contains(l)) _paragraphs.add(l);
}
for(List<HSLFTextParagraph> ltp : _paragraphs) {
for (HSLFTextParagraph tp : ltp) {

View File

@ -32,7 +32,7 @@ import org.apache.poi.hslf.record.*;
* @author Yegor Kozlov
*/
public final class HSLFSlideMaster extends HSLFMasterSheet {
private final List<List<HSLFTextParagraph>> _runs = new ArrayList<List<HSLFTextParagraph>>();
private final List<List<HSLFTextParagraph>> _paragraphs = new ArrayList<List<HSLFTextParagraph>>();
/**
* all TxMasterStyleAtoms available in this master
@ -46,8 +46,11 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
public HSLFSlideMaster(MainMaster record, int sheetNo) {
super(record, sheetNo);
_runs.addAll(HSLFTextParagraph.findTextParagraphs(getPPDrawing()));
for (List<HSLFTextParagraph> p : _runs) {
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
if (!_paragraphs.contains(l)) _paragraphs.add(l);
}
for (List<HSLFTextParagraph> p : _paragraphs) {
for (HSLFTextParagraph htp : p) {
htp.supplySheet(this);
}
@ -58,7 +61,7 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
* Returns an array of all the TextRuns found
*/
public List<List<HSLFTextParagraph>> getTextParagraphs() {
return _runs;
return _paragraphs;
}
/**
@ -138,7 +141,7 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
protected void onAddTextShape(HSLFTextShape shape) {
List<HSLFTextParagraph> runs = shape.getTextParagraphs();
_runs.add(runs);
_paragraphs.add(runs);
}
public TxMasterStyleAtom[] getTxMasterStyleAtoms(){

View File

@ -15,9 +15,10 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
package org.apache.poi.hslf.usermodel;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.model.Line;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.util.LittleEndian;
@ -31,7 +32,7 @@ import java.awt.*;
*
* @author Yegor Kozlov
*/
public final class Table extends HSLFGroupShape {
public final class HSLFTable extends HSLFGroupShape {
protected static final int BORDER_TOP = 1;
protected static final int BORDER_RIGHT = 2;
@ -44,7 +45,7 @@ public final class Table extends HSLFGroupShape {
protected static final int BORDERS_NONE = 8;
protected TableCell[][] cells;
protected HSLFTableCell[][] cells;
/**
* Create a new Table of the given number of rows and columns
@ -52,23 +53,23 @@ public final class Table extends HSLFGroupShape {
* @param numrows the number of rows
* @param numcols the number of columns
*/
public Table(int numrows, int numcols) {
public HSLFTable(int numrows, int numcols) {
super();
if(numrows < 1) throw new IllegalArgumentException("The number of rows must be greater than 1");
if(numcols < 1) throw new IllegalArgumentException("The number of columns must be greater than 1");
int x=0, y=0, tblWidth=0, tblHeight=0;
cells = new TableCell[numrows][numcols];
cells = new HSLFTableCell[numrows][numcols];
for (int i = 0; i < cells.length; i++) {
x = 0;
for (int j = 0; j < cells[i].length; j++) {
cells[i][j] = new TableCell(this);
Rectangle anchor = new Rectangle(x, y, TableCell.DEFAULT_WIDTH, TableCell.DEFAULT_HEIGHT);
cells[i][j] = new HSLFTableCell(this);
Rectangle anchor = new Rectangle(x, y, HSLFTableCell.DEFAULT_WIDTH, HSLFTableCell.DEFAULT_HEIGHT);
cells[i][j].setAnchor(anchor);
x += TableCell.DEFAULT_WIDTH;
x += HSLFTableCell.DEFAULT_WIDTH;
}
y += TableCell.DEFAULT_HEIGHT;
y += HSLFTableCell.DEFAULT_HEIGHT;
}
tblWidth = x;
tblHeight = y;
@ -94,7 +95,7 @@ public final class Table extends HSLFGroupShape {
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
* @param parent the parent of the shape
*/
public Table(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape> parent) {
public HSLFTable(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape> parent) {
super(escherRecord, parent);
}
@ -105,7 +106,7 @@ public final class Table extends HSLFGroupShape {
* @param col the column index (0-based)
* @return the cell
*/
public TableCell getCell(int row, int col) {
public HSLFTableCell getCell(int row, int col) {
return cells[row][col];
}
@ -124,13 +125,13 @@ public final class Table extends HSLFGroupShape {
EscherOptRecord opt = (EscherOptRecord)lst.get(lst.size()-2);
EscherArrayProperty p = opt.lookup(0x3A0);
for (int i = 0; i < cells.length; i++) {
TableCell cell = cells[i][0];
HSLFTableCell cell = cells[i][0];
int rowHeight = cell.getAnchor().height*MASTER_DPI/POINT_DPI;
byte[] val = new byte[4];
LittleEndian.putInt(val, 0, rowHeight);
p.setElement(i, val);
for (int j = 0; j < cells[i].length; j++) {
TableCell c = cells[i][j];
HSLFTableCell c = cells[i][j];
addShape(c);
Line bt = c.getBorderTop();
@ -177,12 +178,12 @@ public final class Table extends HSLFGroupShape {
maxrowlen = Math.max(maxrowlen, row.size());
}
}
cells = new TableCell[lst.size()][maxrowlen];
cells = new HSLFTableCell[lst.size()][maxrowlen];
for (int i = 0; i < lst.size(); i++) {
row = lst.get(i);
for (int j = 0; j < row.size(); j++) {
HSLFTextShape tx = (HSLFTextShape)row.get(j);
cells[i][j] = new TableCell(tx.getSpContainer(), getParent());
cells[i][j] = new HSLFTableCell(tx.getSpContainer(), getParent());
cells[i][j].setSheet(tx.getSheet());
}
}
@ -256,7 +257,7 @@ public final class Table extends HSLFGroupShape {
public void setAllBorders(Line line){
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
TableCell cell = cells[i][j];
HSLFTableCell cell = cells[i][j];
cell.setBorderTop(cloneBorder(line));
cell.setBorderLeft(cloneBorder(line));
if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line));
@ -273,7 +274,7 @@ public final class Table extends HSLFGroupShape {
public void setOutsideBorders(Line line){
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
TableCell cell = cells[i][j];
HSLFTableCell cell = cells[i][j];
if(j == 0) cell.setBorderLeft(cloneBorder(line));
if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line));
@ -300,7 +301,7 @@ public final class Table extends HSLFGroupShape {
public void setInsideBorders(Line line){
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
TableCell cell = cells[i][j];
HSLFTableCell cell = cells[i][j];
if(j != cells[i].length - 1)
cell.setBorderRight(cloneBorder(line));

View File

@ -15,15 +15,14 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
package org.apache.poi.hslf.usermodel;
import java.awt.Rectangle;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFTextBox;
import org.apache.poi.hslf.model.Line;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
@ -32,7 +31,7 @@ import org.apache.poi.sl.usermodel.ShapeType;
*
* @author Yegor Kozlov
*/
public final class TableCell extends HSLFTextBox {
public final class HSLFTableCell extends HSLFTextBox {
protected static final int DEFAULT_WIDTH = 100;
protected static final int DEFAULT_HEIGHT = 40;
@ -47,7 +46,7 @@ public final class TableCell extends HSLFTextBox {
* @param escherRecord {@link EscherSpContainer} container which holds information about this shape
* @param parent the parent of the shape
*/
protected TableCell(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape> parent){
protected HSLFTableCell(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape> parent){
super(escherRecord, parent);
}
@ -57,7 +56,7 @@ public final class TableCell extends HSLFTextBox {
* @param parent the parent of this Shape. For example, if this text box is a cell
* in a table then the parent is Table.
*/
public TableCell(ShapeContainer<HSLFShape> parent){
public HSLFTableCell(ShapeContainer<HSLFShape> parent){
super(parent);
setShapeType(ShapeType.RECT);
@ -81,25 +80,25 @@ public final class TableCell extends HSLFTextBox {
Rectangle cellAnchor = getAnchor();
Rectangle lineAnchor = new Rectangle();
switch(type){
case Table.BORDER_TOP:
case HSLFTable.BORDER_TOP:
lineAnchor.x = cellAnchor.x;
lineAnchor.y = cellAnchor.y;
lineAnchor.width = cellAnchor.width;
lineAnchor.height = 0;
break;
case Table.BORDER_RIGHT:
case HSLFTable.BORDER_RIGHT:
lineAnchor.x = cellAnchor.x + cellAnchor.width;
lineAnchor.y = cellAnchor.y;
lineAnchor.width = 0;
lineAnchor.height = cellAnchor.height;
break;
case Table.BORDER_BOTTOM:
case HSLFTable.BORDER_BOTTOM:
lineAnchor.x = cellAnchor.x;
lineAnchor.y = cellAnchor.y + cellAnchor.height;
lineAnchor.width = cellAnchor.width;
lineAnchor.height = 0;
break;
case Table.BORDER_LEFT:
case HSLFTable.BORDER_LEFT:
lineAnchor.x = cellAnchor.x;
lineAnchor.y = cellAnchor.y;
lineAnchor.width = 0;
@ -116,7 +115,7 @@ public final class TableCell extends HSLFTextBox {
}
public void setBorderLeft(Line line) {
if(line != null) anchorBorder(Table.BORDER_LEFT, line);
if(line != null) anchorBorder(HSLFTable.BORDER_LEFT, line);
this.borderLeft = line;
}
@ -125,7 +124,7 @@ public final class TableCell extends HSLFTextBox {
}
public void setBorderRight(Line line) {
if(line != null) anchorBorder(Table.BORDER_RIGHT, line);
if(line != null) anchorBorder(HSLFTable.BORDER_RIGHT, line);
this.borderRight = line;
}
@ -134,7 +133,7 @@ public final class TableCell extends HSLFTextBox {
}
public void setBorderTop(Line line) {
if(line != null) anchorBorder(Table.BORDER_TOP, line);
if(line != null) anchorBorder(HSLFTable.BORDER_TOP, line);
this.borderTop = line;
}
@ -143,16 +142,16 @@ public final class TableCell extends HSLFTextBox {
}
public void setBorderBottom(Line line) {
if(line != null) anchorBorder(Table.BORDER_BOTTOM, line);
if(line != null) anchorBorder(HSLFTable.BORDER_BOTTOM, line);
this.borderBottom = line;
}
public void setAnchor(Rectangle anchor){
super.setAnchor(anchor);
if(borderTop != null) anchorBorder(Table.BORDER_TOP, borderTop);
if(borderRight != null) anchorBorder(Table.BORDER_RIGHT, borderRight);
if(borderBottom != null) anchorBorder(Table.BORDER_BOTTOM, borderBottom);
if(borderLeft != null) anchorBorder(Table.BORDER_LEFT, borderLeft);
if(borderTop != null) anchorBorder(HSLFTable.BORDER_TOP, borderTop);
if(borderRight != null) anchorBorder(HSLFTable.BORDER_RIGHT, borderRight);
if(borderBottom != null) anchorBorder(HSLFTable.BORDER_BOTTOM, borderBottom);
if(borderLeft != null) anchorBorder(HSLFTable.BORDER_LEFT, borderLeft);
}
}

View File

@ -17,7 +17,10 @@
package org.apache.poi.hslf.usermodel;
import static org.apache.poi.hslf.record.RecordTypes.OutlineTextRefAtom;
import java.awt.Color;
import java.io.IOException;
import java.util.*;
import org.apache.poi.hslf.model.PPFont;
@ -52,8 +55,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
private final TextHeaderAtom _headerAtom;
private TextBytesAtom _byteAtom;
private TextCharsAtom _charAtom;
private StyleTextPropAtom _styleAtom;
private TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
protected TextRulerAtom _ruler;
protected List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
@ -61,11 +63,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
private HSLFSheet _sheet;
private int shapeId;
/**
* all text run records that follow TextHeaderAtom.
* (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
*/
private Record[] _records;
// private StyleTextPropAtom styleTextPropAtom;
private StyleTextProp9Atom styleTextProp9Atom;
@ -76,32 +73,30 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
* @param tha the TextHeaderAtom that defines what's what
* @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided
* @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided
* @param sta the StyleTextPropAtom which defines the character stylings
*/
/* package */ HSLFTextParagraph(
TextHeaderAtom tha,
TextBytesAtom tba,
TextCharsAtom tca,
StyleTextPropAtom sta
TextCharsAtom tca
) {
if (tha == null) {
throw new IllegalArgumentException("TextHeaderAtom must be set.");
}
_headerAtom = tha;
_styleAtom = sta;
_byteAtom = tba;
_charAtom = tca;
}
/* package */ HSLFTextParagraph(HSLFTextParagraph other) {
_headerAtom = other._headerAtom;
_styleAtom = other._styleAtom;
_byteAtom = other._byteAtom;
_charAtom = other._charAtom;
_paragraphStyle = other._paragraphStyle;
_parentShape = other._parentShape;
_sheet = other._sheet;
_ruler = other._ruler; // ????
shapeId = other.shapeId;
_records = other._records;
}
_headerAtom = other._headerAtom;
_byteAtom = other._byteAtom;
_charAtom = other._charAtom;
_parentShape = other._parentShape;
_sheet = other._sheet;
_ruler = other._ruler;
shapeId = other.shapeId;
_paragraphStyle.copy(other._paragraphStyle);
}
public void addTextRun(HSLFTextRun run) {
_runs.add(run);
@ -120,7 +115,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
}
public void setParagraphStyle(TextPropCollection paragraphStyle) {
_paragraphStyle = paragraphStyle;
_paragraphStyle.copy(paragraphStyle);
}
/**
@ -196,20 +191,52 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
_ruler = getTextRuler();
if (_ruler == null) {
_ruler = TextRulerAtom.getParagraphInstance();
_headerAtom.getParentRecord().appendChildRecord(_ruler);
Record childAfter = _byteAtom;
if (childAfter == null) childAfter = _charAtom;
if (childAfter == null) childAfter = _headerAtom;
_headerAtom.getParentRecord().addChildAfter(_ruler, childAfter);
}
return _ruler;
}
/**
* Returns records that make up this text run
* Returns records that make up the list of text paragraphs
* (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
*
* @return text run records
*/
public Record[] getRecords(){
return _records;
Record r[] = _headerAtom.getParentRecord().getChildRecords();
return getRecords(r, new int[]{0}, _headerAtom);
}
private static Record[] getRecords(Record[] records, int[] startIdx, TextHeaderAtom headerAtom) {
if (records == null) {
throw new NullPointerException("records need to be set.");
}
for (; startIdx[0] < records.length; startIdx[0]++) {
Record r = records[startIdx[0]];
if (r instanceof TextHeaderAtom && (headerAtom == null || r == headerAtom)) break;
}
if (startIdx[0] >= records.length) {
logger.log(POILogger.INFO, "header atom wasn't found - container might contain only an OutlineTextRefAtom");
return new Record[0];
}
int length;
for (length = 1; startIdx[0]+length < records.length; length++) {
if (records[startIdx[0]+length] instanceof TextHeaderAtom) break;
}
Record result[] = new Record[length];
System.arraycopy(records, startIdx[0], result, 0, length);
startIdx[0] += length;
return result;
}
/** Numbered List info */
public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
this.styleTextProp9Atom = styleTextProp9Atom;
@ -220,11 +247,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
return this.styleTextProp9Atom;
}
/** Characters covered */
public StyleTextPropAtom getStyleTextPropAtom() {
return this._styleAtom;
}
/**
* Fetch the value of the given Paragraph related TextProp.
* Returns -1 if that TextProp isn't present.
@ -232,14 +254,9 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
* Master Sheet will apply.
*/
private int getParaTextPropVal(String propName) {
TextProp prop = null;
boolean hardAttribute = false;
if (_paragraphStyle != null){
prop = _paragraphStyle.findByName(propName);
BitMaskTextProp maskProp = (BitMaskTextProp)_paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
hardAttribute = maskProp != null && maskProp.getValue() == 0;
}
TextProp prop = _paragraphStyle.findByName(propName);
BitMaskTextProp maskProp = (BitMaskTextProp)_paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
if (prop == null && !hardAttribute){
HSLFSheet sheet = getSheet();
int txtype = getRunType();
@ -258,11 +275,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
*/
public void setParaTextPropVal(String propName, int val) {
// Ensure we have the StyleTextProp atom we're going to need
if(_paragraphStyle == null) {
_styleAtom = findStyleAtomPresent(_headerAtom, -1);
_paragraphStyle = _styleAtom.getParagraphStyles().get(0);
}
assert(_paragraphStyle!=null);
TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName);
tp.setValue(val);
@ -615,10 +627,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
protected void setFlag(int index, boolean value) {
// Ensure we have the StyleTextProp atom we're going to need
if(_paragraphStyle == null) {
_paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
}
assert(_paragraphStyle!=null);
BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME);
prop.setSubValue(value,index);
}
@ -653,12 +662,13 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
boolean afterHeader = false;
StyleTextPropAtom style = null;
for (Record record : header.getParentRecord().getChildRecords()) {
if (afterHeader && record.getRecordType() == RecordTypes.TextHeaderAtom.typeID) {
long rt = record.getRecordType();
if (afterHeader && rt == RecordTypes.TextHeaderAtom.typeID) {
// already on the next header, quit searching
break;
}
afterHeader |= (header == record);
if (afterHeader && record.getRecordType() == RecordTypes.StyleTextPropAtom.typeID) {
if (afterHeader && rt == RecordTypes.StyleTextPropAtom.typeID) {
// found it
style = (StyleTextPropAtom)record;
}
@ -789,12 +799,20 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
* If TextSpecInfoAtom is present, we must update the text size in it,
* otherwise the ppt will be corrupted
*/
for (Record r : paragraphs.get(0)._records) {
for (Record r : paragraphs.get(0).getRecords()) {
if (r instanceof TextSpecInfoAtom) {
((TextSpecInfoAtom)r).setParentSize(rawText.length()+1);
break;
}
}
if (_txtbox instanceof EscherTextboxWrapper) {
try {
((EscherTextboxWrapper)_txtbox).writeOut(null);
} catch (IOException e) {
throw new RuntimeException("failed dummy write", e);
}
}
}
/**
@ -817,7 +835,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
if (!isFirst) {
TextPropCollection tpc = htp.getParagraphStyle();
HSLFTextParagraph prevHtp = htp;
htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom, htp._styleAtom);
htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);
htp.getParagraphStyle().copy(tpc);
htp.setParentShape(prevHtp.getParentShape());
htp.setShapeId(prevHtp.getShapeId());
@ -930,24 +948,14 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
/**
* For a given PPDrawing, grab all the TextRuns
*/
public static List<List<HSLFTextParagraph>> findTextParagraphs(PPDrawing ppdrawing) {
public static List<List<HSLFTextParagraph>> findTextParagraphs(PPDrawing ppdrawing, HSLFSheet sheet) {
List<List<HSLFTextParagraph>> runsV = new ArrayList<List<HSLFTextParagraph>>();
for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) {
runsV.addAll(findTextParagraphs(wrapper));
runsV.add(findTextParagraphs(wrapper, sheet));
}
return runsV;
}
/**
* Scans through the supplied record array, looking for
* a TextHeaderAtom followed by one of a TextBytesAtom or
* a TextCharsAtom. Builds up TextRuns from these
*
* @param records the records to build from
* @param found vector to add any found to
*/
protected static List<List<HSLFTextParagraph>> findTextParagraphs(final Record[] records) {
return findTextParagraphs(records, null);
}
/**
* Scans through the supplied record array, looking for
* a TextHeaderAtom followed by one of a TextBytesAtom or
@ -955,14 +963,73 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
*
* @param wrapper an EscherTextboxWrapper
*/
protected static List<List<HSLFTextParagraph>> findTextParagraphs(EscherTextboxWrapper wrapper) {
protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {
// propagate parents to parent-aware records
RecordContainer.handleParentAwareRecords(wrapper);
int shapeId = wrapper.getShapeId();
List<List<HSLFTextParagraph>> rv = findTextParagraphs(wrapper.getChildRecords(), wrapper.getStyleTextProp9Atom());
for (List<HSLFTextParagraph> htpList : rv) {
for (HSLFTextParagraph htp : htpList) {
List<HSLFTextParagraph> rv = null;
OutlineTextRefAtom ota = (OutlineTextRefAtom)wrapper.findFirstOfType(OutlineTextRefAtom.typeID);
if (ota != null) {
// if we are based on an outline, there are no further records to be parsed from the wrapper
if (sheet == null) {
throw new RuntimeException("Outline atom reference can't be solved without a sheet record");
}
List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
assert(sheetRuns != null);
int idx = ota.getTextIndex();
for (List<HSLFTextParagraph> r : sheetRuns) {
if (r.isEmpty()) continue;
int ridx = r.get(0).getIndex();
if (ridx > idx) break;
if (ridx == idx) {
if (rv == null) {
rv = r;
} else {
// create a new container
// TODO: ... is this case really happening?
rv = new ArrayList<HSLFTextParagraph>(rv);
rv.addAll(r);
}
}
}
if(rv == null || rv.isEmpty()) {
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
}
} else {
if (sheet != null) {
// check sheet runs first, so we get exactly the same paragraph list
List<List<HSLFTextParagraph>> sheetRuns = sheet.getTextParagraphs();
assert(sheetRuns != null);
for (List<HSLFTextParagraph> paras : sheetRuns) {
if (!paras.isEmpty() && paras.get(0)._headerAtom.getParentRecord() == wrapper) {
rv = paras;
break;
}
}
}
if (rv == null) {
// if we haven't found the wrapper in the sheet runs, create a new paragraph list from its record
List<List<HSLFTextParagraph>> rvl = findTextParagraphs(wrapper.getChildRecords());
switch (rvl.size()) {
case 0: break; // nothing found
case 1: rv = rvl.get(0); break; // normal case
default:
throw new RuntimeException("TextBox contains more than one list of paragraphs.");
}
}
}
if (rv != null) {
StyleTextProp9Atom styleTextProp9Atom = wrapper.getStyleTextProp9Atom();
for (HSLFTextParagraph htp : rv) {
htp.setShapeId(shapeId);
htp.setStyleTextProp9Atom(styleTextProp9Atom);
}
}
return rv;
@ -974,77 +1041,59 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
* a TextCharsAtom. Builds up TextRuns from these
*
* @param records the records to build from
* @param styleTextProp9Atom an optional StyleTextProp9Atom with numbered lists info
*/
protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records, StyleTextProp9Atom styleTextProp9Atom) {
protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records) {
List<List<HSLFTextParagraph>> paragraphCollection = new ArrayList<List<HSLFTextParagraph>>();
if (records == null) {
throw new NullPointerException("records need to be filled.");
}
int recordIdx;
for (recordIdx = 0; recordIdx < records.length; recordIdx++) {
if (records[recordIdx] instanceof TextHeaderAtom) break;
}
if (recordIdx == records.length) {
logger.log(POILogger.INFO, "No text records found.");
return paragraphCollection;
}
for (int slwtIndex = 0; recordIdx < records.length; slwtIndex++) {
List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>();
paragraphCollection.add(paragraphs);
TextHeaderAtom header = (TextHeaderAtom)records[recordIdx++];
int[] recordIdx = {0};
for (int slwtIndex = 0; recordIdx[0] < records.length; slwtIndex++) {
TextHeaderAtom header = null;
TextBytesAtom tbytes = null;
TextCharsAtom tchars = null;
TextRulerAtom ruler = null;
MasterTextPropAtom indents = null;
List<Record> otherRecordList = new ArrayList<Record>();
for (; recordIdx < records.length; recordIdx++) {
Record r = records[recordIdx];
for (Record r : getRecords(records, recordIdx, null)) {
long rt = r.getRecordType();
if (RecordTypes.TextHeaderAtom.typeID == rt) break;
else if (RecordTypes.TextBytesAtom.typeID == rt) tbytes = (TextBytesAtom)r;
else if (RecordTypes.TextCharsAtom.typeID == rt) tchars = (TextCharsAtom)r;
// don't search for RecordTypes.StyleTextPropAtom.typeID here ... see findStyleAtomPresent below
else if (RecordTypes.TextRulerAtom.typeID == rt) ruler = (TextRulerAtom)r;
else if (RecordTypes.MasterTextPropAtom.typeID == rt) {
if (RecordTypes.TextHeaderAtom.typeID == rt) {
header = (TextHeaderAtom)r;
} else if (RecordTypes.TextBytesAtom.typeID == rt) {
tbytes = (TextBytesAtom)r;
} else if (RecordTypes.TextCharsAtom.typeID == rt) {
tchars = (TextCharsAtom)r;
} else if (RecordTypes.TextRulerAtom.typeID == rt) {
ruler = (TextRulerAtom)r;
} else if (RecordTypes.MasterTextPropAtom.typeID == rt) {
indents = (MasterTextPropAtom)r;
otherRecordList.add(indents);
} else {
otherRecordList.add(r);
}
// don't search for RecordTypes.StyleTextPropAtom.typeID here ... see findStyleAtomPresent below
}
assert(header != null);
if (header == null) break;
if (header.getParentRecord() instanceof SlideListWithText) {
// runs found in PPDrawing are not linked with SlideListWithTexts
header.setIndex(slwtIndex);
}
Record otherRecords[] = otherRecordList.toArray(new Record[otherRecordList.size()]);
if (tbytes == null && tchars == null) {
tbytes = new TextBytesAtom();
// header.getParentRecord().addChildAfter(tbytes, header);
// don't add record yet - set it in storeText
logger.log(POILogger.INFO, "bytes nor chars atom doesn't exist. Creating dummy record for later saving.");
}
String rawText = (tchars != null) ? tchars.getText() : tbytes.getText();
StyleTextPropAtom styles = findStyleAtomPresent(header, rawText.length());
List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>();
paragraphCollection.add(paragraphs);
// split, but keep delimiter
for (String para : rawText.split("(?<=\r)")) {
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars, styles);
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars);
paragraphs.add(tpara);
tpara.setStyleTextProp9Atom(styleTextProp9Atom);
tpara._ruler = ruler;
tpara._records = otherRecords;
tpara.getParagraphStyle().updateTextSize(para.length());
HSLFTextRun trun = new HSLFTextRun(tpara);
@ -1059,6 +1108,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
}
}
if (paragraphCollection.isEmpty()) {
logger.log(POILogger.DEBUG, "No text records found.");
}
return paragraphCollection;
}
@ -1166,9 +1219,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
TextPropCollection charStyle = sta.addCharacterTextPropCollection(1);
wrapper.appendChildRecord(sta);
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null, sta);
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null);
htp.setParagraphStyle(paraStyle);
htp._records = new Record[0];
HSLFTextRun htr = new HSLFTextRun(htp);
htr.setCharacterStyle(charStyle);

View File

@ -92,7 +92,7 @@ public final class HSLFTextRun implements TextRun {
* Change the text
*/
public void setText(String text) {
_runText = text;
_runText = HSLFTextParagraph.toInternalString(text);
}
// --------------- Internal helpers on rich text properties -------

View File

@ -159,10 +159,29 @@ public abstract class HSLFTextShape extends HSLFSimpleShape implements TextShape
}
protected EscherTextboxWrapper getEscherTextboxWrapper(){
if(_txtbox == null){
EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID);
if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord);
if(_txtbox != null) return _txtbox;
EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID);
if (textRecord == null) return null;
HSLFSheet sheet = getSheet();
if (sheet != null) {
PPDrawing drawing = sheet.getPPDrawing();
if (drawing != null) {
EscherTextboxWrapper wrappers[] = drawing.getTextboxWrappers();
if (wrappers != null) {
for (EscherTextboxWrapper w : wrappers) {
// check for object identity
if (textRecord == w.getEscherRecord()) {
_txtbox = w;
return _txtbox;
}
}
}
}
}
_txtbox = new EscherTextboxWrapper(textRecord);
return _txtbox;
}
@ -507,13 +526,17 @@ public abstract class HSLFTextShape extends HSLFSimpleShape implements TextShape
_paragraphs.addAll(HSLFTextParagraph.createEmptyParagraph());
_txtbox = _paragraphs.get(0).getTextboxWrapper();
} else {
initParagraphsFromSheetRecords();
if (_paragraphs.isEmpty()) {
List<List<HSLFTextParagraph>> llhtp = HSLFTextParagraph.findTextParagraphs(_txtbox);
if (!llhtp.isEmpty()) {
_paragraphs.addAll(llhtp.get(0));
}
_paragraphs = HSLFTextParagraph.findTextParagraphs(_txtbox, getSheet());
if (_paragraphs == null || _paragraphs.isEmpty()) {
throw new RuntimeException("TextRecord didn't contained any text lines");
}
// initParagraphsFromSheetRecords();
// if (_paragraphs.isEmpty()) {
// List<List<HSLFTextParagraph>> llhtp = HSLFTextParagraph.findTextParagraphs(_txtbox);
// if (!llhtp.isEmpty()) {
// _paragraphs.addAll(llhtp.get(0));
// }
// }
}
for (HSLFTextParagraph p : _paragraphs) {
@ -536,57 +559,47 @@ public abstract class HSLFTextShape extends HSLFSimpleShape implements TextShape
}
}
protected void initParagraphsFromSheetRecords(){
EscherTextboxWrapper txtbox = getEscherTextboxWrapper();
HSLFSheet sheet = getSheet();
if(sheet == null || txtbox == null) return;
OutlineTextRefAtom ota = null;
Record[] child = txtbox.getChildRecords();
for (int i = 0; i < child.length; i++) {
if (child[i] instanceof OutlineTextRefAtom) {
ota = (OutlineTextRefAtom)child[i];
break;
}
}
List<List<HSLFTextParagraph>> sheetRuns = _sheet.getTextParagraphs();
_paragraphs.clear();
if (sheetRuns != null) {
if (ota != null) {
int idx = ota.getTextIndex();
for (List<HSLFTextParagraph> r : sheetRuns) {
if (r.isEmpty()) continue;
int ridx = r.get(0).getIndex();
if (ridx > idx) break;
if (ridx == idx) _paragraphs.addAll(r);
}
if(_paragraphs.isEmpty()) {
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
}
} else {
int shapeId = getShapeId();
for (List<HSLFTextParagraph> r : sheetRuns) {
if (r.isEmpty()) continue;
if (r.get(0).getShapeId() == shapeId) _paragraphs.addAll(r);
}
}
}
// ensure the same references child records of TextRun
// TODO: check the purpose of this ...
// if(_txtrun != null) {
// for (int i = 0; i < child.length; i++) {
// for (Record r : _txtrun.getRecords()) {
// if (child[i].getRecordType() == r.getRecordType()) {
// child[i] = r;
// }
// }
// protected void initParagraphsFromSheetRecords(){
// EscherTextboxWrapper txtbox = getEscherTextboxWrapper();
// HSLFSheet sheet = getSheet();
//
// if (sheet == null || txtbox == null) return;
// List<List<HSLFTextParagraph>> sheetRuns = _sheet.getTextParagraphs();
// if (sheetRuns == null) return;
//
// _paragraphs.clear();
// OutlineTextRefAtom ota = (OutlineTextRefAtom)txtbox.findFirstOfType(OutlineTextRefAtom.typeID);
//
// if (ota != null) {
// int idx = ota.getTextIndex();
// for (List<HSLFTextParagraph> r : sheetRuns) {
// if (r.isEmpty()) continue;
// int ridx = r.get(0).getIndex();
// if (ridx > idx) break;
// if (ridx == idx) _paragraphs.addAll(r);
// }
// if(_paragraphs.isEmpty()) {
// logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
// }
// } else {
// int shapeId = getShapeId();
// for (List<HSLFTextParagraph> r : sheetRuns) {
// if (r.isEmpty()) continue;
// if (r.get(0).getShapeId() == shapeId) _paragraphs.addAll(r);
// }
// }
}
//
// // ensure the same references child records of TextRun - see #48916
//// if(_txtrun != null) {
//// for (int i = 0; i < child.length; i++) {
//// for (Record r : _txtrun.getRecords()) {
//// if (child[i].getRecordType() == r.getRecordType()) {
//// child[i] = r;
//// }
//// }
//// }
//// }
// }
/*
// 0xB acts like cariage return in page titles and like blank in the others
@ -740,7 +753,8 @@ public abstract class HSLFTextShape extends HSLFSimpleShape implements TextShape
* Also updates the styles to the correct text length.
*/
protected void storeText() {
HSLFTextParagraph.storeText(_paragraphs);
List<HSLFTextParagraph> paras = getTextParagraphs();
HSLFTextParagraph.storeText(paras);
}
// Accesser methods follow

View File

@ -29,7 +29,7 @@ import org.apache.poi.hslf.record.SlideAtom;
* @author Yegor Kozlov
*/
public final class HSLFTitleMaster extends HSLFMasterSheet {
private final List<List<HSLFTextParagraph>> _runs = new ArrayList<List<HSLFTextParagraph>>();
private final List<List<HSLFTextParagraph>> _paragraphs = new ArrayList<List<HSLFTextParagraph>>();
/**
* Constructs a TitleMaster
@ -38,14 +38,16 @@ public final class HSLFTitleMaster extends HSLFMasterSheet {
public HSLFTitleMaster(org.apache.poi.hslf.record.Slide record, int sheetNo) {
super(record, sheetNo);
_runs.addAll(HSLFTextParagraph.findTextParagraphs(getPPDrawing()));
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
if (!_paragraphs.contains(l)) _paragraphs.add(l);
}
}
/**
* Returns an array of all the TextRuns found
*/
public List<List<HSLFTextParagraph>> getTextParagraphs() {
return _runs;
return _paragraphs;
}
/**

View File

@ -69,8 +69,8 @@ public class DrawFactory {
return getDrawable((FreeformShape<? extends TextParagraph<? extends TextRun>>)shape);
} else if (shape instanceof TextShape) {
return getDrawable((TextShape<? extends TextParagraph<? extends TextRun>>)shape);
} else if (shape instanceof ShapeGroup) {
return getDrawable((ShapeGroup<? extends Shape>)shape);
} else if (shape instanceof GroupShape) {
return getDrawable((GroupShape<? extends Shape>)shape);
} else if (shape instanceof PictureShape) {
return getDrawable((PictureShape)shape);
} else if (shape instanceof Background) {
@ -110,8 +110,8 @@ public class DrawFactory {
return new DrawTextShape<T>(shape);
}
public <T extends ShapeGroup<? extends Shape>> DrawShapeGroup<T> getDrawable(T shape) {
return new DrawShapeGroup<T>(shape);
public <T extends GroupShape<? extends Shape>> DrawGroupShape<T> getDrawable(T shape) {
return new DrawGroupShape<T>(shape);
}
public <T extends PictureShape> DrawPictureShape<T> getDrawable(T shape) {

View File

@ -7,9 +7,9 @@ import java.awt.geom.Rectangle2D;
import org.apache.poi.sl.usermodel.*;
public class DrawShapeGroup<T extends ShapeGroup<? extends Shape>> extends DrawShape<T> implements Drawable {
public class DrawGroupShape<T extends GroupShape<? extends Shape>> extends DrawShape<T> implements Drawable {
public DrawShapeGroup(T shape) {
public DrawGroupShape(T shape) {
super(shape);
}
@ -31,6 +31,7 @@ public class DrawShapeGroup<T extends ShapeGroup<? extends Shape>> extends DrawS
tx.translate(-interior.getX(), -interior.getY());
DrawFactory drawFact = DrawFactory.getInstance(graphics);
AffineTransform at2 = graphics.getTransform();
for (Shape child : shape) {
// remember the initial transform and restore it after we are done with the drawing
@ -46,7 +47,7 @@ public class DrawShapeGroup<T extends ShapeGroup<? extends Shape>> extends DrawS
graphics.setRenderingHint(Drawable.GRESTORE, true);
}
graphics.setTransform(at2);
graphics.setRenderingHint(Drawable.GROUP_TRANSFORM, tx0);
}
}

View File

@ -25,11 +25,10 @@ public class DrawShape<T extends Shape> implements Drawable {
if (!(shape instanceof PlaceableShape)) return;
PlaceableShape ps = (PlaceableShape)shape;
Rectangle2D anchor = ps.getAnchor();
AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
if(tx != null) {
anchor = tx.createTransformedShape(anchor).getBounds2D();
}
final Rectangle2D anchor = (tx != null)
? tx.createTransformedShape(ps.getAnchor()).getBounds2D()
: ps.getAnchor();
// rotation
double rotation = ps.getRotation();
@ -39,7 +38,8 @@ public class DrawShape<T extends Shape> implements Drawable {
double centerY = anchor.getCenterY();
// normalize rotation
rotation = (360.+(rotation%360.))%360.;
rotation %= 360.;
if (rotation < 0) rotation += 360.;
int quadrant = (((int)rotation+45)/90)%4;
double scaleX = 1.0, scaleY = 1.0;
@ -53,26 +53,43 @@ public class DrawShape<T extends Shape> implements Drawable {
// think of it, as if you paint the shape on a canvas. First you rotate the canvas, which might
// be already (differently) scaled, so you can paint the shape in its default orientation
// and later on, turn it around again to compare it with its original size ...
AffineTransform txg = new AffineTransform(); // graphics coordinate space
AffineTransform txs = new AffineTransform(tx); // shape coordinate space
// graphics coordinate space
AffineTransform txg = new AffineTransform();
txg.translate(centerX, centerY);
txg.rotate(Math.toRadians(quadrant*90));
txg.rotate(Math.toRadians(90));
txg.translate(-centerX, -centerY);
txs.translate(centerX, centerY);
txs.rotate(Math.toRadians(-quadrant*90));
txs.translate(-centerX, -centerY);
txg.concatenate(txs);
Rectangle2D anchor2 = txg.createTransformedShape(ps.getAnchor()).getBounds2D();
boolean oldVariant = true;
Rectangle2D anchor2;
if (oldVariant) {
// shape coordinate space
AffineTransform txs = new AffineTransform(tx);
txs.translate(centerX, centerY);
txs.rotate(Math.toRadians(90));
txs.translate(-centerX, -centerY);
txg.concatenate(txs);
anchor2 = txg.createTransformedShape(ps.getAnchor()).getBounds2D();
} else {
anchor2 = txg.createTransformedShape(anchor).getBounds2D();
}
scaleX = anchor.getWidth() == 0. ? 1.0 : anchor.getWidth() / anchor2.getWidth();
scaleY = anchor.getHeight() == 0. ? 1.0 : anchor.getHeight() / anchor2.getHeight();
graphics.translate(centerX, centerY);
graphics.rotate(Math.toRadians(rotation-quadrant*90.));
graphics.scale(scaleX, scaleY);
graphics.rotate(Math.toRadians(quadrant*90));
graphics.translate(-centerX, -centerY);
} else {
graphics.translate(centerX, centerY);
graphics.rotate(Math.toRadians(rotation));
graphics.scale(scaleX, scaleY);
graphics.translate(-centerX, -centerY);
}
// transformation is applied reversed ...
graphics.translate(centerX, centerY);
graphics.rotate(Math.toRadians(rotation-quadrant*90.));
graphics.scale(scaleX, scaleY);
graphics.rotate(Math.toRadians(quadrant*90));
graphics.translate(-centerX, -centerY);
}
//flip horizontal

View File

@ -32,6 +32,23 @@ public interface Drawable {
public boolean isCompatibleValue(Object val) {
return true;
}
public String toString() {
switch (intKey()) {
case 1: return "DRAW_FACTORY";
case 2: return "GROUP_TRANSFORM";
case 3: return "IMAGE_RENDERER";
case 4: return "TEXT_RENDERING_MODE";
case 5: return "GRADIENT_SHAPE";
case 6: return "PRESET_GEOMETRY_CACHE";
case 7: return "FONT_HANDLER";
case 8: return "FONT_FALLBACK";
case 9: return "FONT_MAP";
case 10: return "GSAVE";
case 11: return "GRESTORE";
default: return "UNKNOWN_ID "+intKey();
}
}
}
/**

View File

@ -30,18 +30,35 @@ import javax.imageio.ImageIO;
/**
* For now this class renders only images supported by the javax.imageio.ImageIO
* framework. Subclasses can override this class to support other formats, for
* example, Use Apache batik to render WMF:
* example, use Apache Batik to render WMF, PICT can be rendered using Apple QuickTime API for Java:
*
* <pre>
* <code>
* public class MyImageRendener extends ImageRendener {
* InputStream data;
*
* public boolean drawImage(Graphics2D graphics,Rectangle2D anchor,Insets clip) {
* // draw image
* DataInputStream is = new DataInputStream(data);
* org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore wmfStore =
* new org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore();
* try {
* wmfStore.read(is);
* } catch (IOException e){
* return;
* }
*
* float scale = (float)anchor.width/wmfStore.getWidthPixels();
*
* org.apache.batik.transcoder.wmf.tosvg.WMFPainter painter =
* new org.apache.batik.transcoder.wmf.tosvg.WMFPainter(wmfStore, 0, 0, scale);
* graphics.translate(anchor.x, anchor.y);
* painter.paint(graphics);
* }
*
* public void loadImage(InputStream data, String contentType) throws IOException {
* if ("image/wmf".equals(contentType)) {
* this.data = data;
* // use Apache Batik to handle WMF
* } else {
* super.loadImage(data,contentType);
@ -147,12 +164,14 @@ public class ImageRenderer {
int iw = img.getWidth();
int ih = img.getHeight();
double cw = (100000-clip.left-clip.right) / 100000.0;
double ch = (100000-clip.top-clip.bottom) / 100000.0;
double sx = anchor.getWidth()/(iw*cw);
double sy = anchor.getHeight()/(ih*ch);
double tx = anchor.getX()-(iw*sx*clip.left/100000.0);
double ty = anchor.getY()-(ih*sy*clip.top/100000.0);
AffineTransform at = new AffineTransform(sx, 0, 0, sy, tx, ty) ;
Shape clipOld = graphics.getClip();

View File

@ -19,6 +19,21 @@ package org.apache.poi.sl.usermodel;
import java.awt.geom.Rectangle2D;
public interface ShapeGroup<T extends Shape> extends Shape, ShapeContainer<T>, PlaceableShape {
public interface GroupShape<T extends Shape> extends Shape, ShapeContainer<T>, PlaceableShape {
/**
* Gets the coordinate space of this group. All children are constrained
* to these coordinates.
*
* @param anchor the coordinate space of this group
*/
Rectangle2D getInteriorAnchor();
/**
* Sets the coordinate space of this group. All children are constrained
* to these coordinates.
*
* @param anchor the coordinate space of this group
*/
void setInteriorAnchor(Rectangle2D anchor);
}

View File

@ -20,9 +20,17 @@ package org.apache.poi.sl.usermodel;
import java.awt.Insets;
public interface PictureShape extends SimpleShape {
PictureData getPictureData();
/**
* Returns the picture data for this picture.
*
* @return the picture data for this picture.
*/
PictureData getPictureData();
/**
* Returns the clipping values as percent ratio relatively to the image size.
* The clipping are returned as insets converted/scaled to 100000 (=100%).
*
* @return the clipping rectangle, which is given in percent in relation to the image width/height
*/
Insets getClipping();

View File

@ -17,6 +17,8 @@
package org.apache.poi.sl.usermodel;
import java.awt.Graphics2D;
/**
* Common parent of Slides, Notes and Masters
@ -34,4 +36,11 @@ public interface Sheet<T extends Shape, SS extends SlideShow> extends ShapeConta
MasterSheet<T,SS> getMasterSheet();
Background getBackground();
/**
* Convenience method to draw a sheet to a graphics context
*
* @param graphics
*/
void draw(Graphics2D graphics);
}

View File

@ -29,7 +29,6 @@ import org.junit.runners.Suite;
TestFreeform.class,
TestHeadersFooters.class,
TestHyperlink.class,
TestImagePainter.class,
TestLine.class,
TestMovieShape.class,
TestOleEmbedding.class,

View File

@ -1,55 +0,0 @@
/* ====================================================================
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.Graphics2D;
import junit.framework.TestCase;
import org.apache.poi.hslf.blip.BitmapPainter;
import org.apache.poi.hslf.blip.ImagePainter;
import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFPictureShape;
/**
* Test Picture shape.
*
* @author Yegor Kozlov
*/
public final class TestImagePainter extends TestCase {
private static class CustomImagePainter implements ImagePainter {
public CustomImagePainter() {
// no fields to initialise
}
public void paint(Graphics2D graphics, HSLFPictureData pict, HSLFPictureShape parent){
//do noting
}
}
public void testImagePainter() {
ImagePainter pntr = HSLFPictureData.getImagePainter(HSLFPictureShape.PNG);
assertTrue(HSLFPictureData.getImagePainter(HSLFPictureShape.PNG) instanceof BitmapPainter);
assertTrue(HSLFPictureData.getImagePainter(HSLFPictureShape.JPEG) instanceof BitmapPainter);
assertTrue(HSLFPictureData.getImagePainter(HSLFPictureShape.DIB) instanceof BitmapPainter);
HSLFPictureData.setImagePainter(HSLFPictureShape.WMF, new CustomImagePainter());
assertTrue(HSLFPictureData.getImagePainter(HSLFPictureShape.WMF) instanceof CustomImagePainter);
}
}

View File

@ -43,15 +43,15 @@ public final class TestTable {
HSLFSlide slide = ppt.createSlide();
Table tbl = new Table(2, 5);
HSLFTable tbl = new HSLFTable(2, 5);
slide.addShape(tbl);
TableCell cell = tbl.getCell(0, 0);
HSLFTableCell cell = tbl.getCell(0, 0);
//table cells have type=TextHeaderAtom.OTHER_TYPE, see bug #46033
assertEquals(TextHeaderAtom.OTHER_TYPE, cell.getTextParagraphs().get(0).getRunType());
assertTrue(slide.getShapes().get(0) instanceof Table);
Table tbl2 = (Table)slide.getShapes().get(0);
assertTrue(slide.getShapes().get(0) instanceof HSLFTable);
HSLFTable tbl2 = (HSLFTable)slide.getShapes().get(0);
assertEquals(tbl.getNumberOfColumns(), tbl2.getNumberOfColumns());
assertEquals(tbl.getNumberOfRows(), tbl2.getNumberOfRows());
@ -61,8 +61,8 @@ public final class TestTable {
ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()));
slide = ppt.getSlides().get(0);
assertTrue(slide.getShapes().get(0) instanceof Table);
Table tbl3 = (Table)slide.getShapes().get(0);
assertTrue(slide.getShapes().get(0) instanceof HSLFTable);
HSLFTable tbl3 = (HSLFTable)slide.getShapes().get(0);
assertEquals(tbl.getNumberOfColumns(), tbl3.getNumberOfColumns());
assertEquals(tbl.getNumberOfRows(), tbl3.getNumberOfRows());
}
@ -75,7 +75,7 @@ public final class TestTable {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();
List<HSLFShape> shapes;
Table tbl1 = new Table(1, 5);
HSLFTable tbl1 = new HSLFTable(1, 5);
assertEquals(5, tbl1.getNumberOfColumns());
assertEquals(1, tbl1.getNumberOfRows());
slide.addShape(tbl1);
@ -83,7 +83,7 @@ public final class TestTable {
shapes = slide.getShapes();
assertEquals(1, shapes.size());
Table tbl2 = (Table)shapes.get(0);
HSLFTable tbl2 = (HSLFTable)shapes.get(0);
assertSame(tbl1.getSpContainer(), tbl2.getSpContainer());
assertEquals(tbl1.getNumberOfColumns(), tbl2.getNumberOfColumns());
@ -93,13 +93,13 @@ public final class TestTable {
@Test
public void testIllegalCOnstruction(){
try {
new Table(0, 5);
new HSLFTable(0, 5);
fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1");
} catch (IllegalArgumentException e){
}
try {
new Table(5, 0);
new HSLFTable(5, 0);
fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1");
} catch (IllegalArgumentException e){

View File

@ -281,7 +281,7 @@ public final class TestAddingSlides extends TestCase {
assertEquals(14, doc.getNotesSlideListWithText().getSlideAtomsSets().length);
//remove all slides, corresponding notes should be removed too
for (int i = 0; i < slides.size(); i++) {
for (int i = slides.size(); i > 0; i--) {
ppt.removeSlide(0);
}
assertEquals(0, ppt.getSlides().size());

View File

@ -18,14 +18,10 @@
package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.awt.Color;
import java.awt.Rectangle;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@ -44,14 +40,14 @@ import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.hslf.HSLFTestDataSamples;
import org.apache.poi.hslf.exceptions.OldPowerPointFormatException;
import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.SlideListWithText;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
import org.apache.poi.util.Units;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.*;
import org.junit.Ignore;
import org.junit.Test;
/**
@ -527,7 +523,7 @@ public final class TestBugs {
for (List<HSLFTextParagraph> tr : _slides.get(0).getTextParagraphs()) {
if (! tr.get(0).isDrawingBased()) str++;
}
assertEquals(1, str);
assertEquals(2, str);
}
@Test

View File

@ -17,29 +17,22 @@
package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeTrue;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import javax.imageio.ImageIO;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.model.TextPainter;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.util.TempFile;
import org.junit.Ignore;
import org.junit.Test;
@ -50,7 +43,7 @@ import org.junit.Test;
public class TestFontRendering {
private static POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
@Ignore("This fails on some systems because fonts are rendered slightly different")
// @Ignore2("This fails on some systems because fonts are rendered slightly different")
@Test
public void bug55902mixedFontWithChineseCharacters() throws Exception {
// font files need to be downloaded first via
@ -86,7 +79,7 @@ public class TestFontRendering {
Dimension pgsize = ss.getPageSize();
HSLFSlide slide = ss.getSlides()[0];
HSLFSlide slide = ss.getSlides().get(0);
// render it
double zoom = 1;
@ -95,8 +88,8 @@ public class TestFontRendering {
BufferedImage imgActual = new BufferedImage((int)Math.ceil(pgsize.width*zoom), (int)Math.ceil(pgsize.height*zoom), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D graphics = imgActual.createGraphics();
graphics.setRenderingHint(TextPainter.KEY_FONTFALLBACK, fallbackMap);
graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);
graphics.setRenderingHint(Drawable.FONT_FALLBACK, fallbackMap);
graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
@ -116,7 +109,7 @@ public class TestFontRendering {
if(!Arrays.equals(expectedData, actualData)) {
ImageIO.write(imgActual, "PNG", TempFile.createTempFile("TestFontRendering", ".png"));
}
assertTrue("Expected to have matching raster-arrays, but found differences, size " + expectedData.length + " and " + actualData.length,
Arrays.equals(expectedData, actualData));
assertArrayEquals("Expected to have matching raster-arrays, but found differences", expectedData, actualData);
}
}

View File

@ -79,10 +79,14 @@ public final class TestNumberedList3 {
assertEquals(Short.valueOf((short)1), autoNumbers[0].getAutoNumberStartNumber());//Default value = 1 will be used
assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicPeriod == autoNumbersOfTextBox0[0].getAutoNumberScheme());
final List<TextPropCollection> textProps = textParass.get(1).get(0).getStyleTextPropAtom().getCharacterStyles();
assertEquals(1, textProps.size());
final TextPropCollection textProp = textProps.get(0);
assertEquals(67, textProp.getCharactersCovered());
int chCovered = 0;
for (HSLFTextParagraph htp : textParass.get(1)) {
for (HSLFTextRun htr : htp.getTextRuns()) {
TextPropCollection textProp = htr.getCharacterStyle();
chCovered += textProp.getCharactersCovered();
}
}
assertEquals(67, chCovered);
assertTrue(textParass.get(0).get(0).isBullet());

View File

@ -17,18 +17,11 @@
package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.*;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
@ -36,8 +29,12 @@ import javax.imageio.ImageIO;
import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hssf.usermodel.DummyGraphics2d;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.util.JvmBugs;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.junit.Ignore;
import org.junit.Test;
@ -143,45 +140,42 @@ public final class TestPicture {
}
@Test
@Ignore("Just for visual validation - antialiasing is different on various systems")
// @Ignore("Just for visual validation - antialiasing is different on various systems")
public void bug54541() throws Exception {
// InputStream xis = _slTests.openResourceAsStream("54542_cropped_bitmap.pptx");
// XMLSlideShow xss = new XMLSlideShow(xis);
// xis.close();
//
// Dimension xpg = xss.getPageSize();
// for(XSLFSlide slide : xss.getSlides()) {
// BufferedImage img = new BufferedImage(xpg.width, xpg.height, BufferedImage.TYPE_INT_RGB);
// Graphics2D graphics = img.createGraphics();
// fixFonts(graphics);
// slide.draw(graphics);
// ImageIO.write(img, "PNG", new File("testx.png"));
// }
//
// System.out.println("########################");
InputStream is = _slTests.openResourceAsStream("54541_cropped_bitmap.ppt");
HSLFSlideShow ss = new HSLFSlideShow(is);
String file = new String[]{
"54542_cropped_bitmap.pptx",
"54541_cropped_bitmap.ppt",
"54541_cropped_bitmap2.ppt",
"sample_pptx_grouping_issues.pptx"
}[3];
InputStream is = _slTests.openResourceAsStream(file);
SlideShow ss = file.endsWith("pptx") ? new XMLSlideShow(is) : new HSLFSlideShow(is);
is.close();
boolean debugOut = false;
Dimension pg = ss.getPageSize();
int i=1;
for(HSLFSlide slide : ss.getSlides()) {
BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
fixFonts(graphics);
slide.draw(graphics);
ImageIO.write(img, "PNG", new File("test"+(i++)+".png"));
for(Slide<?,?,?> slide : ss.getSlides()) {
if (debugOut) {
DummyGraphics2d graphics = new DummyGraphics2d();
slide.draw(graphics);
} else {
BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
fixFonts(graphics);
slide.draw(graphics);
ImageIO.write(img, "PNG", new File("test"+(i++)+"hslf.png"));
}
}
}
@SuppressWarnings("unchecked")
private void fixFonts(Graphics2D graphics) {
if (!JvmBugs.hasLineBreakMeasurerBug()) return;
Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);
Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
if (fontMap == null) fontMap = new HashMap<String,String>();
fontMap.put("Calibri", "Lucida Sans");
fontMap.put("Cambria", "Lucida Bright");
graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);
graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);
}
}

View File

@ -22,17 +22,12 @@ import static org.junit.Assert.assertArrayEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import java.util.List;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.blip.DIB;
import org.apache.poi.hslf.blip.EMF;
import org.apache.poi.hslf.blip.JPEG;
import org.apache.poi.hslf.blip.PICT;
import org.apache.poi.hslf.blip.PNG;
import org.apache.poi.hslf.blip.WMF;
import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.blip.*;
/**
* Test adding/reading pictures
@ -65,9 +60,9 @@ public final class TestPictures extends TestCase{
ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray())));
//make sure we can read this picture shape and it refers to the correct picture data
HSLFShape[] sh = ppt.getSlides()[0].getShapes();
assertEquals(1, sh.length);
pict = (HSLFPictureShape)sh[0];
List<HSLFShape> sh = ppt.getSlides().get(0).getShapes();
assertEquals(1, sh.size());
pict = (HSLFPictureShape)sh.get(0);
assertEquals(idx, pict.getPictureIndex());
//check picture data
@ -110,9 +105,9 @@ public final class TestPictures extends TestCase{
ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray())));
//make sure we can read this picture shape and it refers to the correct picture data
HSLFShape[] sh = ppt.getSlides()[0].getShapes();
assertEquals(1, sh.length);
pict = (HSLFPictureShape)sh[0];
List<HSLFShape> sh = ppt.getSlides().get(0).getShapes();
assertEquals(1, sh.size());
pict = (HSLFPictureShape)sh.get(0);
assertEquals(idx, pict.getPictureIndex());
//check picture data
@ -156,9 +151,9 @@ public final class TestPictures extends TestCase{
ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray())));
//make sure we can get this picture shape and it refers to the correct picture data
HSLFShape[] sh = ppt.getSlides()[0].getShapes();
assertEquals(1, sh.length);
pict = (HSLFPictureShape)sh[0];
List<HSLFShape> sh = ppt.getSlides().get(0).getShapes();
assertEquals(1, sh.size());
pict = (HSLFPictureShape)sh.get(0);
assertEquals(idx, pict.getPictureIndex());
//check picture data
@ -195,9 +190,9 @@ public final class TestPictures extends TestCase{
ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray())));
//make sure we can read this picture shape and it refers to the correct picture data
HSLFShape[] sh = ppt.getSlides()[0].getShapes();
assertEquals(1, sh.length);
pict = (HSLFPictureShape)sh[0];
List<HSLFShape> sh = ppt.getSlides().get(0).getShapes();
assertEquals(1, sh.size());
pict = (HSLFPictureShape)sh.get(0);
assertEquals(idx, pict.getPictureIndex());
//check picture data
@ -235,9 +230,9 @@ public final class TestPictures extends TestCase{
ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray())));
//make sure we can read this picture shape and it refers to the correct picture data
HSLFShape[] sh = ppt.getSlides()[0].getShapes();
assertEquals(1, sh.length);
pict = (HSLFPictureShape)sh[0];
List<HSLFShape> sh = ppt.getSlides().get(0).getShapes();
assertEquals(1, sh.size());
pict = (HSLFPictureShape)sh.get(0);
assertEquals(idx, pict.getPictureIndex());
//check picture data
@ -274,9 +269,9 @@ public final class TestPictures extends TestCase{
ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray())));
//make sure we can read this picture shape and it refers to the correct picture data
HSLFShape[] sh = ppt.getSlides()[0].getShapes();
assertEquals(1, sh.length);
pict = (HSLFPictureShape)sh[0];
List<HSLFShape> sh = ppt.getSlides().get(0).getShapes();
assertEquals(1, sh.size());
pict = (HSLFPictureShape)sh.get(0);
assertEquals(idx, pict.getPictureIndex());
//check picture data
@ -302,11 +297,11 @@ public final class TestPictures extends TestCase{
HSLFPictureData pdata;
HSLFSlideShow ppt = new HSLFSlideShow(slTests.openResourceAsStream("pictures.ppt"));
HSLFSlide[] slides = ppt.getSlides();
List<HSLFSlide> slides = ppt.getSlides();
HSLFPictureData[] pictures = ppt.getPictureData();
assertEquals(5, pictures.length);
pict = (HSLFPictureShape)slides[0].getShapes()[0]; //the first slide contains JPEG
pict = (HSLFPictureShape)slides.get(0).getShapes().get(0); //the first slide contains JPEG
pdata = pict.getPictureData();
assertTrue(pdata instanceof JPEG);
assertEquals(HSLFPictureShape.JPEG, pdata.getType());
@ -314,7 +309,7 @@ public final class TestPictures extends TestCase{
ppt_bytes = slTests.readFile("clock.jpg");
assertArrayEquals(src_bytes, ppt_bytes);
pict = (HSLFPictureShape)slides[1].getShapes()[0]; //the second slide contains PNG
pict = (HSLFPictureShape)slides.get(1).getShapes().get(0); //the second slide contains PNG
pdata = pict.getPictureData();
assertTrue(pdata instanceof PNG);
assertEquals(HSLFPictureShape.PNG, pdata.getType());
@ -322,7 +317,7 @@ public final class TestPictures extends TestCase{
ppt_bytes = slTests.readFile("tomcat.png");
assertArrayEquals(src_bytes, ppt_bytes);
pict = (HSLFPictureShape)slides[2].getShapes()[0]; //the third slide contains WMF
pict = (HSLFPictureShape)slides.get(2).getShapes().get(0); //the third slide contains WMF
pdata = pict.getPictureData();
assertTrue(pdata instanceof WMF);
assertEquals(HSLFPictureShape.WMF, pdata.getType());
@ -336,7 +331,7 @@ public final class TestPictures extends TestCase{
System.arraycopy(ppt_bytes, 22, b2, 0, b2.length);
assertArrayEquals(b1, b2);
pict = (HSLFPictureShape)slides[3].getShapes()[0]; //the forth slide contains PICT
pict = (HSLFPictureShape)slides.get(3).getShapes().get(0); //the forth slide contains PICT
pdata = pict.getPictureData();
assertTrue(pdata instanceof PICT);
assertEquals(HSLFPictureShape.PICT, pdata.getType());
@ -350,7 +345,7 @@ public final class TestPictures extends TestCase{
System.arraycopy(ppt_bytes, 512, b2, 0, b2.length);
assertArrayEquals(b1, b2);
pict = (HSLFPictureShape)slides[4].getShapes()[0]; //the fifth slide contains EMF
pict = (HSLFPictureShape)slides.get(4).getShapes().get(0); //the fifth slide contains EMF
pdata = pict.getPictureData();
assertTrue(pdata instanceof EMF);
assertEquals(HSLFPictureShape.EMF, pdata.getType());
@ -375,20 +370,20 @@ public final class TestPictures extends TestCase{
// Now test what happens when we use the SlideShow interface
HSLFSlideShow ppt = new HSLFSlideShow(hslf);
HSLFSlide[] slides = ppt.getSlides();
List<HSLFSlide> slides = ppt.getSlides();
HSLFPictureData[] pictures = ppt.getPictureData();
assertEquals(12, slides.length);
assertEquals(12, slides.size());
assertEquals(2, pictures.length);
HSLFPictureShape pict;
HSLFPictureData pdata;
pict = (HSLFPictureShape)slides[0].getShapes()[1]; // 2nd object on 1st slide
pict = (HSLFPictureShape)slides.get(0).getShapes().get(1); // 2nd object on 1st slide
pdata = pict.getPictureData();
assertTrue(pdata instanceof WMF);
assertEquals(HSLFPictureShape.WMF, pdata.getType());
pict = (HSLFPictureShape)slides[0].getShapes()[2]; // 3rd object on 1st slide
pict = (HSLFPictureShape)slides.get(0).getShapes().get(2); // 3rd object on 1st slide
pdata = pict.getPictureData();
assertTrue(pdata instanceof WMF);
assertEquals(HSLFPictureShape.WMF, pdata.getType());
@ -411,20 +406,20 @@ public final class TestPictures extends TestCase{
// Now test what happens when we use the SlideShow interface
HSLFSlideShow ppt = new HSLFSlideShow(hslf);
HSLFSlide[] slides = ppt.getSlides();
List<HSLFSlide> slides = ppt.getSlides();
HSLFPictureData[] pictures = ppt.getPictureData();
assertEquals(27, slides.length);
assertEquals(27, slides.size());
assertEquals(2, pictures.length);
HSLFPictureShape pict;
HSLFPictureData pdata;
pict = (HSLFPictureShape)slides[6].getShapes()[13];
pict = (HSLFPictureShape)slides.get(6).getShapes().get(13);
pdata = pict.getPictureData();
assertTrue(pdata instanceof WMF);
assertEquals(HSLFPictureShape.WMF, pdata.getType());
pict = (HSLFPictureShape)slides[7].getShapes()[13];
pict = (HSLFPictureShape)slides.get(7).getShapes().get(13);
pdata = pict.getPictureData();
assertTrue(pdata instanceof WMF);
assertEquals(HSLFPictureShape.WMF, pdata.getType());
@ -446,9 +441,9 @@ public final class TestPictures extends TestCase{
public void testGetPictureName() throws Exception {
HSLFSlideShow ppt = new HSLFSlideShow(slTests.openResourceAsStream("ppt_with_png.ppt"));
HSLFSlide slide = ppt.getSlides()[0];
HSLFSlide slide = ppt.getSlides().get(0);
HSLFPictureShape p = (HSLFPictureShape)slide.getShapes()[0]; //the first slide contains JPEG
HSLFPictureShape p = (HSLFPictureShape)slide.getShapes().get(0); //the first slide contains JPEG
assertEquals("test", p.getPictureName());
}
@ -469,7 +464,7 @@ public final class TestPictures extends TestCase{
ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()));
HSLFPictureShape p = (HSLFPictureShape)ppt.getSlides()[0].getShapes()[0];
HSLFPictureShape p = (HSLFPictureShape)ppt.getSlides().get(0).getShapes().get(0);
assertEquals("tomcat.png", p.getPictureName());
}
}

View File

@ -19,10 +19,12 @@
package org.apache.poi.hslf.usermodel;
import junit.framework.TestCase;
import static org.junit.Assert.*;
import java.util.List;
import org.apache.poi.hslf.model.Table;
import org.apache.poi.POIDataSamples;
import org.junit.Test;
/**
@ -30,40 +32,39 @@ import org.apache.poi.POIDataSamples;
*
* @author Alex Nikiforov [mailto:anikif@gmail.com]
*/
public final class TestTable extends TestCase {
public class TestTable {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
protected void setUp() throws Exception {
}
public void testTable() throws Exception {
@Test
public void testTable() throws Exception {
HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("54111.ppt"));
assertTrue("No Exceptions while reading file", true);
final HSLFSlide[] slides = ppt.getSlides();
assertEquals(1, slides.length);
checkSlide(slides[0]);
List<HSLFSlide> slides = ppt.getSlides();
assertEquals(1, slides.size());
checkSlide(slides.get(0));
}
private void checkSlide(final HSLFSlide s) {
HSLFTextParagraph[] textRuns = s.getTextParagraphs();
assertEquals(2, textRuns.length);
List<List<HSLFTextParagraph>> textRuns = s.getTextParagraphs();
assertEquals(2, textRuns.size());
HSLFTextRun textRun = textRuns[0].getTextRuns()[0];
HSLFTextRun textRun = textRuns.get(0).get(0).getTextRuns().get(0);
assertEquals("Table sample", textRun.getRawText().trim());
assertEquals(1, textRuns[0].getTextRuns().length);
assertFalse(textRun.isBullet());
assertEquals(1, textRuns.get(0).get(0).getTextRuns().size());
assertFalse(textRun.getTextParagraph().isBullet());
assertEquals("Dummy text", textRuns[1].getRawText());
assertEquals("Dummy text", HSLFTextParagraph.getRawText(textRuns.get(1)));
final HSLFShape[] shapes = s.getShapes();
List<HSLFShape> shapes = s.getShapes();
assertNotNull(shapes);
assertEquals(3, shapes.length);
assertTrue(shapes[2] instanceof Table);
final Table table = (Table) shapes[2];
assertEquals(3, shapes.size());
assertTrue(shapes.get(2) instanceof HSLFTable);
final HSLFTable table = (HSLFTable) shapes.get(2);
assertEquals(4, table.getNumberOfColumns());
assertEquals(6, table.getNumberOfRows());
for (int x = 0; x < 4; x ++) {
assertEquals("TH Cell " + (x + 1), table.getCell(0, x).getTextParagraphs().getRawText());
assertEquals("TH Cell " + (x + 1), HSLFTextParagraph.getRawText(table.getCell(0, x).getTextParagraphs()));
for (int y = 1; y < 6; y++) {
assertEquals("Row " + y + ", Cell " + (x + 1), table.getCell(y, x).getText());
}

View File

@ -19,10 +19,12 @@ package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.*;
import java.io.IOException;
import java.awt.Color;
import java.io.*;
import java.util.List;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.*;
import org.junit.Before;
import org.junit.Test;
@ -99,7 +101,7 @@ public final class TestTextRun {
// Ensure trailing \n's are NOT stripped, it is legal to set a text with a trailing '\r'
tr.setText(changeTo + "\n");
assertEquals(changeTo + "\n", tr.getRawText());
assertEquals(changeTo + "\r", tr.getRawText());
}
/**
@ -121,7 +123,6 @@ public final class TestTextRun {
else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r;
else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r;
}
// Bytes -> Bytes
assertNull(tca);
@ -197,18 +198,13 @@ public final class TestTextRun {
List<HSLFTextParagraph> trB = textParass.get(1);
assertEquals(1, trA.size());
assertEquals(1, trB.size());
assertEquals(2, trB.size());
HSLFTextRun rtrA = trA.get(0).getTextRuns().get(0);
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
assertEquals(HSLFTextParagraph.getRawText(trA), rtrA.getRawText());
assertEquals(HSLFTextParagraph.getRawText(trB), rtrB.getRawText());
// assertNull(rtrA._getRawCharacterStyle());
// assertNull(rtrA._getRawParagraphStyle());
// assertNull(rtrB._getRawCharacterStyle());
// assertNull(rtrB._getRawParagraphStyle());
assertEquals(HSLFTextParagraph.getRawText(trB.subList(0, 1)), rtrB.getRawText());
}
/**
@ -284,39 +280,39 @@ public final class TestTextRun {
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
HSLFTextRun rtrC = trB.get(1).getTextRuns().get(0);
HSLFTextRun rtrD = trB.get(2).getTextRuns().get(0);
// TextPropCollection tpBP = rtrB._getRawParagraphStyle();
// TextPropCollection tpBC = rtrB._getRawCharacterStyle();
// TextPropCollection tpCP = rtrC._getRawParagraphStyle();
// TextPropCollection tpCC = rtrC._getRawCharacterStyle();
// TextPropCollection tpDP = rtrD._getRawParagraphStyle();
// TextPropCollection tpDC = rtrD._getRawCharacterStyle();
TextPropCollection tpBP = rtrB.getTextParagraph().getParagraphStyle();
TextPropCollection tpBC = rtrB.getCharacterStyle();
TextPropCollection tpCP = rtrC.getTextParagraph().getParagraphStyle();
TextPropCollection tpCC = rtrC.getCharacterStyle();
TextPropCollection tpDP = rtrD.getTextParagraph().getParagraphStyle();
TextPropCollection tpDC = rtrD.getCharacterStyle();
// assertEquals(trB.getRawText().substring(0, 30), rtrB.getRawText());
// assertNotNull(tpBP);
// assertNotNull(tpBC);
// assertNotNull(tpCP);
// assertNotNull(tpCC);
// assertNotNull(tpDP);
// assertNotNull(tpDC);
// assertTrue(tpBP.equals(tpCP));
// assertTrue(tpBP.equals(tpDP));
// assertTrue(tpCP.equals(tpDP));
// assertFalse(tpBC.equals(tpCC));
// assertFalse(tpBC.equals(tpDC));
// assertFalse(tpCC.equals(tpDC));
assertNotNull(tpBP);
assertNotNull(tpBC);
assertNotNull(tpCP);
assertNotNull(tpCC);
assertNotNull(tpDP);
assertNotNull(tpDC);
assertEquals(tpBP,tpCP);
assertEquals(tpBP,tpDP);
assertEquals(tpCP,tpDP);
assertNotEquals(tpBC,tpCC);
assertNotEquals(tpBC,tpDC);
assertNotEquals(tpCC,tpDC);
// Change text via normal
// trB.setText("Test Foo Test");
HSLFTextParagraph.setText(trB, "Test Foo Test");
// Ensure now have first style
// assertEquals(1, trB.getTextRuns().length);
// rtrB = trB.getTextRuns().get(0);
// assertEquals("Test Foo Test", trB.getRawText());
// assertEquals("Test Foo Test", rtrB.getRawText());
// assertNotNull(rtrB._getRawCharacterStyle());
// assertNotNull(rtrB._getRawParagraphStyle());
// assertEquals( tpBP, rtrB._getRawParagraphStyle() );
// assertEquals( tpBC, rtrB._getRawCharacterStyle() );
assertEquals(1, trB.get(0).getTextRuns().size());
rtrB = trB.get(0).getTextRuns().get(0);
assertEquals("Test Foo Test", HSLFTextParagraph.getRawText(trB));
assertEquals("Test Foo Test", rtrB.getRawText());
assertNotNull(rtrB.getCharacterStyle());
assertNotNull(rtrB.getTextParagraph().getParagraphStyle());
assertEquals( tpBP, rtrB.getTextParagraph().getParagraphStyle() );
assertEquals( tpBC, rtrB.getCharacterStyle() );
}
/**
@ -328,21 +324,21 @@ public final class TestTextRun {
HSLFSlide slideOne = ss.getSlides().get(0);
List<List<HSLFTextParagraph>> textRuns = slideOne.getTextParagraphs();
List<HSLFTextParagraph> trB = textRuns.get(1);
// assertEquals(1, trB.getTextRuns().length);
//
// HSLFTextRun rtrB = trB.getTextRuns().get(0);
// assertEquals(trB.getRawText(), rtrB.getRawText());
// assertNull(rtrB._getRawCharacterStyle());
// assertNull(rtrB._getRawParagraphStyle());
assertEquals(1, trB.get(0).getTextRuns().size());
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
assertEquals(HSLFTextParagraph.getRawText(trB.subList(0, 1)), rtrB.getRawText());
assertNotNull(rtrB.getCharacterStyle());
assertNotNull(rtrB.getTextParagraph().getParagraphStyle());
// Change text via rich
// rtrB.setText("Test Test Test");
// assertEquals("Test Test Test", trB.getRawText());
// assertEquals("Test Test Test", rtrB.getRawText());
rtrB.setText("Test Test Test");
assertEquals("Test Test Test", HSLFTextParagraph.getRawText(trB.subList(0, 1)));
assertEquals("Test Test Test", rtrB.getRawText());
// Will now have dummy props
// assertNotNull(rtrB._getRawCharacterStyle());
// assertNotNull(rtrB._getRawParagraphStyle());
assertNotNull(rtrB.getCharacterStyle());
assertNotNull(rtrB.getTextParagraph().getParagraphStyle());
}
/**
@ -357,31 +353,31 @@ public final class TestTextRun {
assertEquals(3, trB.size());
// We start with 3 text runs, each with their own set of styles,
// but all sharing the same paragraph styles
// but all sharing the same paragraph styles
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
HSLFTextRun rtrC = trB.get(1).getTextRuns().get(0);
HSLFTextRun rtrD = trB.get(2).getTextRuns().get(0);
// TextPropCollection tpBP = rtrB._getRawParagraphStyle();
// TextPropCollection tpBC = rtrB._getRawCharacterStyle();
// TextPropCollection tpCP = rtrC._getRawParagraphStyle();
// TextPropCollection tpCC = rtrC._getRawCharacterStyle();
// TextPropCollection tpDP = rtrD._getRawParagraphStyle();
// TextPropCollection tpDC = rtrD._getRawCharacterStyle();
TextPropCollection tpBP = rtrB.getTextParagraph().getParagraphStyle();
TextPropCollection tpBC = rtrB.getCharacterStyle();
TextPropCollection tpCP = rtrC.getTextParagraph().getParagraphStyle();
TextPropCollection tpCC = rtrC.getCharacterStyle();
TextPropCollection tpDP = rtrD.getTextParagraph().getParagraphStyle();
TextPropCollection tpDC = rtrD.getCharacterStyle();
// Check text and stylings
// assertEquals(trB.getRawText().substring(0, 30), rtrB.getRawText());
// assertNotNull(tpBP);
// assertNotNull(tpBC);
// assertNotNull(tpCP);
// assertNotNull(tpCC);
// assertNotNull(tpDP);
// assertNotNull(tpDC);
// assertTrue(tpBP.equals(tpCP));
// assertTrue(tpBP.equals(tpDP));
// assertTrue(tpCP.equals(tpDP));
// assertFalse(tpBC.equals(tpCC));
// assertFalse(tpBC.equals(tpDC));
// assertFalse(tpCC.equals(tpDC));
assertEquals(HSLFTextParagraph.getRawText(trB).substring(0, 30), rtrB.getRawText());
assertNotNull(tpBP);
assertNotNull(tpBC);
assertNotNull(tpCP);
assertNotNull(tpCC);
assertNotNull(tpDP);
assertNotNull(tpDC);
assertEquals(tpBP, tpCP);
assertEquals(tpBP, tpDP);
assertEquals(tpCP, tpDP);
assertNotEquals(tpBC, tpCC);
assertNotEquals(tpBC, tpDC);
assertNotEquals(tpCC, tpDC);
// Check text in the rich runs
assertEquals("This is the subtitle, in bold\r", rtrB.getRawText());
@ -394,32 +390,32 @@ public final class TestTextRun {
rtrB.setText(newBText);
rtrC.setText(newCText);
rtrD.setText(newDText);
assertEquals(newBText, rtrB.getRawText());
assertEquals(newCText, rtrC.getRawText());
assertEquals(newDText, rtrD.getRawText());
HSLFTextParagraph.storeText(trB);
// assertEquals(newBText + newCText + newDText, trB.getRawText());
assertEquals(newBText.replace('\n','\r'), rtrB.getRawText());
assertEquals(newCText.replace('\n','\r'), rtrC.getRawText());
assertEquals(newDText.replace('\n','\r'), rtrD.getRawText());
assertEquals(newBText.replace('\n','\r') + newCText.replace('\n','\r') + newDText.replace('\n','\r'), HSLFTextParagraph.getRawText(trB));
// The styles should have been updated for the new sizes
// assertEquals(newBText.length(), tpBC.getCharactersCovered());
// assertEquals(newCText.length(), tpCC.getCharactersCovered());
// assertEquals(newDText.length()+1, tpDC.getCharactersCovered()); // Last one is always one larger
assertEquals(newBText.length(), tpBC.getCharactersCovered());
assertEquals(newCText.length(), tpCC.getCharactersCovered());
assertEquals(newDText.length()+1, tpDC.getCharactersCovered()); // Last one is always one larger
// assertEquals(
// newBText.length() + newCText.length() + newDText.length(),
// tpBP.getCharactersCovered()
// );
// Paragraph style should be sum of text length
// assertEquals(newBText.length() + newCText.length() + newDText.length(), tpBP.getCharactersCovered());
// Paragraph style should be sum of text length
assertEquals(
newBText.length() + newCText.length() + newDText.length() +1,
tpBP.getCharactersCovered() + tpCP.getCharactersCovered() + tpDP.getCharactersCovered()
);
// Check stylings still as expected
// TextPropCollection ntpBC = rtrB._getRawCharacterStyle();
// TextPropCollection ntpCC = rtrC._getRawCharacterStyle();
// TextPropCollection ntpDC = rtrD._getRawCharacterStyle();
// assertEquals(tpBC.getTextPropList(), ntpBC.getTextPropList());
// assertEquals(tpCC.getTextPropList(), ntpCC.getTextPropList());
// assertEquals(tpDC.getTextPropList(), ntpDC.getTextPropList());
TextPropCollection ntpBC = rtrB.getCharacterStyle();
TextPropCollection ntpCC = rtrC.getCharacterStyle();
TextPropCollection ntpDC = rtrD.getCharacterStyle();
assertEquals(tpBC.getTextPropList(), ntpBC.getTextPropList());
assertEquals(tpCC.getTextPropList(), ntpCC.getTextPropList());
assertEquals(tpDC.getTextPropList(), ntpDC.getTextPropList());
}
@ -467,82 +463,86 @@ public final class TestTextRun {
assertEquals(0, slide.getTextParagraphs().size());
HSLFTextBox shape1 = new HSLFTextBox();
// HSLFTextParagraph run1 = shape1.getTextParagraphs();
// assertSame(run1, shape1.createTextRun());
// run1.setText("Text 1");
List<HSLFTextParagraph> run1 = shape1.getTextParagraphs();
shape1.setText("Text 1");
slide.addShape(shape1);
//The array of Slide's text runs must be updated when new text shapes are added.
// HSLFTextParagraph[] runs = slide.getTextParagraphs();
// assertNotNull(runs);
// assertSame(run1, runs.get(0));
//
// HSLFTextBox shape2 = new HSLFTextBox();
// HSLFTextParagraph run2 = shape2.getTextParagraphs();
// assertSame(run2, shape2.createTextRun());
// run2.setText("Text 2");
// slide.addShape(shape2);
//
// runs = slide.getTextParagraphs();
// assertEquals(2, runs.length);
//
// assertSame(run1, runs.get(0));
// assertSame(run2, runs.get(1));
//
// //as getShapes()
// HSLFShape[] sh = slide.getShapes();
// assertEquals(2, sh.length);
// assertTrue(sh.get(0) instanceof HSLFTextBox);
// HSLFTextBox box1 = (HSLFTextBox)sh.get(0);
// assertSame(run1, box1.getTextParagraphs());
// HSLFTextBox box2 = (HSLFTextBox)sh.get(1);
// assertSame(run2, box2.getTextParagraphs());
//
// //test Table - a complex group of shapes containing text objects
// HSLFSlide slide2 = ppt.createSlide();
// assertNull(slide2.getTextParagraphs());
// Table table = new Table(2, 2);
// slide2.addShape(table);
// runs = slide2.getTextParagraphs();
// assertNotNull(runs);
// assertEquals(4, runs.length);
List<List<HSLFTextParagraph>> runs = slide.getTextParagraphs();
assertNotNull(runs);
assertSame(run1, runs.get(0));
HSLFTextBox shape2 = new HSLFTextBox();
List<HSLFTextParagraph> run2 = shape2.getTextParagraphs();
shape2.setText("Text 2");
slide.addShape(shape2);
runs = slide.getTextParagraphs();
assertEquals(2, runs.size());
assertSame(run1, runs.get(0));
assertSame(run2, runs.get(1));
// as getShapes()
List<HSLFShape> sh = slide.getShapes();
assertEquals(2, sh.size());
assertTrue(sh.get(0) instanceof HSLFTextBox);
HSLFTextBox box1 = (HSLFTextBox)sh.get(0);
assertSame(run1, box1.getTextParagraphs());
HSLFTextBox box2 = (HSLFTextBox)sh.get(1);
assertSame(run2, box2.getTextParagraphs());
// test Table - a complex group of shapes containing text objects
HSLFSlide slide2 = ppt.createSlide();
assertTrue(slide2.getTextParagraphs().isEmpty());
HSLFTable table = new HSLFTable(2, 2);
slide2.addShape(table);
runs = slide2.getTextParagraphs();
assertNotNull(runs);
assertEquals(4, runs.size());
}
@Test
public void test48916() throws IOException {
// HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("SampleShow.ppt"));
// for(HSLFSlide slide : ppt.getSlides()){
// for(HSLFShape sh : slide.getShapes()){
// if(sh instanceof HSLFTextShape){
// HSLFTextShape tx = (HSLFTextShape)sh;
// HSLFTextParagraph run = tx.getTextParagraphs();
// //verify that records cached in TextRun and EscherTextboxWrapper are the same
// Record[] runChildren = run.getRecords();
// Record[] txboxChildren = tx.getEscherTextboxWrapper().getChildRecords();
// assertEquals(runChildren.length, txboxChildren.length);
// for(int i=0; i < txboxChildren.length; i++){
// assertSame(txboxChildren.get(i), runChildren.get(i));
// }
// //caused NPE prior to fix of Bugzilla #48916
// run.getTextRuns().get(0).setBold(true);
// run.getTextRuns().get(0).setFontColor(Color.RED);
// }
// }
// }
// ByteArrayOutputStream out = new ByteArrayOutputStream();
// ppt.write(out);
// ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()));
// for(HSLFSlide slide : ppt.getSlides()){
// for(HSLFShape sh : slide.getShapes()){
// if(sh instanceof HSLFTextShape){
// HSLFTextShape tx = (HSLFTextShape)sh;
// HSLFTextParagraph run = tx.getTextParagraphs();
// HSLFTextRun rt = run.getTextRuns().get(0);
// assertTrue(rt.isBold());
// assertEquals(rt.getFontColor(), Color.RED);
// }
// }
// }
HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("SampleShow.ppt"));
List<HSLFSlide> slides = ppt.getSlides();
for(HSLFSlide slide : slides){
for(HSLFShape sh : slide.getShapes()){
if (!(sh instanceof HSLFTextShape)) continue;
HSLFTextShape tx = (HSLFTextShape)sh;
List<HSLFTextParagraph> paras = tx.getTextParagraphs();
//verify that records cached in TextRun and EscherTextboxWrapper are the same
Record[] runChildren = paras.get(0).getRecords();
Record[] txboxChildren = tx.getEscherTextboxWrapper().getChildRecords();
assertEquals(runChildren.length, txboxChildren.length);
for(int i=0; i < txboxChildren.length; i++){
assertSame(txboxChildren[i], runChildren[i]);
}
// caused NPE prior to fix of Bugzilla #48916
for (HSLFTextParagraph p : paras) {
for (HSLFTextRun rt : p.getTextRuns()) {
rt.setBold(true);
rt.setFontColor(Color.RED);
}
}
tx.storeText();
}
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
ppt.write(out);
ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()));
for(HSLFSlide slide : ppt.getSlides()){
for(HSLFShape sh : slide.getShapes()){
if(sh instanceof HSLFTextShape){
HSLFTextShape tx = (HSLFTextShape)sh;
List<HSLFTextParagraph> run = tx.getTextParagraphs();
HSLFTextRun rt = run.get(0).getTextRuns().get(0);
assertTrue(rt.isBold());
assertEquals(rt.getFontColor(), Color.RED);
}
}
}
}

Binary file not shown.

Binary file not shown.