#56004 - Support for WMF rendering

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1724897 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2016-01-16 00:11:01 +00:00
parent bdef6e1c52
commit c1263423cf
17 changed files with 468 additions and 141 deletions

View File

@ -186,6 +186,10 @@ public final class EscherProperties {
public static final short LINESTYLE__HITLINETEST = 509;
public static final short LINESTYLE__LINEFILLSHAPE = 510;
public static final short LINESTYLE__NOLINEDRAWDASH = 511;
public static final short LINESTYLE__NOLINEDRAWDASH_LEFT = 0x057F;
public static final short LINESTYLE__NOLINEDRAWDASH_TOP = 0x05BF;
public static final short LINESTYLE__NOLINEDRAWDASH_BOTTOM = 0x063F;
public static final short LINESTYLE__NOLINEDRAWDASH_RIGHT = 0x05FF;
public static final short SHADOWSTYLE__TYPE = 512;
public static final short SHADOWSTYLE__COLOR = 513;
public static final short SHADOWSTYLE__HIGHLIGHT = 514;
@ -488,6 +492,10 @@ public final class EscherProperties {
addProp(m, LINESTYLE__HITLINETEST, "linestyle.hitlinetest");
addProp(m, LINESTYLE__LINEFILLSHAPE, "linestyle.linefillshape");
addProp(m, LINESTYLE__NOLINEDRAWDASH, "linestyle.nolinedrawdash", EscherPropertyMetaData.TYPE_BOOLEAN);
addProp(m, LINESTYLE__NOLINEDRAWDASH_LEFT, "linestyle.nolinedrawdash.left", EscherPropertyMetaData.TYPE_BOOLEAN);
addProp(m, LINESTYLE__NOLINEDRAWDASH_TOP, "linestyle.nolinedrawdash.top", EscherPropertyMetaData.TYPE_BOOLEAN);
addProp(m, LINESTYLE__NOLINEDRAWDASH_BOTTOM, "linestyle.nolinedrawdash.bottom", EscherPropertyMetaData.TYPE_BOOLEAN);
addProp(m, LINESTYLE__NOLINEDRAWDASH_RIGHT, "linestyle.nolinedrawdash.right", EscherPropertyMetaData.TYPE_BOOLEAN);
addProp(m, SHADOWSTYLE__TYPE, "shadowstyle.type");
addProp(m, SHADOWSTYLE__COLOR, "shadowstyle.color", EscherPropertyMetaData.TYPE_RGB);
addProp(m, SHADOWSTYLE__HIGHLIGHT, "shadowstyle.highlight");

View File

@ -0,0 +1,142 @@
/* ====================================================================
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.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* For now this class renders only images supported by the javax.imageio.ImageIO framework.
**/
public class BitmapImageRenderer implements ImageRenderer {
private final static POILogger LOG = POILogFactory.getLogger(ImageRenderer.class);
protected BufferedImage img;
@Override
public void loadImage(InputStream data, String contentType) throws IOException {
img = convertBufferedImage(ImageIO.read(data), contentType);
}
@Override
public void loadImage(byte data[], String contentType) throws IOException {
img = convertBufferedImage(ImageIO.read(new ByteArrayInputStream(data)), contentType);
}
/**
* Add alpha channel to buffered image
*/
private static BufferedImage convertBufferedImage(BufferedImage img, String contentType) {
if (img == null) {
LOG.log(POILogger.WARN, "Content-type: "+contentType+" is not support. Image ignored.");
return null;
}
BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return bi;
}
/**
* @return the buffered image
*/
public BufferedImage getImage() {
return img;
}
@Override
public Dimension getDimension() {
return (img == null)
? new Dimension(0,0)
: new Dimension(img.getWidth(),img.getHeight());
}
@Override
public void setAlpha(double alpha) {
if (img == null) return;
Dimension dim = getDimension();
BufferedImage newImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImg.createGraphics();
RescaleOp op = new RescaleOp(new float[]{1.0f, 1.0f, 1.0f, (float)alpha}, new float[]{0,0,0,0}, null);
g.drawImage(img, op, 0, 0);
g.dispose();
img = newImg;
}
@Override
public boolean drawImage(
Graphics2D graphics,
Rectangle2D anchor) {
return drawImage(graphics, anchor, null);
}
@Override
public boolean drawImage(
Graphics2D graphics,
Rectangle2D anchor,
Insets clip) {
if (img == null) return false;
boolean isClipped = true;
if (clip == null) {
isClipped = false;
clip = new Insets(0,0,0,0);
}
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();
if (isClipped) graphics.clip(anchor.getBounds2D());
graphics.drawRenderedImage(img, at);
graphics.setClip(clipOld);
return true;
}
}

View File

@ -26,6 +26,7 @@ import java.text.AttributedString;
import org.apache.poi.sl.usermodel.Background;
import org.apache.poi.sl.usermodel.ConnectorShape;
import org.apache.poi.sl.usermodel.FreeformShape;
import org.apache.poi.sl.usermodel.GraphicalFrame;
import org.apache.poi.sl.usermodel.GroupShape;
import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.PictureShape;
@ -87,6 +88,8 @@ public class DrawFactory {
return getDrawable((GroupShape<?,?>)shape);
} else if (shape instanceof PictureShape) {
return getDrawable((PictureShape<?,?>)shape);
} else if (shape instanceof GraphicalFrame) {
return getDrawable((GraphicalFrame<?,?>)shape);
} else if (shape instanceof Background) {
return getDrawable((Background<?,?>)shape);
} else if (shape instanceof ConnectorShape) {
@ -144,6 +147,10 @@ public class DrawFactory {
return new DrawPictureShape(shape);
}
public DrawGraphicalFrame getDrawable(GraphicalFrame<?,?> shape) {
return new DrawGraphicalFrame(shape);
}
public DrawTextParagraph getDrawable(TextParagraph<?,?,?> paragraph) {
return new DrawTextParagraph(paragraph);
}

View File

@ -0,0 +1,40 @@
/* ====================================================================
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.Graphics2D;
import org.apache.poi.sl.usermodel.GraphicalFrame;
import org.apache.poi.sl.usermodel.PictureShape;
public class DrawGraphicalFrame extends DrawShape {
public DrawGraphicalFrame(GraphicalFrame<?,?> shape) {
super(shape);
}
public void draw(Graphics2D context) {
PictureShape<?,?> ps = ((GraphicalFrame<?,?>)getShape()).getFallbackPicture();
if (ps == null) {
return;
}
DrawPictureShape dps = DrawFactory.getInstance(context).getDrawable(ps);
dps.draw(context);
}
}

View File

@ -130,8 +130,7 @@ public class DrawPaint {
if (is == null) return null;
assert(graphics != null);
ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);
if (renderer == null) renderer = new ImageRenderer();
ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, fill.getContentType());
try {
renderer.loadImage(is, fill.getContentType());

View File

@ -24,11 +24,17 @@ import java.awt.geom.Rectangle2D;
import java.io.IOException;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.sl.usermodel.PictureShape;
import org.apache.poi.sl.usermodel.RectAlign;
public class DrawPictureShape extends DrawSimpleShape {
private static final POILogger LOG = POILogFactory.getLogger(DrawPictureShape.class);
private static final String WMF_IMAGE_RENDERER = "org.apache.poi.hwmf.draw.HwmfSLImageRenderer";
public DrawPictureShape(PictureShape<?,?> shape) {
super(shape);
}
@ -38,14 +44,11 @@ public class DrawPictureShape extends DrawSimpleShape {
PictureData data = getShape().getPictureData();
if(data == null) return;
ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);
if (renderer == null) renderer = new ImageRenderer();
Rectangle2D anchor = getAnchor(graphics, getShape());
Insets insets = getShape().getClipping();
try {
ImageRenderer renderer = getImageRenderer(graphics, data.getContentType());
renderer.loadImage(data.getData(), data.getContentType());
renderer.drawImage(graphics, anchor, insets);
} catch (IOException e) {
@ -54,6 +57,34 @@ public class DrawPictureShape extends DrawSimpleShape {
}
}
/**
* Returns an ImageRenderer for the PictureData
*
* @param graphics
* @return
*/
public static ImageRenderer getImageRenderer(Graphics2D graphics, String contentType) {
ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);
if (renderer != null) {
return renderer;
}
if (PictureType.WMF.contentType.equals(contentType)) {
try {
@SuppressWarnings("unchecked")
Class<? extends ImageRenderer> irc = (Class<? extends ImageRenderer>)
Thread.currentThread().getContextClassLoader().loadClass(WMF_IMAGE_RENDERER);
return irc.newInstance();
} catch (Exception e) {
// WMF image renderer is not on the classpath, continuing with BitmapRenderer
// although this doesn't make much sense ...
LOG.log(POILogger.ERROR, "WMF image renderer is not on the classpath - include poi-scratchpad jar!", e);
}
}
return new BitmapImageRenderer();
}
@Override
protected PictureShape<?,?> getShape() {
return (PictureShape<?,?>)shape;

View File

@ -98,6 +98,7 @@ public class DrawSimpleShape extends DrawShape {
// then stroke the shape outline
if(line != null) {
graphics.setPaint(line);
graphics.setStroke(stroke);
for(Outline o : elems){
if(o.getPath().isStroked()){
java.awt.Shape s = o.getOutline();

View File

@ -31,13 +31,12 @@ import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* For now this class renders only images supported by the javax.imageio.ImageIO
* framework. Subclasses can override this class to support other formats, for
* Classes can implement this interfaces to support other formats, for
* example, use Apache Batik to render WMF, PICT can be rendered using Apple QuickTime API for Java:
*
* <pre>
* <code>
* public class MyImageRendener extends ImageRendener {
* public class MyImageRendener implements ImageRendener {
* InputStream data;
*
* public boolean drawImage(Graphics2D graphics,Rectangle2D anchor,Insets clip) {
@ -79,127 +78,49 @@ import org.apache.poi.util.POILogger;
* </code>
* </pre>
*/
public class ImageRenderer {
private final static POILogger LOG = POILogFactory.getLogger(ImageRenderer.class);
protected BufferedImage img;
public interface ImageRenderer {
/**
* Load and buffer the image
*
* @param data the raw image stream
* @param contentType the content type
*/
public void loadImage(InputStream data, String contentType) throws IOException {
img = convertBufferedImage(ImageIO.read(data), contentType);
}
void loadImage(InputStream data, String contentType) throws IOException;
/**
* Load and buffer the image
*
* @param data the raw image stream
* @param data the raw image bytes
* @param contentType the content type
*/
public void loadImage(byte data[], String contentType) throws IOException {
img = convertBufferedImage(ImageIO.read(new ByteArrayInputStream(data)), contentType);
}
/**
* Add alpha channel to buffered image
*/
private static BufferedImage convertBufferedImage(BufferedImage img, String contentType) {
if (img == null) {
LOG.log(POILogger.WARN, "Content-type: "+contentType+" is not support. Image ignored.");
return null;
}
BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return bi;
}
/**
* @return the buffered image
*/
public BufferedImage getImage() {
return img;
}
void loadImage(byte data[], String contentType) throws IOException;
/**
* @return the dimension of the buffered image
*/
public Dimension getDimension() {
return (img == null)
? new Dimension(0,0)
: new Dimension(img.getWidth(),img.getHeight());
}
Dimension getDimension();
/**
* @param alpha the alpha [0..1] to be added to the image (possibly already containing an alpha channel)
*/
public void setAlpha(double alpha) {
if (img == null) return;
Dimension dim = getDimension();
BufferedImage newImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImg.createGraphics();
RescaleOp op = new RescaleOp(new float[]{1.0f, 1.0f, 1.0f, (float)alpha}, new float[]{0,0,0,0}, null);
g.drawImage(img, op, 0, 0);
g.dispose();
img = newImg;
}
void setAlpha(double alpha);
/**
* @return the image as buffered image
*/
BufferedImage getImage();
/**
* Render picture data into the supplied graphics
*
* @return true if the picture data was successfully rendered
*/
boolean drawImage(Graphics2D graphics, Rectangle2D anchor);
/**
* Render picture data into the supplied graphics
*
* @return true if the picture data was successfully rendered
*/
public boolean drawImage(
Graphics2D graphics,
Rectangle2D anchor) {
return drawImage(graphics, anchor, null);
}
/**
* Render picture data into the supplied graphics
*
* @return true if the picture data was successfully rendered
*/
public boolean drawImage(
Graphics2D graphics,
Rectangle2D anchor,
Insets clip) {
if (img == null) return false;
boolean isClipped = true;
if (clip == null) {
isClipped = false;
clip = new Insets(0,0,0,0);
}
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();
if (isClipped) graphics.clip(anchor.getBounds2D());
graphics.drawRenderedImage(img, at);
graphics.setClip(clipOld);
return true;
}
}
boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip);
}

View File

@ -0,0 +1,29 @@
/* ====================================================================
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.usermodel;
public interface GraphicalFrame<
S extends Shape<S,P>,
P extends TextParagraph<S,P,?>
> extends Shape<S,P>, PlaceableShape<S,P> {
/**
* @return a fallback representation as picture shape
*/
PictureShape<S,P> getFallbackPicture();
}

View File

@ -27,25 +27,26 @@ import org.apache.poi.POIXMLException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.draw.DrawNotImplemented;
import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.sl.usermodel.GraphicalFrame;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.util.Beta;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
/**
* @author Yegor Kozlov
*/
@Beta
@DrawNotImplemented
public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFShape, XSLFTextParagraph> {
public class XSLFGraphicFrame extends XSLFShape implements GraphicalFrame<XSLFShape, XSLFTextParagraph> {
private static final POILogger LOG = POILogFactory.getLogger(XSLFGraphicFrame.class);
/*package*/ XSLFGraphicFrame(CTGraphicalObjectFrame shape, XSLFSheet sheet){
super(shape,sheet);
}
@ -104,7 +105,7 @@ public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFSh
public void setRotation(double theta){
throw new IllegalArgumentException("Operation not supported");
}
/**
* Rotation angle in degrees
* <p>
@ -125,7 +126,7 @@ public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFSh
public void setFlipVertical(boolean flip){
throw new IllegalArgumentException("Operation not supported");
}
/**
* Whether the shape is horizontally flipped
*
@ -189,4 +190,30 @@ public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFSh
}
}
@Override
public XSLFPictureShape getFallbackPicture() {
String xquery =
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main'; "
+ "declare namespace mc='http://schemas.openxmlformats.org/markup-compatibility/2006' "
+ ".//mc:Fallback/*/p:pic"
;
XmlObject xo = selectProperty(XmlObject.class, xquery);
if (xo == null) {
return null;
}
CTGroupShape gs;
try {
gs = CTGroupShape.Factory.parse(xo.newDomNode());
} catch (XmlException e) {
LOG.log(POILogger.WARN, "Can't parse fallback picture stream of graphical frame", e);
return null;
}
if (gs.sizeOfPicArray() == 0) {
return null;
}
return new XSLFPictureShape(gs.getPicArray(0), getSheet());
}
}

View File

@ -257,7 +257,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
public Placeholder getPlaceholder() {
CTPlaceholder ph = getCTPlaceholder();
if (ph == null || !ph.isSetType()) {
if (ph == null || !(ph.isSetType() || ph.isSetIdx())) {
return null;
}
return Placeholder.lookupOoxml(ph.getType().intValue());

View File

@ -37,6 +37,7 @@ public class TestPPTX2PNG {
POIDataSamples samples = POIDataSamples.getSlideShowInstance();
String[] testFiles = {"alterman_security.ppt","alterman_security.pptx","KEY02.pptx","themes.pptx","backgrounds.pptx","layouts.pptx", "sample.pptx", "shapes.pptx",};
// String[] testFiles = {"41246-2.ppt","45543.ppt","53446.ppt","ParagraphStylesShorterThanCharStyles.ppt"};
String[] args = {
"-format", "null", // png,gif,jpg or null for test
"-slide", "-1", // -1 for all

View File

@ -100,7 +100,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
opt.setRecordId(EscherOptRecord.RECORD_ID);
_escherContainer.addChildRecord(opt);
EscherRecord anchor;
EscherRecord anchor;
if(isChild) {
anchor = new EscherChildAnchorRecord();
} else {
@ -155,7 +155,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
}
/**
* @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
* @return color of the line. If color is not set returns {@code null}
*/
public Color getLineColor(){
AbstractEscherOptRecord opt = getEscherOptRecord();
@ -164,7 +164,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
if(p != null && (p.getPropertyValue() & 0x8) == 0) return null;
Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
return clr == null ? Color.black : clr;
return clr == null ? null : clr;
}
/**
@ -187,7 +187,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
AbstractEscherOptRecord opt = getEscherOptRecord();
setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDCAPSTYLE, pen == LineCap.FLAT ? -1 : pen.nativeId);
}
/**
* Gets line dashing.
*
@ -417,7 +417,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
};
}
public DecorationShape getLineHeadDecoration(){
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWHEAD);
@ -428,7 +428,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
AbstractEscherOptRecord opt = getEscherOptRecord();
setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWHEAD, decoShape == null ? -1 : decoShape.nativeId);
}
public DecorationSize getLineHeadWidth(){
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWWIDTH);
@ -439,7 +439,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
AbstractEscherOptRecord opt = getEscherOptRecord();
setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWWIDTH, decoSize == null ? -1 : decoSize.nativeId);
}
public DecorationSize getLineHeadLength(){
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWLENGTH);
@ -450,7 +450,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
AbstractEscherOptRecord opt = getEscherOptRecord();
setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWLENGTH, decoSize == null ? -1 : decoSize.nativeId);
}
public DecorationShape getLineTailDecoration(){
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWHEAD);
@ -461,7 +461,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
AbstractEscherOptRecord opt = getEscherOptRecord();
setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWHEAD, decoShape == null ? -1 : decoShape.nativeId);
}
public DecorationSize getLineTailWidth(){
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWWIDTH);
@ -472,7 +472,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
AbstractEscherOptRecord opt = getEscherOptRecord();
setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWWIDTH, decoSize == null ? -1 : decoSize.nativeId);
}
public DecorationSize getLineTailLength(){
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWLENGTH);
@ -484,8 +484,8 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWLENGTH, decoSize == null ? -1 : decoSize.nativeId);
}
public LineDecoration getLineDecoration() {
return new LineDecoration() {
@ -514,7 +514,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
}
};
}
@Override
public Placeholder getPlaceholder() {
List<? extends Record> clRecords = getClientRecords();
@ -530,10 +530,10 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
return Placeholder.lookupNative(rtp.getPlaceholderId());
}
}
return null;
}
@Override
public void setPlaceholder(Placeholder placeholder) {
EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
@ -547,7 +547,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
// Placeholders can't be grouped
setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, (placeholder == null ? -1 : 262144));
HSLFEscherClientDataRecord clientData = getClientData(false);
if (placeholder == null) {
if (clientData != null) {
@ -560,7 +560,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
}
return;
}
if (clientData == null) {
clientData = getClientData(true);
}
@ -596,11 +596,11 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
} else {
phId = (byte)placeholder.nativeSlideId;
}
if (phId == -2) {
throw new HSLFException("Placeholder "+placeholder.name()+" not supported for this sheet type ("+sheet.getClass()+")");
}
switch (placeholder) {
case HEADER:
case FOOTER:
@ -637,7 +637,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
setLineColor(null);
return;
}
// TODO: handle PaintStyle
for (Object st : styles) {
if (st instanceof Number) {

View File

@ -270,7 +270,6 @@ public class HwmfGraphics {
* This methods gathers and sets the corresponding graphics transformations.
*/
public void updateWindowMapMode() {
GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();
Rectangle2D win = prop.getWindow();
HwmfMapMode mapMode = prop.getMapMode();
graphicsCtx.setTransform(initialAT);
@ -292,12 +291,14 @@ public class HwmfGraphics {
case MM_HIMETRIC:
case MM_LOENGLISH:
case MM_HIENGLISH:
case MM_TWIPS:
case MM_TWIPS: {
// TODO: to be validated ...
GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();
graphicsCtx.transform(gc.getNormalizingTransform());
graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale);
graphicsCtx.translate(-win.getX(), -win.getY());
break;
}
case MM_TEXT:
// TODO: to be validated ...
break;

View File

@ -0,0 +1,115 @@
/* ====================================================================
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.hwmf.draw;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.apache.poi.sl.draw.ImageRenderer;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.util.Units;
public class HwmfSLImageRenderer implements ImageRenderer {
HwmfPicture image = null;
double alpha = 0;
@Override
public void loadImage(InputStream data, String contentType) throws IOException {
if (!PictureData.PictureType.WMF.contentType.equals(contentType)) {
throw new IOException("Invalid picture type");
}
image = new HwmfPicture(data);
}
@Override
public void loadImage(byte[] data, String contentType) throws IOException {
if (!PictureData.PictureType.WMF.contentType.equals(contentType)) {
throw new IOException("Invalid picture type");
}
image = new HwmfPicture(new ByteArrayInputStream(data));
}
@Override
public Dimension getDimension() {
int width = 0, height = 0;
if (image != null) {
Dimension dim = image.getSize();
width = Units.pointsToPixel(dim.getWidth());
// keep aspect ratio for height
height = Units.pointsToPixel(dim.getHeight());
}
return new Dimension(width, height);
}
@Override
public void setAlpha(double alpha) {
this.alpha = alpha;
}
@Override
public BufferedImage getImage() {
if (image == null) {
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
}
Dimension dim = getDimension();
BufferedImage bufImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bufImg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
image.draw(g);
g.dispose();
if (alpha != 0) {
BufferedImage newImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
g = newImg.createGraphics();
RescaleOp op = new RescaleOp(new float[]{1.0f, 1.0f, 1.0f, (float)alpha}, new float[]{0,0,0,0}, null);
g.drawImage(bufImg, op, 0, 0);
g.dispose();
bufImg = newImg;
}
return bufImg;
}
@Override
public boolean drawImage(Graphics2D graphics, Rectangle2D anchor) {
return drawImage(graphics, anchor, null);
}
@Override
public boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip) {
if (image == null) {
return false;
} else {
image.draw(graphics, anchor);
return true;
}
}
}

View File

@ -339,7 +339,7 @@ public class HwmfMisc {
* The META_DIBCREATEPATTERNBRUSH record creates a Brush Object with a
* pattern specified by a DeviceIndependentBitmap (DIB) Object
*/
public static class WmfDibCreatePatternBrush implements HwmfRecord, HwmfImageRecord {
public static class WmfDibCreatePatternBrush implements HwmfRecord, HwmfImageRecord, HwmfObjectTableEntry {
private HwmfBrushStyle style;
@ -388,6 +388,11 @@ public class HwmfMisc {
@Override
public void draw(HwmfGraphics ctx) {
ctx.addObjectTableEntry(this);
}
@Override
public void applyObject(HwmfGraphics ctx) {
HwmfDrawProperties prop = ctx.getProperties();
prop.setBrushStyle(style);
prop.setBrushBitmap(getImage());

View File

@ -102,11 +102,11 @@ public class HwmfPicture {
try {
Rectangle2D wmfBounds = getBounds();
// scale output bounds to image bounds
ctx.translate(graphicsBounds.getX(), graphicsBounds.getY());
ctx.scale(graphicsBounds.getWidth()/wmfBounds.getWidth(), graphicsBounds.getHeight()/wmfBounds.getHeight());
ctx.translate(-wmfBounds.getX(), -wmfBounds.getY());
HwmfGraphics g = new HwmfGraphics(ctx, wmfBounds);
for (HwmfRecord r : records) {
for (HwmfRecord r : records) {
r.draw(g);
}
} finally {