package testIDE;
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import Utils.MyJFrame;
public class ExampleClass {
public static void main(String[] args) {
JFrame ballRotate = new BallRotate();
}
}
class BallRotate extends MyJFrame {
ArrayList<Integer> degree = new ArrayList<Integer>();
BufferedImage backGroundImage = getBufferedImage("testIDE/buttonDefaultImage.jpg");
JLabel backGroundLabel = new JLabel(new ImageIcon(backGroundImage));
BufferedImage footballImage = getBufferedImage("testIDE/Tennis_Ball.png");
int x = 0;
public BallRotate() {
footballImage=getScaledImage(250, 250, footballImage);
BufferedImage rotatedImage = footballImage;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridBagLayout());
setLabel();
add(backGroundLabel);
pack();
centeringWindow();
setVisible(true);
setArray();
while (true) {
setDelay(60);
rotatedImage = rotateImage(rotatedImage, x);
setMyFuckingLabel(rotatedImage);
x += 10;
if (x == 10000) {
break;
}
}
}
private void setArray() {
for (int i = 0; i <= 360; i += 40) {
degree.add(i);
}
}
private void setLabel() {
JPanel footBallPanel = new JPanel(new BorderLayout());
JLabel footBallLabel = new JLabel(new ImageIcon(footballImage));
footBallPanel.add(footBallLabel);
borderingJPanel(footBallPanel, null, null);
backGroundLabel.setLayout(new GridBagLayout());
backGroundLabel.add(footBallPanel);
}
private BufferedImage rotateImage(BufferedImage buffImage, int degree) {
BufferedImage rotatedImage = null;
AffineTransform affineTransform = AffineTransform.getRotateInstance(
Math.toRadians(15*Math.PI), buffImage.getWidth() / 2,
buffImage.getHeight() / 2);
System.out.println(degree*Math.toRadians(1));
rotatedImage = new BufferedImage(buffImage.getWidth(),
buffImage.getHeight(), buffImage.getType());
Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
g.setTransform(affineTransform);
g.drawImage(buffImage, 0, 0, null);
return rotatedImage;
}
public void setMyLabel(BufferedImage rotatedBuffImage) {
JLabel backgroundlabel = (JLabel) getContentPane().getComponent(0);
JPanel footBallPanel = (JPanel) backgroundlabel.getComponent(0);
JLabel footBallLabel = (JLabel) footBallPanel.getComponent(0);
footBallLabel.setIcon(new ImageIcon(rotatedBuffImage));
}
}
As you can see, my rotating tennis ball looses his form and his colouring. It seems to be that the colours are rotating also.
Why? And is there a way to prevent this? Ive posted the code which generated the dialog above.
Thanks for any help.
So a raft of issues...
Scaling an image in a single step is never a good idea (unless you only scaling by 50%). Java also isn't particular good at it. There are tricks you can employee, like using a multi-step scale (demonstrated within the example) or use an external library like imgscalr. See The Perils of Image.getScaledInstance() for more details.
You should avoid apply effects to the same image multiply times, this simply compounds the changes and will reduce the quality of the image. Instead, maintain a master image as close to the original as you can and use it, so you're always starting from the same starting point.
Swing is not thread safe. This means three things. First, you should never do anything within the context of the Event Dispatching Thread that might block it, like infinite loops. Second, you should only ever change the state of UI components from within the context of the EDT and third, you should make sure you are creating your UIs from within the context of the EDT. See Concurrency in Swing and Initial Threads for more details...
Any thing other then a straight horizontal or vertical line is going to look pretty...ordinary under the default rendering settings. You're going to need to supply some RenderingHints to enhance the result
This then raises the question of how do you do animation in Swing? Well, you have two basic options, you can use a Thread of some kind, which requires you to manually synchronise updates back to the EDT or you can use a Swing javax.swing.Timer, which allows you to schedule call backs at regular intervals which are triggered within the context of the EDT. Take a look at How to use Swing Timers for more details...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class BallRotate {
public static void main(String[] args) {
new BallRotate();
}
public BallRotate() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private JLabel ball;
private BufferedImage rotatedImage;
private float angle = 0;
private float delta = 5;
public TestPane() {
setLayout(new GridBagLayout());
try {
master = ImageIO.read(getClass().getResource("/Ball.png"));
master = getScaledInstanceToFit(master, new Dimension(250, 250));
} catch (IOException ex) {
ex.printStackTrace();
}
ImageIcon icon = new ImageIcon(getRotatedImage(0));
ball = new JLabel(icon);
add(ball);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angle += delta;
// ball.setIcon(new ImageIcon(getRotatedImage(delta)));
getRotatedImage(angle);
ball.repaint();
System.out.println(angle);
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
timer.start();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected BufferedImage getRotatedImage(float degree) {
if (rotatedImage == null) {
rotatedImage = new BufferedImage(master.getWidth(),
master.getHeight(), BufferedImage.TYPE_INT_ARGB);
}
AffineTransform affineTransform = AffineTransform.getRotateInstance(
Math.toRadians(degree), rotatedImage.getWidth() / 2,
rotatedImage.getHeight() / 2);
Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
g.setBackground(new Color(255, 255, 255, 0));
g.clearRect(0, 0, rotatedImage.getWidth(), rotatedImage.getHeight());
g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g.setTransform(affineTransform);
g.drawImage(master, 0, 0, null);
g.dispose();
return rotatedImage;
}
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
// System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
if (dScaleFactor < 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
// if (w <= 0) w = 1;
// if (h <= 0) h = 1;
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
return (double) iTargetSize / (double) iMasterSize;
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactorToFit(BufferedImage img, Dimension size) {
double dScale = 1;
if (img != null) {
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
dScale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);
}
return dScale;
}
public static BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {
double scaleFactor = getScaleFactorToFit(img, size);
return getScaledInstance(img, scaleFactor);
}
}
Related
How to resize an image with JLabel resizing in an internal frame?
I tried some code that I found on the Internet like:
public static BufferedImage resize(Image image, int width, int height) {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(image, 0, 0, width, height, null);
g2d.dispose();
return bi;
or
getScaledInstance(l.getWidth(), -1, Image.SCALE_SMOOTH);
the code's result
But it only makes the image smaller.
Is there a way to resize the image with the JLabel and JInternalFrame? Any help is welcome :)
Scaling an image, well, is not simple. Take a look at:
Java: maintaining aspect ratio of JPanel background image
Scale the ImageIcon automatically to label size
Quality of Image after resize very low -- Java
Scaling can also be expensive, so you'd probably want someway to reduce the number of attempts (as a window been re-resized will be bombarded with a large number of sizing events).
The overall method is the same regardless if your using a JFrame, JPanel or JInternalFrame.
You need some way to monitor for the size changes and some way to determine when it might be a suitable time to scale the image. The following example make use of a ComponentListener and non-repeating Swing Timer. This allows us the ability to schedule a task to be executed in the future, but which can be cancelled if we need to.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
BufferedImage image = ImageIO.read(getClass().getResource("/images/happy.png"));
JInternalFrame internalFrame = new JInternalFrame("Test", true, true, true, true);
internalFrame.add(new ImagePane(image));
internalFrame.pack();
internalFrame.setVisible(true);
JDesktopPane desktopPane = new JDesktopPane();
desktopPane.add(internalFrame);
JFrame frame = new JFrame();
frame.add(desktopPane);
frame.setSize(new Dimension(800, 800));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class ImagePane extends JPanel {
private Timer resizeTimer;
private BufferedImage masterImage;
private JLabel label;
private Scaler scaler;
public ImagePane(BufferedImage masterImage) {
this.masterImage = masterImage;
label = new JLabel(new ImageIcon(masterImage));
scaler = new Scaler(masterImage);
resizeTimer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(new ImageIcon(scaler.getScaledInstanceToFill(getSize())));
}
});
resizeTimer.setRepeats(false);
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
resizeTimer.restart();
}
});
setLayout(new BorderLayout());
add(label);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class Scaler {
private BufferedImage master;
private Dimension masterSize;
private Map<RenderingHints.Key, Object> renderingHints = new HashMap<>();
public Scaler(BufferedImage master) {
this.master = master;
masterSize = new Dimension(master.getWidth(), master.getHeight());
renderingHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
renderingHints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
renderingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
renderingHints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
renderingHints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
renderingHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
renderingHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
renderingHints.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
}
public BufferedImage getScaledInstanceToFit(Dimension size) {
return getScaledInstance(getScaleFactorToFit(size));
}
public BufferedImage getScaledInstanceToFill(Dimension size) {
return getScaledInstance(getScaleFactorToFill(size));
}
protected double getScaleFactor(int masterSize, int targetSize) {
return (double) targetSize / (double) masterSize;
}
protected double getScaleFactorToFit(Dimension toFit) {
double dScaleWidth = getScaleFactor(masterSize.width, toFit.width);
double dScaleHeight = getScaleFactor(masterSize.height, toFit.height);
return Math.min(dScaleHeight, dScaleWidth);
}
protected double getScaleFactorToFill(Dimension targetSize) {
double dScaleWidth = getScaleFactor(masterSize.width, targetSize.width);
double dScaleHeight = getScaleFactor(masterSize.height, targetSize.height);
return Math.max(dScaleHeight, dScaleWidth);
}
protected BufferedImage getScaledInstance(double dScaleFactor) {
BufferedImage imgScale = master;
int targetWidth = (int) Math.round(masterSize.getWidth() * dScaleFactor);
int targetHeight = (int) Math.round(masterSize.getHeight() * dScaleFactor);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(targetWidth, targetHeight);
} else {
imgScale = getScaledUpInstance(targetWidth, targetHeight);
}
return imgScale;
}
protected BufferedImage getScaledDownInstance(
int targetWidth,
int targetHeight) {
int type = (master.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaled = master;
if (targetHeight > 0 || targetWidth > 0) {
int width = master.getWidth();
int height = master.getHeight();
do {
if (width > targetWidth) {
width /= 2;
if (width < targetWidth) {
width = targetWidth;
}
}
if (height > targetHeight) {
height /= 2;
if (height < targetHeight) {
height = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(width, 1), Math.max(height, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHints(renderingHints);
g2.drawImage(scaled, 0, 0, width, height, null);
g2.dispose();
scaled = tmp;
} while (width != targetWidth || height != targetHeight);
} else {
scaled = new BufferedImage(1, 1, type);
}
return scaled;
}
protected BufferedImage getScaledUpInstance(
int targetWidth,
int targetHeight) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) master;
int width = master.getWidth();
int height = master.getHeight();
do {
if (width < targetWidth) {
width *= 2;
if (width > targetWidth) {
width = targetWidth;
}
}
if (height < targetHeight) {
height *= 2;
if (height > targetHeight) {
height = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(width, height, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHints(renderingHints);
g2.drawImage(ret, 0, 0, width, height, null);
g2.dispose();
ret = tmp;
} while (width != targetWidth || height != targetHeight);
return ret;
}
}
}
Also, JLabel is actually irrelevant to your problem and I'd probably use a custom painting workflow to render the scaled image, but that's me.
Hi guys I have a problem with Images drawn in a JPanel.There is no problem when the images are drawn to the panel. The Problemm occurn when I scroll up or down the image. The part of the image that was not seen in the viewport is painted white when return to that part again.
I added a BufferedImage in a JPanel. I can also resize the image using AffineTransform. The problem is when I added a JScollPane to my image, whenever I scroll up or down the scrollpane some part of the image disappears ..
I also tried using drawRenderedImage it did solve the problem about the scroll but it messed up other functions.
this is the best concise code I can make;
package convert;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class ZoomTest {
public static void main(String[] args) {
ImagePanel panel = new ImagePanel();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(panel));
f.setSize(1200, 1200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ImagePanel extends JPanel {
BufferedImage image;
double scale;
public ImagePanel() {
loadImage();
scale = .38;
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
int rotation = e.getWheelRotation();
if (rotation < 0) {
scale -= .05;
} else {
scale += .05;
}
if (scale < 0) {
scale = 0;
}
revalidate();
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
double x = (getWidth() - scale * image.getWidth()) / 2;
double y = (getHeight() - scale * image.getHeight()) / 2;
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.scale(scale, scale);
g2.setTransform(at);
g2.drawImage(image, 0, 0, null);
}
public Dimension getPreferredSize() {
int w = (int) (scale * image.getWidth());
int h = (int) (scale * image.getHeight());
return new Dimension(w, h);
}
private void loadImage() {
String fileName = "c:\\users\\john ebarita\\downloads\\lorem-ipsum-1.jpg";
try {
image = ImageIO.read(new File(fileName));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Take a look at Graphics2D#drawImage(Image, AffineTransform, ImageObserver). May be it helps.
package convert;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class ZoomTest2 {
public static void main(String[] args) {
ImagePanel panel = new ImagePanel();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(panel));
f.setSize(1200, 1200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ImagePanel extends JPanel {
BufferedImage image;
double scale;
public ImagePanel() {
loadImage();
scale = .38;
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
int rotation = e.getWheelRotation();
if (rotation < 0) {
scale -= .05;
} else {
scale += .05;
}
if (scale < 0) {
scale = 0;
}
revalidate();
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
double x = (getWidth() - scale * image.getWidth()) / 2;
double y = (getHeight() - scale * image.getHeight()) / 2;
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.scale(scale, scale);
// g2.setTransform(at);
// g2.drawImage(image, 0, 0, this);
g2.drawImage(image, at, this);
// or:
// AffineTransform atf = g2.getTransform();
// atf.concatenate(at);
// g2.setTransform(atf);
// g2.drawImage(image, 0, 0, this);
g2.dispose();
}
public Dimension getPreferredSize() {
int w = (int)(scale * image.getWidth());
int h = (int)(scale * image.getHeight());
return new Dimension(w, h);
}
private void loadImage() {
String fileName = "aaa.png";
try {
image = ImageIO.read(new File(fileName));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is solution for your problem. I had also a bad luck with custom painting, so my solution is directly update the image on mouse wheel and set it to a label.
import java.awt.Image;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
public class ZoomTest {
public static void main(String[] args) {
ImagePanel panel = new ImagePanel();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(panel));
f.setSize(1000, 1000);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ImagePanel extends JLabel {
BufferedImage image;
double scale;
public ImagePanel() {
setHorizontalAlignment(SwingConstants.CENTER);
loadImage();
scale = .38;
updateImage();
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
int rotation = e.getWheelRotation();
if (rotation < 0) {
scale -= .05;
} else {
scale += .05;
}
if (scale < 0) {
scale = 0;
}
updateImage();
revalidate();
repaint();
}
});
}
private void updateImage() {
int w = (int) (scale * image.getWidth());
int h = (int) (scale * image.getHeight());
setIcon(new ImageIcon(image.getScaledInstance(w, h, Image.SCALE_SMOOTH)));
}
private void loadImage() {
String fileName = "c:\\users\\john ebarita\\downloads\\lorem-ipsum-1.jpg";
try {
image = ImageIO.read(new File(fileName));
} catch (Exception e) {
e.printStackTrace();
}
}
}
I'm trying to make my own, very inefficient "image copier". I'm doing it by reading the pixels from the original image on to an array and then resetting those same pixels in my default BufferedImage. And then repaint the frame. Row by row.
I'm trying to repaint the frame every after each row of pixels has been stored in the array. But the frame only gets updated once; when it finishes storing the pixels.
My code is all over the place, and I'm probably doing a lot of stuff wrong. This is for an assignment and I've been going at it for a while now and would really appreciate some help.
Here is my code:
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.*;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class pixelReloc extends JComponent {
static BufferedImage image,newImg;
static JFrame frame;
public void initialize() {
int width = getSize().width;
int height = getSize().height;
int pixels[];
int index = 0;
int j=0,i=0;
File f = new File("/path/to/file/images/shrek4life.jpg");
try{
image = ImageIO.read(f);
}catch(IOException e){}
System.out.println("checkpoint 1");
image = createResizedCopy(image,500,500,true);
newImg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
pixels = new int[(image.getWidth()) * (image.getHeight())];
System.out.println("checkpoint 2");
for(i= 0; i < newImg.getWidth(); i++){
for(j = 0; j < newImg.getHeight(); j++){
//get the rgb color of the old image
Color c = new Color(image.getRGB(i, j));
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
pixels[index++] = (r<<16) | (g<<8) | b;
}
newImg.setRGB(0, 0, i, j, pixels, 0, 0);
frame.getContentPane().validate();
frame.getContentPane().repaint();
}
System.out.println("checkpoint 4");
//image.setRGB(0, 0, width, height, data, 0, width);
}
public BufferedImage createResizedCopy(BufferedImage originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha)
{
System.out.println("resizing...");
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha) {
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
public void paint(Graphics g) {
if (image == null)
initialize();
g.drawImage(newImg, 0, 0, this);
}
public static void main(String[] args) {
frame = new JFrame("P I X E L S");
frame.getContentPane().add(new pixelReloc ());
frame.setSize(500, 500);
frame.setLocation(100, 100);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.setVisible(true);
}
}
Here is the picture I'm reading the pixels from:
and this is how it's coming out:
The program doesn't give any errors or anything.
The basic answer to your question is, you're blocking the Event Dispatching Thread.
Swing is both single threaded and NOT thread safe. This means you can't run long running or blocking operations from within the EDT AND you should't not update the UI or some state the UI depends on from outside the EDT.
I recommend that you start by having a look at Concurrency in Swing.
This leaves with three basic options:
Use another Thread. This is problematic as you need to ensure that any state that the UI relies on is only updated from within the context of the EDT
Use a SwingWorker. This is basically the previous option, but with built in management which allows you to publish updates which are process'ed on the EDT
Use a Swing Timer. In your case, this is probably not the best solution, but it is the simplest.
For example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PixelReloc());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Pixel {
private int x, y;
private int color;
public Pixel(int x, int y, int color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getColor() {
return color;
}
}
public class PixelReloc extends JComponent {
private BufferedImage image;
private BufferedImage newImg;
public PixelReloc() {
SwingWorker<Integer[], List<Pixel>> worker = new SwingWorker<Integer[], List<Pixel>>() {
Integer pixels[];
#Override
protected Integer[] doInBackground() throws Exception {
pixels = new Integer[image.getWidth() * image.getHeight()];
int index = 0;
List<Pixel> pixies = new ArrayList<>(image.getWidth());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int color = image.getRGB(x, y);
pixels[index++] = color;
pixies.add(new Pixel(x, y, color));
}
publish(new ArrayList<Pixel>(pixies));
pixies = new ArrayList<>(image.getWidth());
Thread.sleep(100);
}
return pixels;
}
#Override
protected void process(List<List<Pixel>> chunks) {
for (List<Pixel> pixels : chunks) {
for (Pixel pixel : pixels) {
newImg.setRGB(pixel.getX(), pixel.getY(), pixel.getColor());
}
}
repaint();
}
};
File f = new File("/Volumes/Big Fat Extension/Dropbox/MegaTokyo/chaotic_megatokyo_by_fredrin-d9k84so.jpg");
try {
image = ImageIO.read(f);
} catch (IOException e) {
}
System.out.println("checkpoint 1");
image = createResizedCopy(image, 200, 200, true);
newImg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
worker.execute();
// pixels = new int[(image.getWidth()) * (image.getHeight())];
// System.out.println("checkpoint 2");
// for (i = 0; i < newImg.getWidth(); i++) {
// for (j = 0; j < newImg.getHeight(); j++) {
// //get the rgb color of the old image
// Color c = new Color(image.getRGB(i, j));
// int r = c.getRed();
// int g = c.getGreen();
// int b = c.getBlue();
// pixels[index++] = (r << 16) | (g << 8) | b;
// }
// }
// System.out.println("checkpoint 4");
//image.setRGB(0, 0, width, height, data, 0, width);
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
public BufferedImage createResizedCopy(BufferedImage originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha) {
System.out.println("resizing...");
Image scaled = originalImage.getScaledInstance(scaledWidth, -1, Image.SCALE_SMOOTH);
BufferedImage scaledBI = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledBI.createGraphics();
g.drawImage(scaled, 0, 0, null);
g.dispose();
return scaledBI;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(newImg, 0, 0, this);
}
}
}
The Thread.sleep in the SwingWorker is intended to do two things:
Give time for the EDT to process the results from the process call and
Slow down the worker so that the results can be updated on the UI.
In my testing without it, the image was pretty much updated instantly.
I also recommend you take the time to better understand the paint process in Swing, start by having a look at:
Performing Custom Painting
Painting in AWT and Swing
The scaling mechanism you were using (and the one I've implemented) aren't the best solutions. I recommend having look at:
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
for some better ideas.
You made a couple of mistakes, the first one is using 0 as scansize which should be the width of the image, also in the same line you should use the width and height instead of i and j.
newImg.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
There is one other mistake which I will let you find on your own, it should be obvious after you see the image with the above fixed line.
I have a jLabel with an Icon that I should print. However, I can't get the jLabel's icon to full size.
Here's some of the code that I think that it is affecting the print size.
public static void printComponentToFile(Component comp, boolean fill) throws PrinterException {
Paper paper = new Paper();
paper.setSize(8.3 * 72, 11.7 * 72); //here
paper.setImageableArea(18, 18, 100, 300); //and here
PageFormat pf = new PageFormat();
pf.setPaper(paper);
pf.setOrientation(PageFormat.LANDSCAPE);
BufferedImage img = new BufferedImage(
(int) Math.round(pf.getWidth()),
(int) Math.round(pf.getHeight()),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
ComponentPrinter cp = new ComponentPrinter(comp, fill);
try {
cp.print(g2d, pf, 0);
} finally {
g2d.dispose();
}
try {
ImageIO.write(img, "png", new File("Page-" + (fill ? "Filled" : "") + ".png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class ComponentPrinter implements Printable {
private Component comp;
private boolean fill;
public ComponentPrinter(Component comp, boolean fill) {
this.comp = comp;
this.fill = fill;
}
#Override
public int print(Graphics g, PageFormat format, int page_index) throws PrinterException {
if (page_index > 0) {
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) g;
g2.translate(format.getImageableX(), format.getImageableY());
double width = (int) Math.floor(format.getImageableWidth()); // here too
double height = (int) Math.floor(format.getImageableHeight()); // and here
if (!fill) {
width = Math.min(width, comp.getPreferredSize().width); // here
height = Math.min(height, comp.getPreferredSize().height); // here
}
comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
if (comp.getParent() == null) {
comp.addNotify();
}
comp.validate();
comp.doLayout();
comp.printAll(g2);
if (comp.getParent() != null) {
comp.removeNotify();
}
return Printable.PAGE_EXISTS;
}
}
So what should I change with those? Also, how can I put a radiobutton on the printing process? It's because I want to print the radiobutton altogether with the label.
This is how I print a label using a button:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
try {
printComponent(jLabel2, false);
} catch (PrinterException ex) {
Logger.getLogger(MappingScreen.class.getName()).log(Level.SEVERE, null, ex);
}
}
Can I make it like this?:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
try {
printComponent(jLabel2, false);
printComponent(jRadioBtn1, false); //change
} catch (PrinterException ex) {
Logger.getLogger(M.class.getName()).log(Level.SEVERE, null, ex);
}
}
UPDATE:
I think I have to add something here to print another component:
public static void main(String args[]) {
try {
JLabel label = new JLabel(
"This is a test",
new ImageIcon("/adv/mapp.jpg"),
JLabel.CENTER);
printComponentToFile(label, true);
printComponentToFile(label, false);
} catch (PrinterException exp) {
exp.printStackTrace();
}
Please help. Thanks
So, based on the concept presented in Printing a JFrame and its components, I've been able to produce these two examples...
Which used the following JPanel as the base component...
public static class PrintForm extends JPanel {
public PrintForm() {
setLayout(new GridBagLayout());
JLabel label = new JLabel("This is a label");
label.setVerticalTextPosition(JLabel.BOTTOM);
label.setHorizontalTextPosition(JLabel.CENTER);
try {
label.setIcon(new ImageIcon(ImageIO.read(new File("C:\\hold\\thumbnails\\_cg_1009___Afraid___by_Serena_Clearwater.png"))));
} catch (IOException ex) {
ex.printStackTrace();
}
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
add(label, gbc);
JRadioButton rb = new JRadioButton("Open to suggestions");
rb.setSelected(true);
gbc.gridy++;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.NONE;
add(rb, gbc);
}
}
And based on the concept presented in Fit/Scale JComponent to page being printed I was able to take an image of 7680x4800 and scale it down to print within an area of 842x598.
Now note. JLabel DOES NOT support scaling. If your image does not fit within the available space, you are going to have to scale it yourself some how. The following solution scales the entire component, having said that, with a little bit of clever re-arranging, it would be possible to make the TestPane scale it's image instead and use the above example instead...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
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.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScalablePrintingTest {
public static void main(String[] args) {
new ScalablePrintingTest();
}
public ScalablePrintingTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final TestPane imagePane = new TestPane();
JButton print = new JButton("Print");
print.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
//printComponent(imagePane);
printComponentToFile(imagePane);
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(imagePane);
frame.add(print, BorderLayout.SOUTH);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage bg;
public TestPane() {
try {
bg = ImageIO.read(new File("/path/to/a/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? new Dimension(200, 200) : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (bg != null) {
int x = (getWidth() - bg.getWidth()) / 2;
int y = (getHeight() - bg.getHeight()) / 2;
g2d.drawImage(bg, x, y, this);
}
g2d.dispose();
}
}
public void printComponent(Component comp) {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");
pj.setPrintable(new ComponentPrintable(comp));
if (!pj.printDialog()) {
return;
}
try {
pj.print();
} catch (PrinterException ex) {
System.out.println(ex);
}
}
public static void printComponentToFile(Component comp) throws PrinterException {
Paper paper = new Paper();
paper.setSize(8.3 * 72, 11.7 * 72);
paper.setImageableArea(18, 18, 559, 783);
PageFormat pf = new PageFormat();
pf.setPaper(paper);
pf.setOrientation(PageFormat.LANDSCAPE);
BufferedImage img = new BufferedImage(
(int) Math.round(pf.getWidth()),
(int) Math.round(pf.getHeight()),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
ComponentPrintable cp = new ComponentPrintable(comp);
try {
cp.print(g2d, pf, 0);
} finally {
g2d.dispose();
}
try {
ImageIO.write(img, "png", new File("Page-Scaled.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class ComponentPrintable implements Printable {
private Component comp;
private ComponentPrintable(Component comp) {
this.comp = comp;
}
#Override
public int print(Graphics g, PageFormat pf, int pageNumber)
throws PrinterException {
// TODO Auto-generated method stub
if (pageNumber > 0) {
return Printable.NO_SUCH_PAGE;
}
// Get the preferred size ofthe component...
Dimension compSize = comp.getPreferredSize();
// Make sure we size to the preferred size
comp.setSize(compSize);
// Get the the print size
Dimension printSize = new Dimension();
printSize.setSize(pf.getImageableWidth(), pf.getImageableHeight());
// Calculate the scale factor
double scaleFactor = getScaleFactorToFit(compSize, printSize);
// Don't want to scale up, only want to scale down
if (scaleFactor > 1d) {
scaleFactor = 1d;
}
// Calcaulte the scaled size...
double scaleWidth = compSize.width * scaleFactor;
double scaleHeight = compSize.height * scaleFactor;
// Create a clone of the graphics context. This allows us to manipulate
// the graphics context without begin worried about what effects
// it might have once we're finished
Graphics2D g2 = (Graphics2D) g.create();
// Calculate the x/y position of the component, this will center
// the result on the page if it can
double x = ((pf.getImageableWidth() - scaleWidth) / 2d) + pf.getImageableX();
double y = ((pf.getImageableHeight() - scaleHeight) / 2d) + pf.getImageableY();
// Create a new AffineTransformation
AffineTransform at = new AffineTransform();
// Translate the offset to out "center" of page
at.translate(x, y);
// Set the scaling
at.scale(scaleFactor, scaleFactor);
// Apply the transformation
g2.transform(at);
// Print the component
comp.printAll(g2);
// Dispose of the graphics context, freeing up memory and discarding
// our changes
g2.dispose();
comp.revalidate();
return Printable.PAGE_EXISTS;
}
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = 1;
if (iMasterSize > iTargetSize) {
dScale = (double) iTargetSize / (double) iMasterSize;
} else {
dScale = (double) iTargetSize / (double) iMasterSize;
}
return dScale;
}
}
I was going to update my previous answer, but it's been accepted...
This example basically combines the solutions presented in Fit/Scale JComponent to page being printed and Printing a JFrame and its components and demonstrates the difference between scaling the component when it's printed as apposed to have the component capable of scaling itself...
It creates a interface chain of the Printables, which I hope will help clear up any confusion...well, less then there was...
So starting with...
The panel on the left is static, that is, the image is not scaled by the component. The panel on the right is dynamic, that is, the component will scale the image as the size of the component is changed.
The static panel when printed using the scaled approach. You will note that both the label and radio button have been scaled as well
Compared to the dynamic panel when using the filled approach. You will note that the label and radio button are not scaled, but remain at there normal size, but the background image is scaled instead...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PrintComponentTest {
public static void main(String[] args) {
new PrintComponentTest();
}
public PrintComponentTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private StaticImagePane staticImagePane;
private DynamicImagePane dynamicImagePane;
public TestPane() {
JPanel content = new JPanel(new GridLayout());
content.add(new JScrollPane(preparePane(staticImagePane = new StaticImagePane())));
content.add(preparePane(dynamicImagePane = new DynamicImagePane()));
setLayout(new BorderLayout());
add(content);
JPanel options = new JPanel();
JButton normal = new JButton("Print");
normal.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
printComponentToFile(new FillableCompentPrintable(staticImagePane, false), new File("Static-Normal.png"));
printComponentToFile(new FillableCompentPrintable(staticImagePane, true), new File("Static-Filled.png"));
printComponentToFile(new ScalableCompentPrintable(staticImagePane), new File("Static-Scaled.png"));
printComponentToFile(new FillableCompentPrintable(dynamicImagePane, false), new File("Dynamic-Normal.png"));
printComponentToFile(new FillableCompentPrintable(dynamicImagePane, true), new File("Dynamic-Filled.png"));
printComponentToFile(new ScalableCompentPrintable(dynamicImagePane), new File("Dynamic-Scaled.png"));
staticImagePane.invalidate();
dynamicImagePane.invalidate();
staticImagePane.revalidate();
dynamicImagePane.revalidate();
invalidate();
revalidate();
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
});
options.add(normal);
add(options, BorderLayout.SOUTH);
}
protected JPanel preparePane(JPanel panel) {
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
JLabel label = new JLabel("This is some text on a label");
label.setForeground(Color.WHITE);
panel.add(label, gbc);
JRadioButton btn = new JRadioButton("Do you agree", true);
btn.setOpaque(false);
btn.setForeground(Color.WHITE);
panel.add(btn, gbc);
return panel;
}
}
public void printComponent(ComponentPrintable printable) {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");
pj.setPrintable(printable);
if (!pj.printDialog()) {
return;
}
try {
pj.print();
} catch (PrinterException ex) {
System.out.println(ex);
}
}
public static void printComponentToFile(ComponentPrintable printable, File file) throws PrinterException {
Paper paper = new Paper();
paper.setSize(8.3 * 72, 11.7 * 72);
paper.setImageableArea(18, 18, 559, 783);
PageFormat pf = new PageFormat();
pf.setPaper(paper);
pf.setOrientation(PageFormat.LANDSCAPE);
BufferedImage img = new BufferedImage(
(int) Math.round(pf.getWidth()),
(int) Math.round(pf.getHeight()),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
try {
printable.print(g2d, pf, 0);
} finally {
g2d.dispose();
}
try {
ImageIO.write(img, "png", file);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static interface ComponentPrintable extends Printable {
public Component getComponent();
}
public abstract static class AbstractComponentPrintable implements ComponentPrintable {
private final Component component;
public AbstractComponentPrintable(Component component) {
this.component = component;
}
#Override
public Component getComponent() {
return component;
}
protected void beforePrinting(Component comp) {
if (comp.getParent() == null) {
comp.addNotify();
}
comp.invalidate();
comp.revalidate();
comp.doLayout();
}
protected void afterPrinting(Component comp) {
if (comp.getParent() != null) {
comp.removeNotify();
} else {
comp.invalidate();
comp.revalidate();
}
}
#Override
public int print(Graphics g, PageFormat format, int page_index) throws PrinterException {
if (page_index > 0) {
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) g;
printComponent(g2, format, getComponent());
return Printable.PAGE_EXISTS;
}
protected abstract void printComponent(Graphics2D g, PageFormat pf, Component comp);
}
public static class FillableCompentPrintable extends AbstractComponentPrintable {
private boolean fill;
public FillableCompentPrintable(Component component, boolean fill) {
super(component);
this.fill = fill;
}
public boolean isFill() {
return fill;
}
#Override
protected void printComponent(Graphics2D g2, PageFormat pf, Component comp) {
g2.translate(pf.getImageableX(), pf.getImageableY());
double width = (int) Math.floor(pf.getImageableWidth());
double height = (int) Math.floor(pf.getImageableHeight());
if (!isFill()) {
width = Math.min(width, comp.getPreferredSize().width);
height = Math.min(height, comp.getPreferredSize().height);
}
comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
beforePrinting(comp);
comp.printAll(g2);
afterPrinting(comp);
// Debug purposes only...
g2.translate(-pf.getImageableX(), -pf.getImageableY());
g2.setColor(Color.RED);
g2.drawRect(0, 0, (int) pf.getWidth() - 1, (int) pf.getHeight() - 1);
}
}
public static class ScalableCompentPrintable extends AbstractComponentPrintable {
public ScalableCompentPrintable(Component component) {
super(component);
}
#Override
protected void printComponent(Graphics2D g2d, PageFormat pf, Component comp) {
// Get the preferred size ofthe component...
Dimension compSize = comp.getPreferredSize();
// Make sure we size to the preferred size
comp.setSize(compSize);
// Get the the print size
Dimension printSize = new Dimension();
printSize.setSize(pf.getImageableWidth(), pf.getImageableHeight());
// Calculate the scale factor
double scaleFactor = getScaleFactorToFit(compSize, printSize);
// Don't want to scale up, only want to scale down
if (scaleFactor > 1d) {
scaleFactor = 1d;
}
// Calcaulte the scaled size...
double scaleWidth = compSize.width * scaleFactor;
double scaleHeight = compSize.height * scaleFactor;
// Create a clone of the graphics context. This allows us to manipulate
// the graphics context without begin worried about what effects
// it might have once we're finished
Graphics2D g2 = (Graphics2D) g2d.create();
// Calculate the x/y position of the component, this will center
// the result on the page if it can
double x = ((pf.getImageableWidth() - scaleWidth) / 2d) + pf.getImageableX();
double y = ((pf.getImageableHeight() - scaleHeight) / 2d) + pf.getImageableY();
// Create a new AffineTransformation
AffineTransform at = new AffineTransform();
// Translate the offset to out "center" of page
at.translate(x, y);
// Set the scaling
at.scale(scaleFactor, scaleFactor);
// Apply the transformation
g2.transform(at);
// Print the component
beforePrinting(comp);
comp.printAll(g2);
afterPrinting(comp);
// Dispose of the graphics context, freeing up memory and discarding
// our changes
g2.dispose();
// Debug purposes only...
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, (int) pf.getWidth() - 1, (int) pf.getHeight() - 1);
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = 1;
if (iMasterSize > iTargetSize) {
dScale = (double) iTargetSize / (double) iMasterSize;
} else {
dScale = (double) iTargetSize / (double) iMasterSize;
}
return dScale;
}
}
public class StaticImagePane extends JPanel {
private BufferedImage image;
public StaticImagePane() {
try {
setImage(ImageIO.read(new File("path\to\a\image")));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
repaint();
}
#Override
public Dimension getPreferredSize() {
BufferedImage bg = getImage();
return bg == null ? new Dimension(200, 200) : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
paintBackground(g2d);
g2d.dispose();
}
protected void paintBackground(Graphics2D g2d) {
paintBackground(g2d, getImage());
}
protected void paintBackground(Graphics2D g2d, Image bg) {
if (bg != null) {
int x = (getWidth() - bg.getWidth(this)) / 2;
int y = (getHeight() - bg.getHeight(this)) / 2;
g2d.drawImage(bg, x, y, this);
}
}
}
public class DynamicImagePane extends StaticImagePane {
private Image scaled;
public DynamicImagePane() {
try {
setImage(ImageIO.read(new File("path\to\a\image")));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public void invalidate() {
super.invalidate();
if (getImage() != null) {
int width = getWidth();
int height = getHeight();
if (width > 0 && height > 0) {
// Keep the aspect ratio
if (width > height) {
width = -1;
} else if (height > width) {
height = -1;
}
scaled = getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
}
}
}
public Image getScaledImage() {
return scaled;
}
#Override
protected void paintBackground(Graphics2D g2d) {
paintBackground(g2d, getScaledImage());
}
}
}
Note, this is just an example, there is plenty of work that needs to be done.
One issue is with the scaling, see The Perils of Image.getScaledInstance() for details and Quality of Image after resize very low -- Java for a better approach...
To make it work, I changed it to something like this:
//OLD:
public void printComponent(Component comp) {
//NEW:
public void printComponent(JComponent comp, boolean fill) throws PrinterException {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");
pj.setPrintable(new ComponentPrintable(comp));
if (!pj.printDialog()) {
return;
}
try {
pj.print();
} catch (PrinterException ex) {
System.out.println(ex);
}
}
I'm making a fun little test screen recording program in java, and I want it to have a preview of your screen before you start recording.. but its a very slow and poor method of which I am using, involving capturing an image, saving it, then reading it in through a bufferedimage and drawing that image using Graphics. Its very slow and not useful as a "preview" is there a way to speed up and have a more efficient "previewing system".
Here is what I have so far:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MainFrame implements ActionListener, Runnable {
//add frame components
public static JFrame frame = new JFrame("Screen Caper - v1.0.1");
JButton start = new JButton("record");
JButton close = new JButton("Exit");
JPanel preview = new JPanel();
public static boolean running = false;
public static boolean recording = false;
public static boolean paused = false;
public static String curDir = System.getProperty("user.dir");
//get the screen width
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
Container a = new Container();
Container b = new Container();
public MainFrame() {
frame.setSize((int)(width) - 80, (int)(height) - 80);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setup the buttons and JPanel
a.setLayout(new GridLayout(1, 2));
a.add(start);
start.addActionListener(this);
a.add(close);
close.addActionListener(this);
frame.add(a, BorderLayout.NORTH);
b.setLayout(new GridLayout(1, 2));
b.add(preview);
frame.add(b, BorderLayout.CENTER);
//add anything else
running = true;
//set frame to visible
frame.setVisible(true);
run();
}
public static void main(String[] args) {
new MainFrame();
}
public void run() {
Graphics g = frame.getGraphics();
while (running) {
//draw the preview of the computer screen on the JPanel if its not recording already
if (!recording && !paused) {
drawPreview(g);
}
}
}
public void drawPreview(Graphics g) {
BufferedImage image;
try {
image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(image, "png", new File("test.png"));
} catch (Exception ex) {
ex.printStackTrace();
}
BufferedImage prevIm;
try {
prevIm = ImageIO.read(new File("test.png"));
g.setColor(new Color(0, 0, 0));
g.fillRect(preview.getX() + 3, preview.getY() + 51, preview.getWidth(), preview.getHeight() + 1);
g.drawImage(prevIm, preview.getX() + 3, preview.getY() + 51, preview.getX() + preview.getWidth(), preview.getY() + preview.getHeight(), null);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void record(Graphics g) {
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource().equals(start)) {
if (!recording) {
//if the program isn't recording, then start recording
Graphics g = frame.getGraphics();
record(g);
start.setText("Finish");
recording = true;
System.out.println("recording...");
} else {
//else stop recording
start.setText("record");
recording = false;
System.out.println("done");
}
}
if (event.getSource().equals(close)) {
paused = true;
int ans = JOptionPane.showConfirmDialog(null, "Woah there! You're about to quit the application\nAre you sure you want to procced?", "Caution!", JOptionPane.YES_NO_OPTION);
if (ans == JOptionPane.YES_OPTION) {
System.exit(0);
} else if (ans == JOptionPane.NO_OPTION) {
paused = false;
}
}
}
}
any help is appreciated!
Don't use getGraphics, this is not how custom painting is done.
Your run method may simply be running to fast, consider using a javax.swing.Timer instead
Toolkit.getDefaultToolkit().getScreenSize() only returns the "default" screen and does not take into consideration split screens
Capturing the screen is a time consuming process and there's not much you can do about reducing it (as it's outside of your control). You "could" setup a series of Threads whose job it was to capture a given section of the desktop. You could also achieve this using SwingWorkers which would make it easier to sync the updates back to the UI...
Take a look at:
Performing Custom Painting
Concurrency in Swing
How to Use Swing Timers
Updated with example
This is a proof of concept only! You should understand what it's trying to do and borrow ideas from it...
You can see the preview window change inside the preview window...kinda freaky...
It tested this on a virtual desktop of 4480x1600.
Basically, it divides the desktop up into a 4x4 grid and starts a Thread for each section. Each thread is responsible for capturing it's own section of the screen.
It also scales that resulting image down and feeds it back to the UI.
I had started with SwingWorkers, but it seems to be hard to be limited to 10 threads. You could reduce the grid size and use SwingWorkers, they tend to be simpler to use and manage then raw Threads.
Each section is given an id, which allows me keep track of what's changed. Technically, you could just add elements to a List, but how do you determine what's new and what's old?
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PreviewDesktop {
public static void main(String[] args) {
new PreviewDesktop();
}
public PreviewDesktop() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Puzzler {
private Rectangle virtualBounds;
private double scale;
private Map<Integer, PuzzlePiece> pieces;
public TestPane() {
virtualBounds = getVirtualBounds();
int columns = 4;
int rows = 4;
pieces = new HashMap<>(columns * rows);
int columnWidth = Math.round(virtualBounds.width / (float) columns);
int rowHeight = Math.round(virtualBounds.height / (float) rows);
int id = 0;
for (int row = 0; row < rows; row++) {
int y = virtualBounds.y + (row * rowHeight);
for (int column = 0; column < columns; column++) {
int x = virtualBounds.x + (column * columnWidth);
Rectangle bounds = new Rectangle(x, y, columnWidth, rowHeight);
GrabberWorker worker = new GrabberWorker(id, this, bounds);
System.out.println(id);
id++;
startThread(worker);
}
}
}
#Override
public double getScale() {
return scale;
}
#Override
public void invalidate() {
super.invalidate();
scale = getScaleFactorToFit(virtualBounds.getSize(), getSize());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (Integer id : pieces.keySet()) {
PuzzlePiece piece = pieces.get(id);
Rectangle bounds = piece.getBounds();
BufferedImage img = piece.getImage();
g2d.drawImage(img, bounds.x, bounds.y, this);
// If you want to see each sections bounds, uncomment below...
//g2d.draw(bounds);
}
g2d.dispose();
}
#Override
public void setPiece(int id, PuzzlePiece piece) {
pieces.put(id, piece);
repaint();
}
protected void startThread(GrabberWorker worker) {
Thread thread = new Thread(worker);
thread.setDaemon(true);
thread.start();
}
}
public class PuzzlePiece {
private final Rectangle bounds;
private final BufferedImage img;
public PuzzlePiece(Rectangle bounds, BufferedImage img) {
this.bounds = bounds;
this.img = img;
}
public Rectangle getBounds() {
return bounds;
}
public BufferedImage getImage() {
return img;
}
}
public interface Puzzler {
public void setPiece(int id, PuzzlePiece piece);
public double getScale();
}
public class GrabberWorker implements Runnable {
private Rectangle bounds;
private Puzzler puzzler;
private int id;
private volatile PuzzlePiece parked;
private ReentrantLock lckParked;
public GrabberWorker(int id, Puzzler puzzler, Rectangle bounds) {
this.id = id;
this.bounds = bounds;
this.puzzler = puzzler;
lckParked = new ReentrantLock();
}
protected void process(PuzzlePiece piece) {
// puzzler.setPiece(bounds, chunks.get(chunks.size() - 1));
puzzler.setPiece(id, piece);
}
protected void publish(PuzzlePiece piece) {
lckParked.lock();
try {
parked = piece;
} finally {
lckParked.unlock();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
lckParked.lock();
try {
process(parked);
} finally {
lckParked.unlock();
}
}
});
}
#Override
public void run() {
try {
Robot bot = new Robot();
while (true) {
BufferedImage img = bot.createScreenCapture(bounds);
double scale = puzzler.getScale();
Rectangle scaled = new Rectangle(bounds);
scaled.x *= scale;
scaled.y *= scale;
scaled.width *= scale;
scaled.height *= scale;
BufferedImage imgScaled = getScaledInstance(img, scale);
publish(new PuzzlePiece(scaled, imgScaled));
Thread.sleep(500);
}
} catch (AWTException | InterruptedException exp) {
exp.printStackTrace();
}
}
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
for (GraphicsDevice gd : lstGDs) {
bounds.add(gd.getDefaultConfiguration().getBounds());
}
return bounds;
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = (double) iTargetSize / (double) iMasterSize;
return dScale;
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
// System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected static BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
w = img.getWidth();
h = img.getHeight();
} else {
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}
Now, if you're feeling really adventurous, you could update this idea so that if the underlying image for a section didn't change and the scale didn't change, it didn't send that to the UI, which might help reduce some of the overhead ... and no, I don't have code to do that ;)