图像大小调整质量(Java)
我有一个开源应用程序,可以将照片上传到Facebook。为了节省带宽,照片在上传前会自动调整大小(Facebook规定了最大尺寸限制)。一些人抱怨过照片质量,事实上,你可以看到不同之处(请参阅一些演示图像) 因此,我的问题是,在Java中缩小图像(即照片)的“最佳”方式是什么,而不损失质量,或者至少是质量损失/工件最小图像大小调整质量(Java),java,image,resize,jpeg,photo,Java,Image,Resize,Jpeg,Photo,我有一个开源应用程序,可以将照片上传到Facebook。为了节省带宽,照片在上传前会自动调整大小(Facebook规定了最大尺寸限制)。一些人抱怨过照片质量,事实上,你可以看到不同之处(请参阅一些演示图像) 因此,我的问题是,在Java中缩小图像(即照片)的“最佳”方式是什么,而不损失质量,或者至少是质量损失/工件最小 您可以查看我的当前代码(通过调整代码大小)。您使用的渲染提示是什么?通常双三次重采样是最好的。在你链接到的照片中,它们非常参差不齐,这让我觉得你是在用最近的邻居作为暗示 在链接到
您可以查看我的当前代码(通过调整代码大小)。您使用的渲染提示是什么?通常双三次重采样是最好的。在你链接到的照片中,它们非常参差不齐,这让我觉得你是在用最近的邻居作为暗示
在链接到的类中,在
paintComponent
方法中,它使用了六种不同的方法来调整图像的大小。你试过这六种方法了吗?我试过了所有方法——包括技巧,我能说的是你最好在任何界面上使用ImageMagick。Java的图像库在这方面还没有达到标准。你需要支持如此多的格式和算法才能使它正确。经过几次令人沮丧的实验后,我发现了以下内容,并在我的项目中采用了多通道方法
为此,我将getScaleInstance()方法复制到我的缩略图生成器类中,将我的图像读取方法更改为使用ImageIO(该方法返回一个BuffereImage),现在我非常高兴
我将结果与Photoshop CS3中的调整大小进行了比较,结果基本相同。Phil,我不知道您最终使用了哪种解决方案,但如果您:
- 避免JDK不支持的BuffereImage类型
- 使用增量缩放
- 使用增量缩放时,请坚持使用双三次
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 640);
第二个参数是imgscalr用于缩放图像的边界宽度和高度——即使传递了无效的维度,也要保持其比例正确——有很多,但这是最简单的用法
例如,如果Facebook将图像限制为800x600像素,您需要的用例如下所示:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 800, 600);
这将确保图像保持在受支持的最佳图像类型中,并使用Java能够获得的最高质量方法进行缩放
在我自己的高分辨率测试中,我没有注意到使用此库/这些方法缩放的图像存在任何差异,除非图像被ImageIO加载程序放入支持较差的图像类型中——例如,GIF经常出现这种情况。如果你就这样离开它们,而不把它们从那些支持不好的类型中解救出来,它最终看起来真的很不稳定,很糟糕
原因是Java2D团队实际上对JDK可以处理的所有不同类型的BuffereImage都有不同的硬件加速管道-这些不太常见的映像类型的子集都会在Java2D的封面下使用相同的软件渲染管道,导致图像质量差,有时甚至完全不正确。这是一个很好的解释,我只是把逻辑直接写进了图书馆
最好支持的两种类型是buffereImage.TYPE_INT_RGB和_ARGB(如果您感兴趣)。若要使用自定义质量调整图像大小,请使用thumbnailator.jar 示例代码
我希望在保持纵横比的情况下调整高质量的尺寸。 尝试了一些事情,读了一些条目。损失了两天,最后我用纯Java方法得到了最好的结果(还尝试了ImageMagick和Java图像缩放库):
public static boolean resizeUsingJavaAlgo(字符串源、文件目的、int-width、int-height)抛出IOException{
BuffereImage sourceImage=ImageIO.read(新文件输入流(源));
double ratio=(double)sourceImage.getWidth()/sourceImage.getHeight();
如果(宽度<1){
宽度=(整数)(高度*比率+0.4);
}否则,如果(高度<1){
高度=(整数)(宽度/比率+0.4);
}
图像缩放=sourceImage.getScaledInstance(宽度、高度、图像缩放面积平均值);
BuffereImage bufferedScaled=新的BuffereImage(scaled.getWidth(null)、scaled.getHeight(null)、BuffereImage.TYPE\u INT\u RGB);
Graphics2D g2d=bufferedScaled.createGraphics();
g2d.setRenderingHint(renderingHits.KEY\u插值,renderingHits.VALUE\u插值双三次);
g2d.drawImage(缩放,0,0,宽度,高度,空);
dest.createNewFile();
writeJpeg(bufferedScaled,dest.getCanonicalPath(),1.0f);
返回true;
}
/**
*编写一个JPEG文件,设置压缩质量。
*
*@param image要保存的缓冲区映像
*@param destFile目标文件(绝对或相对路径)
*@param-quality是介于0和1之间的浮点,其中1表示未压缩。
*@在写入文件时引发IOException
*/
私有静态void writeJpeg(buffereImage图像、字符串destFile、浮点质量)
抛出IOException{
ImageWriter=null;
FileImageOutputStream输出=null;
试一试{
writer=ImageIO.getImageWritersByFormatName(“jpeg”).next();
ImageWriteParam参数=writer.getDefaultWriteParam();
参数setCompressionMode(ImageWriteParam.MODE_显式);
参数设置压缩质量(质量);
输出=新文件ImageOutputStream(新文件(destFile));
writer.setOutput(输出);
IIOImage IIOImage=新IIOIma
public static boolean resizeUsingJavaAlgo(String source, File dest, int width, int height) throws IOException {
BufferedImage sourceImage = ImageIO.read(new FileInputStream(source));
double ratio = (double) sourceImage.getWidth()/sourceImage.getHeight();
if (width < 1) {
width = (int) (height * ratio + 0.4);
} else if (height < 1) {
height = (int) (width /ratio + 0.4);
}
Image scaled = sourceImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedScaled.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.drawImage(scaled, 0, 0, width, height, null);
dest.createNewFile();
writeJpeg(bufferedScaled, dest.getCanonicalPath(), 1.0f);
return true;
}
/**
* Write a JPEG file setting the compression quality.
*
* @param image a BufferedImage to be saved
* @param destFile destination file (absolute or relative path)
* @param quality a float between 0 and 1, where 1 means uncompressed.
* @throws IOException in case of problems writing the file
*/
private static void writeJpeg(BufferedImage image, String destFile, float quality)
throws IOException {
ImageWriter writer = null;
FileImageOutputStream output = null;
try {
writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
output = new FileImageOutputStream(new File(destFile));
writer.setOutput(output);
IIOImage iioImage = new IIOImage(image, null, null);
writer.write(null, iioImage, param);
} catch (IOException ex) {
throw ex;
} finally {
if (writer != null) {
writer.dispose();
}
if (output != null) {
output.close();
}
}
}