- All Implemented Interfaces:
ImageObserver,MenuContainer,Serializable,Accessible
ImagePanel 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:
ImagePanel panel = ImagePanel.builder()
.image(bufferedImage)
.build();
// Or change the image reactively
panel.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:
ImagePanel panel = ImagePanel.builder()
.zoomDevice(ZoomDevice.MOUSE_BUTTON)
.build();
// Or change reactively
panel.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:
panel.zoomIncrement().set(0.3); // 30% incrementFor programmatic zoom control, set the zoom device to
ZoomDevice.NONE and use the zoom() Value:
panel.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 panel.
There are no lower or upper zoom level limits. Auto-Resize When auto-resize is enabled, the image automatically re-fits to the panel whenever the panel is resized:
ImagePanel panel = ImagePanel.builder()
.autoResize(true)
.build();
// Or toggle reactively
panel.autoResize().set(true);
When auto-resize is enabled, the image will reset to fit the panel 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
ImagePanel 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 panel, centered. The navigation image can
be enabled/disabled via the navigable() State:
ImagePanel panel = ImagePanel.builder()
.navigable(true)
.build();
// Or toggle reactively
panel.navigable().set(false);
The image can be dragged with the left mouse button when movable() is enabled (default):
panel.movable().set(false); // Disable draggingFor programmatic navigation, use
centerImage(Point) or centerImage(Point2D.Double).
Coordinate Conversion
The panel provides methods to convert between panel coordinates and image coordinates:
toImageCoordinates(Point)- Convert panel point to image coordinatestoPanelCoordinates(Point2D.Double)- Convert image point to panel coordinatesisWithinImage(Point)- Check if panel point is within image bounds
ImagePanel 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 panel.
Custom Overlays
The panel supports custom overlay painting via a BiConsumer<Graphics2D, ImagePanel>
that is called after the image is painted but before the navigation image. This is useful for drawing annotations, grids,
highlighting regions, or any custom graphics on top of the image:
ImagePanel imagePanel = ImagePanel.builder()
.image(image)
.overlay((g2d, panel) -> {
// Draw a red rectangle at image coordinates (100, 100)
Point2D.Double imagePoint = new Point2D.Double(100, 100);
Point2D.Double panelPoint = panel.toPanelCoordinates(imagePoint);
g2d.setColor(Color.RED);
g2d.drawRect((int) panelPoint.x, (int) panelPoint.y, 50, 50);
})
.build();
The overlay painter receives the Graphics2D context for drawing and the ImagePanel for accessing
coordinate conversion methods (toImageCoordinates(Point) and toPanelCoordinates(Point2D.Double))
and other panel state like scale().
The origin() Value provides access to the current image origin (top-left corner position in panel coordinates),
which can be used to programmatically position the image to make specific regions visible:
// Move image to show a specific region
panel.origin().set(new Point(-200, -100));
// React to origin changes
panel.origin().addConsumer(origin ->
System.out.println("Image origin: " + origin));
Example Usage
BufferedImage image = ImageIO.read(new File("photo.jpg"));
ImagePanel imagePanel = ImagePanel.builder()
.image(image)
.zoomDevice(ZoomDevice.MOUSE_WHEEL)
.autoResize(true)
.navigable(true)
.movable(true)
.overlay((g2d, panel) -> {
// Draw custom annotations
g2d.setColor(new Color(255, 0, 0, 128));
g2d.fillOval(100, 100, 50, 50);
})
.build();
// React to zoom changes
panel.zoom().addConsumer(zoom ->
System.out.println("Zoom level: " + zoom));
// Programmatic zoom
panel.zoom().set(1.5);
// Change image dynamically
panel.image().set(newImage);
// Position image to show specific region
panel.origin().set(new Point(-100, -50));
Originally based on http://today.java.net/pub/a/today/2007/03/27/navigable-image-panel.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 anImagePanelstatic interfaceControls the image displayed in anImagePanelstatic 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 forImagePanels.static final PropertyValue<ImagePanel.ZoomDevice> Specifies the defaultImagePanel.ZoomDeviceforImagePanels.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 panel on resize.static ImagePanel.Builderbuilder()voidcenterImage(Point2D.Double imagePoint) Centers the image on the given image pointvoidcenterImage(Point panelPoint) Centers the image on the given point on the panel, if it is within the image boundaries.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 useImagePanel.ImageValue.set(BufferedImage, String)booleanisWithinImage(Point panelPoint) Tests whether a given point in the panel falls within the image boundaries.movable()origin()Returns theValuecontrolling the image origin (the position of the image's top-left corner in panel coordinates).protected voidPaints the panel 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 paneldoublescale()toImageCoordinates(Point panelCoordinates) Converts this panel's point into the original image coordinatestoPanelCoordinates(Point2D.Double imageCoordinates) Converts the original image point into this panel's coordinateszoom()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 defaultImagePanel.ZoomDeviceforImagePanels.- Value type:
ImagePanel.ZoomDevice - Default value:
ImagePanel.ZoomDevice.NONE
- Value type:
-
AUTO_RESIZE
Specifies the default auto-resize behaviour forImagePanels.- 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 useImagePanel.ImageValue.set(BufferedImage, String)- Returns:
- the
ImagePanel.ImageValuecontrolling the image
-
zoomDevice
- Returns:
- the
Valuecontrolling the activeImagePanel.ZoomDevice
-
autoResize
Returns theStatecontrolling whether the image automatically re-fits to the panel on resize. When enabled, the image will reset to fit the panel dimensions whenever the panel 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 panel
-
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 panel coordinates). This can be used to programmatically position the image within the panel.The origin is typically negative when the image is zoomed in and larger than the panel, representing how much of the image is scrolled off the top-left edge of the panel. Example Usage
// Move image to show a region at image coordinates (500, 300) Point2D.Double imagePoint = new Point2D.Double(500, 300); Point2D.Double panelPoint = panel.toPanelCoordinates(imagePoint); // Center that point in the panel int centerX = panel.getWidth() / 2; int centerY = panel.getHeight() / 2; panel.origin().set(new Point( centerX - (int) panelPoint.x, centerY - (int) panelPoint.y)); // React to origin changes (e.g., when user drags the image) panel.origin().addConsumer(origin -> updateVisibleRegionIndicator(origin));- Returns:
- the
Valuecontrolling the image origin in panel coordinates
-
scale
public double scale()- Returns:
- the current scale
-
reset
public void reset()Resets the view so the image is centered and fits the panel -
toImageCoordinates
Converts this panel's point into the original image coordinates- Parameters:
panelCoordinates- the panel coordinates- Returns:
- the image coordinates
-
toPanelCoordinates
Converts the original image point into this panel's coordinates- Parameters:
imageCoordinates- the image coordinates- Returns:
- the panel coordinates
-
centerImage
Centers the image on the given image point- Parameters:
imagePoint- the image point on which to center the image
-
centerImage
Centers the image on the given point on the panel, if it is within the image boundaries.- Parameters:
panelPoint- the point on which to center the image
-
isWithinImage
Tests whether a given point in the panel falls within the image boundaries.- Parameters:
panelPoint- the point on the panel- Returns:
- true if an image is available and the given point is within the image
-
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
ImagePanel.Builderinstance
-
paintComponent
Paints the panel 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
-