You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2015/02/21 11:56:06 UTC
svn commit: r1661322 [5/14] - in /poi/branches/common_sl: ./
src/examples/src/org/apache/poi/hslf/examples/
src/examples/src/org/apache/poi/xslf/usermodel/
src/java/org/apache/poi/common/usermodel/
src/java/org/apache/poi/hssf/usermodel/ src/java/org/a...
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawPaint.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawPaint.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawPaint.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawPaint.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,448 @@
+/* ====================================================================
+ 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.*;
+import java.awt.MultipleGradientPaint.ColorSpaceType;
+import java.awt.MultipleGradientPaint.CycleMethod;
+import java.awt.Shape;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.sl.usermodel.GradientPaint;
+import org.apache.poi.sl.usermodel.TexturePaint;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+
+public class DrawPaint {
+ public final static Color NO_PAINT = new Color(0xFF, 0xFF, 0xFF, 0);
+ private final static POILogger LOG = POILogFactory.getLogger(DrawPaint.class);
+
+ protected PlaceableShape shape;
+
+ public DrawPaint(PlaceableShape shape) {
+ this.shape = shape;
+ }
+
+ public Paint getPaint(Graphics2D graphics, PaintStyle paint) {
+ if (paint instanceof SolidPaint) {
+ return getSolidPaint((SolidPaint)paint, graphics);
+ } else if (paint instanceof GradientPaint) {
+ return getGradientPaint((GradientPaint)paint, graphics);
+ } else if (paint instanceof TexturePaint) {
+ return getTexturePaint((TexturePaint)paint, graphics);
+ }
+ return null;
+ }
+
+ protected Paint getSolidPaint(SolidPaint fill, Graphics2D graphics) {
+ return applyColorTransform(fill.getSolidColor());
+ }
+
+ protected Paint getGradientPaint(GradientPaint fill, Graphics2D graphics) {
+ switch (fill.getGradientType()) {
+ case linear:
+ return createLinearGradientPaint(fill, graphics);
+ case circular:
+ return createRadialGradientPaint(fill, graphics);
+ case shape:
+ return createPathGradientPaint(fill, graphics);
+ default:
+ throw new UnsupportedOperationException("gradient fill of type "+fill+" not supported.");
+ }
+ }
+
+ protected Paint getTexturePaint(TexturePaint fill, Graphics2D graphics) {
+ InputStream is = fill.getImageData();
+ if (is == null) return NO_PAINT;
+ assert(graphics != null);
+
+ ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);
+ if (renderer == null) renderer = new ImageRenderer();
+
+ try {
+ renderer.loadImage(fill.getImageData(), fill.getContentType());
+ } catch (IOException e) {
+ LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
+ return NO_PAINT;
+ }
+
+ int alpha = fill.getAlpha();
+ if (alpha != -1) {
+ renderer.setAlpha(fill.getAlpha()/100000.f);
+ }
+
+ Dimension dim = renderer.getDimension();
+ Rectangle2D textAnchor = new Rectangle2D.Double(0, 0, dim.getWidth(), dim.getHeight());
+ Paint paint = new java.awt.TexturePaint(renderer.getImage(), textAnchor);
+
+ return paint;
+ }
+
+ /**
+ * Convert color transformations in {@link ColorStyle} to a {@link Color} instance
+ */
+ public static Color applyColorTransform(ColorStyle color){
+ Color result = color.getColor();
+
+ if (result == null || color.getAlpha() == 100) return NO_PAINT;
+
+ result = applyAlpha(result, color);
+ result = applyLuminanace(result, color);
+ result = applyShade(result, color);
+ result = applyTint(result, color);
+
+ return result;
+ }
+
+ protected static Color applyAlpha(Color c, ColorStyle fc) {
+ int alpha = c.getAlpha();
+ return (alpha == 0 || alpha == -1) ? c : new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha);
+ }
+
+ /**
+ * Apply lumMod / lumOff adjustments
+ *
+ * @param c the color to modify
+ * @param lumMod luminance modulation in the range [0..100000]
+ * @param lumOff luminance offset in the range [0..100000]
+ * @return modified color
+ */
+ protected static Color applyLuminanace(Color c, ColorStyle fc) {
+ int lumMod = fc.getLumMod();
+ if (lumMod == -1) lumMod = 100000;
+
+ int lumOff = fc.getLumOff();
+ if (lumOff == -1) lumOff = 0;
+
+ if (lumMod == 100000 && lumOff == 0) return c;
+
+ int r = c.getRed();
+ int g = c.getGreen();
+ int b = c.getBlue();
+
+ float red,green,blue;
+
+ Color color;
+ if (lumOff > 0) {
+ float flumOff = lumOff / 100000.f;
+ red = (255.f - r) * (1.f - flumOff) + r;
+ green = (255.f - g) * flumOff + g;
+ blue = (255.f - b) * flumOff + b;
+ } else {
+ float flumMod = lumMod / 100000.f;
+ red = r * lumMod;
+ green = g * lumMod;
+ blue = b * lumMod;
+ }
+ return new Color(Math.round(red), Math.round(green), Math.round(blue), c.getAlpha());
+ }
+
+ /**
+ * This algorithm returns result different from PowerPoint.
+ * TODO: revisit and improve
+ */
+ protected static Color applyShade(Color c, ColorStyle fc) {
+ int shade = fc.getShade();
+ if (shade == -1) return c;
+
+ float fshade = shade / 100000.f;
+
+ float red = c.getRed() * fshade;
+ float green = c.getGreen() * fshade;
+ float blue = c.getGreen() * fshade;
+
+ return new Color(Math.round(red), Math.round(green), Math.round(blue), c.getAlpha());
+ }
+
+ /**
+ * This algorithm returns result different from PowerPoint.
+ * TODO: revisit and improve
+ */
+ protected static Color applyTint(Color c, ColorStyle fc) {
+ int tint = fc.getTint();
+ if (tint == -1) return c;
+
+ float ftint = tint / 100000.f;
+
+ float red = ftint * c.getRed() + (1.f - ftint) * 255.f;
+ float green = ftint * c.getGreen() + (1.f - ftint) * 255.f;
+ float blue = ftint * c.getBlue() + (1.f - ftint) * 255.f;
+
+ return new Color(Math.round(red), Math.round(green), Math.round(blue), c.getAlpha());
+ }
+
+
+ protected Paint createLinearGradientPaint(GradientPaint fill, Graphics2D graphics) {
+ double angle = fill.getGradientAngle();
+ Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
+
+ AffineTransform at = AffineTransform.getRotateInstance(
+ Math.toRadians(angle),
+ anchor.getX() + anchor.getWidth() / 2,
+ anchor.getY() + anchor.getHeight() / 2);
+
+ double diagonal = Math.sqrt(anchor.getHeight() * anchor.getHeight() + anchor.getWidth() * anchor.getWidth());
+ Point2D p1 = new Point2D.Double(anchor.getX() + anchor.getWidth() / 2 - diagonal / 2,
+ anchor.getY() + anchor.getHeight() / 2);
+ p1 = at.transform(p1, null);
+
+ Point2D p2 = new Point2D.Double(anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight() / 2);
+ p2 = at.transform(p2, null);
+
+ snapToAnchor(p1, anchor);
+ snapToAnchor(p2, anchor);
+
+ float[] fractions = fill.getGradientFractions();
+ Color[] colors = new Color[fractions.length];
+
+ int i = 0;
+ for (ColorStyle fc : fill.getGradientColors()) {
+ colors[i++] = applyColorTransform(fc);
+ }
+
+ AffineTransform grAt = new AffineTransform();
+ if(fill.isRotatedWithShape()) {
+ double rotation = shape.getRotation();
+ if (rotation != 0.) {
+ double centerX = anchor.getX() + anchor.getWidth() / 2;
+ double centerY = anchor.getY() + anchor.getHeight() / 2;
+
+ grAt.translate(centerX, centerY);
+ grAt.rotate(Math.toRadians(-rotation));
+ grAt.translate(-centerX, -centerY);
+ }
+ }
+
+ return new LinearGradientPaint
+ (p1, p2, fractions, colors, CycleMethod.NO_CYCLE, ColorSpaceType.SRGB, grAt);
+ }
+
+ protected Paint createRadialGradientPaint(GradientPaint fill, Graphics2D graphics) {
+ Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
+
+ Point2D pCenter = new Point2D.Double(anchor.getX() + anchor.getWidth()/2,
+ anchor.getY() + anchor.getHeight()/2);
+
+ float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
+
+ float[] fractions = fill.getGradientFractions();
+ Color[] colors = new Color[fractions.length];
+
+ int i=0;
+ for (ColorStyle fc : fill.getGradientColors()) {
+ colors[i++] = applyColorTransform(fc);
+ }
+
+ return new RadialGradientPaint(pCenter, radius, fractions, colors);
+ }
+
+ protected Paint createPathGradientPaint(GradientPaint fill, Graphics2D graphics) {
+ // currently we ignore an eventually center setting
+
+ float[] fractions = fill.getGradientFractions();
+ Color[] colors = new Color[fractions.length];
+
+ int i=0;
+ for (ColorStyle fc : fill.getGradientColors()) {
+ colors[i++] = applyColorTransform(fc);
+ }
+
+ return new PathGradientPaint(colors, fractions);
+ }
+
+ protected void snapToAnchor(Point2D p, Rectangle2D anchor) {
+ if (p.getX() < anchor.getX()) {
+ p.setLocation(anchor.getX(), p.getY());
+ } else if (p.getX() > (anchor.getX() + anchor.getWidth())) {
+ p.setLocation(anchor.getX() + anchor.getWidth(), p.getY());
+ }
+
+ if (p.getY() < anchor.getY()) {
+ p.setLocation(p.getX(), anchor.getY());
+ } else if (p.getY() > (anchor.getY() + anchor.getHeight())) {
+ p.setLocation(p.getX(), anchor.getY() + anchor.getHeight());
+ }
+ }
+
+ public static class PathGradientPaint implements Paint {
+
+ // http://asserttrue.blogspot.de/2010/01/how-to-iimplement-custom-paint-in-50.html
+ protected final Color colors[];
+ protected final float fractions[];
+ protected final int capStyle;
+ protected final int joinStyle;
+ protected final int transparency;
+
+
+ public PathGradientPaint(Color colors[], float fractions[]) {
+ this(colors,fractions,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
+ }
+
+ public PathGradientPaint(Color colors[], float fractions[], int capStyle, int joinStyle) {
+ this.colors = colors;
+ this.fractions = fractions;
+ this.capStyle = capStyle;
+ this.joinStyle = joinStyle;
+
+ // determine transparency
+ boolean opaque = true;
+ for (int i = 0; i < colors.length; i++){
+ opaque = opaque && (colors[i].getAlpha() == 0xff);
+ }
+ this.transparency = opaque ? OPAQUE : TRANSLUCENT;
+ }
+
+ public PaintContext createContext(ColorModel cm,
+ Rectangle deviceBounds,
+ Rectangle2D userBounds,
+ AffineTransform transform,
+ RenderingHints hints) {
+ return new PathGradientContext(cm, deviceBounds, userBounds, transform, hints);
+ }
+
+ public int getTransparency() {
+ return transparency;
+ }
+
+ class PathGradientContext implements PaintContext {
+ protected final Rectangle deviceBounds;
+ protected final Rectangle2D userBounds;
+ protected final AffineTransform xform;
+ protected final RenderingHints hints;
+
+ /**
+ * for POI: the shape will be only known when the subclasses determines the concrete implementation
+ * in the draw/-content method, so we need to postpone the setting/creation as long as possible
+ **/
+ protected final Shape shape;
+ protected final PaintContext pCtx;
+ protected final int gradientSteps;
+ WritableRaster raster;
+
+ public PathGradientContext(
+ ColorModel cm
+ , Rectangle deviceBounds
+ , Rectangle2D userBounds
+ , AffineTransform xform
+ , RenderingHints hints
+ ) {
+ shape = (Shape)hints.get(Drawable.GRADIENT_SHAPE);
+ if (shape == null) {
+ throw new IllegalPathStateException("PathGradientPaint needs a shape to be set via the rendering hint PathGradientPaint.GRADIANT_SHAPE.");
+ }
+
+ this.deviceBounds = deviceBounds;
+ this.userBounds = userBounds;
+ this.xform = xform;
+ this.hints = hints;
+
+ gradientSteps = getGradientSteps(shape);
+
+ Point2D start = new Point2D.Double(0, 0);
+ Point2D end = new Point2D.Double(gradientSteps, 0);
+ LinearGradientPaint gradientPaint = new LinearGradientPaint(start, end, fractions, colors, CycleMethod.NO_CYCLE, ColorSpaceType.SRGB, new AffineTransform());
+
+ Rectangle bounds = new Rectangle(0, 0, gradientSteps, 1);
+ pCtx = gradientPaint.createContext(cm, bounds, bounds, new AffineTransform(), hints);
+ }
+
+ public void dispose() {}
+
+ public ColorModel getColorModel() {
+ return pCtx.getColorModel();
+ }
+
+ public Raster getRaster(int xOffset, int yOffset, int w, int h) {
+ ColorModel cm = getColorModel();
+ if (raster == null) createRaster();
+
+ // TODO: eventually use caching here
+ WritableRaster childRaster = cm.createCompatibleWritableRaster(w, h);
+ Rectangle2D childRect = new Rectangle2D.Double(xOffset, yOffset, w, h);
+ if (!childRect.intersects(deviceBounds)) {
+ // usually doesn't happen ...
+ return childRaster;
+ }
+
+ Rectangle2D destRect = new Rectangle2D.Double();
+ Rectangle2D.intersect(childRect, deviceBounds, destRect);
+ int dx = (int)(destRect.getX()-deviceBounds.getX());
+ int dy = (int)(destRect.getY()-deviceBounds.getY());
+ int dw = (int)destRect.getWidth();
+ int dh = (int)destRect.getHeight();
+ Object data = raster.getDataElements(dx, dy, dw, dh, null);
+ dx = (int)(destRect.getX()-childRect.getX());
+ dy = (int)(destRect.getY()-childRect.getY());
+ childRaster.setDataElements(dx, dy, dw, dh, data);
+
+ return childRaster;
+ }
+
+ protected int getGradientSteps(Shape shape) {
+ Rectangle rect = shape.getBounds();
+ int lower = 1;
+ int upper = (int)(Math.max(rect.getWidth(),rect.getHeight())/2.0);
+ while (lower < upper-1) {
+ int mid = lower + (upper - lower) / 2;
+ BasicStroke bs = new BasicStroke(mid, capStyle, joinStyle);
+ Area area = new Area(bs.createStrokedShape(shape));
+ if (area.isSingular()) {
+ upper = mid;
+ } else {
+ lower = mid;
+ }
+ }
+ return upper;
+ }
+
+
+
+ protected void createRaster() {
+ ColorModel cm = getColorModel();
+ raster = cm.createCompatibleWritableRaster((int)deviceBounds.getWidth(), (int)deviceBounds.getHeight());
+ BufferedImage img = new BufferedImage(cm, raster, false, null);
+ Graphics2D graphics = img.createGraphics();
+ graphics.setRenderingHints(hints);
+ graphics.translate(-deviceBounds.getX(), -deviceBounds.getY());
+ graphics.transform(xform);
+
+ Raster img2 = pCtx.getRaster(0, 0, gradientSteps, 1);
+ int rgb[] = new int[cm.getNumComponents()];
+
+ for (int i = gradientSteps-1; i>=0; i--) {
+ img2.getPixel(i, 0, rgb);
+ Color c = new Color(rgb[0],rgb[1],rgb[2]);
+ if (rgb.length == 4) {
+ // it doesn't work to use just a color with transparency ...
+ graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, rgb[3]/255.0f));
+ }
+ graphics.setStroke(new BasicStroke(i+1, capStyle, joinStyle));
+ graphics.setColor(c);
+ graphics.draw(shape);
+ }
+
+ graphics.dispose();
+ }
+ }
+ }
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawShape.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawShape.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawShape.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawShape.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,109 @@
+package org.apache.poi.sl.draw;
+
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.poi.sl.usermodel.PlaceableShape;
+import org.apache.poi.sl.usermodel.Shape;
+
+
+public class DrawShape<T extends Shape> implements Drawable {
+
+ protected final T shape;
+
+ public DrawShape(T shape) {
+ this.shape = shape;
+ }
+
+ /**
+ * Apply 2-D transforms before drawing this shape. This includes rotation and flipping.
+ *
+ * @param graphics the graphics whos transform matrix will be modified
+ */
+ public void applyTransform(Graphics2D graphics) {
+ Rectangle2D anchor = shape.getAnchor();
+ AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
+ if(tx != null) {
+ anchor = tx.createTransformedShape(anchor).getBounds2D();
+ }
+
+ // rotation
+ double rotation = shape.getRotation();
+ if (rotation != 0.) {
+ // PowerPoint rotates shapes relative to the geometric center
+ double centerX = anchor.getCenterX();
+ double centerY = anchor.getCenterY();
+
+ // normalize rotation
+ rotation = (360.+(rotation%360.))%360.;
+ int quadrant = (((int)rotation+45)/90)%4;
+ double scaleX = 1.0, scaleY = 1.0;
+
+ // scale to bounding box (bug #53176)
+ if (quadrant == 1 || quadrant == 3) {
+ // In quadrant 1 and 3, which is basically a shape in a more or less portrait orientation
+ // (45-135 degrees and 225-315 degrees), we need to first rotate the shape by a multiple
+ // of 90 degrees and then resize the bounding box to its original bbox. After that we can
+ // rotate the shape to the exact rotation amount.
+ // It's strange that you'll need to rotate the shape back and forth again, but you can
+ // think of it, as if you paint the shape on a canvas. First you rotate the canvas, which might
+ // be already (differently) scaled, so you can paint the shape in its default orientation
+ // and later on, turn it around again to compare it with its original size ...
+ AffineTransform txg = new AffineTransform(); // graphics coordinate space
+ AffineTransform txs = new AffineTransform(tx); // shape coordinate space
+ txg.translate(centerX, centerY);
+ txg.rotate(Math.toRadians(quadrant*90));
+ txg.translate(-centerX, -centerY);
+ txs.translate(centerX, centerY);
+ txs.rotate(Math.toRadians(-quadrant*90));
+ txs.translate(-centerX, -centerY);
+ txg.concatenate(txs);
+ Rectangle2D anchor2 = txg.createTransformedShape(shape.getAnchor()).getBounds2D();
+ scaleX = anchor.getWidth() == 0. ? 1.0 : anchor.getWidth() / anchor2.getWidth();
+ scaleY = anchor.getHeight() == 0. ? 1.0 : anchor.getHeight() / anchor2.getHeight();
+ }
+
+ // transformation is applied reversed ...
+ graphics.translate(centerX, centerY);
+ graphics.rotate(Math.toRadians(rotation-quadrant*90.));
+ graphics.scale(scaleX, scaleY);
+ graphics.rotate(Math.toRadians(quadrant*90));
+ graphics.translate(-centerX, -centerY);
+ }
+
+ //flip horizontal
+ if (shape.getFlipHorizontal()) {
+ graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());
+ graphics.scale(-1, 1);
+ graphics.translate(-anchor.getX(), -anchor.getY());
+ }
+
+ //flip vertical
+ if (shape.getFlipVertical()) {
+ graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());
+ graphics.scale(1, -1);
+ graphics.translate(-anchor.getX(), -anchor.getY());
+ }
+ }
+
+
+ public void draw(Graphics2D graphics) {
+ }
+
+ public void drawContent(Graphics2D context) {
+ }
+
+ public static Rectangle2D getAnchor(Graphics2D graphics, PlaceableShape shape) {
+ Rectangle2D anchor = shape.getAnchor();
+ if(graphics == null) {
+ return anchor;
+ }
+
+ AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
+ if(tx != null) {
+ anchor = tx.createTransformedShape(anchor).getBounds2D();
+ }
+ return anchor;
+ }
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSheet.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSheet.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSheet.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSheet.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,72 @@
+package org.apache.poi.sl.draw;
+
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+
+import org.apache.poi.sl.usermodel.MasterSheet;
+import org.apache.poi.sl.usermodel.Shape;
+import org.apache.poi.sl.usermodel.Sheet;
+
+
+public class DrawSheet implements Drawable {
+
+ protected final Sheet sheet;
+
+ public DrawSheet(Sheet sheet) {
+ this.sheet = sheet;
+ }
+
+ public void applyTransform(Graphics2D context) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void draw(Graphics2D graphics) {
+ DrawFactory drawFact = DrawFactory.getInstance(graphics);
+ MasterSheet master = sheet.getMasterSheet();
+
+ if(sheet.getFollowMasterGraphics() && master != null) {
+ Drawable drawer = drawFact.getDrawable(master);
+ drawer.draw(graphics);
+ }
+
+ graphics.setRenderingHint(Drawable.GROUP_TRANSFORM, new AffineTransform());
+
+ for (Shape shape : sheet.getShapes()) {
+ if(!canDraw(shape)) continue;
+
+ // remember the initial transform and restore it after we are done with drawing
+ AffineTransform at = graphics.getTransform();
+
+ // concrete implementations can make sense of this hint,
+ // for example PSGraphics2D or PDFGraphics2D would call gsave() / grestore
+ graphics.setRenderingHint(Drawable.GSAVE, true);
+
+ // apply rotation and flipping
+ Drawable drawer = drawFact.getDrawable(shape);
+ drawer.applyTransform(graphics);
+ // draw stuff
+ drawer.draw(graphics);
+
+ // restore the coordinate system
+ graphics.setTransform(at);
+
+ graphics.setRenderingHint(Drawable.GRESTORE, true);
+ }
+ }
+
+ public void drawContent(Graphics2D context) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * Checks if this <code>sheet</code> displays the specified shape.
+ *
+ * Subclasses can override it and skip certain shapes from drawings,
+ * for instance, slide masters and layouts don't display placeholders
+ */
+ protected boolean canDraw(Shape shape){
+ return true;
+ }
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSimpleShape.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSimpleShape.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSimpleShape.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawSimpleShape.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,391 @@
+package org.apache.poi.sl.draw;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.*;
+import java.util.List;
+
+import javax.xml.bind.*;
+import javax.xml.stream.*;
+import javax.xml.stream.EventFilter;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.apache.poi.sl.draw.binding.CTCustomGeometry2D;
+import org.apache.poi.sl.draw.geom.*;
+import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
+import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
+import org.apache.poi.util.Units;
+
+
+public class DrawSimpleShape<T extends SimpleShape> extends DrawShape<T> {
+
+ public DrawSimpleShape(T shape) {
+ super(shape);
+ }
+
+ @Override
+ public void draw(Graphics2D graphics) {
+// RenderableShape rShape = new RenderableShape(this);
+// rShape.render(graphics);
+
+ DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(shape);
+ Paint fill = drawPaint.getPaint(graphics, shape.getFillStyle().getPaint());
+ Paint line = drawPaint.getPaint(graphics, shape.getStrokeStyle().getPaint());
+ BasicStroke stroke = getStroke(); // the stroke applies both to the shadow and the shape
+ graphics.setStroke(stroke);
+
+ Collection<Outline> elems = computeOutlines(graphics);
+
+ // first paint the shadow
+ drawShadow(graphics, elems, fill, line);
+
+ // then fill the shape interior
+ if (fill != null) {
+ graphics.setPaint(fill);
+ for (Outline o : elems) {
+ if (o.getPath().isFilled()){
+ java.awt.Shape s = o.getOutline();
+ graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, s);
+ graphics.fill(s);
+ }
+ }
+ }
+
+ // then draw any content within this shape (text, image, etc.)
+ drawContent(graphics);
+
+ // then stroke the shape outline
+ if(line != null) {
+ graphics.setPaint(line);
+ for(Outline o : elems){
+ if(o.getPath().isStroked()){
+ java.awt.Shape s = o.getOutline();
+ graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, s);
+ graphics.draw(s);
+ }
+ }
+ }
+
+ // draw line decorations
+ drawDecoration(graphics, line, stroke);
+ }
+
+ protected void drawDecoration(Graphics2D graphics, Paint line, BasicStroke stroke) {
+ if(line == null) return;
+ graphics.setPaint(line);
+
+ List<Outline> lst = new ArrayList<Outline>();
+ LineDecoration deco = shape.getLineDecoration();
+ Outline head = getHeadDecoration(graphics, deco, stroke);
+ if (head != null) lst.add(head);
+ Outline tail = getTailDecoration(graphics, deco, stroke);
+ if (tail != null) lst.add(tail);
+
+
+ for(Outline o : lst){
+ java.awt.Shape s = o.getOutline();
+ Path p = o.getPath();
+ graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, s);
+
+ if(p.isFilled()) graphics.fill(s);
+ if(p.isStroked()) graphics.draw(s);
+ }
+ }
+
+ protected Outline getTailDecoration(Graphics2D graphics, LineDecoration deco, BasicStroke stroke) {
+ DecorationSize tailLength = deco.getTailLength();
+ DecorationSize tailWidth = deco.getTailWidth();
+
+ double lineWidth = Math.max(2.5, stroke.getLineWidth());
+
+ Rectangle2D anchor = getAnchor(graphics, shape);
+ double x2 = anchor.getX() + anchor.getWidth(),
+ y2 = anchor.getY() + anchor.getHeight();
+
+ double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
+
+ AffineTransform at = new AffineTransform();
+ java.awt.Shape shape = null;
+ Path p = null;
+ Rectangle2D bounds;
+ double scaleY = Math.pow(2, tailWidth.ordinal());
+ double scaleX = Math.pow(2, tailLength.ordinal());
+ switch (deco.getTailShape()) {
+ case OVAL:
+ p = new Path();
+ shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
+ bounds = shape.getBounds2D();
+ at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2);
+ at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
+ break;
+ case ARROW:
+ p = new Path();
+ GeneralPath arrow = new GeneralPath();
+ arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2));
+ arrow.lineTo(0, 0);
+ arrow.lineTo((float) (-lineWidth * 3), (float) (lineWidth * 2));
+ shape = arrow;
+ at.translate(x2, y2);
+ at.rotate(alpha);
+ break;
+ case TRIANGLE:
+ p = new Path();
+ scaleY = tailWidth.ordinal() + 1;
+ scaleX = tailLength.ordinal() + 1;
+ GeneralPath triangle = new GeneralPath();
+ triangle.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
+ triangle.lineTo(0, 0);
+ triangle.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
+ triangle.closePath();
+ shape = triangle;
+ at.translate(x2, y2);
+ at.rotate(alpha);
+ break;
+ default:
+ break;
+ }
+
+ if (shape != null) {
+ shape = at.createTransformedShape(shape);
+ }
+ return shape == null ? null : new Outline(shape, p);
+ }
+
+ Outline getHeadDecoration(Graphics2D graphics, LineDecoration deco, BasicStroke stroke) {
+ DecorationSize headLength = deco.getHeadLength();
+ DecorationSize headWidth = deco.getHeadWidth();
+
+ double lineWidth = Math.max(2.5, stroke.getLineWidth());
+
+ Rectangle2D anchor = getAnchor(graphics, shape);
+ double x1 = anchor.getX(),
+ y1 = anchor.getY();
+
+ double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());
+
+ AffineTransform at = new AffineTransform();
+ java.awt.Shape shape = null;
+ Path p = null;
+ Rectangle2D bounds;
+ double scaleY = 1;
+ double scaleX = 1;
+ switch (deco.getHeadShape()) {
+ case OVAL:
+ p = new Path();
+ shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
+ bounds = shape.getBounds2D();
+ at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2);
+ at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
+ break;
+ case STEALTH:
+ case ARROW:
+ p = new Path(false, true);
+ GeneralPath arrow = new GeneralPath();
+ arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2));
+ arrow.lineTo(0, 0);
+ arrow.lineTo((float) (lineWidth * 3 * scaleX), (float) (lineWidth * scaleY * 2));
+ shape = arrow;
+ at.translate(x1, y1);
+ at.rotate(alpha);
+ break;
+ case TRIANGLE:
+ p = new Path();
+ scaleY = headWidth.ordinal() + 1;
+ scaleX = headLength.ordinal() + 1;
+ GeneralPath triangle = new GeneralPath();
+ triangle.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
+ triangle.lineTo(0, 0);
+ triangle.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
+ triangle.closePath();
+ shape = triangle;
+ at.translate(x1, y1);
+ at.rotate(alpha);
+ break;
+ default:
+ break;
+ }
+
+ if (shape != null) {
+ shape = at.createTransformedShape(shape);
+ }
+ return shape == null ? null : new Outline(shape, p);
+ }
+
+ public BasicStroke getStroke() {
+ StrokeStyle strokeStyle = shape.getStrokeStyle();
+
+ float lineWidth = (float) strokeStyle.getLineWidth();
+ if (lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt
+
+ LineDash lineDash = strokeStyle.getLineDash();
+ int dashPatI[] = lineDash.pattern;
+ float[] dashPatF = new float[dashPatI.length];
+ final float dash_phase = 0;
+ for (int i=0; i<dashPatI.length; i++) {
+ dashPatF[i] = dashPatI[i]*lineWidth;
+ }
+
+ int lineCap;
+ switch (strokeStyle.getLineCap()) {
+ case ROUND:
+ lineCap = BasicStroke.CAP_ROUND;
+ break;
+ case SQUARE:
+ lineCap = BasicStroke.CAP_SQUARE;
+ break;
+ default:
+ case FLAT:
+ lineCap = BasicStroke.CAP_BUTT;
+ break;
+ }
+
+ int lineJoin = BasicStroke.JOIN_ROUND;
+
+ return new BasicStroke(lineWidth, lineCap, lineJoin, Math.max(1, lineWidth), dashPatF, dash_phase);
+ }
+
+ protected void drawShadow(
+ Graphics2D graphics
+ , Collection<Outline> outlines
+ , Paint fill
+ , Paint line
+ ) {
+ Shadow shadow = shape.getShadow();
+ if (shadow == null || (fill == null && line == null)) return;
+
+ double shapeRotation = shape.getRotation();
+ if(shape.getFlipVertical()) {
+ shapeRotation += 180;
+ }
+ double angle = shadow.getAngle() - shapeRotation;
+ double dist = shadow.getDistance();
+ double dx = dist * Math.cos(Math.toRadians(angle));
+ double dy = dist * Math.sin(Math.toRadians(angle));
+
+ graphics.translate(dx, dy);
+
+ for(Outline o : outlines){
+ java.awt.Shape s = o.getOutline();
+ Path p = o.getPath();
+ graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, s);
+
+ if(fill != null && p.isFilled()){
+ graphics.setPaint(fill);
+ graphics.fill(s);
+ } else if (line != null && p.isStroked()) {
+ graphics.setPaint(line);
+ graphics.draw(s);
+ }
+ }
+
+ graphics.translate(-dx, -dy);
+ }
+
+ protected static CustomGeometry getCustomGeometry(String name) {
+ return getCustomGeometry(name, null);
+ }
+
+ protected static CustomGeometry getCustomGeometry(String name, Graphics2D graphics) {
+ @SuppressWarnings("unchecked")
+ Map<String, CustomGeometry> presets = (graphics == null)
+ ? null
+ : (Map<String, CustomGeometry>)graphics.getRenderingHint(Drawable.PRESET_GEOMETRY_CACHE);
+
+ if (presets == null) {
+ presets = new HashMap<String,CustomGeometry>();
+ if (graphics != null) {
+ graphics.setRenderingHint(Drawable.PRESET_GEOMETRY_CACHE, presets);
+ }
+
+ String packageName = "org.apache.poi.sl.draw.binding";
+ InputStream presetIS = Drawable.class.getResourceAsStream("presetShapeDefinitions.xml");
+ Reader xml = new InputStreamReader( presetIS, Charset.forName("UTF-8") );
+
+ // StAX:
+ EventFilter startElementFilter = new EventFilter() {
+ @Override
+ public boolean accept(XMLEvent event) {
+ return event.isStartElement();
+ }
+ };
+
+ try {
+ XMLInputFactory staxFactory = XMLInputFactory.newInstance();
+ XMLEventReader staxReader = staxFactory.createXMLEventReader(xml);
+ XMLEventReader staxFiltRd = staxFactory.createFilteredReader(staxReader, startElementFilter);
+ // Ignore StartElement:
+ staxFiltRd.nextEvent();
+ // JAXB:
+ JAXBContext jaxbContext = JAXBContext.newInstance(packageName);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ while (staxFiltRd.peek() != null) {
+ StartElement evRoot = (StartElement)staxFiltRd.peek();
+ String cusName = evRoot.getName().getLocalPart();
+ // XMLEvent ev = staxReader.nextEvent();
+ JAXBElement<org.apache.poi.sl.draw.binding.CTCustomGeometry2D> el = unmarshaller.unmarshal(staxReader, CTCustomGeometry2D.class);
+ CTCustomGeometry2D cusGeom = el.getValue();
+
+ presets.put(cusName, new CustomGeometry(cusGeom));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to load preset geometries.", e);
+ }
+ }
+
+ return presets.get(name);
+ }
+
+ protected Collection<Outline> computeOutlines(Graphics2D graphics) {
+
+ List<Outline> lst = new ArrayList<Outline>();
+ CustomGeometry geom = shape.getGeometry();
+ if(geom == null) {
+ return lst;
+ }
+
+ Rectangle2D anchor = getAnchor(graphics, shape);
+ for (Path p : geom) {
+
+ double w = p.getW() == -1 ? anchor.getWidth() * Units.EMU_PER_POINT : p.getW();
+ double h = p.getH() == -1 ? anchor.getHeight() * Units.EMU_PER_POINT : p.getH();
+
+ // the guides in the shape definitions are all defined relative to each other,
+ // so we build the path starting from (0,0).
+ final Rectangle2D pathAnchor = new Rectangle2D.Double(0,0,w,h);
+
+ Context ctx = new Context(geom, pathAnchor, shape);
+
+ java.awt.Shape gp = p.getPath(ctx);
+
+ // translate the result to the canvas coordinates in points
+ AffineTransform at = new AffineTransform();
+ at.translate(anchor.getX(), anchor.getY());
+
+ double scaleX, scaleY;
+ if (p.getW() != -1) {
+ scaleX = anchor.getWidth() / p.getW();
+ } else {
+ scaleX = 1.0 / Units.EMU_PER_POINT;
+ }
+ if (p.getH() != -1) {
+ scaleY = anchor.getHeight() / p.getH();
+ } else {
+ scaleY = 1.0 / Units.EMU_PER_POINT;
+ }
+
+ at.scale(scaleX, scaleY);
+
+ java.awt.Shape canvasShape = at.createTransformedShape(gp);
+
+ lst.add(new Outline(canvasShape, p));
+ }
+
+ return lst;
+ }
+
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextBox.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextBox.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextBox.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextBox.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,9 @@
+package org.apache.poi.sl.draw;
+
+import org.apache.poi.sl.usermodel.*;
+
+public class DrawTextBox<T extends TextBox> extends DrawAutoShape<T> {
+ public DrawTextBox(T shape) {
+ super(shape);
+ }
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextFragment.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextFragment.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextFragment.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextFragment.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,94 @@
+package org.apache.poi.sl.draw;
+
+import java.awt.Graphics2D;
+import java.awt.font.TextLayout;
+import java.text.*;
+
+import org.apache.poi.xslf.usermodel.XSLFRenderingHint;
+
+public class DrawTextFragment implements Drawable {
+ final TextLayout layout;
+ final AttributedString str;
+ double x, y;
+
+ public DrawTextFragment(TextLayout layout, AttributedString str) {
+ this.layout = layout;
+ this.str = str;
+ }
+
+ public void setPosition(double x, double y) {
+ // TODO: replace it, by applyTransform????
+ this.x = x;
+ this.y = y;
+ }
+
+ public void draw(Graphics2D graphics){
+ if(str == null) {
+ return;
+ }
+
+ double yBaseline = y + layout.getAscent();
+
+ Integer textMode = (Integer)graphics.getRenderingHint(XSLFRenderingHint.TEXT_RENDERING_MODE);
+ if(textMode != null && textMode == XSLFRenderingHint.TEXT_AS_SHAPES){
+ layout.draw(graphics, (float)x, (float)yBaseline);
+ } else {
+ graphics.drawString(str.getIterator(), (float)x, (float)yBaseline );
+ }
+ }
+
+ public void applyTransform(Graphics2D graphics) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void drawContent(Graphics2D graphics) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public TextLayout getLayout() {
+ return layout;
+ }
+
+ public AttributedString getAttributedString() {
+ return str;
+ }
+
+ /**
+ * @return full height of this text run which is sum of ascent, descent and leading
+ */
+ public float getHeight(){
+ double h = Math.ceil(layout.getAscent()) + Math.ceil(layout.getDescent()) + layout.getLeading();
+ return (float)h;
+ }
+
+ /**
+ *
+ * @return width if this text run
+ */
+ public float getWidth(){
+ return layout.getAdvance();
+ }
+
+ /**
+ *
+ * @return the string to be painted
+ */
+ public String getString(){
+ if (str == null) return "";
+
+ AttributedCharacterIterator it = str.getIterator();
+ StringBuilder buf = new StringBuilder();
+ for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
+ buf.append(c);
+ }
+ return buf.toString();
+ }
+
+ @Override
+ public String toString(){
+ return "[" + getClass().getSimpleName() + "] " + getString();
+ }
+
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,381 @@
+package org.apache.poi.sl.draw;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.font.*;
+import java.awt.geom.Rectangle2D;
+import java.text.*;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.*;
+
+import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
+import org.apache.poi.sl.usermodel.TextRun.TextCap;
+import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+
+public class DrawTextParagraph implements Drawable {
+ protected TextParagraph paragraph;
+ double x, y;
+ protected Insets2D insets = new Insets2D(0,0,0,0);
+ protected List<DrawTextFragment> lines = new ArrayList<DrawTextFragment>();
+ protected String rawText;
+ protected DrawTextFragment bullet;
+
+ /**
+ * the highest line in this paragraph. Used for line spacing.
+ */
+ protected double maxLineHeight;
+
+ public DrawTextParagraph(TextParagraph paragraph) {
+ this.paragraph = paragraph;
+ }
+
+ public Insets2D getInsets() {
+ return insets;
+ }
+
+ public void setInsets(Insets2D insets) {
+ this.insets.set(insets.top, insets.left, insets.bottom, insets.right);
+ }
+
+ public void setPosition(double x, double y) {
+ // TODO: replace it, by applyTransform????
+ this.x = x;
+ this.y = y;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public void draw(Graphics2D graphics){
+ if (lines.isEmpty()) return;
+
+ double leftInset = insets.left;
+ double rightInset = insets.right;
+ double penY = y;
+
+ double leftMargin = paragraph.getLeftMargin();
+ boolean firstLine = true;
+ double indent = paragraph.getIndent();
+
+ //The vertical line spacing
+ double spacing = paragraph.getLineSpacing();
+ for(DrawTextFragment line : lines){
+ double penX = x + leftMargin;
+
+ if(firstLine) {
+ if (!isEmptyParagraph()) {
+ bullet = getBullet(graphics, line.getAttributedString().getIterator());
+ }
+
+ if(bullet != null){
+ if (indent < 0) {
+ // a negative value means "Hanging" indentation and
+ // indicates the position of the actual bullet character.
+ // (the bullet is shifted to right relative to the text)
+ bullet.setPosition(penX + indent, penY);
+ } else if(indent > 0){
+ // a positive value means the "First Line" indentation:
+ // the first line is indented and other lines start at the bullet ofset
+ bullet.setPosition(penX, penY);
+ penX += indent;
+ } else {
+ // a zero indent means that the bullet and text have the same offset
+ bullet.setPosition(penX, penY);
+
+ // don't let text overlay the bullet and advance by the bullet width
+ penX += bullet.getLayout().getAdvance() + 1;
+ }
+
+ bullet.draw(graphics);
+ } else {
+ penX += indent;
+ }
+ }
+
+ Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
+
+ switch (paragraph.getTextAlign()) {
+ case CENTER:
+ penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2;
+ break;
+ case RIGHT:
+ penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset);
+ break;
+ default:
+ break;
+ }
+
+ line.setPosition(penX, penY);
+ line.draw(graphics);
+
+ if(spacing > 0) {
+ // If linespacing >= 0, then linespacing is a percentage of normal line height.
+ penY += spacing*0.01* line.getHeight();
+ } else {
+ // positive value means absolute spacing in points
+ penY += -spacing;
+ }
+
+ firstLine = false;
+ }
+
+ y = penY - y;
+ }
+
+ public float getFirstLineHeight() {
+ return (lines.isEmpty()) ? 0 : lines.get(0).getHeight();
+ }
+
+ public float getLastLineHeight() {
+ return (lines.isEmpty()) ? 0 : lines.get(lines.size()-1).getHeight();
+ }
+
+ public boolean isEmptyParagraph() {
+ return (lines.isEmpty() || rawText.trim().isEmpty());
+ }
+
+ public void applyTransform(Graphics2D graphics) {
+ }
+
+ public void drawContent(Graphics2D graphics) {
+ }
+
+ /**
+ * break text into lines, each representing a line of text that fits in the wrapping width
+ *
+ * @param graphics
+ */
+ protected void breakText(Graphics2D graphics){
+ lines.clear();
+
+ DrawFactory fact = DrawFactory.getInstance(graphics);
+ StringBuilder text = new StringBuilder();
+ AttributedString at = getAttributedString(graphics, text);
+ boolean emptyParagraph = ("".equals(text.toString().trim()));
+
+ AttributedCharacterIterator it = at.getIterator();
+ LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());
+ for (;;) {
+ int startIndex = measurer.getPosition();
+
+ double wrappingWidth = getWrappingWidth(lines.size() == 0, graphics) + 1; // add a pixel to compensate rounding errors
+ // shape width can be smaller that the sum of insets (this was proved by a test file)
+ if(wrappingWidth < 0) wrappingWidth = 1;
+
+ int nextBreak = text.indexOf("\n", startIndex + 1);
+ if(nextBreak == -1) nextBreak = it.getEndIndex();
+
+ TextLayout layout = measurer.nextLayout((float)wrappingWidth, nextBreak, true);
+ if (layout == null) {
+ // layout can be null if the entire word at the current position
+ // does not fit within the wrapping width. Try with requireNextWord=false.
+ layout = measurer.nextLayout((float)wrappingWidth, nextBreak, false);
+ }
+
+ if(layout == null) {
+ // exit if can't break any more
+ break;
+ }
+
+ int endIndex = measurer.getPosition();
+ // skip over new line breaks (we paint 'clear' text runs not starting or ending with \n)
+ if(endIndex < it.getEndIndex() && text.charAt(endIndex) == '\n'){
+ measurer.setPosition(endIndex + 1);
+ }
+
+ TextAlign hAlign = paragraph.getTextAlign();
+ if(hAlign == TextAlign.JUSTIFY || hAlign == TextAlign.JUSTIFY_LOW) {
+ layout = layout.getJustifiedLayout((float)wrappingWidth);
+ }
+
+ AttributedString str = (emptyParagraph)
+ ? null // we will not paint empty paragraphs
+ : new AttributedString(it, startIndex, endIndex);
+ DrawTextFragment line = fact.getTextFragment(layout, str);
+ lines.add(line);
+
+ maxLineHeight = Math.max(maxLineHeight, line.getHeight());
+
+ if(endIndex == it.getEndIndex()) break;
+ }
+
+ rawText = text.toString();
+ }
+
+ protected DrawTextFragment getBullet(Graphics2D graphics, AttributedCharacterIterator firstLineAttr) {
+ BulletStyle bulletStyle = paragraph.getBulletStyle();
+ if (bulletStyle == null) return null;
+
+ String buCharacter = bulletStyle.getBulletCharacter();
+ if (buCharacter == null) return null;
+
+ String buFont = bulletStyle.getBulletFont();
+ if (buFont == null) buFont = paragraph.getDefaultFontFamily();
+ assert(buFont != null);
+
+ Color buColor = bulletStyle.getBulletFontColor();
+ if (buColor == null) buColor = (Color)firstLineAttr.getAttribute(TextAttribute.FOREGROUND);
+
+ float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE);
+ float buSz = (float)bulletStyle.getBulletFontSize();
+ if(buSz > 0) fontSize *= buSz* 0.01;
+ else fontSize = -buSz;
+
+
+ AttributedString str = new AttributedString(buCharacter);
+ str.addAttribute(TextAttribute.FOREGROUND, buColor);
+ str.addAttribute(TextAttribute.FAMILY, buFont);
+ str.addAttribute(TextAttribute.SIZE, fontSize);
+
+ TextLayout layout = new TextLayout(str.getIterator(), graphics.getFontRenderContext());
+ DrawFactory fact = DrawFactory.getInstance(graphics);
+ return fact.getTextFragment(layout, str);
+ }
+
+ protected String getRenderableText(TextRun tr) {
+ StringBuilder buf = new StringBuilder();
+ TextCap cap = tr.getTextCap();
+ for (char c : tr.getText().toCharArray()) {
+ if(c == '\t') {
+ // TODO: finish support for tabs
+ buf.append(" ");
+ continue;
+ }
+
+ switch (cap) {
+ case ALL: c = Character.toUpperCase(c); break;
+ case SMALL: c = Character.toLowerCase(c); break;
+ case NONE: break;
+ }
+
+ buf.append(c);
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Returns wrapping width to break lines in this paragraph
+ *
+ * @param firstLine whether the first line is breaking
+ *
+ * @return wrapping width in points
+ */
+ protected double getWrappingWidth(boolean firstLine, Graphics2D graphics){
+ // internal margins for the text box
+
+ double leftInset = insets.left;
+ double rightInset = insets.right;
+
+ Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
+
+ double leftMargin = paragraph.getLeftMargin();
+ double indent = paragraph.getIndent();
+
+ double width;
+ TextShape ts = paragraph.getParentShape();
+ if (!ts.getWordWrap()) {
+ // if wordWrap == false then we return the advance to the right border of the sheet
+ width = ts.getSheet().getSlideShow().getPageSize().getWidth() - anchor.getX();
+ } else {
+ width = anchor.getWidth() - leftInset - rightInset - leftMargin;
+ if (firstLine) {
+ if (bullet != null){
+ if (indent > 0) width -= indent;
+ } else {
+ if (indent > 0) width -= indent; // first line indentation
+ else if (indent < 0) { // hanging indentation: the first line start at the left margin
+ width += leftMargin;
+ }
+ }
+ }
+ }
+
+ return width;
+ }
+
+ private static class AttributedStringData {
+ Attribute attribute;
+ Object value;
+ int beginIndex, endIndex;
+ AttributedStringData(Attribute attribute, Object value, int beginIndex, int endIndex) {
+ this.attribute = attribute;
+ this.value = value;
+ this.beginIndex = beginIndex;
+ this.endIndex = endIndex;
+ }
+ }
+
+ protected AttributedString getAttributedString(Graphics2D graphics, StringBuilder text){
+ List<AttributedStringData> attList = new ArrayList<AttributedStringData>();
+ if (text == null) text = new StringBuilder();
+
+ DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);
+
+ for (TextRun run : paragraph){
+ String runText = getRenderableText(run);
+ // skip empty runs
+ if (runText.isEmpty()) continue;
+
+ int beginIndex = text.length();
+ text.append(runText);
+ int endIndex = text.length();
+
+ attList.add(new AttributedStringData(TextAttribute.FOREGROUND, run.getFontColor(), beginIndex, endIndex));
+
+ // user can pass an custom object to convert fonts
+ String fontFamily = run.getFontFamily();
+ @SuppressWarnings("unchecked")
+ Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
+ if (fontMap != null && fontMap.containsKey(fontFamily)) {
+ fontFamily = fontMap.get(fontFamily);
+ }
+ if(fontHandler != null) {
+ fontFamily = fontHandler.getRendererableFont(fontFamily, run.getPitchAndFamily());
+ }
+ attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFamily, beginIndex, endIndex));
+
+ float fontSz = (float)run.getFontSize();
+ attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, beginIndex, endIndex));
+
+ if(run.isBold()) {
+ attList.add(new AttributedStringData(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, beginIndex, endIndex));
+ }
+ if(run.isItalic()) {
+ attList.add(new AttributedStringData(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, beginIndex, endIndex));
+ }
+ if(run.isUnderline()) {
+ attList.add(new AttributedStringData(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, beginIndex, endIndex));
+ attList.add(new AttributedStringData(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_TWO_PIXEL, beginIndex, endIndex));
+ }
+ if(run.isStrikethrough()) {
+ attList.add(new AttributedStringData(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, beginIndex, endIndex));
+ }
+ if(run.isSubscript()) {
+ attList.add(new AttributedStringData(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB, beginIndex, endIndex));
+ }
+ if(run.isSuperscript()) {
+ attList.add(new AttributedStringData(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, beginIndex, endIndex));
+ }
+ }
+
+ // ensure that the paragraph contains at least one character
+ // We need this trick to correctly measure text
+ if (text.length() == 0) {
+ float fontSz = (float)paragraph.getDefaultFontSize();
+ text.append(" ");
+ attList.add(new AttributedStringData(TextAttribute.SIZE, fontSz, 0, 1));
+ }
+
+ AttributedString string = new AttributedString(text.toString());
+ for (AttributedStringData asd : attList) {
+ string.addAttribute(asd.attribute, asd.value, asd.beginIndex, asd.endIndex);
+ }
+
+ return string;
+ }
+
+
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextShape.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,140 @@
+package org.apache.poi.sl.draw;
+
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.Iterator;
+
+import org.apache.poi.sl.usermodel.*;
+
+public class DrawTextShape<T extends TextShape> extends DrawSimpleShape<T> {
+
+ public DrawTextShape(T shape) {
+ super(shape);
+ }
+
+ @Override
+ public void drawContent(Graphics2D graphics) {
+ Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
+ Insets2D insets = shape.getInsets();
+ double x = anchor.getX() + insets.left;
+ double y = anchor.getY();
+
+ // remember the initial transform
+ AffineTransform tx = graphics.getTransform();
+
+ // Transform of text in flipped shapes is special.
+ // At this point the flip and rotation transform is already applied
+ // (see XSLFShape#applyTransform ), but we need to restore it to avoid painting "upside down".
+ // See Bugzilla 54210.
+
+ if(shape.getFlipVertical()){
+ graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());
+ graphics.scale(1, -1);
+ graphics.translate(-anchor.getX(), -anchor.getY());
+
+ // text in vertically flipped shapes is rotated by 180 degrees
+ double centerX = anchor.getX() + anchor.getWidth()/2;
+ double centerY = anchor.getY() + anchor.getHeight()/2;
+ graphics.translate(centerX, centerY);
+ graphics.rotate(Math.toRadians(180));
+ graphics.translate(-centerX, -centerY);
+ }
+
+ // Horizontal flipping applies only to shape outline and not to the text in the shape.
+ // Applying flip second time restores the original not-flipped transform
+ if(shape.getFlipHorizontal()){
+ graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());
+ graphics.scale(-1, 1);
+ graphics.translate(-anchor.getX() , -anchor.getY());
+ }
+
+
+ // first dry-run to calculate the total height of the text
+ double textHeight = shape.getTextHeight();
+
+ switch (shape.getVerticalAlignment()){
+ case TOP:
+ y += insets.top;
+ break;
+ case BOTTOM:
+ y += anchor.getHeight() - textHeight - insets.bottom;
+ break;
+ default:
+ case MIDDLE:
+ double delta = anchor.getHeight() - textHeight - insets.top - insets.bottom;
+ y += insets.top + delta/2;
+ break;
+ }
+
+ drawParagraphs(graphics, x, y);
+
+ // restore the transform
+ graphics.setTransform(tx);
+ }
+
+ /**
+ * paint the paragraphs starting from top left (x,y)
+ *
+ * @return the vertical advance, i.e. the cumulative space occupied by the text
+ */
+ public double drawParagraphs(Graphics2D graphics, double x, double y) {
+ DrawFactory fact = DrawFactory.getInstance(graphics);
+ Insets2D shapePadding = shape.getInsets();
+
+ double y0 = y;
+ Iterator<TextParagraph> paragraphs = shape.iterator();
+
+ boolean isFirstLine = true;
+ while (paragraphs.hasNext()){
+ TextParagraph p = paragraphs.next();
+ DrawTextParagraph dp = fact.getDrawable(p);
+ dp.setInsets(shapePadding);
+ dp.breakText(graphics);
+
+ if (!isFirstLine) {
+ // the amount of vertical white space before the paragraph
+ double spaceBefore = p.getSpaceBefore();
+ if(spaceBefore > 0) {
+ // positive value means percentage spacing of the height of the first line, e.g.
+ // the higher the first line, the bigger the space before the paragraph
+ y += spaceBefore*0.01*dp.getFirstLineHeight();
+ } else {
+ // negative value means the absolute spacing in points
+ y += -spaceBefore;
+ }
+ isFirstLine = false;
+ }
+
+ dp.setPosition(x, y);
+ dp.draw(graphics);
+ y += dp.getY();
+
+ if (paragraphs.hasNext()) {
+ double spaceAfter = p.getSpaceAfter();
+ if(spaceAfter > 0) {
+ // positive value means percentage spacing of the height of the last line, e.g.
+ // the higher the last line, the bigger the space after the paragraph
+ y += spaceAfter*0.01*dp.getLastLineHeight();
+ } else {
+ // negative value means the absolute spacing in points
+ y += -spaceAfter;
+ }
+ }
+ }
+ return y - y0;
+ }
+
+ /**
+ * Compute the cumulative height occupied by the text
+ */
+ protected double getTextHeight(){
+ // dry-run in a 1x1 image and return the vertical advance
+ BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
+ Graphics2D graphics = img.createGraphics();
+ return drawParagraphs(graphics, 0, 0);
+ }
+
+
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/Drawable.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/Drawable.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/Drawable.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/Drawable.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,123 @@
+/* ====================================================================
+ 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 java.awt.RenderingHints;
+
+import org.apache.poi.util.Internal;
+
+
+public interface Drawable {
+ class DrawableHint extends RenderingHints.Key {
+ protected DrawableHint(int id) {
+ super(id);
+ }
+
+ public boolean isCompatibleValue(Object val) {
+ return true;
+ }
+ }
+
+ /**
+ * {@link DrawFactory} which will be used to draw objects into this graphics context
+ */
+ DrawableHint DRAW_FACTORY = new DrawableHint(1);
+
+ /**
+ * Key will be internally used to store affine transformation temporarily within group shapes
+ */
+ @Internal
+ DrawableHint GROUP_TRANSFORM = new DrawableHint(2);
+
+ /**
+ * Use a custom image renderer of an instance of {@link ImageRenderer}
+ */
+ DrawableHint IMAGE_RENDERER = new DrawableHint(3);
+
+ /**
+ * how to render text:
+ *
+ * {@link #TEXT_AS_CHARACTERS} (default) means to draw via
+ * {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}.
+ * This mode draws text as characters. Use it if the target graphics writes the actual
+ * character codes instead of glyph outlines (PDFGraphics2D, SVGGraphics2D, etc.)
+ *
+ * {@link #TEXT_AS_SHAPES} means to render via
+ * {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}.
+ * This mode draws glyphs as shapes and provides some advanced capabilities such as
+ * justification and font substitution. Use it if the target graphics is an image.
+ *
+ */
+ DrawableHint TEXT_RENDERING_MODE = new DrawableHint(4);
+
+ /**
+ * PathGradientPaint needs the shape to be set.
+ * It will be achieved through setting it in the rendering hints
+ */
+ DrawableHint GRADIENT_SHAPE = new DrawableHint(5);
+
+
+ /**
+ * Internal key for caching the preset geometries
+ */
+ DrawableHint PRESET_GEOMETRY_CACHE = new DrawableHint(6);
+
+ /**
+ * draw text via {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}
+ */
+ int TEXT_AS_CHARACTERS = 1;
+
+ /**
+ * draw text via {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}
+ */
+ int TEXT_AS_SHAPES = 2;
+
+ /**
+ * Use this object to resolve unknown / missing fonts when rendering slides
+ */
+ DrawableHint FONT_HANDLER = new DrawableHint(7);
+ DrawableHint FONT_FALLBACK = new DrawableHint(8);
+ DrawableHint FONT_MAP = new DrawableHint(9);
+
+ DrawableHint GSAVE = new DrawableHint(10);
+ DrawableHint GRESTORE = new DrawableHint(11);
+
+
+
+ /**
+ * Apply 2-D transforms before drawing this shape. This includes rotation and flipping.
+ *
+ * @param graphics the graphics whos transform matrix will be modified
+ */
+ void applyTransform(Graphics2D graphics);
+
+ /**
+ * Draw this shape into the supplied canvas
+ *
+ * @param graphics the graphics to draw into
+ */
+ void draw(Graphics2D graphics);
+
+ /**
+ * draw any content within this shape (image, text, etc.).
+ *
+ * @param graphics the graphics to draw into
+ */
+ void drawContent(Graphics2D graphics);
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/ImageRenderer.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/ImageRenderer.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/ImageRenderer.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/ImageRenderer.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,155 @@
+/*
+ * ====================================================================
+ * 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.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.RescaleOp;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+
+/**
+ * For now this class renders only images supported by the javax.imageio.ImageIO
+ * framework. Subclasses can override this class to support other formats, for
+ * example, Use Apache batik to render WMF:
+ *
+ * <pre>
+ * <code>
+ * public class MyImageRendener extends ImageRendener {
+ *
+ * public boolean drawImage(Graphics2D graphics,Rectangle2D anchor,Insets clip) {
+ * // draw image
+ * }
+ *
+ * public void loadImage(InputStream data, String contentType) throws IOException {
+ * if ("image/wmf".equals(contentType)) {
+ * // use Apache Batik to handle WMF
+ * } else {
+ * super.loadImage(data,contentType);
+ * }
+ * }
+ * }
+ * </code>
+ * </pre>
+ *
+ * and then pass this class to your instance of java.awt.Graphics2D:
+ *
+ * <pre>
+ * <code>
+ * graphics.setRenderingHint(Drawable.IMAGE_RENDERER, new MyImageRendener());
+ * </code>
+ * </pre>
+ */
+public class ImageRenderer {
+ protected BufferedImage img;
+
+ /**
+ * 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 = ImageIO.read(data);
+ }
+
+ /**
+ * @return the buffered image
+ */
+ public BufferedImage getImage() {
+ return img;
+ }
+
+ /**
+ * @return the dimension of the buffered image
+ */
+ public Dimension getDimension() {
+ return (img == null)
+ ? new Dimension(0,0)
+ : new Dimension(img.getWidth(),img.getHeight());
+ }
+
+ /**
+ * @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;
+ }
+
+
+ /**
+ * Render picture data into the supplied graphics
+ *
+ * @return true if the picture data was successfully rendered
+ */
+ public boolean drawImage(
+ Graphics2D graphics,
+ Rectangle2D anchor) {
+ return drawImage(graphics, anchor, null);
+ }
+
+ /**
+ * Render picture data into the supplied graphics
+ *
+ * @return true if the picture data was successfully rendered
+ */
+ public boolean drawImage(
+ Graphics2D graphics,
+ Rectangle2D anchor,
+ Insets clip) {
+ if (img == null) return false;
+
+ boolean isClipped = true;
+ if (clip == null) {
+ isClipped = false;
+ clip = new Insets(0,0,0,0);
+ }
+
+ int iw = img.getWidth();
+ int ih = img.getHeight();
+
+ double cw = (100000-clip.left-clip.right) / 100000.0;
+ double ch = (100000-clip.top-clip.bottom) / 100000.0;
+ double sx = anchor.getWidth()/(iw*cw);
+ double sy = anchor.getHeight()/(ih*ch);
+ double tx = anchor.getX()-(iw*sx*clip.left/100000.0);
+ double ty = anchor.getY()-(ih*sy*clip.top/100000.0);
+ AffineTransform at = new AffineTransform(sx, 0, 0, sy, tx, ty) ;
+
+ Shape clipOld = graphics.getClip();
+ if (isClipped) graphics.clip(anchor.getBounds2D());
+ graphics.drawRenderedImage(img, at);
+ graphics.setClip(clipOld);
+
+ return true;
+ }
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjPoint2D.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjPoint2D.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjPoint2D.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjPoint2D.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,126 @@
+/* ====================================================================
+ 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.binding;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import com.sun.xml.internal.bind.Locatable;
+import com.sun.xml.internal.bind.annotation.XmlLocation;
+import org.xml.sax.Locator;
+
+
+/**
+ * <p>Java class for CT_AdjPoint2D complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="CT_AdjPoint2D">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="x" use="required" type="{http://schemas.openxmlformats.org/drawingml/2006/main}ST_AdjCoordinate" />
+ * <attribute name="y" use="required" type="{http://schemas.openxmlformats.org/drawingml/2006/main}ST_AdjCoordinate" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "CT_AdjPoint2D", namespace = "http://schemas.openxmlformats.org/drawingml/2006/main")
+public class CTAdjPoint2D
+ implements Locatable
+{
+
+ @XmlAttribute(name = "x", required = true)
+ protected String x;
+ @XmlAttribute(name = "y", required = true)
+ protected String y;
+ @XmlLocation
+ @XmlTransient
+ protected Locator locator;
+
+ /**
+ * Gets the value of the x property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getX() {
+ return x;
+ }
+
+ /**
+ * Sets the value of the x property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setX(String value) {
+ this.x = value;
+ }
+
+ public boolean isSetX() {
+ return (this.x!= null);
+ }
+
+ /**
+ * Gets the value of the y property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getY() {
+ return y;
+ }
+
+ /**
+ * Sets the value of the y property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setY(String value) {
+ this.y = value;
+ }
+
+ public boolean isSetY() {
+ return (this.y!= null);
+ }
+
+ public Locator sourceLocation() {
+ return locator;
+ }
+
+ public void setSourceLocation(Locator newLocator) {
+ locator = newLocator;
+ }
+
+}
Added: poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjustHandleList.java
URL: http://svn.apache.org/viewvc/poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjustHandleList.java?rev=1661322&view=auto
==============================================================================
--- poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjustHandleList.java (added)
+++ poi/branches/common_sl/src/scratchpad/src/org/apache/poi/sl/draw/binding/CTAdjustHandleList.java Sat Feb 21 10:56:03 2015
@@ -0,0 +1,116 @@
+/* ====================================================================
+ 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.binding;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import com.sun.xml.internal.bind.Locatable;
+import com.sun.xml.internal.bind.annotation.XmlLocation;
+import org.xml.sax.Locator;
+
+
+/**
+ * <p>Java class for CT_AdjustHandleList complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="CT_AdjustHandleList">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <choice maxOccurs="unbounded" minOccurs="0">
+ * <element name="ahXY" type="{http://schemas.openxmlformats.org/drawingml/2006/main}CT_XYAdjustHandle"/>
+ * <element name="ahPolar" type="{http://schemas.openxmlformats.org/drawingml/2006/main}CT_PolarAdjustHandle"/>
+ * </choice>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "CT_AdjustHandleList", namespace = "http://schemas.openxmlformats.org/drawingml/2006/main", propOrder = {
+ "ahXYOrAhPolar"
+})
+public class CTAdjustHandleList
+ implements Locatable
+{
+
+ @XmlElements({
+ @XmlElement(name = "ahXY", namespace = "http://schemas.openxmlformats.org/drawingml/2006/main", type = CTXYAdjustHandle.class),
+ @XmlElement(name = "ahPolar", namespace = "http://schemas.openxmlformats.org/drawingml/2006/main", type = CTPolarAdjustHandle.class)
+ })
+ protected List<Object> ahXYOrAhPolar;
+ @XmlLocation
+ @XmlTransient
+ protected Locator locator;
+
+ /**
+ * Gets the value of the ahXYOrAhPolar property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the ahXYOrAhPolar property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getAhXYOrAhPolar().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link CTXYAdjustHandle }
+ * {@link CTPolarAdjustHandle }
+ *
+ *
+ */
+ public List<Object> getAhXYOrAhPolar() {
+ if (ahXYOrAhPolar == null) {
+ ahXYOrAhPolar = new ArrayList<Object>();
+ }
+ return this.ahXYOrAhPolar;
+ }
+
+ public boolean isSetAhXYOrAhPolar() {
+ return ((this.ahXYOrAhPolar!= null)&&(!this.ahXYOrAhPolar.isEmpty()));
+ }
+
+ public void unsetAhXYOrAhPolar() {
+ this.ahXYOrAhPolar = null;
+ }
+
+ public Locator sourceLocation() {
+ return locator;
+ }
+
+ public void setSourceLocation(Locator newLocator) {
+ locator = newLocator;
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org