簡體   English   中英

將BufferedImage的像素設置為透明

[英]Set pixels of BufferedImage as transparent

如何快速有效地將BufferedImage所有像素設置為透明,以便我可以簡單地重繪每幀想要的精靈圖形?

我正在用Java設計一個簡單的游戲引擎,該引擎會更新背景和前景BufferedImage並將它們繪制到復合的VolatileImage以進行有效縮放,以繪制到JPanel 這種可擴展的模型使我可以添加更多層並在每個繪圖層上進行迭代。

我將我的應用程序簡化為下面給出的一個類,它演示了我的問題。 使用箭頭鍵在圖像上移動紅色方塊。 我面臨的挑戰是,我想將更新游戲圖形與將合成圖形繪制到游戲引擎上分離開來。 我研究了這個問題看似徹底的答案,但無法弄清楚如何將其應用於我的應用程序:

這是關鍵部分,無法正確清除像素。 注釋掉的部分來自我已經閱讀過的堆棧溢出答案,但是它們將背景繪制為非透明的黑色或白色。 我知道我的實現中foregroundImage圖像以透明像素開始,因為您可以在應用程序啟動時看到紅色小精靈后面的backgroundImage的隨機像素噪聲。 現在,該圖像尚未清除,因此保留了先前繪制的圖像。

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

編輯:

-修復了for循環中將backgroundPixels初始化為隨機的輸入錯誤。

原來我在方法選擇中感到很困惑。 我注意到我正在清理一個1像素寬的框,該框是我圖形的輪廓。 這是因為我不小心使用了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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM