首页 > 编程语言 >python使用pillow和opencv生成图片缩略图

python使用pillow和opencv生成图片缩略图

时间:2024-03-13 20:35:29浏览次数:34  
标签:verbose img 缩略图 python fmt bytes opencv thumbnail size

代码如下:

from io import BytesIO
from pathlib import Path
from typing import Annotated, Literal, Optional, Tuple, Union

# pip install pillow opencv-python
import cv2  # type:ignore[import-untyped]
import numpy as np
from PIL import Image

ImageSizeType = Annotated[Tuple[int, int], "图片尺寸(宽,高),如:(1080, 720)"]


class Picture:
    default_size = (351, 190)

    @staticmethod
    def generate_thumbnail_pil(
        img_bytes: bytes, size, fmt: Literal["JPEG", "PNG"], *, verbose=False
    ) -> bytes:
        with Image.open(BytesIO(img_bytes)) as image:
            origin_size = image.size
            image.thumbnail(size)
            if verbose:
                print(f"pil[target_{size=}]: {origin_size} -> {image.size}")
            bio = BytesIO()
            if fmt == "JPEG":
                image = image.convert("RGB")
            image.save(bio, format=fmt)
            return bio.getvalue()

    @staticmethod
    def generate_thumbnail_opencv(
        img_bytes: bytes, size, fmt: Literal[".jpeg", ".png"], *, verbose=False
    ) -> bytes:
        img = cv2.imdecode(np.frombuffer(img_bytes, dtype=np.uint8), cv2.IMREAD_COLOR)
        resized = cv2.resize(img, size)
        if verbose:
            origin_size, converted_size = img.shape[:2][::-1], resized.shape[:2][::-1]
            print(f"opencv[target_{size=}]: {origin_size} -> {converted_size}")
        _, img_encode = cv2.imencode(fmt, resized)
        return img_encode.tobytes()

    @classmethod
    def thumbnail(
        cls,
        img: Union[bytes, BytesIO, str, Path],
        size: Optional[ImageSizeType] = None,
        keep_scale=False,
        fmt: Optional[str] = None,
        *,
        verbose=False,
    ) -> bytes:
        """生成缩略图

        :param img: 图片二进制或路径
        :param size: 缩略图的宽、高, 如果为None,则使用类的default_size
        :param keep_scale: 是否保持宽高比
        :param fmt: 缩略图格式(jpg或png)
        :param verbose: 调试用参数,是否打印生成的缩略图尺寸

        Usage::
            >>> p = Path('a.jpg')
            >>> thumb = Picture.thumbnail(p.read_bytes(), fmt=p.suffix)
            >>> isinstance(thumb, bytes)
            True
        """
        if size is None:
            size = cls.default_size
        if fmt is None:
            if isinstance(img, (str, Path)) and str(img).lower().endswith(".png"):
                fmt = "png"
        else:
            fmt = fmt.strip(".").lower()
            assert fmt in ("jpg", "jpeg", "png"), "Invalid `fmt`: only support png/jpg"
        if isinstance(img, BytesIO):
            img = img.getvalue()
        elif isinstance(img, (str, Path)):
            img = Path(img).read_bytes()
        if keep_scale:
            fmt1: Literal["PNG", "JPEG"] = "PNG" if fmt == "png" else "JPEG"
            return cls.generate_thumbnail_pil(img, size, fmt=fmt1, verbose=verbose)
        else:
            fmt2: Literal[".png", ".jpeg"] = ".png" if fmt == "png" else ".jpeg"
            return cls.generate_thumbnail_opencv(img, size, fmt=fmt2, verbose=verbose)


def main():
    import sys
    import doctest
    filepath = sys.argv[1]
    if not (p := Path(filepath)).exists():
        raise FileNotFoundError(filepath)
    b1 = Picture.thumbnail(p, keep_scale=True, verbose=True, fmt=p.suffix)
    b2 = Picture.thumbnail(p, verbose=True, fmt=p.suffix)
    p1 = p.with_name(p.stem + "-pil" + p.suffix)
    p2 = p.with_name(p.stem + "-opencv" + p.suffix)
    size = p1.write_bytes(b1)
    print(f"Write to {p1} with {size=}")
    size = p2.write_bytes(b2)
    print(f"Write to {p2} with {size=}")
    # verify param type
    content = p.read_bytes()
    assert isinstance(Picture.thumbnail(content, keep_scale=True, fmt=".png"), bytes)
    assert isinstance(Picture.thumbnail(str(p), keep_scale=True), bytes)
    assert isinstance(
        Picture.thumbnail(BytesIO(content), keep_scale=True, fmt="jpg"), bytes
    )
    assert isinstance(Picture.thumbnail(content, fmt=".jpg"), bytes)
    assert isinstance(Picture.thumbnail(str(p)), bytes)
    assert isinstance(Picture.thumbnail(BytesIO(content), fmt="png"), bytes)
    # doctest
    if Path("a.jpg").exists():
        doctest.testmod(verbose=True)
    # doctest
    if Path('a.jpg').exists():
        doctest.testmod(verbose=True)


