/*
This program is a part of the companion code for Core Java 8th ed.
(http://horstmann.com/corejava)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* This program demonstrates the Porter-Duff composition rules.
* @version 1.03 2007-08-16
* @author Cay Horstmann
*/
public class CompositeTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new CompositeTestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
/**
* This frame contains a combo box to choose a composition rule, a slider to change the source alpha
* channel, and a component that shows the composition.
*/
class CompositeTestFrame extends JFrame
{
public CompositeTestFrame()
{
setTitle("CompositeTest");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
canvas = new CompositeComponent();
add(canvas, BorderLayout.CENTER);
ruleCombo = new JComboBox(new Object[] { new Rule("CLEAR", " ", " "),
new Rule("SRC", " S", " S"), new Rule("DST", " ", "DD"),
new Rule("SRC_OVER", " S", "DS"), new Rule("DST_OVER", " S", "DD"),
new Rule("SRC_IN", " ", " S"), new Rule("SRC_OUT", " S", " "),
new Rule("DST_IN", " ", " D"), new Rule("DST_OUT", " ", "D "),
new Rule("SRC_ATOP", " ", "DS"), new Rule("DST_ATOP", " S", " D"),
new Rule("XOR", " S", "D "), });
ruleCombo.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Rule r = (Rule) ruleCombo.getSelectedItem();
canvas.setRule(r.getValue());
explanation.setText(r.getExplanation());
}
});
alphaSlider = new JSlider(0, 100, 75);
alphaSlider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent event)
{
canvas.setAlpha(alphaSlider.getValue());
}
});
JPanel panel = new JPanel();
panel.add(ruleCombo);
panel.add(new JLabel("Alpha"));
panel.add(alphaSlider);
add(panel, BorderLayout.NORTH);
explanation = new JTextField();
add(explanation, BorderLayout.SOUTH);
canvas.setAlpha(alphaSlider.getValue());
Rule r = (Rule) ruleCombo.getSelectedItem();
canvas.setRule(r.getValue());
explanation.setText(r.getExplanation());
}
private CompositeComponent canvas;
private JComboBox ruleCombo;
private JSlider alphaSlider;
private JTextField explanation;
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 400;
}
/**
* This class describes a Porter-Duff rule.
*/
class Rule
{
/**
* Constructs a Porter-Duff rule
* @param n the rule name
* @param pd1 the first row of the Porter-Duff square
* @param pd2 the second row of the Porter-Duff square
*/
public Rule(String n, String pd1, String pd2)
{
name = n;
porterDuff1 = pd1;
porterDuff2 = pd2;
}
/**
* Gets an explanation of the behavior of this rule.
* @return the explanation
*/
public String getExplanation()
{
StringBuilder r = new StringBuilder("Source ");
if (porterDuff2.equals(" ")) r.append("clears");
if (porterDuff2.equals(" S")) r.append("overwrites");
if (porterDuff2.equals("DS")) r.append("blends with");
if (porterDuff2.equals(" D")) r.append("alpha modifies");
if (porterDuff2.equals("D ")) r.append("alpha complement modifies");
if (porterDuff2.equals("DD")) r.append("does not affect");
r.append(" destination");
if (porterDuff1.equals(" S")) r.append(" and overwrites empty pixels");
r.append(".");
return r.toString();
}
public String toString()
{
return name;
}
/**
* Gets the value of this rule in the AlphaComposite class
* @return the AlphaComposite constant value, or -1 if there is no matching constant.
*/
public int getValue()
{
try
{
return (Integer) AlphaComposite.class.getField(name).get(null);
}
catch (Exception e)
{
return -1;
}
}
private String name;
private String porterDuff1;
private String porterDuff2;
}
/**
* This component draws two shapes, composed with a composition rule.
*/
class CompositeComponent extends JComponent
{
public CompositeComponent()
{
shape1 = new Ellipse2D.Double(100, 100, 150, 100);
shape2 = new Rectangle2D.Double(150, 150, 150, 100);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D gImage = image.createGraphics();
gImage.setPaint(Color.red);
gImage.fill(shape1);
AlphaComposite composite = AlphaComposite.getInstance(rule, alpha);
gImage.setComposite(composite);
gImage.setPaint(Color.blue);
gImage.fill(shape2);
g2.drawImage(image, null, 0, 0);
}
/**
* Sets the composition rule.
* @param r the rule (as an AlphaComposite constant)
*/
public void setRule(int r)
{
rule = r;
repaint();
}
/**
* Sets the alpha of the source
* @param a the alpha value between 0 and 100
*/
public void setAlpha(int a)
{
alpha = (float) a / 100.0F;
repaint();
}
private int rule;
private Shape shape1;
private Shape shape2;
private float alpha;
}
|