chore: 添加 MIT LICENSE、完善 README 并忽略 .vscode 文件夹
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ wheels/
|
|||||||
|
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
|
.vscode
|
||||||
7
LICENSE
Normal file
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Copyright 2026 SidneyZhang
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
89
README.md
89
README.md
@@ -0,0 +1,89 @@
|
|||||||
|
# pptopic
|
||||||
|
|
||||||
|
将 PowerPoint 演示文稿导出为长图的工具。
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
- 📊 **PPT 转长图**:将 PPTX 文件导出为一张连续的长图
|
||||||
|
- 🖼️ **图片优化**:支持使用 `pngquant` 进行无损压缩
|
||||||
|
- ⚙️ **灵活配置**:可自定义输出尺寸、格式、保存路径等
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
- **Windows 系统**(依赖 PowerPoint COM 接口)
|
||||||
|
- Python ≥ 3.13
|
||||||
|
- 已安装 Microsoft PowerPoint
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install pptopic
|
||||||
|
```
|
||||||
|
|
||||||
|
如需图片优化功能,请安装 `pngquant`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scoop install pngquant
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以使用你熟悉的图片优化引擎替代 `pngquant` ,但一般情况下,我更推荐 `pngquant` 。
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
|
||||||
|
### 导出长图
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 基本用法
|
||||||
|
pptopic export presentation.pptx
|
||||||
|
|
||||||
|
# 指定输出文件名和目录
|
||||||
|
pptopic export presentation.pptx -o result.png -d ./output
|
||||||
|
|
||||||
|
# 自定义宽度并启用优化
|
||||||
|
pptopic export presentation.pptx --width 1200 --optimize
|
||||||
|
```
|
||||||
|
|
||||||
|
### 优化图片
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 优化现有图片
|
||||||
|
pptopic optimize image.png
|
||||||
|
|
||||||
|
# 指定输出路径和最大高度
|
||||||
|
pptopic optimize image.png -o optimized.png --max-height 20000
|
||||||
|
```
|
||||||
|
|
||||||
|
## 命令选项
|
||||||
|
|
||||||
|
### export 命令
|
||||||
|
|
||||||
|
| 选项 | 简写 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `--output` | `-o` | 输出文件名 |
|
||||||
|
| `--dir` | `-d` | 输出目录(默认当前目录) |
|
||||||
|
| `--width` | `-w` | 导出图片宽度(像素) |
|
||||||
|
| `--format` | `-f` | 输出格式:JPG 或 PNG(默认 PNG) |
|
||||||
|
| `--optimize` | - | 启用图片优化 |
|
||||||
|
| `--max-height` | - | 优化时最大高度(默认 29999) |
|
||||||
|
|
||||||
|
### optimize 命令
|
||||||
|
|
||||||
|
| 选项 | 简写 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `--output` | `-o` | 输出文件路径 |
|
||||||
|
| `--max-height` | - | 最大高度限制 |
|
||||||
|
| `--engine` | - | 优化引擎(默认 pngquant) |
|
||||||
|
|
||||||
|
## 示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 导出并优化
|
||||||
|
pptopic export presentation.pptx --optimize
|
||||||
|
|
||||||
|
# 导出为 JPG 格式
|
||||||
|
pptopic export presentation.pptx -f JPG -o result
|
||||||
|
```
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "pptopic"
|
name = "pptopic"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
description = "导出长图"
|
description = "导出长图"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|||||||
@@ -1 +1,7 @@
|
|||||||
from pptopic.main import main
|
from pptopic.main import main
|
||||||
|
|
||||||
|
__version__ = "0.3.0"
|
||||||
|
|
||||||
|
__author__ = "Sidney Zhang <zly@lyzhang.me>"
|
||||||
|
|
||||||
|
__all__ = ["main"]
|
||||||
|
|||||||
@@ -1,32 +1,30 @@
|
|||||||
from typing import Self
|
|
||||||
from pathlib import Path
|
|
||||||
import cv2
|
|
||||||
from PIL import Image
|
|
||||||
from tempfile import TemporaryDirectory
|
|
||||||
import win32com.client as wcc
|
|
||||||
import shutil
|
import shutil
|
||||||
import numpy as np
|
|
||||||
from simtoolsz.utils import lastFile
|
|
||||||
import sys
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from typing import Self
|
||||||
|
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import win32com.client as wcc
|
||||||
|
from PIL import Image
|
||||||
|
from simtoolsz.utils import lastFile
|
||||||
|
|
||||||
__all__ = ["convertPPT", "PPT_longPic", "imageOptimization"]
|
__all__ = ["convertPPT", "PPT_longPic", "imageOptimization"]
|
||||||
|
|
||||||
class convertPPT(object):
|
|
||||||
|
class convertPPT:
|
||||||
"""
|
"""
|
||||||
win32com使用VBA的API,可从官方教程中看到:
|
win32com使用VBA的API,可从官方教程中看到:
|
||||||
https://learn.microsoft.com/en-us/office/vba/api/PowerPoint.Presentation.SaveAs
|
https://learn.microsoft.com/en-us/office/vba/api/PowerPoint.Presentation.SaveAs
|
||||||
编码来源:https://my.oschina.net/zxcholmes/blog/484789
|
编码来源:https://my.oschina.net/zxcholmes/blog/484789
|
||||||
"""
|
"""
|
||||||
TTYPES = {
|
|
||||||
"JPG" : 17,
|
TTYPES = {"JPG": 17, "PNG": 18, "PDF": 32, "XPS": 33}
|
||||||
"PNG" : 18,
|
|
||||||
"PDF" : 32,
|
|
||||||
"XPS" : 33
|
|
||||||
}
|
|
||||||
__all__ = ["savetype", "trans", "close", "open"]
|
__all__ = ["savetype", "trans", "close", "open"]
|
||||||
|
|
||||||
def __init__(self, file:str|Path, trans:str = "JPG") -> None:
|
def __init__(self, file: str | Path, trans: str = "JPG") -> None:
|
||||||
if sys.platform != "win32":
|
if sys.platform != "win32":
|
||||||
raise SystemError("Only support Windows system.")
|
raise SystemError("Only support Windows system.")
|
||||||
if not Path(file).exists():
|
if not Path(file).exists():
|
||||||
@@ -35,114 +33,126 @@ class convertPPT(object):
|
|||||||
raise ValueError("Save type is not supported.")
|
raise ValueError("Save type is not supported.")
|
||||||
self.__file = Path(file)
|
self.__file = Path(file)
|
||||||
self.__saveType = (convertPPT.TTYPES[trans.upper()], trans.upper())
|
self.__saveType = (convertPPT.TTYPES[trans.upper()], trans.upper())
|
||||||
self.__inUsing = wcc.Dispatch('PowerPoint.Application')
|
self.__inUsing = wcc.Dispatch("PowerPoint.Application")
|
||||||
|
|
||||||
def __enter__(self) -> Self:
|
def __enter__(self) -> Self:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def savetype(self) -> str :
|
def savetype(self) -> str:
|
||||||
return self.__saveType[1]
|
return self.__saveType[1]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def open(cls, file:str|Path, trans:str = "JPG") -> Self :
|
def open(cls, file: str | Path, trans: str = "JPG") -> Self:
|
||||||
return cls(file, trans = trans.upper())
|
return cls(file, trans=trans.upper())
|
||||||
def saveAs(self, saveType:str|None = None) -> None :
|
|
||||||
|
def saveAs(self, saveType: str | None = None) -> None:
|
||||||
if saveType not in convertPPT.TTYPES.keys():
|
if saveType not in convertPPT.TTYPES.keys():
|
||||||
raise ValueError("Save type is not supported.")
|
raise ValueError("Save type is not supported.")
|
||||||
if saveType is not None:
|
if saveType is not None:
|
||||||
self.__saveType = (convertPPT.TTYPES[saveType.upper()], saveType.upper())
|
self.__saveType = (convertPPT.TTYPES[saveType.upper()], saveType.upper())
|
||||||
else:
|
else:
|
||||||
self.__saveType = (convertPPT.TTYPES["JPG"], "JPG")
|
self.__saveType = (convertPPT.TTYPES["JPG"], "JPG")
|
||||||
def trans(self, saveto:str|Path = ".",
|
|
||||||
width:int|None = None) -> None :
|
def trans(self, saveto: str | Path = ".", width: int | None = None) -> None:
|
||||||
"""
|
"""
|
||||||
saveto : 保存路径,默认为当前路径。
|
saveto : 保存路径,默认为当前路径。
|
||||||
"""
|
"""
|
||||||
ppt = self.__inUsing.Presentations.Open(self.__file.absolute())
|
ppt = self.__inUsing.Presentations.Open(self.__file.absolute())
|
||||||
if Path(saveto) == Path('.') :
|
if Path(saveto) == Path("."):
|
||||||
output = self.__file.absolute()
|
output = self.__file.absolute()
|
||||||
else :
|
else:
|
||||||
output = Path(saveto).absolute()
|
output = Path(saveto).absolute()
|
||||||
if width is not None :
|
if width is not None:
|
||||||
ppt.Export(output, self.__saveType[1], width)
|
ppt.Export(output, self.__saveType[1], width)
|
||||||
else:
|
else:
|
||||||
ppt.SaveAs(output, self.__saveType[0])
|
ppt.SaveAs(output, self.__saveType[0])
|
||||||
def close(self, to_console:bool = False) -> None :
|
|
||||||
|
def close(self, to_console: bool = False) -> None:
|
||||||
self.__inUsing.Quit()
|
self.__inUsing.Quit()
|
||||||
if to_console :
|
if to_console:
|
||||||
print("File converted successfully.")
|
print("File converted successfully.")
|
||||||
|
|
||||||
|
|
||||||
def PPT_longPic(pptFile:str|Path, saveName:str|None = None, width:int|str|None = None,
|
def PPT_longPic(
|
||||||
saveto:str|Path = ".") -> None :
|
pptFile: str | Path, saveName: str | None = None, width: int | str | None = None, saveto: str | Path = "."
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
width : 画幅宽度,可以直接指定宽度像素,也可以使用字符串数据输入百分比。
|
width : 画幅宽度,可以直接指定宽度像素,也可以使用字符串数据输入百分比。
|
||||||
(700; "22.1%")
|
(700; "22.1%")
|
||||||
指定为None的时候,不进行图像缩放。
|
指定为None的时候,不进行图像缩放。
|
||||||
"""
|
"""
|
||||||
if saveName :
|
if saveName:
|
||||||
sType = saveName.split(".")[-1] if "." in saveName else "JPG"
|
sType = saveName.split(".")[-1] if "." in saveName else "JPG"
|
||||||
if sType.upper() not in ["JPG", "PNG"] :
|
if sType.upper() not in ["JPG", "PNG"]:
|
||||||
raise ValueError("Unable to save this type `{}` of image.".format(sType))
|
raise ValueError(f"Unable to save this type `{sType}` of image.")
|
||||||
else:
|
else:
|
||||||
sType = "JPG"
|
sType = "JPG"
|
||||||
with TemporaryDirectory() as tmpdirname:
|
with TemporaryDirectory() as tmpdirname:
|
||||||
with convertPPT(pptFile, trans=sType) as ppt:
|
with convertPPT(pptFile, trans=sType) as ppt:
|
||||||
ppt.trans(saveto=tmpdirname)
|
ppt.trans(saveto=tmpdirname)
|
||||||
picList = list(Path(tmpdirname).glob("*.{}".format(sType)))
|
picList = list(Path(tmpdirname).glob(f"*.{sType}"))
|
||||||
with Image.open(picList[0]) as img :
|
with Image.open(picList[0]) as img:
|
||||||
if isinstance(width, str):
|
if isinstance(width, str):
|
||||||
qw = float(width[:-1])/100.0
|
qw = float(width[:-1]) / 100.0
|
||||||
nwidth, nheight = (int(img.width*qw), int(img.height*qw))
|
nwidth, nheight = (int(img.width * qw), int(img.height * qw))
|
||||||
elif width is None:
|
elif width is None:
|
||||||
nwidth, nheight = img.size
|
nwidth, nheight = img.size
|
||||||
else:
|
else:
|
||||||
nwidth, nheight = (width, int(img.height*width/img.width))
|
nwidth, nheight = (width, int(img.height * width / img.width))
|
||||||
canvas = Image.new(img.mode, (nwidth, nheight * len(picList)))
|
canvas = Image.new(img.mode, (nwidth, nheight * len(picList)))
|
||||||
for i in range(1,len(picList)+1) :
|
for i in range(1, len(picList) + 1):
|
||||||
with Image.open(Path(tmpdirname).joinpath("幻灯片{}.{}".format(i,sType))) as img :
|
with Image.open(Path(tmpdirname).joinpath(f"幻灯片{i}.{sType}")) as img:
|
||||||
new_img = img.resize((nwidth,nheight), resample=Image.Resampling.LANCZOS)
|
new_img = img.resize((nwidth, nheight), resample=Image.Resampling.LANCZOS)
|
||||||
canvas.paste(new_img, box=(0, (i-1) * nheight))
|
canvas.paste(new_img, box=(0, (i - 1) * nheight))
|
||||||
if Path(saveto) == Path('.') :
|
if Path(saveto) == Path("."):
|
||||||
filepath = Path(pptFile).parent
|
filepath = Path(pptFile).parent
|
||||||
else :
|
else:
|
||||||
filepath = Path(saveto)
|
filepath = Path(saveto)
|
||||||
if saveName :
|
if saveName:
|
||||||
if '.' in saveName :
|
if "." in saveName:
|
||||||
canvas.save(filepath.joinpath(saveName))
|
canvas.save(filepath.joinpath(saveName))
|
||||||
else:
|
else:
|
||||||
canvas.save(filepath.joinpath(saveName), format=sType)
|
canvas.save(filepath.joinpath(saveName), format=sType)
|
||||||
else:
|
else:
|
||||||
canvas.save(filepath.joinpath(Path(pptFile).stem), format=sType)
|
canvas.save(filepath.joinpath(Path(pptFile).stem), format=sType)
|
||||||
|
|
||||||
def imageOptimization(imageFile:str|Path|Image.Image, saveFile:str|Path|None = None,
|
|
||||||
max_width:int = None, max_height:int = None,
|
def imageOptimization(
|
||||||
engine:str|None = "pngquant",
|
imageFile: str | Path | Image.Image,
|
||||||
engine_conf:str|None = None) -> Image.Image|None :
|
saveFile: str | Path | None = None,
|
||||||
|
max_width: int = None,
|
||||||
|
max_height: int = None,
|
||||||
|
engine: str | None = "pngquant",
|
||||||
|
engine_conf: str | None = None,
|
||||||
|
) -> Image.Image | None:
|
||||||
"""图片优化、无损压缩
|
"""图片优化、无损压缩
|
||||||
默认建议使用pngquant进行无损压缩,也可以设置为其他图片无损压缩引擎,
|
默认建议使用pngquant进行无损压缩,也可以设置为其他图片无损压缩引擎,
|
||||||
不需要针对性压缩,可设定engine为None。
|
不需要针对性压缩,可设定engine为None。
|
||||||
"""
|
"""
|
||||||
if isinstance(imageFile, (str, Path)):
|
if isinstance(imageFile, str | Path):
|
||||||
imageFile = Image.open(imageFile)
|
imageFile = Image.open(imageFile)
|
||||||
img = cv2.cvtColor(np.array(imageFile), cv2.COLOR_RGB2BGR)
|
img = cv2.cvtColor(np.array(imageFile), cv2.COLOR_RGB2BGR)
|
||||||
if max_width or max_height :
|
if max_width or max_height:
|
||||||
height, width, _ = img.shape
|
height, width, _ = img.shape
|
||||||
oShape = (width, height)
|
oShape = (width, height)
|
||||||
if max_width :
|
if max_width:
|
||||||
if width > max_width :
|
if width > max_width:
|
||||||
height = int(height * max_width / width)
|
height = int(height * max_width / width)
|
||||||
width = max_width
|
width = max_width
|
||||||
if max_width < 1 :
|
if max_width < 1:
|
||||||
width = int(width * max_width)
|
width = int(width * max_width)
|
||||||
height = int(height * max_width)
|
height = int(height * max_width)
|
||||||
if max_height :
|
if max_height:
|
||||||
if height > max_height :
|
if height > max_height:
|
||||||
width = int(width * max_height / height)
|
width = int(width * max_height / height)
|
||||||
height = max_height
|
height = max_height
|
||||||
if max_height < 1 :
|
if max_height < 1:
|
||||||
if width < oShape[0] :
|
if width < oShape[0]:
|
||||||
if height / oShape[1] > max_height :
|
if height / oShape[1] > max_height:
|
||||||
height = int(oShape[1] * max_height)
|
height = int(oShape[1] * max_height)
|
||||||
width = int(oShape[0] * max_height)
|
width = int(oShape[0] * max_height)
|
||||||
else:
|
else:
|
||||||
@@ -150,18 +160,18 @@ def imageOptimization(imageFile:str|Path|Image.Image, saveFile:str|Path|None = N
|
|||||||
width = int(width * max_height)
|
width = int(width * max_height)
|
||||||
img = cv2.resize(img, (width, height))
|
img = cv2.resize(img, (width, height))
|
||||||
res = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
|
res = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
|
||||||
with TemporaryDirectory(prefix="pytoolsz") as tmpFolder :
|
with TemporaryDirectory(prefix="pytoolsz") as tmpFolder:
|
||||||
res.save(Path(tmpFolder)/"tmp.png", compress_level=2, quality=100)
|
res.save(Path(tmpFolder) / "tmp.png", compress_level=2, quality=100)
|
||||||
if engine :
|
if engine:
|
||||||
try:
|
try:
|
||||||
subprocess.run([engine, engine_conf, Path(tmpFolder)/"tmp.png"], shell=True, check=True)
|
subprocess.run([engine, engine_conf, Path(tmpFolder) / "tmp.png"], shell=True, check=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("未安装pngquant,不能进行图片优化压缩。\n可使用`scoop install pngquant`进行安装。")
|
print("未安装pngquant,不能进行图片优化压缩。\n可使用`scoop install pngquant`进行安装。")
|
||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
res.save(Path(tmpFolder)/"tmp.png", compress_level=7, quality=95)
|
res.save(Path(tmpFolder) / "tmp.png", compress_level=7, quality=95)
|
||||||
if saveFile is None :
|
if saveFile is None:
|
||||||
res = Image.open(lastFile(Path(tmpFolder), "*.*"))
|
res = Image.open(lastFile(Path(tmpFolder), "*.*"))
|
||||||
return res
|
return res
|
||||||
else :
|
else:
|
||||||
shutil.copyfile(lastFile(Path(tmpFolder), "*.*"), saveFile)
|
shutil.copyfile(lastFile(Path(tmpFolder), "*.*"), saveFile)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from simtoolsz.utils import today
|
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
from simtoolsz.utils import today
|
||||||
|
|
||||||
from pptopic.lib import PPT_longPic, imageOptimization
|
from pptopic.lib import PPT_longPic, imageOptimization
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def export(
|
def export(
|
||||||
input_file: Path = typer.Argument(..., help="输入的PPTX文件路径", exists=True),
|
input_file: Path = typer.Argument(..., help="输入的PPTX文件路径", exists=True),
|
||||||
@@ -16,12 +17,14 @@ def export(
|
|||||||
optimize: bool = typer.Option(False, "--optimize", help="是否优化导出的图片"),
|
optimize: bool = typer.Option(False, "--optimize", help="是否优化导出的图片"),
|
||||||
max_height: int = typer.Option(29999, "--max-height", help="优化图片的最大高度(默认29999)"),
|
max_height: int = typer.Option(29999, "--max-height", help="优化图片的最大高度(默认29999)"),
|
||||||
engine: str = typer.Option("pngquant", "--engine", help="图片优化引擎(默认pngquant)"),
|
engine: str = typer.Option("pngquant", "--engine", help="图片优化引擎(默认pngquant)"),
|
||||||
engine_conf: str = typer.Option("--skip-if-larger", "--engine-conf", help="图片优化引擎配置参数(默认--skip-if-larger)"),
|
engine_conf: str = typer.Option(
|
||||||
format: str = typer.Option("PNG", "--format", "-f", help="输出格式(JPG或PNG,默认PNG)")
|
"--skip-if-larger", "--engine-conf", help="图片优化引擎配置参数(默认--skip-if-larger)"
|
||||||
|
),
|
||||||
|
format: str = typer.Option("PNG", "--format", "-f", help="输出格式(JPG或PNG,默认PNG)"),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
将PPTX文件导出为长图
|
将PPTX文件导出为长图
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
pptopic export presentation.pptx
|
pptopic export presentation.pptx
|
||||||
pptopic export presentation.pptx --optimize
|
pptopic export presentation.pptx --optimize
|
||||||
@@ -31,42 +34,40 @@ def export(
|
|||||||
if output_name:
|
if output_name:
|
||||||
save_name = f"{output_name}.{format.lower()}" if "." not in output_name else output_name
|
save_name = f"{output_name}.{format.lower()}" if "." not in output_name else output_name
|
||||||
else:
|
else:
|
||||||
save_name = f"{input_file.stem}_{today(fmt="YYYYMMDDHHmm",addtime=True)}.{format.lower()}"
|
save_name = f"{input_file.stem}_{today(fmt='YYYYMMDDHHmm', addtime=True)}.{format.lower()}"
|
||||||
|
|
||||||
PPT_longPic(
|
PPT_longPic(pptFile=input_file, saveName=save_name, width=width, saveto=output_dir)
|
||||||
pptFile=input_file,
|
|
||||||
saveName=save_name,
|
|
||||||
width=width,
|
|
||||||
saveto=output_dir
|
|
||||||
)
|
|
||||||
|
|
||||||
if optimize:
|
if optimize:
|
||||||
output_path = output_dir / save_name
|
output_path = output_dir / save_name
|
||||||
|
|
||||||
imageOptimization(
|
imageOptimization(
|
||||||
imageFile=output_path,
|
imageFile=output_path,
|
||||||
saveFile=output_path,
|
saveFile=output_path,
|
||||||
max_height=max_height,
|
max_height=max_height,
|
||||||
engine=engine,
|
engine=engine,
|
||||||
engine_conf=engine_conf
|
engine_conf=engine_conf,
|
||||||
)
|
)
|
||||||
|
|
||||||
typer.echo(f"成功导出长图: {output_dir / save_name}")
|
typer.echo(f"成功导出长图: {output_dir / save_name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
typer.echo(f"导出失败: {e}", err=True)
|
typer.echo(f"导出失败: {e}", err=True)
|
||||||
raise typer.Exit(code=1)
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def optimize(
|
def optimize(
|
||||||
input_file: Path = typer.Argument(..., help="输入的图片文件路径", exists=True),
|
input_file: Path = typer.Argument(..., help="输入的图片文件路径", exists=True),
|
||||||
output_file: Path = typer.Option(None, "--output", "-o", help="输出图片文件路径,默认覆盖原文件"),
|
output_file: Path = typer.Option(None, "--output", "-o", help="输出图片文件路径,默认覆盖原文件"),
|
||||||
max_height: int = typer.Option(29999, "--max-height", help="优化图片的最大高度(默认29999)"),
|
max_height: int = typer.Option(29999, "--max-height", help="优化图片的最大高度(默认29999)"),
|
||||||
engine: str = typer.Option("pngquant", "--engine", help="图片优化引擎(默认pngquant)"),
|
engine: str = typer.Option("pngquant", "--engine", help="图片优化引擎(默认pngquant)"),
|
||||||
engine_conf: str = typer.Option("--skip-if-larger", "--engine-conf", help="图片优化引擎配置参数(默认--skip-if-larger)")
|
engine_conf: str = typer.Option(
|
||||||
|
"--skip-if-larger", "--engine-conf", help="图片优化引擎配置参数(默认--skip-if-larger)"
|
||||||
|
),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
单独优化图片
|
单独优化图片
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
pptopic optimize image.png
|
pptopic optimize image.png
|
||||||
pptopic optimize image.png --output optimized.png --max-height 20000
|
pptopic optimize image.png --output optimized.png --max-height 20000
|
||||||
@@ -74,19 +75,25 @@ def optimize(
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
save_file = output_file if output_file else input_file
|
save_file = output_file if output_file else input_file
|
||||||
|
|
||||||
imageOptimization(
|
imageOptimization(
|
||||||
imageFile=input_file,
|
imageFile=input_file, saveFile=save_file, max_height=max_height, engine=engine, engine_conf=engine_conf
|
||||||
saveFile=save_file,
|
|
||||||
max_height=max_height,
|
|
||||||
engine=engine,
|
|
||||||
engine_conf=engine_conf
|
|
||||||
)
|
)
|
||||||
|
|
||||||
typer.echo(f"成功优化图片: {save_file}")
|
typer.echo(f"成功优化图片: {save_file}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
typer.echo(f"优化失败: {e}", err=True)
|
typer.echo(f"优化失败: {e}", err=True)
|
||||||
raise typer.Exit(code=1)
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
|
|
||||||
|
@app.command()
|
||||||
|
def version():
|
||||||
|
"""显示版本信息"""
|
||||||
|
from pptopic import __version__
|
||||||
|
|
||||||
|
typer.echo(f"pptopic version: {__version__}")
|
||||||
|
typer.echo("Under the MIT License.")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app()
|
app()
|
||||||
|
|||||||
Reference in New Issue
Block a user