package com.yeechart.dotMatrix.canvas;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;

/**
 * 点阵图 画布转换 工具类
 */
public class DotMatrixImageUtil {


    /**
     * 根据图片绘制点阵图
     *
     * @param resourcePath
     * @param width
     * @param height
     * @param tolerance    容差
     * @return
     */
    public static byte[] canvasImageBitmapArrays(String resourcePath, int width, int height, int tolerance) {
        try {
            //因为是墨水屏 所有使用 灰度模型 BufferedImage.TYPE_BYTE_GRAY 但是灰度模型的颜色不准 所以使用BufferedImage.TYPE_INT_ARGB_PRE
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
            Graphics2D graphics = image.createGraphics();

            // 设置背景色为白色
            graphics.setBackground(Color.WHITE);
            graphics.clearRect(0, 0, image.getWidth(), image.getHeight());

            // 加载图片
            InputStream inputStream = DotMatrixImageUtil.class.getClassLoader().getResourceAsStream(resourcePath);

            if (inputStream == null) {
                throw new RuntimeException("文件未找到！");
            }

            BufferedImage originalImage = ImageIO.read(inputStream);
            //绘制图片
            graphics.drawImage(originalImage, 0, 0, width, height, Color.WHITE, null);


            //获取点阵数组
            byte[] twoBytes = DotMatrixImageUtil.convertImageToPixelArray(image, tolerance);


            return twoBytes;

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 将图片转换为点阵图
     *
     * @param bufferedImage
     * @param tolerance     容差
     * @return
     */
    public static byte[] convertImageToPixelArray(BufferedImage bufferedImage, int tolerance) {

        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        byte[] pixelArray = new byte[width * height];

        DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();

        if (dataBuffer instanceof DataBufferByte) {
            byte[] pixels = ((DataBufferByte) dataBuffer).getData();
            processPixels(pixels, width, height, pixelArray, tolerance);
        } else if (dataBuffer instanceof DataBufferInt) {
            int[] pixels = ((DataBufferInt) dataBuffer).getData();
            processPixels(pixels, width, height, pixelArray, tolerance);
        }


        return pixelArray;
    }

    private static void processPixels(byte[] pixels, int width, int height, byte[] pixelArray, int tolerance) {
        ForkJoinPool.commonPool().submit(() -> IntStream.range(0, height)
                .parallel()
                .forEach(y -> {
                    for (int x = 0; x < width; x++) {
                        int index = y * width + x;
                        int pixelIndex = index * 3;

                        int red = pixels[pixelIndex] & 0xFF;
                        int green = pixels[pixelIndex + 1] & 0xFF;
                        int blue = pixels[pixelIndex + 2] & 0xFF;

                        boolean isWhite = (red >= 255 - tolerance) && (green >= 255 - tolerance) && (blue >= 255 - tolerance);
                        pixelArray[index] = (byte) (isWhite ? 0x00 : 0x01);
                    }
                })).join();
    }

    private static void processPixels(int[] pixels, int width, int height, byte[] pixelArray, int tolerance) {
        ForkJoinPool.commonPool().submit(() -> IntStream.range(0, height)
                .parallel()
                .forEach(y -> {
                    for (int x = 0; x < width; x++) {
                        int index = y * width + x;
                        int pixel = pixels[index];

                        int red = (pixel >> 16) & 0xFF;
                        int green = (pixel >> 8) & 0xFF;
                        int blue = pixel & 0xFF;

                        boolean isWhite = (red >= 255 - tolerance) && (green >= 255 - tolerance) && (blue >= 255 - tolerance);
                        pixelArray[index] = (byte) (isWhite ? 0x00 : 0x01);
                    }
                })).join();
    }


    /**
     * 判断像素是否是白色
     *
     * @param pixel
     * @return
     */
//    private int tolerance = 50;//白色 容差
    private static boolean isWhite(int pixel, int tolerance) {

        int alpha = (pixel >> 24) & 0xFF;
        int red = (pixel >> 16) & 0xFF;
        int green = (pixel >> 8) & 0xFF;
        int blue = pixel & 0xFF;

//        if(pixel == Color.WHITE.getRGB()
////                ||
////                ( ( ( pixel >> 24 ) & 0xFF ) == 0 )//pixel == Color.TRANSPARENT
//        ){
//            return true;
//        }
        //判断是否是纯白
        if ((red == 255 && green == 255 && blue == 255)) {   //|| alpha == 0
            return true;
        }

        //判断是完全透明
//        if(alpha == 0){
////            System.out.println("走了判断是否是纯透明");
//            return true;
//        }


//        int tolerance = 220;//容差  84     140


//
//        // 判断像素是否在白色范围内
        boolean isWhite = (red >= (255 - tolerance)) && (green >= (255 - tolerance)) && (blue >= (255 - tolerance));

        return isWhite;

//        return false;

    }


    /**
     * 将点阵图转换为图片
     *
     * @param twoBytes
     * @return
     */
    public static BufferedImage pixelArrayToConvertImage(byte[] twoBytes, int width, int height) {

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

        for (int y = 0; y < image.getHeight(); y++) {
            for (int x = 0; x < image.getWidth(); x++) {

                byte pixel = twoBytes[y * image.getWidth() + x];

                image.setRGB(x, y, pixel == 0x01 ? Color.BLACK.getRGB() : Color.WHITE.getRGB());

            }
        }
        return image;

    }


    public static BufferedImage pixelArrayToConvertImage(int[][] canvasBitmapArrays) {

        int width = canvasBitmapArrays[0].length;

        int height = canvasBitmapArrays.length;

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {

                int pixel = canvasBitmapArrays[y][x];

                image.setRGB(x, y, pixel == 0x01 ? Color.BLACK.getRGB() : Color.WHITE.getRGB());

            }
        }
        return image;

    }


    /**
     * 将画布数组转化为 点阵数组
     *
     * @param canvasBitmapArrays 这个数组的内容需要强转为byte的
     * @return
     */
    public static byte[] canvasBitmapArraysToTwo(int[][] canvasBitmapArrays) {
        int width = canvasBitmapArrays[0].length;
        int height = canvasBitmapArrays.length;

        byte[] data = new byte[width * height];

        for (int i = 0; i < height; i++) {

            for (int j = 0; j < width; j++) {

                data[i * width + j] = (byte) canvasBitmapArrays[i][j];

            }
        }

        return data;
    }


    /**
     * 将点阵数组转换为 画布数组
     *
     * @param data
     * @param width
     * @param height
     * @return
     */
    public static int[][] twoToCanvasBitmapArrays(byte[] data, int width, int height) {
        int[][] canvasBitmapArrays = new int[height][width];

        for (int i = 0; i < height; i++) {

            for (int j = 0; j < width; j++) {

                canvasBitmapArrays[i][j] = data[i * width + j];

            }
        }
        return canvasBitmapArrays;
    }


    /**
     * 将 画布进行横竖切换 即 画布 的横竖屏进行切换 类似于将画布进行旋转 竖的旋转-90° or 横的旋转90°
     *
     * @param data
     * @return
     */
    public static int[][] screenHorizontalToVertical(int[][] data) {
        //首先获取原画布的宽高
        int width = data[0].length;
        int height = data.length;

        int[][] canvasBitmapArrays = new int[width][height];

        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                if (height > width) {
                    //竖向转横向 -90°
//                    canvasBitmapArrays[i][j] = data[height-j-1][width-i-1];  这个效果为镜像 且角度为90°
                    canvasBitmapArrays[i][j] = data[j][width - i - 1];
                } else {
                    //横向转竖向 90°
                    canvasBitmapArrays[i][j] = data[height - 1 - j][i];
                }

            }
        }

        return canvasBitmapArrays;
    }


    /**
     * 将画布倒装
     *
     * @param data
     * @return
     */
    public static int[][] screenFlip(int[][] data) {
        //首先获取原画布的宽高
        int width = data[0].length;
        int height = data.length;

        int[][] canvasBitmapArrays = new int[height][width];

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {

                canvasBitmapArrays[i][j] = data[height - 1 - i][width - 1 - j];

            }
        }

        return canvasBitmapArrays;
    }

}
