83 lines
2.3 KiB
Python
83 lines
2.3 KiB
Python
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def run_bytes(args):
|
|
try:
|
|
return subprocess.run(args, check=True, stdout=subprocess.PIPE).stdout
|
|
except FileNotFoundError:
|
|
sys.exit(f"missing required command: {args[0]}")
|
|
except subprocess.CalledProcessError as exc:
|
|
sys.exit(f"command failed ({exc.returncode}): {' '.join(args)}")
|
|
|
|
|
|
def run_text(args):
|
|
return run_bytes(args).decode("utf-8", "replace")
|
|
|
|
|
|
def parse_ppm(data):
|
|
idx = 0
|
|
|
|
def next_token():
|
|
nonlocal idx
|
|
while idx < len(data) and data[idx] in b" \t\r\n":
|
|
idx += 1
|
|
if idx < len(data) and data[idx] == ord("#"):
|
|
while idx < len(data) and data[idx] not in b"\r\n":
|
|
idx += 1
|
|
return next_token()
|
|
start = idx
|
|
while idx < len(data) and data[idx] not in b" \t\r\n":
|
|
idx += 1
|
|
return data[start:idx]
|
|
|
|
magic = next_token()
|
|
if magic != b"P6":
|
|
sys.exit("ImageMagick did not return binary PPM data")
|
|
|
|
width = int(next_token())
|
|
height = int(next_token())
|
|
max_value = int(next_token())
|
|
if max_value != 255:
|
|
sys.exit(f"unsupported PPM max value: {max_value}")
|
|
|
|
while idx < len(data) and data[idx] in b" \t\r\n":
|
|
idx += 1
|
|
|
|
return width, height, data[idx:]
|
|
|
|
|
|
def ppm_from_magick(args):
|
|
return parse_ppm(run_bytes(["magick", *args, "-alpha", "off", "-depth", "8", "ppm:-"]))
|
|
|
|
|
|
def try_ppm_from_magick(args):
|
|
command = ["magick", *args, "-alpha", "off", "-depth", "8", "ppm:-"]
|
|
try:
|
|
result = subprocess.run(command, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
except FileNotFoundError:
|
|
sys.exit("missing required command: magick")
|
|
|
|
if result.returncode != 0:
|
|
return None, result.stderr.decode("utf-8", "replace").strip()
|
|
|
|
try:
|
|
return parse_ppm(result.stdout), ""
|
|
except Exception as exc:
|
|
return None, str(exc)
|
|
|
|
|
|
def magick_fonts():
|
|
fonts = set()
|
|
for line in run_text(["magick", "-list", "font"]).splitlines():
|
|
match = re.match(r"\s*Font:\s*(\S+)", line)
|
|
if match:
|
|
fonts.add(match.group(1))
|
|
return fonts
|
|
|
|
|
|
def image_size(image_path):
|
|
output = run_bytes(["magick", "identify", "-format", "%w %h", image_path]).decode("ascii")
|
|
width, height = output.split()
|
|
return int(width), int(height)
|