简体   繁体   English

将JPanel转换为JScrollPane中的图像

[英]Convert a JPanel to an image in a JScrollPane

I want to convert an JPanel to an image. 我想将JPanel转换为图像。 I used the following method: 我使用以下方法:

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;
}

But the problem is that the JPanel is contained within a JScrollPane. 但问题是JPanel包含在JScrollPane中。 So when I convert the jpanel to an image, the image contains only the parts visible in the jpanel and the parts that are hidden inside the scrollpane aren't contained in the image. 因此,当我将jpanel转换为图像时,图像仅包含jpanel中可见的部分,并且隐藏在滚动窗格内部的部分不包含在图像中。

Are there any solutions to get the full content of the JPanel into an image? 是否有任何解决方案可以将JPanel的全部内容转换为图像?

But the problem is that the JPanel is contained within a JScrollPane. 但问题是JPanel包含在JScrollPane中。 So when I convert the jpanel to an image, the image contains only the parts visible in the jpanel and the parts that are hidden inside the scrollpane aren't contained in the image. 因此,当我将jpanel转换为图像时,图像仅包含jpanel中可见的部分,并且隐藏在滚动窗格内部的部分不包含在图像中。

This doesnt happen to me... have you tried paintAll instead of paint ? 这不会发生在我身上......你尝试过paintAll而不是paint吗?

Here is a great method which will capture the content of any Component visible or not (Its not mine I got it somewhere off the SO and have used it since): 这是一个很好的方法,可以捕获任何可见或不可见的Component的内容(它不是我的,我从它的某个地方得到它,并从那以后使用它):

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);
            }
        }
    }
}

Here is an example showcasing the above: 以下是展示上述内容的示例:

The frame view: 框架视图:

在此输入图像描述

capture of the panel: 捕获小组:

在此输入图像描述

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);
    }
}

UPDATE: 更新:

As per your comment: 根据你的评论:

I wrote the BufferedImage into a file by using ImageIO.write(bufferedImage, "jpg" , file); 我使用ImageIO.write(bufferedImage,“jpg”,file)将BufferedImage写入文件中; this works fine for both png and gif images, but jpg image shows a red background instead of white. 这适用于png和gif图像,但jpg图像显示红色背景而不是白色。 How can i slove that problem. 我该如何解决这个问题呢。 Thanks 谢谢

See this similar question/answer for more. 有关更多信息,请参阅类似问题/答案 You would do something like: 你会做的事情如下:

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

SwingUtilities.paintComponent does it: 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;
}

I don't know why you need to do something so complicated. 我不知道为什么你需要做一些如此复杂的事情。 As long as your Buffered image and paint function all use the component (huge) that is the in the JScroolPane, the whole thing should be saved. 只要您的Buffered图像和绘图功能都使用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();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM