在Java中调整jpegs大小时丢失颜色(尝试使用多个库)

我已经尝试过在SO上发布的多个图像调整库,以及使用getScaledInstance的raw java.虽然一切都在大部分时间工作,但是有两个jpeg图像,每当调整大小时,颜色总是被弄乱.

第一张图片

结果:

第二张图片

结果:

我已经尝试过这些图像与多个库,包括Scalr,Thumbnailator和raw java使用image.getScaledInstance()(参见here代码),但结果是一样的.

任何想法是什么问题?

解决方法

我找到了一个解决方案,从 this answer的很多帮助:
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImgUtility
{

    /**
     * Takes a file,and resizes it to the given width and height,while keeping
     * original proportions. Note: It resizes a new file rather than resizing 
     * the original one. Resulting file is always written as a png file due to issues
     * with resizing jpeg files which results in color loss. See:
     * https://stackoverflow.com/a/19654452/49153 
     * for details,including the comments.
     * 
     */    
    public static File resize(File file,int width,int height) throws Exception
    {
        Image img = Toolkit.getDefaultToolkit().getImage( file.getAbsolutePath() );
        loadCompletely(img);
        BufferedImage bm = toBufferedImage(img);
        bm = resize(bm,width,height);

        StringBuilder sb = new StringBuilder();
        sb.append( bm.hashCode() ).append(".png");
        String filename = sb.toString(); 

        File result = new File( filename );
        ImageIO.write(bm,"png",result);

        return result;
    }

    public static BufferedImage toBufferedImage(Image img)
    {
        if (img instanceof BufferedImage)
        {
            return (BufferedImage) img;
        }

        BufferedImage bimage = new BufferedImage(img.getWidth(null),img.getHeight(null),BufferedImage.TYPE_INT_ARGB);

        bimage.getGraphics().drawImage(img,null);
        bimage.getGraphics().dispose();

        return bimage;
    }

    public static BufferedImage resize(BufferedImage image,int areaWidth,int areaHeight)
    {
        float scaleX = (float) areaWidth / image.getWidth();
        float scaleY = (float) areaHeight / image.getHeight();
        float scale = Math.min(scaleX,scaleY);
        int w = Math.round(image.getWidth() * scale);
        int h = Math.round(image.getHeight() * scale);

        int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        boolean scaleDown = scale < 1;

        if (scaleDown) {
            // multi-pass bilinear div 2
            int currentW = image.getWidth();
            int currentH = image.getHeight();
            BufferedImage resized = image;
            while (currentW > w || currentH > h) {
                currentW = Math.max(w,currentW / 2);
                currentH = Math.max(h,currentH / 2);

                BufferedImage temp = new BufferedImage(currentW,currentH,type);
                Graphics2D g2 = temp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2.drawImage(resized,currentW,null);
                g2.dispose();
                resized = temp;
            }
            return resized;
        } else {
            Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;

            BufferedImage resized = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = resized.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,hint);
            g2.drawImage(image,w,null);
            g2.dispose();
            return resized;
        }
    }


    /**
     * Since some methods like toolkit.getImage() are asynchronous,this
     * method should be called to load them completely.
     */
    public static void loadCompletely (Image img)
    {
        MediaTracker tracker = new MediaTracker(new JPanel());
        tracker.addImage(img,0);
        try {
            tracker.waitForID(0);
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);
        }
    }
}

相关文章

ArrayList简介:ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增...
一、进程与线程 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。 线程...
本文为博客园作者所写:&#160;一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 简单的一个类...
#############java面向对象详解#############1、面向对象基本概念2、类与对象3、类和对象的定义格式4、...
一、什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错。在java中,阻止当前方法或作用域...
Collection接口 Collection接口 Collection接口 Collection是最基本的集合接口,一个Collection代表一组...