/Users/lyon/j4p/src/j2d/gui/Main.java
|
1 // Glenn Josefiak
2 // Fairfield University
3 // SW513
4 // Spring 2003
5
6 package j2d.gui;
7
8 // Standard libraries
9
10 import futils.StreamSniffer;
11 import gui.ClosableJFrame;
12 import gui.run.RunMenu;
13 import gui.run.RunMenuItem;
14 import j2d.Images;
15 import j2d.ImageUtils;
16 import j2d.file.ExtensionFileFilter;
17 import j2d.file.PPMToolkit;
18 import j2d.imageproc.ExponentialStretchProcessor;
19 import j2d.imageproc.FalseColorProcessor;
20 import j2d.imageproc.HistogramEQProcessor;
21 import j2d.imageproc.LinearMappingProcessor;
22
23 import javax.swing.*;
24 import javax.media.format.VideoFormat;
25 import javax.media.protocol.PushBufferDataSource;
26 import java.awt.*;
27 import java.awt.image.BufferedImage;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.io.*;
31 import java.util.Observable;
32 import java.util.Observer;
33
34 /**
35 * This class provides a GUI for altering images
36 */
37
38 public class Main extends ClosableJFrame {
39
40 private MDIDesktopPane deskTop = new MDIDesktopPane();
41
42 private FalseColorToolbox falseColorToolbox;
43 private LinearMappingToolbox linearMappingToolbox;
44 private HistogramEQToolbox histEqToolbox;
45 private ExponentialStretchToolbox estStretchControls;
46
47
48 // Image processors
49
50 private FalseColorProcessor fcProcessor
51 = new FalseColorProcessor();
52 private LinearMappingProcessor lmProcessor
53 = new LinearMappingProcessor();
54 private HistogramEQProcessor heProcessor
55 = new HistogramEQProcessor();
56 private ExponentialStretchProcessor esProcessor
57 = new ExponentialStretchProcessor();
58
59 // Capture details
60 private VideoFormat vfFormat;
61 private PushBufferDataSource pbds;
62
63 /**
64 * Construct a new ImageTool
65 */
66 public Main() {
67 Container c;
68
69 c = getContentPane();
70 c.setLayout(new BorderLayout());
71
72
73 c.add(new JScrollPane(deskTop));
74
75 setTitle("Image Tool");
76 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
77
78 // Set up the menus
79
80 JMenuBar mb = new JMenuBar();
81 setJMenuBar(mb);
82 addFileMenu(mb);
83 addProcessMenu(mb);
84 WindowMenu windowMenu = new WindowMenu(deskTop);
85 mb.add(windowMenu);
86 windowMenu.setMnemonic('W');
87 }
88
89 private void addProcessMenu(JMenuBar mb) {
90 RunMenu processMenu = new RunMenu("[process");
91 mb.add(processMenu);
92 processMenu.add(new RunMenuItem("[False Color") {
93 public void run() {
94 if (falseColorToolbox == null ||
95 falseColorToolbox.isClosed()) {
96 launchColorControls();
97 }
98 }
99 });
100 processMenu.add(new RunMenuItem("[negate{ctrl N}") {
101 public void run() {
102 Utils.negate(deskTop);
103 }
104 });
105 processMenu.add(new RunMenuItem("[Linear Mapping") {
106 public void run() {
107 if (linearMappingToolbox == null ||
108 linearMappingToolbox.isClosed()) {
109 launchMappingControls();
110 }
111 }
112 });
113 processMenu.add(new RunMenuItem("[Histogram EQ{ctrl H}") {
114 public void run() {
115 if (histEqToolbox == null ||
116 histEqToolbox.isClosed()) {
117 launchHistogramControls();
118 }
119 }
120 });
121 processMenu.add(new RunMenuItem("[Exponential Stretch") {
122 public void run() {
123 if (estStretchControls == null ||
124 estStretchControls.isClosed()) {
125 launchStretchControls();
126 }
127 }
128 });
129 }
130
131 private void addFileMenu(JMenuBar mb) {
132 RunMenu fileMenu = new RunMenu("[File");
133 mb.add(fileMenu);
134
135 fileMenu.add(new RunMenuItem("[Open{ctrl O}",
136 Images.getOpenIcon()) {
137 public void run() {
138 openImage();
139 }
140 });
141
142 fileMenu.add(new RunMenuItem("[Capture screen{alt 4}") {
143 public void run() {
144 captureScreen();
145 }
146 });
147 fileMenu.add(new RunMenuItem("[Save{ctrl S}",
148 Images.getSaveIcon()) {
149 public void run() {
150 saveImage();
151 }
152 });
153 fileMenu.add(new RunMenuItem("[Revert{crtl R}",
154 Images.getRevertIcon()) {
155 public void run() {
156 revertImage();
157 }
158 });
159 fileMenu.add(new RunMenuItem("[Exit{ctrl Q}",
160 Images.getExitIcon()) {
161 public void run() {
162 shutdown();
163 }
164 });
165 }
166
167 /**
168 * Helper function for closing the ImageTool.
169 * Could put other termination code here.
170 */
171 private void shutdown() {
172 dispose();
173 }
174 /**
175 * This is called when the user requests a new file to be opened.
176 */
177 private void captureScreen() {
178
179 Image imgProcessee;
180 ImageChildFrame icfNewFrame;
181 //int intSuccess = 0;
182
183 try {
184 BufferedImage bi = ImageUtils.captureWholeScreen();
185 imgProcessee = ImageUtils.getImage(bi);
186
187 icfNewFrame =
188 new ImageChildFrame(imgProcessee,
189 "screen shot");
190 deskTop.add(icfNewFrame);
191 } catch (AWTException e) {
192 e.printStackTrace();
193
194 }
195
196 }
197 /**
198 * This is called when the user requests a new
199 * file to be opened.
200 */
201 private void openImage() {
202 File imageFile;
203 Image imgProcessee;
204 ImageChildFrame icfNewFrame;
205 //int intSuccess = 0;
206
207 imageFile =
208 futils.Futil.getReadFile("select an image file");
209 imgProcessee = getImage(imageFile);
210
211 icfNewFrame =
212 new ImageChildFrame(imgProcessee,
213 imageFile.getName());
214 deskTop.add(icfNewFrame);
215
216 }
217
218 public Image getImage(File f) {
219 if (f == null) return null;
220 if (!f.exists()) return null;
221
222 InputStream is = null;
223 try {
224 is = new FileInputStream(f);
225 } catch (FileNotFoundException e) {
226 e.printStackTrace();
227 }
228
229 StreamSniffer ss = new StreamSniffer(is);
230 int id = ss.classifyStream();
231 switch (id) {
232 case StreamSniffer.PPM:
233 return getPPMImage(f);
234 case StreamSniffer.PPM_RAWBITS:
235 return getPPMImage(f);
236 case StreamSniffer.GIF87a:
237 return getGifOrJpg(f);
238 case StreamSniffer.GIF89a:
239 return getGifOrJpg(f);
240 case StreamSniffer.JPEG:
241 return getGifOrJpg(f);
242 default:
243 {
244 System.out.println("Can not open " +
245 ss +
246 " as image");
247 return null;
248 }
249
250 }
251 }
252
253 private Image getGifOrJpg(File imageFile) {
254 return Toolkit.getDefaultToolkit()
255 .getImage(imageFile.getAbsolutePath());
256 }
257
258 /*
259 private Image getZippedPPMImage(File imageFile) {
260 Image imgProcessee = null;
261 try {
262 imgProcessee = PPMToolkit.getImage(imageFile, true);
263 } catch (IOException e) {
264 e.printStackTrace();
265 }
266 return imgProcessee;
267 }
268 */
269
270 private Image getPPMImage(File imageFile) {
271 try {
272 Image imgProcessee;
273 imgProcessee =
274 PPMToolkit.getImage(imageFile,
275 false);
276 return imgProcessee;
277 } catch (IOException e) {
278 e.printStackTrace();
279 }
280 return null;
281 }
282
283 /**
284 * This is called when the user picks the save
285 * menu option.
286 */
287 private void saveImage() {
288 ImageChildFrame icf;
289 int intSuccess;
290 File imageFile;
291
292
293 try {
294 icf =
295 (ImageChildFrame) deskTop.getTopmostFrame(ImageChildFrame.class);
296 if (icf == null) return;
297 } catch (Exception e) {
298 return;
299 }
300
301 JFileChooser jfc = new JFileChooser();
302 ExtensionFileFilter eff1 =
303 new ExtensionFileFilter("ppm",
304 "Portable Pixelmap image file");
305 jfc.addChoosableFileFilter(eff1);
306 ExtensionFileFilter eff2 =
307 new ExtensionFileFilter("ppm.gz",
308 "Zipped Pixelmap image file");
309 jfc.addChoosableFileFilter(eff2);
310 jfc.setFileFilter(eff1);
311 jfc.setAcceptAllFileFilterUsed(false);
312
313 intSuccess = jfc.showSaveDialog(this);
314
315 if (intSuccess ==
316 JFileChooser.APPROVE_OPTION) {
317 imageFile = jfc.getSelectedFile();
318
319 ExtensionFileFilter eff = (ExtensionFileFilter) jfc.getFileFilter();
320
321 try {
322 if (eff == eff1) {
323 imageFile =
324 fixExtension(imageFile,
325 "ppm");
326 PPMToolkit.saveImage(icf.getImage(),
327 imageFile,
328 false);
329 } else if (eff == eff2) {
330 imageFile =
331 fixExtension(imageFile,
332 "ppm.gz");
333 PPMToolkit.saveImage(icf.getImage(),
334 imageFile,
335 true);
336 }
337 icf.setTitle(imageFile.getName());
338 } catch (Exception e) {
339 JOptionPane.showMessageDialog(this, "File write error: \n"
340 + e.toString());
341 }
342 }
343 }
344
345 /**
346 * Fix the file extension
347 */
348 private File fixExtension(File file,
349 String extension) {
350 String path = file.getAbsolutePath();
351
352 if (!path.endsWith("." + extension)) {
353 path += "." + extension;
354 }
355 return new File(path);
356 }
357
358 /**
359 * Set the image in the active frame to the
360 * base image.
361 */
362 private void revertImage() {
363 ImageChildFrame icf;
364
365 try {
366 icf =
367 (ImageChildFrame)
368 deskTop.getTopmostFrame(ImageChildFrame.class);
369 icf.revert();
370 } catch (Exception e) {
371 // do nothing
372 }
373 }
374
375 /**
376 * Helper function to show LinearMappingToolbox
377 */
378 private void launchMappingControls() {
379 linearMappingToolbox =
380 new LinearMappingToolbox();
381 linearMappingToolbox.show();
382 linearMappingToolbox.getSliderBank()
383 .addObserver(new Observer() {
384 public void update(Observable x,
385 Object y) {
386 adjustLinearMapping(false);
387 }
388 });
389 linearMappingToolbox.getButton()
390 .addActionListener(new ActionListener() {
391 public void actionPerformed(ActionEvent e) {
392 adjustLinearMapping(true);
393 }
394 });
395 deskTop.add(linearMappingToolbox);
396 }
397
398 /**
399 * Helper function to show FalseColorToolbox
400 */
401 private void launchColorControls() {
402 falseColorToolbox =
403 new FalseColorToolbox();
404 falseColorToolbox.show();
405 falseColorToolbox.getSliderBank()
406 .addObserver(new Observer() {
407 public void update(Observable x,
408 Object y) {
409 adjustColorization();
410 }
411 });
412 deskTop.add(falseColorToolbox);
413 }
414
415 /**
416 * Helper function to show HistogramEQToolbox
417 */
418 private void launchHistogramControls() {
419 histEqToolbox = new HistogramEQToolbox();
420 histEqToolbox.show();
421 histEqToolbox.getButton()
422 .addActionListener(new ActionListener() {
423 public void actionPerformed(ActionEvent e) {
424 adjustHistogram();
425 }
426 });
427 histEqToolbox.getSlider().addObserver(new Observer() {
428 public void update(Observable x,
429 Object y) {
430 adjustHistogram();
431 }
432 });
433
434 deskTop.add(histEqToolbox);
435 }
436
437 /**
438 * Helper function to show ExponentialStretchToolbox
439 */
440 private void launchStretchControls() {
441 estStretchControls =
442 new ExponentialStretchToolbox();
443 estStretchControls.show();
444 estStretchControls.getSlider()
445 .addObserver(new Observer() {
446 public void update(Observable x,
447 Object y) {
448 adjustExponentialStretch();
449 }
450 });
451 deskTop.add(estStretchControls);
452 }
453
454
455 /**
456 * This is called each time a slider in the
457 * FalseColorToolbox is moved. This is where
458 * the real image processing happens.
459 */
460 private void adjustColorization() {
461 float coeff[] = new float[3];
462 ImageChildFrame icf;
463
464 try {
465 coeff =
466 falseColorToolbox.getSliderBank()
467 .getValues();
468
469 icf =
470 (ImageChildFrame)
471 deskTop.getTopmostFrame(ImageChildFrame.class);
472 fcProcessor.setBaseImage(icf.getBaseImage());
473 fcProcessor.setColorization(coeff[0],
474 coeff[1],
475 coeff[2]);
476 fcProcessor.performAlgorithm();
477 icf.setImage(fcProcessor.getProcessedImage());
478 } catch (Exception e) {
479 // for now, do nothing.
480 }
481 }
482
483 /**
484 * This is called each time a slider on the
485 * LinearMappingToolbox is moved (btn = false)
486 * or the button on the LinearMappingToolbox
487 * is pressed (btn = true). This is where the
488 * real image processing happens.
489 */
490 private void adjustLinearMapping(boolean btn) {
491 float coeff[] = new float[2];
492 ImageChildFrame icf;
493
494 try {
495 icf =
496 (ImageChildFrame) deskTop.getTopmostFrame(ImageChildFrame.class);
497 lmProcessor.setBaseImage(icf.getBaseImage());
498 if (btn) {
499 // compute parameters from the image, then update the toolbox sliders
500 coeff =
501 lmProcessor.setOptimalParameters();
502 linearMappingToolbox.getSliderBank()
503 .setValues(coeff);
504 } else {
505 // get the parameters from the sliders, then update the image
506 coeff =
507 linearMappingToolbox.getSliderBank()
508 .getValues();
509 lmProcessor.setParameters(coeff[0], coeff[1]);
510 }
511 lmProcessor.performAlgorithm();
512 icf.setImage(lmProcessor.getProcessedImage());
513 } catch (Exception e) {
514 // for now, do nothing.
515 }
516 }
517
518 /**
519 * This is called when the slider on the
520 * HistogramEQToolbox is moved, or when its
521 * button is pressed.
522 */
523 private void adjustHistogram() {
524 boolean exponential;
525 float alpha;
526 ImageChildFrame icf;
527
528 try {
529 icf =
530 (ImageChildFrame) deskTop.getTopmostFrame(ImageChildFrame.class);
531 heProcessor.setBaseImage(icf.getBaseImage());
532
533 exponential =
534 histEqToolbox.getExponential();
535 heProcessor.setExponential(exponential);
536 if (exponential) {
537 alpha =
538 histEqToolbox.getSlider()
539 .getValue();
540 heProcessor.setAlpha(alpha);
541 }
542
543 heProcessor.performAlgorithm();
544 icf.setImage(heProcessor.getProcessedImage());
545 } catch (Exception e) {
546 // for now, do nothing.
547 }
548 }
549
550 /**
551 * This is called each time a slider in the
552 * ExponentialStretchToolbox is moved. This is
553 * where the real image processing happens.
554 */
555 private void adjustExponentialStretch() {
556 float coeff;
557 ImageChildFrame icf;
558 try {
559 coeff =
560 estStretchControls.getSlider()
561 .getValue();
562
563 icf =
564 (ImageChildFrame) deskTop.getTopmostFrame(ImageChildFrame.class);
565 esProcessor.setBaseImage(icf.getBaseImage());
566 esProcessor.setPower(coeff);
567 esProcessor.performAlgorithm();
568 icf.setImage(esProcessor.getProcessedImage());
569 } catch (Exception e) {
570 // for now, do nothing.
571 }
572 }
573
574 /**
575 * Entry point of the ImageTool application.
576 */
577 public static void main(String args[]) {
578 Main fc = new Main();
579 fc.setSize(500, 400);
580 fc.show();
581 }
582 }