[英]Re-sizing an image without losing quality
我制作了這段代碼以使用兩個因素調整圖像大小。 它可以工作,但是調整大小后圖像質量很差! 你能幫助我嗎?
這是代碼
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 是在范圍內完成的,以免質量下降..但確實如此! 為什么? 你能幫我解決這個問題嗎?
我讀過的關於這個主題的最好的文章是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;
}
以下代碼為我生成了最高質量的調整大小,並保留了縱橫比。 嘗試了一些事情並閱讀了其他答案中提供的幾個條目。 失去了兩天,最后我用普通的 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
沒有一個答案能幫助你獲得你想要的真正質量。 在您的項目中包含thumailator.jar(從這里下載它):
https://code.google.com/p/thumbnailator/
https://code.google.com/p/thumbnailator/wiki/Downloads?tm=2
然后首先上傳圖像(作為文件,沒有縮略圖 - 它的用途是創建拇指,但您當然可以使用它創建大圖像),並將其調整為您想要的每個尺寸(例如使用縮略圖 800x600)。 質量會很好。 我搜索了很長時間,這個 .jar 幫助我實現了我想要的。
是的,我遇到了同樣的問題並解決了它們,請閱讀我的問題(答案嵌入在問題中)。 我嘗試了imgscalr和java-image-scaling庫,發現第二個質量要好得多。 靠近顯示器以了解縮略圖示例之間的差異。
盡管我最初的想法是,調整圖像大小似乎是一件非常復雜的事情,你不想自己做。 例如,我告訴java-image-scaling使用ResampleFilters.getLanczos3Filter()
以獲得更好的結果。
它還解決了如何保存質量高於標准 75 的 JPG,這會產生不好的結果,尤其是對於縮略圖。
我還編寫了一個名為MyImage
來幫助完成常見任務,例如從字節數組中讀取圖像,從文件中讀取圖像,通過僅指定寬度或僅高度進行縮放,通過指定邊界框進行縮放,通過指定寬度和高度並添加白帶使圖像不失真並寫入 JPG 文件。
答案:刪除提示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 會模糊正在調整大小的圖像。
發布的所有方法對我都不起作用我必須減小 QrCode 大小,但是使用上述方法質量很差並且掃描儀不起作用,如果我拍攝原始圖片並在油漆中調整其大小,則掃描儀正在工作。
The Perils of Image.getScaledInstance() 中使用的 do while 循環將進入無限循環,給定這些值,w = 606; h = 505,目標寬度 = 677,目標高度 = 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,則跳出循環。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.