-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.hslf.usermodel.PictureData;
+import org.apache.poi.hslf.blip.Bitmap;
+import org.apache.poi.util.POILogger;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
/**
* Background shape
*/
public class Background extends Shape {
- protected Background(EscherContainerRecord escherRecord, Shape parent){
+ protected Background(EscherContainerRecord escherRecord, Shape parent) {
super(escherRecord, parent);
}
- protected EscherContainerRecord createSpContainer(boolean isChild){
+ protected EscherContainerRecord createSpContainer(boolean isChild) {
return null;
}
+ public void draw(Graphics2D graphics) {
+ Fill f = getFill();
+ Dimension pg = getSheet().getSlideShow().getPageSize();
+ Rectangle anchor = new Rectangle(0, 0, pg.width, pg.height);
+ switch (f.getFillType()) {
+ case Fill.FILL_SOLID:
+ Color color = f.getForegroundColor();
+ graphics.setPaint(color);
+ graphics.fill(anchor);
+ break;
+ case Fill.FILL_PICTURE:
+ PictureData data = f.getPictureData();
+ if (data instanceof Bitmap) {
+ BufferedImage img = null;
+ try {
+ img = ImageIO.read(new ByteArrayInputStream(data.getData()));
+ } catch (Exception e) {
+ logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + data.getType());
+ return;
+ }
+ Image scaledImg = img.getScaledInstance(anchor.width, anchor.height, Image.SCALE_SMOOTH);
+ graphics.drawImage(scaledImg, anchor.x, anchor.y, null);
+
+ }
+ break;
+ default:
+ logger.log(POILogger.WARN, "unsuported fill type: " + f.getFillType());
+ break;
+ }
+ }
}
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.record.Document;
import org.apache.poi.hslf.blip.Bitmap;
+import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.POILogger;
import javax.imageio.ImageIO;
import java.awt.geom.Rectangle2D;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Arrays;
//set default properties for a picture
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
- setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736);
+ setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x800080);
//another weird feature of powerpoint: for picture id we must add 0x4000.
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
return null;
}
+ /**
+ * Name of this picture.
+ *
+ * @return name of this picture
+ */
+ public String getPictureName(){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ EscherComplexProperty prop = (EscherComplexProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME);
+ String name = null;
+ if(prop != null){
+ try {
+ name = new String(prop.getComplexData(), "UTF-16LE");
+ int idx = name.indexOf('\u0000');
+ return idx == -1 ? name : name.substring(0, idx);
+ } catch (UnsupportedEncodingException e){
+ throw new HSLFException(e);
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Name of this picture.
+ *
+ * @param name of this picture
+ */
+ public void setPictureName(String name){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ try {
+ byte[] data = (name + '\u0000').getBytes("UTF-16LE");
+ EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.BLIP__BLIPFILENAME, false, data);
+ opt.addEscherProperty(prop);
+ } catch (UnsupportedEncodingException e){
+ throw new HSLFException(e);
+ }
+ }
+
/**
* By default set the orininal image size
*/
Image scaledImg = img.getScaledInstance(anchor.width, anchor.height, Image.SCALE_SMOOTH);
graphics.drawImage(scaledImg, anchor.x, anchor.y, null);
} else {
- logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + data.getType());
+ logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + (data == null ? "NA" : data.getClass().getName()));
}
}
}
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
anchor = new java.awt.Rectangle();
- anchor = new Rectangle2D.Float(
- (float)rec.getDx1()*POINT_DPI/MASTER_DPI,
- (float)rec.getDy1()*POINT_DPI/MASTER_DPI,
- (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
- (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
- );
+ if(rec == null){
+ logger.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found");
+ EscherClientAnchorRecord clrec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
+ anchor = new java.awt.Rectangle();
+ anchor = new Rectangle2D.Float(
+ (float)clrec.getCol1()*POINT_DPI/MASTER_DPI,
+ (float)clrec.getFlag()*POINT_DPI/MASTER_DPI,
+ (float)(clrec.getDx1()-clrec.getCol1())*POINT_DPI/MASTER_DPI,
+ (float)(clrec.getRow1()-clrec.getFlag())*POINT_DPI/MASTER_DPI
+ );
+ } else {
+ anchor = new Rectangle2D.Float(
+ (float)rec.getDx1()*POINT_DPI/MASTER_DPI,
+ (float)rec.getDy1()*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
+ );
+ }
}
else {
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
* @return escher property or <code>null</code> if not found.
*/
public static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
- for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
+ if(opt != null) for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
{
EscherProperty prop = (EscherProperty) iterator.next();
if (prop.getPropertyNumber() == propId)
EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
Rectangle2D.Float anchor = new Rectangle2D.Float();
- anchor.x = (float)clientAnchor.getCol1()*POINT_DPI/MASTER_DPI;
- anchor.y = (float)clientAnchor.getFlag()*POINT_DPI/MASTER_DPI;
- anchor.width = (float)(clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ;
- anchor.height = (float)(clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI;
+ if(clientAnchor == null){
+ logger.log(POILogger.WARN, "EscherClientAnchorRecord was not found for the shape group");
+ EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(spContainer, EscherChildAnchorRecord.RECORD_ID);
+ anchor = new Rectangle2D.Float(
+ (float)rec.getDx1()*POINT_DPI/MASTER_DPI,
+ (float)rec.getDy1()*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI,
+ (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI
+ );
+ } else {
+ anchor.x = (float)clientAnchor.getCol1()*POINT_DPI/MASTER_DPI;
+ anchor.y = (float)clientAnchor.getFlag()*POINT_DPI/MASTER_DPI;
+ anchor.width = (float)(clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ;
+ anchor.height = (float)(clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI;
+ }
return anchor;
}
package org.apache.poi.hslf.model;\r
\r
\r
+import org.apache.poi.util.POILogger;\r
+import org.apache.poi.util.POILogFactory;\r
+\r
import java.awt.*;\r
import java.awt.geom.Rectangle2D;\r
\r
* @author Yegor Kozlov\r
*/\r
public class ShapePainter {\r
+ protected static POILogger logger = POILogFactory.getLogger(ShapePainter.class);\r
\r
public static void paint(SimpleShape shape, Graphics2D graphics){\r
Rectangle2D anchor = shape.getAnchor2D();\r
//fill\r
Color fillColor = shape.getFill().getForegroundColor();\r
if (fillColor != null) {\r
+ //TODO: implement gradient and texture fill patterns\r
graphics.setPaint(fillColor);\r
graphics.fill(outline);\r
}\r
if (lineColor != null){\r
graphics.setPaint(lineColor);\r
float width = (float)shape.getLineWidth();\r
+ if(width == 0) width = 0.75f;\r
+\r
int dashing = shape.getLineDashing();\r
//TODO: implement more dashing styles\r
float[] dashptrn = null;\r
switch(dashing){\r
+ case Line.PEN_SOLID:\r
+ dashptrn = null;\r
+ break;\r
case Line.PEN_PS_DASH:\r
- dashptrn = new float[]{2, 2};\r
+ dashptrn = new float[]{width, width};\r
+ break;\r
+ case Line.PEN_DOTGEL:\r
+ dashptrn = new float[]{width*4, width*3};\r
+ break;\r
+ default:\r
+ logger.log(POILogger.WARN, "unsupported dashing: " + dashing);\r
+ dashptrn = new float[]{width, width};\r
break;\r
}\r
\r
default:
return null;
}
- return null;
-
}
prop = getStyleAttribute(txtype, level, name, isCharacter);
}
_shape = shape;\r
}\r
\r
+ /**\r
+ * Convert the underlying set of rich text runs into java.text.AttributedString\r
+ */\r
public AttributedString getAttributedString(TextRun txrun){\r
String text = txrun.getText();\r
AttributedString at = new AttributedString(text);\r
return at;\r
}\r
\r
- protected RichTextRun getRichTextRunAt(int pos){\r
- RichTextRun[] rt = _shape.getTextRun().getRichTextRuns();\r
- for (int i = 0; i < rt.length; i++) {\r
- int start = rt[i].getStartIndex();\r
- int end = rt[i].getEndIndex();\r
- if(pos >= start && pos < end) return rt[i];\r
- }\r
- return null;\r
- }\r
-\r
public void paint(Graphics2D graphics){\r
TextRun run = _shape.getTextRun();\r
if (run == null) return;\r
boolean prStart = text.charAt(startIndex) == '\n';\r
if(prStart) measurer.setPosition(startIndex++);\r
\r
- RichTextRun rt = getRichTextRunAt(startIndex);\r
+ RichTextRun rt = run.getRichTextRunAt(startIndex == text.length() ? (startIndex-1) : startIndex);\r
if(rt == null) {\r
logger.log(POILogger.WARN, "RichTextRun not found at pos" + startIndex + "; text.length: " + text.length());\r
break;\r
}\r
int endIndex = measurer.getPosition();\r
\r
+ float lineHeight = (float)textLayout.getBounds().getHeight();\r
+ int linespacing = rt.getLineSpacing();\r
+ if(linespacing == 0) linespacing = 100;\r
+\r
TextElement el = new TextElement();\r
- el.ascent = textLayout.getAscent();\r
- el._startIndex = startIndex;\r
- el._endIndex = endIndex;\r
+ if(linespacing >= 0){\r
+ el.ascent = textLayout.getAscent()*linespacing/100;\r
+ } else {\r
+ el.ascent = -linespacing*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+ }\r
+\r
el._align = rt.getAlignment();\r
el._text = textLayout;\r
el._textOffset = rt.getTextOffset();\r
\r
- textHeight += textLayout.getAscent();\r
- if (prStart || startIndex == 0){\r
- int spaceBefore = rt.getSpaceBefore();\r
- if (spaceBefore != 0) {\r
- float val = (float)(textLayout.getAscent() + textLayout.getDescent())* spaceBefore/100;\r
- textHeight += val;\r
- el.ascent += val;\r
+ if (prStart){\r
+ int sp = rt.getSpaceBefore();\r
+ float spaceBefore;\r
+ if(sp >= 0){\r
+ spaceBefore = lineHeight * sp/100;\r
+ } else {\r
+ spaceBefore = -sp*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+ }\r
+ el.ascent += spaceBefore;\r
+ }\r
+\r
+ float descent;\r
+ if(linespacing >= 0){\r
+ descent = (textLayout.getDescent() + textLayout.getLeading())*linespacing/100;\r
+ } else {\r
+ descent = -linespacing*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+ }\r
+ if (prStart){\r
+ int sp = rt.getSpaceAfter();\r
+ float spaceAfter;\r
+ if(sp >= 0){\r
+ spaceAfter = lineHeight * sp/100;\r
+ } else {\r
+ spaceAfter = -sp*Shape.POINT_DPI/Shape.MASTER_DPI;\r
}\r
+ el.ascent += spaceAfter;\r
}\r
+ el.descent = descent;\r
+\r
+ textHeight += el.ascent + el.descent;\r
\r
if(rt.isBullet() && (prStart || startIndex == 0)){\r
it.setIndex(startIndex);\r
\r
AttributedString bat = new AttributedString(Character.toString(rt.getBulletChar()), it.getAttributes());\r
- int bulletSize = rt.getBulletSize();\r
- if (bulletSize != -1){\r
- Float sz = (Float)bat.getIterator().getAttribute(TextAttribute.SIZE);\r
- if(sz != null) bat.addAttribute(TextAttribute.SIZE, new Float(sz.floatValue()*bulletSize/100));\r
- }\r
+ Color clr = rt.getBulletColor();\r
+ if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);\r
\r
TextLayout bulletLayout = new TextLayout(bat.getIterator(), graphics.getFontRenderContext());\r
if(text.substring(startIndex, endIndex).length() > 1){\r
el._bulletOffset = rt.getBulletOffset();\r
}\r
}\r
-\r
-\r
- float descent = textLayout.getDescent();\r
- int lineSpacing = rt.getLineSpacing();\r
- if(lineSpacing != 0) descent += textLayout.getLeading()*lineSpacing/100;\r
- else descent = textLayout.getLeading();\r
- textHeight += descent;\r
-\r
- el.descent = descent;\r
- if (prStart){\r
- int spaceAfter = rt.getSpaceAfter();\r
- if (spaceAfter != 0) {\r
- float val = (float)(textLayout.getAscent() + textLayout.getDescent())* spaceAfter/100;\r
- textHeight += val;\r
- el.descent += val;\r
- }\r
- }\r
-\r
lines.add(el);\r
}\r
\r
public TextLayout _bullet;\r
public int _bulletOffset;\r
public int _align;\r
- public int _startIndex;\r
- public int _endIndex;\r
- public float _spacing;\r
public float ascent, descent;\r
}\r
}\r
public Hyperlink[] getHyperlinks(){
return Hyperlink.find(this);
}
+
+ /**
+ * Fetch RichTextRun at a given position
+ *
+ * @param pos 0-based index in the text
+ * @return RichTextRun or null if not found
+ */
+ public RichTextRun getRichTextRunAt(int pos){
+ for (int i = 0; i < _rtRuns.length; i++) {
+ int start = _rtRuns[i].getStartIndex();
+ int end = _rtRuns[i].getEndIndex();
+ if(pos >= start && pos < end) return _rtRuns[i];
+ }
+ return null;
+ }
+
}
* Returns the bullet color
*/
public Color getBulletColor() {
- int rgb = getCharTextPropVal("bullet.color");
- if (rgb >= 0x8000000) {
- int idx = rgb % 0x8000000;
+ int rgb = getParaTextPropVal("bullet.color");
+ if(rgb == -1) return getFontColor();
+
+ int cidx = rgb >> 24;
+ if (rgb % 0x1000000 == 0){
ColorSchemeAtom ca = parentRun.getSheet().getColorScheme();
- if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
+ if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx);
}
-
Color tmp = new Color(rgb, true);
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
}
assertTrue(pdata instanceof WMF);
assertEquals(Picture.WMF, pdata.getType());
}
+
+ public void testGetPictureName() throws Exception {
+ SlideShow ppt = new SlideShow(new HSLFSlideShow(new File(cwd, "ppt_with_png.ppt").getPath()));
+ Slide slide = ppt.getSlides()[0];
+
+ Picture p = (Picture)slide.getShapes()[0]; //the first slide contains JPEG
+ assertEquals("test", p.getPictureName());
+ }
+
+ public void testSetPictureName() throws Exception {
+ SlideShow ppt = new SlideShow();
+
+ Slide slide = ppt.createSlide();
+ File img = new File(cwd, "tomcat.png");
+ int idx = ppt.addPicture(img, Picture.PNG);
+ Picture pict = new Picture(idx);
+ pict.setPictureName("tomcat.png");
+ slide.addShape(pict);
+
+ //serialize and read again
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ppt.write(out);
+ out.close();
+
+ ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
+
+ Picture p = (Picture)ppt.getSlides()[0].getShapes()[0];
+ assertEquals("tomcat.png", p.getPictureName());
+ }
}