diff --git a/contributors/rs1973/process_img1.py b/contributors/rs1973/process_img1.py new file mode 100644 index 0000000..bfd7d97 --- /dev/null +++ b/contributors/rs1973/process_img1.py @@ -0,0 +1,139 @@ +"""" +Creator:rs1973 +E-mail:dingzheng_2023@qq.com/gunshi98@gmail.com +Description:支持输入一个目录或一张图片,修改它(或者整个目录里)的图片尺寸,色彩通道,并决定是否留下图像的 +alpha值,会自动筛选不是图片或不支持的格式 程序为多线程(多进程下使用笔记本测试时cpu过热),但gif合成 +暂时不支持多线程 + +ps:这是我的第一个项目,有很多做得不够好的地方,请多包容 +""" + +import os +import time +from concurrent.futures import ThreadPoolExecutor +from PIL import Image, ImageOps + +def get_img(srcpath=None, sinfile=None): + """筛选目录中的非图片文件,只筛选一层,不读取子目录里的文件""" + + img_lst = [] + not_img = '' + if srcpath: + for dirpath, dirname, filenames in os.walk(srcpath): + if filenames: + for img in filenames: + img = os.path.join(dirpath, img) + if os.path.isfile(img): + if os.path.splitext(img)[1].lower() in {".jpg", ".jpeg", ".png", ".bmp", ".tiff", '.webp'}: + img_lst.append(img) + else: + not_img += f'{img}\n' + else: + print(f'注意: 目录 {dirpath} 中没有图片') + return [] + + if not_img: + print(f'提示: 以下文件/目录不是图片:\n{not_img}') + return img_lst + + if sinfile: + if os.path.splitext(sinfile)[1].lower() in {".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff", '.webp'}: + return [sinfile] + else: + print(f'错误: 文件 {sinfile} 不是图片') + return [] + + +def normal_img(im, input_info: tuple, outpath: str, kind: str, img: str, alpha: bool): + """图像的缩放处理,每一个格式都会用到""" + if input_info: + x, y = input_info + if round(int(x) / im.size[0], 2) == round(int(y) / im.size[1], 2): + real_tuple = (int(x), int(y)) + im = im.resize(real_tuple) + else: + if not alpha: + pad_im = ImageOps.pad(im, (int(x), int(y)), color='#FFFFFF') + else: + pad_im = ImageOps.pad(im, (int(x), int(y)), + color=(0, 0, 0, 0), centering=(0.5, 0.5)) + + im = pad_im + + base_name = os.path.basename(img) + name_only = os.path.splitext(base_name)[0] + save_path = os.path.join(outpath, name_only + kind) + im.save(save_path, format=kind[1:].upper()) + im.close() + + +def gif(filenames=None, outpath=None, duration=300, name='index'): + """合成gif""" + try: + img_lst = [Image.open(i).copy().convert('RGB') for i in filenames] + img_lst[0].save( + os.path.join(outpath, f'{name}.gif'), + append_images=img_lst[1:], + duration=duration, + loop=0, + optimize=True + ) + except ValueError as e: + print(f'错误: 序列中图片大小不一致, {e}') + + +def process_img(outpath=None, input_info=None, kind=None, alpha=None, img=None): + """修改图片中的alpha""" + if kind in ('.png', '.webp', '.bmp'): + with Image.open(img) as im: + im = im.convert('RGBA') + if not alpha: + new_im = im.copy() + new_im.convert('RGB') + alpha_pixel = im.getdata() + write_pixel = [] + for item in alpha_pixel: + r, g, b, a = item + if a == 0: + write_pixel.append((255, 255, 255)) + else: + write_pixel.append((r, g, b)) + new_im.putdata(write_pixel) + im = new_im + normal_img(im, input_info, outpath, kind, img, alpha) + else: + with Image.open(img) as im: + if im.mode == 'RGBA': + im = im.convert('RGB') + normal_img(im, input_info, outpath, kind, img, alpha) + + +def main(srcpath: str = None, outpath: str = None, sinfile: str = None, + img_size: tuple = None, kind: str = '.jpeg', alpha: bool = False, + duration: int = 300, process: int = int(os.cpu_count()//2), name='index'): + """主逻辑函数""" + print('开始处理图片……') + start = time.time() + + filenames = get_img(srcpath, sinfile) + if not filenames: + return + + if kind == '.gif': + print('注意:请确保图像列表中所有图片的大小都一样') + gif(filenames, outpath, duration, name) + else: + with ThreadPoolExecutor(process) as pool: + futures = [pool.submit(process_img, outpath, + img_size, kind, alpha, img) for img in filenames] + for fut in futures: + fut.result() + + end = time.time() + print(f'处理完成, 耗时: {end - start:.2f}s') + +# src = r"C:\Users\rollingstone\OneDrive\Desktop\001" +# out = r"C:\Users\rollingstone\OneDrive\Desktop\s\re" + +# if __name__ == '__main__': +# main(srcpath=src, outpath=out, alpha=False, kind='.gif', name='hello', duration=250) diff --git a/contributors/rs1973/readme.md b/contributors/rs1973/readme.md new file mode 100644 index 0000000..3521029 --- /dev/null +++ b/contributors/rs1973/readme.md @@ -0,0 +1,46 @@ +# 批量图片尺寸与通道处理工具 + +**Creator:** rs1973 +**E-mail:** dingzheng_2023@qq.com / gunshi98@gmail.com + +本工具支持对 **单张图片** 或 **整个目录的全部图片** 进行批量处理,包括: + +- 调整图片尺寸 +- 统一色彩通道(可选择去除或保留透明通道 alpha) +- 批量导出到指定目录 +- 支持 `.jpg / .jpeg / .png / .bmp / .tiff / .webp` 格式 +- 支持 GIF 合成(单线程) + +程序内部使用 **多线程** 加速大量图片处理,默认为5线程。 + +--- + +## 功能特点 + +| 功能 | 说明 | +|-----|----------------------------------------------------------------| +| 批量筛选图片 | 自动忽略非图片文件 | +| 多线程处理 | 提升处理速度,默认为5线程 | +| 支持保留 / 去除透明通道 | 当输出格式支持alpha,可以选择保留或丢弃,丢弃时会将原本的alpha像素替换成白色(后续会添加颜色选择选项) | +| 自适应缩放或填充模式 | 保证目标尺寸一致:当目标大小小于原图时,会缩放/拉伸原图,大于且长宽比例与目标大小相同时,则直接缩放,反之则会用白色填充图片 | +| GIF 合成 | 可根据延迟参数调节帧率,默认300ms/帧 | + +--- + +## 基本使用示例 + +```python +from contributors.rs1973.process_img1.py import main + +src = r"C:\path\to\input_dir" +out = r"C:\path\to\output_dir" +size = (1000, 1000) + +main( + srcpath=src, + outpath=out, + img_size=size, + alpha=False, # 是否保留透明通道 + kind='.png', # 输出格式 + duration=300 # GIF 合成时的帧间隔,仅在 kind='.gif' 时使用 +) \ No newline at end of file diff --git a/tests/test_code/test_img.py b/tests/test_code/test_img.py new file mode 100644 index 0000000..e69de29