import io
import os
import re
import base64
from PIL import Image


IMAGE_QUALITIES = {
    "NEAREST": Image.NEAREST,
    "BILINEAR": Image.BILINEAR,
    "BICUBIC": Image.BICUBIC,
    "LANCZOS": Image.LANCZOS,
}


def load_image_content(data):
    """图片字节流转图片对象。
    """
    return Image.open(io.BytesIO(data))


def get_b64image_content(source):
    """
    获取data:image/jpeg,base64,...格式图片的图片内容字节流。
    """
    try:
        match = re.search("base64,", source, re.IGNORECASE)
        return base64.decodebytes(source[match.span()[1]:].encode("utf-8"))
    except Exception:
        raise ValueError("get_b64image_content failed from: source = [ {} ].".format(source))

def get_b64image(source):
    """
    将data:image/jpeg,base64,...格式的图片字符串转成图片对象。
    """
    content = get_b64image_content(source)
    return load_image_content(content)


def get_image_content(image, format="png"):
    """
    从图片对象中获取图片字节流。
    """
    buf = io.BytesIO()
    image.save(buf, format)
    return buf.getvalue()


def make_b64image(image, format="png"):
    """
    将图片对象或图片字节流转成data:image/jpeg,base64,...格式的图片字符串。
    """
    image = get_image(image)
    image = get_image_content(image, format)
    image = base64.encodebytes(image).decode("utf-8")
    image = "".join(image.splitlines())
    return "data:image/{format};base64,{content}".format(format=format, content=image)


def get_image(data):
    """
    从data中智能获取图片对象。
    """
    if isinstance(data, Image.Image):
        return data
    if isinstance(data, bytes):
        return load_image_content(data)
    if isinstance(data, str):
        if data.startswith("data:image/"):
            return get_b64image(data)
        if os.path.isfile(data):
            with open(data, 'rb') as fobj:
                return load_image_content(fobj.read())
        return load_image_content(base64.decodebytes(data.encode("utf-8")))
    if hasattr(data, "read") and callable(getattr(data, "read")):
        return load_image_content(data.read())
    return None


def get_quality(quality):
    """
    将图片质量名称转化成质量数值。
    """
    return IMAGE_QUALITIES[quality]


def get_quality_names():
    """
    获取质量名称列表。
    """
    return list(IMAGE_QUALITIES.keys())


def resize_image(image, width, height, quality="LANCZOS"):
    """
    图片缩放至指定长宽。
    """
    image = get_image(image)
    quality = get_quality(quality)
    image.resize((width, height), quality)
    return image


def crop_image(image, left, top, width, height):
    """
    从图片指定位置截取指定大小的子图。
    """
    image = get_image(image)
    image.crop((left, top, left+width, top+height))
    return image
