6

为什么组合 BG 为 JPEG 的图像会导致意外结果?

这是我在Overlaying of 2 images doesn't work proper 中回答的后续内容。那里发布的源(使用在内存中创建的 BG 图像)如下所示:

  • BG 图像在左侧。
  • FG 图像(具有透明度的 PNG)位于中间。
  • 组合图像在右侧。

到现在为止还挺好。但随后提出问题的人评论说,如果 BG 是 JPEG,它就失败了。认为他们弄错了,我改变了我的示例,将 BG 图像编码为 JPEG。现在,如果我使用BufferedImage.TYPE_INT_ARGBorBufferedImage.TYPE_INT_RGB作为最终图像,我会得到他们所指的内容:

TYPE_INT_ARGB

使用支持透明度的最终图像组合图像

TYPE_INT_RGB

使用不支持透明度的最终图像的组合图像

我希望至少其中一个的结果与原始结果相同(ARGB变体更是如此)。

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import javax.imageio.ImageIO;

class CombineImages {

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                try {
                    URL urlImage1 =
                        new URL("http://i.stack.imgur.com/T5uTa.png");

                    // Load the FG image
                    Image fgImage = ImageIO.read(urlImage1);
                    int w = fgImage.getWidth(null);
                    int h = fgImage.getHeight(null);
                    // Create a non-trasparent BG image
                    BufferedImage bgImageTemp =
                            new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);

                    ByteArrayOutputStream baos =
                        new ByteArrayOutputStream();
                    ImageIO.write(bgImageTemp, "jpg", baos);
                    ByteArrayInputStream bais =
                        new ByteArrayInputStream(baos.toByteArray());
                    BufferedImage bgImageJpeg = ImageIO.read(bais);

                    int result = JOptionPane.showConfirmDialog(
                        null,
                        "Use a final image with transparency?",
                        "Transparency",
                        JOptionPane.YES_NO_OPTION);

                    int type = (result==JOptionPane.OK_OPTION ?
                        BufferedImage.TYPE_INT_ARGB :
                        BufferedImage.TYPE_INT_RGB);

                    // Create the final image
                    BufferedImage finalImage =
                            new BufferedImage(w,h,type);
                    Graphics2D g = finalImage.createGraphics();
                    g.drawImage(bgImageJpeg, w, h, null);
                    g.drawImage(fgImage, w, h, null);
                    g.dispose();

                    JPanel gui = new JPanel(new GridLayout(1,0,5,5));

                    gui.add(new JLabel(new ImageIcon(bgImageJpeg)));
                    gui.add(new JLabel(new ImageIcon(fgImage)));
                    gui.add(new JLabel(new ImageIcon(finalImage)));

                    JOptionPane.showMessageDialog(null, gui);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
4

2 回答 2

3

看起来这是由于一个错字。

在您引用的答案中,形成组合图像的代码是

Graphics2D g = finalImage.createGraphics();
g.drawImage(bgImage, 0, 0, null);
g.drawImage(fgImage, 0, 0, null);

但是在这个问题中,它已更改为,

Graphics2D g = finalImage.createGraphics();
g.drawImage(bgImageJpeg, w, h, null);
g.drawImage(fgImage, w, h, null);

后者从“左上角”开始绘制,恰好是图像的右下角,因此没有真正绘制。然而,如预期的那样,前者绘制了整个图像。

于 2013-07-24T14:01:52.747 回答
0

gui.repaint();

尝试之后,因为您在构造 joptionpane 时有效地绘制了面板和组件,但是,即使那样,因为构造线程匹配可见性调用将不成立,所以无论如何您都应该在调用 joptionpane 之后在绘制覆盖方法中调用 g.drawImage。

它不能在屏幕上绘制实际上不存在的东西,但是对调用有容忍度,因为理论上它作为一组对象存在,足以满足该方法的需要。

于 2013-07-23T18:58:09.140 回答