早在1984年,托马斯·波特(Thomas Porter)和汤姆·达夫(Tom Duff)撰写了一篇题为“合成数字图像”的论文,该论文描述了结合两个图像的12条规则。 在Java语言的1.2版中首次引入的AlphaComposite类中找到了对这些合成规则的支持。 当前处于beta 2中的1.4版支持所有12条规则。
对于诸如游戏之类的应用程序,包括多种图像类型(包括背景图像,玩家角色图像等)的应用程序,必须支持合成。 虽然很容易总是将玩家吸引到背景的前面,但是如果玩家跳到一棵树后面,您可能希望显示角色图像在树图像后面逐渐消失。 这是合成方便的地方。
AlphaComposite类具有12个常量,每个规则一个。 可视化规则的应用方式可能很棘手,因此我提供了每个操作规则的说明。 如果图像不是不透明的,则实际组合会有所不同。 该示范项目,在所示清单1和可供下载的相关主题部分,让你尝试不同级别的透明度。
注意:Merlin版本中新添加的那些规则以星号(*)表示。
规则1. AlphaComposite.CLEAR :在合成图像中不会绘制任何内容。
规则2. AlphaComposite.SRC :SRC代表源; 只有源图像将在组合图像中。
规则3. AlphaComposite.DST *:DST代表目的地; 只有目标图像将在组合图像中。
规则4. AlphaComposite.SRC_OVER :源图像将绘制在目标图像上。
规则5. AlphaComposite.DST_OVER :目标图像将绘制在源图像上。
规则6. AlphaComposite.SRC_IN :仅绘制源图像中与目标图像重叠的部分。
规则7. AlphaComposite.DST_IN :仅绘制目标图像中与源图像重叠的部分。
规则8. AlphaComposite.SRC_OUT :仅绘制源图像中与目标图像不重叠的部分。
规则9. AlphaComposite.DST_OUT :仅绘制目标图像中与源图像不重叠的部分。
规则10. AlphaComposite.SRC_ATOP *:将绘制源图像中与目标图像重叠的部分以及目标图像中与源图像不重叠的部分。
规则11. AlphaComposite.DST_ATOP *:将绘制目标图像中与源图像重叠的部分,以及源图像中与目标图像不重叠的部分。
规则12. AlphaComposite.XOR *:源图像中与目标图像不重叠的部分将与目标图像中与源图像不重叠的部分一起绘制。
以下程序是alpha合成规则的交互式演示。 只需更改每个三角形的不透明度,然后选择一个规则即可使用以查看混合图像的效果。
import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.image.*; import java.lang.reflect.*; import javax.swing.*; import javax.swing.event.*; import java.util.*; public class CompositeIt extends JFrame { JSlider sourcePercentage = new JSlider(); JSlider destinationPercentage = new JSlider(); JComboBox alphaComposites = new JComboBox(); DrawingPanel drawingPanel = new DrawingPanel(); public CompositeIt() { super("Porter-Duff"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel contentPane = (JPanel) this.getContentPane(); Dictionary labels = new Hashtable(); labels.put(new Integer(0), new JLabel("0.0")); labels.put(new Integer(25), new JLabel("0.25")); labels.put(new Integer(33), new JLabel("0.33")); labels.put(new Integer(50), new JLabel("0.50")); labels.put(new Integer(67), new JLabel("0.67")); labels.put(new Integer(75), new JLabel("0.75")); labels.put(new Integer(100), new JLabel("1.00")); sourcePercentage.setOrientation(JSlider.VERTICAL); sourcePercentage.setLabelTable(labels); sourcePercentage.setPaintTicks(true); sourcePercentage.setPaintLabels(true); sourcePercentage.setValue(100); sourcePercentage.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { int sourceValue = sourcePercentage.getValue(); drawingPanel.setSourcePercentage(sourceValue/100.0f); } }); destinationPercentage.setOrientation(JSlider.VERTICAL); destinationPercentage.setLabelTable(labels); destinationPercentage.setPaintTicks(true); destinationPercentage.setPaintLabels(true); destinationPercentage.setValue(100); destinationPercentage.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { int destinationValue = destinationPercentage.getValue(); drawingPanel.setDestinationPercentage(destinationValue/100.0f); } }); String rules[] = { "CLEAR", "DST", "DST_ATOP", "DST_IN", "DST_OUT", "DST_OVER", "SRC", "SRC_ATOP", "SRC_IN", "SRC_OUT", "SRC_OVER", "XOR"}; ComboBoxModel model = new DefaultComboBoxModel(rules); alphaComposites.setModel(model); alphaComposites.setSelectedItem("XOR"); alphaComposites.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String alphaValue = alphaComposites.getSelectedItem().toString(); Class alphaClass = AlphaComposite.class; try { Field field = alphaClass.getDeclaredField(alphaValue); int rule = ((Integer)field.get(AlphaComposite.Clear)).intValue(); drawingPanel.setCompositeRule(rule); } catch (Exception exception) { System.err.println("Unable to find field"); } } }); contentPane.add(sourcePercentage, BorderLayout.WEST); contentPane.add(destinationPercentage, BorderLayout.EAST); contentPane.add(alphaComposites, BorderLayout.SOUTH); contentPane.add(drawingPanel, BorderLayout.CENTER); pack(); } public static void main(String args[]) { new CompositeIt().show(); } class DrawingPanel extends JPanel { GeneralPath sourcePath, destPath; BufferedImage source, dest; float sourcePercentage = 1, destinationPercentage = 1; int compositeRule = AlphaComposite.XOR; Dimension dimension = new Dimension(200, 200); public DrawingPanel() { sourcePath = new GeneralPath(); sourcePath.moveTo(0, 0); sourcePath.lineTo(150, 0); sourcePath.lineTo(0, 200); sourcePath.closePath(); source = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB); destPath = new GeneralPath(); destPath.moveTo(200, 0); destPath.lineTo(50, 0); destPath.lineTo(200, 200); destPath.closePath(); dest = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB); } public void setSourcePercentage(float value) { sourcePercentage = value; repaint(); } public void setDestinationPercentage(float value) { destinationPercentage = value; repaint(); } public void setCompositeRule(int value) { compositeRule = value; repaint(); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; Graphics2D sourceG = source.createGraphics(); Graphics2D destG = dest.createGraphics(); destG.setComposite(AlphaComposite.Clear); destG.fillRect(0, 0, 200, 200); destG.setComposite(AlphaComposite.getInstance( AlphaComposite.XOR, destinationPercentage)); destG.setPaint(Color.magenta); destG.fill(destPath); sourceG.setComposite(AlphaComposite.Clear); sourceG.fillRect(0, 0, 200, 200); sourceG.setComposite(AlphaComposite.getInstance( AlphaComposite.XOR, sourcePercentage)); sourceG.setPaint(Color.green); sourceG.fill(sourcePath); destG.setComposite(AlphaComposite.getInstance(compositeRule)); destG.drawImage(source, 0, 0, null); g2d.drawImage(dest, 0, 0, this); } public Dimension getPreferredSize() { return dimension; } } }翻译自: https://www.ibm.com/developerworks/java/library/j-mer0918/index.html