在Java Graphics2D中绘制透明图像

22
我想在一张图片的基础上绘制一个部分透明的图像(制作影子效果)。我目前正在使用Java的Graphics2D类进行渲染,有人告诉我要将复合设置为AlphaComposite,但那只会使它完全透明。
在我的当前设置中,我能做到这点吗?我需要做什么来解决这个问题?
这是我被告知可以使其部分透明的代码:
    AlphaComposite ac = java.awt.AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.5F);
    g.setComposite(ac);

(顺便说一下,我正在使用png图像)

这是你的SSCCE(为了简单起见,它们都在不同的类中,但我将它们放在一起)。 我使用一个名为“Test”的图像,在本地文件夹“Images”中,你可以使用任何名字相同的png图像。

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Window;

import javax.swing.ImageIcon;

import com.blazingkin.atrox.ScreenManager;

public class AtroxAdventrum{

public static void main(String[] args) {
new AtroxAdventrum().run();
}

    private static DisplayMode modes[] = {

        //new DisplayMode(1080,720,32,0),
        //new DisplayMode(1080,720,24,0),
        //new DisplayMode(1080,720,16,0),
        //new DisplayMode(1440,900,32,0),
        //new DisplayMode(1440,900,24,0),
        //new DisplayMode(1440,900,16,0),

    };
    private boolean running = true;
    public ScreenManager s;

    public void stop(){
        running = false;
    }

    public void run(){
        try{
            init();
            gameLoop();
        }finally{
            s.restoreScreen();
        }
    }

    public void init(){
        s = new ScreenManager();
        DisplayMode dm = s.findFirstCompatibleMode(modes);
        s.setFullScreen(dm);


        Window w = s.getFullScreenWindow();
        w.setFont(new Font("Arial", Font.PLAIN, 20));
        w.setBackground(Color.black);
        w.setForeground(Color.white);
    }

    public void gameLoop(){
        long startTime = System.currentTimeMillis();
        long cumTime = startTime;

        while (running)
        {
            long timePassed = System.currentTimeMillis() - cumTime;
            cumTime += timePassed;
            if (limitfps){
            try{
                Thread.sleep(15);
            }catch(Exception e){}
            }
            update(timePassed);
            Graphics2D g = s.getGraphics();
            draw(g);
            g.dispose();
            s.update();
        }
    }

    public void update(long timePassed){
    }

    public boolean limitfps = false;

        public void draw(Graphics2D g){
        g.clearRect(0, 0, s.getWidth(), s.getHeight());
        AlphaComposite ac = java.awt.AlphaComposite.getInstance(AlphaComposite.CLEAR,0.5F);
        g.setComposite(ac);
        g.drawImage(new ImageIcon("Images/Test.png").getImage(), 30, 30, 30, 30, null);
        }







}
如果你运行这个代码,你将不得不按alt + tab键退出并结束进程(因为在代码的这一部分中没有任何操作来完成此任务)。

你说:“我被告知要将复合设置为AlphaComposite,但这只会完全透明....” 这是无稽之谈。如果正确设置了alpha复合,则可以导致完全透明的渐变。因此,你一定做错了什么,但如果没有代码,我们无法确定具体问题。请向我们展示代码,最好是一个sscce - Hovercraft Full Of Eels
我在那里发布了一些代码,我相信应该可以使用绘制方法将任何渲染的内容部分透明。 - blazingkin
我无法测试你的代码,因为我无法运行它。如果您没有很快得到答案,请考虑创建并发布一个sscce(阅读链接以了解其包含的内容)。 - Hovercraft Full Of Eels
好的,我添加了一个 SSCCE,它可以编译并展示问题所在。 - blazingkin
1个回答

26

你使用了错误的规则 - 不要使用AlphaComposite.CLEAR。

AlphaComposite API 对CLEAR做了如下说明:

清除目标图像的颜色和alpha值(Porter-Duff 清除规则)。源图像和目标图像都不作为输入使用。

因此,这将使图像消失。尝试其他规则。当你创建你的SSCCE时,我也创建了我的。尝试注释掉一个规则行并更改为另一个规则,看看会发生什么。例如,将以下内容进行更改:

// int rule = AlphaComposite.CLEAR;
int rule = AlphaComposite.SRC_OVER;

变成这样:

int rule = AlphaComposite.CLEAR;
// int rule = AlphaComposite.SRC_OVER;

完整的SSCCE:

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class TestAlphaComposite extends JPanel {
   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private static final Stroke BASIC_STROKE = new BasicStroke(6f);
   BufferedImage backgroundImage;
   BufferedImage overlayImage;

   public TestAlphaComposite() {
      backgroundImage = createBackGroundImage();
      overlayImage = createOverlayImage();
   }

   private BufferedImage createBackGroundImage() {
      BufferedImage img = new BufferedImage(PREF_W, PREF_H,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setStroke(BASIC_STROKE);
      g2.setColor(Color.blue);
      int circleCount = 10;
      for (int i = 0; i < circleCount ; i++) {
         int x = (i * PREF_W) / (2 * circleCount);
         int y = x;
         int w = PREF_W - 2 * x;
         int h = w;
         g2.drawOval(x, y, w, h);
      }
      g2.dispose();
      return img;
   }

   private BufferedImage createOverlayImage() {
      BufferedImage img = new BufferedImage(PREF_W, PREF_H,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setStroke(BASIC_STROKE);
      g2.setColor(Color.red);
      int circleCount = 10;
      for (int i = 0; i < circleCount + 1; i++) {
         int x1 = (i * PREF_W) / (circleCount);
         int y1 = 0;
         int x2 = PREF_W - x1;
         int y2 = PREF_H;
         float alpha = (float)i / circleCount;
         if (alpha > 1f) {
            alpha = 1f;
         }
         // int rule = AlphaComposite.CLEAR;
         int rule = AlphaComposite.SRC_OVER;
         Composite comp = AlphaComposite.getInstance(rule , alpha );
         g2.setComposite(comp );
         g2.drawLine(x1, y1, x2, y2);
      }
      g2.dispose();
      return img;
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (backgroundImage != null) {
         g.drawImage(backgroundImage, 0, 0, null);
      }
      if (overlayImage != null) {
         g.drawImage(overlayImage, 0, 0, null);
      }
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("TestAlphaComposite");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new TestAlphaComposite());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

顺便提一句,你的SSCCE并不是真正的SSCCE。我们无法编译或运行该代码,因为它具有我们无法访问的依赖项,即“com.blazingkin.atrox.ScreenManager”。如果你将来需要我们的帮助,你需要编写更好的符合SSCCE规范的代码。


7
+1, SSCE(简明、自给自足的最小可重现示例)是非常有用的。此外,您还可以参考这个实用程序。 - trashgod
1
请尝试一下@thrashgod发现的内容,这是一个小应用程序,可以自我解释!感谢thrashgod! - Benj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接