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. |