File size: 2,389 Bytes
38dcabe
 
599b9bf
38dcabe
599b9bf
38dcabe
 
 
 
 
 
 
 
 
 
 
 
 
599b9bf
 
 
 
 
38dcabe
 
 
 
 
 
 
 
 
 
 
599b9bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38dcabe
599b9bf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import os
import re
import io
import img2pdf
from PIL import Image  # 用于图像压缩

# --- 全局配置 ---
BASE_DIR = "download_cache"
PDF_FINAL_DIR = os.path.join(BASE_DIR, "final_pdfs")
os.makedirs(PDF_FINAL_DIR, exist_ok=True)

def natural_sort_key(s):
    return [int(text) if text.isdigit() else text.lower()
            for text in re.split(r'(\d+)', s)]

def sanitize_filename(name):
    return re.sub(r'[\\/*?:"<>|]', '_', name)

def manual_merge_pdf(album_dir, output_pdf_path, quality=100):
    """
    核心功能:将目录下的图片合并为 PDF
    :param quality: 图片质量 (1-100)。100为无损(原图打包),数字越小体积越小。
    """
    image_paths = []
    for root, _, files in os.walk(album_dir):
        for file in files:
            if file.lower().endswith(('.jpg', '.jpeg', '.png', '.webp')):
                image_paths.append(os.path.join(root, file))
    
    if not image_paths:
        raise Exception("目录中未找到任何图片")

    image_paths.sort(key=natural_sort_key)

    # === 分支 1: 无损模式 (秒成,体积大) ===
    if quality >= 100:
        with open(output_pdf_path, "wb") as f:
            f.write(img2pdf.convert(image_paths))
        return

    # === 分支 2: 压缩模式 (稍慢,体积小) ===
    # 将图片读入内存 -> 压缩 -> 转 PDF
    compressed_data = []
    
    for img_path in image_paths:
        try:
            with Image.open(img_path) as img:
                # 1. 如果是 RGBA (PNG透明底),转为 RGB,否则 JPEG 不支持
                if img.mode in ("RGBA", "P"):
                    img = img.convert("RGB")
                
                # 2. 存入内存缓冲流
                buffer = io.BytesIO()
                # optimize=True 还能再省点空间
                img.save(buffer, format="JPEG", quality=quality, optimize=True)
                
                # 3. 放入列表
                compressed_data.append(buffer.getvalue())
        except Exception as e:
            print(f"压缩图片出错 {img_path}: {e}")
            # 如果这张图压缩坏了,就直接把原图放进去,防止整个崩掉
            with open(img_path, "rb") as f:
                compressed_data.append(f.read())

    # 将压缩后的数据流写入 PDF
    with open(output_pdf_path, "wb") as f:
        f.write(img2pdf.convert(compressed_data))