Java: Как выполнять манипуляции с изображениями (панорамирование, масштабирование, отражение и поворот)? - PullRequest
0 голосов
/ 20 сентября 2019

Я делаю приложение для просмотра изображений для моих собственных интересов.Я использую JPanel для отображения bufferedImage.

Цель - я хочу манипулировать изображением и дать пользователю возможность масштабировать, панорамировать, переворачивать или поворачивать изображения.

Теперь я могу масштабировать, панорамировать ивращаться.Но проблема в том, что это не то же самое, что вы видите, когда открываете файл .pdf в Microsoft Edge .

Я добавил следующий код:

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.*;

public class ZoomAndPan1 extends JPanel {

    BufferedImage img;
    private boolean init = true;
    private int zoomLevel = 0;
    private int minZoomLevel = -20;
    private int maxZoomLevel = 10;
    private double zoomMultiplicationFactor = 1.2;

    private Point dragStartScreen;
    private Point dragEndScreen;
    private AffineTransform coordTransform = new AffineTransform();

    public ZoomAndPan1() throws IOException {
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                dragStartScreen = e.getPoint();
                dragEndScreen = null;
            }
        });
        this.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                pan(e);
            }
        });
        this.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                if (e.isControlDown()) {
                    zoom(e);
                }
            }
        });
        img = ImageIO.read(new File("file.path"));
    }

    @Override
    protected void paintComponent(Graphics g) {

        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        int x = (int) (this.size().getWidth() - (img.getWidth() * .2)) / 2;
        int y = (int) (this.size().getHeight() - (img.getHeight() * .2)) / 2;

        AffineTransform at = new AffineTransform();
        at.translate(x, y);
        at.scale(.2, .2);
        if (init) {
            g2.setTransform(at);
            init = false;
            coordTransform = g2.getTransform();
        } else {
            g2.setTransform(coordTransform);
        }

        g2.drawImage(img, 0, 0, this);

        g2.dispose();
    }

    private void pan(MouseEvent e) {
        try {
            dragEndScreen = e.getPoint();
            Point2D.Float dragStart = transformPoint(dragStartScreen);
            Point2D.Float dragEnd = transformPoint(dragEndScreen);
            double dx = dragEnd.getX() - dragStart.getX();
            double dy = dragEnd.getY() - dragStart.getY();
            coordTransform.translate(dx, dy);
            dragStartScreen = dragEndScreen;
            dragEndScreen = null;
            repaint();
        } catch (NoninvertibleTransformException ex) {
            ex.printStackTrace();
        }
    }

    private void zoom(MouseWheelEvent e) {
        try {
            int wheelRotation = e.getWheelRotation();
            Point p = e.getPoint();
            if (wheelRotation > 0) {
                if (zoomLevel < maxZoomLevel) {
                    zoomLevel++;
                    Point2D p1 = transformPoint(p);
                    coordTransform.scale(1 / zoomMultiplicationFactor, 1 / zoomMultiplicationFactor);
                    Point2D p2 = transformPoint(p);
                    coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
                    repaint();
                }
            } else {
                if (zoomLevel > minZoomLevel) {
                    zoomLevel--;
                    Point2D p1 = transformPoint(p);
                    coordTransform.scale(zoomMultiplicationFactor, zoomMultiplicationFactor);
                    Point2D p2 = transformPoint(p);
                    coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
                    repaint();
                }
            }
        } catch (NoninvertibleTransformException ex) {
            ex.printStackTrace();
        }
    }

    private Point2D.Float transformPoint(Point p1) throws NoninvertibleTransformException {
        AffineTransform inverse = coordTransform.createInverse();
        Point2D.Float p2 = new Point2D.Float();
        inverse.transform(p1, p2);
        return p2;
    }

    public Dimension getPreferredSize() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        return new Dimension(screenSize.width, screenSize.height);
    }

    public static void main(String[] args) {
        try {
            JFrame frame = new JFrame("Zoom and Pan ");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(new ZoomAndPan1(), BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
        } catch (IOException ex) {
            Logger.getLogger(ZoomAndPan1.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Этот код может выполнять следующие действия:

  1. Увеличение / уменьшение на CTRL + прокрутка мыши

  2. Панорамирование изображения при перетаскивании мышью .

Ограничения:

  1. Возврат в центр при уменьшении.

  2. Панорамирование не ограничено границами Jpanel или viewport.

Я хочу достичьэто:

enter image description here

К сожалению, код работает следующим образом:

enter image description here

Как это решить?

Заранее спасибо ..

Ответы [ 2 ]

0 голосов
/ 24 сентября 2019

Наконец-то я смог управлять функцией панорамирования.

Я заменил функцию панорамирования этим слушателем.Он применяет ту же концепцию, что и изображение на этикетке.И я не могу позволить себе использовать ярлыки, так как я буду писать поверх самого изображения, поэтому я так и сделал.

//map - represents the container or component the image was drawn.
//then I added a ScrollPane on map..


map.setAutoscrolls(true);
add(new JScrollPane(map));

MouseAdapter ma = new MouseAdapter() {
  private Point origin;

  @Override
  public void mousePressed(MouseEvent e) {
      origin = new Point(e.getPoint());
      System.out.println("click");
  }

  @Override
  public void mouseDragged(MouseEvent e) {
      if (origin != null) {
        JViewport viewPort = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, map);
        if (viewPort != null) {
              int deltaX = origin.x - e.getX();
              int deltaY = origin.y - e.getY();

              Rectangle view = viewPort.getViewRect();
              view.x += deltaX;
              view.y += deltaY;

              map.scrollRectToVisible(view);

         }
      }                
   }
};
0 голосов
/ 23 сентября 2019

Вот простая программа, которая демонстрирует то, что я предложил, а именно большое изображение, установленное как значок JLabel, а JLabel - это прокручиваемый клиент для JScrollPane.Обратите внимание, что я установил предпочтительный размер JScrollPane равным 800 x 600 пикселей, поскольку по умолчанию поведение JScrollPane соответствует размеру его прокручиваемого клиента.Размеры изображения составляют 2312 x 1536 пикселей, что означает, что он больше, чем экран моего компьютера.Поэтому, если я не установлю предпочтительный размер, при запуске программы JFrame переполняет экран.Вы не видите все JFrame.Это сделано специально, чтобы вы могли видеть, как изображение прокручивается.URL для изображения: https://unsplash.com/photos/l68Z6eF2peA. А вот код, который является MCVE

Кстати, я скачал и сохранил изображение в файле, который я назвал worldmap.jpg

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;

public class ScrolImg implements Runnable {
    private JFrame  frame;
/* Start 'Runnable' interface methods. */
    public void run() {
        showGui();
    }
/* End 'Runnable' interface methods. */
    private JScrollPane createMainPanel() {
        Icon ico = new ImageIcon("worldmap.jpg");
        JLabel label = new JLabel(ico);
        JScrollPane scrollPane = new JScrollPane(label);
        scrollPane.setPreferredSize(new Dimension(800, 600));
        return scrollPane;
    }

    private void showGui() {
        frame = new JFrame("ScrolImg");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(createMainPanel(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        ScrolImg instance = new ScrolImg();
        EventQueue.invokeLater(instance);
    }
}

Надеемся, этот код поможет вам завершить ваш проект.

...