Java - resize image without losing quality

前端 未结 7 1636
轮回少年
轮回少年 2020-11-29 15:48

I have 10,000 photos that need to be resized so I have a Java program to do that. Unfortunately, the quality of the image is poorly lost and I don\'t have access to the unco

7条回答
  •  自闭症患者
    2020-11-29 16:50

    Given your input image, the method from the answer in the first link in the comments (kudos to Chris Campbell) produces one of the following thumbnails:

    enter image description here enter image description here

    (The other one is the thumbnail that you created with MS Paint. It's hard to call one of them "better" than the other...)

    EDIT: Just to point this out as well: The main problem with your original code was that you did not really scale the image in multiple steps. You just used a strange loop to "compute" the target size. The key point is that you actually perform the scaling in multiple steps.

    Just for completeness, the MVCE

    (Edit: I mentioned Chris Campbell and referred to the source via the comments, but to make this more clear here: The following is based on the article The Perils of Image.getScaledInstance() )

    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.Transparency;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Iterator;
    
    import javax.imageio.IIOImage;
    import javax.imageio.ImageIO;
    import javax.imageio.ImageWriteParam;
    import javax.imageio.ImageWriter;
    import javax.imageio.stream.ImageOutputStream;
    import javax.imageio.stream.MemoryCacheImageOutputStream;
    
    public class ResizeQuality
    {
        public static void main(String[] args) throws IOException
        {
            BufferedImage image = ImageIO.read(new File("X0aPT.jpg"));
            BufferedImage scaled = getScaledInstance(
                image, 51, 75, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
            writeJPG(scaled, new FileOutputStream("X0aPT_tn.jpg"), 0.85f);
        }
    
        public static 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;
        }
    
        public static void writeJPG(
            BufferedImage bufferedImage,
            OutputStream outputStream,
            float quality) throws IOException
        {
            Iterator iterator =
                ImageIO.getImageWritersByFormatName("jpg");
            ImageWriter imageWriter = iterator.next();
            ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
            imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            imageWriteParam.setCompressionQuality(quality);
            ImageOutputStream imageOutputStream =
                new MemoryCacheImageOutputStream(outputStream);
            imageWriter.setOutput(imageOutputStream);
            IIOImage iioimage = new IIOImage(bufferedImage, null, null);
            imageWriter.write(null, iioimage, imageWriteParam);
            imageOutputStream.flush();
        }    
    }
    

提交回复
热议问题