13
回答
用java改变图片的存储大小
华为云4核8G,高性能云服务器,免费试用   
请问如何改变图片的大小,不是分辩率的大小,而是存储大小,比如我想让一张图片变为200k,请问怎么做到,网上一些文章说改变质量,但是质量跟大小的关系不知道是怎么计算的,没有一个公式可以算出应该设定多少的质量值。
举报
romi
发帖于6年前 13回/10K+阅
共有13个答案 最后回答: 3年前
哇,这个太难了吧,好像没听说有这么干的
--- 共有 4 条评论 ---
feiniu5566回复 @romi : 这个需求我见过,不过我是用ps把图片大小改了 4年前 回复
romi呵呵,应该有办法吧,JPEGEncodeParam里面有一个setQuality的方法,就是不知道这个quality和图片的大小有什么关系,可能存在关系的因素很多。 6年前 回复
红薯回复 @romi : 我觉得这个需求本身就很扯淡 6年前 回复
romi不是吧,大牛,连你也没有做过,正想问你呢。我就恰恰有这样一个需求,你说悲不悲哀啊。 6年前 回复

翻翻冈萨雷斯那本数字图像处理第八章看看有没有相关的?

我手头上有一本,但是不大敢翻开。。

--- 共有 1 条评论 ---
romi为什么呢? 6年前 回复
去看看BufferedImage类的那几个参数把,直接变成固定的200K这玩意怕是有难度。通过改变图片质量改变大小是可能的,比如 TYPE_4BYTE_ABGR变成 TYPE_BYTE_INDEXED,每一个像素从4个byte变成了一个byte。这种转换和图片格式以及像素分布有关,没有一个确定的公式来计算。
--- 共有 3 条评论 ---
Monkey回复 @romi : new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED); 6年前 回复
romi你说变它的TYPE_BYTE_INDEXED,怎么改啊?? 6年前 回复
romi不一定要刚好200k,就是在200k左右。 6年前 回复

引用来自“Monkey”的答案

去看看BufferedImage类的那几个参数把,直接变成固定的200K这玩意怕是有难度。通过改变图片质量改变大小是可能的,比如 TYPE_4BYTE_ABGR变成 TYPE_BYTE_INDEXED,每一个像素从4个byte变成了一个byte。这种转换和图片格式以及像素分布有关,没有一个确定的公式来计算。

这个改得到。

