package com.bonus.common.core.utils;

import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;


/**
 * @author cwchen
 */
public class PicUtils {
    //以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
    private static final Logger logger = LoggerFactory.getLogger(PicUtils.class);
    private static final Integer ZERO = 0;
    private static final Integer ONE_ZERO_TWO_FOUR = 1024;
    private static final Integer NINE_ZERO_ZERO = 900;
    private static final Integer THREE_TWO_SEVEN_FIVE = 3275;
    private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;
    private static final Double ZERO_EIGHT_FIVE = 0.85;
    private static final Double ZERO_SIX = 0.6;
    private static final Double ZERO_FOUR_FOUR = 0.44;
    private static final Double ZERO_FOUR = 0.4;

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
        if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
        try {
            while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            logger.info("图片原大小={}kb | 压缩后大小={}kb",
                    srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
        } catch (Exception e) {
            logger.error("【图片压缩】msg=图片压缩失败!", e);
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < NINE_ZERO_ZERO) {
            accuracy = ZERO_EIGHT_FIVE;
        } else if (size < TWO_ZERO_FOUR_SEVEN) {
            accuracy = ZERO_SIX;
        } else if (size < THREE_TWO_SEVEN_FIVE) {
            accuracy = ZERO_FOUR_FOUR;
        } else {
            accuracy = ZERO_FOUR;
        }
        return accuracy;
    }

    public static byte[] FileTobyte(File file) {
        FileInputStream fileInputStream = null;
        byte[] imgData = null;

        try {
            imgData = new byte[(int) file.length()];

            //read file into bytes[]
            fileInputStream = new FileInputStream(file);
            fileInputStream.read(imgData);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return imgData;
    }

    /**
     * 压缩base64编码图片，并返回base64
     *
     * @param base64Image  需要压缩的图片
     * @param compressSize 压缩大小,传入多少就压缩到该值范围内 （例：524,288 等于 512kb）
     * @return 返回base64编码
     * @throws Exception 异常处理
     */
    public static String compressBase64Image(String base64Image, Integer compressSize) throws Exception {
        try {
            String newBase64;
            // 判断格式
            if (base64Image.startsWith("data:image")) {
                int index = base64Image.indexOf("base64,");
                if (index == -1) {
                    throw new Exception("无效base64照片格式");
                }
                newBase64 = base64Image.substring(index + 7);
            } else {
                newBase64 = base64Image;
            }
            // replace(" ", "+")
            newBase64 = newBase64.replace(" ", "+");
            // 解码Base64字符串为字节数组
            byte[] imageBytes = Base64.getDecoder().decode(newBase64);
            //  缓冲图像
            BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
            //  根据指定的图像及宽、高按比例缩放并进行压缩质量90%新建缓冲图像缩略图
            BufferedImage image = Thumbnails.of(bufferedImage).size(bufferedImage.getWidth() / 2,
                    bufferedImage.getHeight() / 2).outputQuality(0.9).asBufferedImage();
            // 创建输出流对象
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            // 根据传入图像，图像类型，写入指定的输出流中
            ImageIO.write(image, "jpg", outputStream);
            // 输出流转换成字节数组
            imageBytes = outputStream.toByteArray();
            // 使用 Base64 编码方案将指定的字节数组转为 String
            String base64 = Base64.getEncoder().encodeToString(imageBytes);
            // 根据String对象长度判断是否需要进行压缩
            if (base64.length() - base64.length() / 8 * 2 > compressSize) {
                // 设置图像的缩放系数并创建图像 (默认1.0 代表缩略100%)
                image = Thumbnails.of(image).scale(1.0 / base64.length() / compressSize).asBufferedImage();
                // 根据传入图像，图像类型，写入指定的输出流中
                ImageIO.write(image, "jpg", outputStream);
                // 使用 Base64 编码方案将指定的字节数组转为 String
                base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray());
            }
            // 关闭流
            outputStream.flush();
            outputStream.close();
            // 返回Base64编码图片
            return "data:image/jpeg;base64,"  + base64;
        } catch (Exception e) {
            logger.error("图片压缩异常", e);
        }
        return null;
    }
}
