gpt4 book ai didi

java - 将 BufferedImage 的像素设置为透明

转载 作者:行者123 更新时间:2023-11-30 06:59:46 26 4
gpt4 key购买 nike

如何快速有效地设置 BufferedImage 的所有像素?透明化,以便我可以简单地为每一帧重新绘制我想要的 Sprite 图形?

我正在用 Java 设计一个简单的游戏引擎来更新背景和前景 BufferedImage并将它们绘制成复合 VolatileImage为了有效缩放,绘制到 JPanel .这种可扩展模型允许我添加更多层并迭代每个绘图层。

我将我的应用程序简化为下面给出的一个类来演示我的问题。使用箭头键在图像上移动一个红色方 block 。挑战在于我想将更新游戏图形与将合成图形绘制到游戏引擎分离。我已经研究了这个问题的看似彻底的答案,但无法弄清楚如何将它们应用到我的应用程序中:

这里是没有正确清除像素的临界区。注释掉的部分来 self 已经阅读过的堆栈溢出答案,但它们将背景绘制为不透明的黑色或白色。我知道 foregroundImage在我的实现中从透明像素开始,因为您可以看到 backgroundImage 的随机像素噪声应用程序开始时在红色 Sprite 后面。此时图像没有被清除,所以之前绘制的图像仍然存在。

/** Update the foregroundGraphics. */
private void updateGraphics(){
Graphics2D fgGraphics = (Graphics2D) foregroundImage.getGraphics();

// set image pixels to transparent
//fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
//fgGraphics.setColor(new Color(0,0,0,0));
//fgGraphics.clearRect(0, 0, width, height);
//fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));

// draw again.
fgGraphics.setColor(Color.RED);
fgGraphics.fillRect(sx, sy, spriteSize, spriteSize);
fgGraphics.dispose();
}

这是我的整个示例代码:

/**
* The goal is to draw two BufferedImages quickly onto a scalable JPanel, using
* a VolatileImage as a composite.
*/
public class Example extends JPanel implements Runnable, KeyListener
{
private static final long serialVersionUID = 1L;
private int width;
private int height;
private Object imageLock;
private Random random;
private JFrame frame;
private Container contentPane;
private BufferedImage backgroundImage;
private BufferedImage foregroundImage;
private VolatileImage compositeImage;
private Graphics2D compositeGraphics;
private int[] backgroundPixels;
private int[] foregroundPixels;
// throttle the framerate.
private long prevUpdate;
private int frameRate;
private int maximumWait;
// movement values.
private int speed;
private int sx;
private int sy;
private int dx;
private int dy;
private int spriteSize;

/** Setup required fields. */
public Example(){
width = 512;
height = 288;
super.setPreferredSize(new Dimension(width, height));
imageLock = new Object();
random = new Random();
frame = new JFrame("BufferedImage Example");
frame.addKeyListener(this);
contentPane = frame.getContentPane();
contentPane.add(this, BorderLayout.CENTER);
// used to create hardware-accelerated images.
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
backgroundImage = gc.createCompatibleImage(width, height,Transparency.TRANSLUCENT);
foregroundImage = gc.createCompatibleImage(width, height,Transparency.TRANSLUCENT);
compositeImage = gc.createCompatibleVolatileImage(width, height,Transparency.TRANSLUCENT);
compositeGraphics = compositeImage.createGraphics();
compositeGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
compositeGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
backgroundPixels = ((DataBufferInt) backgroundImage.getRaster().getDataBuffer()).getData();
foregroundPixels = ((DataBufferInt) foregroundImage.getRaster().getDataBuffer()).getData();
//initialize the background image.
for(int i = 0; i < backgroundPixels.length; i++){
backgroundPixels[i] = random.nextInt();
}
// used to throttle frames per second
frameRate = 180;
maximumWait = 1000 / frameRate;
prevUpdate = System.currentTimeMillis();
// used to update sprite state.
speed = 1;
dx = 0;
dy = 0;
sx = 0;
sy = 0;
spriteSize = 32;
}

/** Renders the compositeImage to the Example, scaling to fit. */
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// draw the composite, scaled to the JPanel.
synchronized (imageLock) {
((Graphics2D) g).drawImage(compositeImage, 0, 0, super.getWidth(), super.getHeight(), 0, 0, width, height, null);
}
// force repaint.
repaint();
}

/** Update the BufferedImage states. */
@Override
public void run() {
while(true){
updateSprite();
updateGraphics();
updateComposite();
throttleUpdateSpeed();
}
}

