package com.ruoyi.common.utils.file;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.StringUtils;

import javax.imageio.ImageIO;

/**
 * 图片处理工具类
 *
 * @author ruoyi
 */
public class ImageUtils
{
    //以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
    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;

    private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);

    public static byte[] getImage(String imagePath)
    {
        InputStream is = getFile(imagePath);
        try
        {
            return IOUtils.toByteArray(is);
        }
        catch (Exception e)
        {
            log.error("图片加载异常 {}", e);
            return null;
        }
        finally
        {
            IOUtils.closeQuietly(is);
        }
    }

    public static InputStream getFile(String imagePath)
    {
        try
        {
            byte[] result = readFile(imagePath);
            result = Arrays.copyOf(result, result.length);
            return new ByteArrayInputStream(result);
        }
        catch (Exception e)
        {
            log.error("获取图片异常 {}", e);
        }
        return null;
    }

    /**
     * 读取文件为字节数据
     * 
     * @param url 地址
     * @return 字节数据
     */
    public static byte[] readFile(String url)
    {
        InputStream in = null;
        try
        {
            if (url.startsWith("http"))
            {
                // 网络地址
                URL urlObj = new URL(url);
                URLConnection urlConnection = urlObj.openConnection();
                urlConnection.setConnectTimeout(30 * 1000);
                urlConnection.setReadTimeout(60 * 1000);
                urlConnection.setDoInput(true);
                in = urlConnection.getInputStream();
            }
            else
            {
                // 本机地址
                String localPath = RuoYiConfig.getProfile();
                String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
                in = new FileInputStream(downloadPath);
            }
            return IOUtils.toByteArray(in);
        }
        catch (Exception e)
        {
            log.error("获取文件路径异常 {}", e);
            return null;
        }
        finally
        {
            IOUtils.closeQuietly(in);
        }
    }

    /**
     * 根据指定大小压缩图片
     *
     * @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) {
            // log.info("图片无需压缩");
            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();
            }
            //log.info("图片原大小={}kb | 压缩后大小={}kb", srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
        } catch (Exception e) {
            log.error("【图片压缩】msg=图片压缩失败!", e);
        }
        return imageBytes;
    }

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

    public static BufferedImage getBufferedImg(BufferedImage src, int width, int height, int ro) {
        int angle = (int) (90 * ro);
        int type = src.getColorModel().getTransparency();
        int wid = width;
        int hei = height;
        if (ro % 2 != 0) {
            int temp = width;
            width = height;
            height = temp;
        }
        Rectangle re = new Rectangle(new Dimension(width, height));
        BufferedImage BfImg = null;
        BfImg = new BufferedImage(re.width, re.height, type);
        Graphics2D g2 = BfImg.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2.rotate(Math.toRadians(angle), re.width / 2, re.height / 2);
        g2.drawImage(src, (re.width - wid) / 2, (re.height - hei) / 2, null);
        g2.dispose();
        return BfImg;
    }

    //获得图片的高
    public static int getHeight(InputStream is) {
        BufferedImage src = null;
        int height = -1;
        try {
            src = ImageIO.read(is);
            height = src.getHeight();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return height;
    }

    //获得图片的宽
    public static int getWidth(InputStream is) {
        BufferedImage src = null;
        int width = -1;
        try {
            src = ImageIO.read(is);
            width = src.getWidth();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return width;
    }

    //获得图片的宽高
    public static Dimension getSize(byte[] bytes)
    {
        BufferedImage src = null;
        try
        {
            src = ImgUtil.toImage(bytes);
            return new Dimension(src.getWidth(), src.getHeight());
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }

    public static byte[] rotateImage(byte[] bytes, String format, int ro) {
        int angle = (int) (90 * ro);
        BufferedImage src = ImgUtil.toImage(bytes);
        int type = src.getColorModel().getTransparency();
        int width = src.getWidth();
        int height = src.getHeight();
        int wid = width;
        int hei = height;
        if (ro % 2 != 0) {
            int temp = width;
            width = height;
            height = temp;
        }
        Rectangle re = new Rectangle(new Dimension(width, height));
        BufferedImage BfImg = null;
        BfImg = new BufferedImage(re.width, re.height, type);
        Graphics2D g2 = BfImg.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2.rotate(Math.toRadians(angle), re.width / 2.0, re.height / 2.0);
        g2.drawImage(src, (re.width - wid) / 2, (re.height - hei) / 2, null);
        g2.dispose();

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try
        {
            ImageIO.write(BfImg, format, os);
            return os.toByteArray();
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return null;
        }
        finally
        {
            IoUtil.close(os);
        }
    }

    public static byte[] generateThumbnail(byte[] bytes, int size/* = 0 */, boolean toSquare/* = false */, float quality/* = 1.0 */)
    {
        if(null == bytes)
            return null;

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try
        {
            if(generateThumbnail(bytes, os, size, toSquare, quality))
            {
                os.flush();
                return os.toByteArray();
            }
            else
                return null;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return null;
        }
        finally
        {
            IoUtil.close(os);
        }
    }

    public static boolean generateThumbnail(byte[] bytes, File file, int size/* = 0 */, boolean toSquare/* = false */, float quality/* = 1.0 */)
    {
        if(null == bytes)
            return false;

        FileOutputStream os = null;
        try
        {
            os = new FileOutputStream(file);
            if(generateThumbnail(bytes, os, size, toSquare, quality))
            {
                os.flush();
                return true;
            }
            else
                return false;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return false;
        }
        finally
        {
            IoUtil.close(os);
        }
    }

    public static boolean generateThumbnail(byte[] bytes, OutputStream os, int size/* = 0 */, boolean toSquare/* = false */, float quality/* = 1.0 */)
    {
        if(null == bytes || null == os)
            return false;

        if(size <= 0)
            size = 128;

        ByteArrayInputStream is = new ByteArrayInputStream(bytes);

        Thumbnails.Builder<? extends InputStream> builder = Thumbnails.of(is)
                .width(size)
                .height(size)
                .keepAspectRatio(true)
                .outputQuality(quality)
                .outputFormat("jpg");//.antialiasing(Antialiasing.ON) // 抗锯齿
//.rendering(Rendering.QUALITY) // 渲染偏重
        if(toSquare)
            builder.crop(Positions.CENTER);

        try
        {
            builder.toOutputStream(os);
            os.flush();
            return true;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return false;
        }
        finally
        {
            IoUtil.close(is);
        }
    }
}
