86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
import os
|
||
import pathlib
|
||
import subprocess
|
||
from typing import Union
|
||
|
||
import matplotlib
|
||
import matplotlib.pyplot as plt
|
||
|
||
|
||
class Week1:
|
||
def __init__(self):
|
||
# 避免覆盖内置名 list
|
||
self.qualities = [2, 7, 12, 17, 22, 27, 31]
|
||
|
||
def _ffmpeg_path(self) -> pathlib.Path:
|
||
"""
|
||
返回项目 bin 目录下 ffmpeg 的可执行路径。
|
||
Week1/Week1.py 位于项目的 Week1 目录内,bin 与 Week1 处于同级。
|
||
"""
|
||
here = pathlib.Path(__file__).resolve()
|
||
project_root = here.parent.parent # <project_root>/Week1/Week1.py -> <project_root>
|
||
bin_dir = project_root / "bin"
|
||
exe_name = "ffmpeg.exe" if os.name == "nt" else "ffmpeg"
|
||
ffmpeg = bin_dir / exe_name
|
||
if not ffmpeg.exists():
|
||
raise FileNotFoundError(f"未找到 ffmpeg 可执行文件: {ffmpeg}")
|
||
return ffmpeg
|
||
|
||
def compress(self, image_src: Union[str, pathlib.Path]):
|
||
"""
|
||
使用不同 q:v 质量参数将 PNG 转为 JPEG。
|
||
输出文件与输入文件位于同目录,命名为 <原名>_<q>.jpg
|
||
"""
|
||
image_path = pathlib.Path(image_src).resolve()
|
||
if not image_path.exists():
|
||
raise FileNotFoundError(f"输入图像不存在: {image_path}")
|
||
|
||
ffmpeg = self._ffmpeg_path()
|
||
stem = image_path.stem
|
||
parent = image_path.parent
|
||
|
||
for q in self.qualities:
|
||
out_path = parent / f"{stem}_{q}.jpg"
|
||
# -y 覆盖已存在文件;参数以列表方式传入
|
||
cmd = [
|
||
str(ffmpeg),
|
||
"-y",
|
||
"-i", str(image_path),
|
||
"-q:v", str(q),
|
||
str(out_path),
|
||
]
|
||
# 失败时抛异常,便于定位问题
|
||
subprocess.run(cmd, check=True)
|
||
|
||
def render(self, image_src: Union[str, pathlib.Path]):
|
||
"""
|
||
读取生成的 JPEG 文件大小,并绘制质量(q) vs 文件大小(bytes) 的折线图。
|
||
"""
|
||
image_path = pathlib.Path(image_src).resolve()
|
||
stem = image_path.stem
|
||
parent = image_path.parent
|
||
|
||
sizes = []
|
||
qualities = []
|
||
for q in self.qualities:
|
||
jpg_path = parent / f"{stem}_{q}.jpg"
|
||
if not jpg_path.exists():
|
||
# 若缺失,给出清晰异常,提示先运行 compress
|
||
raise FileNotFoundError(f"缺少压缩输出文件,请先运行 compress: {jpg_path}")
|
||
qualities.append(q)
|
||
sizes.append(os.path.getsize(jpg_path)/8)
|
||
|
||
# 使用 pyplot 正确保存图像
|
||
plt.figure(figsize=(6, 4))
|
||
plt.plot(qualities, sizes, marker="o")
|
||
plt.xlabel("JPEG quality (q:v)")
|
||
plt.ylabel("File size (Kbytes)")
|
||
plt.title("Quality vs File Size")
|
||
plt.grid(True)
|
||
|
||
project_root = pathlib.Path(__file__).resolve().parent.parent
|
||
out_png = project_root / "data" / "render.png"
|
||
out_png.parent.mkdir(parents=True, exist_ok=True)
|
||
plt.tight_layout()
|
||
plt.savefig(str(out_png))
|
||
plt.close() |