package com.cm.common.utils.image;

import com.cm.common.utils.image.enums.LongImageType;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 图片工具
 *
 * @author wanggeng
 */
public class ImageUtil {

    private int imageWidth = 0;
    /**
     * 角度
     */
    private double degree;
    /**
     * 弧度
     */
    private double radian;

    public ImageUtil(double degree) {
        // 角度转弧度
        this.degree = degree % 360;
        this.degree = degree < 0 ? degree + 360 : degree;
        this.radian = Math.toRadians(degree);
    }

    public ImageUtil(double degree, int imageWidth) {
        this.degree = degree % 360;
        this.degree = degree < 0 ? degree + 360 : degree;
        this.radian = Math.toRadians(degree);
        this.imageWidth = imageWidth;
    }

    /**
     * 生成长图
     *
     * @param longImageType 图片类型
     * @param outImage      长图路径
     * @param imagePaths    原图地址
     * @throws IOException
     * @author wenc
     * @date 2019年6月3日 下午3:20:06
     * @modifier wenc
     * @date 2019年6月3日 下午3:20:06
     */
    public void getLongImage(LongImageType longImageType, String outImage, List<String> imagePaths)
            throws IOException {
        if (longImageType == null) {
            throw new IOException("图片格式不正确，支持png, jpg, jpeg");
        }
        if (outImage == null || outImage.isEmpty()) {
            throw new IOException("输出图片路径错误");
        }
        if (imagePaths == null || imagePaths.isEmpty()) {
            throw new IOException("输入图片文件错误");
        }
        List<BufferedImage> originalBufferedImages = listBufferedImage(imagePaths);
        createLongImage(longImageType, outImage, originalBufferedImages);
    }

    /**
     * 生成长图
     *
     * @param longImageType  图片类型
     * @param outImage       长图路径
     * @param bufferedImages 原图地址
     * @throws IOException
     * @author wenc
     * @date 2019年6月3日 下午3:35:30
     * @modifier wenc
     * @date 2019年6月3日 下午3:35:30
     */
    private void createLongImage(LongImageType longImageType, String outImage,
                                 List<BufferedImage> bufferedImages) throws IOException {
        // 旋转图片
        if (this.degree != 0) {
            bufferedImages = rotateBufferImages(bufferedImages);
        }
        if (this.imageWidth <= 0) {
            this.imageWidth = getMaxWidth(bufferedImages);
        }
        List<BufferedImage> scaleBufferedImages = scaleBufferedImages(imageWidth,
                bufferedImages);
        int longImageHeight = getImageHeight(scaleBufferedImages);
        BufferedImage getLongBufferedImage = getLongBufferedImage(imageWidth, longImageHeight,
                scaleBufferedImages);
        ImageIO.write(getLongBufferedImage, longImageType.getValue(), new File(outImage));
    }

