Skip to content

Instantly share code, notes, and snippets.

@dmoruzzi
Created April 5, 2023 03:46
Show Gist options
  • Save dmoruzzi/2414f3edbee0331b13b55b3e3c2b608b to your computer and use it in GitHub Desktop.
Save dmoruzzi/2414f3edbee0331b13b55b3e3c2b608b to your computer and use it in GitHub Desktop.
Convert MP4 to PDF
import os
import subprocess
import argparse
import logging
from PIL import Image
from pathlib import Path
# Define command line arguments
parser = argparse.ArgumentParser(description="Convert MP4 to PDF")
parser.add_argument(
"input_file",
nargs="?",
default="input.mp4",
help="path to input video file (default: input.mp4)",
)
parser.add_argument(
"output_file",
nargs="?",
default="output.pdf",
help="path to output PDF file (default: output.pdf)",
)
args = parser.parse_args()
# Manage logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
file_handler = logging.FileHandler("conversion.log")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# Check if ffmpeg is installed
try:
subprocess.check_call(
["ffmpeg", "-version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
except subprocess.CalledProcessError:
logger.error("Please install ffmpeg and add it to your PATH environment variable")
exit(1)
# Make sure input file exists
if not os.path.exists(args.input_file):
logger.error("Input file does not exist")
exit(1)
# Make sure input file is an MP4
if not args.input_file.endswith(".mp4"):
logger.error("Input file is not an MP4")
exit(1)
# Make sure input file is not empty
if os.path.getsize(args.input_file) == 0:
logger.error("Input file is empty")
exit(1)
# Create frames directory if it doesn't exist
output_folder: str = "frames"
os.makedirs(output_folder, exist_ok=True)
# Convert MP4 to PNG frames
try:
subprocess.check_call(
[
"ffmpeg",
"-hide_banner",
"-loglevel",
"error",
"-i",
args.input_file,
"-vf",
"scale=595:-1",
f"{output_folder}/frame-%03d.png",
]
)
except subprocess.CalledProcessError as e:
logger.error(f"Error converting MP4 to PNG frames: {e}")
exit(1)
# Create a list of PIL Image objects from PNG files in frames directory
frames: list = []
for frame_file in Path("frames").glob("*.png"):
try:
frame = Image.open(frame_file)
frames.append(frame)
except IOError as e:
logger.warning(f"Error opening frame file {frame_file}: {e}")
# Save frames as pages in a new PDF file
try:
frames[0].save(
args.output_file,
save_all=True,
append_images=frames[1:],
optimize=False,
quality=100,
)
except Exception as e:
logger.error(f"Error saving PDF file: {e}")
exit(1)
# Delete each PNG file and the frames directory
for file in os.listdir(output_folder):
try:
os.remove(os.path.join(output_folder, file))
except OSError as e:
logger.warning(f"Error deleting file {os.path.join(output_folder, file)}: {e}")
try:
os.rmdir(output_folder)
except OSError as e:
logger.warning(f"Error deleting directory {output_folder}: {e}")
# Open PDF document
if os.name == "nt":
os.startfile(args.output_file)
elif os.name == "posix":
subprocess.check_call(["xdg-open", args.output_file])
else:
logger.warning(f"Could not open {args.output_file} automatically")
print(f"Please open {args.output_file}.")
# Exit program
exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment