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.GeneralPath; | |
19 | import java.awt.geom.Line2D; | |
20 | import java.awt.geom.Point2D; | |
21 | import java.awt.image.BufferedImage; | |
22 | import java.io.IOException; | |
23 | ||
24 | import javax.imageio.ImageIO; | |
25 | ||
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 PivotingImageShaper { |
42 | ||
43 | /** | |
44 | * the number of pixels to skip while sampling the | |
45 | * images edges | |
46 | */ | |
47 | 0 | static int sample = 1; |
48 | /** | |
49 | * the first x coordinate of the shape. Used to discern | |
50 | * when we are done | |
51 | */ | |
52 | 0 | static int firstx = 0; |
53 | ||
54 | public static Shape getShape(String fileName) { | |
55 | 0 | return getShape(fileName, Integer.MAX_VALUE); |
56 | } | |
57 | public static Shape getShape(String fileName, int max) { | |
58 | 0 | BufferedImage image = null; |
59 | try { | |
60 | 0 | image = ImageIO.read(FourPassImageShaper.class.getResource(fileName)); |
61 | 0 | } catch(IOException ex) { |
62 | 0 | ex.printStackTrace(); |
63 | 0 | } |
64 | 0 | return getShape(image, max); |
65 | } | |
66 | ||
67 | /** | |
68 | * Given an image, possibly with a transparent background, return | |
69 | * the Shape of the opaque part of the image | |
70 | * @param image | |
71 | * @return the Shape | |
72 | */ | |
73 | public static Shape getShape(Image image) { | |
74 | 0 | return getShape(image, Integer.MAX_VALUE); |
75 | } | |
76 | public static Shape getShape(Image image, int max) { | |
77 | 0 | BufferedImage bi = |
78 | new BufferedImage(image.getWidth(null), image.getHeight(null), | |
79 | BufferedImage.TYPE_INT_ARGB); | |
80 | 0 | Graphics g = bi.createGraphics(); |
81 | 0 | g.drawImage(image, 0, 0, null); |
82 | 0 | g.dispose(); |
83 | 0 | return getShape(bi, max); |
84 | } | |
85 | ||
86 | /** | |
87 | * Given an image, possibly with a transparent background, return | |
88 | * the Shape of the opaque part of the image | |
89 | * @param image | |
90 | * @return the Shape | |
91 | */ | |
92 | public static Shape getShape(BufferedImage image, int max) { | |
93 | ||
94 | 0 | float width = image.getWidth(); |
95 | 0 | float height = image.getHeight(); |
96 | 0 | if(width > max || height > max) { |
97 | 0 | BufferedImage smaller = |
98 | new BufferedImage(max, max, BufferedImage.TYPE_INT_ARGB); | |
99 | 0 | Graphics g = smaller.createGraphics(); |
100 | 0 | AffineTransform at = AffineTransform.getScaleInstance(max/width,max/height); |
101 | 0 | AffineTransform back = AffineTransform.getScaleInstance(width/max,height/max); |
102 | 0 | Graphics2D g2 = (Graphics2D)g; |
103 | 0 | g2.drawImage(image, at, null); |
104 | 0 | g2.dispose(); |
105 | 0 | return back.createTransformedShape(getShape(smaller)); |
106 | } else { | |
107 | 0 | return getShape(image); |
108 | } | |
109 | } | |
110 | ||
111 | /** | |
112 | * Given an image, possibly with a transparent background, return | |
113 | * the Shape of the opaque part of the image | |
114 | * @param image | |
115 | * @return the Shape | |
116 | */ | |
117 | public static Shape getShape(BufferedImage image) { | |
118 | 0 | firstx = 0; |
119 | 0 | return leftEdge(image, new GeneralPath()); |
120 | } | |
121 | ||
122 | private static Point2D detectLine(Point2D p1, Point2D p2, Point2D p, | |
123 | Line2D line, GeneralPath path) { | |
124 | 0 | if(p2 == null) { |
125 | 0 | p2 = p; |
126 | 0 | line.setLine(p1,p2); |
127 | } | |
128 | // check for line | |
129 | 0 | else if(line.ptLineDistSq(p) < 1) { // its on the line |
130 | // make it p2 | |
131 | 0 | p2.setLocation(p); |
132 | } else { // its not on the current line | |
133 | 0 | p1.setLocation(p2); |
134 | 0 | p2.setLocation(p); |
135 | 0 | line.setLine(p1,p2); |
136 | 0 | path.lineTo((float)p1.getX(), (float)p1.getY()); |
137 | } | |
138 | 0 | return p2; |
139 | } | |
140 | /** | |
141 | * trace the left side of the image | |
142 | * @param image | |
143 | * @param path | |
144 | * @return | |
145 | */ | |
146 | private static Shape leftEdge(BufferedImage image, GeneralPath path) { | |
147 | 0 | int lastj = 0; |
148 | 0 | Point2D p1 = null; |
149 | 0 | Point2D p2 = null; |
150 | 0 | Line2D line = new Line2D.Float(); |
151 | 0 | for(int i=0; i<image.getHeight(); i+=sample) { |
152 | 0 | boolean aPointExistsOnThisLine = false; |
153 | // go until we reach an opaque point, then stop | |
154 | 0 | for(int j=0; j<image.getWidth(); j+=sample) { |
155 | 0 | if((image.getRGB(j,i) & 0xff000000) != 0) { |
156 | // this is a point I want | |
157 | 0 | Point2D p = new Point2D.Float(j,i); |
158 | 0 | aPointExistsOnThisLine = true; |
159 | 0 | if(path.getCurrentPoint() != null) { |
160 | // this is a continuation of a path | |
161 | 0 | p2 = detectLine(p1,p2,p,line,path); |
162 | } else { | |
163 | // this is the first point in the path | |
164 | 0 | path.moveTo(j,i); |
165 | 0 | firstx = j; |
166 | 0 | p1 = p; |
167 | } | |
168 | 0 | lastj = j; |
169 | 0 | break; |
170 | } | |
171 | } | |
172 | 0 | if(aPointExistsOnThisLine == false) { |
173 | 0 | break; |
174 | } | |
175 | } | |
176 | 0 | return bottomEdge(image, path, lastj); |
177 | } | |
178 | ||
179 | /** | |
180 | * trace the bottom of the image | |
181 | * @param image | |
182 | * @param path | |
183 | * @param start | |
184 | * @return | |
185 | */ | |
186 | private static Shape bottomEdge(BufferedImage image, GeneralPath path, int start) { | |
187 | 0 | int lastj = 0; |
188 | 0 | Point2D p1 = path.getCurrentPoint(); |
189 | 0 | Point2D p2 = null; |
190 | 0 | Line2D line = new Line2D.Float(); |
191 | 0 | for(int i=start; i<image.getWidth(); i+=sample) { |
192 | 0 | boolean aPointExistsOnThisLine = false; |
193 | 0 | for(int j=image.getHeight()-1; j>=0; j-=sample) { |
194 | 0 | if((image.getRGB(i,j) & 0xff000000) != 0) { |
195 | // this is a point I want | |
196 | 0 | Point2D p = new Point2D.Float(i,j); |
197 | 0 | aPointExistsOnThisLine = true; |
198 | 0 | p2 = detectLine(p1,p2,p,line,path); |
199 | 0 | lastj = j; |
200 | 0 | break; |
201 | } | |
202 | } | |
203 | 0 | if(aPointExistsOnThisLine == false) { |
204 | 0 | break; |
205 | } | |
206 | } | |
207 | 0 | return rightEdge(image, path, lastj); |
208 | } | |
209 | ||
210 | /** | |
211 | * trace the right side of the image | |
212 | * @param image | |
213 | * @param path | |
214 | * @param start | |
215 | * @return | |
216 | */ | |
217 | private static Shape rightEdge(BufferedImage image, GeneralPath path, int start) { | |
218 | 0 | int lastj = 0; |
219 | 0 | Point2D p1 = path.getCurrentPoint(); |
220 | 0 | Point2D p2 = null; |
221 | 0 | Line2D line = new Line2D.Float(); |
222 | 0 | for(int i=start; i>=0; i-=sample) { |
223 | 0 | boolean aPointExistsOnThisLine = false; |
224 | ||
225 | 0 | for(int j=image.getWidth()-1; j>=0; j-=sample) { |
226 | 0 | if((image.getRGB(j,i) & 0xff000000) != 0) { |
227 | // this is a point I want | |
228 | 0 | Point2D p = new Point2D.Float(j,i); |
229 | 0 | aPointExistsOnThisLine = true; |
230 | 0 | p2 = detectLine(p1,p2,p,line,path); |
231 | 0 | lastj=j; |
232 | 0 | break; |
233 | } | |
234 | } | |
235 | 0 | if(aPointExistsOnThisLine == false) { |
236 | 0 | break; |
237 | } | |
238 | } | |
239 | 0 | return topEdge(image, path, lastj); |
240 | } | |
241 | ||
242 | /** | |
243 | * trace the top of the image | |
244 | * @param image | |
245 | * @param path | |
246 | * @param start | |
247 | * @return | |
248 | */ | |
249 | private static Shape topEdge(BufferedImage image, GeneralPath path, int start) { | |
250 | 0 | Point2D p1 = path.getCurrentPoint(); |
251 | 0 | Point2D p2 = null; |
252 | 0 | Line2D line = new Line2D.Float(); |
253 | 0 | for(int i=start; i>=firstx; i-=sample) { |
254 | 0 | boolean aPointExistsOnThisLine = false; |
255 | 0 | for(int j=0; j<image.getHeight(); j+=sample) { |
256 | 0 | if((image.getRGB(i,j) & 0xff000000) != 0) { |
257 | // this is a point I want | |
258 | 0 | Point2D p = new Point2D.Float(i,j); |
259 | 0 | aPointExistsOnThisLine = true; |
260 | 0 | p2 = detectLine(p1,p2,p,line,path); |
261 | 0 | break; |
262 | } | |
263 | } | |
264 | 0 | if(aPointExistsOnThisLine == false) { |
265 | 0 | break; |
266 | } | |
267 | } | |
268 | 0 | path.closePath(); |
269 | 0 | return path; |
270 | } | |
271 | } |
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |