Die Klasse ermöglicht den Test einiger
Einstellungsgrößen von Bildbearbeitungsmethoden der
JAI-Bibliothek. Sie lässt sich problemlos um weitere Methoden
erweitern.
Über Schieberegler können Werte zur Kontrast- und
Helligkeitssteuerung, sowie zur Skalierung ausgelesen und in
ihren Auswirkungen überprüft werden.
Zur Erweiterung
müssen lediglich in der Methode render()
der
erforderliche Parameterblock hinzugefügt und der Pfad zum
Bild angepasst werden.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.IOException;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.widget.DisplayJAI;
/*
* file JAITest.java
* @version 0.3
* Created on 23.10.2006
* Changed on 06.03.2022
* @author Joerg Czeschla, javabeginners.de (c)2006 - 2022
*/
public class JAITest implements ChangeListener, ActionListener, ItemListener {
// GUI Elemente
private JSlider slider1, slider2, slider3;
private JTextField bildTF, methodeTF, param1TF, param2TF, param3TF;
private JLabel bildLabel, methodeLabel;
private JPanel hauptPanel, werteTFPanel, sliderPanel, slider1Panel, slider2Panel, slider3Panel, elementePanel,
buttonPanel, bildPanel, boxPanel, obenPanel;
private JButton okButt, cancelButt;
private JComboBox<String> comboBox;
private DisplayJAI displayJAI;
private RenderedImage renderedImage = null;
// Eingabeverzeichnisname
private String inputFile = "img/bild.jpg";
// ComboBox-Starttext
private String startText = "Bitte Methode w\u00E4hlen!";
public JAITest() {
initGUI();
}
private void initGUI() {
// Slider
slider1 = new JSlider(0, 0, 0);
slider2 = new JSlider(0, 0, 0);
slider3 = new JSlider(0, 0, 0);
slider1.addChangeListener(this);
slider2.addChangeListener(this);
slider3.addChangeListener(this);
// TextFelder
bildTF = new JTextField(inputFile, 20);
methodeTF = new JTextField("", 20);
param1TF = new JTextField("0.00", 5);
param1TF.addActionListener(this);
param2TF = new JTextField("75.0", 5);
param2TF.addActionListener(this);
param3TF = new JTextField("0.00", 5);
param3TF.addActionListener(this);
// Label
bildLabel = new JLabel("Bild: ");
methodeLabel = new JLabel("Methode: ");
// Buttons
okButt = new JButton("ok");
okButt.addActionListener(this);
cancelButt = new JButton("cancel");
cancelButt.addActionListener(this);
// ComboBox
comboBox = new JComboBox<String>();
comboBox.addItemListener(this);
comboBox.addItem(startText);
comboBox.addItem("threshold");
comboBox.addItem("rescale");
comboBox.addItem("addConst");
comboBox.addItem("scale");
// Panels
hauptPanel = new JPanel(new BorderLayout());
werteTFPanel = new JPanel();
sliderPanel = new JPanel(new BorderLayout());
slider1Panel = new JPanel(new FlowLayout());
slider2Panel = new JPanel(new FlowLayout());
slider3Panel = new JPanel(new FlowLayout());
bildPanel = new JPanel(new FlowLayout());
boxPanel = new JPanel(new FlowLayout());
obenPanel = new JPanel(new BorderLayout());
elementePanel = new JPanel(new BorderLayout());
buttonPanel = new JPanel();
// Bilddisplay
displayJAI = new DisplayJAI();
// Slider und Textfelder in Grundstellung setzen
setAllDisplays(true);
// Layoutmanagement (der Einfachheit halber ohne GridBagLayout)
slider1Panel.add(slider1);
slider1Panel.add(param1TF);
slider2Panel.add(slider2);
slider2Panel.add(param2TF);
slider3Panel.add(slider3);
slider3Panel.add(param3TF);
sliderPanel.add(slider1Panel, BorderLayout.NORTH);
sliderPanel.add(slider2Panel, BorderLayout.CENTER);
sliderPanel.add(slider3Panel, BorderLayout.SOUTH);
bildPanel.add(bildLabel);
bildPanel.add(bildTF);
boxPanel.add(methodeLabel);
boxPanel.add(comboBox);
boxPanel.add(methodeTF);
obenPanel.add(bildPanel, BorderLayout.NORTH);
obenPanel.add(boxPanel, BorderLayout.SOUTH);
buttonPanel.add(okButt);
buttonPanel.add(cancelButt);
elementePanel.add(sliderPanel, BorderLayout.NORTH);
elementePanel.add(werteTFPanel, BorderLayout.CENTER);
elementePanel.add(buttonPanel, BorderLayout.SOUTH);
hauptPanel.add(obenPanel, BorderLayout.NORTH);
hauptPanel.add(elementePanel, BorderLayout.SOUTH);
// Bild initialisieren
if (verifyFile(bildTF.getText())) {
RenderedImage ri = readImg();
if (ri != null) {
setzeBild(ri);
}
}
hauptPanel.add(displayJAI, BorderLayout.CENTER);
JFrame frame = new JFrame("JAI Tool");
frame.add(hauptPanel);
frame.setSize(800, 800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
/**
* Prüft die Pfadangabe und erzeugt einen InputStream des Bildes
*
* @return FileSeekableStream des zu bearbeitenden Bildes
*/
private RenderedImage readImg() {
FileSeekableStream image = null;
try {
if (verifyFile(bildTF.getText())) {
image = new FileSeekableStream(bildTF.getText());
// RenderedImage erstellen
renderedImage = JAI.create("stream", image);
return renderedImage;
}
} catch (IOException e) {
System.out.println("Bitte den Pfad zu einem Bild angeben!");
setAllDisplays(true);
return null;
}
return null;
}
/**
* Prüft die Pfadangabe auf Existenz und Lesbarkeit
*/
private boolean verifyFile(String pfad) {
File f = new File(pfad);
if (f.isFile() && f.canRead()) {
return true;
}
return false;
}
/**
* positioniert das Bild auf dem Display
*
* @param ri
* @return
*/
private void setzeBild(RenderedImage ri) {
int breite = ri.getWidth(), hoehe = ri.getHeight();
Dimension dim = new Dimension((800 - breite) / 2, (600 - hoehe) / 2);
displayJAI.set(ri, (int) dim.getWidth(), (int) dim.getHeight());
}
/**
* Factory-Methode zum methodenabhängigen Setzen der Slider
*
* @param slider
* @param visible sichtbar wenn true
* @param min Minimalwert
* @param max Maximalwert
* @param val Ausgangsposition des Sliders
*/
private void setSliderValue(JSlider slider, JTextField field, boolean visible, int min, int max, int val) {
slider.setPreferredSize(new Dimension(300, 25));
slider.setVisible(visible);
slider.setMinimum(min);
slider.setMaximum(max);
slider.setValue(val);
field.setVisible(visible);
field.setText(new Double(val / 100).toString());
}
/**
* Setzt alle Slider und Werte-Textfelder auf Grundstellung
*
* @param visible
*/
private void setAllDisplays(boolean visible) {
setSliderValue(slider1, param1TF, visible, 0, 0, 0);
setSliderValue(slider2, param2TF, visible, 0, 0, 0);
setSliderValue(slider3, param3TF, visible, 0, 0, 0);
}
/**
* Passt die Werte-Textfelder und Slider-Positionen aneinander an
*
* @param ce
*/
private void setTFText(ChangeEvent ce) {
if (ce.getSource() == slider1) {
param1TF.setText(new Double((double) slider1.getValue() / 100).toString());
}
if (ce.getSource() == slider2) {
param2TF.setText(new Double((double) slider2.getValue() / 100).toString());
}
if (ce.getSource() == slider3) {
param3TF.setText(new Double((double) slider3.getValue() / 100).toString());
}
}
/**
* Hauptmethode zur Bildbearbeitung
*
* @param im Zu bearbeitendes RenderedImage
* @param methode String der anzuwendenden Methode
* @param wert1 Wert1
* @param wert2 Wert2
* @param wert3 Wert3
*/
private void render(RenderedImage im, String methode, String wert1, String wert2, String wert3) {
if (renderedImage != null) {
im = renderedImage;
System.out.println("renderedImahe ungleich null!");
}
System.out.println(methode + " gew\u00E4hlt...");
ParameterBlock pb = new ParameterBlock();
pb.addSource(im);
float f = 1.0F;
double[] d1 = new double[3];
double[] d2 = new double[3];
double[] d3 = new double[3];
if (methode.equals("") || methode.equals(startText)) {
return;
} else if (methode.equals("addConst")) {
d1[0] = new Double(wert1).doubleValue();
d1[1] = new Double(wert2).doubleValue();
d1[2] = new Double(wert3).doubleValue();
pb.add(d1);
} else if (methode.equals("rescale")) {
d1[0] = new Double(wert1).doubleValue();
d1[1] = new Double(wert1).doubleValue();
d1[2] = new Double(wert1).doubleValue();
d2[0] = new Double(wert2).doubleValue();
d2[1] = new Double(wert2).doubleValue();
d2[2] = new Double(wert2).doubleValue();
pb.add(d1);
pb.add(d2);
} else if (methode.equals("scale")) {
f = new Float(wert1).floatValue();
pb.add(f);
pb.add(f);
pb.add(0.0F);
pb.add(0.0F);
RenderedOp op = JAI.create(methode, pb);
int breite = op.getWidth();
int hoehe = op.getHeight();
System.out.println("Breite: " + breite);
System.out.println("Hoehe: " + hoehe);
System.out.println("Berechnete Breite: " + (displayJAI.getWidth() - breite) / 2.0F);
System.out.println("Berechnete Hoehe: " + (displayJAI.getHeight() - hoehe) / 2.0F);
displayJAI.setOrigin((displayJAI.getWidth() - breite) / 2, 0);
} else {
d1[0] = new Double(wert1).doubleValue();
d2[0] = new Double(wert2).doubleValue();
d3[0] = new Double(wert3).doubleValue();
if (d1[0] >= d2[0])
d1[0] = d2[0];
pb.add(d1);
if (d2[0] <= d1[0])
d2[0] = d1[0];
pb.add(d2);
pb.add(d3);
}
// Bild bearbeiten
RenderedOp op = JAI.create(methode, pb);
// bearbeitetes Bild registrieren
renderedImage = op;
// Bild darstellen
displayJAI.set(op);
}
/**
* Aufruf bei Methodenauswahl der Combobox
*/
public void stateChanged(ChangeEvent ce) {
setTFText(ce);
RenderedImage ri = readImg();
if (ri == null) {
return;
}
render(ri, (String) comboBox.getSelectedItem(), param1TF.getText(), param2TF.getText(), param3TF.getText());
}
/**
* Aufgerufen durch Textfelder und Buttons
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource() == cancelButt) {
System.exit(0);
}
if (e.getSource() == okButt) {
RenderedImage ri = readImg();
if (ri == null) {
return;
}
String methode = (String) comboBox.getSelectedItem();
render(ri, methode, param1TF.getText(), param2TF.getText(), param3TF.getText());
}
if (e.getSource() == param1TF) {
slider1.setValue((int) (new Double(param1TF.getText()).doubleValue() * 100));
}
if (e.getSource() == param2TF) {
slider2.setValue((int) (new Double(param2TF.getText()).doubleValue() * 100));
}
if (e.getSource() == param3TF) {
slider3.setValue((int) (new Double(param3TF.getText()).doubleValue() * 100));
}
}
/**
* Sliderwerte je nach Auswahl einer Bearbeitungsmethode setzen und bei Bewegung
* anpassen
*/
public void itemStateChanged(ItemEvent e) {
if (comboBox.getSelectedItem().equals(startText)) {
setAllDisplays(true);
}
if (comboBox.getSelectedItem().equals("rescale")) {
methodeTF.setText("Kontrast");
setSliderValue(slider1, param1TF, true, 0, 400, 100);
setSliderValue(slider2, param2TF, true, -25500, 25500, 0);
setSliderValue(slider3, param3TF, false, 0, 0, 0);
}
if (comboBox.getSelectedItem().equals("threshold")) {
methodeTF.setText("bin\u00E4rer Kontrast");
setSliderValue(slider1, param1TF, true, 0, 500, 0);
setSliderValue(slider2, param2TF, true, 5000, 10000, 7500);
setSliderValue(slider3, param3TF, true, 0, 10000, 0);
}
if (comboBox.getSelectedItem().equals("addConst")) {
methodeTF.setText("Helligkeit");
setSliderValue(slider1, param1TF, true, -25000, 25000, 0);
setSliderValue(slider2, param2TF, true, -25000, 25000, 0);
setSliderValue(slider3, param3TF, true, -25000, 25000, 0);
}
if (comboBox.getSelectedItem().equals("scale")) {
methodeTF.setText("Skalieren");
setSliderValue(slider1, param1TF, true, 10, 190, 100);
setSliderValue(slider2, param2TF, false, 0, 0, 0);
setSliderValue(slider3, param3TF, false, 0, 0, 0);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new JAITest());
}
}
Zur weiteren Vertiefung der JAI-Thematik sei auf die Docs unter
https://docs.oracle.com/cd/E19957-01/806-5413-10/806-5413-10.pdf
verwiesen. Man beachte jedoch, dass diese nicht mehr so
ganz aktuell sind. Insbesondere wird auf einige, mittlerweile
als
deprecated
eingestufte Elemente wie etwa
ScrollingImagePanel
verwiesen. Dies sollte unbedingt durch die Klasse
DisplayJAI
ersetzt werden.