Сохранение JPanel как изображения

Я занимаюсь разработкой приложения, позволяющего пользователю загружать изображение в слой. Пользователь может нарисовать какую-то картинку на другом слое и сохранить только изображение, нарисованное пользователем. Вот мой код:

import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class LayerDemo extends JApplet {

    private JLayeredPane mainLayer;

    private JPanel layer1;

    private JPanel layer2;

    private JLabel label;

    private ImageIcon imgIcon;


    /**
     * Create the applet.
     */
    public LayerDemo() {    
    }

    public void init() {
        Dimension mainDemension = new Dimension(1024,768);
        setSize(mainDemension);

        mainLayer = new JLayeredPane();   
        layer1 = new JPanel();
        layer1.setOpaque(false);
        layer1.setBounds(0, 0, this.getWidth(), this.getHeight());
        imgIcon = new ImageIcon("bear.jpg");
        label = new JLabel(imgIcon);
        label.setBounds(0, 0, imgIcon.getIconWidth(), imgIcon.getIconHeight());
        layer1.add(label);

        layer2 = new PaintDemo(true);
        layer2.setOpaque(false);
        layer2.setBounds(0, 0, this.getWidth(), this.getHeight());

        mainLayer.add(layer1, 1);
        mainLayer.add(layer2, 2);
        this.setContentPane(mainLayer);
    }

    public void paint(Graphics g) {    
    }

}

Это класс для рисования пользователя:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelListener;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class PaintDemo extends JPanel {
    /**
     * field explanation
     */
    private Point startPoint = new Point();

    private Point endPoint = new Point();

    private Graphics2D g2;

    private int minX;

    private int minY;

    private int maxX;

    private int maxY;

    private int height;

    private int width;


    /**
     * Create the panel.
     */

    public PaintDemo(boolean isDoubleBuffer) {

        addMouseWheelListener(new MouseWheelListener() {
            public void mouseWheelMoved(MouseWheelEvent e) {
            }
        });
        this.setDoubleBuffered(isDoubleBuffer);
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                endPoint = e.getPoint();
                Graphics g = PaintDemo.this.getGraphics();
                paintComponent(g);
                minX = minX < endPoint.x ? minX : endPoint.x;
                minY = minY < endPoint.y ? minY : endPoint.y;
                maxX = maxX > endPoint.x ? maxX : endPoint.x;
                maxY = maxY > endPoint.y ? maxY : endPoint.y;
                startPoint = endPoint;
            }
        });
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                startPoint = e.getPoint();
                minX = startPoint.x;
                minY = startPoint.y;
                maxX = startPoint.x;
                maxY = startPoint.y;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                endPoint = e.getPoint();
                Graphics g = PaintDemo.this.getGraphics();
                paintComponent(g);
                minX = minX < endPoint.x ? minX : endPoint.x;
                minY = minY < endPoint.y ? minY : endPoint.y;
                maxX = maxX > endPoint.x ? maxX : endPoint.x;
                maxY = maxY > endPoint.y ? maxY : endPoint.y;
                minX = minX > 0 ? minX : 0;
                minY = minY > 0 ? minY : 0;
                maxX = maxX < 1024 ? maxX : 1024;
                maxY = maxY < 768 ? maxY : 768;
                width = maxX - minX;
                height = maxY - minY;
                saveImage();     
                startPoint = new Point();
                endPoint = new Point();

            }
        });
    }

    /**
     * Paint method
     * 
     * {@inheritDoc}
     */
    @Override
    public void paintComponent(Graphics g) {
        g2 = (Graphics2D)g;
        g2.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2.setFont(new Font("Serif", Font.BOLD, 18));
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.red);
        g2.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
    }

    public void saveImage() {
        BufferedImage bi = new BufferedImage(PaintDemo.this.getWidth(), PaintDemo.this.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = bi.createGraphics();
        paintComponent(g2);
        g2.dispose();
        try
        {
            ImageIO.write(bi, "jpg", new File("clip.jpg"));
        }
        catch(IOException ioe)
        {
            System.out.println("Clip write help: " + ioe.getMessage());
        }
    }
}

Когда сохранить изображение, это просто пустое изображение. Пожалуйста, помогите мне. Большое спасибо. P/S: я отредактировал мой код как вашу идею, но он не работает. Результатом является отсутствие фонового изображения и сохранение пустого изображения.:(

2 ответа

Решение

Выборочная окраска выполняется путем переопределения метода paintComponent() панели. Затем вы используете объект Graphics для рисования.

У вас не должно быть пустого метода paint().

Метод drawline() не должен использовать метод getGraphics(). Вместо этого этот код следует переместить в метод paintComponent(), а затем использовать объект Graphics, переданный методу.

Кроме того, вы НЕ должны переопределять метод paint() апплета. Так как ваш код рисует изображение в его реальном размере, вы должны просто использовать JLabel для отображения изображения, создав ImageIcon. Затем вы добавляете метку на многослойную панель для использования в качестве фонового изображения.

Редактировать:

Почему у вас все еще есть пустой метод paint()? Избавьтесь от этого, нет необходимости переопределять метод paint().

Когда я запускаю код, я получаю исключение безопасности, поскольку апплеты не могут записывать в файл, поэтому я не могу проверить эту часть вашего кода. Но если вам интересно, я использую Screen Image для создания изображений компонента.

Тем не менее, ваша главная проблема в том, что код рисования неверен. Да, вы увидите нарисованные линии, но они не являются постоянными. Никогда не следует использовать метод getGraphics() компонента, если вы хотите выполнить постоянное рисование. Попробуйте нарисовать несколько линий, затем сверните апплет, а затем восстановите апплет, и вы поймете, что я имею в виду.

Решением для этого является рисование на BufferedImage. Увидеть DrawOnImage пример из пользовательских подходов к рисованию.

См. ComponentImageCapture.java для советов.

Другие вопросы по тегам