解决句柄占用问题。
This commit is contained in:
@@ -150,12 +150,11 @@ def download_image(img_url, folder_path, img_index, max_retries=3):
|
|||||||
time.sleep(2 * (attempt + 1))
|
time.sleep(2 * (attempt + 1))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
img = Image.open(BytesIO(response.content)).convert('RGB')
|
with Image.open(BytesIO(response.content)).convert('RGB') as img:
|
||||||
img_name = f"{img_index:03d}.jpg"
|
img_name = f"{img_index:03d}.jpg"
|
||||||
img_path = os.path.join(folder_path, img_name)
|
img_path = os.path.join(folder_path, img_name)
|
||||||
|
img.save(img_path, 'JPEG', quality=95)
|
||||||
img.save(img_path, 'JPEG', quality=95)
|
logger.info(f"已下载并转换为JPG: {img_path}")
|
||||||
logger.info(f"已下载并转换为JPG: {img_path}")
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -8,45 +8,45 @@ import io
|
|||||||
|
|
||||||
def compress_image(image_path, target_size_kb=300):
|
def compress_image(image_path, target_size_kb=300):
|
||||||
"""快速压缩图片到目标大小(单位:KB)"""
|
"""快速压缩图片到目标大小(单位:KB)"""
|
||||||
img = PILImage.open(image_path)
|
with PILImage.open(image_path) as img:
|
||||||
|
# 调整图片尺寸,保持宽高比
|
||||||
|
# 如果图片有透明度,转换为RGB
|
||||||
|
if img.mode in ('RGBA', 'P'):
|
||||||
|
img = img.convert('RGB')
|
||||||
|
|
||||||
# 如果图片有透明度,转换为RGB
|
# 获取原始文件大小(KB)
|
||||||
if img.mode in ('RGBA', 'P'):
|
original_size_kb = os.path.getsize(image_path) / 1024
|
||||||
img = img.convert('RGB')
|
|
||||||
|
|
||||||
# 获取原始文件大小(KB)
|
# 如果原始大小已小于目标大小,直接返回原始数据
|
||||||
original_size_kb = os.path.getsize(image_path) / 1024
|
if original_size_kb <= target_size_kb:
|
||||||
|
output = io.BytesIO()
|
||||||
|
img.save(output, format='JPEG', quality=85)
|
||||||
|
return output.getvalue()
|
||||||
|
|
||||||
|
# 根据原始大小和目标大小预估初始质量
|
||||||
|
# 假设质量与文件大小近似线性关系,设置一个初始值
|
||||||
|
estimated_quality = min(95, max(10, int(85 * (target_size_kb / original_size_kb))))
|
||||||
|
|
||||||
# 如果原始大小已小于目标大小,直接返回原始数据
|
|
||||||
if original_size_kb <= target_size_kb:
|
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
img.save(output, format='JPEG', quality=85)
|
img.save(output, format='JPEG', quality=estimated_quality)
|
||||||
return output.getvalue()
|
size_kb = len(output.getvalue()) / 1024
|
||||||
|
|
||||||
# 根据原始大小和目标大小预估初始质量
|
# 如果预估结果偏差较大,使用二分法调整(最多尝试3次)
|
||||||
# 假设质量与文件大小近似线性关系,设置一个初始值
|
low, high = 10, 95
|
||||||
estimated_quality = min(95, max(10, int(85 * (target_size_kb / original_size_kb))))
|
for _ in range(3):
|
||||||
|
if size_kb <= target_size_kb * 0.9 or size_kb >= target_size_kb * 1.1: # 允许±10%偏差
|
||||||
|
quality = (low + high) // 2
|
||||||
|
output.seek(0)
|
||||||
|
output.truncate(0)
|
||||||
|
img.save(output, format='JPEG', quality=quality)
|
||||||
|
size_kb = len(output.getvalue()) / 1024
|
||||||
|
|
||||||
output = io.BytesIO()
|
if size_kb > target_size_kb:
|
||||||
img.save(output, format='JPEG', quality=estimated_quality)
|
high = quality - 1
|
||||||
size_kb = len(output.getvalue()) / 1024
|
else:
|
||||||
|
low = quality + 1
|
||||||
# 如果预估结果偏差较大,使用二分法调整(最多尝试3次)
|
|
||||||
low, high = 10, 95
|
|
||||||
for _ in range(3):
|
|
||||||
if size_kb <= target_size_kb * 0.9 or size_kb >= target_size_kb * 1.1: # 允许±10%偏差
|
|
||||||
quality = (low + high) // 2
|
|
||||||
output.seek(0)
|
|
||||||
output.truncate(0)
|
|
||||||
img.save(output, format='JPEG', quality=quality)
|
|
||||||
size_kb = len(output.getvalue()) / 1024
|
|
||||||
|
|
||||||
if size_kb > target_size_kb:
|
|
||||||
high = quality - 1
|
|
||||||
else:
|
else:
|
||||||
low = quality + 1
|
break
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
return output.getvalue()
|
return output.getvalue()
|
||||||
|
|
||||||
@@ -85,8 +85,8 @@ def create_pdf_from_images(directory, output_pdf):
|
|||||||
compressed_image_data = compress_image(image_file)
|
compressed_image_data = compress_image(image_file)
|
||||||
|
|
||||||
# 从压缩字节数据中读取图片以获取新尺寸
|
# 从压缩字节数据中读取图片以获取新尺寸
|
||||||
compressed_img = PILImage.open(io.BytesIO(compressed_image_data))
|
with PILImage.open(io.BytesIO(compressed_image_data)) as compressed_img:
|
||||||
img_width, img_height = compressed_img.size
|
img_width, img_height = compressed_img.size
|
||||||
|
|
||||||
# 设置目标宽度(适应A3页面宽度,最大800点)
|
# 设置目标宽度(适应A3页面宽度,最大800点)
|
||||||
target_width = 800
|
target_width = 800
|
||||||
|
|||||||
@@ -182,27 +182,25 @@ def fetch_and_create_pdf(url):
|
|||||||
if image:
|
if image:
|
||||||
try:
|
try:
|
||||||
# 使用PIL处理图片尺寸
|
# 使用PIL处理图片尺寸
|
||||||
img = PILImage.open(image)
|
with PILImage.open(image) as img:
|
||||||
img_width, img_height = img.size
|
img_width, img_height = img.size
|
||||||
|
# 计算缩放比例,确保图片适应页面
|
||||||
# 计算缩放比例,确保图片适应页面
|
scale_width = max_image_width / img_width
|
||||||
scale_width = max_image_width / img_width
|
scale_height = max_image_height / img_height
|
||||||
scale_height = max_image_height / img_height
|
scale = min(scale_width, scale_height, 1.0) # 不超过原始大小
|
||||||
scale = min(scale_width, scale_height, 1.0) # 不超过原始大小
|
|
||||||
|
# 计算新的尺寸
|
||||||
# 计算新的尺寸
|
new_width = img_width * scale
|
||||||
new_width = img_width * scale
|
new_height = img_height * scale
|
||||||
new_height = img_height * scale
|
|
||||||
|
# 重置文件指针
|
||||||
# 重置文件指针
|
image.seek(0)
|
||||||
image.seek(0)
|
img_stream = BytesIO(image.getvalue())
|
||||||
img_stream = BytesIO(image.getvalue())
|
|
||||||
|
# 添加图片到内容中,使用计算后的尺寸
|
||||||
# 添加图片到内容中,使用计算后的尺寸
|
content.append(Image(img_stream, width=new_width, height=new_height))
|
||||||
content.append(Image(img_stream, width=new_width, height=new_height))
|
content.append(Spacer(1, 4))
|
||||||
content.append(Spacer(1, 4))
|
print(f"处理图片: 原始尺寸 {img_width}x{img_height}, 新尺寸 {new_width}x{new_height}")
|
||||||
|
|
||||||
print(f"处理图片: 原始尺寸 {img_width}x{img_height}, 新尺寸 {new_width}x{new_height}")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"处理图片时出错: {e}")
|
print(f"处理图片时出错: {e}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user