7

我想将 JPanel 转换为图像。我使用了以下方法:

public BufferedImage createImage(){

    int w = getWidth();
    int h = getHeight();
    BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    Graphics2D g = bi.createGraphics();
    paint(g);
    return bi;
}

但问题是 JPanel 包含在 JScrollPane 中。因此,当我将 jpanel 转换为图像时,图像仅包含 jpanel 中可见的部分,而隐藏在滚动窗格内的部分不包含在图像中。

是否有任何解决方案可以将 JPanel 的全部内容转换为图像?

4

3 回答 3

12

但问题是 JPanel 包含在 JScrollPane 中。因此,当我将 jpanel 转换为图像时,图像仅包含 jpanel 中可见的部分,而隐藏在滚动窗格内的部分不包含在图像中。

这不会发生在我身上......你试过paintAll代替paint吗?

这是一个很好的方法,可以捕获任何Component可见或不可见的内容(它不是我的,我从 SO 的某个地方得到它并从那以后使用它):

public static BufferedImage componentToImage(Component component, boolean visible) {
    if (visible) {
        BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
        Graphics2D g2d = (Graphics2D) img.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        component.paintAll(g2d);
        return img;
    } else {
        component.setSize(component.getPreferredSize());
        layoutComponent(component);
        BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
        CellRendererPane crp = new CellRendererPane();
        crp.add(component);
        crp.paintComponent(img.createGraphics(), component, crp, component.getBounds());
        return img;
    }
}

private static void layoutComponent(Component c) {
    synchronized (c.getTreeLock()) {
        c.doLayout();
        if (c instanceof Container) {
            for (Component child : ((Container) c).getComponents()) {
                layoutComponent(child);
            }
        }
    }
}

这是一个展示上述内容的示例:

框架视图:

在此处输入图像描述

面板截图:

在此处输入图像描述

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.CellRendererPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class Test {

    public Test() {
        createAndShowGui();
    }

    private void createAndShowGui() {
        JFrame frame = new JFrame() {
            @Override
            public Dimension getPreferredSize() {//size frame purposefully smaller
                return new Dimension(100, 100);
            }
        };
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        Image img = null;
        try {
            img = ImageIO.read(new URL("http://images4.wikia.nocookie.net/__cb20120515073660/naruto/images/0/09/Naruto_newshot.png")).getScaledInstance(200, 200, Image.SCALE_SMOOTH);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        final ImagePanel imagePanel = new ImagePanel(200, 200, img);
        JScrollPane jsp = new JScrollPane(imagePanel);
        frame.add(jsp);


        frame.pack();
        frame.setVisible(true);
        BufferedImage bi = componentToImage(imagePanel, true);
        try {
            File outputfile = new File("c:/saved.png");
            ImageIO.write(bi, "png", outputfile);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static BufferedImage componentToImage(Component component, boolean visible) {
        if (visible) {
            BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
            Graphics2D g2d = (Graphics2D) img.getGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            component.paintAll(g2d);
            return img;
        } else {
            component.setSize(component.getPreferredSize());
            layoutComponent(component);
            BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
            CellRendererPane crp = new CellRendererPane();
            crp.add(component);
            crp.paintComponent(img.createGraphics(), component, crp, component.getBounds());
            return img;
        }
    }

    private static void layoutComponent(Component c) {
        synchronized (c.getTreeLock()) {
            c.doLayout();
            if (c instanceof Container) {
                for (Component child : ((Container) c).getComponents()) {
                    layoutComponent(child);
                }
            }
        }
    }

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

class ImagePanel extends JPanel {

    int width, height;
    Image bg;

    public ImagePanel(int width, int height, Image bg) {
        this.width = width;
        this.height = height;
        this.bg = bg;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(width, height);
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        grphcs.drawImage(bg, 0, 0, null);
    }
}

更新:

根据您的评论:

我使用 ImageIO.write(bufferedImage, "jpg" , file); 将 BufferedImage 写入文件 这适用于 png 和 gif 图像,但 jpg 图像显示红色背景而不是白色。我该如何解决这个问题。谢谢

有关更多信息,请参阅这个类似的问题/答案。你会做这样的事情:

private static final int[] RGB_MASKS = {0xFF0000, 0xFF00, 0xFF};
private static final ColorModel RGB_OPAQUE = new DirectColorModel(32, RGB_MASKS[0], RGB_MASKS[1], RGB_MASKS[2]);
...

BufferedImage image = componentToImage(imagePanel, true);
saveJPeg(image, "c:/saved.jpg");

private void saveJPeg(BufferedImage image, String name) {
    PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, true);
    try {
        pg.grabPixels();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
    int width = pg.getWidth(), height = pg.getHeight();

    DataBuffer buffer = new DataBufferInt((int[]) pg.getPixels(), pg.getWidth() * pg.getHeight());
    WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, RGB_MASKS, null);
    BufferedImage bi = new BufferedImage(RGB_OPAQUE, raster, false, null);

    try {
        ImageIO.write(bi, "jpg", new File(name));
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}
于 2013-01-27T20:08:05.453 回答
3

SwingUtilities.paintComponent做到了:

static void drawComponent(JComponent c,
                          BufferedImage destination) {

    JFrame frame = new JFrame();

    Graphics g = destination.createGraphics();

    SwingUtilities.paintComponent(g, c, frame.getContentPane(),
        0, 0, destination.getWidth(), destination.getHeight());

    g.dispose();

    frame.dispose();
}

static BufferedImage createSnapshotOf(JComponent c) {

    Dimension size = c.getSize();
    if (size.width <= 0 || size.height <= 0) {
        size = c.getPreferredSize();
    }

    BufferedImage snapshot =
        new BufferedImage(size.width, size.height,
            BufferedImage.TYPE_INT_ARGB);

    drawComponent(c, snapshot);

    return snapshot;
}
于 2013-01-27T21:07:56.597 回答
1

我不知道你为什么需要做这么复杂的事情。只要您的缓冲图像和绘画功能都使用 JScroolPane 中的组件(巨大),就应该保存整个内容。

    //create a tree data structure
    DefaultMutableTreeNode tree = new DefaultMutableTreeNode("root");
    //optional: you can make the tree really big

    //now show the tree
    JFrame frame = new JFrame("TreeDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Create a Jtree component to display your data structure 
    JTree treeDisplay = new JTree(tree);

    //expand the tree all out
    for(int i = 0; i < treeDisplay.getRowCount(); i++) {
        treeDisplay.expandRow(i);
    }

    //put your tree display component in a scroll pane
    frame.add(new JScrollPane(treeDisplay));

    //Display the window.
    frame.pack();
    frame.setVisible(true);

    //save tree in the window to a file
    BufferedImage img = new BufferedImage(treeDisplay.getWidth(), treeDisplay.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics2D graphics = img.createGraphics();
    //put graphics on the buffered image
    treeDisplay.paintAll(graphics);    
    graphics.dispose();

    try {
        ImageIO.write(img, "png", new File("tree.png"));
    }
    catch (IOException e) {
        e.printStackTrace();
    }
于 2015-06-19T21:23:11.597 回答