    /**
     * 旋转图片
     *
     * @param bufferedImages
     * @return
     * @author wenc
     * @date 2019年6月3日 下午5:15:16
     * @modifier wenc
     * @date 2019年6月3日 下午5:15:16
     */
    private List<BufferedImage> rotateBufferImages(List<BufferedImage> bufferedImages) {
        List<BufferedImage> rotateBufferImages = new ArrayList<>();
        for (BufferedImage bufferedImage : bufferedImages) {
            int width, height;
            if (this.degree == 0 || this.degree == 180 || this.degree == 360) {
                width = bufferedImage.getWidth();
                height = bufferedImage.getHeight();
            }
            if (this.degree == 90 || this.degree == 270) {
                width = bufferedImage.getHeight();
                height = bufferedImage.getWidth();
            } else {
                width = (int) (bufferedImage.getWidth() * Math.cos(this.radian)
                        + bufferedImage.getHeight() * Math.sin(this.radian));
                height = (int) (bufferedImage.getWidth() * Math.sin(this.radian)
                        + bufferedImage.getHeight() * Math.cos(this.radian));
            }
            // 确定原点坐标
            int x = (width / 2) - (bufferedImage.getWidth() / 2);
            int y = (height / 2) - (bufferedImage.getHeight() / 2);

            BufferedImage roateBufferedImage = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);

            Graphics2D graphics = (Graphics2D) roateBufferedImage.getGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            graphics.setColor(Color.white);
            graphics.fillRect(0, 0, width, height);
            graphics.rotate(this.radian, width / 2, height / 2);
            graphics.drawImage(bufferedImage, x, y, null);
            graphics.dispose();
            rotateBufferImages.add(roateBufferedImage);
        }
        return rotateBufferImages;
    }

    /**
     * 获取最大图片宽度
     *
     * @param bufferedImages
     * @return
     * @author wenc
     * @date 2019年6月3日 下午3:45:41
     * @modifier wenc
     * @date 2019年6月3日 下午3:45:41
     */
    private int getMaxWidth(List<BufferedImage> bufferedImages) {
        int maxWidth = 0;
        for (BufferedImage bufferedImage : bufferedImages) {
            if (bufferedImage.getWidth() > maxWidth) {
                maxWidth = bufferedImage.getWidth();
            }
        }
        return maxWidth;
    }

    /**
     * 生成长图
     *
     * @param imageWidth
     * @param imageHeight
     * @param bufferedImages
     * @return
     * @author wenc
     * @date 2019年6月3日 下午3:12:30
     * @modifier wenc
     * @date 2019年6月3日 下午3:12:30
     */
    private BufferedImage getLongBufferedImage(int imageWidth, int imageHeight,
                                               List<BufferedImage> bufferedImages) {
        int currentImageHeight = 0;
        BufferedImage longBufferedImage = new BufferedImage(imageWidth, imageHeight,
                BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < bufferedImages.size(); i++) {
            BufferedImage bufferedImage = bufferedImages.get(i);
            int[] bufferedImageArray = new int[bufferedImage.getWidth()
                    * bufferedImage.getHeight()];
            bufferedImageArray = bufferedImage.getRGB(0, 0, bufferedImage.getWidth(),
                    bufferedImage.getHeight(), bufferedImageArray, 0, bufferedImage.getWidth());
            longBufferedImage.setRGB(0, currentImageHeight, bufferedImage.getWidth(),
                    bufferedImage.getHeight(), bufferedImageArray, 0, imageWidth);
            currentImageHeight += bufferedImage.getHeight();
        }
        return longBufferedImage;
    }

    /**
     * 获取长图长度
     *
     * @param bufferedImages
     * @return
     * @author wenc
     * @date 2019年6月3日 下午3:05:53
     * @modifier wenc
     * @date 2019年6月3日 下午3:05:53
     */
    private int getImageHeight(List<BufferedImage> bufferedImages) {
        int height = 0;
        for (BufferedImage bufferedImage : bufferedImages) {
            height += bufferedImage.getHeight();
        }
        return height;
    }

    /**
     * 缩放调整后的缓存图片
     *
     * @param imageWidth
     * @param originalBufferedImages
     * @return
     * @author wenc
     * @date 2019年6月3日 下午3:02:53
     * @modifier wenc
     * @date 2019年6月3日 下午3:02:53
     */
    private List<BufferedImage> scaleBufferedImages(int imageWidth,
                                                    List<BufferedImage> bufferedImages) {
        List<BufferedImage> scaleBufferedImages = new ArrayList<>();
        for (BufferedImage originalBufferedImage : bufferedImages) {
            double ratio = getRatio(imageWidth, originalBufferedImage);
            AffineTransformOp affineTransformOp = new AffineTransformOp(
                    AffineTransform.getScaleInstance(ratio, ratio), null);
            Image scaleImage = affineTransformOp.filter(originalBufferedImage, null);
            BufferedImage scaleBufferedImage = new BufferedImage(scaleImage.getWidth(null),
                    scaleImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
            Graphics graphics = scaleBufferedImage.getGraphics();
            graphics.drawImage(scaleImage, 0, 0, null);
            graphics.dispose();
            scaleBufferedImages.add(scaleBufferedImage);
        }
        return scaleBufferedImages;
    }

    /**
     * 构建图片列表
     *
     * @param imagePaths
     * @return
     * @throws IOException
     * @author wenc
     * @date 2019年6月3日 下午2:41:14
     * @modifier wenc
     * @date 2019年6月3日 下午2:41:14
     */
    private List<BufferedImage> listBufferedImage(List<String> imagePaths) throws IOException {
        List<BufferedImage> bufferedImages = new ArrayList<>();
        for (String imagePath : imagePaths) {
            BufferedImage bufferedImage = ImageIO.read(new File(imagePath));
            bufferedImages.add(bufferedImage);
        }
        return bufferedImages;
    }

    /**
     * 获得缩放比例
     *
     * @param imageWidth
     * @param bufferedImage
     * @return
     * @author wenc
     * @date 2019年6月3日 下午2:49:40
     * @modifier wenc
     * @date 2019年6月3日 下午2:49:40
     */
    private double getRatio(int imageWidth, BufferedImage bufferedImage) {
        return imageWidth * 1.0 / bufferedImage.getWidth();
    }

    public static void main(String[] args) throws IOException {
        ImageUtil imageUtil = new ImageUtil(0);
        String[] imagePaths = {
                "/Users/wenc/Desktop/Desktop/社会投资/施工许可阶段服务指南2-1.png",
                "/Users/wenc/Desktop/Desktop/社会投资/施工许可阶段服务指南2-2.png",
                "/Users/wenc/Desktop/Desktop/社会投资/施工许可阶段服务指南2-3.png"};
        imageUtil.getLongImage(LongImageType.PNG, "/Users/wenc/Desktop/Desktop/社会投资/sgxkjdfwzn2.png",
                Arrays.asList(imagePaths));
    }
}
