export script_name = "ASS2TTF" export script_description = "Convert shapes to a TTF font" export script_version = "0.0.1" export script_author = "PhosCity" export script_namespace = "phos.ASSS2TTF" DependencyControl = require "l0.DependencyControl" depctrl = DependencyControl{ feed: "https://raw.githubusercontent.com/PhosCity/Aegisub-Scripts/main/DependencyControl.json", { {"ILL.ILL", version: "1.7.7", url: "https://github.com/TypesettingTools/ILL-Aegisub-Scripts/" feed: "https://raw.githubusercontent.com/TypesettingTools/ILL-Aegisub-Scripts/main/DependencyControl.json"}, } } ILL = depctrl\requireModules! {:Ass, :Line, :Path} = ILL assShapeTosvgPath = (shape) -> path = {} for i = 1, #shape path[i] = {} j, contour = 2, shape[i] while j <= #contour prev = contour[j - 1]\round 3 curr = contour[j]\round 3 if curr.id == "b" c = contour[j + 1]\round 3 d = contour[j + 2]\round 3 table.insert path[i], "C #{curr.x} #{curr.y} #{c.x} #{c.y} #{d.x} #{d.y}" j += 2 else table.insert path[i], "L #{curr.x} #{curr.y}" j += 1 path[i] = "M #{contour[1].x} #{contour[1].y} " .. table.concat(path[i], " ") .. " Z" table.concat path, " " checkFontForgeExists = -> handle = io.popen("fontforge --version") result = handle\read("*a") handle\close! if result and result != "" return aegisub.log "fontforge not found in path. Install it and try again." aegisub.cancel! createFont = (xmlContent, fontFilePath) -> temp = aegisub.decode_path "?temp" pathsep = package.config\sub(1, 1) svgPath = temp .. pathsep .. "ASS2TTF.svg" ffScript = temp .. pathsep .. "fontforgeScript.pe" svgFile = io.open(svgPath, "w") if svgFile svgFile\write(xmlContent) svgFile\close! else aegisub.log "Error: Could not open svg svg file for writing." ffScriptContent = table.concat({ 'Open($1)', 'Generate($2)', 'Quit()', }, "\n") ffScriptFile = io.open(ffScript, "w") if ffScriptFile ffScriptFile\write(ffScriptContent) ffScriptFile\close! else aegisub.log "Error: Could not open svg file for writing." handle = io.popen("fontforge -script \"#{ffScript}\" \"#{svgPath}\" \"#{fontFilePath}\"") output = handle\read("*a") success, reason, exit = handle\close! unless success aegisub.log tostring(reason) main = (sub, sel, act) -> checkFontForgeExists! pathsep = package.config\sub(1, 1) fontFilePath = aegisub.dialog.save("Enter font name", "", aegisub.decode_path("?script")..pathsep, "Truetype font files (.ttf)|*.ttf") if not fontFilePath aegisub.log "You did not provide the filename. Exiting." return -- Get filename (with extension) filename = fontFilePath\match("^.+[/\\](.+)$") or fontFilePath -- Remove extension filename = filename\match("(.+)%..+$") or filename ass = Ass sub, sel, act svgBoilerPlate = { '', '', ' ', ' ', ' ", ' ', ' ', ' ', '', } glyph_name = {} for l, s in ass\iterSel! continue if l.comment Line.extend ass, l if l.isShape Line.callBackExpand ass, l, nil, (line) -> current_glyph = line.effect if #current_glyph != 1 ass\error s, "The line must have a single letter glyph in effect field." for glyph in *glyph_name if glyph == current_glyph ass\error s, "Glyph \"#{glyph}\" is repeated." table.insert glyph_name, current_glyph {x, y} = l.data.pos newPath = Path line.shape bbox = newPath\boundingBox! scale = (400 / bbox.height) * 100 -- 400 is the distance between baseline and x height newPath\scale scale, scale newPath\rotatefrz 180 bbox = newPath\boundingBox! newPath\move 500 - bbox.center.x, 600 - bbox.center.y for item in *{ ' ", } table.insert(svgBoilerPlate, #svgBoilerPlate-2, item) else ass\error s, "Text/Empty line cannot be converted to font. Use shapes instead." createFont table.concat(svgBoilerPlate, "\n"), fontFilePath depctrl\registerMacro main