const std = @import("std"); const freetype = @import("freetype"); // Remove once the stage2 compiler fixes pkg std not found comptime { _ = @import("utils"); } const OutlinePrinter = struct { library: freetype.Library, face: freetype.Face, output_file: std.fs.File, path_stream: std.io.FixedBufferStream([]u8), xMin: isize, yMin: isize, width: isize, height: isize, const Self = @This(); var buf = [_]u8{0} ** (1024 * 10); pub fn init(file: std.fs.File) freetype.Error!Self { var lib = try freetype.Library.init(); return Self{ .library = lib, .face = try lib.createFace("upstream/assets/FiraSans-Regular.ttf", 0), .output_file = file, .path_stream = std.io.fixedBufferStream(&buf), .xMin = 0, .yMin = 0, .width = 0, .height = 0, }; } pub fn deinit(self: Self) void { self.library.deinit(); } pub fn outlineExists(self: Self) bool { const outline = self.face.glyph().outline() orelse return false; if (outline.numContours() <= 0 or outline.numPoints() <= 0) return false; outline.check() catch return false; return true; } pub fn flipOutline(self: Self) void { const multiplier = 65536; const matrix = freetype.Matrix{ .xx = 1 * multiplier, .xy = 0 * multiplier, .yx = 0 * multiplier, .yy = -1 * multiplier, }; self.face.glyph().outline().?.transform(matrix); } pub fn extractOutline(self: *Self) !void { try self.path_stream.writer().writeAll(""); } pub fn computeViewBox(self: *Self) !void { const boundingBox = try self.face.glyph().outline().?.bbox(); self.xMin = boundingBox.xMin; self.yMin = boundingBox.yMin; self.width = boundingBox.xMax - boundingBox.xMin; self.height = boundingBox.yMax - boundingBox.yMin; } pub fn printSVG(self: Self) !void { try self.output_file.writer().print( \\ \\ {s} \\ , .{ self.xMin, self.yMin, self.width, self.height, self.path_stream.getWritten() }); } pub fn moveToFunction(self: *Self, to: freetype.Vector) freetype.Error!void { self.path_stream.writer().print("M {d} {d}\t", .{ to.x, to.y }) catch unreachable; } pub fn lineToFunction(self: *Self, to: freetype.Vector) freetype.Error!void { self.path_stream.writer().print("L {d} {d}\t", .{ to.x, to.y }) catch unreachable; } pub fn conicToFunction(self: *Self, control: freetype.Vector, to: freetype.Vector) freetype.Error!void { self.path_stream.writer().print("Q {d} {d}, {d} {d}\t", .{ control.x, control.y, to.x, to.y }) catch unreachable; } pub fn cubicToFunction(self: *Self, control_0: freetype.Vector, control_1: freetype.Vector, to: freetype.Vector) freetype.Error!void { self.path_stream.writer().print("C {d} {d}, {d} {d}, {d} {d}\t", .{ control_0.x, control_0.y, control_1.x, control_1.y, to.x, to.y }) catch unreachable; } pub fn run(self: *Self, symbol: u32) !void { try self.face.loadChar(symbol, .{ .no_scale = true, .no_bitmap = true }); if (!self.outlineExists()) return error.OutlineDoesntExists; self.flipOutline(); try self.extractOutline(); try self.computeViewBox(); try self.printSVG(); } }; pub fn main() !void { var file = try std.fs.cwd().createFile("out.svg", .{}); defer file.close(); var outline_printer = try OutlinePrinter.init(file); defer outline_printer.deinit(); try outline_printer.run(@as(u32, 'ë')); }