public static boolean compressPic(String srcFilePath, String descFilePath) throws IOException {
        File file = null;
        BufferedImage src = null;
        FileOutputStream out = null;
        ImageWriter imgWrier;
        ImageWriteParam imgWriteParams;

        // 指定写图片的方式为 jpg
        imgWrier = ImageIO.getImageWritersByFormatName("jpg").next();
        imgWriteParams = new javax.imageio.plugins.jpeg.JPEGImageWriteParam(
                null);
        // 要使用压缩,必须指定压缩方式为MODE_EXPLICIT
        imgWriteParams.setCompressionMode(imgWriteParams.MODE_EXPLICIT);
        // 这里指定压缩的程度,参数qality是取值0~1范围内,
        imgWriteParams.setCompressionQuality((float) 1);
        imgWriteParams.setProgressiveMode(imgWriteParams.MODE_DISABLED);
        ColorModel colorModel =ImageIO.read(new File(srcFilePath)).getColorModel();// ColorModel.getRGBdefault();
        // 指定压缩时使用的色彩模式
//        imgWriteParams.setDestinationType(new javax.imageio.ImageTypeSpecifier(
//                colorModel, colorModel.createCompatibleSampleModel(16, 16)));
        imgWriteParams.setDestinationType(new javax.imageio.ImageTypeSpecifier(
                colorModel, colorModel.createCompatibleSampleModel(16, 16)));

        try {
            if (isBlank(srcFilePath)) {
                return false;
            } else {
                file = new File(srcFilePath);System.out.println(file.length());
                src = ImageIO.read(file);
                out = new FileOutputStream(descFilePath);

                imgWrier.reset();
                // 必须先指定 out值,才能调用write方法, ImageOutputStream可以通过任何
                // OutputStream构造
                imgWrier.setOutput(ImageIO.createImageOutputStream(out));
                // 调用write方法,就可以向输入流写图片
                imgWrier.write(null, new IIOImage(src, null, null),
                        imgWriteParams);
                out.flush();
                out.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

public static boolean isBlank(String string) {
        if (string == null || string.length() == 0 || string.trim().equals("")) {
            return true;
        }
        return false;
    }

--- 共有 1 条评论 ---
Monkey晕,你直接new一个新的iamge,draw上去就是可以了。这么麻烦干嘛。 6年前 回复

再补充一下,图片保存需要使用ImageIO,java本身支持BMP, bmp, jpg, JPG, jpeg, wbmp, png, PNG, JPEG, WBMP, GIF, gif这些文件格式的图片,jpg的压缩比是最高的,这里是另外一个意义上的压缩。我之前所说的只是在图片的颜色存储上做手脚,然后还要按照文件格式再进行一次压缩。

通常而言,创建一个和目标图一样大的索引图,TYPE_BYTE_BINARY,然后将目标图draw上去,用jpg格式保存,这样的压缩应该是最大的(除非你用黑白灰度图那就变成更小了)。此外可以通过这种graphics的RenderingHints选择速度优先的方式来减少颜色特征值也可减小数据。

图片大小主要还是受大小和颜色丰富限制的,如果图片大颜色又丰富拿压缩起来就非常吃力。

--- 共有 3 条评论 ---
romi回复 @Monkey : 保存什么格式倒无所谓,主要是这个需求是如果超过指定大小就把大小压为与指定大小差不多的大小。 6年前 回复
Monkey回复 @romi : 你直接全部保存为jpg,再超过了,用户自己处理。 6年前 回复
romi唉呀,好昏。 6年前 回复

引用来自“Monkey”的答案

再补充一下,图片保存需要使用ImageIO,java本身支持BMP, bmp, jpg, JPG, jpeg, wbmp, png, PNG, JPEG, WBMP, GIF, gif这些文件格式的图片,jpg的压缩比是最高的,这里是另外一个意义上的压缩。我之前所说的只是在图片的颜色存储上做手脚,然后还要按照文件格式再进行一次压缩。
再进行一次压缩是怎么压缩的?
--- 共有 1 条评论 ---
Monkey这是java按照文件格式进行的,是这个图片文件格式的规范。不如java保存的jpg可以再画图板打开,就是这个规范 6年前 回复
分辨率变小,质量变小,都能使得图片缩小,那么,你是要哪种呢?你这个不定,是没法做的。组合情况太多了。
--- 共有 4 条评论 ---
romi回复 @Monkey : 可以q聊吗? 6年前 回复
Andre.Z回复 @romi : 假设图片就是色块,那么,要到你的大小,直接缩放,应该就行了,但是,普通图片不是色块,像素点存在位置不一样,那么,就多试几次,到你要的为止。方法么,可以简单的2分法或其它,逐渐逼近,其它的,我是不知道了。 6年前 回复
Monkey回复 @romi : 我劝你还是放弃这种200k的想法,图片大了你就是把吃奶力气试出来都没用。 6年前 回复
romi都可以,只是能变小,变到指定的小,比如变到200k左右。 6年前 回复
可以这样。。。如果图片大于200K,对其进行压缩,压缩比为9,出来之后如果还是大再压,压缩比8,最后终于少于200,不过图片质量,惨不忍睹了~~~
很好奇你们产品的想法,如果说是往小了压,那压缩的实际结果也是没法准确控制的,每张源图大小还不一定呢,压缩仅仅是一个不确定的经验比例,谁敢说一张图按多少质量比压完了就是多少K。
顶部