{"id":15444542,"url":"https://github.com/cariad/palign","last_synced_at":"2025-03-28T08:13:52.709Z","repository":{"id":63570878,"uuid":"568773253","full_name":"cariad/palign","owner":"cariad","description":"Python package that helps to render and align text in Pillow","archived":false,"fork":false,"pushed_at":"2022-12-05T08:43:18.000Z","size":1132,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-02T12:41:23.518Z","etag":null,"topics":["image-processing","pillow","python"],"latest_commit_sha":null,"homepage":"https://palign.dev","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cariad.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"cariad"}},"created_at":"2022-11-21T11:32:40.000Z","updated_at":"2022-12-01T08:51:31.000Z","dependencies_parsed_at":"2023-01-24T04:15:48.310Z","dependency_job_id":null,"html_url":"https://github.com/cariad/palign","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cariad%2Fpalign","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cariad%2Fpalign/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cariad%2Fpalign/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cariad%2Fpalign/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cariad","download_url":"https://codeload.github.com/cariad/palign/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245991585,"owners_count":20706129,"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":["image-processing","pillow","python"],"created_at":"2024-10-01T19:41:43.280Z","updated_at":"2025-03-28T08:13:52.688Z","avatar_url":"https://github.com/cariad.png","language":"Python","funding_links":["https://github.com/sponsors/cariad"],"categories":[],"sub_categories":[],"readme":"# Palign\n\n[![codecov](https://codecov.io/gh/cariad/palign/branch/main/graph/badge.svg?token=m2tDKm3v3E)](https://codecov.io/gh/cariad/palign)\n\n**Palign** is a Python package that helps to render and align text in [Pillow](https://python-pillow.org/).\n\nFull documentation is online at **[palign.dev](https://palign.dev/)**.\n\n## Examples\n\n[`Text`](https://palign.dev/text/) draws text of a given [`Style`](https://palign.dev/style/) at a set of coordinates:\n\n```python\nfrom PIL import Image, ImageDraw\nfrom PIL.ImageFont import truetype\n\nfrom palign import Style, Text\n\n\n# Create a Pillow Image and Draw as usual:\nimage = Image.new(\"RGB\", (270, 60))\ndraw = ImageDraw.Draw(image)\n\n# Create a Style to describe the font:\nstyle = Style(\n    font=truetype(\"tests/font/ChelseaMarket-Regular.ttf\", 42),\n)\n\n# Create a text renderer:\ntext = Text(draw, style)\n\n# Draw \"Hello world!\" at (0, 0):\ntext.draw(\"Hello world!\", (0, 0))\n\n# Same the image via Pillow:\nimage.save(\"./docs/images/example-0.png\", \"png\")\n```\n\n![Hello world!](https://github.com/cariad/palign/blob/main/docs/images/example-0.png)\n\n[`Style`](https://palign.dev/style/) can also describe borders, colour and tracking:\n\n```python\nfrom PIL import Image, ImageDraw\nfrom PIL.ImageFont import truetype\n\nfrom palign import Style, Text\n\n\nimage = Image.new(\"RGB\", (410, 410), (255, 255, 255))\ndraw = ImageDraw.Draw(image)\n\nstyle = Style(\n    color=(0, 0, 0),\n    font=truetype(\"tests/font/ChelseaMarket-Regular.ttf\", 42),\n)\n\ntext = Text(draw, style)\n\n# Pass in a style to merge into the renderer's base style:\ntext.draw(\n    \"Red!\",\n    (0, 0),\n    style=Style(color=(255, 0, 0)),\n)\n\ntext.draw(\n    \"More tracking!\",\n    (0, 60),\n    style=Style(tracking=2),\n)\n\ntext.draw(\n    \"Less tracking!\",\n    (0, 120),\n    style=Style(tracking=-5),\n)\n\ntext.draw(\n    \"Highlight!\",\n    (0, 180),\n    style=Style(background=(100, 255, 255)),\n)\n\ntext.draw(\n    \"Rounded highlight!\",\n    (0, 240),\n    style=Style(background=(100, 255, 255), border_radius=20),\n)\n\ntext.draw(\n    \"Border!\",\n    (0, 300),\n    style=Style(border_color=(255, 0, 0), border_width=3),\n)\n\ntext.draw(\n    \"Rounded border!\",\n    (0, 360),\n    style=Style(border_color=(255, 0, 0), border_radius=20, border_width=3),\n)\n\nimage.save(\"./docs/images/example-1.png\", \"png\")\n```\n\n![Text of various styles](https://github.com/cariad/palign/blob/main/docs/images/example-1.png)\n\nIf you specify a region to render within (rather than just a point to render _at_) then text can aligned:\n\n```python\nfrom PIL import Image, ImageDraw\nfrom PIL.ImageFont import truetype\n\nfrom palign import Alignment, Percent, Style, Text, make_image_region\n\n\n# Create an image region:\nimage_region = make_image_region(300, 720)\n\n# Pass the image region's size into Image.new:\nimage = Image.new(\"RGB\", image_region.size, (255, 255, 255))\ndraw = ImageDraw.Draw(image)\n\n# We're going to build a region to render the first block of text into.\n#\n# We want this region to fill the entire width of the image, with a little\n# margin on every edge for comfort.\n#\n# So, let's start by creating a subregion with that margin by contracting in:\nmargin_region = image_region.expand(-10)\n\n# Now we'll create a subregion that starts in the top-left corner, fills 100%\n# of the available width and is 70 pixels tall:\ntext_region = margin_region.region2(0, 0, Percent(100), 70).resolve()\n# Note that we need to .resolve() the region to resolve the relative values to\n# absolutes.\n\nstyle = Style(\n    border_color=(200, 200, 200),\n    border_radius=3,\n    border_width=1,\n    color=(0, 0, 0),\n    font=truetype(\"tests/font/ChelseaMarket-Regular.ttf\", 21),\n)\n\ntext = Text(draw, style)\n\nfor vertical in Alignment:\n    for horizontal in Alignment:\n        alignment = Style(horizontal=horizontal, vertical=vertical)\n\n        match horizontal:\n            case Alignment.Near:\n                horizontal_name = \"Left\"\n            case Alignment.Center:\n                horizontal_name = \"Center\"\n            case Alignment.Far:\n                horizontal_name = \"Right\"\n\n        match vertical:\n            case Alignment.Near:\n                vertical_name = \"Top\"\n            case Alignment.Center:\n                vertical_name = \"Center\"\n            case Alignment.Far:\n                vertical_name = \"Bottom\"\n\n        t = f\"{vertical_name} {horizontal_name}\"\n        text.draw(t, text_region, style=alignment)\n\n        # Translate the region down by (text_region.height + 10) pixels for\n        # the next block:\n        text_region += (0, text_region.height + 10)\n\nimage.save(\"./docs/images/example-2.png\", \"png\")\n```\n\n![Text aligned horizontally and vertically](https://github.com/cariad/palign/blob/main/docs/images/example-2.png)\n\nTo align text in a grid, use a [`Grid`](https://palign.dev/grid/):\n\n```python\nfrom PIL import Image, ImageDraw\nfrom PIL.ImageFont import truetype\n\nfrom palign import Alignment, Grid, Style, make_image_region\n\n\nimage_region = make_image_region(600, 400)\n\nimage = Image.new(\"RGB\", image_region.size, (255, 255, 255))\ndraw = ImageDraw.Draw(image)\n\nstyle = Style(\n    color=(0, 0, 0),\n    font=truetype(\"tests/font/ChelseaMarket-Regular.ttf\", 26),\n)\n\ncolumn_count = 3\nrow_count = 3\n\ngrid = Grid(\n    column_count,\n    row_count,\n    image_region.expand(-10),\n    style=style,\n)\n\nfor vertical_index, vertical in enumerate(Alignment):\n    for horizontal_index, horizontal in enumerate(Alignment):\n        match horizontal:\n            case Alignment.Near:\n                horizontal_name = \"Left\"\n            case Alignment.Center:\n                horizontal_name = \"Center\"\n            case Alignment.Far:\n                horizontal_name = \"Right\"\n\n        match vertical:\n            case Alignment.Near:\n                vertical_name = \"Top\"\n            case Alignment.Center:\n                vertical_name = \"Center\"\n            case Alignment.Far:\n                vertical_name = \"Bottom\"\n\n        t = f\"{vertical_name}\\n{horizontal_name}\"\n\n        grid[horizontal_index, vertical_index].text = t\n        grid[horizontal_index, vertical_index].style.horizontal = horizontal\n        grid[horizontal_index, vertical_index].style.vertical = vertical\n\n\ndef color_bit(column: int) -\u003e int:\n    return 155 + int((100 / column_count) * column)\n\n\nfor x in range(column_count):\n    for y in range(row_count):\n        red = color_bit(x) if y == 0 else 255\n        green = color_bit(x) if y == 1 else 255\n        blue = color_bit(x) if y == 2 else 255\n        grid[x, y].style.background = (red, green, blue)\n\ngrid.draw(draw)\n\nimage.save(\"./docs/images/grid.png\", \"png\")\n```\n\n![](https://github.com/cariad/palign/blob/main/docs/images/grid.png)\n\nFor detailed usage information, see the [`Style`](https://palign.dev/style/), [`Text`](https://palign.dev/text/) and [`Grid`](https://palign.dev/grid/) classes.\n\n## Installation\n\n**Palign** requires Python 3.9 or later.\n\n```console\npip install palign\n```\n\n## Support\n\nPlease raise bugs, request new features and ask questions at [github.com/cariad/palign/issues](https://github.com/cariad/palign/issues).\n\n## Contributions\n\nSee [CONTRIBUTING.md](https://github.com/cariad/palign/blob/main/CONTRIBUTING.md) for contribution guidelines.\n\n## The Project\n\n**Palign** is \u0026copy; 2022 Cariad Eccleston and released under the [MIT License](https://github.com/cariad/palign/blob/main/LICENSE) at [github.com/cariad/palign](https://github.com/cariad/palign).\n\n**Chelsea Market** is copyright \u0026copy; 2011 Font Diner and redistributed under the [SIL Open Font License 1.1](https://github.com/cariad/palign/blob/main/tests/font/OFL.txt).\n\n## The Author\n\nHello! 👋 I'm **Cariad Eccleston** and I'm a freelance backend and infrastructure engineer in the United Kingdom. You can find me at [cariad.earth](https://cariad.earth), [github.com/cariad](https://github.com/cariad), [linkedin.com/in/cariad](https://linkedin.com/in/cariad) and on Mastodon at [@cariad@tech.lgbt](https://tech.lgbt/@cariad).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcariad%2Fpalign","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcariad%2Fpalign","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcariad%2Fpalign/lists"}