diff --git a/core/src/main/java/edu/umd/cs/piccolo/PNode.java b/core/src/main/java/edu/umd/cs/piccolo/PNode.java index 1121896..506e20d 100644 --- a/core/src/main/java/edu/umd/cs/piccolo/PNode.java +++ b/core/src/main/java/edu/umd/cs/piccolo/PNode.java @@ -2907,15 +2907,16 @@ g2.setPaint(backGroundPaint); g2.fillRect(0, 0, imageWidth, imageHeight); } - - final PBounds imageBounds = getFullBounds(); - - imageBounds.expandNearestIntegerDimensions(); - g2.setClip(0, 0, imageWidth, imageHeight); + final PBounds nodeBounds = getFullBounds(); + nodeBounds.expandNearestIntegerDimensions(); + + final double nodeWidth = nodeBounds.getWidth(); + final double nodeHeight = nodeBounds.getHeight(); + double imageRatio = imageWidth / (imageHeight * 1.0); - double nodeRatio = getWidth() / getHeight(); + double nodeRatio = nodeWidth / nodeHeight; double scale; switch (fillStrategy) { case FILL_STRATEGY_ASPECT_FIT: @@ -2923,31 +2924,31 @@ // bounds but aspect ration is retained if (nodeRatio <= imageRatio) { - scale = image.getHeight() / getHeight(); + scale = image.getHeight() / nodeHeight; } else { - scale = image.getWidth() / getWidth(); + scale = image.getWidth() / nodeWidth; } g2.scale(scale, scale); - g2.translate(-imageBounds.x, -imageBounds.y); + g2.translate(-nodeBounds.x, -nodeBounds.y); break; case FILL_STRATEGY_ASPECT_COVER: // scale the graphics so node completely covers the imageable // area, but retains its aspect ratio. if (nodeRatio <= imageRatio) { - scale = image.getWidth() / getWidth(); + scale = image.getWidth() / nodeWidth; } else { - scale = image.getHeight() / getHeight(); + scale = image.getHeight() / nodeHeight; } g2.scale(scale, scale); - g2.translate(-getWidth() * scale, -getHeight() * scale); + g2.translate(-nodeWidth * scale, -nodeHeight * scale); break; case FILL_STRATEGY_EXACT_FIT: - // scale the node so that it - g2.scale(image.getWidth() / getWidth(), image.getHeight() / getHeight()); - - g2.translate(-imageBounds.x, -imageBounds.y); + // scale the node so that it covers then entire image, + // distorting it if necessary. + g2.scale(image.getWidth() / nodeWidth, image.getHeight() / nodeHeight); + g2.translate(-nodeBounds.x, -nodeBounds.y); break; default: throw new IllegalArgumentException("Fill strategy provided is invalid"); diff --git a/core/src/test/java/edu/umd/cs/piccolo/PNodeTest.java b/core/src/test/java/edu/umd/cs/piccolo/PNodeTest.java index bacf518..04e3110 100644 --- a/core/src/test/java/edu/umd/cs/piccolo/PNodeTest.java +++ b/core/src/test/java/edu/umd/cs/piccolo/PNodeTest.java @@ -32,11 +32,14 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.GraphicsEnvironment; +import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; import java.beans.PropertyChangeEvent; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -44,6 +47,7 @@ import java.util.Iterator; import java.util.ListIterator; +import javax.imageio.ImageIO; import javax.swing.text.MutableAttributeSet; import junit.framework.TestCase; @@ -202,47 +206,46 @@ node.setPaintInvalid(true); node.setPickable(false); node.setPropertyChangeParentMask(PNode.PROPERTY_CODE_PAINT); - node.setVisible(false); - + node.setVisible(false); + final PNode clonedNode = (PNode) node.clone(); assertEquals(1, clonedNode.getX(), Double.MIN_VALUE); assertEquals(2, clonedNode.getY(), Double.MIN_VALUE); assertEquals(3, clonedNode.getWidth(), Double.MIN_VALUE); - assertEquals(4, clonedNode.getHeight(), Double.MIN_VALUE); + assertEquals(4, clonedNode.getHeight(), Double.MIN_VALUE); assertTrue(clonedNode.getChildPaintInvalid()); assertFalse(clonedNode.getChildrenPickable()); assertEquals(Color.YELLOW, clonedNode.getPaint()); - + assertFalse(clonedNode.getPickable()); assertEquals(PNode.PROPERTY_CODE_PAINT, node.getPropertyChangeParentMask()); - assertFalse(clonedNode.getVisible()); - } - - public void testCloneCopiesTransforms() { + assertFalse(clonedNode.getVisible()); + } + + public void testCloneCopiesTransforms() { node.setScale(0.5); - node.setRotation(Math.PI/8d); - node.setOffset(5,6); - + node.setRotation(Math.PI / 8d); + node.setOffset(5, 6); + final PNode clonedNode = (PNode) node.clone(); - + assertEquals(0.5, clonedNode.getScale(), 0.00001); - assertEquals(Math.PI/8d, clonedNode.getRotation(), 0.00001); + assertEquals(Math.PI / 8d, clonedNode.getRotation(), 0.00001); assertEquals(5, clonedNode.getXOffset(), Double.MIN_VALUE); assertEquals(6, clonedNode.getYOffset(), Double.MIN_VALUE); - } + } - public void testCloneClonesChildrenAswell() { + public void testCloneClonesChildrenAswell() { final PNode child = new PNode(); node.addChild(child); final PNode clonedNode = (PNode) node.clone(); - + assertEquals(clonedNode.getChildrenCount(), 1); assertNotSame(child, clonedNode.getChild(0)); } - public void testLocalToGlobal() { final PNode aParent = new PNode(); final PNode aChild = new PNode(); @@ -1028,6 +1031,28 @@ assertEquals(Color.RED.getRGB(), img.getRGB(9, 9)); } + public void testToImageUsesFullBoundsWhenConvertingImage() throws IOException { + node.setBounds(0, 0, 50, 50); + PNode child1 = new PNode(); + child1.setBounds(0, 0, 100, 50); + child1.setPaint(Color.RED); + node.addChild(child1); + + PNode child2 = new PNode(); + child2.setBounds(0, 0, 50, 100); + child2.setPaint(Color.BLUE); + node.addChild(child2); + + BufferedImage image = (BufferedImage) node.toImage(); + assertNotNull(image); + assertEquals(100, image.getWidth()); + assertEquals(100, image.getHeight()); + assertEquals(Color.RED.getRGB(), image.getRGB(99, 1)); + + //This line fails if PNode.toImage uses getWidth() rather than getFullBounds().getWidth() + assertEquals(Color.BLUE.getRGB(), image.getRGB(1, 99)); + } + public void testToImageWillAcceptBackgroundPaint() { node.setBounds(0, 0, 10, 10);