source: trunk/src/org/expeditee/items/Picture.java@ 7

Last change on this file since 7 was 7, checked in by ra33, 16 years ago

New expeditee version

File size: 13.0 KB
Line 
1package org.expeditee.items;
2
3import java.awt.AlphaComposite;
4import java.awt.Color;
5import java.awt.Dimension;
6import java.awt.Graphics2D;
7import java.awt.Image;
8import java.awt.Point;
9import java.awt.Polygon;
10import java.awt.Rectangle;
11import java.awt.Shape;
12import java.awt.geom.AffineTransform;
13import java.awt.image.ImageObserver;
14import java.io.File;
15import java.io.IOException;
16import java.text.DecimalFormat;
17import java.util.List;
18
19import javax.imageio.ImageIO;
20import javax.swing.ImageIcon;
21
22import org.expeditee.gui.Frame;
23import org.expeditee.gui.FrameGraphics;
24import org.expeditee.gui.FrameIO;
25import org.expeditee.io.Logger;
26
27/**
28 * This class represents an Image loaded from a file which is shown on the
29 * screen. Loading of the Image from disk occurs in the constructor, and takes
30 * approximately one second per mb of the Image file size. <br>
31 * <br>
32 * Currently Supported (Tested) Image formats:<br>
33 * BMP<br>
34 * JPG<br>
35 * GIF<br>
36 * GIF (Animated)<br>
37 * <br>
38 * Currently only the default size of the Image is supported, but future
39 * versions may support scaling.
40 *
41 * @author jdm18
42 *
43 */
44public class Picture extends Item {
45
46 public static final int WIDTH = 0;
47
48 public static final int RATIO = 1;
49
50 public static final int FRACTION = 2;
51
52 private Image _image = null;
53
54 private Polygon _poly = null;
55
56 // private Polygon _circle = null;
57 private Text _source = null;
58
59 // true if this is a frame picture
60 private boolean _isFrame = false;
61
62 private int _numerator = -1;
63
64 private int _denominator = -1;
65
66 private float _ratio = 1.0f;
67
68 private int _width = -1;
69
70 private int _scaleType = RATIO;
71
72 private float _scale = 1.0f;
73
74 private Point _cropStart = null;
75
76 private Point _cropEnd = null;
77
78 private Point _cropOrigin = null;
79
80 private boolean _showCropping = false;
81
82 // used to repaint animated GIF images, among other things.
83 private ImageObserver _imageObserver = null;
84
85 /**
86 * Creates a new Picture from the given path. The ImageObserver is optional
87 * and can be set to NULL. <br>
88 * Note: It is assumed that the file described in path has already been
89 * checked to exist.
90 *
91 * @param source
92 * The Text Item that was used to create this Picture
93 * @param path
94 * The Path of the Image to load from disk.
95 * @param observer
96 * The ImageObserver to assign when painting the Image on the
97 * screen.
98 */
99 public Picture(Text source, String path, String size, ImageObserver observer)
100 throws IllegalArgumentException {
101 super();
102 _source = source;
103 _imageObserver = observer;
104
105 // Check if the picture is being created with @f
106 if (path == null && source.getLink() != null) {
107 String link = source.getLink();
108 if (FrameIO.isPositiveInteger(link)) {
109 link = source.getParent().getFramesetNameAdjusted() + link;
110 }
111 Frame frame = FrameIO.LoadFrame(link);
112 FrameGraphics.UpdateBuffer(frame, false);
113 _image = frame.getBuffer();
114 _isFrame = true;
115 } else {
116
117 // ImageIcon is faster, but cannot handle some formats
118 // (notably
119 // .bmp)
120 // hence, we try this first, then if it fails we try
121 // ImageIO
122 _image = new ImageIcon(path).getImage();
123
124 // if ImageIcon failed to read the image
125 if (_image.getWidth(null) <= 0) {
126 try {
127 _image = ImageIO.read(new File(path));
128 } catch (IOException e) {
129 // e.printStackTrace();
130 Logger.Log(e);
131 _image = null;
132 }
133 }
134 }
135
136 if (_image == null)
137 throw new IllegalArgumentException();
138
139 try {
140 if (size.length() == 0) {
141 size = "" + _image.getWidth(null);
142 _source.setText(_source.getFirstLine() + " " + size);
143 }
144
145 // parse size from text
146 if (size.contains("/")) {
147 // this is a fraction
148 _numerator = Integer.parseInt(size.substring(0, size
149 .indexOf("/")));
150 _denominator = Integer.parseInt(size.substring(size
151 .indexOf("/") + 1));
152 _scale = (_numerator * 1.0f) / _denominator;
153 _scaleType = FRACTION;
154 } else if (size.contains(".")) {
155 // this is a ratio
156 _ratio = Float.parseFloat(size);
157 _scaleType = RATIO;
158 _scale = _ratio;
159 } else if (size.length() > 0) {
160 // this is an absolute width
161 _width = Integer.parseInt(size);
162 _scaleType = WIDTH;
163 _scale = _width / (_image.getWidth(null) * 1.0f);
164 }
165 } catch (Exception e) {
166 size = "" + _image.getWidth(null);
167 _source.setText("@f " + size);
168 FrameGraphics.ErrorMessage("Invalid argument for @f tag");
169 }
170
171 }
172
173 public void setStartCrop(int x, int y) {
174 _cropStart = new Point(x - getX(), y - getY());
175 _cropOrigin = new Point(getX(), getY());
176 }
177
178 public void setEndCrop(int x, int y) {
179 _cropEnd = new Point(x - getX(), y - getY());
180 }
181
182 public void setShowCrop(boolean value) {
183 _showCropping = value;
184 }
185
186 public int getCroppedSize() {
187 if (_cropStart == null || _cropEnd == null)
188 return 0;
189
190 int diff = (_cropEnd.x - _cropStart.x);
191 diff *= (_cropEnd.y - _cropStart.y);
192 return diff;
193 }
194
195 public void clearCropping() {
196 _cropStart = null;
197 _cropEnd = null;
198 setShowCrop(false);
199 }
200
201 protected void updatePolygon() {
202 if (_image == null)
203 return;
204
205 _poly = new Polygon();
206
207 if (_cropStart == null || _cropEnd == null) {
208 int width = _image.getWidth(null);
209 int height = _image.getHeight(null);
210
211 width *= _scale;
212 height *= _scale;
213
214 int xdiff = 0;
215
216 if (getLink() != null || getAction() != null) {
217 xdiff -= 10;
218 }
219
220 // extra pixel around the image so the highlighting is visible
221 _poly.addPoint(_source.getX() - 1 + xdiff, _source.getY() - 1);
222 _poly.addPoint(_source.getX() + 1 + width, _source.getY() - 1);
223 _poly.addPoint(_source.getX() + 1 + width, _source.getY() + 1
224 + height);
225 _poly.addPoint(_source.getX() - 1 + xdiff, _source.getY() + 1
226 + height);
227 } else {
228 Rectangle clip = new Rectangle(_source.getX() + _cropStart.x
229 + _cropOrigin.x, _source.getY() + _cropStart.y
230 + _cropOrigin.y, _cropEnd.x - _cropStart.x, _cropEnd.y
231 - _cropStart.y).getBounds();
232 _poly.addPoint((int) clip.getMinX() - 1, (int) clip.getMinY() - 1);
233 _poly.addPoint((int) clip.getMinX() - 1, (int) clip.getMaxY() + 1);
234 _poly.addPoint((int) clip.getMaxX() + 1, (int) clip.getMaxY() + 1);
235 _poly.addPoint((int) clip.getMaxX() + 1, (int) clip.getMinY() - 1);
236
237 }
238 }
239
240 /**
241 * Returns the Text Item that was used to create this Picture object. This
242 * is required by KMSWriter for saving the Frame.
243 *
244 * @return The Text Item used to create this Picture.
245 */
246 public Text getText() {
247 return _source;
248 }
249
250 @Override
251 public int getID() {
252 return _source.getID();
253 }
254
255 @Override
256 public void setID(int newID) {
257 _source.setID(newID);
258 }
259
260 @Override
261 public int getY() {
262 return _source.getY();
263 }
264
265 @Override
266 public int getX() {
267 return _source.getX();
268 }
269
270 @Override
271 public void setPosition(int x, int y) {
272 _source.setPosition(x, y);
273
274 updatePolygon();
275 }
276
277 @Override
278 public String getLink() {
279 if (_source == null)
280 return null;
281 else
282 return _source.getLink();
283 }
284
285 @Override
286 public void setLink(String frameName) {
287 if (_source == null)
288 return;
289 else {
290 _source.setLink(frameName);
291
292 if (_isFrame) {
293 Frame frame = FrameIO.LoadFrame(_source.getLink());
294 // if (frame.getBuffer() == null)
295 FrameGraphics.UpdateBuffer(frame, false);
296 _image = frame.getBuffer();
297 }
298 }
299
300 updatePolygon();
301 }
302
303 @Override
304 public void setAction(List<String> action) {
305 if (_source == null)
306 return;
307 else
308 _source.setAction(action);
309
310 updatePolygon();
311 }
312
313 @Override
314 public List<String> getAction() {
315 if (_source == null)
316 return null;
317 else
318 return _source.getAction();
319 }
320
321 @Override
322 public void paint(Graphics2D g) {
323 if (_image == null)
324 return;
325
326 int width = _image.getWidth(null);
327 int height = _image.getHeight(null);
328
329 width *= _scale;
330 height *= _scale;
331
332 if (getLink() != null || getAction() != null) {
333 g.setColor(getPaintHighlightColor());
334
335 AffineTransform at = new AffineTransform();
336 AffineTransform orig = g.getTransform();
337 at.translate(getX() - 12, getY() + (getBoundsHeight() / 2));
338 g.setTransform(at);
339
340 if (getLinkMark() && getLink() != null) {
341 g.drawPolygon(getCircle());
342
343 // if the link is not valid, cross out the circle
344 if (!isLinkValid())
345 g.drawPolygon(getCircleCross());
346 }
347
348 if (getActionMark() && getAction() != null) {
349 g.drawPolygon(getCircle());
350 g.fillPolygon(getCircle());
351
352 // if the link is not valid, cross out the circle
353 if (getLink() != null && !isLinkValid()) {
354 g.setColor(getPaintBackgroundColor());
355 g.drawPolygon(getCircleCross());
356 }
357 }
358 g.setTransform(orig);
359 }
360
361 if (isHighlighted()) {
362 g.setColor(getHighlightColor());
363 g.drawPolygon(getPolygon());
364 }
365
366 // if we are showing the cropping, then show the original as transparent
367 if (_showCropping && _cropStart != null && _cropEnd != null) {
368 // show the full image as transparent
369 float alpha = .5f;
370 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
371 alpha));
372 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
373 _imageObserver);
374
375 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
376 1.0f));
377 // show the cropped area normally
378 Shape clip = new Rectangle(_source.getX() + _cropStart.x, _source
379 .getY()
380 + _cropStart.y, _cropEnd.x - _cropStart.x, _cropEnd.y
381 - _cropStart.y);
382 g.setColor(getPaintHighlightColor());
383 g.draw(clip);
384 g.setClip(clip);
385
386 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
387 _imageObserver);
388 g.draw(clip);
389 // if the image is cropped, but we are not showing the cropping
390 } else if (_cropStart != null && _cropEnd != null) {
391 Shape clip = new Rectangle(_source.getX() + _cropStart.x
392 + _cropOrigin.x, _source.getY() + _cropStart.y
393 + _cropOrigin.y, _cropEnd.x - _cropStart.x, _cropEnd.y
394 - _cropStart.y);
395 g.setClip(clip);
396
397 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
398 _imageObserver);
399
400 // otherwise, paint normally
401 } else {
402 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
403 _imageObserver);
404 }
405 }
406
407 @Override
408 public Polygon getPolygon() {
409 if (_poly == null)
410 updatePolygon();
411
412 Polygon external = new Polygon(_poly.xpoints, _poly.ypoints,
413 _poly.npoints);
414 return external;
415 }
416
417 @Override
418 public int showHighlight(boolean val) {
419 super.showHighlight(val);
420
421 return Item.DEFAULT_CURSOR;
422 }
423
424 @Override
425 public Picture copy() {
426 Picture p;
427
428 if (_isFrame) {
429 p = ItemUtils.CreateFramePicture((Text) _source.copy(),
430 _imageObserver);
431 } else
432 p = ItemUtils.CreatePicture((Text) _source.copy(), _imageObserver);
433
434 Item.DuplicateItem(this, p);
435
436 if (_cropStart != null)
437 p.setStartCrop(_cropStart.x, _cropStart.y);
438
439 if (_cropEnd != null)
440 p.setEndCrop(_cropEnd.x, _cropEnd.y);
441
442 return p;
443 }
444
445 @Override
446 public void setMaxSize(Dimension d) {
447 // TODO Auto-generated method stub
448 }
449
450 @Override
451 public Color getColor() {
452 return _source.getColor();
453 }
454
455 @Override
456 public void setColor(Color c) {
457 _source.setColor(c);
458 }
459
460 @Override
461 public int getSize() {
462 return _source.getSize();
463 }
464
465 @Override
466 public void setSize(int size) {
467 int diff = size - _source.getSize();
468 float oldScale = _scale;
469
470 int oldDenom = _denominator;
471 int oldNumer = _numerator;
472 float oldRatio = _ratio;
473 int oldWidth = _width;
474
475 switch (_scaleType) {
476 case (FRACTION):
477 _numerator += diff;
478 _scale = (_numerator * 1.0f) / _denominator;
479 break;
480 case (RATIO):
481 _ratio += (diff) * 0.05;
482 _scale = _ratio;
483 break;
484 case (WIDTH):
485 _width += 10 * diff;
486 _scale = _width / (_image.getWidth(null) * 1.0f);
487 break;
488 }
489
490 // picture must still be at least 10 pixels wide
491 if ((_scale * _image.getWidth(null)) <= 10) {
492 _scale = oldScale;
493
494 _denominator = oldDenom;
495 _numerator = oldNumer;
496 _ratio = oldRatio;
497 _width = oldWidth;
498 }
499
500 // update source text item
501 String line = _source.getFirstLine();
502
503 switch (_scaleType) {
504 case (FRACTION):
505 line = line.replace(oldNumer + "/" + oldDenom, _numerator + "/"
506 + _denominator);
507 break;
508 case (RATIO):
509 DecimalFormat format = new DecimalFormat("0.00");
510 line = line.replace(format.format(oldRatio), format.format(_ratio));
511 break;
512 case (WIDTH):
513 line = line.replace("" + oldWidth, "" + _width);
514 break;
515 }
516
517 _source.setText(line);
518 updatePolygon();
519 }
520
521 @Override
522 public void setAnnotation(boolean val) {
523 // TODO Auto-generated method stub
524
525 }
526
527 @Override
528 public boolean isAnnotation() {
529 // TODO Auto-generated method stub
530 return false;
531 }
532
533 /**
534 * Returns the Image that this Picture object is painting on the screen.
535 * This is used by Frame to repaint animated GIFs.
536 *
537 * @return The Image that this Picture object represents.
538 */
539 public Image getImage() {
540 return _image;
541 }
542
543 @Override
544 public Item merge(Item merger, int mouseX, int mouseY) {
545 return merger;
546 }
547
548 public void refresh() {
549 if (_isFrame) {
550 String link = _source.getLink();
551 if (FrameIO.isPositiveInteger(link)) {
552 link = _source.getParent().getFramesetNameAdjusted() + link;
553 }
554 Frame frame = FrameIO.LoadFrame(link);
555 FrameGraphics.UpdateBuffer(frame, false);
556 _image = frame.getBuffer();
557 }
558 }
559
560}
Note: See TracBrowser for help on using the repository browser.