• 【Java】将Base64格式的图片等比伸缩至目标尺寸代码实现


    等比伸缩

    需求

    前端页面上传的图片是Base64字符串,需要根据目标尺寸进行伸缩,不能改变图片的比例

    代码实现

    使用图片处理工具:thumbnailator

    引入Maven依赖

            
                net.coobird
                thumbnailator
                0.4.8
            
    
    • 1
    • 2
    • 3
    • 4
    • 5

    核心代码:

    import net.coobird.thumbnailator.Thumbnails;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.IOException;
    import java.math.RoundingMode;
    import java.text.DecimalFormat;
    import java.util.Base64;
    import java.util.Objects;
    
    public class Test {
        public static final String IMAGE_BASE64_PREFIX_REG = "data:image/[^;]+;base64,";
      	// 你的测试数据
        private static final String IMG_BASE64 = "";
        private static final String FILE_PATH = "/Users/xdf/Desktop/Temp/test.png";
        private static Integer targetHeight = 400;
        private static Integer targetWidth = 400;
    
        public static void main(String[] args) throws IOException {
            DecimalFormat df = new DecimalFormat("#.##");
            df.setRoundingMode(RoundingMode.FLOOR);
            String image = IMG_BASE64.replaceAll(IMAGE_BASE64_PREFIX_REG, "");
            BufferedImage bufferedImage = convertBase64ToImage(image);
            if (Objects.isNull(bufferedImage)) {
                System.err.println("covert base64 image error.");
                return;
            }
            int height = bufferedImage.getHeight();
            int width = bufferedImage.getWidth();
            // 计算缩放比例,目标尺寸/当前尺寸,大于0则需要放大(目标大),小于0则需要缩放(目标小)
            double heightScale = Double.parseDouble(df.format((double) targetHeight / height));
            double widthScale = Double.parseDouble(df.format((double) targetWidth / width));
            System.out.printf("[current height]: %d, [current width]: %d \n[target height]: %d, [target width]: %d\n", height, width, targetHeight, targetWidth);
            // 放大时,需要以目标较长的一边作为放大基准;缩小时,需要以当前尺寸较短的一边为基准(当目标尺寸大时,分子越大,差距越大,当目标尺寸小时,分母越小,差距越大,两种情况都会导致商更大)
            double scale = Math.max(heightScale, widthScale);
            System.out.printf("[heightScale]: %s, [widthScale]: %s, [final scale]: %s \n", heightScale, widthScale, scale);
            BufferedImage targetImage = Thumbnails.of(bufferedImage).scale(scale).asBufferedImage();
            ImageIO.write(targetImage, "png", new File(FILE_PATH));
        }
    
        public static BufferedImage convertBase64ToImage(String base64String) {
            try {
                // 解码Base64字符串为字节数组
                byte[] imageBytes = Base64.getDecoder().decode(base64String);
                // 创建ByteArrayInputStream对象
                ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
                // 将ByteArrayInputStream对象转换为BufferedImage对象
                BufferedImage bufferedImage = ImageIO.read(bis);
                // 关闭ByteArrayInputStream
                bis.close();
                // 返回BufferedImage对象
                return bufferedImage;
            } catch (Exception e) {
                System.err.println(e);
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    这个方案是保证图片完整的情况下,尽量接近目标尺寸,如果要精确等于目标尺寸,还需要用到裁剪或者下面的非等比方法,做微调。

    非等比

    使用jdk自带的BufferedImage实现:

        public static String resizeBase64Image(final String originalBase64Image, final Integer targetWidth, final Integer targetHeight) throws Exception {
            // base64转为BufferedImage
            log.info("start to resize picture...");
            long start = System.currentTimeMillis();
            BufferedImage originalImage = convertBase64ToImage(originalBase64Image);
            assert originalImage != null;
            // 将图片伸缩至目标长宽(非等比)
            BufferedImage targetImage = resizeImage(originalImage, targetWidth, targetHeight);
            String targetBase64Image = convertImageToBase64(targetImage);
            log.info("resize image finished. [cost]: {} ms", System.currentTimeMillis() - start);
            return targetBase64Image;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    相关方法:

        /**
         * 通过BufferedImage图片流调整图片大小
         * 在创建新的 BufferedImage 实例时,将图像类型设置为 BufferedImage.TYPE_INT_RGB,它不支持透明度。原始图像的透明区域在目标图像中会变成黑色。
         * 如果想保留原始图像的透明区域,需要使用支持透明度的图像类型,比如 BufferedImage.TYPE_INT_ARGB。
         */
        public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException {
            if (originalImage.getWidth() == targetWidth && originalImage.getHeight() == targetHeight) {
                return originalImage;
            }
            Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_AREA_AVERAGING);
            BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB);
            outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
            return outputImage;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Base64转BuffedImage:

        public static BufferedImage convertBase64ToImage(String base64String) {
            try {
                // 解码Base64字符串为字节数组
                byte[] imageBytes = Base64.getDecoder().decode(base64String);
                // 创建ByteArrayInputStream对象
                ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
                // 将ByteArrayInputStream对象转换为BufferedImage对象
                BufferedImage bufferedImage = ImageIO.read(bis);
                // 关闭ByteArrayInputStream
                bis.close();
                // 返回BufferedImage对象
                return bufferedImage;
            } catch (Exception e) {
                log.info("convertBase64ToImage error: {}", e.getMessage());
            }
    
            return null;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    BuffedImage转Base64:

        public static String convertImageToBase64(BufferedImage image) {
            try {
                // 创建字节数组输出流
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                // 将BufferedImage对象写入字节数组输出流
                ImageIO.write(image, "png", baos);
                // 关闭字节数组输出流
                baos.close();
                // 获取字节数组
                byte[] imageBytes = baos.toByteArray();
                // 返回Base64编码的字符串
                return Base64.getEncoder().encodeToString(imageBytes);
            } catch (Exception e) {
                log.info("convertImageToBase64 error: {}", e.getMessage());
            }
            return null;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    理论+案例,带你掌握Angular依赖注入模式的应用
    3. MongoDB存储和索引
    JavaScript利用多态的思想封装组件
    this的基本概念,call/bind/apply的使用,手写call/bind/apply方法
    accelerate 的一个tip:early stopping 处可能存在的bug
    【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【10】【仓库管理】【分布式基础篇总结】
    EPLAN小知识——如何在费斯托(FESTO)官网下载EPLAN部件
    vue CSS 实现上下小三角组件(类似表格排序)
    QQ邮箱批量发送
    新概念英语第二册(74)
  • 原文地址:https://blog.csdn.net/sinat_14840559/article/details/133362611