Revision: 649
Author: allain.lalonde
Date: Wed Aug  5 07:47:02 2009
Log: Fixed issue 106. Added fillStrategy to the toImage method.

Not sure if this method will stick around long term in 2.0, since it's  
doing something that more appropriately belongs in a helper class of some  
sort, but it works now.  Tests have been added aswell.
http://code.google.com/p/piccolo2d/source/detail?r=649

Modified:
  /piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PNode.java
  /piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PNodeTest.java

=======================================
--- /piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PNode.java      
 
Tue Aug  4 18:13:28 2009
+++ /piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PNode.java      
 
Wed Aug  5 07:47:02 2009
@@ -44,13 +44,13 @@
  import java.awt.image.BufferedImage;
  import java.awt.print.Book;
  import java.awt.print.PageFormat;
-import java.awt.print.Paper;
  import java.awt.print.Printable;
  import java.awt.print.PrinterException;
  import java.awt.print.PrinterJob;
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  import java.io.ByteArrayInputStream;
+import java.io.File;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
@@ -64,6 +64,7 @@
  import java.util.List;
  import java.util.ListIterator;

+import javax.imageio.ImageIO;
  import javax.swing.event.EventListenerList;
  import javax.swing.event.SwingPropertyChangeSupport;
  import javax.swing.text.MutableAttributeSet;
@@ -353,6 +354,25 @@
      /** Stores the name associated to this node. */
      private String name;

+    /**
+     * toImage fill strategy that stretches the node be as large as  
possible
+     * while still retaining its aspect ratio.
+     */
+    public static final int FILL_STRATEGY_ASPECT_FIT = 1;
+
+    /**
+     * toImage fill strategy that stretches the node be large enough to  
cover
+     * the image, and centers it.
+     */
+    public static final int FILL_STRATEGY_ASPECT_COVER = 2;
+
+    /**
+     * toImage fill strategy that stretches the node to be exactly the
+     * dimensions of the image. Will result in distortion if the aspect  
ratios
+     * are different.
+     */
+    public static final int FILL_STRATEGY_EXACT_FIT = 4;
+
      /**
       * Creates a new PNode with the given name.
       *
@@ -2865,23 +2885,79 @@
       *         image
       */
      public Image toImage(final BufferedImage image, final Paint  
backGroundPaint) {
-        final int width = image.getWidth();
-        final int height = image.getHeight();
+        return toImage(image, backGroundPaint, FILL_STRATEGY_ASPECT_FIT);
+    }
+
+    /**
+     * Paint a representation of this node into the specified buffered  
image. If
+     * background, paint is null, then the image will not be filled with a  
color
+     * prior to rendering
+     *
+     * @param image Image onto which this node will be painted
+     * @param backGroundPaint will fill background of image with this. May  
be
+     *            null.
+     * @param fillStrategy strategy to use regarding how node will cover  
the
+     *            image
+     * @return a rendering of this image and its descendants onto the  
specified
+     *         image
+     */
+    public Image toImage(final BufferedImage image, final Paint  
backGroundPaint, int fillStrategy) {
+        final int imageWidth = image.getWidth();
+        final int imageHeight = image.getHeight();
          final Graphics2D g2 = image.createGraphics();

          if (backGroundPaint != null) {
              g2.setPaint(backGroundPaint);
-            g2.fillRect(0, 0, width, height);
+            g2.fillRect(0, 0, imageWidth, imageHeight);
          }

-        // reuse print method
-        final Paper paper = new Paper();
-        paper.setSize(width, height);
-        paper.setImageableArea(0, 0, width, height);
-        final PageFormat pageFormat = new PageFormat();
-        pageFormat.setPaper(paper);
-        print(g2, pageFormat, 0);
-
+        final PBounds imageBounds = getFullBounds();
+
+        imageBounds.expandNearestIntegerDimensions();
+
+        g2.setClip(0, 0, imageWidth, imageHeight);
+
+        double imageRatio = imageWidth / (imageHeight * 1.0);
+        double nodeRatio = getWidth() / getHeight();
+        double scale;
+        switch (fillStrategy) {
+            case FILL_STRATEGY_ASPECT_FIT:
+                // scale the graphics so node's full bounds fit in the  
imageable
+                // bounds but aspect ration is retained
+
+                if (nodeRatio <= imageRatio) {
+                    scale = image.getHeight() / getHeight();
+                }
+                else {
+                    scale = image.getWidth() / getWidth();
+                }
+                g2.scale(scale, scale);
+                g2.translate(-imageBounds.x, -imageBounds.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();
+                }
+                else {
+                    scale = image.getHeight() / getHeight();
+                }
+                g2.scale(scale, scale);
+                g2.translate(-getWidth()*scale, -getHeight()*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);
+                break;
+            default:
+                throw new IllegalArgumentException("Fill strategy provided  
is invalid");
+        }
+
+        final PPaintContext pc = new PPaintContext(g2);
+        pc.setRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING);
+        fullPaint(pc);
          return image;
      }

