///|
/// Render with integer scaling and a quiet zone of at least one module.
/// Limits keep dimensions and memory use bounded across all backends.
pub fn render_svg(
symbol : Symbol,
scale? : Int = 4,
quiet_zone? : Int = 2,
) -> String raise EncodeError {
if scale < 1 || scale > 1024 || quiet_zone < 1 || quiet_zone > 1024 {
raise InvalidOption("scale and quiet zone must be between 1 and 1024")
}
let w = symbol.width() + 2 * quiet_zone
let h = symbol.height() + 2 * quiet_zone
let pxw = w * scale
let pxh = h * scale
let parts = [
"\n")
parts.join("")
}
///|
/// Parse strict, even-length hexadecimal. Whitespace is not silently removed.
pub fn parse_hex(input : String) -> Bytes raise EncodeError {
let bytes = @utf8.encode(input)
if bytes.length() % 2 != 0 {
raise InvalidOption("hex must contain an even number of digits")
}
fn digit(c : Byte) -> Int raise EncodeError {
let n = c.to_int()
if n >= 48 && n <= 57 {
n - 48
} else if n >= 65 && n <= 70 {
n - 55
} else if n >= 97 && n <= 102 {
n - 87
} else {
raise InvalidOption("invalid hexadecimal digit")
}
}
let out = Array::make(bytes.length() / 2, b'\x00')
for i in 0..