/** Update the Sprite's position. */
private void updateSprite(){
// update the sprite state from the inputs.
dx = 0;
dy = 0;
if (Command.UP.isPressed()) dy -= speed;
if (Command.DOWN.isPressed()) dy += speed;
if (Command.LEFT.isPressed()) dx -= speed;
if (Command.RIGHT.isPressed()) dx += speed;
sx += dx;
sy += dy;
// adjust to keep in bounds.
sx = sx < 0 ? 0 : sx + spriteSize >= width ? width - spriteSize : sx;
sy = sy < 0 ? 0 : sy + spriteSize >= height ? height - spriteSize : sy;
}

/** Update the foregroundGraphics. */
private void updateGraphics(){
Graphics2D fgGraphics = (Graphics2D) foregroundImage.getGraphics();

// set image pixels to transparent
//fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
//fgGraphics.setColor(new Color(255, 255, 255, 255));
//fgGraphics.clearRect(0, 0, width, height);
//fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));

// draw again.
fgGraphics.setColor(Color.RED);
fgGraphics.fillRect(sx, sy, spriteSize, spriteSize);
fgGraphics.dispose();
}

/** Draw the background and foreground images to the volatile composite. */
private void updateComposite(){
synchronized (imageLock) {
compositeGraphics.drawImage(backgroundImage, 0, 0, null);
compositeGraphics.drawImage(foregroundImage, 0, 0, null);
}

}

/** Keep the update rate around 60 FPS. */
public void throttleUpdateSpeed(){
try {
Thread.sleep(Math.max(0, maximumWait - (System.currentTimeMillis() - prevUpdate)));
prevUpdate = System.currentTimeMillis();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}

/** Ignore key typed events. */
@Override
public void keyTyped(KeyEvent e) {}

/** Handle key presses. */
@Override
public void keyPressed(KeyEvent e) {
setCommandPressedFrom(e.getKeyCode(), true);
}

/** Handle key releases. */
@Override
public void keyReleased(KeyEvent e) {
setCommandPressedFrom(e.getKeyCode(), false);
}

/** Switch over key codes and set the associated Command's pressed value. */
private void setCommandPressedFrom(int keycode, boolean pressed){
switch (keycode) {
case KeyEvent.VK_UP:
Command.UP.setPressed(pressed);
break;
case KeyEvent.VK_DOWN:
Command.DOWN.setPressed(pressed);
break;
case KeyEvent.VK_LEFT:
Command.LEFT.setPressed(pressed);
break;
case KeyEvent.VK_RIGHT:
Command.RIGHT.setPressed(pressed);
break;
}
}
/** Commands are used to interface with key press values. */
public enum Command{
UP, DOWN, LEFT, RIGHT;
private boolean pressed;

/** Press the Command. */
public void press() {
if (!pressed) pressed = true;
}
/** Release the Command. */
public void release() {
if (pressed) pressed = false;
}
/** Check if the Command is pressed. */
public boolean isPressed() {
return pressed;
}
/** Set if the Command is pressed. */
public void setPressed(boolean pressed) {
if (pressed) press();
else release();
}
}

/** Begin the Example. */
public void start(){
try {
// create and display the frame.
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
Example e = new Example();
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
// start updating from key inputs.
Thread t = new Thread(this);
t.start();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}

/** Start the application. */
public static void main(String[] args){
Example e = new Example();
e.start();
}
}

编辑:

- 修复了初始化 backgroundPixels 的 for 循环中的拼写错误随机。

最佳答案

原来我在选择方法时犯了错误。我注意到我正在清除一个一像素宽的框,它是我的图形的轮廓。这是因为我不小心使用了 drawRect() 而不是 fillRect()。更改我的代码后,它现在可以工作了。以下是我能够开始工作的示例。

使用 AlphaComposite.CLEAR 的示例(使用任何不透明颜色绘制):

    // clear pixels
fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
fgGraphics.setColor(new Color(255,255,255,255));
fgGraphics.fillRect(0, 0, width, height);
fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
// draw new graphics

使用 AlphaComposite.SRC_OUT 的示例(使用任何带有 alpha 零的颜色绘制):

    // clear pixels
fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT));
fgGraphics.setColor(new Color(255,255,255,0));
fgGraphics.fillRect(0, 0, width, height);
fgGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
// draw new graphics

关于java - 将 BufferedImage 的像素设置为透明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31149206/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com