/** @version 1.01 2001-07-24 @author Cay Horstmann */ import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.awt.geom.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; /** This program demonstrates the Porter-Duff composition rules. */ public class CompositeTest { public static void main(String[] args) { JFrame frame = new CompositeTestFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } } /** This frame contains a combo box to choose a composition rule, a slider to change the source alpha channel, and a panel that shows the composition. */ class CompositeTestFrame extends JFrame { public CompositeTestFrame() { setTitle("CompositeTest"); setSize(WIDTH, HEIGHT); Container contentPane = getContentPane(); canvas = new CompositePanel(); contentPane.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); contentPane.add(panel, BorderLayout.NORTH); explanation = new JTextField(); contentPane.add(explanation, BorderLayout.SOUTH); canvas.setAlpha(alphaSlider.getValue()); Rule r = (Rule)ruleCombo.getSelectedItem(); canvas.setRule(r.getValue()); explanation.setText(r.getExplanation()); } private CompositePanel canvas; private JComboBox ruleCombo; private JSlider alphaSlider; private JTextField explanation; private static final int WIDTH = 400; private static final int 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() { StringBuffer r = new StringBuffer("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 { Integer i = (Integer) AlphaComposite.class.getField(name).get(null); return i.intValue(); } catch (Exception ex) { return -1; } } private String name; private String porterDuff1; private String porterDuff2; } /** This panel draws two shapes, composed with a composition rule. */ class CompositePanel extends JPanel { public CompositePanel() { shape1 = new Ellipse2D.Double(100, 100, 150, 100); shape2 = new Rectangle2D.Double(150, 150, 150, 100); } public void paintComponent(Graphics g) { super.paintComponent(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; }