import logging import os import random import requests from PIL import Image from PIL import ImageDraw, ImageFont, ImageEnhance from config import * from utils import safe_open_directory, safe_filename IMGS_BASE_PATH = CONFIG['General']['images_path'] def crop_and_replace_images(folder_path): """ 修改图片尺寸 :param folder_path: :return: """ print("开始处理图片。。。。") # 遍历文件夹中的所有文件 for filename in os.listdir(folder_path): # 检查文件扩展名是否为图片格式 if filename.lower().endswith(('.jpg')): # 拼接完整的文件路径 file_path = os.path.join(folder_path, filename) print("文件夹路径:" + folder_path) print("文件路径:" + file_path) # 打开图片 with Image.open(file_path) as img: # 获取图片的尺寸 width, height = img.size # 裁剪图片,裁剪下方10px print("裁剪图片。。。") cropped_img = img.crop((0, 0, width, height - (height * 0.1))) # 保存裁剪后的图片,覆盖原文件 # 通过拉伸使改变裁剪后图片的尺寸与原图片尺寸相同 resized_img = cropped_img.resize((width, height)) # output_path = file_path[0:file_path.find('.')] + '.png' resized_img.save(file_path, 'jpg') def deduplicate_images(folder_path): print("开始对图片去重。。。") """扫描 folder_path 下的图片,对每张图片做修改并直接覆盖原文件""" if not os.path.exists(folder_path): print("错误:输入文件夹不存在!") return supported_ext = ('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp') for root, _, files in os.walk(folder_path): for file in files: if file.lower().endswith(supported_ext): file_path = os.path.join(root, file) try: with Image.open(file_path) as img: modified_img = modify_image(img) modified_img.save(file_path) # 直接覆盖原图片 print(f"已处理并覆盖:{file_path}") except Exception as e: print(f"处理 {file_path} 时出错:{e}") def download_image(image_url, save_path): """ 下载图片并保存 :param image_url: 图片链接 :param save_path: 保存路径 :return: """ try: response = requests.get(image_url) if response.status_code == 200: with open(save_path, 'wb') as f: f.write(response.content) print(f"图片下载成功,保存路径为:{save_path}") else: print(f"图片下载失败,状态码为:{response.status_code}") except requests.exceptions.RequestException as e: print(f"请求出错:{e}") def download_and_process_images(img_urls, article_title, save_dir=None): """ 下载并处理图片 :param img_urls: 图片URL列表 :param article_title: 文章标题 :param save_dir: 自定义保存目录,如果为None则使用默认目录 """ if save_dir is None: save_dir = IMGS_BASE_PATH # 使用safe_filename处理文章标题 safe_title = safe_filename(article_title) # 使用os.path.normpath来规范化路径,避免路径分隔符的问题 img_dir_path = os.path.normpath(os.path.join(str(save_dir), safe_title)) logger.info(f"图片保存路径:{img_dir_path}") safe_open_directory(img_dir_path) for i, img_url in enumerate(img_urls): if img_url.startswith("https"): imgurl = img_url else: imgurl = "https:" + img_url # 使用os.path.normpath来规范化图片路径 img_path = os.path.normpath(os.path.join(img_dir_path, f"图片{i}.jpg")) try: download_image(imgurl, img_path) # 只处理当前下载的图片,而不是整个文件夹 with Image.open(img_path) as img: modified_img = modify_image(img) modified_img.save(img_path) # 直接覆盖原图片 print(f"已处理并覆盖:{img_path}") except Exception as e: logging.error(f"处理图片失败: {e}") # def download_and_process_images(img_urls, article_title, save_dir=None): # """ # 下载并处理图片 # :param img_urls: 图片URL列表 # :param article_title: 文章标题 # :param save_dir: 自定义保存目录,如果为None则使用默认目录 # """ # if save_dir is None: # save_dir = IMGS_BASE_PATH # # img_dir_path = os.path.join(str(save_dir), str(article_title)) # logger.info(f"图片保存路径:{img_dir_path}") # safe_open_directory(img_dir_path) # # for i, img_url in enumerate(img_urls): # if img_url.startswith("https"): # imgurl = img_url # else: # imgurl = "https:"+img_url # img_path = os.path.join(img_dir_path, f"图片{i}.jpg") # try: # download_image(imgurl, img_path) # # crop_and_replace_images(img_dir_path) # deduplicate_images(img_dir_path) # except Exception as e: # logging.error(f"处理图片失败: {e}") # def modify_image(img): # print("修改图片") # """对图片应用去重处理,不翻转,仅裁剪、旋转、亮度调整、添加水印、加透明蒙版""" # width, height = img.size # # # 从配置中获取参数 # crop_percent = float(CONFIG['ImageModify']['crop_percent']) # min_rotation = float(CONFIG['ImageModify']['min_rotation']) # max_rotation = float(CONFIG['ImageModify']['max_rotation']) # min_brightness = float(CONFIG['ImageModify']['min_brightness']) # max_brightness = float(CONFIG['ImageModify']['max_brightness']) # watermark_text = CONFIG['ImageModify']['watermark_text'] # watermark_opacity = int(CONFIG['ImageModify']['watermark_opacity']) # overlay_opacity = int(CONFIG['ImageModify']['overlay_opacity']) # # # 1. 裁剪边缘 # crop_px_w = int(width * crop_percent) # crop_px_h = int(height * crop_percent) # img = img.crop((crop_px_w, crop_px_h, width - crop_px_w, height - crop_px_h)) # # # 2. 随机旋转 # angle = random.uniform(min_rotation, max_rotation) * random.choice([-1, 1]) # img = img.rotate(angle, expand=True) # # # 3. 调整亮度 # enhancer = ImageEnhance.Brightness(img) # factor = random.uniform(min_brightness, max_brightness) # 亮度调整因子 # img = enhancer.enhance(factor) # # # 4. 添加文字水印 # draw = ImageDraw.Draw(img) # font_size = max(20, int(min(img.size) * 0.05)) # try: # font = ImageFont.truetype("arial.ttf", font_size) # except: # font = ImageFont.load_default() # # # 获取文本尺寸 # text_width, text_height = draw.textbbox((0, 0), watermark_text, font=font)[2:] # # # 水印放在图片右下角 # x = img.size[0] - text_width - 5 # y = img.size[1] - text_height - 5 # draw.text((x, y), watermark_text, font=font, fill=(255, 255, 255, watermark_opacity)) # # # 5. 添加半透明蒙版 # overlay = Image.new('RGBA', img.size, (255, 255, 255, overlay_opacity)) # if img.mode != 'RGBA': # img = img.convert('RGBA') # img = Image.alpha_composite(img, overlay) # # return img.convert('RGB') def modify_image(img): """ 对图片应用去重处理,不翻转,仅裁剪、旋转、亮度调整、添加水印、加透明蒙版 参数: img: PIL.Image对象,要处理的图片 返回: PIL.Image对象,处理后的图片 """ print("修改图片") # 确保图片是RGB模式 if img.mode != 'RGB': img = img.convert('RGB') # 从配置中获取参数 config = CONFIG['ImageModify'] crop_percent = float(config['crop_percent']) min_rotation = float(config['min_rotation']) max_rotation = float(config['max_rotation']) min_brightness = float(config['min_brightness']) max_brightness = float(config['max_brightness']) watermark_text = config['watermark_text'] watermark_opacity = int(config['watermark_opacity']) overlay_opacity = int(config['overlay_opacity']) # 1. 新增功能:裁剪图片下方20px img = crop_bottom(img, 20) # 2. 裁剪边缘 img = crop_edges(img, crop_percent) # 3. 随机旋转 img = random_rotate(img, min_rotation, max_rotation) # 4. 调整亮度 img = adjust_brightness(img, min_brightness, max_brightness) # 5. 添加文字水印 img = add_watermark(img, watermark_text, watermark_opacity) # 6. 添加半透明蒙版 img = add_overlay(img, overlay_opacity) # 返回RGB模式的图片 return img.convert('RGB') def crop_bottom(img, pixels): """ 裁剪图片底部指定像素 参数: img: PIL.Image对象,要裁剪的图片 pixels: int,要裁剪的像素数 返回: PIL.Image对象,裁剪后的图片 """ width, height = img.size if height > pixels: # 确保图片高度大于要裁剪的像素 return img.crop((0, 0, width, height - pixels)) return img def crop_edges(img, percent): """ 按比例裁剪图片边缘 参数: img: PIL.Image对象,要裁剪的图片 percent: float,裁剪比例(0-1之间) 返回: PIL.Image对象,裁剪后的图片 """ width, height = img.size crop_px_w = int(width * percent) crop_px_h = int(height * percent) return img.crop((crop_px_w, crop_px_h, width - crop_px_w, height - crop_px_h)) def random_rotate(img, min_rotation, max_rotation): """ 随机旋转图片 参数: img: PIL.Image对象,要旋转的图片 min_rotation: float,最小旋转角度 max_rotation: float,最大旋转角度 返回: PIL.Image对象,旋转后的图片 """ angle = random.uniform(min_rotation, max_rotation) * random.choice([-1, 1]) return img.rotate(angle, expand=True) def adjust_brightness(img, min_brightness, max_brightness): """ 调整图片亮度 参数: img: PIL.Image对象,要调整亮度的图片 min_brightness: float,最小亮度因子 max_brightness: float,最大亮度因子 返回: PIL.Image对象,调整亮度后的图片 """ enhancer = ImageEnhance.Brightness(img) factor = random.uniform(min_brightness, max_brightness) return enhancer.enhance(factor) def add_watermark(img, text, opacity): """ 添加文字水印到图片右下角 参数: img: PIL.Image对象,要添加水印的图片 text: str,水印文本 opacity: int,水印透明度(0-255) 返回: PIL.Image对象,添加水印后的图片 """ # 确保图片是RGBA模式以支持透明度 if img.mode != 'RGBA': img = img.convert('RGBA') draw = ImageDraw.Draw(img) font_size = max(20, int(min(img.size) * 0.05)) try: font = ImageFont.truetype("arial.ttf", font_size) except: font = ImageFont.load_default() # 获取文本尺寸 text_width, text_height = draw.textbbox((0, 0), text, font=font)[2:] # 确保水印不超出图片边界 x = max(5, img.size[0] - text_width - 5) y = max(5, img.size[1] - text_height - 5) # 添加水印 draw.text((x, y), text, font=font, fill=(255, 255, 255, opacity)) return img def add_overlay(img, opacity): """ 添加半透明蒙版 参数: img: PIL.Image对象,要添加蒙版的图片 opacity: int,蒙版透明度(0-255) 返回: PIL.Image对象,添加蒙版后的图片 """ # 确保图片是RGBA模式以支持透明度 if img.mode != 'RGBA': img = img.convert('RGBA') overlay = Image.new('RGBA', img.size, (255, 255, 255, opacity)) return Image.alpha_composite(img, overlay)