Bal*_*eth 47 java image-processing
我有一个应用程序,用户可以在相册中上传图片,但自然上传的图像需要调整大小,因此也有拇指可用,所显示的图片也适合页面(例如800x600).我调整大小的方式是这样的:
Image scaledImage = img.getScaledInstance((int)width, (int)height, Image.SCALE_SMOOTH);
BufferedImage imageBuff = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_RGB);
Graphics g = imageBuff.createGraphics();
g.drawImage(scaledImage, 0, 0, new Color(0,0,0), null);
g.dispose();
Run Code Online (Sandbox Code Playgroud)
它工作得很好.我唯一的问题是这个g.drawImage()方法看起来非常慢,而我无法想象用户要耐心等待上传20张图片20*10秒~3分钟.事实上,在我的电脑上,为单张照片制作3种不同的调整大小需要近40秒.
这还不够好,我正在寻找更快的解决方案.我想知道是否有人可以通过调用shell脚本,命令告诉我有关更好的一个,或者通过调用shell脚本,命令,无论你知道什么,它必须更快,其他一切都无关紧要.
Jör*_*ann 26
我正在使用类似于以下的代码来缩放图像,我删除了处理保留纵横比的部分.性能绝对优于每张图像10秒,但我不记得任何确切的数字.为了在缩小时存档更好的质量,如果原始图像的大小超过所需缩略图的两倍,则应按几个步骤缩放,每个步骤应将前一个图像缩放到其大小的一半.
public static BufferedImage getScaledImage(BufferedImage image, int width, int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double)width/imageWidth;
double scaleY = (double)height/imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(
image,
new BufferedImage(width, height, image.getType()));
}
Run Code Online (Sandbox Code Playgroud)
Kla*_*rth 14
你真的需要使用Image.SCALE_SMOOTH提供的质量吗?如果不这样做,您可以尝试使用Image.SCALE_FAST.如果您想坚持使用Java提供的东西,您可能会发现本文很有帮助.
小智 13
好吧,Jacob和我想要调整Image的大小,而不是BufferedImage.所以我们最终得到了这段代码:
/**
* we want the x and o to be resized when the JFrame is resized
*
* @param originalImage an x or an o. Use cross or oh fields.
*
* @param biggerWidth
* @param biggerHeight
*/
private Image resizeToBig(Image originalImage, int biggerWidth, int biggerHeight) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage resizedImage = new BufferedImage(biggerWidth, biggerHeight, type);
Graphics2D g = resizedImage.createGraphics();
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);
g.drawImage(originalImage, 0, 0, biggerWidth, biggerHeight, this);
g.dispose();
return resizedImage;
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*o13 13
问题的主要内容是关于Java中缩放图像的性能.其他答案显示了不同的方法,没有进一步评估.我对此也很好奇,所以我试着写一个小的性能测试.然而,难以可靠,合理和客观地测试图像缩放性能.有太多的影响因素需要考虑:
BufferedImage.TYPE_*输入图像的BufferedImage.TYPE_*输出图像的我试图涵盖那些我认为最重要的那些.设置是:
输入是一张简单的"平均"照片(特别是维基百科的"今日形象",大小为2560x1706像素)
主内插类型进行测试-即,通过使用RenderingHints其中INTERPOLATION键被设置为的值NEAREST_NEIGHBOR,BILINEAR和BICUBIC
输入图像已转换为不同类型:
BufferedImage.TYPE_INT_RGB:一种常用的类型,因为它"通常"显示最佳性能特征
BufferedImage.TYPE_3BTE_BGR:这是默认情况下读取时使用的类型 ImageIO
目标图像大小在宽度10000(因此,向上缩放图像)和100(因此,将图像缩小到缩略图大小)之间变化
测试已在具有3.7 GHz和JDK 1.8u31的Win64/AMD K10上运行-Xmx4000m -server.
测试方法是:
AffineTransformOp,如JörnHorstmann的答案Graphics,如johnstosh的回答Image#getScaledInstance测试代码如下所示:
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.function.Supplier;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
public class ImageScalingPerformance
{
private static int blackHole = 0;
public static void main(String[] args) throws IOException
{
// Image with size 2560 x 1706, from https://upload.wikimedia.org/
// wikipedia/commons/4/41/Pitta_moluccensis_-_Kaeng_Krachan.jpg
BufferedImage image = ImageIO.read(
new File("Pitta_moluccensis_-_Kaeng_Krachan.jpg"));
int types[] =
{
BufferedImage.TYPE_3BYTE_BGR,
BufferedImage.TYPE_INT_RGB,
};
Object interpolationValues[] =
{
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
RenderingHints.VALUE_INTERPOLATION_BILINEAR,
RenderingHints.VALUE_INTERPOLATION_BICUBIC,
};
int widths[] =
{
10000, 5000, 2500, 1000, 500, 100
};
System.out.printf("%10s%22s%6s%18s%10s\n",
"Image type", "Interpolation", "Size", "Method", "Duration (ms)");
for (int type : types)
{
BufferedImage currentImage = convert(image, type);
for (Object interpolationValue : interpolationValues)
{
for (int width : widths)
{
List<Supplier<Image>> tests =
createTests(currentImage, interpolationValue, width);
for (Supplier<Image> test : tests)
{
double durationMs = computeMs(test);
System.out.printf("%10s%22s%6s%18s%10s\n",
stringForBufferedImageType(type),
stringForInterpolationValue(interpolationValue),
String.valueOf(width),
String.valueOf(test),
String.format(Locale.ENGLISH, "%6.3f", durationMs));
}
}
}
}
System.out.println(blackHole);
}
private static List<Supplier<Image>> createTests(
BufferedImage image, Object interpolationValue, int width)
{
RenderingHints renderingHints = new RenderingHints(null);
renderingHints.put(
RenderingHints.KEY_INTERPOLATION,
interpolationValue);
double scale = (double) width / image.getWidth();
int height = (int)(scale * image.getHeight());
Supplier<Image> s0 = new Supplier<Image>()
{
@Override
public BufferedImage get()
{
return scaleWithAffineTransformOp(
image, width, height, renderingHints);
}
@Override
public String toString()
{
return "AffineTransformOp";
}
};
Supplier<Image> s1 = new Supplier<Image>()
{
@Override
public Image get()
{
return scaleWithGraphics(
image, width, height, renderingHints);
}
@Override
public String toString()
{
return "Graphics";
}
};
Supplier<Image> s2 = new Supplier<Image>()
{
@Override
public Image get()
{
return scaleWithGetScaledInstance(
image, width, height, renderingHints);
}
@Override
public String toString()
{
return "GetScaledInstance";
}
};
List<Supplier<Image>> tests = new ArrayList<Supplier<Image>>();
tests.add(s0);
tests.add(s1);
tests.add(s2);
return tests;
}
private static double computeMs(Supplier<Image> supplier)
{
int runs = 5;
long before = System.nanoTime();
for (int i=0; i<runs; i++)
{
Image image0 = supplier.get();
blackHole += image0.hashCode();
}
long after = System.nanoTime();
double durationMs = (after-before) / 1e6 / runs;
return durationMs;
}
private static BufferedImage convert(BufferedImage image, int type)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(), type);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
private static BufferedImage scaleWithAffineTransformOp(
BufferedImage image, int w, int h,
RenderingHints renderingHints)
{
BufferedImage scaledImage = new BufferedImage(w, h, image.getType());
double scaleX = (double) w / image.getWidth();
double scaleY = (double) h / image.getHeight();
AffineTransform affineTransform =
AffineTransform.getScaleInstance(scaleX, scaleY);
AffineTransformOp affineTransformOp = new AffineTransformOp(
affineTransform, renderingHints);
return affineTransformOp.filter(
image, scaledImage);
}
private static BufferedImage scaleWithGraphics(
BufferedImage image, int w, int h,
RenderingHints renderingHints)
{
BufferedImage scaledImage = new BufferedImage(w, h, image.getType());
Graphics2D g = scaledImage.createGraphics();
g.setRenderingHints(renderingHints);
g.drawImage(image, 0, 0, w, h, null);
g.dispose();
return scaledImage;
}
private static Image scaleWithGetScaledInstance(
BufferedImage image, int w, int h,
RenderingHints renderingHints)
{
int hint = Image.SCALE_REPLICATE;
if (renderingHints.get(RenderingHints.KEY_ALPHA_INTERPOLATION) !=
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
{
hint = Image.SCALE_AREA_AVERAGING;
}
Image scaledImage = image.getScaledInstance(w, h, hint);
MediaTracker mediaTracker = new MediaTracker(new JLabel());
mediaTracker.addImage(scaledImage, 0);
try
{
mediaTracker.waitForAll();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
return scaledImage;
}
private static String stringForBufferedImageType(int type)
{
switch (type)
{
case BufferedImage.TYPE_INT_RGB : return "INT_RGB";
case BufferedImage.TYPE_INT_ARGB : return "INT_ARGB";
case BufferedImage.TYPE_INT_ARGB_PRE : return "INT_ARGB_PRE";
case BufferedImage.TYPE_INT_BGR : return "INT_BGR";
case BufferedImage.TYPE_3BYTE_BGR : return "3BYTE_BGR";
case BufferedImage.TYPE_4BYTE_ABGR : return "4BYTE_ABGR";
case BufferedImage.TYPE_4BYTE_ABGR_PRE : return "4BYTE_ABGR_PRE";
case BufferedImage.TYPE_USHORT_565_RGB : return "USHORT_565_RGB";
case BufferedImage.TYPE_USHORT_555_RGB : return "USHORT_555_RGB";
case BufferedImage.TYPE_BYTE_GRAY : return "BYTE_GRAY";
case BufferedImage.TYPE_USHORT_GRAY : return "USHORT_GRAY";
case BufferedImage.TYPE_BYTE_BINARY : return "BYTE_BINARY";
case BufferedImage.TYPE_BYTE_INDEXED : return "BYTE_INDEXED";
}
return "CUSTOM";
}
private static String stringForInterpolationValue(Object value)
{
if (value == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
{
return "NEAREST/REPLICATE";
}
if (value == RenderingHints.VALUE_INTERPOLATION_BILINEAR)
{
return "BILINEAR/AREA_AVG";
}
if (value == RenderingHints.VALUE_INTERPOLATION_BICUBIC)
{
return "BICUBIC/AREA_AVG";
}
return "(unknown)";
}
}
Run Code Online (Sandbox Code Playgroud)
First, regarding getScaledInstance: As Chris Campbell has pointed out in his (famous) article about The Perils of Image.getScaledInstance() (which was already linked to in other answers), the Image#getScaledInstance method is somewhat broken, and has a distressingly bad performance for most configurations. Additionally, it has the disadvantage of not having such a fine-grained control about the interpolation type. This should be taken into account in the following performance comparison: The quality of the resulting images may differ, which is not considered here. For example, the "area averaging" method of getScaledInstance does not yield a good image quality when the image size is increased.
(最严重的缺点Image#getScaledInstance是恕我直言,它只提供一个Image,而不是一个BufferedImage,但如果图像只应该被绘成一个Graphics,这可能不重要)
我将在这里转储程序的输出以供参考,一些细节将在下面进行:
Image type Interpolation Size MethodDuration (ms)
3BYTE_BGR NEAREST/REPLICATE 10000 AffineTransformOp 197.287
3BYTE_BGR NEAREST/REPLICATE 10000 Graphics 184.427
3BYTE_BGR NEAREST/REPLICATE 10000 GetScaledInstance 1869.759
3BYTE_BGR NEAREST/REPLICATE 5000 AffineTransformOp 38.354
3BYTE_BGR NEAREST/REPLICATE 5000 Graphics 40.220
3BYTE_BGR NEAREST/REPLICATE 5000 GetScaledInstance 1088.448
3BYTE_BGR NEAREST/REPLICATE 2500 AffineTransformOp 10.153
3BYTE_BGR NEAREST/REPLICATE 2500 Graphics 9.461
3BYTE_BGR NEAREST/REPLICATE 2500 GetScaledInstance 613.030
3BYTE_BGR NEAREST/REPLICATE 1000 AffineTransformOp 2.137
3BYTE_BGR NEAREST/REPLICATE 1000 Graphics 1.956
3BYTE_BGR NEAREST/REPLICATE 1000 GetScaledInstance 464.989
3BYTE_BGR NEAREST/REPLICATE 500 AffineTransformOp 0.861
3BYTE_BGR NEAREST/REPLICATE 500 Graphics 0.750
3BYTE_BGR NEAREST/REPLICATE 500 GetScaledInstance 407.751
3BYTE_BGR NEAREST/REPLICATE 100 AffineTransformOp 0.206
3BYTE_BGR NEAREST/REPLICATE 100 Graphics 0.153
3BYTE_BGR NEAREST/REPLICATE 100 GetScaledInstance 385.863
3BYTE_BGR BILINEAR/AREA_AVG 10000 AffineTransformOp 830.097
3BYTE_BGR BILINEAR/AREA_AVG 10000 Graphics 1501.290
3BYTE_BGR BILINEAR/AREA_AVG 10000 GetScaledInstance 1627.934
3BYTE_BGR BILINEAR/AREA_AVG 5000 AffineTransformOp 207.816
3BYTE_BGR BILINEAR/AREA_AVG 5000 Graphics 376.789
3BYTE_BGR BILINEAR/AREA_AVG 5000 GetScaledInstance 1063.942
3BYTE_BGR BILINEAR/AREA_AVG 2500 AffineTransformOp 52.362
3BYTE_BGR BILINEAR/AREA_AVG 2500 Graphics 95.041
3BYTE_BGR BILINEAR/AREA_AVG 2500 GetScaledInstance 612.660
3BYTE_BGR BILINEAR/AREA_AVG 1000 AffineTransformOp 9.121
3BYTE_BGR BILINEAR/AREA_AVG 1000 Graphics 15.749
3BYTE_BGR BILINEAR/AREA_AVG 1000 GetScaledInstance 452.578
3BYTE_BGR BILINEAR/AREA_AVG 500 AffineTransformOp 2.593
3BYTE_BGR BILINEAR/AREA_AVG 500 Graphics 4.237
3BYTE_BGR BILINEAR/AREA_AVG 500 GetScaledInstance 407.661
3BYTE_BGR BILINEAR/AREA_AVG 100 AffineTransformOp 0.275
3BYTE_BGR BILINEAR/AREA_AVG 100 Graphics 0.297
3BYTE_BGR BILINEAR/AREA_AVG 100 GetScaledInstance 381.835
3BYTE_BGR BICUBIC/AREA_AVG 10000 AffineTransformOp 3015.943
3BYTE_BGR BICUBIC/AREA_AVG 10000 Graphics 5431.703
3BYTE_BGR BICUBIC/AREA_AVG 10000 GetScaledInstance 1654.424
3BYTE_BGR BICUBIC/AREA_AVG 5000 AffineTransformOp 756.136
3BYTE_BGR BICUBIC/AREA_AVG 5000 Graphics 1359.288
3BYTE_BGR BICUBIC/AREA_AVG 5000 GetScaledInstance 1063.467
3BYTE_BGR BICUBIC/AREA_AVG 2500 AffineTransformOp 189.953
3BYTE_BGR BICUBIC/AREA_AVG 2500 Graphics 341.039
3BYTE_BGR BICUBIC/AREA_AVG 2500 GetScaledInstance 615.807
3BYTE_BGR BICUBIC/AREA_AVG 1000 AffineTransformOp 31.351
3BYTE_BGR BICUBIC/AREA_AVG 1000 Graphics 55.914
3BYTE_BGR BICUBIC/AREA_AVG 1000 GetScaledInstance 451.808
3BYTE_BGR BICUBIC/AREA_AVG 500 AffineTransformOp 8.422
3BYTE_BGR BICUBIC/AREA_AVG 500 Graphics 15.028
3BYTE_BGR BICUBIC/AREA_AVG 500 GetScaledInstance 408.626
3BYTE_BGR BICUBIC/AREA_AVG 100 AffineTransformOp 0.703
3BYTE_BGR BICUBIC/AREA_AVG 100 Graphics 0.825
3BYTE_BGR BICUBIC/AREA_AVG 100 GetScaledInstance 382.610
INT_RGB NEAREST/REPLICATE 10000 AffineTransformOp 330.445
INT_RGB NEAREST/REPLICATE 10000 Graphics 114.656
INT_RGB NEAREST/REPLICATE 10000 GetScaledInstance 2784.542
INT_RGB NEAREST/REPLICATE 5000 AffineTransformOp 83.081
INT_RGB NEAREST/REPLICATE 5000 Graphics 29.148
INT_RGB NEAREST/REPLICATE 5000 GetScaledInstance 1117.136
INT_RGB NEAREST/REPLICATE 2500 AffineTransformOp 22.296
INT_RGB NEAREST/REPLICATE 2500 Graphics 7.735
INT_RGB NEAREST/REPLICATE 2500 GetScaledInstance 436.779
INT_RGB NEAREST/REPLICATE 1000 AffineTransformOp 3.859
INT_RGB NEAREST/REPLICATE 1000 Graphics 2.542
INT_RGB NEAREST/REPLICATE 1000 GetScaledInstance 205.863
INT_RGB NEAREST/REPLICATE 500 AffineTransformOp 1.413
INT_RGB NEAREST/REPLICATE 500 Graphics 0.963
INT_RGB NEAREST/REPLICATE 500 GetScaledInstance 156.537
INT_RGB NEAREST/REPLICATE 100 AffineTransformOp 0.160
INT_RGB NEAREST/REPLICATE 100 Graphics 0.074
INT_RGB NEAREST/REPLICATE 100 GetScaledInstance 126.159
INT_RGB BILINEAR/AREA_AVG 10000 AffineTransformOp 1019.438
INT_RGB BILINEAR/AREA_AVG 10000 Graphics 1230.621
INT_RGB BILINEAR/AREA_AVG 10000 GetScaledInstance 2721.918
INT_RGB BILINEAR/AREA_AVG 5000 AffineTransformOp 254.616
INT_RGB BILINEAR/AREA_AVG 5000 Graphics 308.374
INT_RGB BILINEAR/AREA_AVG 5000 GetScaledInstance 1269.898
INT_RGB BILINEAR/AREA_AVG 2500 AffineTransformOp 68.137
INT_RGB BILINEAR/AREA_AVG 2500 Graphics 80.163
INT_RGB BILINEAR/AREA_AVG 2500 GetScaledInstance 444.968
INT_RGB BILINEAR/AREA_AVG 1000 AffineTransformOp 13.093
INT_RGB BILINEAR/AREA_AVG 1000 Graphics 15.396
INT_RGB BILINEAR/AREA_AVG 1000 GetScaledInstance 211.929
INT_RGB BILINEAR/AREA_AVG 500 AffineTransformOp 3.238
INT_RGB BILINEAR/AREA_AVG 500 Graphics 3.689
INT_RGB BILINEAR/AREA_AVG 500 GetScaledInstance 159.688
INT_RGB BILINEAR/AREA_AVG 100 AffineTransformOp 0.329
INT_RGB BILINEAR/AREA_AVG 100 Graphics 0.277
INT_RGB BILINEAR/AREA_AVG 100 GetScaledInstance 127.905
INT_RGB BICUBIC/AREA_AVG 10000 AffineTransformOp 4211.287
INT_RGB BICUBIC/AREA_AVG 10000 Graphics 4712.587
INT_RGB BICUBIC/AREA_AVG 10000 GetScaledInstance 2830.749
INT_RGB BICUBIC/AREA_AVG 5000 AffineTransformOp 1069.088
INT_RGB BICUBIC/AREA_AVG 5000 Graphics 1182.285
INT_RGB BICUBIC/AREA_AVG 5000 GetScaledInstance 1155.663
INT_RGB BICUBIC/AREA_AVG 2500 AffineTransformOp 263.003
INT_RGB BICUBIC/AREA_AVG 2500 Graphics 297.663
INT_RGB BICUBIC/AREA_AVG 2500 GetScaledInstance 444.497
INT_RGB BICUBIC/AREA_AVG 1000 AffineTransformOp 42.841
INT_RGB BICUBIC/AREA_AVG 1000 Graphics 48.605
INT_RGB BICUBIC/AREA_AVG 1000 GetScaledInstance 209.261
INT_RGB BICUBIC/AREA_AVG 500 AffineTransformOp 11.004
INT_RGB BICUBIC/AREA_AVG 500 Graphics 12.407
INT_RGB BICUBIC/AREA_AVG 500 GetScaledInstance 156.794
INT_RGB BICUBIC/AREA_AVG 100 AffineTransformOp 0.817
INT_RGB BICUBIC/AREA_AVG 100 Graphics 0.790
INT_RGB BICUBIC/AREA_AVG 100 GetScaledInstance 128.700
Run Code Online (Sandbox Code Playgroud)
可以看出,对于几乎所有情况,getScaledInstance与其他方法相比表现不佳(并且在扩展时可以通过较低质量来解释其似乎表现更好的少数情况).
该AffineTransformOp基础的方法似乎表现最佳,平均,唯一明显的例外是一个NEAREST_NEIGHBOR缩放TYPE_INT_RGB图像,其中Graphics基的方法似乎是一致的更快.
底线是:AffineTransformOp在JörnHorstmann的答案中,使用的方法似乎是为大多数应用案例提供最佳性能的方法.
dog*_*ane 11
您可以使用的ImageMagick来创建缩略图.
convert -define jpeg:size=500x180 hatching_orig.jpg -auto-orient \
-thumbnail 250x90 -unsharp 0x.5 thumbnail.gif
Run Code Online (Sandbox Code Playgroud)
要从Java中使用它,您可以尝试JMagick,它为ImageMagick提供Java(JNI)接口.或者您可以直接使用Runtime.exec或调用ImageMagick命令ProcessBuilder.
这对我有用:
private BufferedImage getScaledImage(BufferedImage src, int w, int h){
int original_width = src.getWidth();
int original_height = src.getHeight();
int bound_width = w;
int bound_height = h;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
BufferedImage resizedImg = new BufferedImage(new_width, new_height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setBackground(Color.WHITE);
g2.clearRect(0,0,new_width, new_height);
g2.drawImage(src, 0, 0, new_width, new_height, null);
g2.dispose();
return resizedImg;
}
Run Code Online (Sandbox Code Playgroud)
我还为png添加了白色背景
在不降低图像质量的情况下在Java中缩放图像的最快方法是使用双线性缩放.双线性是唯一好的,因为它的工作方式一次缩放50%的图像.以下代码来自Chet Haase的"肮脏富客户".他解释了本书中的多种技术,但这种技术在质量权衡方面具有最高的性能.
它支持所有类型的BufferedImages,因此不必担心兼容性.它还允许java2D硬件加速您的图像,因为计算是由Java2D完成的.如果您不理解最后一部分,请不要担心.最重要的是,这是最快的方法.
public static BufferedImage getFasterScaledInstance(BufferedImage img, int targetWidth, int targetHeight, boolean progressiveBilinear)
{
int type = (img.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
BufferedImage scratchImage = null;
Graphics2D g2 = null;
int w, h;
int prevW = ret.getWidth();
int prevH = ret.getHeight();
if(progressiveBilinear) {
w = img.getWidth();
h = img.getHeight();
}else{
w = targetWidth;
h = targetHeight;
}
do {
if (progressiveBilinear && w > targetWidth) {
w /= 2;
if(w < targetWidth) {
w = targetWidth;
}
}
if (progressiveBilinear && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
if(scratchImage == null) {
scratchImage = new BufferedImage(w, h, type);
g2 = scratchImage.createGraphics();
}
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(ret, 0, 0, w, h, 0, 0, prevW, prevH, null);
prevW = w;
prevH = h;
ret = scratchImage;
} while (w != targetWidth || h != targetHeight);
if (g2 != null) {
g2.dispose();
}
if (targetWidth != ret.getWidth() || targetHeight != ret.getHeight()) {
scratchImage = new BufferedImage(targetWidth, targetHeight, type);
g2 = scratchImage.createGraphics();
g2.drawImage(ret, 0, 0, null);
g2.dispose();
ret = scratchImage;
}
System.out.println("ret is "+ret);
return ret;
}
Run Code Online (Sandbox Code Playgroud)