mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-06-28 01:52:06 +08:00
106 lines
3.4 KiB
Python
106 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import binascii
|
|
import os
|
|
import struct
|
|
from pathlib import Path
|
|
|
|
|
|
IGNORED_TAIL = b"\x00\x00\x00\x00\x00"
|
|
VALUES_COUNT = 13
|
|
VALUES_FMT = f"<{VALUES_COUNT}e"
|
|
VALUES_SIZE = struct.calcsize(VALUES_FMT)
|
|
|
|
|
|
def read_color_cal(path: str) -> tuple[float, list[float], list[float], bytes]:
|
|
with open(path, "rb") as f:
|
|
data = f.read()
|
|
|
|
if len(data) < VALUES_SIZE:
|
|
raise ValueError(f"{path} is too short: expected at least {VALUES_SIZE} bytes, got {len(data)}")
|
|
|
|
values = struct.unpack(VALUES_FMT, data[:VALUES_SIZE])
|
|
gamma = float(values[0])
|
|
ccm = [float(v) for v in values[1:10]]
|
|
wb = [float(v) for v in values[10:13]]
|
|
return gamma, ccm, wb, data[VALUES_SIZE:]
|
|
|
|
|
|
def write_color_cal(path: str, gamma: float, ccm: list[float], wb: list[float], tail: bytes = IGNORED_TAIL) -> None:
|
|
if len(ccm) != 9:
|
|
raise ValueError("CCM must contain exactly 9 values")
|
|
if len(wb) != 3:
|
|
raise ValueError("WB gains must contain exactly 3 values")
|
|
|
|
payload = struct.pack(VALUES_FMT, gamma, *ccm, *wb)
|
|
data = payload + tail
|
|
out = Path(path)
|
|
out.parent.mkdir(parents=True, exist_ok=True)
|
|
out.write_bytes(data)
|
|
|
|
|
|
def cmd_analyze(args: argparse.Namespace) -> int:
|
|
gamma, ccm, wb, tail = read_color_cal(args.path)
|
|
data = Path(args.path).read_bytes()
|
|
print(f"path: {args.path}")
|
|
print(f"size: {len(data)}")
|
|
print(f"hex: {binascii.hexlify(data).decode()}")
|
|
print(f"gamma: {gamma:.4f}")
|
|
print("ccm:")
|
|
print(f" [{ccm[0]:.4f}, {ccm[1]:.4f}, {ccm[2]:.4f}]")
|
|
print(f" [{ccm[3]:.4f}, {ccm[4]:.4f}, {ccm[5]:.4f}]")
|
|
print(f" [{ccm[6]:.4f}, {ccm[7]:.4f}, {ccm[8]:.4f}]")
|
|
print(f"wb: [R={wb[0]:.4f}, G={wb[1]:.4f}, B={wb[2]:.4f}]")
|
|
print(f"ignored_tail_hex: {tail.hex()}")
|
|
return 0
|
|
|
|
|
|
def cmd_generate(args: argparse.Namespace) -> int:
|
|
tail = binascii.unhexlify(args.tail_hex) if args.tail_hex else IGNORED_TAIL
|
|
write_color_cal(args.output, args.gamma, args.ccm, args.wb, tail=tail)
|
|
print(f"wrote {args.output}")
|
|
return 0
|
|
|
|
|
|
def cmd_from_hex(args: argparse.Namespace) -> int:
|
|
data = binascii.unhexlify(args.hex_string)
|
|
out = Path(args.output)
|
|
out.parent.mkdir(parents=True, exist_ok=True)
|
|
out.write_bytes(data)
|
|
print(f"wrote {args.output}")
|
|
return 0
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(description="Inspect and generate comma/Weston color_cal files.")
|
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
|
|
analyze = subparsers.add_parser("analyze", help="Decode an existing color_cal file")
|
|
analyze.add_argument("path")
|
|
analyze.set_defaults(func=cmd_analyze)
|
|
|
|
generate = subparsers.add_parser("generate", help="Generate a color_cal file from gamma/CCM/WB values")
|
|
generate.add_argument("output")
|
|
generate.add_argument("--gamma", type=float, required=True)
|
|
generate.add_argument("--ccm", type=float, nargs=9, required=True)
|
|
generate.add_argument("--wb", type=float, nargs=3, required=True)
|
|
generate.add_argument("--tail-hex", default="", help="Optional trailing bytes as hex; Weston ignores these")
|
|
generate.set_defaults(func=cmd_generate)
|
|
|
|
from_hex = subparsers.add_parser("from-hex", help="Write a raw color_cal blob from a hex string")
|
|
from_hex.add_argument("output")
|
|
from_hex.add_argument("hex_string")
|
|
from_hex.set_defaults(func=cmd_from_hex)
|
|
|
|
return parser
|
|
|
|
|
|
def main() -> int:
|
|
parser = build_parser()
|
|
args = parser.parse_args()
|
|
return args.func(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|