1
2
3
4 package de.desy.acop.video;
5
6 import java.awt.Dimension;
7 import java.awt.Rectangle;
8 import java.awt.geom.Rectangle2D;
9 import java.beans.PropertyChangeListener;
10 import java.beans.PropertyChangeSupport;
11
12 import de.desy.acop.video.displayer.ImageZoom;
13
14
15
16
17
18
19
20
21
22
23 public class ScaleHelper {
24
25 public static final String PROPERTY_IMAGE_AOI = "imageAoi";
26 public static final String PROPERTY_IMAGE_DIMENSION = "imageDimension";
27 public static final String PROPERTY_COMPONENT_DIMENSION = "componentDimension";
28 public static final String PROPERTY_ACTIVE_RECTANGLE = "activeRectangle";
29 public static final String PROPERTY_KEEP_ASPECT_RATIO = "keepAspectRatio";
30 public static final String PROPERTY_AOI_ZOOM = "aoiZoom";
31 public static final String PROPERTY_IMAGE_ZOOM = "imageZoom";
32
33 private PropertyChangeSupport pcSupport;
34
35 private Rectangle imageAoi = null;
36 private Dimension imageDimension = null;
37 private Dimension componentDimension = null;
38 private Rectangle2D activeRectangle = null;
39 private boolean keepAspectRatio;
40 private boolean aoiZoom;
41 private ImageZoom imageZoom;
42
43
44
45
46
47 public ScaleHelper(boolean keepAspectRatio, boolean aoiZoom, ImageZoom imageZoom) {
48 this.keepAspectRatio = keepAspectRatio;
49 this.aoiZoom = aoiZoom;
50 this.imageZoom = imageZoom;
51 }
52
53
54
55
56
57
58
59 public synchronized Rectangle componentToImage(Rectangle2D componentRect) {
60 if (imageAoi == null || activeRectangle == null) return null;
61 int roiX = (int) Math.round((componentRect.getX()-activeRectangle.getX())/activeRectangle.getWidth()*imageAoi.width);
62 int roiY = (int) Math.round((componentRect.getY()-activeRectangle.getY())/activeRectangle.getHeight()*imageAoi.height);
63 int roiW = (int) Math.round(componentRect.getWidth()/activeRectangle.getWidth()*imageAoi.width);
64 int roiH = (int) Math.round(componentRect.getHeight()/activeRectangle.getHeight()*imageAoi.height);
65 return new Rectangle(roiX, roiY, roiW, roiH);
66 }
67
68
69
70
71
72
73
74 public synchronized Rectangle2D imageToComponent(Rectangle2D rectangle) {
75 return internalImageToComponent(rectangle);
76 }
77
78 private Rectangle2D internalImageToComponent(Rectangle2D rectangle) {
79 if (imageAoi == null || componentDimension == null) return null;
80
81 boolean isAspectKeeped = imageZoom == ImageZoom.AUTO && keepAspectRatio;
82 Dimension size = isAspectKeeped ? getKeepedRatioSize(new Dimension(imageDimension.width, imageDimension.height)) : getZoomedSize();
83
84 Rectangle rectDst = new Rectangle((componentDimension.width-size.width)/2, (componentDimension.height-size.height)/2, size.width, size.height);
85
86 if (aoiZoom) {
87 if (imageZoom == ImageZoom.AUTO && keepAspectRatio) {
88 size = getKeepedRatioSize(imageAoi.getSize());
89 rectDst = new Rectangle((componentDimension.width-size.width)/2, (componentDimension.height-size.height)/2, size.width, size.height);
90 }
91
92 } else {
93 double wscale_full = (double) rectDst.width / (double) imageDimension.width;
94 double hscale_full = (double) rectDst.height / (double) imageDimension.height;
95 rectDst.width = (int) Math.round(imageAoi.width * wscale_full);
96 rectDst.height = (int) Math.round(imageAoi.height * hscale_full);
97 rectDst.x += ((int) (imageAoi.x * wscale_full));
98 rectDst.y += ((int) (imageAoi.y * hscale_full));
99 }
100
101 double rh = (double)rectDst.width/(double)imageAoi.width;
102 double rv = (double)rectDst.height/(double)imageAoi.height;
103
104 double x = rectangle.getX()*rh+rectDst.x;
105 double y = rectangle.getY()*rv+rectDst.y;
106 double w = rectangle.getWidth()*rh;
107 double h = rectangle.getHeight()*rv;
108
109 return new Rectangle2D.Double(x, y, w, h);
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 }
144
145
146
147
148 private Dimension getZoomedSize() {
149 switch (imageZoom) {
150 case AUTO:
151 return new Dimension(componentDimension);
152
153 case HALF:
154 return new Dimension(
155 Math.round((float)imageDimension.width/2),
156 Math.round((float)imageDimension.height/2));
157
158 case NORMAL:
159 return new Dimension(imageDimension);
160
161 case DOUBLE:
162 return new Dimension(imageDimension.width*2, imageDimension.height*2);
163
164 default:
165 throw new IllegalStateException("unsupported image zoom: " + imageZoom);
166 }
167 }
168
169
170
171
172 private Dimension getKeepedRatioSize(Dimension src) {
173 float ratio = (float) src.width / (float) src.height;
174 int width = componentDimension.width;
175 int height = componentDimension.height;
176 if (width > height) {
177 int tmp = Math.round(ratio * height);
178 if (tmp > width)
179 return new Dimension(width, Math.round(width / ratio));
180 else
181 return new Dimension(tmp, height);
182 } else
183 return new Dimension(width, Math.round(width / ratio));
184 }
185
186
187
188
189
190 public Dimension getImageDimension() {
191 return imageDimension;
192 }
193
194
195
196
197
198 public Rectangle getImageAoi() {
199 return imageAoi;
200 }
201
202
203
204
205
206
207 public synchronized void setImageData(Dimension imageDimension, Rectangle imageAoi) {
208 Dimension oldDim = this.imageDimension;
209 Rectangle oldAoi = this.imageAoi;
210 if (imageDimension == null || imageAoi == null) {
211 imageDimension = null;
212 imageAoi = null;
213 }
214 this.imageDimension = imageDimension;
215 this.imageAoi = imageAoi;
216 getPcSupport().firePropertyChange(PROPERTY_IMAGE_AOI, oldAoi, imageAoi);
217 getPcSupport().firePropertyChange(PROPERTY_IMAGE_DIMENSION, oldDim, imageDimension);
218 if (imageAoi == null) {
219 setActiveRectangle(null);
220 return;
221 }
222 setActiveRectangle(internalImageToComponent(imageAoi));
223 }
224
225
226
227
228
229
230 public synchronized Dimension getComponentDimension() {
231 return componentDimension;
232 }
233
234
235
236
237
238
239 public synchronized void setComponentDimesnion(Dimension componentDimension) {
240 if (
241 this.componentDimension != null && componentDimension != null &&
242 this.componentDimension.width == componentDimension.width &&
243 this.componentDimension.height == componentDimension.height) return;
244 Dimension old = this.componentDimension;
245 this.componentDimension = componentDimension;
246 getPcSupport().firePropertyChange(PROPERTY_COMPONENT_DIMENSION, old, componentDimension);
247 if (imageAoi == null) return;
248 setActiveRectangle(internalImageToComponent(imageAoi));
249 }
250
251
252
253
254
255
256
257 public synchronized Rectangle2D getActiveRectangle() {
258 return activeRectangle;
259 }
260
261 private void setActiveRectangle(Rectangle2D activeRectangle) {
262 Rectangle2D old = this.activeRectangle;
263 this.activeRectangle = activeRectangle;
264 getPcSupport().firePropertyChange(PROPERTY_ACTIVE_RECTANGLE, old, activeRectangle);
265 }
266
267
268
269
270
271
272 public synchronized boolean isKeepAspectRatio() {
273 return keepAspectRatio;
274 }
275
276
277
278
279
280
281 public synchronized void setKeepAspectRatio(boolean keepAspectRatio) {
282 boolean old = this.keepAspectRatio;
283 this.keepAspectRatio = keepAspectRatio;
284 getPcSupport().firePropertyChange(PROPERTY_KEEP_ASPECT_RATIO, old, keepAspectRatio);
285 if (imageAoi == null) return;
286 setActiveRectangle(internalImageToComponent(imageAoi));
287 }
288
289
290
291
292
293 public synchronized boolean isAoiZoom() {
294 return aoiZoom;
295 }
296
297
298
299
300
301 public synchronized void setAoiZoom(boolean aoiZoom) {
302 boolean old = this.aoiZoom;
303 this.aoiZoom = aoiZoom;
304 getPcSupport().firePropertyChange(PROPERTY_AOI_ZOOM, old, aoiZoom);
305 if (imageAoi == null) return;
306 setActiveRectangle(internalImageToComponent(imageAoi));
307 }
308
309
310
311
312
313 public synchronized ImageZoom getImageZoom() {
314 return imageZoom;
315 }
316
317
318
319
320
321 public synchronized void setImageZoom(ImageZoom imageZoom) {
322 ImageZoom old = this.imageZoom;
323 this.imageZoom = imageZoom;
324 getPcSupport().firePropertyChange(PROPERTY_IMAGE_ZOOM, old, imageZoom);
325 if (imageAoi == null) return;
326 setActiveRectangle(internalImageToComponent(imageAoi));
327 }
328
329 private PropertyChangeSupport getPcSupport() {
330 if (pcSupport == null) {
331 pcSupport = new PropertyChangeSupport(this);
332 }
333 return pcSupport;
334 }
335
336
337
338
339
340
341 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
342 getPcSupport().addPropertyChangeListener(propertyName, listener);
343 }
344
345
346
347
348
349
350 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
351 getPcSupport().removePropertyChangeListener(propertyName, listener);
352 }
353
354
355
356
357
358 public void addPropertyChangeListener(PropertyChangeListener listener) {
359 getPcSupport().addPropertyChangeListener(listener);
360 }
361
362
363
364
365
366 public void removePropertyChangeListener(PropertyChangeListener listener) {
367 getPcSupport().removePropertyChangeListener(listener);
368 }
369
370 }