Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

This program demonstrates the Porter-Duff composition rules

/*    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; }