diff options
author | Andreas Beeker <kiwiwings@apache.org> | 2020-12-17 23:42:26 +0000 |
---|---|---|
committer | Andreas Beeker <kiwiwings@apache.org> | 2020-12-17 23:42:26 +0000 |
commit | bfade7c591a7ddb8eda643e4fb4932f7f8bad6a4 (patch) | |
tree | 20fe19f553260c1a08c7b1b41fa76359cca5576e /src/ooxml | |
parent | fcc808d17db2c61e9f4d472ef07b3c4468eb6da6 (diff) | |
download | poi-bfade7c591a7ddb8eda643e4fb4932f7f8bad6a4.tar.gz poi-bfade7c591a7ddb8eda643e4fb4932f7f8bad6a4.zip |
#64876 - Unable to convert pptx to pdf
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1884578 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/ooxml')
5 files changed, 1166 insertions, 12 deletions
diff --git a/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFShape.java b/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFShape.java index 0427817fdd..2f22ab805f 100644 --- a/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFShape.java +++ b/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFShape.java @@ -28,6 +28,8 @@ import java.util.Collection; import java.util.List; import java.util.Map.Entry; +import com.microsoft.schemas.office.visio.x2012.main.ShapeSheetType; +import com.microsoft.schemas.office.visio.x2012.main.TextType; import org.apache.poi.ooxml.POIXMLException; import org.apache.poi.util.Internal; import org.apache.poi.xdgf.exceptions.XDGFException; @@ -37,9 +39,6 @@ import org.apache.poi.xdgf.usermodel.section.XDGFSection; import org.apache.poi.xdgf.usermodel.shape.ShapeVisitor; import org.apache.poi.xdgf.usermodel.shape.exceptions.StopVisitingThisBranch; -import com.microsoft.schemas.office.visio.x2012.main.ShapeSheetType; -import com.microsoft.schemas.office.visio.x2012.main.TextType; - /** * A shape is a collection of Geometry Visualization, Format, Text, Images, and * Shape Data in a Drawing Page. @@ -723,7 +722,6 @@ public class XDGFShape extends XDGFSheet { float lineWeight = getLineWeight().floatValue(); int cap; int join = BasicStroke.JOIN_MITER; - float miterlimit = 10.0f; switch (getLineCap()) { case 0: @@ -826,7 +824,7 @@ public class XDGFShape extends XDGFSheet { } } - return new BasicStroke(lineWeight, cap, join, miterlimit, dash, 0); + return new BasicStroke(lineWeight, cap, join, 10, dash, 0); } // diff --git a/src/ooxml/java/org/apache/poi/xslf/util/DummyFormat.java b/src/ooxml/java/org/apache/poi/xslf/util/DummyFormat.java new file mode 100644 index 0000000000..8079ac9acb --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xslf/util/DummyFormat.java @@ -0,0 +1,49 @@ +package org.apache.poi.xslf.util; + +import java.awt.Graphics2D; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +public class DummyFormat implements OutputFormat { + + private final ByteArrayOutputStream bos; + private final DummyGraphics2d dummy2d; + + public DummyFormat() { + try { + bos = new ByteArrayOutputStream(); + dummy2d = new DummyGraphics2d(new PrintStream(bos, true, StandardCharsets.UTF_8.name())); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + @Override + public Graphics2D addSlide(double width, double height) throws IOException { + bos.reset(); + return dummy2d; + } + + @Override + public void writeSlide(MFProxy proxy, File outFile) throws IOException { + try (FileOutputStream fos = new FileOutputStream(outFile)) { + bos.writeTo(fos); + bos.reset(); + } + } + + @Override + public void writeDocument(MFProxy proxy, File outFile) throws IOException { + + } + + @Override + public void close() throws IOException { + bos.reset(); + } +} diff --git a/src/ooxml/java/org/apache/poi/xslf/util/DummyGraphics2d.java b/src/ooxml/java/org/apache/poi/xslf/util/DummyGraphics2d.java new file mode 100644 index 0000000000..281f4129d5 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xslf/util/DummyGraphics2d.java @@ -0,0 +1,1029 @@ +/* ==================================================================== + 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.xslf.util; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.io.PrintStream; +import java.text.AttributedCharacterIterator; +import java.text.AttributedCharacterIterator.Attribute; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +import org.apache.poi.util.Internal; + +public class DummyGraphics2d extends Graphics2D { + private BufferedImage bufimg; + private final Graphics2D g2D; + private final PrintStream log; + + public DummyGraphics2d() { + this(System.out); + } + + public DummyGraphics2d(PrintStream log) { + bufimg = new BufferedImage(1000, 1000, 2); + g2D = (Graphics2D)bufimg.getGraphics(); + this.log = log; + } + + public DummyGraphics2d(PrintStream log, Graphics2D g2D) { + this.g2D = g2D; + this.log = log; + } + + public void addRenderingHints(Map<?,?> hints) { + String l = + "addRenderingHinds(Map):" + + "\n hints = " + hints; + log.println( l ); + g2D.addRenderingHints( hints ); + } + + public void clip(Shape s) { + String l = + "clip(Shape):" + + "\n s = " + s; + log.println( l ); + g2D.clip( s ); + } + + private void pathToString(StringBuilder sb, Path2D p) { + sb.append("Path2D p = new Path2D.Double("+p.getWindingRule()+");\n"); + double[] coords = new double[6]; + + for (PathIterator pi = p.getPathIterator(null); !pi.isDone(); pi.next()) { + // The type will be SEG_LINETO, SEG_MOVETO, or SEG_CLOSE + // Because the Area is composed of straight lines + switch (pi.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + sb.append("p.moveTo("+coords[0]+","+coords[1]+");\n"); + break; + case PathIterator.SEG_LINETO: + sb.append("p.lineTo("+coords[0]+","+coords[1]+");\n"); + break; + case PathIterator.SEG_QUADTO: + sb.append("p.quadTo("+coords[0]+","+coords[1]+","+coords[2]+","+coords[3]+");\n"); + break; + case PathIterator.SEG_CUBICTO: + sb.append("p.curveTo("+coords[0]+","+coords[1]+","+coords[2]+","+coords[3]+","+coords[4]+","+coords[5]+");\n"); + break; + case PathIterator.SEG_CLOSE: + sb.append("p.closePath();\n"); + break; + } + } + } + + public void draw(Shape s) { + if (s instanceof Path2D) { + StringBuilder sb = new StringBuilder(); + pathToString(sb, (Path2D)s); + sb.append("g.draw(p);"); + log.println( sb.toString() ); + } else { + log.println( "g.draw("+ s + ")" ); + } + g2D.draw( s ); + } + + public void drawGlyphVector(GlyphVector g, float x, float y) { + String l = + "drawGlyphVector(GlyphVector, float, float):" + + "\n g = " + g + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.drawGlyphVector( g, x, y ); + } + + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { + String l = + "drawImage(BufferedImage, BufferedImageOp, x, y):" + + "\n img = " + img + + "\n op = " + op + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.drawImage( img, op, x, y ); + } + + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { + String l = + "drawImage(Image,AfflineTransform,ImageObserver):" + + "\n img = " + img + + "\n xform = " + xform + + "\n obs = " + obs; + log.println( l ); + return g2D.drawImage( img, xform, obs ); + } + + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + String l = + "drawRenderableImage(RenderableImage, AfflineTransform):" + + "\n img = " + img + + "\n xform = " + xform; + log.println( l ); + g2D.drawRenderableImage( img, xform ); + } + + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + String l = + "drawRenderedImage(RenderedImage, AffineTransform):" + + "\n img = " + img + + "\n xform = " + xform; + log.println( l ); + g2D.drawRenderedImage( img, xform ); + } + + public void drawString(String s, float x, float y) { + String l = + "drawString(s,x,y):" + + "\n s = " + s + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.drawString( s, x, y ); + } + + public void fill(Shape s) { + if (s instanceof Path2D) { + StringBuilder sb = new StringBuilder(); + pathToString(sb, (Path2D)s); + sb.append("g.fill(p);"); + log.println( sb.toString() ); + } else { + log.println( "g.fill("+ s + ")" ); + } + g2D.fill( s ); + } + + public Color getBackground() { + log.println( "getBackground():" ); + return g2D.getBackground(); + } + + public Composite getComposite() { + log.println( "getComposite():" ); + return g2D.getComposite(); + } + + public GraphicsConfiguration getDeviceConfiguration() { + log.println( "getDeviceConfiguration():" ); + return g2D.getDeviceConfiguration(); + } + + public FontRenderContext getFontRenderContext() { + log.println( "getFontRenderContext():" ); + return g2D.getFontRenderContext(); + } + + public Paint getPaint() { + log.println( "getPaint():" ); + return g2D.getPaint(); + } + + public Object getRenderingHint(RenderingHints.Key hintKey) { + log.println( "getRenderingHint(\""+hintKey+"\")" ); + return g2D.getRenderingHint( hintKey ); + } + + public RenderingHints getRenderingHints() { + log.println( "getRenderingHints():" ); + return g2D.getRenderingHints(); + } + + public Stroke getStroke() { + log.println( "getStroke():" ); + return g2D.getStroke(); + } + + public AffineTransform getTransform() { + log.println( "getTransform():" ); + return g2D.getTransform(); + } + + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { + String l = + "hit(Rectangle, Shape, onStroke):" + + "\n rect = " + rect + + "\n s = " + s + + "\n onStroke = " + onStroke; + log.println( l ); + return g2D.hit( rect, s, onStroke ); + } + + public void rotate(double theta) { + String l = + "rotate(theta):" + + "\n theta = " + theta; + log.println( l ); + g2D.rotate( theta ); + } + + public void rotate(double theta, double x, double y) { + String l = + "rotate(double,double,double):" + + "\n theta = " + theta + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.rotate( theta, x, y ); + } + + public void scale(double sx, double sy) { + log.println( "g.scale("+sx+","+sy+");" ); + g2D.scale( sx, sy ); + } + + public void setBackground(Color color) { + log.println(String.format(Locale.ROOT, "setBackground(new Color(0x%08X))", color.getRGB())); + g2D.setBackground( color ); + } + + private static final String[] COMPOSITE_RULES = { + "CLEAR", "SRC", "SRC_OVER", "DST_OVER", "SRC_IN", "DST_IN", "SRC_OUT", "DST_OUT", "DST", "SRC_ATOP", "DST_ATOP", "XOR" + }; + + public void setComposite(Composite comp) { + String l = "g.setComposite("; + if (comp instanceof AlphaComposite) { + AlphaComposite ac = (AlphaComposite)comp; + l += "AlphaComposite.getInstance(AlphaComposite." + + COMPOSITE_RULES[Math.max(0,Math.min(COMPOSITE_RULES.length-1,ac.getRule()))] + + ", " + ac.getAlpha() + "f));"; + } else { + l += comp.toString() + ");"; + } + log.println( l ); + g2D.setComposite( comp ); + } + + public void setPaint( Paint paint ) { + String l = "g.setPaint("; + if (paint instanceof Color) { + l += String.format(Locale.ROOT, "new Color(0x%08X));", ((Color)paint).getRGB()); + } else { + l += paint.toString() + ");"; + } + log.println( l ); + g2D.setPaint( paint ); + } + + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { + log.println( "g.setRenderingHint("+mapHint(hintKey)+", " + mapHint(hintValue) + ");" ); + g2D.setRenderingHint( hintKey, hintValue ); + } + + + private static String mapHint(Object hint) { + if (hint == null) { + return "null"; + } + if (hint instanceof AffineTransform) { + return mapTransform((AffineTransform) hint); + } + for (int i=0; i<HINTS.length; i+=2) { + if (hint == HINTS[i]) { + return (String)HINTS[i+1]; + } + } + return "\"" + hint.toString() + "\""; + } + + + public void setRenderingHints(Map<?,?> hints) { + String l = + "setRenderingHints(Map):" + + "\n hints = " + hints; + log.println( l ); + g2D.setRenderingHints( hints ); + } + + public void setStroke(Stroke s) { + String l; + if (s instanceof BasicStroke) { + BasicStroke bs = (BasicStroke)s; + String cap = new String[]{"BUTT","ROUND","SQUARE"}[bs.getEndCap()]; + String join = new String[]{"MITER","ROUND","BEVEL"}[bs.getLineJoin()]; + l = "g.setStroke(new BasicStroke(" + bs.getLineWidth() + "f, BasicStroke.CAP_" + cap + ", BasicStroke.JOIN_" + join + ", " + + bs.getMiterLimit() + "f, " + Arrays.toString(bs.getDashArray()) + ", " + bs.getDashPhase() + "f));"; + } else { + l = "g.setStroke(" + s + ");"; + } + log.println( l ); + g2D.setStroke( s ); + } + + private static String mapTransform(AffineTransform tx) { + return tx.isIdentity() ? "new AffineTransform()" + : "new AffineTransform("+tx.getScaleX()+"f,"+tx.getShearY()+"f,"+tx.getShearX()+"f,"+tx.getScaleY()+"f,"+tx.getTranslateX()+"f,"+tx.getTranslateY()+"f)"; + } + + public void setTransform(AffineTransform Tx) { + log.println( "g.setTransform("+mapTransform(Tx)+");" ); + g2D.setTransform( Tx ); + } + + public void shear(double shx, double shy) { + String l = + "shear(shx, dhy):" + + "\n shx = " + shx + + "\n shy = " + shy; + log.println( l ); + g2D.shear( shx, shy ); + } + + public void transform(AffineTransform Tx) { + String l = + "transform(AffineTransform):" + + "\n Tx = " + Tx; + log.println( l ); + g2D.transform( Tx ); + } + + public void translate(double tx, double ty) { + String l = + "translate(double, double):" + + "\n tx = " + tx + + "\n ty = " + ty; + log.println( l ); + g2D.translate( tx, ty ); + } + + public void clearRect(int x, int y, int width, int height) { + String l = + "clearRect(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + g2D.clearRect( x, y, width, height ); + } + + public void clipRect(int x, int y, int width, int height) { + String l = + "clipRect(int, int, int, int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "height = " + height; + log.println( l ); + g2D.clipRect( x, y, width, height ); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + String l = + "copyArea(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + g2D.copyArea( x, y, width, height, dx, dy ); + } + + public Graphics create() { + log.println( "create():" ); + return g2D.create(); + } + + public Graphics create(int x, int y, int width, int height) { + String l = + "create(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + return g2D.create( x, y, width, height ); + } + + public void dispose() { + log.println( "dispose():" ); + g2D.dispose(); + } + + public void draw3DRect(int x, int y, int width, int height, boolean raised) { + String l = + "draw3DRect(int,int,int,int,boolean):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height + + "\n raised = " + raised; + log.println( l ); + g2D.draw3DRect( x, y, width, height, raised ); + } + + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + String l = + "drawArc(int,int,int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height + + "\n startAngle = " + startAngle + + "\n arcAngle = " + arcAngle; + log.println( l ); + g2D.drawArc( x, y, width, height, startAngle, arcAngle ); + } + + public void drawBytes(byte[] data, int offset, int length, int x, int y) { + String l = + "drawBytes(byte[],int,int,int,int):" + + "\n data = " + Arrays.toString(data) + + "\n offset = " + offset + + "\n length = " + length + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.drawBytes( data, offset, length, x, y ); + } + + public void drawChars(char[] data, int offset, int length, int x, int y) { + String l = + "drawChars(data,int,int,int,int):" + + "\n data = " + Arrays.toString(data) + + "\n offset = " + offset + + "\n length = " + length + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.drawChars( data, offset, length, x, y ); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { + String l = + "drawImage(Image,int,int,int,int,int,int,int,int,ImageObserver):" + + "\n img = " + img + + "\n dx1 = " + dx1 + + "\n dy1 = " + dy1 + + "\n dx2 = " + dx2 + + "\n dy2 = " + dy2 + + "\n sx1 = " + sx1 + + "\n sy1 = " + sy1 + + "\n sx2 = " + sx2 + + "\n sy2 = " + sy2 + + "\n observer = " + observer; + log.println( l ); + return g2D.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer ); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { + String l = + "drawImage(Image,int,int,int,int,int,int,int,int,Color,ImageObserver):" + + "\n img = " + img + + "\n dx1 = " + dx1 + + "\n dy1 = " + dy1 + + "\n dx2 = " + dx2 + + "\n dy2 = " + dy2 + + "\n sx1 = " + sx1 + + "\n sy1 = " + sy1 + + "\n sx2 = " + sx2 + + "\n sy2 = " + sy2 + + "\n bgcolor = " + bgcolor + + "\n observer = " + observer; + log.println( l ); + return g2D.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer ); + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + String l = + "drawImage(Image,int,int,Color,ImageObserver):" + + "\n img = " + img + + "\n x = " + x + + "\n y = " + y + + "\n bgcolor = " + bgcolor + + "\n observer = " + observer; + log.println( l ); + return g2D.drawImage( img, x, y, bgcolor, observer ); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + String l = + "drawImage(Image,int,int,observer):" + + "\n img = " + img + + "\n x = " + x + + "\n y = " + y + + "\n observer = " + observer; + log.println( l ); + return g2D.drawImage( img, x, y, observer ); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { + String l = + "drawImage(Image,int,int,int,int,Color,ImageObserver):" + + "\n img = " + img + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height + + "\n bgcolor = " + bgcolor + + "\n observer = " + observer; + log.println( l ); + return g2D.drawImage( img, x, y, width, height, bgcolor, observer ); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + String l = + "drawImage(Image,int,int,width,height,observer):" + + "\n img = " + img + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height + + "\n observer = " + observer; + log.println( l ); + return g2D.drawImage( img, x, y, width, height, observer ); + } + + public void drawLine(int x1, int y1, int x2, int y2) { + String l = + "drawLine(int,int,int,int):" + + "\n x1 = " + x1 + + "\n y1 = " + y1 + + "\n x2 = " + x2 + + "\n y2 = " + y2; + log.println( l ); + g2D.drawLine( x1, y1, x2, y2 ); + } + + public void drawOval(int x, int y, int width, int height) { + String l = + "drawOval(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + g2D.drawOval( x, y, width, height ); + } + + public void drawPolygon(Polygon p) { + String l = + "drawPolygon(Polygon):" + + "\n p = " + p; + log.println( l ); + g2D.drawPolygon( p ); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { + String l = + "drawPolygon(int[],int[],int):" + + "\n xPoints = " + Arrays.toString(xPoints) + + "\n yPoints = " + Arrays.toString(yPoints) + + "\n nPoints = " + nPoints; + log.println( l ); + g2D.drawPolygon( xPoints, yPoints, nPoints ); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { + String l = + "drawPolyline(int[],int[],int):" + + "\n xPoints = " + Arrays.toString(xPoints) + + "\n yPoints = " + Arrays.toString(yPoints) + + "\n nPoints = " + nPoints; + log.println( l ); + g2D.drawPolyline( xPoints, yPoints, nPoints ); + } + + public void drawRect(int x, int y, int width, int height) { + String l = + "drawRect(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + g2D.drawRect( x, y, width, height ); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + String l = + "drawRoundRect(int,int,int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height + + "\n arcWidth = " + arcWidth + + "\n arcHeight = " + arcHeight; + log.println( l ); + g2D.drawRoundRect( x, y, width, height, arcWidth, arcHeight ); + } + + private static String mapAttribute(Object attr) { + if (attr == null) { + return "null"; + } + if (attr instanceof Font) { + Font f = (Font)attr; + final String[] STYLE = { "Font.PLAIN", "Font.BOLD", "Font.ITALIC", "Font.BOLD | Font.ITALIC" }; + return "new Font(\"" + f.getFamily(Locale.ROOT) + "\"," + STYLE[f.getStyle()] + "," + f.getSize() + ")"; + } + if (attr instanceof Color) { + return String.format(Locale.ROOT, "new Color(0x%08X)", ((Color)attr).getRGB()); + } + for (int i=0; i<ATTRS.length; i+=2) { + if (attr == ATTRS[i]) { + return (String)ATTRS[i+1]; + } + } + return "\""+attr.toString()+"\""; + } + + public void drawString(AttributedCharacterIterator iterator, float x, float y) { + final int startIdx = iterator.getIndex(); + + final Map<Attribute, Map<Integer,Object>> attMap = new HashMap<>(); + StringBuilder sb = new StringBuilder(); + for (char ch = iterator.current(); ch != AttributedCharacterIterator.DONE; ch = iterator.next()) { + sb.append(ch); + iterator.getAttributes().forEach((k,v) -> + attMap.computeIfAbsent(k, (k2) -> new LinkedHashMap<>()).put(iterator.getIndex(), v) + ); + } + + String l = "AttributedString as = new AttributedString(\""+sb+"\");\n"; + sb.setLength(0); + sb.append(l); + + for (Map.Entry<Attribute, Map<Integer,Object>> me : attMap.entrySet()) { + int startPos = -2, lastPos = -2; + Object lastObj = null; + for (Map.Entry<Integer,Object> mo : me.getValue().entrySet()) { + int pos = mo.getKey(); + Object obj = mo.getValue(); + if (lastPos < pos-1 || obj != lastObj) { + if (startPos >= 0) { + Attribute at = me.getKey(); + sb.append("as.addAttribute("+mapAttribute(me.getKey())+","+mapAttribute(lastObj)+","+startPos+","+(lastPos+1)+");\n"); + } + startPos = pos; + } + lastPos = pos; + lastObj = obj; + } + if (lastObj != null) { + sb.append("as.addAttribute("+mapAttribute(me.getKey())+","+mapAttribute(lastObj)+","+startPos+","+(lastPos+1)+");\n"); + } + } + + sb.append("g.drawString(as.getIterator(),"+x+"f,"+y+"f);"); + log.println( sb.toString() ); + + iterator.setIndex(startIdx); + g2D.drawString( iterator, x, y ); + } + + + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + drawString(iterator, (float)x, (float)y); + } + + public void drawString(String str, int x, int y) { + String l = + "drawString(str,int,int):" + + "\n str = " + str + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.drawString( str, x, y ); + } + + public void fill3DRect(int x, int y, int width, int height, boolean raised) { + String l = + "fill3DRect(int,int,int,int,boolean):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height + + "\n raised = " + raised; + log.println( l ); + g2D.fill3DRect( x, y, width, height, raised ); + } + + public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + String l = + "fillArc(int,int,int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height + + "\n startAngle = " + startAngle + + "\n arcAngle = " + arcAngle; + log.println( l ); + g2D.fillArc( x, y, width, height, startAngle, arcAngle ); + } + + public void fillOval(int x, int y, int width, int height) { + String l = + "fillOval(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + g2D.fillOval( x, y, width, height ); + } + + public void fillPolygon(Polygon p) { + String l = + "fillPolygon(Polygon):" + + "\n p = " + p; + log.println( l ); + g2D.fillPolygon( p ); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { + String l = + "fillPolygon(int[],int[],int):" + + "\n xPoints = " + Arrays.toString(xPoints) + + "\n yPoints = " + Arrays.toString(yPoints) + + "\n nPoints = " + nPoints; + log.println( l ); + g2D.fillPolygon( xPoints, yPoints, nPoints ); + } + + public void fillRect(int x, int y, int width, int height) { + log.println( "g.fillRect(" + x + "," + y + "," + width + "," + height + ");" ); + g2D.fillRect( x, y, width, height ); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + log.println( "fillRoundRect(" + x + "," + y + "," + width + "," + height + "," + arcWidth + "," + arcHeight + ")" ); + g2D.fillRoundRect( x, y, width, height, arcWidth, arcHeight ); + } + + // FIXME: should be protected + // FindBugs, category MALICIOUS_CODE, FI_PUBLIC_SHOULD_BE_PROTECTED + // A class's finalize() method should have protected access, not public + @Internal + @Override + public final void finalize() { + log.println( "finalize():" ); + g2D.dispose(); + dispose(); + } + + public Shape getClip() { + log.println( "getClip():" ); + return g2D.getClip(); + } + + public Rectangle getClipBounds() { + log.println( "getClipBounds():" ); + return g2D.getClipBounds(); + } + + public Rectangle getClipBounds(Rectangle r) { + String l = + "getClipBounds(Rectangle):" + + "\n r = " + r; + log.println( l ); + return g2D.getClipBounds( r ); + } + + public Color getColor() { + log.println( "getColor():" ); + return g2D.getColor(); + } + + public Font getFont() { + log.println( "getFont():" ); + return g2D.getFont(); + } + + public FontMetrics getFontMetrics() { + log.println( "getFontMetrics():" ); + return g2D.getFontMetrics(); + } + + public FontMetrics getFontMetrics(Font f) { + log.println( "getFontMetrics():" ); + return g2D.getFontMetrics( f ); + } + + public boolean hitClip(int x, int y, int width, int height) { + String l = + "hitClip(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + return g2D.hitClip( x, y, width, height ); + } + + public void setClip(Shape clip) { + String l = + "setClip(Shape):" + + "\n clip = " + clip; + log.println( l ); + g2D.setClip( clip ); + } + + public void setClip(int x, int y, int width, int height) { + String l = + "setClip(int,int,int,int):" + + "\n x = " + x + + "\n y = " + y + + "\n width = " + width + + "\n height = " + height; + log.println( l ); + g2D.setClip( x, y, width, height ); + } + + public void setColor(Color c) { + log.println( String.format(Locale.ROOT, "g.setColor(new Color(0x%08X));", c.getRGB())); + g2D.setColor( c ); + } + + public void setFont(Font font) { + String l = + "setFont(Font):" + + "\n font = " + font; + log.println( l ); + g2D.setFont( font ); + } + + public void setPaintMode() { + log.println( "setPaintMode():" ); + g2D.setPaintMode(); + } + + public void setXORMode(Color c1) { + String l = + "setXORMode(Color):" + + "\n c1 = " + c1; + log.println( l ); + g2D.setXORMode( c1 ); + } + + public String toString() { + log.println( "toString():" ); + return g2D.toString(); + } + + public void translate(int x, int y) { + String l = + "translate(int,int):" + + "\n x = " + x + + "\n y = " + y; + log.println( l ); + g2D.translate( x, y ); + } + + + private static final Object[] HINTS = { + RenderingHints.KEY_ANTIALIASING, "RenderingHints.KEY_ANTIALIASING", + RenderingHints.VALUE_ANTIALIAS_ON, "RenderingHints.VALUE_ANTIALIAS_ON", + RenderingHints.VALUE_ANTIALIAS_OFF, "RenderingHints.VALUE_ANTIALIAS_OFF", + RenderingHints.VALUE_ANTIALIAS_DEFAULT, "RenderingHints.VALUE_ANTIALIAS_DEFAULT", + RenderingHints.KEY_RENDERING, "RenderingHints.KEY_RENDERING", + RenderingHints.VALUE_RENDER_SPEED, "RenderingHints.VALUE_RENDER_SPEED", + RenderingHints.VALUE_RENDER_QUALITY, "RenderingHints.VALUE_RENDER_QUALITY", + RenderingHints.VALUE_RENDER_DEFAULT, "RenderingHints.VALUE_RENDER_DEFAULT", + RenderingHints.KEY_DITHERING, "RenderingHints.KEY_DITHERING", + RenderingHints.VALUE_DITHER_DISABLE, "RenderingHints.VALUE_DITHER_DISABLE", + RenderingHints.VALUE_DITHER_ENABLE, "RenderingHints.VALUE_DITHER_ENABLE", + RenderingHints.VALUE_DITHER_DEFAULT, "RenderingHints.VALUE_DITHER_DEFAULT", + RenderingHints.KEY_TEXT_ANTIALIASING, "RenderingHints.KEY_TEXT_ANTIALIASING", + RenderingHints.VALUE_TEXT_ANTIALIAS_ON, "RenderingHints.VALUE_TEXT_ANTIALIAS_ON", + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF, "RenderingHints.VALUE_TEXT_ANTIALIAS_OFF", + RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT, "RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT", + RenderingHints.VALUE_TEXT_ANTIALIAS_GASP, "RenderingHints.VALUE_TEXT_ANTIALIAS_GASP", + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB, "RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB", + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR, "RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR", + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB, "RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB", + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR, "RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR", + RenderingHints.KEY_TEXT_LCD_CONTRAST, "RenderingHints.KEY_TEXT_LCD_CONTRAST", + RenderingHints.KEY_FRACTIONALMETRICS, "RenderingHints.KEY_FRACTIONALMETRICS", + RenderingHints.VALUE_FRACTIONALMETRICS_OFF, "RenderingHints.VALUE_FRACTIONALMETRICS_OFF", + RenderingHints.VALUE_FRACTIONALMETRICS_ON, "RenderingHints.VALUE_FRACTIONALMETRICS_ON", + RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT, "RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT", + RenderingHints.KEY_INTERPOLATION, "RenderingHints.KEY_INTERPOLATION", + RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR, "RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR", + RenderingHints.VALUE_INTERPOLATION_BILINEAR, "RenderingHints.VALUE_INTERPOLATION_BILINEAR", + RenderingHints.VALUE_INTERPOLATION_BICUBIC, "RenderingHints.VALUE_INTERPOLATION_BICUBIC", + RenderingHints.KEY_ALPHA_INTERPOLATION, "RenderingHints.KEY_ALPHA_INTERPOLATION", + RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED, "RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED", + RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY, "RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY", + RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT, "RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT", + RenderingHints.KEY_COLOR_RENDERING, "RenderingHints.KEY_COLOR_RENDERING", + RenderingHints.VALUE_COLOR_RENDER_SPEED, "RenderingHints.VALUE_COLOR_RENDER_SPEED", + RenderingHints.VALUE_COLOR_RENDER_QUALITY, "RenderingHints.VALUE_COLOR_RENDER_QUALITY", + RenderingHints.VALUE_COLOR_RENDER_DEFAULT, "RenderingHints.VALUE_COLOR_RENDER_DEFAULT", + RenderingHints.KEY_STROKE_CONTROL, "RenderingHints.KEY_STROKE_CONTROL", + RenderingHints.VALUE_STROKE_DEFAULT, "RenderingHints.VALUE_STROKE_DEFAULT", + RenderingHints.VALUE_STROKE_NORMALIZE, "RenderingHints.VALUE_STROKE_NORMALIZE", + RenderingHints.VALUE_STROKE_PURE, "RenderingHints.VALUE_STROKE_PURE" + }; + + private static final Object[] ATTRS = { + TextAttribute.FAMILY, "TextAttribute.FAMILY", + TextAttribute.WEIGHT, "TextAttribute.WEIGHT", + TextAttribute.WEIGHT_EXTRA_LIGHT, "TextAttribute.WEIGHT_EXTRA_LIGHT", + TextAttribute.WEIGHT_LIGHT, "TextAttribute.WEIGHT_LIGHT", + TextAttribute.WEIGHT_DEMILIGHT, "TextAttribute.WEIGHT_DEMILIGHT", + TextAttribute.WEIGHT_REGULAR, "TextAttribute.WEIGHT_REGULAR", + TextAttribute.WEIGHT_SEMIBOLD, "TextAttribute.WEIGHT_SEMIBOLD", + TextAttribute.WEIGHT_MEDIUM, "TextAttribute.WEIGHT_MEDIUM", + TextAttribute.WEIGHT_DEMIBOLD, "TextAttribute.WEIGHT_DEMIBOLD", + TextAttribute.WEIGHT_BOLD, "TextAttribute.WEIGHT_BOLD", + TextAttribute.WEIGHT_HEAVY, "TextAttribute.WEIGHT_HEAVY", + TextAttribute.WEIGHT_EXTRABOLD, "TextAttribute.WEIGHT_EXTRABOLD", + TextAttribute.WEIGHT_ULTRABOLD, "TextAttribute.WEIGHT_ULTRABOLD", + TextAttribute.WIDTH, "TextAttribute.WIDTH", + TextAttribute.WIDTH_CONDENSED, "TextAttribute.WIDTH_CONDENSED", + TextAttribute.WIDTH_SEMI_CONDENSED, "TextAttribute.WIDTH_SEMI_CONDENSED", + TextAttribute.WIDTH_REGULAR, "TextAttribute.WIDTH_REGULAR", + TextAttribute.WIDTH_SEMI_EXTENDED, "TextAttribute.WIDTH_SEMI_EXTENDED", + TextAttribute.WIDTH_EXTENDED, "TextAttribute.WIDTH_EXTENDED", + TextAttribute.POSTURE, "TextAttribute.POSTURE", + TextAttribute.POSTURE_REGULAR, "TextAttribute.POSTURE_REGULAR", + TextAttribute.POSTURE_OBLIQUE, "TextAttribute.POSTURE_OBLIQUE", + TextAttribute.SIZE, "TextAttribute.SIZE", + TextAttribute.TRANSFORM, "TextAttribute.TRANSFORM", + TextAttribute.SUPERSCRIPT, "TextAttribute.SUPERSCRIPT", + TextAttribute.SUPERSCRIPT_SUPER, "TextAttribute.SUPERSCRIPT_SUPER", + TextAttribute.SUPERSCRIPT_SUB, "TextAttribute.SUPERSCRIPT_SUB", + TextAttribute.FONT, "TextAttribute.FONT", + TextAttribute.CHAR_REPLACEMENT, "TextAttribute.CHAR_REPLACEMENT", + TextAttribute.FOREGROUND, "TextAttribute.FOREGROUND", + TextAttribute.BACKGROUND, "TextAttribute.BACKGROUND", + TextAttribute.UNDERLINE, "TextAttribute.UNDERLINE", + TextAttribute.UNDERLINE_ON, "TextAttribute.UNDERLINE_ON", + TextAttribute.STRIKETHROUGH, "TextAttribute.STRIKETHROUGH", + TextAttribute.STRIKETHROUGH_ON, "TextAttribute.STRIKETHROUGH_ON", + TextAttribute.RUN_DIRECTION, "TextAttribute.RUN_DIRECTION", + TextAttribute.RUN_DIRECTION_LTR, "TextAttribute.RUN_DIRECTION_LTR", + TextAttribute.RUN_DIRECTION_RTL, "TextAttribute.RUN_DIRECTION_RTL", + TextAttribute.BIDI_EMBEDDING, "TextAttribute.BIDI_EMBEDDING", + TextAttribute.JUSTIFICATION, "TextAttribute.JUSTIFICATION", + TextAttribute.JUSTIFICATION_FULL, "TextAttribute.JUSTIFICATION_FULL", + TextAttribute.JUSTIFICATION_NONE, "TextAttribute.JUSTIFICATION_NONE", + TextAttribute.INPUT_METHOD_HIGHLIGHT, "TextAttribute.INPUT_METHOD_HIGHLIGHT", + TextAttribute.INPUT_METHOD_UNDERLINE, "TextAttribute.INPUT_METHOD_UNDERLINE", + TextAttribute.UNDERLINE_LOW_ONE_PIXEL, "TextAttribute.UNDERLINE_LOW_ONE_PIXEL", + TextAttribute.UNDERLINE_LOW_TWO_PIXEL, "TextAttribute.UNDERLINE_LOW_TWO_PIXEL", + TextAttribute.UNDERLINE_LOW_DOTTED, "TextAttribute.UNDERLINE_LOW_DOTTED", + TextAttribute.UNDERLINE_LOW_GRAY, "TextAttribute.UNDERLINE_LOW_GRAY", + TextAttribute.UNDERLINE_LOW_DASHED, "TextAttribute.UNDERLINE_LOW_DASHED", + TextAttribute.SWAP_COLORS, "TextAttribute.SWAP_COLORS", + TextAttribute.SWAP_COLORS_ON, "TextAttribute.SWAP_COLORS_ON", + TextAttribute.NUMERIC_SHAPING, "TextAttribute.NUMERIC_SHAPING", + TextAttribute.KERNING, "TextAttribute.KERNING", + TextAttribute.KERNING_ON, "TextAttribute.KERNING_ON", + TextAttribute.LIGATURES, "TextAttribute.LIGATURES", + TextAttribute.LIGATURES_ON, "TextAttribute.LIGATURES_ON", + TextAttribute.TRACKING, "TextAttribute.TRACKING", + TextAttribute.TRACKING_TIGHT, "TextAttribute.TRACKING_TIGHT", + TextAttribute.TRACKING_LOOSE, "TextAttribute.TRACKING_LOOSE" + }; +} diff --git a/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java index 609b3efcbb..33c5703f8b 100644 --- a/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java +++ b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java @@ -63,7 +63,7 @@ public final class PPTX2PNG { " -scale <float> scale factor\n" + " -fixSide <side> specify side (long,short,width,height) to fix - use <scale> as amount of pixels\n" + " -slide <integer> 1-based index of a slide to render\n" + - " -format <type> png,gif,jpg,svg,pdf (,null for testing)\n" + + " -format <type> png,gif,jpg,svg,pdf (,log,null for testing)\n" + " -outdir <dir> output directory, defaults to origin of the ppt/pptx file\n" + " -outfile <file> output filename, defaults to '"+OUTPUT_PAT_REGEX+"'\n" + " -outpat <pattern> output filename pattern, defaults to '"+OUTPUT_PAT_REGEX+"'\n" + @@ -239,7 +239,7 @@ public final class PPTX2PNG { return false; } - if (format == null || !format.matches("^(png|gif|jpg|null|svg|pdf)$")) { + if (format == null || !format.matches("^(png|gif|jpg|null|svg|pdf|log)$")) { usage("Invalid format given"); return false; } @@ -354,6 +354,8 @@ public final class PPTX2PNG { return new SVGFormat(textAsShapes); case "pdf": return new PDFFormat(textAsShapes,fontDir,fontTtf); + case "log": + return new DummyFormat(); default: return new BitmapFormat(format); } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java index 19222c7006..adfa7ed46e 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java @@ -17,6 +17,8 @@ package org.apache.poi.xslf; import static org.apache.poi.POITestCase.assertContains; +import static org.apache.poi.sl.draw.DrawTextParagraph.HYPERLINK_HREF; +import static org.apache.poi.sl.draw.DrawTextParagraph.HYPERLINK_LABEL; import static org.apache.poi.xslf.XSLFTestDataSamples.openSampleDocument; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -25,6 +27,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; import java.awt.Color; import java.awt.Dimension; @@ -39,16 +42,23 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.text.AttributedCharacterIterator; +import java.text.AttributedCharacterIterator.Attribute; +import java.text.CharacterIterator; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.imageio.ImageIO; import org.apache.poi.POIDataSamples; +import org.apache.poi.common.usermodel.HyperlinkType; import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; @@ -57,6 +67,7 @@ import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.extractor.SlideShowExtractor; +import org.apache.poi.sl.usermodel.Hyperlink; import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; @@ -66,8 +77,13 @@ import org.apache.poi.sl.usermodel.PictureShape; import org.apache.poi.sl.usermodel.Shape; import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.Slide; +import org.apache.poi.sl.usermodel.SlideShow; +import org.apache.poi.sl.usermodel.SlideShowFactory; +import org.apache.poi.sl.usermodel.TextRun; +import org.apache.poi.sl.usermodel.TextShape; import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.util.IOUtils; +import org.apache.poi.util.NullPrintStream; import org.apache.poi.xslf.usermodel.XMLSlideShow; import org.apache.poi.xslf.usermodel.XSLFAutoShape; import org.apache.poi.xslf.usermodel.XSLFGroupShape; @@ -87,6 +103,8 @@ import org.apache.poi.xslf.usermodel.XSLFTableRow; import org.apache.poi.xslf.usermodel.XSLFTextBox; import org.apache.poi.xslf.usermodel.XSLFTextParagraph; import org.apache.poi.xslf.usermodel.XSLFTextRun; +import org.apache.poi.xslf.util.DummyGraphics2d; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect; @@ -95,6 +113,17 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; public class TestXSLFBugs { private static final POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); + private static boolean xslfOnly; + + @BeforeClass + public static void checkHslf() { + try { + Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow"); + } catch (Exception e) { + xslfOnly = true; + } + } + @Test public void bug62929() throws Exception { try(XMLSlideShow ss1 = openSampleDocument("missing-blip-fill.pptx")) { @@ -247,9 +276,9 @@ public class TestXSLFBugs { public void bug62587() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try (XMLSlideShow ppt = new XMLSlideShow()) { - Slide slide = ppt.createSlide(); + Slide<?,?> slide = ppt.createSlide(); XSLFPictureData pd = ppt.addPicture(slTests.getFile("wrench.emf"), PictureType.EMF); - PictureShape ps = slide.createPicture(pd); + PictureShape<?,?> ps = slide.createPicture(pd); ps.setAnchor(new Rectangle2D.Double(100,100,100,100)); ppt.write(bos); } @@ -584,9 +613,7 @@ public class TestXSLFBugs { // Some dummy pictures byte[][] pics = new byte[15][3]; for (int i=0; i<pics.length; i++) { - for (int j=0; j<pics[i].length; j++) { - pics[i][j] = (byte)i; - } + Arrays.fill(pics[i], (byte) i); } // Add a few pictures @@ -1011,4 +1038,53 @@ public class TestXSLFBugs { assertEquals("Picture 5", ps.getShapeName()); } } + + + @Test + public void bug57796() throws IOException { + assumeFalse(xslfOnly); + + try (SlideShow<?,?> ppt = SlideShowFactory.create(slTests.getFile("WithLinks.ppt"))) { + Slide<?,?> slide = ppt.getSlides().get(0); + TextShape<?,?> shape = (TextShape<?,?>) slide.getShapes().get(1); + TextRun r = shape.getTextParagraphs().get(1).getTextRuns().get(0); + Hyperlink<?,?> hlRun = r.getHyperlink(); + assertNotNull(hlRun); + assertEquals("http://jakarta.apache.org/poi/", hlRun.getAddress()); + assertEquals("http://jakarta.apache.org/poi/", hlRun.getLabel()); + assertEquals(HyperlinkType.URL, hlRun.getType()); + + final List<Object> strings = new ArrayList<>(); + + DummyGraphics2d dgfx = new DummyGraphics2d(new NullPrintStream()) { + @Override + public void drawString(AttributedCharacterIterator iterator, float x, float y) { + // For the test file, common sl draws textruns one by one and not mixed + // so we evaluate the whole iterator + Map<Attribute, Object> attributes = null; + StringBuilder sb = new StringBuilder(); + + for (char c = iterator.first(); + c != CharacterIterator.DONE; + c = iterator.next()) { + sb.append(c); + attributes = iterator.getAttributes(); + } + + if ("Jakarta HSSF".equals(sb.toString())) { + // this is a test for a manually modified ppt, for real hyperlink label + // one would need to access the screen tip record + Attribute[] obj = { HYPERLINK_HREF, HYPERLINK_LABEL }; + assertNotNull(attributes); + Stream.of(obj).map(attributes::get).forEach(strings::add); + } + } + }; + + ppt.getSlides().get(1).draw(dgfx); + assertEquals(2, strings.size()); + assertEquals("http://jakarta.apache.org/poi/hssf/", strings.get(0)); + assertEquals("Open Jakarta POI HSSF module test ", strings.get(1)); + } + } } |