mirror of https://github.com/apache/poi.git
#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:
parent
0ba83f7683
commit
50d98918d9
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue