Hi!

I'm trying to zoom in/out ImageIcon in JLabel. The problem is that after 2-3 zooming actions, the image quality becomes horrible. How could I solve this problem? Thanks!

private void doZoom(int scaleFactor) {
          Component[] c = SelectablePanel.getMainPanel().getComponents();
          for(int i = 0; i < c.length; i++) {
                if(c[i] instanceof JLabel) {                   
                    JLabel selectedLabel = (JLabel)c[i];
                    ImageIcon newIcon = (ImageIcon) selectedLabel.getIcon();
                    Image img = newIcon.getImage();
                    Image newImg = img.getScaledInstance(img.getWidth(null)+scaleFactor, img.getHeight(null)+scaleFactor, java.awt.Image.SCALE_SMOOTH);
                    selectedLabel.setPreferredSize(new Dimension(img.getWidth(null)+scaleFactor, img.getHeight(null)+scaleFactor));
                    newIcon = new ImageIcon(newImg);
                    selectedLabel.setIcon(newIcon);
                }
         }
         repaint();
}

Dani AI

Generated

A few focused things to check and a small, reliable approach to keep images sharp while zooming.

Repeatedly scaling the already-scaled raster image causes progressive quality loss — keep one unmodified master BufferedImage in memory and re-scale from that on every zoom. As suggested, a higher-resolution source (or vector graphics) is the only way to get good quality when zooming in a lot. , the black image you saw is usually caused by using the wrong constant when constructing a BufferedImage (the constructor needs a BufferedImage type like TYPE_INT_ARGB or TYPE_INT_RGB, not Image.SCALE_SMOOTH), and by setting rendering hints after you draw and dispose the Graphics2D.

Example: one-step high-quality scaling (scale from the original master image every time)

public static BufferedImage scaleTo(BufferedImage src, int w, int h) {
    int type = src.getColorModel().hasAlpha() ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
    BufferedImage dst = new BufferedImage(w, h, type);
    Graphics2D g = dst.createGraphics();
    g.setComposite(AlphaComposite.Src);
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.drawImage(src, 0, 0, w, h, null);
    g.dispose();
    return dst;
}

For large downscales prefer a multi-step approach (halve dimensions in steps) using bilinear for intermediate steps — it preserves detail better than one big jump. Always set hints and composite before drawing, dispose afterwards, and update the UI on the EDT. After replacing the icon call label.setIcon(new ImageIcon(scaled)) and then label.revalidate() (or panel.revalidate()), not just repaint().

If memory is a concern, cache the original master per-image (or use soft references), and consider AffineTransformOp with TYPE_BICUBIC for production-quality upscaling.

Recommended Answers

All 2 Replies

How could I solve this problem?

By using a high resolution image? If you would try to zoom in on a 128 * 128 image, it would obviously look bad.

Two options AFAICT:
* Use a new image as the image source every time a zoom is done instead of scaling the same low resolution image
* Use vector graphics instead of raster graphics which provide infinite zoom capabilities

Hi!

Thanks. I improved my code a little bit. However, now a black image is returned instead of rescaled one. (I'm using two images). The problem is with the line newIcon = new ImageIcon(resizeImageHintJpg) . How could this problem be solved?

...
            BufferedImage originalImage;
            try {
                Component[] c = MainClass.getSelectablePanel().getComponents();
                for(int i = 0; i < c.length; i++) {
                    if(c[i] instanceof JLabel) {
                        JLabel selectedLabel = (JLabel)c[i];
                        ImageIcon newIcon = (ImageIcon) selectedLabel.getIcon();
                        Image img = newIcon.getImage();
                        originalImage = new BufferedImage(img.getWidth(null), img.getHeight(null), java.awt.Image.SCALE_SMOOTH);
                        int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
                        BufferedImage resizeImageHintJpg = resizeImageWithHint(originalImage, type);
                        newIcon = new ImageIcon(resizeImageHintJpg);
                        selectedLabel.setIcon(newIcon);
                    }
                }
                repaint();
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            }
..

    private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type){

	BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
	Graphics2D g = resizedImage.createGraphics();
	g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
	g.dispose();
	g.setComposite(AlphaComposite.Src);

	g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
	RenderingHints.VALUE_INTERPOLATION_BILINEAR);
	g.setRenderingHint(RenderingHints.KEY_RENDERING,
	RenderingHints.VALUE_RENDER_QUALITY);
	g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
	RenderingHints.VALUE_ANTIALIAS_ON);

	return resizedImage;
    }
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.