为啥加入小缓冲图像的 Java 代码不起作用?

Posted

技术标签:

【中文标题】为啥加入小缓冲图像的 Java 代码不起作用?【英文标题】:Why Java code to join small buffered images does not work?为什么加入小缓冲图像的 Java 代码不起作用? 【发布时间】:2021-10-10 09:17:48 【问题描述】:

我创建了 4 个缓冲图像对象并用不同的颜色填充它们。然后创建一个更大的 bufferedimage 对象并将之前创建的所有四个 buff.image 绘制到其中以创建更大的图像。然后我将大图像保存到带有 gif 扩展名的文件中。虽然大小正确,但 gif 文件不包含颜色。为什么 ?我的错在哪里?

import java.awt.HeadlessException;
import java.awt.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class MainFrame extends JFrame implements Runnable

    public MainFrame() throws HeadlessException 
        ImagePanel ip=new ImagePanel(this);
        add(ip,"Center");
    
    
    public static void main(String[] args) 
        MainFrame mf=new MainFrame();
        mf.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        mf.setSize(new Dimension(800,600));
        mf.setLocationRelativeTo(null);
        mf.setVisible(true);

    



class ImagePanel extends JPanel 

    public ImagePanel(MainFrame jf) 
        ImageJoiner imj=new ImageJoiner();
    





class ImageJoiner 
    
    // this will joing four buffered images together to construct bigger image as buffered image and save it as gif file
    
    public ImageJoiner() 
        createImages();
    
    
    public void createImages() 
            
    imtl=new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    imtr=new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    imbl=new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    imbr=new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    
    bigW=PW*2;
    bigH=PH*2;
    
    bigmap=new BufferedImage(bigW, bigH, BufferedImage.TYPE_INT_RGB); 
    
    imtl.createGraphics().setColor(Color.blue);
    imtl.createGraphics().fillRect(0,0, PW, PH);

    imtr.getGraphics().setColor(Color.red);
    imtr.getGraphics().fillRect(0, 0, PW, PH);

    imbl.getGraphics().setColor(Color.green);
    imbl.getGraphics().fillRect(0, 0, PW, PH);
    
    imbr.getGraphics().setColor(Color.yellow);
    imbr.getGraphics().fillRect(0, 0, PW, PH);
            
    bigmap.getGraphics().drawImage(imtl, 0, 0,PW,PH,null);
    bigmap.getGraphics().drawImage(imtr, PW, 0,PW,PH,null);
    bigmap.getGraphics().drawImage(imbl, 0, PH, PW,PH,null);
    bigmap.getGraphics().drawImage(imbr, PW, PH,PW,PH,null);
    
    writeBufferedImageToFile(bigmap);
        
    
    
    private void writeBufferedImageToFile(BufferedImage bim) 
        File file = new File("images/out.gif");
        try 
            ImageIO.write(bim, "gif", file);
         catch (IOException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
    
    
    static final int PW =1000;
    static final int PH =1000;
    static int bigW,bigH;
    BufferedImage imtl,imtr,imbl,imbr;
    BufferedImage bigmap;


【问题讨论】:

请注意,即使存储imtl 而不是bigmap 也会产生一个白色文件,而JFrame 是不必要的,因此您仍然可以将这个示例剪掉很多。跨度> 【参考方案1】:

您正在随意创建 Graphics 对象,设置一个对象的颜色,使用另一个对象进行绘图,这可能行不通。以更好的方式创建并使用您的 Graphics 对象,例如:

public static void createImages() 
            
    imtl = new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    imtr = new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    imbl = new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    imbr = new BufferedImage(PW, PH, BufferedImage.TYPE_INT_RGB);
    
    int bigW = PW * 2;
    int bigH = PH * 2;
    
    BufferedImage bigmap = new BufferedImage(bigW, bigH, BufferedImage.TYPE_INT_RGB); 
    
    Graphics2D g2d = imtl.createGraphics();
    g2d.setColor(Color.BLUE);
    g2d.fillRect(0,0, PW, PH);
    g2d.dispose();

    g2d = imtr.createGraphics();
    g2d.setColor(Color.RED);
    g2d.fillRect(0,0, PW, PH);
    g2d.dispose();
    
    g2d = imbl.createGraphics();
    g2d.setColor(Color.GREEN);
    g2d.fillRect(0,0, PW, PH);
    g2d.dispose();

    g2d = imbr.createGraphics();
    g2d.setColor(Color.YELLOW);
    g2d.fillRect(0,0, PW, PH);
    g2d.dispose();
    
    g2d = bigmap.createGraphics();
    g2d.drawImage(imtl, 0, 0,PW,PH,null);
    g2d.drawImage(imtr, PW, 0,PW,PH,null);
    g2d.drawImage(imbl, 0, PH, PW,PH,null);
    g2d.drawImage(imbr, PW, PH,PW,PH,null);
    g2d.dispose();
    
    writeBufferedImageToFile(bigmap);

代码经过测试,可以正常工作


你也问过:

我仍然很好奇,为什么BufferedImage#getGraphics().fillRect() 不起作用?它只有你定义一个图形对象然后分配它才有效?为什么不能直接使用?

BufferedImage#getGraphics()BufferedImage#createGraphics() 创建一个 Graphics2D 实例时,该实例与之前创建的任何实例都没有关系。

例如,您可以通过调用来测试:

BufferedImage img = new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB);
Graphics ga = img.getGraphics();
Graphics gb = img.getGraphics();

System.out.println("ga: " + ga.hashCode());
System.out.println("gb: " + gb.hashCode());

ga.dispose();  // always dispose of resources that *you* create
gb.dispose();

运行这个程序,你会看到两个不同的 hashCodes被打印出来,证明ga和gb实例是不同的。如果您调用.createGraphics(),将出现相同的相对输出。

所以,当你这样做时:

imtl.createGraphics().setColor(Color.blue);
imtl.createGraphics().fillRect(0,0, PW, PH);

您正在设置一个 Graphics 实例的颜色,然后使用另一个独特的新实例进行绘制。由于第二个实例的颜色没有设置,它会使用默认颜色进行绘制,所有图像都将保持黑色。

【讨论】:

呃......我已经很久没有做过任何 AWT 或 Swing,但那是非常不直观的,特别是因为该方法被称为 getGraphics:假设总是返回相同的 Graphics ,但这不是它指定要做的事情。 @JoachimSauer 始终使用createGraphics()。它做同样的事情,但有一个更好的名字,你不需要转换为Graphics2D。 ? 谢谢,它起作用了,但我仍然很好奇,为什么 .getGraphics().fillRect() 不起作用?它只有你定义一个图形对象然后分配它才有效?为什么不能直接使用? @JoachimSauer:Graphics 对象的本质始终是它们永远不会被认为是持久的,它们本质上是短暂的,我对这里展示的行为并不感到惊讶。 非常感谢@HovercraftFullOfEels。

以上是关于为啥加入小缓冲图像的 Java 代码不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥图像文字在 Xcode 11.2.1 中不起作用?

为啥我的 SVG 背景图像不起作用?

为啥这个信号/槽代码不起作用

Django 和引导程序,为啥我的小部件不起作用?

为啥我的 Center 小部件在 Dart 中不起作用? |扑

为啥 preventDefault 不起作用?