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

Last change on this file since 21 was 21, checked in by ra33, 16 years ago
File size: 13.1 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 if (_source.getLink() == null) {
294 Frame parent = getParent();
295 if (parent != null){
296 parent.removeItem(this);
297 parent.addItem(_source);
298 }
299 } else {
300 Frame frame = FrameIO.LoadFrame(_source.getLink());
301 if (frame != null) {
302 FrameGraphics.UpdateBuffer(frame, false);
303 _image = frame.getBuffer();
304 }
305 }
306 }
307 }
308
309 updatePolygon();
310 }
311
312 @Override
313 public void setAction(List<String> action) {
314 if (_source == null)
315 return;
316 else
317 _source.setAction(action);
318
319 updatePolygon();
320 }
321
322 @Override
323 public List<String> getAction() {
324 if (_source == null)
325 return null;
326 else
327 return _source.getAction();
328 }
329
330 @Override
331 public void paint(Graphics2D g) {
332 if (_image == null)
333 return;
334
335 int width = _image.getWidth(null);
336 int height = _image.getHeight(null);
337
338 width *= _scale;
339 height *= _scale;
340
341 if (getLink() != null || getAction() != null) {
342 g.setColor(getPaintHighlightColor());
343
344 AffineTransform at = new AffineTransform();
345 AffineTransform orig = g.getTransform();
346 at.translate(getX() - 12, getY() + (getBoundsHeight() / 2));
347 g.setTransform(at);
348
349 if (getLinkMark() && getLink() != null) {
350 g.drawPolygon(getCircle());
351
352 // if the link is not valid, cross out the circle
353 if (!isLinkValid())
354 g.drawPolygon(getCircleCross());
355 }
356
357 if (getActionMark() && getAction() != null) {
358 g.drawPolygon(getCircle());
359 g.fillPolygon(getCircle());
360
361 // if the link is not valid, cross out the circle
362 if (getLink() != null && !isLinkValid()) {
363 g.setColor(getPaintBackgroundColor());
364 g.drawPolygon(getCircleCross());
365 }
366 }
367 g.setTransform(orig);
368 }
369
370 if (isHighlighted()) {
371 g.setColor(getHighlightColor());
372 g.drawPolygon(getPolygon());
373 }
374
375 // if we are showing the cropping, then show the original as transparent
376 if (_showCropping && _cropStart != null && _cropEnd != null) {
377 // show the full image as transparent
378 float alpha = .5f;
379 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
380 alpha));
381 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
382 _imageObserver);
383
384 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
385 1.0f));
386 // show the cropped area normally
387 Shape clip = new Rectangle(_source.getX() + _cropStart.x, _source
388 .getY()
389 + _cropStart.y, _cropEnd.x - _cropStart.x, _cropEnd.y
390 - _cropStart.y);
391 g.setColor(getPaintHighlightColor());
392 g.draw(clip);
393 g.setClip(clip);
394
395 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
396 _imageObserver);
397 g.draw(clip);
398 // if the image is cropped, but we are not showing the cropping
399 } else if (_cropStart != null && _cropEnd != null) {
400 Shape clip = new Rectangle(_source.getX() + _cropStart.x
401 + _cropOrigin.x, _source.getY() + _cropStart.y
402 + _cropOrigin.y, _cropEnd.x - _cropStart.x, _cropEnd.y
403 - _cropStart.y);
404 g.setClip(clip);
405
406 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
407 _imageObserver);
408
409 // otherwise, paint normally
410 } else {
411 g.drawImage(_image, _source.getX(), _source.getY(), width, height,
412 _imageObserver);
413 }
414 }
415
416 @Override
417 public Polygon getPolygon() {
418 if (_poly == null)
419 updatePolygon();
420
421 Polygon external = new Polygon(_poly.xpoints, _poly.ypoints,
422 _poly.npoints);
423 return external;
424 }
425
426 @Override
427 public int setSelectionColor() {
428 super.setSelectionColor();
429
430 return Item.DEFAULT_CURSOR;
431 }
432
433 @Override
434 public Picture copy() {
435 Picture p;
436
437 if (_isFrame) {
438 p = ItemUtils.CreateFramePicture((Text) _source.copy(),
439 _imageObserver);
440 } else
441 p = ItemUtils.CreatePicture((Text) _source.copy(), _imageObserver);
442
443 Item.DuplicateItem(this, p);
444
445 if (_cropStart != null)
446 p.setStartCrop(_cropStart.x, _cropStart.y);
447
448 if (_cropEnd != null)
449 p.setEndCrop(_cropEnd.x, _cropEnd.y);
450
451 return p;
452 }
453
454 @Override
455 public void setMaxSize(Dimension d) {
456 // TODO Auto-generated method stub
457 }
458
459 @Override
460 public Color getColor() {
461 return _source.getColor();
462 }
463
464 @Override
465 public void setColor(Color c) {
466 _source.setColor(c);
467 }
468
469 @Override
470 public int getSize() {
471 return _source.getSize();
472 }
473
474 @Override
475 public void setSize(int size) {
476 int diff = size - _source.getSize();
477 float oldScale = _scale;
478
479 int oldDenom = _denominator;
480 int oldNumer = _numerator;
481 float oldRatio = _ratio;
482 int oldWidth = _width;
483
484 switch (_scaleType) {
485 case (FRACTION):
486 _numerator += diff;
487 _scale = (_numerator * 1.0f) / _denominator;
488 break;
489 case (RATIO):
490 _ratio += (diff) * 0.05;
491 _scale = _ratio;
492 break;
493 case (WIDTH):
494 _width += 10 * diff;
495 _scale = _width / (_image.getWidth(null) * 1.0f);
496 break;
497 }
498
499 // picture must still be at least 10 pixels wide
500 if ((_scale * _image.getWidth(null)) <= 10) {
501 _scale = oldScale;
502
503 _denominator = oldDenom;
504 _numerator = oldNumer;
505 _ratio = oldRatio;
506 _width = oldWidth;
507 }
508
509 // update source text item
510 String line = _source.getFirstLine();
511
512 switch (_scaleType) {
513 case (FRACTION):
514 line = line.replace(oldNumer + "/" + oldDenom, _numerator + "/"
515 + _denominator);
516 break;
517 case (RATIO):
518 DecimalFormat format = new DecimalFormat("0.00");
519 line = line.replace(format.format(oldRatio), format.format(_ratio));
520 break;
521 case (WIDTH):
522 line = line.replace("" + oldWidth, "" + _width);
523 break;
524 }
525
526 _source.setText(line);
527 updatePolygon();
528 }
529
530 @Override
531 public void setAnnotation(boolean val) {
532 // TODO Auto-generated method stub
533
534 }
535
536 @Override
537 public boolean isAnnotation() {
538 // TODO Auto-generated method stub
539 return false;
540 }
541
542 /**
543 * Returns the Image that this Picture object is painting on the screen.
544 * This is used by Frame to repaint animated GIFs.
545 *
546 * @return The Image that this Picture object represents.
547 */
548 public Image getImage() {
549 return _image;
550 }
551
552 @Override
553 public Item merge(Item merger, int mouseX, int mouseY) {
554 return merger;
555 }
556
557 public void refresh() {
558 if (_isFrame) {
559 String link = _source.getLink();
560 if (FrameIO.isPositiveInteger(link)) {
561 link = _source.getParent().getFramesetNameAdjusted() + link;
562 }
563 Frame frame = FrameIO.LoadFrame(link);
564 FrameGraphics.UpdateBuffer(frame, false);
565 _image = frame.getBuffer();
566 }
567 }
568
569}
Note: See TracBrowser for help on using the repository browser.