- All Implemented Interfaces:
ImageObserver,MenuContainer,Serializable,Accessible
ImagePane is a lightweight container displaying an image that can be zoomed in and out
and panned with ease and simplicity, using adaptive rendering for high quality display and satisfactory performance.
All configuration is done via an Observable/Value-based API, allowing reactive UI updates. Image
An image is loaded via the builder or controlled via the image() Value:
ImagePane pane = ImagePane.builder()
.image(bufferedImage)
.build();
// Or change the image reactively
pane.image().set(newImage);
When an image is set, it is initially painted centered in the component at the largest possible size,
fully visible, with its aspect ratio preserved. This is defined as 100% of the image size and
its corresponding zoom level is 1.0.
Zooming
Zooming can be controlled interactively using either the mouse scroll wheel (default) or mouse buttons,
or programmatically via the zoom() Value. To change the zoom device:
ImagePane pane = ImagePane.builder()
.zoomDevice(ZoomDevice.MOUSE_BUTTON)
.build();
// Or change reactively
pane.zoomDevice().set(ZoomDevice.NONE);
When using ZoomDevice.MOUSE_BUTTON, the left mouse button toggles between zooming in and out modes,
and the right button zooms by one increment (default 20%). The zoom increment can be controlled:
pane.zoomIncrement().set(0.3); // 30% incrementFor programmatic zoom control, set the zoom device to
ZoomDevice.NONE and use the zoom() Value:
pane.zoom().set(2.0); // Zoom to 200%Mouse wheel zooming is always around the point the mouse pointer is currently at, ensuring that the area being zoomed into remains visible. Programmatic zooming via
zoom().set() zooms
around the center of the pane.
There are no lower or upper zoom level limits. Auto-Resize When auto-resize is enabled, the image automatically re-fits to the pane whenever the pane is resized:
ImagePane pane = ImagePane.builder()
.autoResize(true)
.build();
// Or toggle reactively
pane.autoResize().set(true);
When auto-resize is enabled, the image will reset to fit the pane dimensions on every resize event,
regardless of the current zoom level. This is useful for responsive layouts where you want the image
to always fill the available space.
Navigation
ImagePane does not use scroll bars for navigation, but can optionally display a navigation image
in the upper left corner. The navigation image is a small replica of the main image. Clicking on any point
of the navigation image displays that part of the image in the pane, centered. The navigation image can
be enabled/disabled via the navigable() State:
ImagePane pane = ImagePane.builder()
.navigable(true)
.build();
// Or toggle reactively
pane.navigable().set(false);
The image can be dragged with the left mouse button when movable() is enabled (default):
pane.movable().set(false); // Disable draggingFor programmatic navigation, use
center().
Coordinate Conversion
The pane provides coordinate translation between pane and image coordinate spaces via coordinates().
Use this for overlay drawing or when working with mouse events on the image.
Rendering
ImagePane uses Nearest Neighbor interpolation for image rendering (default in Java).
When the scaled image becomes larger than the original image, Bilinear interpolation is applied,
but only to the part of the image displayed in the pane.
Custom Overlays
The pane supports custom overlay painting for drawing annotations, grids, highlights, or any custom
graphics on top of the image. See ImagePane.Builder.overlay(BiConsumer) for details.
The origin() Value provides access to the current image origin (top-left corner position in pane coordinates),
which can be used to programmatically position the image to make specific regions visible:
// Move image to show a specific region
pane.origin().set(new Point(-200, -100));
// React to origin changes
pane.origin().addConsumer(origin ->
System.out.println("Image origin: " + origin));
Example Usage
BufferedImage image = ImageIO.read(new File("photo.jpg"));
ImagePane imagePane = ImagePane.builder()
.image(image)
.zoomDevice(ZoomDevice.MOUSE_WHEEL)
.autoResize(true)
.navigable(true)
.movable(true)
.build();
// Coordinate translation
Point2D.Double imagePoint = pane.coordinates().toImage(mouseEvent.getPoint());
// Center image on a specific point
pane.center().onImage(new Point2D.Double(500, 300));
// Programmatic zoom
pane.zoom().set(1.5);
// React to zoom changes
pane.zoom().addConsumer(zoom ->
System.out.println("Zoom level: " + zoom));
Originally based on http://today.java.net/pub/a/today/2007/03/27/navigable-image-pane.html Included with express permission from the author, 2019.
- Author:
- Slav Boleslawski, Björn Darri Sigurðsson
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceBuilds anImagePanefinal classCenters the imagefinal classProvides coordinate translations.static interfaceControls the image displayed in anImagePanestatic enumDefines zoom devices.Nested classes/interfaces inherited from class javax.swing.JPanel
JPanel.AccessibleJPanelNested classes/interfaces inherited from class javax.swing.JComponent
JComponent.AccessibleJComponentNested classes/interfaces inherited from class java.awt.Container
Container.AccessibleAWTContainerNested classes/interfaces inherited from class java.awt.Component
Component.AccessibleAWTComponent, Component.BaselineResizeBehavior, Component.BltBufferStrategy, Component.FlipBufferStrategy -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final PropertyValue<Boolean> Specifies the default auto-resize behaviour forImagePanes.static final PropertyValue<ImagePane.ZoomDevice> Specifies the defaultImagePane.ZoomDeviceforImagePanes.Fields inherited from class javax.swing.JComponent
listenerList, TOOL_TIP_TEXT_KEY, ui, UNDEFINED_CONDITION, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, WHEN_FOCUSED, WHEN_IN_FOCUSED_WINDOWFields inherited from class java.awt.Component
accessibleContext, BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENTFields inherited from interface java.awt.image.ImageObserver
ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, WIDTH -
Method Summary
Modifier and TypeMethodDescriptionReturns theStatecontrolling whether the image automatically re-fits to the pane on resize.static ImagePane.Builderbuilder()center()image()Note that setting the image via this value without specifying the format does not populate the associated byte[]ComponentValue, for that to happen you must useImagePane.ImageValue.set(BufferedImage, String)movable()origin()Returns theValuecontrolling the image origin (the position of the image's top-left corner in pane coordinates).protected voidPaints the pane and its image at the current zoom level, location, and interpolation method dependent on the image scale.static BufferedImageReads an image from the given pathvoidreset()Resets the view so the image is centered and fits the panedoublescale()zoom()Methods inherited from class javax.swing.JPanel
getAccessibleContext, getUI, getUIClassID, paramString, setUI, updateUIMethods inherited from class javax.swing.JComponent
addAncestorListener, addNotify, addVetoableChangeListener, computeVisibleRect, contains, createToolTip, disable, enable, firePropertyChange, firePropertyChange, firePropertyChange, fireVetoableChange, getActionForKeyStroke, getActionMap, getAlignmentX, getAlignmentY, getAncestorListeners, getAutoscrolls, getBaseline, getBaselineResizeBehavior, getBorder, getBounds, getClientProperty, getComponentGraphics, getComponentPopupMenu, getConditionForKeyStroke, getDebugGraphicsOptions, getDefaultLocale, getFontMetrics, getGraphics, getHeight, getInheritsPopupMenu, getInputMap, getInputMap, getInputVerifier, getInsets, getInsets, getListeners, getLocation, getMaximumSize, getMinimumSize, getNextFocusableComponent, getPopupLocation, getPreferredSize, getRegisteredKeyStrokes, getRootPane, getSize, getToolTipLocation, getToolTipText, getToolTipText, getTopLevelAncestor, getTransferHandler, getVerifyInputWhenFocusTarget, getVetoableChangeListeners, getVisibleRect, getWidth, getX, getY, grabFocus, hide, isDoubleBuffered, isLightweightComponent, isManagingFocus, isOpaque, isOptimizedDrawingEnabled, isPaintingForPrint, isPaintingOrigin, isPaintingTile, isRequestFocusEnabled, isValidateRoot, paint, paintBorder, paintChildren, paintImmediately, paintImmediately, print, printAll, printBorder, printChildren, printComponent, processComponentKeyEvent, processKeyBinding, processKeyEvent, processMouseEvent, processMouseMotionEvent, putClientProperty, registerKeyboardAction, registerKeyboardAction, removeAncestorListener, removeNotify, removeVetoableChangeListener, repaint, repaint, requestDefaultFocus, requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow, resetKeyboardActions, reshape, revalidate, scrollRectToVisible, setActionMap, setAlignmentX, setAlignmentY, setAutoscrolls, setBackground, setBorder, setComponentPopupMenu, setDebugGraphicsOptions, setDefaultLocale, setDoubleBuffered, setEnabled, setFocusTraversalKeys, setFont, setForeground, setInheritsPopupMenu, setInputMap, setInputVerifier, setMaximumSize, setMinimumSize, setNextFocusableComponent, setOpaque, setPreferredSize, setRequestFocusEnabled, setToolTipText, setTransferHandler, setUI, setVerifyInputWhenFocusTarget, setVisible, unregisterKeyboardAction, updateMethods inherited from class java.awt.Container
add, add, add, add, add, addContainerListener, addImpl, addPropertyChangeListener, addPropertyChangeListener, applyComponentOrientation, areFocusTraversalKeysSet, countComponents, deliverEvent, doLayout, findComponentAt, findComponentAt, getComponent, getComponentAt, getComponentAt, getComponentCount, getComponents, getComponentZOrder, getContainerListeners, getFocusTraversalKeys, getFocusTraversalPolicy, getLayout, getMousePosition, insets, invalidate, isAncestorOf, isFocusCycleRoot, isFocusCycleRoot, isFocusTraversalPolicyProvider, isFocusTraversalPolicySet, layout, list, list, locate, minimumSize, paintComponents, preferredSize, printComponents, processContainerEvent, processEvent, remove, remove, removeAll, removeContainerListener, setComponentZOrder, setFocusCycleRoot, setFocusTraversalPolicy, setFocusTraversalPolicyProvider, setLayout, transferFocusDownCycle, validate, validateTreeMethods inherited from class java.awt.Component
action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, bounds, checkImage, checkImage, coalesceEvents, contains, createImage, createImage, createVolatileImage, createVolatileImage, disableEvents, dispatchEvent, enable, enableEvents, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, getBackground, getBounds, getColorModel, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusCycleRootAncestor, getFocusListeners, getFocusTraversalKeysEnabled, getFont, getForeground, getGraphicsConfiguration, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputContext, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getLocale, getLocation, getLocationOnScreen, getMouseListeners, getMouseMotionListeners, getMousePosition, getMouseWheelListeners, getName, getParent, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getToolkit, getTreeLock, gotFocus, handleEvent, hasFocus, imageUpdate, inside, isBackgroundSet, isCursorSet, isDisplayable, isEnabled, isFocusable, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isMaximumSizeSet, isMinimumSizeSet, isPreferredSizeSet, isShowing, isValid, isVisible, keyDown, keyUp, list, list, list, location, lostFocus, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paintAll, postEvent, prepareImage, prepareImage, processComponentEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processMouseWheelEvent, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, requestFocus, requestFocus, requestFocusInWindow, resize, resize, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setFocusable, setFocusTraversalKeysEnabled, setIgnoreRepaint, setLocale, setLocation, setLocation, setMixingCutoutShape, setName, setSize, setSize, show, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycle
-
Field Details
-
ZOOM_DEVICE
Specifies the defaultImagePane.ZoomDeviceforImagePanes.- Value type:
ImagePane.ZoomDevice - Default value:
ImagePane.ZoomDevice.NONE
- Value type:
-
AUTO_RESIZE
Specifies the default auto-resize behaviour forImagePanes.- Value type: Boolean
- Default value: false
-
-
Method Details
-
image
Note that setting the image via this value without specifying the format does not populate the associated byte[]ComponentValue, for that to happen you must useImagePane.ImageValue.set(BufferedImage, String)- Returns:
- the
ImagePane.ImageValuecontrolling the image
-
zoomDevice
- Returns:
- the
Valuecontrolling the activeImagePane.ZoomDevice
-
autoResize
Returns theStatecontrolling whether the image automatically re-fits to the pane on resize. When enabled, the image will reset to fit the pane dimensions whenever the pane is resized, regardless of the current zoom level.- Returns:
- the
Statecontrolling the auto-resize behavior
-
movable
- Returns:
- the
Statecontrolling whether the image is movable within the pane
-
zoomIncrement
- Returns:
- the
Valuecontrolling the zoom increment
-
zoom
- Returns:
- the
Valuecontrolling the current zoom level
-
origin
Returns theValuecontrolling the image origin (the position of the image's top-left corner in pane coordinates). This can be used to programmatically position the image within the pane.The origin is typically negative when the image is zoomed in and larger than the pane, representing how much of the image is scrolled off the top-left edge of the pane. Example Usage
// Move image to show a region at image coordinates (500, 300) Point2D.Double imagePoint = new Point2D.Double(500, 300); Point2D.Double panePoint = pane.toPaneCoordinates(imagePoint); // Center that point in the pane int centerX = pane.getWidth() / 2; int centerY = pane.getHeight() / 2; pane.origin().set(new Point( centerX - (int) panePoint.x, centerY - (int) panePoint.y)); // React to origin changes (e.g., when user drags the image) pane.origin().addConsumer(origin -> updateVisibleRegionIndicator(origin));- Returns:
- the
Valuecontrolling the image origin in pane coordinates
-
scale
public double scale()- Returns:
- the current scale
-
reset
public void reset()Resets the view so the image is centered and fits the pane -
coordinates
- Returns:
- the coordinate translator
-
center
- Returns:
- image centerer
-
readImage
Reads an image from the given path- Parameters:
imagePath- the path, either file or http- Returns:
- the loaded image
- Throws:
IOException- in case of an exception
-
builder
- Returns:
- a new
ImagePane.Builderinstance
-
paintComponent
Paints the pane and its image at the current zoom level, location, and interpolation method dependent on the image scale.- Overrides:
paintComponentin classJComponent- Parameters:
g- theGraphicscontext for painting
-