Java保真组合图片以及生成缩略图

866 阅读5分钟

业务需求:在推送商品给买家的时候,可能会推送多个商品,每个商品对应一张图片,现在只需要发送一条消息,那么就需要将多张图片组合成一张自定义大小的图片。

1、举例

尺寸:648*300 尺寸:1080*454 尺寸:600*300 尺寸:800*500

如果传进来了两张图片,那么合成自定义大小的二宫格图片,如果传进来四张图片,合成自定义大小的四宫格图片(九宫格等等的可以再自己增加一下

2、尝试先等比缩小或放大图片,然后组合(测试后发现好像不太行)

  • 1、先尝试生成图片自定义大小的缩略图
/**
     * 生成缩略图
     * 
     * @param imgsrc 图片路径
     * @param imgdist 输出路径
     * @param widthdist 缩放后图片长
     * @param heightdist 缩放后图片宽
     */
    public static void reduceImg(String imgsrc, String imgdist, int widthdist, int heightdist) {
        try {
            File srcfile = new File(imgsrc);
            if (!srcfile.exists()) {
                return;
            }
            Image src = javax.imageio.ImageIO.read(srcfile);
            BufferedImage tag= new BufferedImage(widthdist, heightdist, BufferedImage.TYPE_INT_RGB);
            tag.getGraphics().drawImage(src.getScaledInstance(widthdist, heightdist,  Image.SCALE_SMOOTH), 0, 0,  null);

            FileOutputStream out = new FileOutputStream(imgdist);
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            encoder.encode(tag);
            out.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
public static void main(String[] args) {
        try {
            ImageUtils.reduceImg("/Users/weiwanxi/Downloads/写作图片/aqs.jpeg", "/Users/weiwanxi/Downloads/写作图片/treasureMap.jpg", 324, 150);
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }

测试之后生成的图片:

这一步缩略图其实是可以的,按照固定大小缩放也没有失真,至于我说的不行,是下面这一步。

  • 2、先尝试生成四张图片的缩略图,然后组合成四宫格
public class ImageUtils2 {

    /**
     * 合成图片
     *
     * @param imageList 图片路径集合
     * @param width 合成图片的长
     * @param height 合成图片的宽
     * @throws Exception
     */
    public static void syntheticImage(List<String> imageList, int width, int height) throws Exception {
        // 如果只有一张图片,直接返回
        if (imageList.size() == 1){
            return;
        }
        // 构造一个类型为预定义图像类型之一的BufferedImage,宽高为传进来的参数
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 创建输出流
        FileOutputStream out = new FileOutputStream("/Users/weiwanxi/Downloads/写作图片/treasureMap.jpg");
        // 制图的宽(长是一样的)
        int syntheticHeight = 0;
        // 图片缩放的大小
        int zoomWeight, zoomHeight = 0;
        // 二宫格
        if (imageList.size() == 2){
            zoomWeight = width / 2;
            zoomHeight = height / 2;
            syntheticHeight = height;
        } // 四宫格
        else if (imageList.size() <= 4){
            zoomWeight = width / 4;
            zoomHeight = height / 4;
            syntheticHeight = height/ 2;
        }else {
            throw new RuntimeException();
        }
        BufferedImage img = null;
        for (int i = 0; i < imageList.size(); i++){
            // 绘制合成图像
            Graphics g = bufferedImage.createGraphics();
            try {
                File file = new File(imageList.get(i));
                img = reduceImg(file, zoomWeight, zoomHeight);
                assert img != null;
                switch (i){
                    case 0:
                        g.drawImage(img, 0, 0, width/2, syntheticHeight, null);
                        break;
                    case 1:
                        g.drawImage(img, width/2, 0, width/2, syntheticHeight, null);
                        break;
                    case 2:
                        g.drawImage(img, 0, height/2, width/2, height/2, null);
                        break;
                    case 3:
                        g.drawImage(img, width/2, height/2, width/2, height/2, null);
                    default:
                        break;
                }
            }catch (Exception e){
                throw new RuntimeException("绘图出现异常");
            }finally {
                // 释放此图形的上下文以及它使用的所有系统资源。
                g.dispose();
            }
        }
        //将绘制的图像生成至输出流
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(bufferedImage);
        //关闭输出流
        out.close();
        System.out.println("合成图片完成咯。。");
    }

    /**
     * 生成缩略图
     *
     * @param image
     * @param width
     * @param height
     * @return
     */
    public static BufferedImage reduceImg(File image, int width, int height) {
        BufferedImage tag = null;
        try {
            Image src = ImageIO.read(image);
            tag= new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 绘制图片
            tag.getGraphics().drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0,  null);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return tag;
    }
}

测试:

public static void main(String[] args) {
        try {
            List<String> list = new ArrayList<>();
            list.add("/Users/weiwanxi/Downloads/写作图片/aqs.jpeg");
            list.add("/Users/weiwanxi/Downloads/写作图片/说着说着.jpg");
            list.add("/Users/weiwanxi/Downloads/写作图片/线程池.png");
            list.add("/Users/weiwanxi/Downloads/写作图片/乐观锁与悲观锁.jpg");
            ImageUtils2.syntheticImage(list, 648, 300);
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }

合成后图片:648*300

可以看到,这样合成的图片失真是比较严重的,字都模糊不清,然后我就尝试了下面这种办法。

3、切割合成图片的大小,不在比例缩放,由image自动填充

public class ImageUtils {

    /**
     * 合成图片
     *
     * @param imageList 图片路径集合
     * @param width 合成图片的长
     * @param height 合成图片的宽
     * @throws Exception
     */
    public static void syntheticImage(List<String> imageList, int width, int height) throws Exception {
        // 如果只有一张图片,直接返回
        if (imageList.size() == 1){
            return;
        }
        // 构造一个类型为预定义图像类型之一的BufferedImage,宽高为传进来的参数
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 创建输出流
        FileOutputStream out = new FileOutputStream("/Users/weiwanxi/Downloads/写作图片/treasureMap2.jpg");
        // 制图的宽(长是一样的)
        int syntheticHeight = 0;
        // 二宫格
        if (imageList.size() == 2){
            syntheticHeight = height;
        } // 四宫格
        else if (imageList.size() <= 4){
            syntheticHeight = height/ 2;
        }else {
            throw new RuntimeException();
        }
        BufferedImage img = null;
        for (int i = 0; i < imageList.size(); i++){
            // 绘制合成图像
            Graphics g = bufferedImage.createGraphics();
            try {
                File file = new File(imageList.get(i));
                img = javax.imageio.ImageIO.read(file);
                assert img != null;
                switch (i){
                    case 0:
                        g.drawImage(img, 0, 0, width/2, syntheticHeight, null);
                        break;
                    case 1:
                        g.drawImage(img, width/2, 0, width/2, syntheticHeight, null);
                        break;
                    case 2:
                        g.drawImage(img, 0, height/2, width/2, height/2, null);
                        break;
                    case 3:
                        g.drawImage(img, width/2, height/2, width/2, height/2, null);
                    default:
                        break;
                }
            }catch (Exception e){
                throw new RuntimeException("绘图出现异常");
            }finally {
                // 释放此图形的上下文以及它使用的所有系统资源。
                g.dispose();
            }
        }
        //将绘制的图像生成至输出流
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(bufferedImage);
        //关闭输出流
        out.close();
        System.out.println("合成图片完成咯。。");
    }
  }

测试(二宫格):

public static void main(String[] args) {
        try {
            List<String> list = new ArrayList<>();
            list.add("/Users/weiwanxi/Downloads/写作图片/aqs.jpeg");
            list.add("/Users/weiwanxi/Downloads/写作图片/说着说着.jpg");
//            list.add("/Users/weiwanxi/Downloads/写作图片/线程池.png");
//            list.add("/Users/weiwanxi/Downloads/写作图片/乐观锁与悲观锁.jpg");
            ImageUtils.syntheticImage(list, 648, 300);
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }

合成后图片:648*300

测试(四宫格):

public static void main(String[] args) {
        try {
            List<String> list = new ArrayList<>();
            list.add("/Users/weiwanxi/Downloads/写作图片/aqs.jpeg");
            list.add("/Users/weiwanxi/Downloads/写作图片/说着说着.jpg");
            list.add("/Users/weiwanxi/Downloads/写作图片/线程池.png");
            list.add("/Users/weiwanxi/Downloads/写作图片/乐观锁与悲观锁.jpg");
            ImageUtils.syntheticImage(list, 648, 300);
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }

合成后图片:648*300

这张图片看起来失真情况就比上面那张好很多了,文中示例只写到了四宫格,如果需要九宫格的话,可以再补充一下,增加一个九宫格的图片切割长宽即可!

4、公众号

如果你觉得我的文章对你有帮助话,欢迎关注我的微信公众号:"一个快乐又痛苦的程序员"(无广告,单纯分享原创文章、已pj的实用工具、各种Java学习资源,期待与你共同进步) 公众号