To scale the image, you need to create a new image and draw it. One way is to use the filter() method for AffineTransferOp , as suggested here . This allows you to select the interpolation method.
private static BufferedImage scale1(BufferedImage before, double scale) { int w = before.getWidth(); int h = before.getHeight();
Another way is to simply draw the original image in a new image, using the zoom operation to scale. This method is very similar, but it also illustrates how you can draw whatever you want in the final image. (I put an empty line where the two methods start to differ.)
private static BufferedImage scale2(BufferedImage before, double scale) { int w = before.getWidth(); int h = before.getHeight();
Addendum: Results
To illustrate the differences, I compared the results of the five methods below. Here's what the results look like, scalable both up and down, as well as performance data. (Performance varies from one run to another, so use these numbers only as a rough guide.) The top image is original. I scale it in half and half size.
As you can see, AffineTransformOp.filter() used in scaleBilinear() is faster than the standard Graphics2D.drawImage() drawing method in scale2() . Also, BiCubic interpolation is the slowest, but gives the best results when expanding the image. (For performance, it should only be compared with scaleBilinear() and scaleNearest(). ) A bilinear image seems better for compressing the image, although this is not an easy call. And NearestNeighbor is the fastest, with worse results. Bilinear seems to be the best compromise between speed and quality. Image.getScaledInstance() , called by the questionable() method, performed very poorly and returned to the same poor quality as NearestNeighbor. (Performance metrics are for image expansion only.)

public static BufferedImage scaleBilinear(BufferedImage before, double scale) { final int interpolation = AffineTransformOp.TYPE_BILINEAR; return scale(before, scale, interpolation); } public static BufferedImage scaleBicubic(BufferedImage before, double scale) { final int interpolation = AffineTransformOp.TYPE_BICUBIC; return scale(before, scale, interpolation); } public static BufferedImage scaleNearest(BufferedImage before, double scale) { final int interpolation = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; return scale(before, scale, interpolation); } @NotNull private static BufferedImage scale(final BufferedImage before, final double scale, final int type) { int w = before.getWidth(); int h = before.getHeight(); int w2 = (int) (w * scale); int h2 = (int) (h * scale); BufferedImage after = new BufferedImage(w2, h2, before.getType()); AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale); AffineTransformOp scaleOp = new AffineTransformOp(scaleInstance, type); scaleOp.filter(before, after); return after; } private static BufferedImage scale2(BufferedImage before, double scale) { int w = before.getWidth(); int h = before.getHeight();