if __name__ == "__main__":
    main()

标签:verbose,img,缩略图,python,fmt,bytes,opencv,thumbnail,size
From: https://www.cnblogs.com/waketzheng/p/18071450

相关文章

  • python 猜数字 random
    #猜数字如果数字太大则输出Toolarge!如果数字太小则输出Toosmall!如果猜中则输出Justright!importrandomnumber=random.randint(1,100)whileTrue: num=int(input('输入1-100之间的数')) ifnum>number: print('你猜的数字太大了请重新输入') elifnu......
  • Python中AdaBoost与GBDT模型【附代码】
    目录1、AdaBoost算法的原理介绍(1)AdaBoost算法核心思想(2)AdaBoost算法数学原理概述1、初始化各个样本点权重,各权重相等2、计算误差率3、调整弱学习区权重4、更新样本点权重5、反复迭代6、正则化项(3)AdaBoost算法的简单代码实现2、案例- AdaBoost信用卡精准营销模型......
  • 【C++】【OpenCV-4.9.0】视频写入(VideoWriter,借助samples中的代码示例来进行学习)
    借助官方离线文档中的samples来理解VideoWriter文档位置:samples/cpp/tutorial_code/videoio/video-write/video-write.cpp注:需要提前下载openh264-1.8.0-win64.dll,然后放在Release文件夹下,否则无法正确对输出文件进行编码从而运行失败1#include<iostream>2#include......
  • 在vscode中如何利用快捷键运行python文件
    通常运行python文件只能选择调试运行,或者右键点击需要鼠标点击比较麻烦可以自己设置一个快捷键在上方的搜索框键入>运行python文件点击这个齿轮由于我设置过了快捷键所以能看到Shift+R点击图中的标识,你就能编辑你想要的快捷键随后你就可以用新设置的快捷键在终端直......
  • 【华为OD机试真题 Python】人气最高的店铺|解题思路、代码解析
    文章目录题目描述输入输出示例1输入输出说明示例2输入输出说明解题思路实现代码题目描述某购物城有m个商铺,现决定举办一场活动选出人气最高店铺。活动共有n位市民参与,每位市民只能投一票,但1号店铺如果给该市民发放q元的购物补贴,该市民会改......
  • Python collections详细介绍及实例
    Python的collections库提供了许多有用的数据结构,这些数据结构是对内建数据类型的补充。以下是一些collections库中主要数据结构的详细介绍和示例:CounterCounter是一个字典子类,用于计数可哈希对象。常用于统计字符出现的次数、列表中元素出现的次数等。示例:fromcollections......
  • 运维常用的Python第三方模块及实例
    在运维工作中,Python是一种非常流行的脚本语言,因为它具有简洁的语法、丰富的库和跨平台的能力。运维工程师经常使用Python来编写自动化脚本,以简化日常任务。以下是一些运维常用的Python第三方模块及其示例:paramiko-用于SSH连接和执行命令。示例:importparamikossh=par......
  • python内置函数 C
    python内置函数CPython解释器内置了很多函数和类型,任何时候都能使用。C名称描述callable检查一个对象是否是可调用的。chr将整数(表示Unicode码点)转换为对应的字符。classmethod将一个方法转变为类方法。compile将源代码字符串编译为字节码对象。complex创建复数。call......
  • python内置函数 A
    python内置函数APython解释器内置了很多函数和类型,任何时候都能使用。A名称描述abs返回一个数的绝对值。aiter返回对象的异步迭代器。all所有元素均为真值(或可迭代对象为空)则返回True。anext获取异步迭代器中的下一个异步项。any任一元素为真值则返回True。ascii返......
  • Python 内置模块及实例
    Python有许多内置模块,这些模块提供了各种功能,如数学运算、文件操作、日期和时间处理、数据压缩等。以下是一些常用内置模块及其简单实例:math-提供数学函数和常量。实例:importmathprint(math.sqrt(16))#输出:4.0print(math.pi)#输出:3.1415926535897......