{"id":28965874,"url":"https://github.com/inochi2d/hairetsu","last_synced_at":"2026-02-02T12:09:36.720Z","repository":{"id":279903717,"uuid":"933995488","full_name":"Inochi2D/hairetsu","owner":"Inochi2D","description":"Simple font handling and text shaping for DLang.","archived":false,"fork":false,"pushed_at":"2025-06-23T19:45:00.000Z","size":360,"stargazers_count":18,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-23T20:34:21.369Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"D","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Inochi2D.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-17T05:14:28.000Z","updated_at":"2025-06-23T16:47:58.000Z","dependencies_parsed_at":"2025-02-28T12:16:31.262Z","dependency_job_id":"8cbab93f-71ff-47f6-93d1-8e1906ea8c2c","html_url":"https://github.com/Inochi2D/hairetsu","commit_stats":null,"previous_names":["inochi2d/hairetsu"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Inochi2D/hairetsu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inochi2D%2Fhairetsu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inochi2D%2Fhairetsu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inochi2D%2Fhairetsu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inochi2D%2Fhairetsu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Inochi2D","download_url":"https://codeload.github.com/Inochi2D/hairetsu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Inochi2D%2Fhairetsu/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261624969,"owners_count":23186121,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-24T07:10:21.958Z","updated_at":"2026-02-02T12:09:36.713Z","avatar_url":"https://github.com/Inochi2D.png","language":"D","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"hairetsu.png\" alt=\"NuMem\" style=\"height: 50%; max-height: 512px; width: auto;\"\u003e\n\u003c/p\u003e  \n\n*Rendered with Hairetsu using Noto Sans JP*\n\n# Hairetsu\nHairetsu (配列 /haiɾetsɯ/, sequence/arrangement in Japanese) provides cross-platform text \nlookup, shaping and rasterization with plans for complex text layout and bidi in the pipeline.\n\nHairetsu is built around reference counted types built ontop of `numem`; despite this the types provided\nby hairetsu should be usable in a GC context.\n\n# Building and Packaging\nHairetsu uses the `dub` or `redub` build system and package manager during the build process.\nWhen using hairetsu in D code you can just simply add it as a D dependency.\nIf you wish to use hairetsu outside of DLang, you can compile a shared/dynamic library using the `-dynamic` variants\nof the configurations.\n\n## On Linux, FreeBSD, etc.\n```\n# Using dub\ndub build --build=release --config=posix-dynamic\n\n# Using redub\nredub build --build=release --config=posix-dynamic\n```\n\n## On Windows\n```\n# Using dub\ndub build --build=release --config=win32-dynamic\n\n# Using redub\nredub build --build=release --config=win32-dynamic\n```\n\n## On macOS (and derived)\n```\n# Using dub\ndub build --build=release --config=appleos-dynamic\n\n# Using redub\nredub build --build=release --config=appleos-dynamic\n```\n\nThe shared object will be put in `out/`, a C FFI interface is provided in [cffi.d](source/hairetsu/cffi.d).\nA C [header file](res/hairetsu.h) will also be copied out to the `out/` directory.\n\n## Enumerating System Fonts\n\nHairetsu has a subsystem for enumerating fonts on the system and their capabilities.\nTo facilitate this, Hairetsu provides \"collections\". Collections cover fonts and their variants.\n\nYou can get a collection of all fonts that the OS is aware of by calling `FontCollection.createFromSystem`,\nthis function will only list fonts which Hairetsu can realize to actual font objects and will omit non-realizable fonts.\n\nFor example, to select the first font that supports a given unicode code point, \nyou can use `FontFamily.getFirstFaceWith` to query each face in the collection for a UTF-32 character.\n\nFontFaceInfo's can be realised to their font file using `FontFaceInfo.realize`; some fonts might not be\nrealizable. Use `FontFaceInfo.isRealizable` to query this.\n\n```d\n// Note:  You can pass in a boolean to tell Hairetsu whether to ask the OS\n//        to reindex its font list.\nFontCollection systemFonts = FontCollection.createFromSystem();\nFontFile selectedFont;\nforeach(family; systemFonts.families) {\n    if (FontFaceInfo face = family.getFirstFaceWith('あ')) {\n        selectedFont = face.realize();\n        break;\n    }\n}\n```\n\n#### NOTE\nThis will only work on systems where a backend is implemented; otherwise you will get an empty collection.\n\n## Loading Fonts\n\nHairetsu includes its own font reading and rendering mechanism, to load a font you first create a `FontFile` instance.\nA couple of convenience functions are provided to do this.\n\nFont Files are the top level object of Hairetsu's font ownership hirearchy; ownership is managed internally by hairetsu,\nas such you should not attempt to manually destroy objects unless the documentation tells you to.\n\nFrom these font files you can create `Font` objects, which represent the logical font within a font file container,\nsome containers can contain **multiple** fonts within a single file, such as TTC containers.\n\n```d\nFontFile myFile = FontFile.fromFile(\"notosans.ttf\");\nFont myFont = myFile.fonts[0]; // Gets the first font within the file.\n\nwriteln(myFont.type, \" \", myFile.type); // Likely would print \"TrueType SFNT\"\n```\n\n## Looking up glyphs\n\nGenerally you should refer to a text shaper to find glyph IDs for your target language,\nbut Hairetsu does provide the essentials for looking up glyphs by character, however this\nwill be **without** substitutions unless you write code to fetch those.\n\nA `CharMap` is provided by fonts which allows looking up glyph indices from eg. the `CMAP`\ntable in TTF and OTF fonts. If a font does not contain a glyph for the given character code,\nthe `.notdef` glyph index will be returned instead, a convenience `GLYPH_MISSING` enum is provided\nto help you check this case.\n\n```d\nGlyphIndex i = myFont.charMap.getGlyphIndex('あ');\n```\n\n## Faces\nWhen using a font it's often desired to be able to configure properties about the font without needing\nto repeatedly reload a font to do so; the `FontFace` facilitates this by being a type which refers\nback in to the parent font that created it.\n\nThis allows you to, for example, set style, sizing, hinting requirements, etc. for the glyph data\nyou wish to fetch from the font. You can have as many font faces loaded at a time as you want.\n\n```d\n\n// Create a font face, scaled to half of the base size.\nFontFace myFace = myFont.createFace();\nmyFace.scale.x = 0.5;\nmyFace.scale.y = 0.5;\n```\n\n### Acknowledgements\nLanguage tag mapping is based on the map table created by `jclark`.\n\nhttps://github.com/jclark/lang-ietf-opentype\n\nSome inspiration has been taken from various renderers, such as fontdue, canvas_ity and others.  \nThe glyph rendering algorithm is more or less an amalgamation of them all, with smaller tweaks,\nusing signed converage masks (note; NOT SDFs) to effectively render glyphs.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finochi2d%2Fhairetsu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finochi2d%2Fhairetsu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finochi2d%2Fhairetsu/lists"}