Bug 63580 - Fix texture paint handling

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1863600 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2019-07-22 21:29:55 +00:00
parent 21ed5240e7
commit 58eb1a8070
10 changed files with 409 additions and 64 deletions

View File

@ -18,13 +18,13 @@
package org.apache.poi.sl.draw;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
@ -38,11 +38,13 @@ import java.util.function.BiFunction;
import org.apache.poi.sl.usermodel.AbstractColorStyle;
import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.FlipMode;
import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
import org.apache.poi.sl.usermodel.PaintStyle.PaintModifier;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -243,11 +245,6 @@ public class DrawPaint {
ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, contentType);
int alpha = fill.getAlpha();
if (0 <= alpha && alpha < 100000) {
renderer.setAlpha(alpha/100000.f);
}
// TODO: handle tile settings, currently the pattern is always streched 100% in height/width
Rectangle2D textAnchor = shape.getAnchor();
@ -258,25 +255,67 @@ public class DrawPaint {
renderer.loadImage(is, contentType);
final BufferedImage image;
switch (contentType) {
case "image/x-wmf":
case "image/x-emf":
// don't rely on wmf dimensions, use dimension of anchor
// TODO: check pixels vs. points for image dimension
image = renderer.getImage(new Dimension((int)textAnchor.getWidth(), (int)textAnchor.getHeight()));
break;
default:
image = renderer.getImage();
break;
int alpha = fill.getAlpha();
if (0 <= alpha && alpha < 100000) {
renderer.setAlpha(alpha/100000.f);
}
Dimension2D imgDim = renderer.getDimension();
if ("image/x-wmf".contains(contentType)) {
// don't rely on wmf dimensions, use dimension of anchor
// TODO: check pixels vs. points for image dimension
imgDim = new Dimension2DDouble(textAnchor.getWidth(), textAnchor.getHeight());
}
BufferedImage image = renderer.getImage(imgDim);
if(image == null) {
LOG.log(POILogger.ERROR, "Can't load image data");
return TRANSPARENT;
}
return new java.awt.TexturePaint(image, textAnchor);
double flipX = 1, flipY = 1;
final FlipMode flip = fill.getFlipMode();
if (flip != null && flip != FlipMode.NONE) {
final int width = image.getWidth(), height = image.getHeight();
switch (flip) {
case X:
flipX = 2;
break;
case Y:
flipY = 2;
break;
case XY:
flipX = 2;
flipY = 2;
break;
}
final BufferedImage img = new BufferedImage((int)(width*flipX), (int)(height*flipY), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
g.drawImage(image, 0, 0, null);
switch (flip) {
case X:
g.drawImage(image, 2*width, 0, -width, height, null);
break;
case Y:
g.drawImage(image, 0, 2*height, width, -height, null);
break;
case XY:
g.drawImage(image, 2*width, 0, -width, height, null);
g.drawImage(image, 0, 2*height, width, -height, null);
g.drawImage(image, 2*width, 2*height, -width, -height, null);
break;
}
g.dispose();
image = img;
}
Shape s = (Shape)graphics.getRenderingHint(Drawable.GRADIENT_SHAPE);
// TODO: check why original bitmaps scale/behave differently to vector based images
return new DrawTexturePaint(image, s, fill, flipX, flipY, renderer instanceof BitmapImageRenderer);
} catch (IOException e) {
LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
return TRANSPARENT;

View File

@ -20,6 +20,7 @@ package org.apache.poi.sl.draw;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
@ -114,7 +115,12 @@ public class DrawPictureShape extends DrawSimpleShape {
// falling back to BitmapImageRenderer, at least it gracefully handles invalid images
return bir;
}
@Override
protected Paint getFillPaint(Graphics2D graphics) {
return null;
}
@Override
protected PictureShape<?,?> getShape() {
return (PictureShape<?,?>)shape;

View File

@ -24,12 +24,14 @@ import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import org.apache.poi.sl.draw.geom.Context;
import org.apache.poi.sl.draw.geom.CustomGeometry;
@ -38,6 +40,8 @@ import org.apache.poi.sl.draw.geom.Path;
import org.apache.poi.sl.usermodel.LineDecoration;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.PaintModifier;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.Shadow;
import org.apache.poi.sl.usermodel.SimpleShape;
@ -58,9 +62,8 @@ public class DrawSimpleShape extends DrawShape {
return;
}
DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(getShape());
Paint fill = drawPaint.getPaint(graphics, getShape().getFillStyle().getPaint());
Paint line = drawPaint.getPaint(graphics, getShape().getStrokeStyle().getPaint());
Paint fill = getFillPaint(graphics);
Paint line = getLinePaint(graphics);
BasicStroke stroke = getStroke(); // the stroke applies both to the shadow and the shape
graphics.setStroke(stroke);
@ -71,17 +74,29 @@ public class DrawSimpleShape extends DrawShape {
// then fill the shape interior
if (fill != null) {
final Path2D area = new Path2D.Double();
graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, area);
Consumer<PaintModifier> fun = (pm) -> fillArea(graphics, pm, area);
PaintModifier pm = null;
for (Outline o : elems) {
if (o.getPath().isFilled()){
Paint fillMod = drawPaint.getPaint(graphics, getShape().getFillStyle().getPaint(), o.getPath().getFill());
if (fillMod != null) {
graphics.setPaint(fillMod);
java.awt.Shape s = o.getOutline();
graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, s);
fillPaintWorkaround(graphics, s);
Path path = o.getPath();
if (path.isFilled()) {
PaintModifier pmOld = pm;
pm = path.getFill();
if (pmOld != null && pmOld != pm) {
fun.accept(pmOld);
area.reset();
} else {
area.append(o.getOutline(), false);
}
}
}
if (area.getCurrentPoint() != null) {
fun.accept(pm);
}
}
// then draw any content within this shape (text, image, etc.)
@ -104,6 +119,30 @@ public class DrawSimpleShape extends DrawShape {
drawDecoration(graphics, line, stroke);
}
private void fillArea(Graphics2D graphics, PaintModifier pm, Path2D area) {
final SimpleShape<?, ?> ss = getShape();
final PaintStyle ps = ss.getFillStyle().getPaint();
final DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(ss);
final Paint fillMod = drawPaint.getPaint(graphics, ps, pm);
if (fillMod != null) {
graphics.setPaint(fillMod);
fillPaintWorkaround(graphics, area);
}
}
protected Paint getFillPaint(Graphics2D graphics) {
final PaintStyle ps = getShape().getFillStyle().getPaint();
DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(getShape());
return drawPaint.getPaint(graphics, ps);
}
protected Paint getLinePaint(Graphics2D graphics) {
final PaintStyle ps = getShape().getFillStyle().getPaint();
DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(getShape());
return drawPaint.getPaint(graphics, getShape().getStrokeStyle().getPaint());
}
protected void drawDecoration(Graphics2D graphics, Paint line, BasicStroke stroke) {
if(line == null) {
return;

View File

@ -0,0 +1,149 @@
/* ====================================================================
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.sl.draw;
import java.awt.PaintContext;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import org.apache.poi.sl.usermodel.PaintStyle;
/* package */ class DrawTexturePaint extends java.awt.TexturePaint {
private final PaintStyle.TexturePaint fill;
private final Shape shape;
private final double flipX, flipY;
private final boolean isBitmapSrc;
DrawTexturePaint(BufferedImage txtr, Shape shape, PaintStyle.TexturePaint fill, double flipX, double flipY, boolean isBitmapSrc) {
// deactivate scaling/translation in super class, by specifying the dimension of the texture
super(txtr, new Rectangle2D.Double(0,0,txtr.getWidth(),txtr.getHeight()));
this.fill = fill;
this.shape = shape;
this.flipX = flipX;
this.flipY = flipY;
this.isBitmapSrc = isBitmapSrc;
}
@Override
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) {
final double usr_w, usr_h;
if (fill.isRotatedWithShape() || shape == null) {
usr_w = userBounds.getWidth();
usr_h = userBounds.getHeight();
xform.translate(userBounds.getX(), userBounds.getY());
} else {
AffineTransform transform = new AffineTransform(xform);
// Eliminate any post-translation
transform.preConcatenate(AffineTransform.getTranslateInstance(
-transform.getTranslateX(), -transform.getTranslateY()));
Point2D p1 = new Point2D.Double(1, 0);
p1 = transform.transform(p1,p1);
final double rad = Math.atan2(p1.getY(),p1.getX());
if (rad != 0) {
xform.rotate(-rad, userBounds.getCenterX(), userBounds.getCenterY());
}
// TODO: check if approximation via rotating only the bounds (instead of the shape) is sufficient
transform = AffineTransform.getRotateInstance(rad, userBounds.getCenterX(), userBounds.getCenterY());
Rectangle2D newBounds = transform.createTransformedShape(shape).getBounds2D();
usr_w = newBounds.getWidth();
usr_h = newBounds.getHeight();
xform.translate(newBounds.getX(), newBounds.getY());
}
final Dimension2D scale = fill.getScale();
final BufferedImage bi = getImage();
final double img_w = bi.getWidth() * (scale == null ? 1 : scale.getWidth())/flipX;
final double img_h = bi.getHeight() * (scale == null ? 1 : scale.getHeight())/flipY;
// Alignment happens after the scaling but before any offset.
PaintStyle.TextureAlignment ta = fill.getAlignment();
final double alg_x, alg_y;
switch (ta == null ? PaintStyle.TextureAlignment.TOP_LEFT : ta) {
case BOTTOM:
alg_x = (usr_w-img_w)/2;
alg_y = usr_h-img_h;
break;
case BOTTOM_LEFT:
alg_x = 0;
alg_y = usr_h-img_h;
break;
case BOTTOM_RIGHT:
alg_x = usr_w-img_w;
alg_y = usr_h-img_h;
break;
case CENTER:
alg_x = (usr_w-img_w)/2;
alg_y = (usr_h-img_h)/2;
break;
case LEFT:
alg_x = 0;
alg_y = (usr_h-img_h)/2;
break;
case RIGHT:
alg_x = usr_w-img_w;
alg_y = (usr_h-img_h)/2;
break;
case TOP:
alg_x = (usr_w-img_w)/2;
alg_y = 0;
break;
default:
case TOP_LEFT:
alg_x = 0;
alg_y = 0;
break;
case TOP_RIGHT:
alg_x = usr_w-img_w;
alg_y = 0;
break;
}
xform.translate(alg_x, alg_y);
// Apply additional horizontal/vertical offset after alignment.
// Values are as percentages.
// TODO: apply scaling of drawing context to offset
final Point2D offset = fill.getOffset();
if (offset != null) {
xform.translate(offset.getX(),offset.getY());
}
if (scale != null) {
xform.scale(scale.getWidth()/(isBitmapSrc ? flipX : 1.),scale.getHeight()/(isBitmapSrc ? flipY : 1.));
}
return super.createContext(cm, deviceBounds, userBounds, xform, hints);
}
}

View File

@ -99,7 +99,7 @@ public interface ImageRenderer {
void loadImage(byte[] data, String contentType) throws IOException;
/**
* @return the dimension of the buffered image
* @return the dimension of the buffered image in pixel
*/
Dimension2D getDimension();

View File

@ -17,6 +17,8 @@
package org.apache.poi.sl.usermodel;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.io.InputStream;
@ -41,6 +43,45 @@ public interface PaintStyle {
DARKEN_LESS
}
enum FlipMode {
/** not flipped/mirrored */
NONE,
/** flipped/mirrored/duplicated along the x axis */
X,
/** flipped/mirrored/duplicated along the y axis */
Y,
/** flipped/mirrored/duplicated along the x and y axis */
XY
}
enum TextureAlignment {
BOTTOM("b"),
BOTTOM_LEFT("bl"),
BOTTOM_RIGHT("br"),
CENTER("ctr"),
LEFT("l"),
RIGHT("r"),
TOP("t"),
TOP_LEFT("tl"),
TOP_RIGHT("tr");
private final String ooxmlId;
TextureAlignment(String ooxmlId) {
this.ooxmlId = ooxmlId;
}
public static TextureAlignment fromOoxmlId(String ooxmlId) {
for (TextureAlignment ta : values()) {
if (ta.ooxmlId.equals(ooxmlId)) {
return ta;
}
}
return null;
}
}
interface SolidPaint extends PaintStyle {
ColorStyle getSolidColor();
}
@ -73,5 +114,29 @@ public interface PaintStyle {
* @return the alpha mask in percents [0..100000]
*/
int getAlpha();
/**
* @return {@code true}, if the rotation of the shape is also applied to the texture paint
*/
default boolean isRotatedWithShape() { return true; }
/**
* @return the dimensions of the tiles in percent of the shape dimensions
* or {@code null} if no scaling is applied
*/
default Dimension2D getScale() { return null; }
/**
* @return the offset of the tiles in points or {@code null} if there's no offset
*/
default Point2D getOffset() { return null; }
/**
* @return the flip/mirroring/duplication mode
*/
default FlipMode getFlipMode() { return FlipMode.NONE; }
default TextureAlignment getAlignment() { return null; }
}
}

View File

@ -139,7 +139,7 @@ public class Units {
return (int)Math.rint(points);
}
public static double pixelToPoints(int pixel) {
public static double pixelToPoints(double pixel) {
double points = pixel;
points *= POINT_DPI;
points /= PIXEL_DPI;
@ -152,6 +152,12 @@ public class Units {
return new Dimension2DDouble(width, height);
}
public static Dimension2D pixelToPoints(Dimension2D pointsDim) {
double width = pointsDim.getWidth() * POINT_DPI / PIXEL_DPI;
double height = pointsDim.getHeight() * POINT_DPI / PIXEL_DPI;
return new Dimension2DDouble(width, height);
}
public static int charactersToEMU(double characters) {
return (int) characters * EMU_PER_CHARACTER;
}

View File

@ -20,6 +20,8 @@
package org.apache.poi.xslf.usermodel;
import java.awt.Graphics2D;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;
@ -41,7 +43,9 @@ import org.apache.poi.sl.usermodel.PlaceholderDetails;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.sl.usermodel.SimpleShape;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.Internal;
import org.apache.poi.util.Units;
import org.apache.poi.xslf.model.PropertyFetcher;
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
import org.apache.xmlbeans.XmlCursor;
@ -58,7 +62,9 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTileInfoProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTileFlipMode;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
@ -441,6 +447,50 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
? blip.getAlphaModFixArray(0).getAmt()
: 100000;
}
@Override
public boolean isRotatedWithShape() {
return blipFill.isSetRotWithShape() && blipFill.getRotWithShape();
}
@Override
public Dimension2D getScale() {
CTTileInfoProperties tile = blipFill.getTile();
return (tile == null) ? null : new Dimension2DDouble(
tile.isSetSx() ? tile.getSx()/100_000. : 1,
tile.isSetSy() ? tile.getSy()/100_000. : 1);
}
@Override
public Point2D getOffset() {
CTTileInfoProperties tile = blipFill.getTile();
return (tile == null) ? null : new Point2D.Double(
tile.isSetTx() ? Units.toPoints(tile.getTx()) : 0,
tile.isSetTy() ? Units.toPoints(tile.getTy()) : 0);
}
@Override
public FlipMode getFlipMode() {
CTTileInfoProperties tile = blipFill.getTile();
switch (tile == null ? STTileFlipMode.INT_NONE : tile.getFlip().intValue()) {
default:
case STTileFlipMode.INT_NONE:
return FlipMode.NONE;
case STTileFlipMode.INT_X:
return FlipMode.X;
case STTileFlipMode.INT_Y:
return FlipMode.Y;
case STTileFlipMode.INT_XY:
return FlipMode.XY;
}
}
@Override
public TextureAlignment getAlignment() {
CTTileInfoProperties tile = blipFill.getTile();
return (tile == null || !tile.isSetAlgn()) ? null
: TextureAlignment.fromOoxmlId(tile.getAlgn().toString());
}
};
}

View File

@ -22,12 +22,11 @@ package org.apache.poi.xslf.usermodel;
import static org.junit.Assume.assumeFalse;
import java.io.File;
import java.io.FileFilter;
import java.util.Collection;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.poi.POIDataSamples;
import org.apache.poi.xslf.util.PPTX2PNG;
@ -66,29 +65,15 @@ public class TestPPTX2PNG {
@Parameter(value = 0)
public String pptFile;
@SuppressWarnings("ConstantConditions")
@Parameters(name="{0}")
public static Collection<String> data() {
final Set<String> data = new TreeSet<>();
for (String f : files.split(", ?")) {
if (basedir == null) {
data.add(f);
} else {
final Pattern p = Pattern.compile(f);
basedir.listFiles(new FileFilter(){
public boolean accept(File pathname) {
String name = pathname.getName();
if (p.matcher(name).matches()) {
data.add(name);
}
return false;
}
});
}
}
return data;
Function<String, Stream<String>> fun = (basedir == null) ? Stream::of :
(f) -> Stream.of(basedir.listFiles(p -> p.getName().matches(f))).map(File::getName);
return Stream.of(files.split(", ?")).flatMap(fun).collect(Collectors.toList());
}
@Test
public void render() throws Exception {
assumeFalse("ignore HSLF / .ppt files in no-scratchpad run", xslfOnly && pptFile.toLowerCase(Locale.ROOT).endsWith("ppt"));
@ -98,6 +83,7 @@ public class TestPPTX2PNG {
"-slide", "-1", // -1 for all
"-outdir", new File("build/tmp/").getCanonicalPath(),
"-outpat", "${basename}-${slideno}-${ext}.${format}",
"-scale", "1.333333333",
"-quiet",
(basedir == null ? samples.getFile(pptFile) : new File(basedir, pptFile)).getAbsolutePath()
};

View File

@ -254,20 +254,20 @@ public final class HSLFFill {
};
}
private boolean isRotatedWithShape() {
// NOFILLHITTEST can be in the normal escher opt record but also in the tertiary record
// the extended bit fields seem to be in the second
AbstractEscherOptRecord opt = shape.getEscherChild(RecordTypes.EscherUserDefined);
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
int propVal = (p == null) ? 0 : p.getPropertyValue();
return FILL_USE_USE_SHAPE_ANCHOR.isSet(propVal) && FILL_USE_SHAPE_ANCHOR.isSet(propVal);
}
private GradientPaint getGradientPaint(final GradientType gradientType) {
AbstractEscherOptRecord opt = shape.getEscherOptRecord();
final EscherArrayProperty ep = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__SHADECOLORS);
final int colorCnt = (ep == null) ? 0 : ep.getNumberOfElementsInArray();
// NOFILLHITTEST can be in the normal escher opt record but also in the tertiary record
// the extended bit fields seem to be in the second
opt = shape.getEscherChild(RecordTypes.EscherUserDefined);
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
int propVal = (p == null) ? 0 : p.getPropertyValue();
final boolean rotateWithShape = FILL_USE_USE_SHAPE_ANCHOR.isSet(propVal) && FILL_USE_SHAPE_ANCHOR.isSet(propVal);
return new GradientPaint() {
@Override
public double getGradientAngle() {
@ -319,7 +319,7 @@ public final class HSLFFill {
@Override
public boolean isRotatedWithShape() {
return rotateWithShape;
return HSLFFill.this.isRotatedWithShape();
}
@Override
@ -350,6 +350,11 @@ public final class HSLFFill {
public int getAlpha() {
return (int)(shape.getAlpha(EscherProperties.FILL__FILLOPACITY)*100000.0);
}
@Override
public boolean isRotatedWithShape() {
return HSLFFill.this.isRotatedWithShape();
}
};
}