pptx2mp4.py ダウンロード/コピー
pptx2mp4.py
pptx2mp4.py
1#!/usr/bin/env python
2"""
3概要:
4 Windows版PowerPointを使って、PPTXファイルをMP4へ変換します。
5詳細説明:
6 必要条件として pip install pywin32 を実行してモジュールをインストールしてください。
7関連リンク:
8 pptx2mp4_usage
9"""
10
11from __future__ import annotations
12
13import argparse
14import sys
15import time
16from pathlib import Path
17
18import pythoncom
19import win32com.client
20
21
22# PowerPoint.PpMediaTaskStatus
23STATUS_NONE = 0
24STATUS_IN_PROGRESS = 1
25STATUS_QUEUED = 2
26STATUS_DONE = 3
27STATUS_FAILED = 4
28
29STATUS_NAMES = {
30 STATUS_NONE: "準備中",
31 STATUS_IN_PROGRESS: "変換中",
32 STATUS_QUEUED: "待機中",
33 STATUS_DONE: "完了",
34 STATUS_FAILED: "失敗",
35}
36
37
38def convert_pptx_to_mp4(
39 input_path: Path,
40 output_path: Path,
41 *,
42 resolution: int = 720,
43 fps: int = 30,
44 quality: int = 100,
45 default_slide_duration: int = 5,
46 use_timings_and_narrations: bool = True,
47 overwrite: bool = False,
48) -> None:
49 """
50 概要:
51 PowerPointのCreateVideoを使ってPPTXをMP4に変換します。
52 詳細説明:
53 入力されたPowerPointファイルを指定された設定でMP4動画ファイルに変換します。
54 変換の進捗状況を標準出力に表示し、完了するまで待機します。
55 引数:
56 :param input_path: 入力となるPowerPointファイルのパス。
57 :type input_path: pathlib.Path
58 :param output_path: 出力するMP4ファイルのパス。
59 :type output_path: pathlib.Path
60 :param resolution: 動画の縦解像度。
61 :type resolution: int
62 :param fps: 動画のフレームレート。
63 :type fps: int
64 :param quality: 動画の品質設定。
65 :type quality: int
66 :param default_slide_duration: タイミング未設定時の1スライドの秒数。
67 :type default_slide_duration: int
68 :param use_timings_and_narrations: 記録済みのタイミングとナレーションを使用するかどうか。
69 :type use_timings_and_narrations: bool
70 :param overwrite: 既存の出力ファイルがある場合に上書きするかどうか。
71 :type overwrite: bool
72 戻り値:
73 :returns: なし。
74 :rtype: None
75 例外:
76 :raises FileNotFoundError: 入力ファイルが存在しない場合に発生します。
77 :raises ValueError: 入出力ファイルの拡張子が適切でない場合に発生します。
78 :raises FileExistsError: 出力ファイルがすでに存在し、overwriteがFalseの場合に発生します。
79 :raises RuntimeError: PowerPointのビデオ作成処理に失敗した場合、またはMP4ファイルが作成されなかった場合に発生します。
80 """
81
82 input_path = input_path.resolve()
83 output_path = output_path.resolve()
84
85 if not input_path.is_file():
86 raise FileNotFoundError(f"入力ファイルが見つかりません: {input_path}")
87
88 if input_path.suffix.lower() not in {".pptx", ".pptm", ".ppt"}:
89 raise ValueError(f"PowerPointファイルではありません: {input_path}")
90
91 if output_path.suffix.lower() != ".mp4":
92 raise ValueError("出力ファイルの拡張子は .mp4 にしてください。")
93
94 output_path.parent.mkdir(parents=True, exist_ok=True)
95
96 if output_path.exists():
97 if not overwrite:
98 raise FileExistsError(
99 f"出力ファイルがすでに存在します: {output_path}\n"
100 "--overwrite を指定すると上書きできます。"
101 )
102 output_path.unlink()
103
104 pythoncom.CoInitialize()
105
106 powerpoint = None
107 presentation = None
108
109 try:
110 # 独立したPowerPointプロセスを起動
111 powerpoint = win32com.client.DispatchEx("PowerPoint.Application")
112 powerpoint.Visible = True
113
114 print(f"入力: {input_path}")
115 print(f"出力: {output_path}")
116 print(
117 f"設定: {resolution}p, {fps} fps, "
118 f"quality={quality}, timings={use_timings_and_narrations}"
119 )
120
121 # Open(FileName, ReadOnly, Untitled, WithWindow)
122 presentation = powerpoint.Presentations.Open(
123 str(input_path),
124 True, # ReadOnly
125 False, # Untitled
126 True, # WithWindow
127 )
128
129 # CreateVideo(
130 # FileName,
131 # UseTimingsAndNarrations,
132 # DefaultSlideDuration,
133 # VertResolution,
134 # FramesPerSecond,
135 # Quality
136 # )
137 presentation.CreateVideo(
138 str(output_path),
139 use_timings_and_narrations,
140 default_slide_duration,
141 resolution,
142 fps,
143 quality,
144 )
145
146 print("ビデオの作成を開始しました。")
147
148 previous_status = None
149
150 while True:
151 status = int(presentation.CreateVideoStatus)
152
153 if status != previous_status:
154 print(f"状態: {STATUS_NAMES.get(status, f'不明 ({status})')}")
155 previous_status = status
156
157 if status == STATUS_DONE:
158 break
159
160 if status == STATUS_FAILED:
161 raise RuntimeError("PowerPointによるビデオ作成に失敗しました。")
162
163 time.sleep(2)
164
165 if not output_path.exists():
166 raise RuntimeError(
167 "PowerPointは完了を返しましたが、MP4ファイルが見つかりません。"
168 )
169
170 size_mb = output_path.stat().st_size / (1024 * 1024)
171
172 print("変換が完了しました。")
173 print(f"MP4: {output_path}")
174 print(f"サイズ: {size_mb:.1f} MB")
175
176 finally:
177 if presentation is not None:
178 try:
179 presentation.Close()
180 except Exception:
181 pass
182
183 if powerpoint is not None:
184 try:
185 powerpoint.Quit()
186 except Exception:
187 pass
188
189 pythoncom.CoUninitialize()
190
191
192def parse_args() -> argparse.Namespace:
193 """
194 概要:
195 コマンドライン引数を解析します。
196 詳細説明:
197 argparseを使って、入力ファイル、出力ファイル、解像度などの変換オプションを読み取ります。
198 戻り値:
199 :returns: 解析されたコマンドライン引数を格納した名前空間オブジェクト。
200 :rtype: argparse.Namespace
201 """
202 parser = argparse.ArgumentParser(
203 description="Windows版PowerPointを使ってPPTXをMP4に変換します。"
204 )
205
206 parser.add_argument(
207 "input",
208 type=Path,
209 help="入力するPowerPointファイル",
210 )
211
212 parser.add_argument(
213 "-o",
214 "--output",
215 type=Path,
216 help="出力MP4ファイル。省略時は入力ファイルと同じ場所に作成",
217 )
218
219 parser.add_argument(
220 "--resolution",
221 type=int,
222 default=720,
223 choices=(480, 720, 1080, 2160),
224 help="動画の縦解像度。デフォルト: 720",
225 )
226
227 parser.add_argument(
228 "--fps",
229 type=int,
230 default=30,
231 help="フレームレート。デフォルト: 30",
232 )
233
234 parser.add_argument(
235 "--quality",
236 type=int,
237 default=100,
238 choices=range(1, 101),
239 metavar="1-100",
240 help="動画品質。デフォルト: 100",
241 )
242
243 parser.add_argument(
244 "--default-duration",
245 type=int,
246 default=5,
247 help="タイミング未設定時の1スライドの秒数。デフォルト: 5",
248 )
249
250 parser.add_argument(
251 "--ignore-timings",
252 action="store_true",
253 help="記録済みタイミングとナレーションを使わない",
254 )
255
256 parser.add_argument(
257 "--overwrite",
258 type=int,
259 default=0,
260 help="既存のMP4ファイルを上書きするか [0|1]",
261 )
262
263 parser.add_argument(
264 "--pause",
265 type=int,
266 default=0,
267 help="既存のMP4ファイルを上書きするか [0|1]",
268 )
269
270 return parser.parse_args()
271
272
273def main() -> int:
274 """
275 概要:
276 スクリプトのメイン処理を実行します。
277 詳細説明:
278 コマンドライン引数を取得し、変換関数を呼び出します。
279 キーボード割り込みや予期せぬエラーが発生した場合はキャッチして終了コードを返します。
280 戻り値:
281 :returns: 終了コードとコマンドライン引数のタプル。
282 :rtype: tuple
283 """
284 args = parse_args()
285
286 output = args.output
287 if output is None:
288 output = args.input.with_suffix(".mp4")
289
290 try:
291 convert_pptx_to_mp4(
292 args.input,
293 output,
294 resolution=args.resolution,
295 fps=args.fps,
296 quality=args.quality,
297 default_slide_duration=args.default_duration,
298 use_timings_and_narrations=not args.ignore_timings,
299 overwrite=args.overwrite,
300 )
301 return 0, args
302
303 except KeyboardInterrupt:
304 print("\n中断しました。", file=sys.stderr)
305 return 130, args
306
307 except Exception as exc:
308 print(f"エラー: {exc}", file=sys.stderr)
309 return 1, args
310
311
312if __name__ == "__main__":
313 ret, args = main()
314 if args.pause: input("\nPress ENTER to terminate>>\n")
315 raise SystemExit(ret)