git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1724897 13f79535-47bb-0310-9956-ffa450edef68pull/28/head
@@ -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 | |||
*/ | |||
public boolean drawImage( | |||
Graphics2D graphics, | |||
Rectangle2D anchor) { | |||
return drawImage(graphics, anchor, null); | |||
} | |||
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, | |||
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 { |