@@ -3642,5 +3718,5 @@
           * @param node node needing repaint
           */
          void nodeFullBoundsInvalidated(PNode node);
-    }
-}
+    }
+}
=======================================
---  
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PNodeTest.java      
 
Fri Jul 31 14:04:44 2009
+++  
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PNodeTest.java      
 
Wed Aug  5 07:47:02 2009
@@ -1029,6 +1029,54 @@
          assertEquals(Color.BLUE.getRGB(), img.getRGB(19, 20));
      }

+    public void testToImageScalesAccordingToExactFitStrategy() throws  
IOException {
+        node.setBounds(0, 0, 10, 10);
+        node.setPaint(Color.RED);
+
+        final BufferedImage img = (BufferedImage) node.toImage(new  
BufferedImage(20, 40, BufferedImage.TYPE_INT_RGB),
+                Color.BLUE, PNode.FILL_STRATEGY_EXACT_FIT);
+
+        assertEquals(Color.RED.getRGB(), img.getRGB(0, 0));
+        assertEquals(Color.RED.getRGB(), img.getRGB(19, 0));
+        assertEquals(Color.RED.getRGB(), img.getRGB(0, 39));
+        assertEquals(Color.RED.getRGB(), img.getRGB(19, 39));
+
+    }
+
+    public void testToImageScalesAccordingToAspectCoverStrategy() throws  
IOException {
+        node.setBounds(0, 0, 10, 10);
+        node.setPaint(Color.RED);
+
+        PNode blueSquare = new PNode();
+        blueSquare.setPaint(Color.BLUE);
+        blueSquare.setBounds(0, 0, 5, 5);
+        node.addChild(blueSquare);
+
+        PNode greenSquare = new PNode();
+        greenSquare.setPaint(Color.GREEN);
+        greenSquare.setBounds(5, 5, 5, 5);
+        node.addChild(greenSquare);
+
+
+        final BufferedImage img = (BufferedImage) node.toImage(new  
BufferedImage(20, 40, BufferedImage.TYPE_INT_RGB),
+                Color.BLUE, PNode.FILL_STRATEGY_EXACT_FIT);
+
+        assertEquals(Color.RED.getRGB(), img.getRGB(11, 19));
+        assertEquals(Color.RED.getRGB(), img.getRGB(9, 20));
+        assertEquals(Color.RED.getRGB(), img.getRGB(0, 20));
+        assertEquals(Color.RED.getRGB(), img.getRGB(9, 39));
+
+        assertEquals(Color.BLUE.getRGB(), img.getRGB(9, 19));
+        assertEquals(Color.BLUE.getRGB(), img.getRGB(0, 0));
+        assertEquals(Color.BLUE.getRGB(), img.getRGB(0, 19));
+        assertEquals(Color.BLUE.getRGB(), img.getRGB(9, 0));
+
+        assertEquals(Color.GREEN.getRGB(), img.getRGB(10, 20));
+        assertEquals(Color.GREEN.getRGB(), img.getRGB(19, 20));
+        assertEquals(Color.GREEN.getRGB(), img.getRGB(10, 39));
+        assertEquals(Color.GREEN.getRGB(), img.getRGB(19, 39));
+    }
+
      public void testGetPickableShouldDefaultToTrue() {
          assertTrue(node.getPickable());
      }

--~--~---------~--~----~------------~-------~--~----~
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to