我制作了这段代码,用两个因素来调整图像大小。它有效,但调整大小后图像质量非常糟糕!你能救我吗?
这是代码
public class ImageTest {
private static final int factor1 = 3;
private static final int factor2 = 4;
public static void main(String [] args){
JFileChooser cs = new JFileChooser();
cs.setFileSelectionMode(cs.DIRECTORIES_ONLY);
int i = cs.showOpenDialog(null);
if(i==cs.APPROVE_OPTION){
File f = cs.getSelectedFile();
File[] ff = f.listFiles();
for(int j=0;j<ff.length;j++){
String end = ff[j].getName().substring(ff[j].getName().indexOf(".")+1);
System.out.println(end);
try{
BufferedImage originalImage = ImageIO.read(ff[j]);
int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImageJpg = resizeImageWithHint(originalImage, type);
ImageIO.write(resizeImageJpg, end, new File("pr/"+ff[j].getName()));
}catch(IOException e){
e.printStackTrace();
}
}
}
}
private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type){
int IMG_WIDTH = (originalImage.getWidth()*factor1)/factor2;
int IMG_HEIGHT = (originalImage.getHeight()*factor1)/factor2;
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
return resizedImage;
}
}
我在网上看到resizeImageWithHint是在范围内完成的,以免损失质量..但确实如此!为什么?你可以帮帮我吗?
答案 0 :(得分:30)
我在这个主题上读过的最好的文章是The Perils of Image.getScaledInstance()(网络档案)。
简而言之:您需要使用多个调整大小的步骤才能获得良好的图像。文章中的助手方法:
public BufferedImage getScaledInstance(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;
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(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;
} while (w != targetWidth || h != targetHeight);
return ret;
}
答案 1 :(得分:10)
以下代码为我提供了保留纵横比的最高质量调整大小。 尝试了一些事情并阅读了其他答案中的几个条目。失去了两天,最后我用普通的Java方法获得了最好的结果(同时尝试了ImageMagick和java-image-scaling库):
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();
}
}
}
答案 2 :(得分:6)
知道问题已经过时了......我尝试了不同的解决方案,然后上网,我使用getScaledInstance()
得到了最好的结果,提供Image.SCALE_SMOOTH
作为参数。事实上,最终的图像质量确实更好。
我的代码如下:
final int THUMB_SIDE = 140;
try {
BufferedImage masterImage = ImageIO.read(startingImage);
BufferedImage thumbImage = new BufferedImage(THUMB_SIDE, THUMB_SIDE, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = thumbImage.createGraphics();
g2d.drawImage(masterImage.getScaledInstance(THUMB_SIDE, THUMB_SIDE, Image.SCALE_SMOOTH), 0, 0, THUMB_SIDE, THUMB_SIDE, null);
g2d.dispose();
String thumb_path = path.substring(0, path.indexOf(".png")) + "_thumb.png";
ImageIO.write(thumbImage, "png", new File(thumb_path));
} catch (IOException e) {
e.printStackTrace();
}
答案 3 :(得分:3)
如果您的图片来源是png
,请按照以下方式使用:
Image imgSmall = imgBig.getScaledInstance(
targetWidth, targetHeight, Image.SCALE_SMOOTH);
如果你想调整jpeg或gif的大小而没有太高的质量,我在2010年为此创建了一个库:beautylib on github在内部使用这个其他库:java-image-scaling。您可以直接查看源代码以查找有用的内容:https://github.com/felipelalli/beautylib/blob/master/src/br/eti/fml/beautylib/ResizeImage.java
答案 4 :(得分:2)
这些答案都无法帮助您获得所需的真实品质。在项目中包含thumbailator.jar(在此处下载表单):
https://code.google.com/p/thumbnailator/
https://code.google.com/p/thumbnailator/wiki/Downloads?tm=2
然后首先上传图像(作为文件,没有Thumbnailator - 它的用途是创建拇指,但你可以用它创建大图像),并将其调整到你想要的每个尺寸(使用Thumbnailator 800x600例如)。质量会很好。我正在寻找这么长时间,这个.jar帮我实现了我想要的目标。
答案 5 :(得分:1)
是的,我有同样的问题并解决了它们,请read my question(答案已嵌入问题中)。我尝试了 imgscalr 和 java-image-scaling 库,发现了第二个更好的质量。靠近显示器以了解缩略图示例之间的区别。
尽管我最初的想法,调整图像大小似乎是一件非常复杂的事情,你不想自己做。例如,我告诉 java-image-scaling 使用ResampleFilters.getLanczos3Filter()
来获得更好的结果。
它还解决了如何保存质量高于标准75的JPG,这会对缩略图产生不良影响。
我还编写了一个名为MyImage
的小类来帮助完成常见任务,例如从文件数组中读取图像,从文件读取图像,通过仅指定宽度或仅指定高度进行缩放,通过指定边界进行缩放框,通过指定宽度和高度进行缩放,并添加白色条带以使图像不失真并写入JPG文件。
答案 6 :(得分:0)
发布的所有方法对我都不起作用我必须减少QrCode的大小,但是使用上述方法质量很差并且扫描仪不起作用,如果我拍摄原始图片并在油漆中调整大小,扫描仪正在工作。
答案 7 :(得分:0)
在给定这些值的情况下,The Perils of Image.getScaledInstance()中使用的do while循环将陷入无限循环, w = 606; h = 505,targetWidth = 677,targetHeight = 505
这是一个简化的测试代码,您可以尝试一下。
public class LoopTest {
public static void main(String[] args) {
new LoopTest(true, 606, 505, 677, 505);
}
public LoopTest(boolean higherQuality, int w, int h, int targetWidth, int targetHeight) {
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
} while (w != targetWidth || h != targetHeight); // TODO Auto-generated constructor stub
}
}
一个快速的变通方法:定义循环计数的索引。如果索引大于等于10,则跳出循环。
答案 8 :(得分:-1)
答案: 删除提示 VALUE_INTERPOLATION_BILINEAR 和 VALUE_RENDERING_QUALITY 。
<强> 实施例 强>
public static BufferedImage resizeImage(BufferedImage image, int width, int height) {
// Temporary image
BufferedImage tmp = image;
// Result image
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Graphics object
Graphics2D graphics = (Graphics2D)result.createGraphics();
// Add rendering hints
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
// Draw tmp
graphics.drawImage(tmp, 0, 0, width, height, null);
// Dispose of graphics object
graphics.dispose();
// Return image result
return result;
}
注意: 由于某种原因,提示 VALUE_INTERPOLATION_BILINEAR 和 VALUE_RENDERING_QUALITY 模糊正在调整大小的图像。