重新调整图像大小而不会降低质量

我制作了这个代码,用两个因素调整图像大小。 它有效,但resize后图像质量非常糟糕! 你可以帮我吗?

这是代码

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是在范围内完成的,以免损失质量..但确实如此! 为什么? 你能帮我这个吗?

我在这个主题上读过的最好的文章是Image of Perils of Image.getScaledInstance() (web archive)。

简而言之:您需要使用多个resize的步骤才能获得良好的图像。 文章中的助手方法:

 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; } 

以下代码生成了最高质量的resize并保留了宽高比。 尝试了一些事情并阅读了其他答案中提到的几个条目。 失去了两天,最后我用普通的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(); } } } 

知道问题已经过时了……我尝试了不同的解决方案,然后上网,我使用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(); } 

如果你的图像源是png那么使用如下:

 Image imgSmall = imgBig.getScaledInstance( targetWidth, targetHeight, Image.SCALE_SMOOTH); 

如果你想调整jpeg或gif的大小而没有太多的质量,我在2010年为此创建了一个库: github上的beautylib在内部使用了另一个库: java-image-scaling 。 您可以直接看到源代码以找到有用的东西: https : //github.com/felipelalli/beautylib/blob/master/src/br/eti/fml/beautylib/ResizeImage.java

没有一个答案可以帮助您获得您想要的真实质量。 在项目中包含thumbailator.jar(在此处下载表单):

https://code.google.com/p/thumbnailator/

https://code.google.com/p/thumbnailator/wiki/Downloads?tm=2

然后首先上传图像(作为文件,没有Thumbnailator – 它的用途是创建拇指,但你可以用它创建大图像),并将其调整到你想要的每个维度(例如用Thumbnailator 800×600)。 质量会很好。 我正在寻找这么长时间,这个.jar帮我实现了我想要的。

是的,我有同样的问题并解决了它们,请阅读我的问题 (答案已嵌入问题中)。 我尝试了imgscalrjava-image-scaling库,发现了第二个更好的质量。 靠近显示器以了解缩略图示例之间的差异。

尽管我最初的想法,调整图像大小似乎是一件非常复杂的事情,你不想自己做。 例如,我告诉java-image-scaling使用ResampleFilters.getLanczos3Filter()来获得更好的结果。

它还解决了如何保存质量高于标准75的JPG,这会产生一个糟糕的结果,特别是对于缩略图。

我还编写了一个名为MyImage来帮助完成常见任务,例如从字节数组中读取图像,从文件中读取图像,通过仅指定宽度或仅指定高度进行缩放,通过指定边界框进行缩放,通过指定宽度进行缩放高度并添加白色条带以使图像不失真并写入JPG文件。

发布的所有方法都不适合我,我必须减少QrCode的大小,但是使用上述方法质量很差,扫描仪不起作用,如果我拍摄原始照片并在油漆中resize,扫描仪正在工作。

答案:删除提示VALUE_INTERPOLATION_BILINEARVALUE_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_BILINEARVALUE_RENDERING_QUALITY会模糊正在resize的图像。