The code I have uses the MouseAdapter to listen to the user, to "draw" a field around the area of ββthe image that they would like to enlarge, and calculate the ratio of the window to the image. Then it resizes the image to the calculated one. This part works.
The problem I am facing is that the JScrollPane view looks as if it is still in the same upper left position after resizing the image. I tried several methods that seemed to come close to the result I want, but not quite.
This is a listener who finds the scaling factor and sets the position:
import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.Graphics; import java.awt.Point; import javax.swing.JScrollPane; import javax.swing.JViewport; import javax.swing.JComponent; public class DynamicZoom extends MouseAdapter { private Point start; private Point end; private double zoom = 1.0; private JScrollPane pane; private JViewport port; public void mousePressed(MouseEvent e) { if(e.getButton() == MouseEvent.BUTTON1) { this.pane = (JScrollPane)e.getSource(); this.port = pane.getViewport(); start = e.getPoint(); } } public void mouseReleased(MouseEvent e) { if(this.pane != null) { Point curr = this.port.getViewPosition(); end = e.getPoint(); ImageComponent canvas = (ImageComponent)this.port.getView(); zoom = canvas.getScale(); double factor = 0.0; double selectedWidth = Math.abs(end.getX() - start.getX()); double selectedHeight = Math.abs(end.getY() - start.getY()); if(selectedWidth > selectedHeight) factor = this.port.getWidth() / selectedWidth; else factor = this.port.getHeight() / selectedHeight; zoom *= factor; int x = (int)((start.x+curr.x)*zoom); int y = (int)((start.y+curr.y)*zoom); Point point = new Point(x, y); ((ImageComponent)(this.port.getView())).setScale(zoom); ResizeViewport.resize(pane); this.port.setViewPosition(point); } } public void mouseDragged(MouseEvent e) { if(this.pane != null) { Graphics g = this.port.getGraphics(); int width = this.start.x - e.getX(); int height = this.start.y - e.getY(); int w = Math.abs( width ); int h = Math.abs( height ); int x = width < 0 ? this.start.x : e.getX(); int y = height < 0 ? this.start.y : e.getY(); g.drawRect(x, y, w, h); this.port.repaint(); } }
}
This is an ImageComponent that resizes and displays the image:
import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import javax.swing.JComponent; public class ImageComponent extends JComponent { private static final long serialVersionUID = 1975488835382044371L; private BufferedImage img = null; private double scale = 0.0; public ImageComponent() {} public ImageComponent(BufferedImage img) { this.displayPage(img); } @Override public void paint(Graphics g) { Graphics2D g2 = ((Graphics2D)g); if(this.img != null) { int width = (int)(this.img.getWidth() * this.scale); int height = (int)(this.img.getHeight() * this.scale); this.setPreferredSize(new Dimension(width, height)); g2.drawImage(this.img, 0, 0, width, height, null, null); g2.dispose(); } } public void displayPage(BufferedImage pic) { if(img != null) { this.img = pic; } } public BufferedImage getPage() { return this.img; } public void setScale(double ratio) { if(ratio > .04) { this.scale = ratio; this.repaint(); } } public double getScale() { return this.scale; } }
ResizeViewport causes the viewport to display the entire ImageComponent when it is scaled, because otherwise it will crop the image to the size that was previously:
import java.awt.Dimension; import javax.swing.JScrollPane; public class ResizeViewport { public static void resize(JScrollPane scroll) { int vw = scroll.getWidth()-scroll.getVerticalScrollBar().getWidth(); int vh = scroll.getHeight()-scroll.getHorizontalScrollBar().getHeight(); scroll.getViewport().setViewSize(new Dimension(vw, vh)); } }
java image zoom jscrollpane
Daniel
source share