#!D:\IDE\Anaconda3\envs\Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName: ImageUtils.py
 @DateTime: 2025/3/23 16:37
 @SoftWare: PyCharm
 @Author  ：xsh
"""
import os
import cv2
import base64
import numpy as np
from PyQt5 import Qt
import asyncio


async def image_save(filename: str, image: np.ndarray, param: list = None):
    info: Qt.QFileInfo = Qt.QFileInfo(filename)
    if image is None:
        return
    try:
        if not info.dir().exists():
            info.dir().mkpath(info.absolutePath())
        if isinstance(param, (list, tuple)):
            cv2.imwrite(info.absoluteFilePath(), image, param)
        else:
            cv2.imwrite(info.absoluteFilePath(), image)
    except Exception as e:
        pass

class ImageUtils:
    @staticmethod
    def image_save(filename: str, image: np.ndarray, param: list = None):
        info: Qt.QFileInfo = Qt.QFileInfo(filename)
        if image is None:
            return
        try:
            if not info.dir().exists():
                info.dir().mkpath(info.absolutePath())
            if isinstance(param, (list, tuple)):
                cv2.imwrite(info.absoluteFilePath(), image, param)
            else:
                cv2.imwrite(info.absoluteFilePath(), image)
        except Exception as e:
            pass
    @staticmethod
    def image_to_base64(image: np.ndarray, w: int = -1, h: int = -1) -> str:
        # 将图像编码为JPEG格式
        try:
            img: np.ndarray = ImageUtils.image_resize(image, w, h)
            _, buffer = cv2.imencode('.jpg', img)
            # 将编码后的图像转换为字节流
            image_bytes = buffer.tobytes()
            # 将字节流编码为Base64
            base64_string = base64.b64encode(image_bytes).decode('utf-8')
            return base64_string
        except Exception as e:
            return ''
    @staticmethod
    def base64_to_image(base64_string: str, w: int = -1, h: int = -1):
        # 将Base64字符串解码为字节流
        image: np.ndarray
        try:
            image_bytes = base64.b64decode(base64_string.encode('utf-8'))
            # 将字节流解码为图像
            image_array = np.frombuffer(image_bytes, np.uint8)
            img = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
            image = ImageUtils.image_resize(img, w, h)
        except Exception as e:
            image = None
        return image

    @staticmethod
    def cv2_to_QImage(cv_image: np.ndarray, w: int = -1, h: int = -1):
        img = ImageUtils.image_resize(cv_image, w, h)
        q_image = Qt.QImage()
        if img is None:
            return q_image
        # 获取图像的宽度、高度和通道数
        if len(cv_image.shape) == 2:

            height, width = cv_image.shape
            q_image = Qt.QImage(cv_image.data.tobytes(), width, height, width, Qt.QImage.Format_Grayscale8)
        elif len(cv_image.shape) >= 3:
            height, width, channel = cv_image.shape
            bytes_per_line = 3 * width
            # 将OpenCV图像转换为QImage
            q_image = Qt.QImage(cv_image.data.tobytes(), width, height, bytes_per_line, Qt.QImage.Format_RGB888).rgbSwapped()
        else:
            q_image = Qt.QImage()

        return q_image

    @staticmethod
    def numpy_to_QImage(cv_image: np.ndarray, w: int = -1, h: int = -1) -> Qt.QImage:
        img = ImageUtils.image_resize(cv_image, w, h)
        q_image = Qt.QImage()
        if img is None:
            return q_image
        # 获取图像的宽度、高度和通道数
        if len(cv_image.shape) == 2:
            height, width = cv_image.shape
            q_image = Qt.QImage(cv_image.data, width, height, width, Qt.QImage.Format_Grayscale8)
        elif len(cv_image.shape) >= 3:
            height, width, channel = cv_image.shape
            bytes_per_line = 3 * width
            # 将OpenCV图像转换为QImage
            q_image = Qt.QImage(cv_image.data, width, height, bytes_per_line, Qt.QImage.Format_RGB888).rgbSwapped()
        else:
            q_image = Qt.QImage()
        return q_image

    @staticmethod
    def QImage_to_numpy(image: Qt.QImage) -> np.ndarray:
        img: np.ndarray = None
        if ImageUtils.isNull(image):
            return img
        try:
            size: Qt.QSize = image.size()
            string = image.bits().asstring((size.width() * size.height() * image.depth()) // 8)  # """format 0xffRRGGBB"""
            img = np.fromstring(string, dtype=np.uint8).reshape((size.height(), size.width(), image.depth() // 8))
        except Exception as e:
            from AppLog.logHelper import logOTHER
            logOTHER << f"{e}"
        return img

    @staticmethod
    def QImage_to_base64(image: Qt.QImage, w: int = -1, h: int = -1, fmt: str = 'JPEG') -> str:
        img = ImageUtils.QImage_resize(image, w, h)
        if ImageUtils.isNull(img):
            return ''
        data = Qt.QByteArray()
        buffer = Qt.QBuffer(data)
        img.save(buffer, fmt)
        return str(data.toBase64())[2:-1]

    @staticmethod
    def file_to_base64(filename: str) -> str:
        info: Qt.QFileInfo = Qt.QFileInfo(filename)
        if not info.exists():
            return ''
        fp: Qt.QFile = Qt.QFile(info.absoluteFilePath())
        if not fp.open(Qt.QIODevice.ReadOnly):
            return ''
        buffer: str = str(base64.b64encode(fp.readAll()))[2:-1]
        fp.close()
        return buffer

    @staticmethod
    def base64_to_QImage(buffer: str, fmt: str = "JPEG") -> Qt.QImage:
        image: Qt.QImage = Qt.QImage()
        try:
            base_buffers: list = buffer.split(',')
            data: Qt.QByteArray
            if len(base_buffers) >= 1:
                data = Qt.QByteArray().fromBase64(base_buffers[1].encode())
            else:
                data = Qt.QByteArray().fromBase64(buffer.encode())

            image.loadFromData(data, fmt)
        except Exception as e:
            from AppLog.logHelper import logOTHER
            logOTHER << f"{e}"
        return image

    @staticmethod
    def image_ROI(image: np.ndarray, center_x: int, center_y: int, w: int, h: int, isRect: bool = True) -> np.ndarray:
        roi: np.ndarray = None
        if image is None:
            return roi
        roi_w   : int
        roi_h   : int
        src_w   : int
        src_h   : int
        beginX  : int
        beginY  : int
        endX    : int
        endY    : int
        src_w   = image.shape[1]
        src_h   = image.shape[0]
        roi_w = w + w
        roi_h = h + h
        if isRect:
            beginX  = center_x - w
            beginY  = center_y - h
            endX    = center_x + w
            endY    = center_y + h
            if beginX < 0 or beginY < 0 or endX > src_w or endY > src_h:
                return roi
        else:
            beginX  = max(0, center_x - w)
            beginY  = max(0, center_y - h)
            endX    = min(center_x + w, src_w)
            endY    = min(center_y + h, src_h)
        try:
            roi = image[beginY: endY, beginX:endX]
            if roi_w != roi.shape[1] or roi_h != roi.shape[0]:
                roi = ImageUtils.image_resize(roi, roi_w, roi_h)
        except Exception as e:

            roi = None
        return roi

    @staticmethod
    def isNull(image: Qt.QImage) -> bool:
        return image is None or not isinstance(image, Qt.QImage) or image.isNull()

    @staticmethod
    def QImage_resize(image: Qt.QImage, w: int = -1, h: int = -1) -> Qt.QImage:
        if image is None or w is None or h is None:
            return image
        if not isinstance(image, Qt.QImage) or image.isNull():
            return image
        src_w: int = image.width()
        src_h: int = image.height()
        dst_w: int
        dst_h: int
        if w <= 0:
            dst_w = src_w
        else:
            dst_w = w
        if h <= 0:
            dst_h = src_h
        else:
            dst_h = h
        img = image.scaled(dst_w, dst_h, Qt.Qt.IgnoreAspectRatio, Qt.Qt.SmoothTransformation)
        return img

    @staticmethod
    def image_read(filename: str, isGray: bool = False) -> np.ndarray:
        img: np.ndarray
        try:
            info: Qt.QFileInfo = Qt.QFileInfo(filename)
            if not info.exists():
                return None
            img = cv2.imread(info.absoluteFilePath(), cv2.IMREAD_GRAYSCALE if isGray else cv2.IMREAD_COLOR)
        except Exception as e:
            img = None
        return img

    @staticmethod
    def image_resize(image, w: int = -1, h: int = -1):
        if image is None or w is None or h is None:
            return image
        src_w: int = image.shape[1]
        src_h: int = image.shape[0]
        dst_w: int
        dst_h: int
        if w <= 0:
            dst_w = src_w
        else:
            dst_w = w
        if h <= 0:
            dst_h = src_h
        else:
            dst_h = h
        img = cv2.resize(image, dsize=(dst_w, dst_h), interpolation=cv2.INTER_LINEAR)
        return img


    @staticmethod
    def image_empty(w: int, h: int, color: int = 255):
        result_image = np.zeros((h if h >= 1 else 1, w if w >= 1 else 1), dtype=np.uint8)
        result_image = result_image + (color % 256)
        return result_image