diff --git a/konabot/docs/user/giftool.txt b/konabot/docs/user/giftool.txt new file mode 100644 index 0000000..457eb74 --- /dev/null +++ b/konabot/docs/user/giftool.txt @@ -0,0 +1,59 @@ +指令介绍 + giftool - 对 GIF 动图进行裁剪、抽帧等处理 + +格式 + giftool [图片] [选项] + +示例 + 回复一张 GIF 并发送: + `giftool --ss 1.5 -t 2.0` + 从 1.5 秒处开始,截取 2 秒长度的片段。 + + `giftool [图片] --ss 0:10 -to 0:15` + 截取从 10 秒到 15 秒之间的片段(支持 MM:SS 或 HH:MM:SS 格式)。 + + `giftool [图片] --frames:v 10` + 将整张 GIF 均匀抽帧,最终保留 10 帧。 + + `giftool [图片] --ss 2 --frames:v 5` + 从第 2 秒开始截取,并将结果抽帧为 5 帧。 + +参数说明 + 图片(必需) + - 必须是 GIF 动图。 + - 支持直接附带图片,或回复一条含 GIF 的消息后使用指令。 + + --ss <时间戳>(可选) + - 指定开始时间(单位:秒),可使用以下格式: + • 纯数字(如 `1.5` 表示 1.5 秒) + • 分秒格式(如 `1:30` 表示 1 分 30 秒) + • 时分秒格式(如 `0:1:30` 表示 1 分 30 秒) + - 默认从开头开始(0 秒)。 + + -t <持续时间>(可选) + - 指定截取的持续时间(单位:秒),格式同 --ss。 + - 与 --ss 配合使用:截取 [ss, ss + t] 区间。 + - 不能与 --to 同时使用。 + + --to <时间戳>(可选) + - 指定结束时间(单位:秒),格式同 --ss。 + - 与 --ss 配合使用:截取 [ss, to] 区间。 + - 不能与 -t 同时使用。 + + --frames:v <帧数>(可选) + - 对截取后的片段进行均匀抽帧,保留指定数量的帧。 + - 帧数必须为正整数(> 0)。 + - 若原始帧数 ≤ 指定帧数,则保留全部帧。 + + --s <速度>(可选) + - 调整 gif 图的速度 + +使用方式 + 1. 发送指令前,请确保: + - 消息中附带一张 GIF 动图,或 + - 回复一条包含 GIF 动图的消息后再发送指令。 + 2. 插件会自动: + - 解析 GIF 的每一帧及其持续时间(duration) + - 根据时间参数转换为帧索引进行裁剪 + - 如指定抽帧,则对裁剪后的片段均匀采样 + - 生成新的 GIF 并保持原始循环设置(loop=0) diff --git a/konabot/plugins/image_process/__init__.py b/konabot/plugins/image_process/__init__.py index 2993a73..2a518a8 100644 --- a/konabot/plugins/image_process/__init__.py +++ b/konabot/plugins/image_process/__init__.py @@ -36,6 +36,7 @@ cmd_giftool = on_alconna(Alconna( Option("--frames:v", Args["frame_count", int]), Option("-t", Args["length", str]), Option("-to", Args["end_point", str]), + Option("--speed", Args["speed_factor", float], default=1.0, alias=["-s"]), )) @@ -45,6 +46,7 @@ async def _( start_point: str | None = None, frame_count: int | None = None, length: str | None = None, + speed_factor: float = 1.0, end_point: str | None = None, ): ss: None | float = None @@ -69,9 +71,12 @@ async def _( raise BotExceptionMessage("错误:出点时间小于入点") if frame_count is not None and frame_count <= 0: raise BotExceptionMessage("错误:帧数量应该大于 0") + if speed_factor <= 0: + raise BotExceptionMessage("错误:--speed 必须大于 0") if not getattr(image, "is_animated", False): raise BotExceptionMessage("错误:输入的不是动图(GIF)") + frames = [] durations = [] total_duration = 0.0 @@ -135,13 +140,17 @@ async def _( output_img = BytesIO() + adjusted_durations = [ + max(10, int(dur / speed_factor)) for dur in selected_durations + ] + if selected_frames: selected_frames[0].save( output_img, format="GIF", save_all=True, append_images=selected_frames[1:], - duration=selected_durations, + duration=adjusted_durations, loop=0, ) else: