]> source.dussan.org Git - poi.git/commitdiff
more improvements in slide rendering
authorYegor Kozlov <yegor@apache.org>
Sun, 20 Apr 2008 11:17:48 +0000 (11:17 +0000)
committerYegor Kozlov <yegor@apache.org>
Sun, 20 Apr 2008 11:17:48 +0000 (11:17 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@649911 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hslf/model/Background.java
src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java
src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java
src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java

index 4906922a824f37bcd6200e99e4653c27a4002bda..e2718f6acaa5551bdad9f5bf70de4e36cac01dee 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    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
@@ -27,12 +34,42 @@ import org.apache.poi.ddf.EscherContainerRecord;
  */
 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;
+        }
+    }
 }
index ed642791f1db67475860de85e49b85b142899db1..e10986966bf85532c169a7aa8a87da1350175ec2 100644 (file)
@@ -21,6 +21,7 @@ import org.apache.poi.hslf.usermodel.PictureData;
 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;
@@ -29,6 +30,7 @@ import java.awt.*;
 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;
 
@@ -129,7 +131,7 @@ public class Picture extends SimpleShape {
 
         //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);
@@ -193,6 +195,43 @@ public class Picture extends SimpleShape {
         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
      */
@@ -219,7 +258,7 @@ public class Picture extends SimpleShape {
             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()));
         }
     }
 }
index 2aed43f47d2f80453a04c1cb44bf47f10001c6d4..d4975df429b6764a2cc78561c9596e3855ea2a4b 100644 (file)
@@ -166,12 +166,24 @@ public abstract class Shape {
         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);
@@ -245,7 +257,7 @@ public abstract class Shape {
      * @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)
index 2c146817ed490b45a3305d84317657beff513d46..a0fbb114dc57a276cde1847fc71c44d6165f2c89 100644 (file)
@@ -236,10 +236,21 @@ public class ShapeGroup extends Shape{
         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;
     }
index 4e3054569b247c86c23a5f9ae27e1c226afa7656..b50b4f7caf6d1b0a6ec4fda47a0ccb067a75d140 100755 (executable)
@@ -17,6 +17,9 @@
 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
@@ -26,6 +29,7 @@ import java.awt.geom.Rectangle2D;
  * @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
@@ -59,6 +63,7 @@ public class ShapePainter {
         //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
@@ -68,12 +73,24 @@ public class ShapePainter {
         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
index 2a8467437b4c6cb6c4a90c0bbea5d24e0da44bce..26870dbdbbbdeaf9a81cf1ed7bb7152a640f9f83 100644 (file)
@@ -101,8 +101,6 @@ public class SlideMaster extends MasterSheet {
                     default:
                         return null;
                 }
-                return null;
-
             }
             prop = getStyleAttribute(txtype, level, name, isCharacter);
         }
index c4eac3d066ed361e17a3e1733d707a884cecaec7..7d23c7cfb8ee6310d3a3d6cd2043fe4970b092fd 100755 (executable)
@@ -44,6 +44,9 @@ public class TextPainter {
         _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
@@ -70,16 +73,6 @@ public class TextPainter {
         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
@@ -106,7 +99,7 @@ public class TextPainter {
             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
@@ -133,33 +126,58 @@ public class TextPainter {
             }\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
@@ -167,24 +185,6 @@ public class TextPainter {
                     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
@@ -242,9 +242,6 @@ public class TextPainter {
         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
index e425b83f18328640d649dd3c38cd8eb7cf77dec5..2f77ac5ffa2c044d8796be07c330aedf10563127 100644 (file)
@@ -639,4 +639,20 @@ public class TextRun
     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;
+    }
+
 }
index c58979757e3fbfe181a68f9de1bd6cb5cfbc53df..2a09f2224c3dfa9a4103981838b76ab431215c77 100644 (file)
@@ -642,13 +642,14 @@ public class RichTextRun {
      * 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());
     }
index 797f97cda729227636f96f6f546bae8aad8df4e3..78458f0630d291cacef63767dab49d13d90c804b 100644 (file)
@@ -437,4 +437,33 @@ public class TestPictures extends TestCase{
         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());
+    }
 }