| Line | Hits | Source |
|---|---|---|
| 1 | /* | |
| 2 | * Copyright (c) 2005, the JUNG Project and the Regents of the University of | |
| 3 | * California All rights reserved. | |
| 4 | * | |
| 5 | * This software is open-source under the BSD license; see either "license.txt" | |
| 6 | * or http://jung.sourceforge.net/license.txt for a description. | |
| 7 | * | |
| 8 | * Created on Jun 17, 2005 | |
| 9 | */ | |
| 10 | ||
| 11 | package edu.uci.ics.jung.visualization; | |
| 12 | ||
| 13 | import java.awt.Graphics; | |
| 14 | import java.awt.Graphics2D; | |
| 15 | import java.awt.Image; | |
| 16 | import java.awt.Shape; | |
| 17 | import java.awt.geom.AffineTransform; | |
| 18 | import java.awt.geom.Area; | |
| 19 | import java.awt.geom.GeneralPath; | |
| 20 | import java.awt.geom.Line2D; | |
| 21 | import java.awt.geom.Point2D; | |
| 22 | import java.awt.image.BufferedImage; | |
| 23 | import java.io.IOException; | |
| 24 | ||
| 25 | import javax.imageio.ImageIO; | |
| 26 | ||
| 27 | /** | |
| 28 | * Provides factory methods that, given a BufferedImage, an Image, | |
| 29 | * or the fileName of an image, will return a java.awt.Shape that | |
| 30 | * is the contiguous traced outline of the opaque part of the image. | |
| 31 | * This could be used to define an image for use in a Vertex, where | |
| 32 | * the shape used for picking and edge-arrow placement follows the | |
| 33 | * opaque part of an image that has a transparent background. | |
| 34 | * The methods try to detect lines in order to minimize points | |
| 35 | * in the path | |
| 36 | * | |
| 37 | * @author Tom Nelson - RABA Technologies | |
| 38 | * | |
| 39 | * | |
| 40 | */ | |
| 41 | 0 | public class FourPassImageShaper { |
| 42 | ||
| 43 | /** | |
| 44 | * given the fileName of an image, possibly with a transparent | |
| 45 | * background, return the Shape of the opaque part of the image | |
| 46 | * @param fileName name of the image, loaded from the classpath | |
| 47 | * @return the Shape | |
| 48 | */ | |
| 49 | public static Shape getShape(String fileName) { | |
| 50 | 0 | return getShape(fileName, Integer.MAX_VALUE); |
| 51 | } | |
| 52 | public static Shape getShape(String fileName, int max) { | |
| 53 | 0 | BufferedImage image = null; |
| 54 | try { | |
| 55 | 0 | image = ImageIO.read(FourPassImageShaper.class.getResource(fileName)); |
| 56 | 0 | } catch(IOException ex) { |
| 57 | 0 | ex.printStackTrace(); |
| 58 | 0 | } |
| 59 | 0 | return getShape(image, max); |
| 60 | } | |
| 61 | ||
| 62 | /** | |
| 63 | * Given an image, possibly with a transparent background, return | |
| 64 | * the Shape of the opaque part of the image | |
| 65 | * @param image | |
| 66 | * @return the Shape | |
| 67 | */ | |
| 68 | public static Shape getShape(Image image) { | |
| 69 | 0 | return getShape(image, Integer.MAX_VALUE); |
| 70 | } | |
| 71 | public static Shape getShape(Image image, int max) { | |
| 72 | 0 | BufferedImage bi = |
| 73 | new BufferedImage(image.getWidth(null), image.getHeight(null), | |
| 74 | BufferedImage.TYPE_INT_ARGB); | |
| 75 | 0 | Graphics g = bi.createGraphics(); |
| 76 | 0 | g.drawImage(image, 0, 0, null); |
| 77 | 0 | g.dispose(); |
| 78 | 0 | return getShape(bi, max); |
| 79 | } | |
| 80 | ||
| 81 | /** | |
| 82 | * Given an image, possibly with a transparent background, return | |
| 83 | * the Shape of the opaque part of the image | |
| 84 | * | |
| 85 | * If the image is larger than max in either direction, scale the | |
| 86 | * image down to max-by-max, do the trace (on fewer points) then | |
| 87 | * scale the resulting shape back up to the size of the original | |
| 88 | * image. | |
| 89 | * | |
| 90 | * @param image the image to trace | |
| 91 | * @param max used to restrict number of points in the resulting shape | |
| 92 | * @return the Shape | |
| 93 | */ | |
| 94 | public static Shape getShape(BufferedImage image, int max) { | |
| 95 | ||
| 96 | 0 | float width = image.getWidth(); |
| 97 | 0 | float height = image.getHeight(); |
| 98 | 0 | if(width > max || height > max) { |
| 99 | 0 | BufferedImage smaller = |
| 100 | new BufferedImage(max, max, BufferedImage.TYPE_INT_ARGB); | |
| 101 | 0 | Graphics g = smaller.createGraphics(); |
| 102 | 0 | AffineTransform at = AffineTransform.getScaleInstance(max/width,max/height); |
| 103 | 0 | AffineTransform back = AffineTransform.getScaleInstance(width/max,height/max); |
| 104 | 0 | Graphics2D g2 = (Graphics2D)g; |
| 105 | 0 | g2.drawImage(image, at, null); |
| 106 | 0 | g2.dispose(); |
| 107 | 0 | return back.createTransformedShape(getShape(smaller)); |
| 108 | } else { | |
| 109 | 0 | return getShape(image); |
| 110 | } | |
| 111 | } | |
| 112 | ||
| 113 | public static Shape getShape(BufferedImage image) { | |
| 114 | 0 | Area area = new Area(leftEdge(image)); |
| 115 | 0 | area.intersect(new Area(bottomEdge(image))); |
| 116 | 0 | area.intersect(new Area(rightEdge(image))); |
| 117 | 0 | area.intersect(new Area(topEdge(image))); |
| 118 | 0 | return area; |
| 119 | } | |
| 120 | /** | |
| 121 | * Checks to see if point p is on a line that passes thru | |
| 122 | * points p1 and p2. If p is on the line, extend the line | |
| 123 | * segment so that it is from p1 to the location of p. | |
| 124 | * If the point p is not on the line, update my shape | |
| 125 | * with a line extending to the old p2 location, make | |
| 126 | * the old p2 the new p1, and make p2 the old p | |
| 127 | * @param p1 | |
| 128 | * @param p2 | |
| 129 | * @param p | |
| 130 | * @param line | |
| 131 | * @param path | |
| 132 | * @return | |
| 133 | */ | |
| 134 | private static Point2D detectLine(Point2D p1, Point2D p2, Point2D p, | |
| 135 | Line2D line, GeneralPath path) { | |
| 136 | 0 | if(p2 == null) { |
| 137 | 0 | p2 = p; |
| 138 | 0 | line.setLine(p1,p2); |
| 139 | } | |
| 140 | // check for line | |
| 141 | 0 | else if(line.ptLineDistSq(p) < 1) { // its on the line |
| 142 | // make it p2 | |
| 143 | 0 | p2.setLocation(p); |
| 144 | } else { // its not on the current line | |
| 145 | 0 | p1.setLocation(p2); |
| 146 | 0 | p2.setLocation(p); |
| 147 | 0 | line.setLine(p1,p2); |
| 148 | 0 | path.lineTo((float)p1.getX(), (float)p1.getY()); |
| 149 | } | |
| 150 | 0 | return p2; |
| 151 | } | |
| 152 | /** | |
| 153 | * trace the left side of the image | |
| 154 | * @param image | |
| 155 | * @param path | |
| 156 | * @return | |
| 157 | */ | |
| 158 | private static Shape leftEdge(BufferedImage image) { | |
| 159 | 0 | GeneralPath path = new GeneralPath(); |
| 160 | 0 | Point2D p1 = new Point2D.Float(image.getWidth()-1, 0); |
| 161 | 0 | Point2D p2 = null; |
| 162 | 0 | Line2D line = new Line2D.Float(); |
| 163 | 0 | Point2D p = new Point2D.Float(); |
| 164 | 0 | path.moveTo(image.getWidth()-1, 0); |
| 165 | ||
| 166 | 0 | for(int i=0; i<image.getHeight(); i++) { |
| 167 | 0 | p.setLocation(image.getWidth()-1, i); |
| 168 | // go until we reach an opaque point, then stop | |
| 169 | 0 | for(int j=0; j<image.getWidth(); j++) { |
| 170 | 0 | if((image.getRGB(j,i) & 0xff000000) != 0) { |
| 171 | // this is a point I want | |
| 172 | 0 | p.setLocation(j,i); |
| 173 | 0 | break; |
| 174 | } | |
| 175 | } | |
| 176 | 0 | p2 = detectLine(p1, p2, p, line, path); |
| 177 | } | |
| 178 | 0 | p.setLocation(image.getWidth()-1, image.getHeight()-1); |
| 179 | 0 | detectLine(p1, p2, p, line, path); |
| 180 | 0 | path.closePath(); |
| 181 | 0 | return path; |
| 182 | } | |
| 183 | ||
| 184 | /** | |
| 185 | * trace the bottom of the image | |
| 186 | * @param image | |
| 187 | * @param path | |
| 188 | * @param start | |
| 189 | * @return | |
| 190 | */ | |
| 191 | private static Shape bottomEdge(BufferedImage image) { | |
| 192 | 0 | GeneralPath path = new GeneralPath(); |
| 193 | 0 | Point2D p1 = new Point2D.Float(0, 0); |
| 194 | 0 | Point2D p2 = null; |
| 195 | 0 | Line2D line = new Line2D.Float(); |
| 196 | 0 | Point2D p = new Point2D.Float(); |
| 197 | 0 | path.moveTo(0, 0); |
| 198 | 0 | for(int i=0; i<image.getWidth(); i++) { |
| 199 | 0 | p.setLocation(i, 0); |
| 200 | 0 | for(int j=image.getHeight()-1; j>=0; j--) { |
| 201 | 0 | if((image.getRGB(i,j) & 0xff000000) != 0) { |
| 202 | // this is a point I want | |
| 203 | 0 | p.setLocation(i,j); |
| 204 | 0 | break; |
| 205 | } | |
| 206 | } | |
| 207 | 0 | p2 = detectLine(p1, p2, p, line, path); |
| 208 | } | |
| 209 | 0 | p.setLocation(image.getWidth()-1, 0); |
| 210 | 0 | detectLine(p1, p2, p, line, path); |
| 211 | 0 | path.closePath(); |
| 212 | 0 | return path; |
| 213 | } | |
| 214 | ||
| 215 | /** | |
| 216 | * trace the right side of the image | |
| 217 | * @param image | |
| 218 | * @param path | |
| 219 | * @param start | |
| 220 | * @return | |
| 221 | */ | |
| 222 | private static Shape rightEdge(BufferedImage image) { | |
| 223 | 0 | GeneralPath path = new GeneralPath(); |
| 224 | 0 | Point2D p1 = new Point2D.Float(0, image.getHeight()-1); |
| 225 | 0 | Point2D p2 = null; |
| 226 | 0 | Line2D line = new Line2D.Float(); |
| 227 | 0 | Point2D p = new Point2D.Float(); |
| 228 | 0 | path.moveTo(0, image.getHeight()-1); |
| 229 | ||
| 230 | 0 | for(int i=image.getHeight()-1; i>=0; i--) { |
| 231 | 0 | p.setLocation(0, i); |
| 232 | 0 | for(int j=image.getWidth()-1; j>=0; j--) { |
| 233 | 0 | if((image.getRGB(j,i) & 0xff000000) != 0) { |
| 234 | // this is a point I want | |
| 235 | 0 | p.setLocation(j,i); |
| 236 | 0 | break; |
| 237 | } | |
| 238 | } | |
| 239 | 0 | p2 = detectLine(p1, p2, p, line, path); |
| 240 | } | |
| 241 | 0 | p.setLocation(0, 0); |
| 242 | 0 | detectLine(p1, p2, p,line, path); |
| 243 | 0 | path.closePath(); |
| 244 | 0 | return path; |
| 245 | } | |
| 246 | ||
| 247 | /** | |
| 248 | * trace the top of the image | |
| 249 | * @param image | |
| 250 | * @param path | |
| 251 | * @param start | |
| 252 | * @return | |
| 253 | */ | |
| 254 | private static Shape topEdge(BufferedImage image) { | |
| 255 | 0 | GeneralPath path = new GeneralPath(); |
| 256 | 0 | Point2D p1 = new Point2D.Float(image.getWidth()-1, image.getHeight()-1); |
| 257 | 0 | Point2D p2 = null; |
| 258 | 0 | Line2D line = new Line2D.Float(); |
| 259 | 0 | Point2D p = new Point2D.Float(); |
| 260 | 0 | path.moveTo(image.getWidth()-1, image.getHeight()-1); |
| 261 | ||
| 262 | 0 | for(int i=image.getWidth()-1; i>=0; i--) { |
| 263 | 0 | p.setLocation(i, image.getHeight()-1); |
| 264 | 0 | for(int j=0; j<image.getHeight(); j++) { |
| 265 | 0 | if((image.getRGB(i,j) & 0xff000000) != 0) { |
| 266 | // this is a point I want | |
| 267 | 0 | p.setLocation(i,j); |
| 268 | 0 | break; |
| 269 | } | |
| 270 | } | |
| 271 | 0 | p2 = detectLine(p1, p2, p, line, path); |
| 272 | } | |
| 273 | 0 | p.setLocation(0, image.getHeight()-1); |
| 274 | 0 | detectLine(p1, p2, p, line, path); |
| 275 | 0 | path.closePath(); |
| 276 | 0 | return path; |
| 277 | } | |
| 278 | } |
|
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |