Test and fix for bug #46441

Use generics on Shape.getEscherChild() and SimpleShape.getClientDataRecord() to minimize casting
Unify access to Shape.getEscherOptRecord()

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1649152 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-01-02 22:57:05 +00:00
parent a361a16899
commit 460678e607
19 changed files with 639 additions and 241 deletions

View File

@ -17,8 +17,11 @@
package org.apache.poi.ddf;
import org.apache.poi.util.LittleEndian;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
/**
* Escher array properties are the most wierd construction ever invented
@ -26,7 +29,7 @@ import org.apache.poi.util.HexDump;
*
* @author Glen Stampoultzis (glens at superlinksoftware.com)
*/
public final class EscherArrayProperty extends EscherComplexProperty {
public final class EscherArrayProperty extends EscherComplexProperty implements Iterable<byte[]> {
/**
* The size of the header that goes at the
* start of the array, before the data
@ -205,4 +208,24 @@ public final class EscherArrayProperty extends EscherComplexProperty {
}
return sizeOfElements;
}
public Iterator<byte[]> iterator() {
return new Iterator<byte[]>(){
int idx = 0;
public boolean hasNext() {
return (idx < getNumberOfElementsInArray());
}
public byte[] next() {
if (!hasNext()) throw new NoSuchElementException();
return getElement(idx++);
}
public void remove() {
throw new UnsupportedOperationException("not yet implemented");
}
};
}
}

View File

@ -0,0 +1,283 @@
/* ====================================================================
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.ddf;
import org.apache.poi.util.BitField;
import org.apache.poi.util.LittleEndian;
/**
* An OfficeArtCOLORREF structure entry which also handles color extension opid data
*/
public class EscherColorRef {
int opid = -1;
int colorRef = 0;
public enum SysIndexSource {
/** Use the fill color of the shape. */
FILL_COLOR(0xF0),
/** If the shape contains a line, use the line color of the shape. Otherwise, use the fill color. */
LINE_OR_FILL_COLOR(0xF1),
/** Use the line color of the shape. */
LINE_COLOR(0xF2),
/** Use the shadow color of the shape. */
SHADOW_COLOR(0xF3),
/** Use the current, or last-used, color. */
CURRENT_OR_LAST_COLOR(0xF4),
/** Use the fill background color of the shape. */
FILL_BACKGROUND_COLOR(0xF5),
/** Use the line background color of the shape. */
LINE_BACKGROUND_COLOR(0xF6),
/** If the shape contains a fill, use the fill color of the shape. Otherwise, use the line color. */
FILL_OR_LINE_COLOR(0xF7)
;
int value;
SysIndexSource(int value) { this.value = value; }
}
/**
* The following enum specifies values that indicate special procedural properties that
* are used to modify the color components of another color. These values are combined with
* those of the {@link SysIndexSource} enum or with a user-specified color.
* The first six values are mutually exclusive.
*/
public enum SysIndexProcedure {
/**
* Darken the color by the value that is specified in the blue field.
* A blue value of 0xFF specifies that the color is to be left unchanged,
* whereas a blue value of 0x00 specifies that the color is to be completely darkened.
*/
DARKEN_COLOR(0x01),
/**
* Lighten the color by the value that is specified in the blue field.
* A blue value of 0xFF specifies that the color is to be left unchanged,
* whereas a blue value of 0x00 specifies that the color is to be completely lightened.
*/
LIGHTEN_COLOR(0x02),
/**
* Add a gray level RGB value. The blue field contains the gray level to add:
* NewColor = SourceColor + gray
*/
ADD_GRAY_LEVEL(0x03),
/**
* Subtract a gray level RGB value. The blue field contains the gray level to subtract:
* NewColor = SourceColor - gray
*/
SUB_GRAY_LEVEL(0x04),
/**
* Reverse-subtract a gray level RGB value. The blue field contains the gray level from
* which to subtract:
* NewColor = gray - SourceColor
*/
REVERSE_GRAY_LEVEL(0x05),
/**
* If the color component being modified is less than the parameter contained in the blue
* field, set it to the minimum intensity. If the color component being modified is greater
* than or equal to the parameter, set it to the maximum intensity.
*/
THRESHOLD(0x06),
/**
* After making other modifications, invert the color.
* This enum value is only for documentation and won't be directly returned.
*/
INVERT_AFTER(0x20),
/**
* After making other modifications, invert the color by toggling just the high bit of each
* color channel.
* This enum value is only for documentation and won't be directly returned.
*/
INVERT_HIGHBIT_AFTER(0x40)
;
BitField mask;
SysIndexProcedure(int mask) {
this.mask = new BitField(mask);
}
}
/**
* A bit that specifies whether the system color scheme will be used to determine the color.
* A value of 0x1 specifies that green and red will be treated as an unsigned 16-bit index
* into the system color table. Values less than 0x00F0 map directly to system colors.
*/
private static final BitField FLAG_SYS_INDEX = new BitField(0x10000000);
/**
* A bit that specifies whether the current application-defined color scheme will be used
* to determine the color. A value of 0x1 specifies that red will be treated as an index
* into the current color scheme table. If this value is 0x1, green and blue MUST be 0x00.
*/
private static final BitField FLAG_SCHEME_INDEX = new BitField(0x08000000);
/**
* A bit that specifies whether the color is a standard RGB color.
* 0x0 : The RGB color MAY use halftone dithering to display.
* 0x1 : The color MUST be a solid color.
*/
private static final BitField FLAG_SYSTEM_RGB = new BitField(0x04000000);
/**
* A bit that specifies whether the current palette will be used to determine the color.
* A value of 0x1 specifies that red, green, and blue contain an RGB value that will be
* matched in the current color palette. This color MUST be solid.
*/
private static final BitField FLAG_PALETTE_RGB = new BitField(0x02000000);
/**
* A bit that specifies whether the current palette will be used to determine the color.
* A value of 0x1 specifies that green and red will be treated as an unsigned 16-bit index into
* the current color palette. This color MAY be dithered. If this value is 0x1, blue MUST be 0x00.
*/
private static final BitField FLAG_PALETTE_INDEX = new BitField(0x01000000);
/**
* An unsigned integer that specifies the intensity of the blue color channel. A value
* of 0x00 has the minimum blue intensity. A value of 0xFF has the maximum blue intensity.
*/
private static final BitField FLAG_BLUE = new BitField(0x00FF0000);
/**
* An unsigned integer that specifies the intensity of the green color channel. A value
* of 0x00 has the minimum green intensity. A value of 0xFF has the maximum green intensity.
*/
private static final BitField FLAG_GREEN = new BitField(0x0000FF00);
/**
* An unsigned integer that specifies the intensity of the red color channel. A value
* of 0x00 has the minimum red intensity. A value of 0xFF has the maximum red intensity.
*/
private static final BitField FLAG_RED = new BitField(0x000000FF);
public EscherColorRef(int colorRef) {
this.colorRef = colorRef;
}
public EscherColorRef(byte[] source, int start, int len) {
assert(len == 4 || len == 6);
int offset = start;
if (len == 6) {
opid = LittleEndian.getUShort(source, offset);
offset += 2;
}
colorRef = LittleEndian.getInt(source, offset);
}
public boolean hasSysIndexFlag() {
return FLAG_SYS_INDEX.isSet(colorRef);
}
public void setSysIndexFlag(boolean flag) {
FLAG_SYS_INDEX.setBoolean(colorRef, flag);
}
public boolean hasSchemeIndexFlag() {
return FLAG_SCHEME_INDEX.isSet(colorRef);
}
public void setSchemeIndexFlag(boolean flag) {
FLAG_SCHEME_INDEX.setBoolean(colorRef, flag);
}
public boolean hasSystemRGBFlag() {
return FLAG_SYSTEM_RGB.isSet(colorRef);
}
public void setSystemRGBFlag(boolean flag) {
FLAG_SYSTEM_RGB.setBoolean(colorRef, flag);
}
public boolean hasPaletteRGBFlag() {
return FLAG_PALETTE_RGB.isSet(colorRef);
}
public void setPaletteRGBFlag(boolean flag) {
FLAG_PALETTE_RGB.setBoolean(colorRef, flag);
}
public boolean hasPaletteIndexFlag() {
return FLAG_PALETTE_INDEX.isSet(colorRef);
}
public void setPaletteIndexFlag(boolean flag) {
FLAG_PALETTE_INDEX.setBoolean(colorRef, flag);
}
public int[] getRGB() {
int rgb[] = {
FLAG_RED.getValue(colorRef),
FLAG_GREEN.getValue(colorRef),
FLAG_BLUE.getValue(colorRef)
};
return rgb;
}
/**
* @return {@link SysIndexSource} if {@link #hasSysIndexFlag()} is {@code true}, otherwise null
*/
public SysIndexSource getSysIndexSource() {
if (!hasSysIndexFlag()) return null;
int val = FLAG_RED.getValue(colorRef);
for (SysIndexSource sis : SysIndexSource.values()) {
if (sis.value == val) return sis;
}
return null;
}
/**
* Return the {@link SysIndexProcedure} - for invert flag use {@link #getSysIndexInvert()}
* @return {@link SysIndexProcedure} if {@link #hasSysIndexFlag()} is {@code true}, otherwise null
*/
public SysIndexProcedure getSysIndexProcedure() {
if (!hasSysIndexFlag()) return null;
int val = FLAG_RED.getValue(colorRef);
for (SysIndexProcedure sip : SysIndexProcedure.values()) {
if (sip == SysIndexProcedure.INVERT_AFTER || sip == SysIndexProcedure.INVERT_HIGHBIT_AFTER) continue;
if (sip.mask.isSet(val)) return sip;
}
return null;
}
/**
* @return 0 for no invert flag, 1 for {@link SysIndexProcedure#INVERT_AFTER} and
* 2 for {@link SysIndexProcedure#INVERT_HIGHBIT_AFTER}
*/
public int getSysIndexInvert() {
if (!hasSysIndexFlag()) return 0;
int val = FLAG_GREEN.getValue(colorRef);
if ((SysIndexProcedure.INVERT_AFTER.mask.isSet(val))) return 1;
if ((SysIndexProcedure.INVERT_HIGHBIT_AFTER.mask.isSet(val))) return 2;
return 0;
}
/**
* @return index of the scheme color or -1 if {@link #hasSchemeIndexFlag()} is {@code false}
*
* @see org.apache.poi.hslf.record.ColorSchemeAtom#getColor(int)
*/
public int getSchemeIndex() {
if (!hasSchemeIndexFlag()) return -1;
return FLAG_RED.getValue(colorRef);
}
/**
* @return index of current palette (color) or -1 if {@link #hasPaletteIndexFlag()} is {@code false}
*/
public int getPaletteIndex() {
if (!hasPaletteIndexFlag()) return -1;
return (FLAG_GREEN.getValue(colorRef) << 8) & FLAG_RED.getValue(colorRef);
}
}

View File

@ -40,4 +40,19 @@ public class Units {
public static double toPoints(long emu){
return (double)emu/EMU_PER_POINT;
}
/**
* Converts a value of type FixedPoint to a decimal number
*
* @param fixedPoint
* @return decimal number
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd910765(v=office.12).aspx">[MS-OSHARED] - 2.2.1.6 FixedPoint</a>
*/
public static double fixedPointToDecimal(int fixedPoint) {
int i = (fixedPoint >> 16);
int f = (fixedPoint >> 0) & 0xFFFF;
double decimal = (i + f/65536.0);
return decimal;
}
}

View File

@ -123,7 +123,7 @@ public final class ActiveXShape extends Picture {
public int getControlIndex(){
int idx = -1;
OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
if(oe != null) idx = oe.getOptions();
return idx;
}

View File

@ -17,15 +17,20 @@
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import java.awt.Color;
import java.util.List;
import java.awt.*;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
@ -112,16 +117,16 @@ public final class Fill {
* @return type of fill
*/
public int getFillType(){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__FILLTYPE);
EscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty prop = Shape.getEscherProperty(opt, EscherProperties.FILL__FILLTYPE);
return prop == null ? FILL_SOLID : prop.getPropertyValue();
}
/**
*/
protected void afterInsert(Sheet sh){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
EscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
if(p != null) {
int idx = p.getPropertyValue();
EscherBSERecord bse = getEscherBSERecord(idx);
@ -138,12 +143,12 @@ public final class Fill {
SlideShow ppt = sheet.getSlideShow();
Document doc = ppt.getDocumentRecord();
EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
if(bstore == null) {
logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found ");
return null;
}
List lst = bstore.getChildRecords();
List<EscherRecord> lst = bstore.getChildRecords();
return (EscherBSERecord)lst.get(idx-1);
}
@ -154,7 +159,7 @@ public final class Fill {
* @param type type of the fill
*/
public void setFillType(int type){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherOptRecord opt = shape.getEscherOptRecord();
Shape.setEscherProperty(opt, EscherProperties.FILL__FILLTYPE, type);
}
@ -162,8 +167,8 @@ public final class Fill {
* Foreground color
*/
public Color getForegroundColor(){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
EscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
if(p != null && (p.getPropertyValue() & 0x10) == 0) return null;
@ -175,7 +180,7 @@ public final class Fill {
* Foreground color
*/
public void setForegroundColor(Color color){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherOptRecord opt = shape.getEscherOptRecord();
if (color == null) {
Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150000);
}
@ -190,8 +195,8 @@ public final class Fill {
* Background color
*/
public Color getBackgroundColor(){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
EscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
if(p != null && (p.getPropertyValue() & 0x10) == 0) return null;
@ -202,7 +207,7 @@ public final class Fill {
* Background color
*/
public void setBackgroundColor(Color color){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherOptRecord opt = shape.getEscherOptRecord();
if (color == null) {
Shape.setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, -1);
}
@ -216,8 +221,8 @@ public final class Fill {
* <code>PictureData</code> object used in a texture, pattern of picture fill.
*/
public PictureData getPictureData(){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
EscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
if (p == null) return null;
SlideShow ppt = shape.getSheet().getSlideShow();
@ -225,7 +230,7 @@ public final class Fill {
Document doc = ppt.getDocumentRecord();
EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
java.util.List<EscherRecord> lst = bstore.getChildRecords();
int idx = p.getPropertyValue();
@ -249,7 +254,7 @@ public final class Fill {
* @param idx 0-based index of the picture added to this ppt by <code>SlideShow.addPicture</code> method.
*/
public void setPictureData(int idx){
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherOptRecord opt = shape.getEscherOptRecord();
Shape.setEscherProperty(opt, (short)(EscherProperties.FILL__PATTERNTEXTURE + 0x4000), idx);
if( idx != 0 ) {
if( shape.getSheet() != null ) {

View File

@ -179,11 +179,11 @@ public final class Freeform extends AutoShape {
EscherOptRecord opt = getEscherOptRecord();
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4));
EscherArrayProperty verticesProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000));
if(verticesProp == null) verticesProp = (EscherArrayProperty)getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
EscherArrayProperty verticesProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000));
if(verticesProp == null) verticesProp = getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
EscherArrayProperty segmentsProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000));
if(segmentsProp == null) segmentsProp = (EscherArrayProperty)getEscherProperty(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
EscherArrayProperty segmentsProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000));
if(segmentsProp == null) segmentsProp = getEscherProperty(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
//sanity check
if(verticesProp == null) {

View File

@ -116,10 +116,10 @@ public final class MovieShape extends Picture {
* @param idx the index of the movie
*/
public void setMovieIndex(int idx){
OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
oe.setOptions(idx);
AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null) {
AnimationInfoAtom ai = an.getAnimationInfoAtom();
ai.setDimColor(0x07000000);
@ -131,7 +131,7 @@ public final class MovieShape extends Picture {
}
public void setAutoPlay(boolean flag){
AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null){
an.getAnimationInfoAtom().setFlag(AnimationInfoAtom.Automatic, flag);
updateClientData();
@ -139,7 +139,7 @@ public final class MovieShape extends Picture {
}
public boolean isAutoPlay(){
AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
if(an != null){
return an.getAnimationInfoAtom().getFlag(AnimationInfoAtom.Automatic);
}
@ -150,7 +150,7 @@ public final class MovieShape extends Picture {
* @return UNC or local path to a video file
*/
public String getPath(){
OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
int idx = oe.getOptions();
SlideShow ppt = getSheet().getSlideShow();

View File

@ -41,6 +41,7 @@ import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil;
import org.apache.poi.util.Units;
/**
@ -120,7 +121,7 @@ public class Picture extends SimpleShape {
*/
public int getPictureIndex(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY);
return prop == null ? 0 : prop.getPropertyValue();
}
@ -202,7 +203,7 @@ public class Picture extends SimpleShape {
SlideShow ppt = getSheet().getSlideShow();
Document doc = ppt.getDocumentRecord();
EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
if(bstore == null) {
logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found ");
return null;
@ -223,7 +224,7 @@ public class Picture extends SimpleShape {
*/
public String getPictureName(){
EscherOptRecord opt = getEscherOptRecord();
EscherComplexProperty prop = (EscherComplexProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME);
EscherComplexProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME);
if (prop == null) return null;
String name = StringUtil.getFromUnicodeLE(prop.getComplexData());
return name.trim();
@ -289,16 +290,11 @@ public class Picture extends SimpleShape {
/**
* @return the fractional property or 0 if not defined
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd910765(v=office.12).aspx">2.2.1.6 FixedPoint</a>
*/
private static double getFractProp(EscherOptRecord opt, short propertyId) {
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propertyId);
EscherSimpleProperty prop = getEscherProperty(opt, propertyId);
if (prop == null) return 0;
int fixedPoint = prop.getPropertyValue();
int i = (fixedPoint >> 16);
int f = (fixedPoint >> 0) & 0xFFFF;
double fp = i + f/65536.0;
return fp;
return Units.fixedPointToDecimal(fixedPoint);
}
}

View File

@ -21,6 +21,7 @@ import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.Units;
import java.util.*;
import java.awt.*;
@ -129,7 +130,7 @@ public abstract class Shape {
* @see org.apache.poi.hslf.record.RecordTypes
*/
public int getShapeType(){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
return spRecord.getShapeType();
}
@ -138,7 +139,7 @@ public abstract class Shape {
* @see org.apache.poi.hslf.record.RecordTypes
*/
public void setShapeType(int type){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
spRecord.setShapeType( (short) type );
spRecord.setVersion( (short) 0x2 );
}
@ -161,15 +162,15 @@ public abstract class Shape {
* @return the anchor of this shape
*/
public Rectangle2D getAnchor2D(){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
int flags = spRecord.getFlags();
Rectangle2D anchor=null;
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
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 = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
EscherClientAnchorRecord clrec = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle();
anchor = new Rectangle2D.Float(
(float)clrec.getCol1()*POINT_DPI/MASTER_DPI,
@ -187,7 +188,7 @@ public abstract class Shape {
}
}
else {
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
EscherClientAnchorRecord rec = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle();
anchor = new Rectangle2D.Float(
(float)rec.getCol1()*POINT_DPI/MASTER_DPI,
@ -210,17 +211,17 @@ public abstract class Shape {
* @param anchor new anchor
*/
public void setAnchor(Rectangle2D anchor){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
int flags = spRecord.getFlags();
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(EscherChildAnchorRecord.RECORD_ID);
rec.setDx1((int)(anchor.getX()*MASTER_DPI/POINT_DPI));
rec.setDy1((int)(anchor.getY()*MASTER_DPI/POINT_DPI));
rec.setDx2((int)((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI));
rec.setDy2((int)((anchor.getHeight() + anchor.getY())*MASTER_DPI/POINT_DPI));
}
else {
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(EscherClientAnchorRecord.RECORD_ID);
rec.setFlag((short)(anchor.getY()*MASTER_DPI/POINT_DPI));
rec.setCol1((short)(anchor.getX()*MASTER_DPI/POINT_DPI));
rec.setDx1((short)(((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI)));
@ -246,14 +247,12 @@ public abstract class Shape {
*
* @return escher record or <code>null</code> if not found.
*/
public static EscherRecord getEscherChild(EscherContainerRecord owner, int recordId){
for ( Iterator<EscherRecord> iterator = owner.getChildIterator(); iterator.hasNext(); )
{
EscherRecord escherRecord = iterator.next();
if (escherRecord.getRecordId() == recordId)
return escherRecord;
public static <T extends EscherRecord> T getEscherChild(EscherContainerRecord owner, int recordId){
return owner.getChildById((short)recordId);
}
return null;
public <T extends EscherRecord> T getEscherChild(int recordId){
return _escherContainer.getChildById((short)recordId);
}
/**
@ -261,14 +260,8 @@ public abstract class Shape {
*
* @return escher property or <code>null</code> if not found.
*/
public static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
if(opt != null) for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
{
EscherProperty prop = (EscherProperty) iterator.next();
if (prop.getPropertyNumber() == propId)
return prop;
}
return null;
public static <T extends EscherProperty> T getEscherProperty(EscherOptRecord opt, int propId){
return opt.lookup(propId);
}
/**
@ -279,11 +272,11 @@ public abstract class Shape {
* @param value value of the property. If value = -1 then the property is removed.
*/
public static void setEscherProperty(EscherOptRecord opt, short propId, int value){
java.util.List props = opt.getEscherProperties();
for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) {
EscherProperty prop = (EscherProperty) iterator.next();
if (prop.getId() == propId){
java.util.List<EscherProperty> props = opt.getEscherProperties();
for ( Iterator<EscherProperty> iterator = props.iterator(); iterator.hasNext(); ) {
if (iterator.next().getPropertyNumber() == propId){
iterator.remove();
break;
}
}
if (value != -1) {
@ -310,7 +303,7 @@ public abstract class Shape {
*/
public int getEscherProperty(short propId){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
EscherSimpleProperty prop = getEscherProperty(opt, propId);
return prop == null ? 0 : prop.getPropertyValue();
}
@ -321,7 +314,7 @@ public abstract class Shape {
*/
public int getEscherProperty(short propId, int defaultValue){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
EscherSimpleProperty prop = getEscherProperty(opt, propId);
return prop == null ? defaultValue : prop.getPropertyValue();
}
@ -365,32 +358,30 @@ public abstract class Shape {
Color getColor(short colorProperty, short opacityProperty, int defaultColor){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty p = (EscherSimpleProperty)getEscherProperty(opt, colorProperty);
EscherSimpleProperty p = getEscherProperty(opt, colorProperty);
if(p == null && defaultColor == -1) return null;
int val = p == null ? defaultColor : p.getPropertyValue();
int val = (p == null) ? defaultColor : p.getPropertyValue();
int a = (val >> 24) & 0xFF;
int b = (val >> 16) & 0xFF;
int g = (val >> 8) & 0xFF;
int r = (val >> 0) & 0xFF;
EscherColorRef ecr = new EscherColorRef(val);
boolean fPaletteIndex = (a & 1) != 0;
boolean fPaletteRGB = (a & (1 << 1)) != 0;
boolean fSystemRGB = (a & (1 << 2)) != 0;
boolean fSchemeIndex = (a & (1 << 3)) != 0;
boolean fSysIndex = (a & (1 << 4)) != 0;
boolean fPaletteIndex = ecr.hasPaletteIndexFlag();
boolean fPaletteRGB = ecr.hasPaletteRGBFlag();
boolean fSystemRGB = ecr.hasSystemRGBFlag();
boolean fSchemeIndex = ecr.hasSchemeIndexFlag();
boolean fSysIndex = ecr.hasSysIndexFlag();
int rgb[] = ecr.getRGB();
Sheet sheet = getSheet();
if (fSchemeIndex && sheet != null)
{
if (fSchemeIndex && sheet != null) {
//red is the index to the color scheme
ColorSchemeAtom ca = sheet.getColorScheme();
int schemeColor = ca.getColor(r);
int schemeColor = ca.getColor(ecr.getSchemeIndex());
r = (schemeColor >> 0) & 0xFF;
g = (schemeColor >> 8) & 0xFF;
b = (schemeColor >> 16) & 0xFF;
rgb[0] = (schemeColor >> 0) & 0xFF;
rgb[1] = (schemeColor >> 8) & 0xFF;
rgb[2] = (schemeColor >> 16) & 0xFF;
} else if (fPaletteIndex){
//TODO
} else if (fPaletteRGB){
@ -401,13 +392,11 @@ public abstract class Shape {
//TODO
}
EscherSimpleProperty op = (EscherSimpleProperty)getEscherProperty(opt, opacityProperty);
EscherSimpleProperty op = getEscherProperty(opt, opacityProperty);
int defaultOpacity = 0x00010000;
int opacity = op == null ? defaultOpacity : op.getPropertyValue();
int i = (opacity >> 16);
int f = (opacity >> 0) & 0xFFFF ;
double alpha = (i + f/65536.0)*255;
return new Color(r, g, b, (int)alpha);
int opacity = (op == null) ? defaultOpacity : op.getPropertyValue();
double alpha = Units.fixedPointToDecimal(opacity)*255.0;
return new Color(rgb[0], rgb[1], rgb[2], (int)alpha);
}
Color toRGB(int val){
@ -436,7 +425,7 @@ public abstract class Shape {
* @return id for the shape.
*/
public int getShapeId(){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
return spRecord == null ? 0 : spRecord.getShapeId();
}
@ -446,7 +435,7 @@ public abstract class Shape {
* @param id of the shape
*/
public void setShapeId(int id){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
if(spRecord != null) spRecord.setShapeId(id);
}
@ -484,7 +473,48 @@ public abstract class Shape {
return getLogicalAnchor2D();
}
protected EscherOptRecord getEscherOptRecord() {
return (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
public EscherOptRecord getEscherOptRecord() {
return getEscherChild(EscherOptRecord.RECORD_ID);
}
/**
* Whether the shape is horizontally flipped
*
* @return whether the shape is horizontally flipped
*/
public boolean getFlipHorizontal(){
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0;
}
/**
* Whether the shape is vertically flipped
*
* @return whether the shape is vertically flipped
*/
public boolean getFlipVertical(){
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0;
}
/**
* Rotation angle in degrees
*
* @return rotation angle in degrees
*/
public int getRotation(){
int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION);
int angle = (rot >> 16) % 360;
return angle;
}
/**
* Rotate this shape
*
* @param theta the rotation angle in degrees
*/
public void setRotation(int theta){
setEscherProperty(EscherProperties.TRANSFORM__ROTATION, (theta << 16));
}
}

View File

@ -62,7 +62,7 @@ public final class ShapeFactory {
if(opt != null){
try {
EscherPropertyFactory f = new EscherPropertyFactory();
List props = f.createProperties( opt.serialize(), 8, opt.getInstance() );
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);
@ -91,8 +91,8 @@ public final class ShapeFactory {
break;
case ShapeTypes.HostControl:
case ShapeTypes.PictureFrame: {
InteractiveInfo info = (InteractiveInfo)getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID);
OEShapeAtom oes = (OEShapeAtom)getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID);
InteractiveInfo info = getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID);
OEShapeAtom oes = getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID);
if(info != null && info.getInteractiveInfoAtom() != null){
switch(info.getInteractiveInfoAtom().getAction()){
case InteractiveInfoAtom.ACTION_OLE:
@ -115,7 +115,7 @@ public final class ShapeFactory {
shape = new Line(spContainer, parent);
break;
case ShapeTypes.NotPrimitive: {
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
EscherOptRecord opt = Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
if(prop != null)
shape = new Freeform(spContainer, parent);
@ -134,7 +134,8 @@ public final class ShapeFactory {
}
protected static Record getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
@SuppressWarnings("unchecked")
protected static <T extends Record> T getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
Record oep = null;
for (Iterator<EscherRecord> it = spContainer.getChildIterator(); it.hasNext();) {
EscherRecord obj = it.next();
@ -143,12 +144,12 @@ public final class ShapeFactory {
Record[] records = Record.findChildRecords(data, 8, data.length - 8);
for (int j = 0; j < records.length; j++) {
if (records[j].getRecordType() == recordType) {
return records[j];
return (T)records[j];
}
}
}
}
return oep;
return (T)oep;
}
}

View File

@ -100,9 +100,7 @@ public class ShapeGroup extends Shape{
*/
public void setAnchor(java.awt.Rectangle anchor){
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
//hack. internal variable EscherClientAnchorRecord.shortRecord can be
//initialized only in fillFields(). We need to set shortRecord=false;
byte[] header = new byte[16];
@ -116,7 +114,7 @@ public class ShapeGroup extends Shape{
clientAnchor.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI));
clientAnchor.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI));
EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
spgr.setRectX1(anchor.x*MASTER_DPI/POINT_DPI);
spgr.setRectY1(anchor.y*MASTER_DPI/POINT_DPI);
@ -131,8 +129,7 @@ public class ShapeGroup extends Shape{
* @param anchor the coordinate space of this group
*/
public void setCoordinates(Rectangle2D anchor){
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
int x1 = (int)Math.round(anchor.getX()*MASTER_DPI/POINT_DPI);
int y1 = (int)Math.round(anchor.getY()*MASTER_DPI/POINT_DPI);
@ -153,8 +150,7 @@ public class ShapeGroup extends Shape{
* @return the coordinate space of this group
*/
public Rectangle2D getCoordinates(){
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
Rectangle2D.Float anchor = new Rectangle2D.Float();
anchor.x = (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI;
@ -237,12 +233,11 @@ public class ShapeGroup extends Shape{
* @return the anchor of this shape group
*/
public Rectangle2D getAnchor2D(){
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
Rectangle2D.Float anchor = new Rectangle2D.Float();
if(clientAnchor == null){
logger.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord.");
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(spContainer, EscherChildAnchorRecord.RECORD_ID);
EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID);
anchor = new Rectangle2D.Float(
(float)rec.getDx1()*POINT_DPI/MASTER_DPI,
(float)rec.getDy1()*POINT_DPI/MASTER_DPI,
@ -266,8 +261,7 @@ public class ShapeGroup extends Shape{
* @return type of the shape.
*/
public int getShapeType(){
EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0);
EscherSpRecord spRecord = groupInfoContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
return spRecord.getOptions() >> 4;
}
@ -291,4 +285,10 @@ public class ShapeGroup extends Shape{
graphics.setTransform(at);
}
@Override
public <T extends EscherRecord> T getEscherChild(int recordId){
EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0);
return groupInfoContainer.getChildById((short)recordId);
}
}

View File

@ -484,7 +484,7 @@ public abstract class Sheet {
placeholderId = oep.getPlaceholderId();
} else {
//special case for files saved in Office 2007
RoundTripHFPlaceholder12 hldr = (RoundTripHFPlaceholder12)tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
RoundTripHFPlaceholder12 hldr = tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
if(hldr != null) placeholderId = hldr.getPlaceholderId();
}
if(placeholderId == type){

View File

@ -23,9 +23,16 @@ import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ddf.*;
import org.apache.poi.ddf.DefaultEscherRecordFactory;
import org.apache.poi.ddf.EscherChildAnchorRecord;
import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.InteractiveInfo;
@ -103,7 +110,7 @@ public abstract class SimpleShape extends Shape {
*/
public double getLineWidth(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
double width = prop == null ? DEFAULT_LINE_WIDTH : (double)prop.getPropertyValue()/EMU_PER_POINT;
return width;
}
@ -139,7 +146,7 @@ public abstract class SimpleShape extends Shape {
public Color getLineColor(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty p = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
EscherSimpleProperty p = getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
if(p != null && (p.getPropertyValue() & 0x8) == 0) return null;
Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
@ -154,7 +161,7 @@ public abstract class SimpleShape extends Shape {
public int getLineDashing(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING);
return prop == null ? Line.PEN_SOLID : prop.getPropertyValue();
}
@ -186,7 +193,7 @@ public abstract class SimpleShape extends Shape {
*/
public int getLineStyle(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE);
return prop == null ? Line.LINE_SIMPLE : prop.getPropertyValue();
}
@ -206,47 +213,6 @@ public abstract class SimpleShape extends Shape {
getFill().setForegroundColor(color);
}
/**
* Whether the shape is horizontally flipped
*
* @return whether the shape is horizontally flipped
*/
public boolean getFlipHorizontal(){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0;
}
/**
* Whether the shape is vertically flipped
*
* @return whether the shape is vertically flipped
*/
public boolean getFlipVertical(){
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0;
}
/**
* Rotation angle in degrees
*
* @return rotation angle in degrees
*/
public int getRotation(){
int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION);
int angle = (rot >> 16) % 360;
return angle;
}
/**
* Rotate this shape
*
* @param theta the rotation angle in degrees
*/
public void setRotation(int theta){
setEscherProperty(EscherProperties.TRANSFORM__ROTATION, (theta << 16));
}
/**
*
* @return 'absolute' anchor of this shape relative to the parent sheet
@ -256,17 +222,13 @@ public abstract class SimpleShape extends Shape {
//if it is a groupped shape see if we need to transform the coordinates
if (_parent != null){
List<Shape> lst = new ArrayList<Shape>();
lst.add(_parent);
Shape top = _parent;
while(top.getParent() != null) {
top = top.getParent();
lst.add(top);
ArrayList<ShapeGroup> lst = new ArrayList<ShapeGroup>();
for (Shape top=this; (top = top.getParent()) != null; ) {
lst.add(0, (ShapeGroup)top);
}
AffineTransform tx = new AffineTransform();
for(int i = lst.size() - 1; i >= 0; i--) {
ShapeGroup prnt = (ShapeGroup)lst.get(i);
for(ShapeGroup prnt : lst) {
Rectangle2D exterior = prnt.getAnchor2D();
Rectangle2D interior = prnt.getCoordinates();
@ -276,6 +238,7 @@ public abstract class SimpleShape extends Shape {
tx.translate(exterior.getX(), exterior.getY());
tx.scale(scaleX, scaleY);
tx.translate(-interior.getX(), -interior.getY());
}
anchor = tx.createTransformedShape(anchor).getBounds2D();
}
@ -314,12 +277,13 @@ public abstract class SimpleShape extends Shape {
*
* @param recordType type of the record to search
*/
protected Record getClientDataRecord(int recordType) {
@SuppressWarnings("unchecked")
protected <T extends Record> T getClientDataRecord(int recordType) {
Record[] records = getClientRecords();
if(records != null) for (int i = 0; i < records.length; i++) {
if(records[i].getRecordType() == recordType){
return records[i];
return (T)records[i];
}
}
return null;
@ -332,7 +296,7 @@ public abstract class SimpleShape extends Shape {
*/
protected Record[] getClientRecords() {
if(_clientData == null){
EscherRecord r = Shape.getEscherChild(getSpContainer(), EscherClientDataRecord.RECORD_ID);
EscherRecord r = getEscherChild(EscherClientDataRecord.RECORD_ID);
//ddf can return EscherContainerRecord with recordId=EscherClientDataRecord.RECORD_ID
//convert in to EscherClientDataRecord on the fly
if(r != null && !(r instanceof EscherClientDataRecord)){

View File

@ -88,7 +88,7 @@ public final class Slide extends Sheet
// Grab text from SlideListWithTexts entries
int i=0;
for(i=0; i<textRuns.size(); i++) {
_runs[i] = (TextRun)textRuns.get(i);
_runs[i] = textRuns.get(i);
_runs[i].setSheet(this);
}
// Grab text from slide's PPDrawing

View File

@ -225,7 +225,7 @@ public abstract class TextShape extends SimpleShape {
protected EscherTextboxWrapper getEscherTextboxWrapper(){
if(_txtbox == null){
EscherTextboxRecord textRecord = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID);
if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord);
}
return _txtbox;
@ -281,7 +281,7 @@ public abstract class TextShape extends SimpleShape {
*/
public int getVerticalAlignment(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
int valign = TextShape.AnchorTop;
if (prop == null){
/**
@ -352,7 +352,7 @@ public abstract class TextShape extends SimpleShape {
*/
public float getMarginBottom(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
@ -377,7 +377,7 @@ public abstract class TextShape extends SimpleShape {
*/
public float getMarginLeft(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
@ -402,7 +402,7 @@ public abstract class TextShape extends SimpleShape {
*/
public float getMarginRight(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
@ -426,7 +426,7 @@ public abstract class TextShape extends SimpleShape {
*/
public float getMarginTop(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
@ -450,7 +450,7 @@ public abstract class TextShape extends SimpleShape {
*/
public int getWordWrap(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
return prop == null ? WrapSquare : prop.getPropertyValue();
}
@ -469,7 +469,7 @@ public abstract class TextShape extends SimpleShape {
*/
public int getTextId(){
EscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
return prop == null ? 0 : prop.getPropertyValue();
}
@ -561,7 +561,7 @@ public abstract class TextShape extends SimpleShape {
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
}
} else {
EscherSpRecord escherSpRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord escherSpRecord = getEscherChild(EscherSpRecord.RECORD_ID);
int shapeId = escherSpRecord.getShapeId();
if(runs != null) for (int i = 0; i < runs.length; i++) {
if(runs[i].getShapeId() == shapeId){
@ -593,7 +593,7 @@ public abstract class TextShape extends SimpleShape {
* @return <code>OEPlaceholderAtom</code> or <code>null</code> if not found
*/
public OEPlaceholderAtom getPlaceholderAtom(){
return (OEPlaceholderAtom)getClientDataRecord(RecordTypes.OEPlaceholderAtom.typeID);
return getClientDataRecord(RecordTypes.OEPlaceholderAtom.typeID);
}
/**

View File

@ -17,17 +17,25 @@
package org.apache.poi.hslf.model;
import junit.framework.TestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.*;
import java.awt.*;
import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import org.apache.poi.ddf.*;
import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.POIDataSamples;
import org.junit.Test;
/**
@ -35,13 +43,14 @@ import org.apache.poi.POIDataSamples;
*
* @author Yegor Kozlov
*/
public final class TestBackground extends TestCase {
public final class TestBackground {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
/**
* Default background for slide, shape and slide master.
*/
public void testDefaults() {
@Test
public void defaults() {
SlideShow ppt = new SlideShow();
assertEquals(Fill.FILL_SOLID, ppt.getSlidesMasters()[0].getBackground().getFill().getFillType());
@ -57,7 +66,8 @@ public final class TestBackground extends TestCase {
/**
* Read fill information from an reference ppt file
*/
public void testReadBackground() throws Exception {
@Test
public void readBackground() throws Exception {
SlideShow ppt = new SlideShow(_slTests.openResourceAsStream("backgrounds.ppt"));
Fill fill;
Shape shape;
@ -88,7 +98,8 @@ public final class TestBackground extends TestCase {
/**
* Create a ppt with various fill effects
*/
public void testBackgroundPicture() throws Exception {
@Test
public void backgroundPicture() throws Exception {
SlideShow ppt = new SlideShow();
Slide slide;
Fill fill;
@ -191,8 +202,8 @@ public final class TestBackground extends TestCase {
}
private int getFillPictureRefCount(Shape shape, Fill fill) {
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
EscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
if(p != null) {
int idx = p.getPropertyValue();
@ -200,8 +211,8 @@ public final class TestBackground extends TestCase {
SlideShow ppt = sheet.getSlideShow();
Document doc = ppt.getDocumentRecord();
EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
List lst = bstore.getChildRecords();
EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
List<EscherRecord> lst = bstore.getChildRecords();
return ((EscherBSERecord)lst.get(idx-1)).getRef();
}
return 0;

View File

@ -17,38 +17,60 @@
package org.apache.poi.hslf.model;
import junit.framework.TestCase;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.ddf.*;
import org.apache.poi.POIDataSamples;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.awt.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.junit.Before;
import org.junit.Test;
/**
* Test drawing shapes via Graphics2D
*
* @author Yegor Kozlov
*/
public final class TestShapes extends TestCase {
public final class TestShapes {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
private SlideShow ppt;
private SlideShow pptB;
protected void setUp() throws Exception {
ppt = new SlideShow(_slTests.openResourceAsStream("empty.ppt"));
pptB = new SlideShow(_slTests.openResourceAsStream("empty_textbox.ppt"));
@Before
public void setUp() throws Exception {
InputStream is1 = null, is2 = null;
try {
is1 = _slTests.openResourceAsStream("empty.ppt");
ppt = new SlideShow(is1);
is2 = _slTests.openResourceAsStream("empty_textbox.ppt");
pptB = new SlideShow(is2);
} finally {
is1.close();
is2.close();
}
}
public void testGraphics() throws Exception {
@Test
public void graphics() throws Exception {
Slide slide = ppt.createSlide();
Line line = new Line();
@ -92,7 +114,8 @@ public final class TestShapes extends TestCase {
* Verify that we can read TextBox shapes
* @throws Exception
*/
public void testTextBoxRead() throws Exception {
@Test
public void textBoxRead() throws Exception {
ppt = new SlideShow(_slTests.openResourceAsStream("with_textbox.ppt"));
Slide sl = ppt.getSlides()[0];
Shape[] sh = sl.getShapes();
@ -127,7 +150,8 @@ public final class TestShapes extends TestCase {
* Verify that we can add TextBox shapes to a slide
* and set some of the style attributes
*/
public void testTextBoxWriteBytes() throws Exception {
@Test
public void textBoxWriteBytes() throws Exception {
ppt = new SlideShow();
Slide sl = ppt.createSlide();
RichTextRun rt;
@ -180,7 +204,8 @@ public final class TestShapes extends TestCase {
/**
* Test with an empty text box
*/
public void testEmptyTextBox() {
@Test
public void emptyTextBox() {
assertEquals(2, pptB.getSlides().length);
Slide s1 = pptB.getSlides()[0];
Slide s2 = pptB.getSlides()[1];
@ -194,7 +219,8 @@ public final class TestShapes extends TestCase {
* If you iterate over text shapes in a slide and collect them in a set
* it must be the same as returned by Slide.getTextRuns().
*/
public void testTextBoxSet() throws Exception {
@Test
public void textBoxSet() throws Exception {
textBoxSet("with_textbox.ppt");
textBoxSet("basic_test_ppt_file.ppt");
textBoxSet("next_test_ppt_file.ppt");
@ -207,13 +233,13 @@ public final class TestShapes extends TestCase {
SlideShow ppt = new SlideShow(_slTests.openResourceAsStream(filename));
Slide[] sl = ppt.getSlides();
for (int k = 0; k < sl.length; k++) {
ArrayList lst1 = new ArrayList();
ArrayList<String> lst1 = new ArrayList<String>();
TextRun[] txt = sl[k].getTextRuns();
for (int i = 0; i < txt.length; i++) {
lst1.add(txt[i].getText());
}
ArrayList lst2 = new ArrayList();
ArrayList<String> lst2 = new ArrayList<String>();
Shape[] sh = sl[k].getShapes();
for (int i = 0; i < sh.length; i++) {
if (sh[i] instanceof TextShape){
@ -229,7 +255,8 @@ public final class TestShapes extends TestCase {
/**
* Test adding shapes to <code>ShapeGroup</code>
*/
public void testShapeGroup() throws Exception {
@Test
public void shapeGroup() throws Exception {
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
@ -280,7 +307,8 @@ public final class TestShapes extends TestCase {
/**
* Test functionality of Sheet.removeShape(Shape shape)
*/
public void testRemoveShapes() throws IOException {
@Test
public void removeShapes() throws IOException {
String file = "with_textbox.ppt";
SlideShow ppt = new SlideShow(_slTests.openResourceAsStream(file));
Slide sl = ppt.getSlides()[0];
@ -304,21 +332,23 @@ public final class TestShapes extends TestCase {
assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length);
}
public void testLineWidth() {
@Test
public void lineWidth() {
SimpleShape sh = new AutoShape(ShapeTypes.RightTriangle);
EscherOptRecord opt = (EscherOptRecord)SimpleShape.getEscherChild(sh.getSpContainer(), EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
EscherOptRecord opt = sh.getEscherOptRecord();
EscherSimpleProperty prop = SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
assertNull(prop);
assertEquals(SimpleShape.DEFAULT_LINE_WIDTH, sh.getLineWidth());
assertEquals(SimpleShape.DEFAULT_LINE_WIDTH, sh.getLineWidth(), 0);
sh.setLineWidth(1.0);
prop = (EscherSimpleProperty)SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
prop = SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
assertNotNull(prop);
assertEquals(1.0, sh.getLineWidth());
assertEquals(1.0, sh.getLineWidth(), 0);
}
public void testShapeId() {
@Test
public void shapeId() {
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
Shape shape = null;
@ -367,7 +397,8 @@ public final class TestShapes extends TestCase {
assertEquals(numClusters + 1, dgg.getNumIdClusters());
}
public void testLineColor() throws IOException {
@Test
public void lineColor() throws IOException {
SlideShow ppt = new SlideShow(_slTests.openResourceAsStream("51731.ppt"));
Shape[] shape = ppt.getSlides()[0].getShapes();
@ -384,11 +415,11 @@ public final class TestShapes extends TestCase {
TextShape sh3 = (TextShape)shape[2];
assertEquals("Text in a black border", sh3.getText());
assertEquals(Color.black, sh3.getLineColor());
assertEquals(0.75, sh3.getLineWidth());
assertEquals(0.75, sh3.getLineWidth(), 0);
TextShape sh4 = (TextShape)shape[3];
assertEquals("Border width is 5 pt", sh4.getText());
assertEquals(Color.black, sh4.getLineColor());
assertEquals(5.0, sh4.getLineWidth());
assertEquals(5.0, sh4.getLineWidth(), 0);
}
}

View File

@ -37,9 +37,14 @@ import java.util.Set;
import junit.framework.AssertionFailedError;
import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.EscherArrayProperty;
import org.apache.poi.ddf.EscherColorRef;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.HSLFTestDataSamples;
import org.apache.poi.hslf.exceptions.OldPowerPointFormatException;
import org.apache.poi.hslf.model.AutoShape;
import org.apache.poi.hslf.model.Background;
import org.apache.poi.hslf.model.Fill;
import org.apache.poi.hslf.model.HeadersFooters;
@ -59,7 +64,9 @@ import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.SlideListWithText;
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.junit.Test;
/**
@ -625,4 +632,36 @@ public final class TestBugs {
inputStream.close();
}
}
@Test
public void bug46441() throws Exception {
InputStream inputStream = new FileInputStream(_slTests.getFile("bug46441.ppt"));
try {
SlideShow slideShow = new SlideShow(inputStream);
AutoShape as = (AutoShape)slideShow.getSlides()[0].getShapes()[0];
EscherOptRecord opt = as.getEscherOptRecord();
EscherArrayProperty ep = Shape.getEscherProperty(opt, EscherProperties.FILL__SHADECOLORS);
double exp[][] = {
// r, g, b, position
{ 94, 158, 255, 0 },
{ 133, 194, 255, 0.399994 },
{ 196, 214, 235, 0.699997 },
{ 255, 235, 250, 1 }
};
int i = 0;
for (byte data[] : ep) {
EscherColorRef ecr = new EscherColorRef(data, 0, 4);
int rgb[] = ecr.getRGB();
double pos = Units.fixedPointToDecimal(LittleEndian.getInt(data, 4));
assertEquals((int)exp[i][0], rgb[0]);
assertEquals((int)exp[i][1], rgb[1]);
assertEquals((int)exp[i][2], rgb[2]);
assertEquals(exp[i][3], pos, 0.01);
i++;
}
} finally {
inputStream.close();
}
}
}

Binary file not shown.