{"id":18686517,"url":"https://github.com/docsaidlab/wordcanvas","last_synced_at":"2026-02-06T03:30:59.583Z","repository":{"id":232721058,"uuid":"785020866","full_name":"DocsaidLab/WordCanvas","owner":"DocsaidLab","description":"Generating text with custom fonts and styles.","archived":false,"fork":false,"pushed_at":"2024-04-13T22:58:18.000Z","size":5281,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2024-04-14T04:06:16.571Z","etag":null,"topics":["dataset","ocr","pillow","python","synthetic","text"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DocsaidLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-04-11T03:00:05.000Z","updated_at":"2024-05-22T14:00:19.103Z","dependencies_parsed_at":"2024-04-14T04:06:18.405Z","dependency_job_id":null,"html_url":"https://github.com/DocsaidLab/WordCanvas","commit_stats":null,"previous_names":["docsaidlab/textgenerator","docsaidlab/textimagegenerator"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DocsaidLab%2FWordCanvas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DocsaidLab%2FWordCanvas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DocsaidLab%2FWordCanvas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DocsaidLab%2FWordCanvas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DocsaidLab","download_url":"https://codeload.github.com/DocsaidLab/WordCanvas/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239248419,"owners_count":19607013,"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":["dataset","ocr","pillow","python","synthetic","text"],"created_at":"2024-11-07T10:27:57.261Z","updated_at":"2025-11-08T00:30:29.021Z","avatar_url":"https://github.com/DocsaidLab.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"**[English](./README.md)** | [中文](./README_tw.md)\n\n# WordCanvas\n\n\u003cp align=\"left\"\u003e\n    \u003ca href=\"./LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-Apache%202-dfd.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"\"\u003e\u003cimg src=\"https://img.shields.io/badge/python-3.10+-aff.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/DocsaidLab/WordCanvas/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/DocsaidLab/WordCanvas?color=ffa\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/wordcanvas_docsaid/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/wordcanvas_docsaid.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/wordcanvas_docsaid/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/dm/wordcanvas_docsaid?color=9cf\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Introduction\n\n\u003cdiv align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/DocsaidLab/WordCanvas/blob/main/docs/title.jpg?raw=true\" width=\"800\"\u003e\n\u003c/div\u003e\n\n---\n\nThis project is a text image rendering tool based on Pillow, designed specifically for random image generation.\n\nBy adding a variety of parameter settings, users can flexibly adjust input text, font styles, colors, and other attributes to achieve large-scale random generation of text images. Whether addressing issues such as data scarcity, class imbalance, or enhancing image diversity, WordCanvas provides a simple and efficient solution, offering a solid data foundation for deep learning training.\n\n## Technical Documentation\n\nFor installation and usage instructions, please refer to [**WordCanvas Documents**](https://docsaid.org/en/docs/wordcanvas).\n\nThere you will find detailed information about the project.\n\n## Installation\n\n### Install via PyPI\n\n1. Install `wordcanvas-docsaid`:\n\n   ```bash\n   pip install wordcanvas-docsaid\n   ```\n\n2. Verify installation:\n\n   ```bash\n   python -c \"import wordcanvas; print(wordcanvas.__version__)\"\n   ```\n\n3. If you see the version number, the installation is successful.\n\n### Install from GitHub\n\n1. Clone the project from GitHub:\n\n   ```bash\n   git clone https://github.com/DocsaidLab/WordCanvas.git\n   ```\n\n2. Install the wheel package:\n\n   ```bash\n   pip install wheel setuptools\n   ```\n\n3. Build the whl file:\n\n   ```bash\n   cd WordCanvas\n   python setup.py bdist_wheel\n   ```\n\n4. Install the whl file:\n\n   ```bash\n   pip install dist/wordcanvas_docsaid-*-py3-none-any.whl\n   ```\n\n## Quick Start\n\nThe hardest part is getting started, so we need a simple beginning.\n\n### Start with a String\n\nSimply provide a basic declaration and you're ready to go.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas(return_infos=True)\n```\n\nUsing all default settings, you can directly call the function to generate a text image.\n\n```python\ntext = \"你好！Hello, World!\"\nimg, infos = gen(text)\n\nprint(img.shape)\n# \u003e\u003e\u003e (67, 579, 3)\n\nprint(infos)\n# {'text': '你好！Hello, World!',\n#  'bbox(xyxy)': (0, 21, 579, 88),\n#  'bbox(wh)': (579, 67),\n#  'offset': (0, -21),\n#  'direction': 'ltr',\n#  'background_color': (0, 0, 0),\n#  'text_color': (255, 255, 255),\n#  'spacing': 4,\n#  'align': 'left',\n#  'stroke_width': 0,\n#  'stroke_fill': (0, 0, 0),\n#  'font_path': 'fonts/NotoSansTC-Regular.otf',\n#  'font_size_actual': 64,\n#  'font_name': 'NotoSansTC-Regular',\n#  'align_mode': \u003cAlignMode.Left: 0\u003e,\n#  'output_direction': \u003cOutputDirection.Remain: 0\u003e}\n```\n\n![sample1](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample1.jpg?raw=true)\n\n\u003e [!TIP]\n\u003e In default mode, the output image size depends on:\n\u003e\n\u003e 1. **Font size**: The default is 64. As the font size increases, the image size will also increase.\n\u003e 2. **Text length**: The longer the text, the wider the image will be, with the exact length determined by `pillow`.\n\u003e 3. The output information `infos` contains all drawing parameters, including text, background color, text color, etc.\n\u003e 4. To output only the image, set `return_infos=False`, which is the default setting.\n\n### Specify a Specific Font\n\nYou can specify your preferred font using the `font` parameter.\n\n```python\nfrom wordcanvas import WordCanvas\n\n# Do not specify return_infos, default is False, which will not return infos\ngen = WordCanvas(\n    font_path=\"/path/to/your/font/OcrB-Regular.ttf\"\n)\n\ntext = 'Hello, World!'\nimg = gen(text)\n```\n\n![sample14](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample14.jpg?raw=true)\n\nIf the font does not support the input text, tofu characters will appear.\n\n```python\ntext = 'Hello, 中文!'\nimg = gen(text)\n```\n\n![sample15](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample15.jpg?raw=true)\n\n\u003e [!TIP]\n\u003e\n\u003e **How to Check if the Font Supports Characters:**\n\u003e\n\u003e I currently don’t have this requirement, so I’ve left a basic method. This is a simple check that only checks one character at a time, so you need to iterate through all the characters. If you have other requirements, feel free to expand on this.\n\u003e\n\u003e ```python title=\"check_font.py\"\n\u003e from wordcanvas import is_character_supported, load_ttfont\n\u003e\n\u003e target_text = 'Hello, 中文!'\n\u003e\n\u003e font = load_ttfont(\"/path/to/your/font/OcrB-Regular.ttf\")\n\u003e\n\u003e for c in target_text:\n\u003e     status = is_character_supported(font, c)\n\u003e\n\u003e # \u003e\u003e\u003e Character '中' (0x4e2d) is not supported by the font.\n\u003e # \u003e\u003e\u003e Character '文' (0x6587) is not supported by the font.\n\u003e ```\n\n### Set Image Size\n\nYou can adjust the image size using the `output_size` parameter.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas(output_size=(64, 1024)) # Height 64, Width 1024\nimg = gen(text)\nprint(img.shape)\n# \u003e\u003e\u003e (64, 1024, 3)\n```\n\n![sample4](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample4.jpg?raw=true)\n\nWhen the specified size is smaller than the text image size, the text image will be automatically scaled.\n\nIn other words, the text will be squeezed together, becoming a narrow rectangle, for example:\n\n```python\nfrom wordcanvas import WordCanvas\n\ntext = '你好' * 10\ngen = WordCanvas(output_size=(64, 512))  # Height 64, Width 512\nimg = gen(text)\n```\n\n![sample8](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample8.jpg?raw=true)\n\n### Adjust Background Color\n\nYou can adjust the background color using the `background_color` parameter.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas(background_color=(255, 0, 0)) # Red background\nimg = gen(text)\n```\n\n![sample2](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample2.jpg?raw=true)\n\n### Adjust Text Color\n\nYou can adjust the text color using the `text_color` parameter.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas(text_color=(0, 255, 0)) # Green text\nimg = gen(text)\n```\n\n![sample3](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample3.jpg?raw=true)\n\n### Adjust Text Alignment\n\n\u003e [!WARNING]\n\u003e Do you remember the image size mentioned earlier?\n\u003e\n\u003e By default, **setting text alignment does not have any effect**. When drawing the image, there must be extra space in the text image to see the alignment effect.\n\nYou can adjust the text alignment using the `align_mode` parameter.\n\n```python\nfrom wordcanvas import AlignMode, WordCanvas\n\ngen = WordCanvas(\n    output_size=(64, 1024),\n    align_mode=AlignMode.Center\n)\n\ntext = '你好！ Hello, World!'\nimg = gen(text)\n```\n\n- **Center alignment: `AlignMode.Center`**\n\n  ![sample5](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample5.jpg?raw=true)\n\n- **Right alignment: `AlignMode.Right`**\n\n  ![sample6](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample6.jpg?raw=true)\n\n- **Left alignment: `AlignMode.Left`**\n\n  ![sample4](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample4.jpg?raw=true)\n\n- **Scatter alignment: `AlignMode.Scatter`**\n\n  ![sample7](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample7.jpg?raw=true)\n\n\u003e [!TIP]\n\u003e\n\u003e In scatter alignment mode, not every character will be spread out, but words will be spread as a unit. In Chinese, the unit of a word is a character; in English, the unit of a word is a space.\n\u003e\n\u003e For example, the input text \"你好！ Hello, World!\" will be split into:\n\u003e\n\u003e - [\"你\", \"好\", \"！\", \"Hello,\", \"World!\"]\n\u003e\n\u003e Spaces are ignored, and scatter alignment is applied.\n\u003e\n\u003e Additionally, when the input text can only be split into a single word, scatter alignment for Chinese words is equivalent to center alignment, and English words will be split into individual characters for scatter alignment.\n\u003e\n\u003e The logic we use for this is:\n\u003e\n\u003e ```python\n\u003e def split_text(text: str):\n\u003e     \"\"\" Split text into a list of characters. \"\"\"\n\u003e     pattern = r\"[a-zA-Z0-9\\p{P}\\p{S}]+|.\"\n\u003e     matches = regex.findall(pattern, text)\n\u003e     matches = [m for m in matches if not regex.match(r'\\p{Z}', m)]\n\u003e     if len(matches) == 1:\n\u003e         matches = list(text)\n\u003e     return matches\n\u003e ```\n\n\u003e [!WARNING]\n\u003e This is a very simple implementation and may not meet all requirements. If you have a more complete solution for string splitting, feel free to provide it.\n\n### Adjust Text Direction\n\nYou can adjust the text direction using the `direction` parameter.\n\n- **Output horizontal text**\n\n  ```python\n  from wordcanvas import AlignMode, WordCanvas\n\n  text = '你好！'\n  gen = WordCanvas(direction='ltr') # Left to right horizontal text\n  img = gen(text)\n  ```\n\n  ![sample9](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample9.jpg?raw=true)\n\n- **Output vertical text**\n\n  ```python\n  from wordcanvas import AlignMode, WordCanvas\n\n  text = '你好！'\n  gen = WordCanvas(direction='ttb') # Top to bottom vertical text\n  img = gen(text)\n  ```\n\n  ![sample10](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample10.jpg?raw=true)\n\n- **Output vertical text with scatter alignment**\n\n  ```python\n  from wordcanvas import AlignMode, WordCanvas\n\n  text = '你好！'\n  gen = WordCanvas(\n      direction='ttb',\n      align_mode=AlignMode.Scatter,\n      output_size=(64, 512)\n  )\n  img = gen(text)\n  ```\n\n  ![sample11](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample11.jpg?raw=true)\n\n### Adjust Output Direction\n\nYou can adjust the output direction using the `output_direction` parameter.\n\n\u003e [!TIP]\n\u003e\n\u003e **When to use this parameter**: When you choose \"Output vertical text\" but still want to view the text image horizontally, you can use this parameter.\n\n- **Vertical text, horizontal output**\n\n  ```python\n  from wordcanvas import OutputDirection, WordCanvas\n\n  gen = WordCanvas(\n      direction='ttb',\n      output_direction=OutputDirection.Horizontal\n  )\n\n  text = '你好！'\n  img = gen(text)\n  ```\n\n  ![sample12](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample12.jpg?raw=true)\n\n- **Horizontal text, vertical output**\n\n  ```python\n  from wordcanvas import OutputDirection, WordCanvas\n\n  gen = WordCanvas(\n      direction='ltr',\n      output_direction=OutputDirection.Vertical\n  )\n\n  text = '你好！'\n  img = gen(text)\n  ```\n\n  ![sample13](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample13.jpg?raw=true)\n\n### Squeeze Text\n\nIn some scenarios, the text might need to be specially squeezed. You can use the `text_aspect_ratio` parameter to adjust this.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas(\n    text_aspect_ratio=0.25, # Text height / text width = 1/4\n    output_size=(32, 1024),\n)  # Squeezed text\n\ntext=\"壓扁測試\"\nimg = gen(text)\n```\n\n![sample16](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample16.jpg?raw=true)\n\n\u003e [!IMPORTANT]\n\u003e It is important to note that if the squeezed text size exceeds the `output_size`, the image will go through an automatic scaling process. Therefore, you might end up squeezing the text, but it will be scaled back to its original size, and nothing will appear to have happened.\n\n### Text Stroke\n\nYou can adjust the width of the text stroke using the `stroke_width` parameter.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas(\n    font_size=64,\n    text_color=(0, 0, 255), # Red text\n    background_color=(255, 0, 0), # Blue background\n    stroke_width=2, # Stroke width\n    stroke_fill=(0, 255, 0), # Green stroke\n)\n\ntext=\"文字外框測試\"\nimg = gen(text)\n```\n\n![sample29](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample29.jpg?raw=true)\n\n\u003e [!WARNING]\n\u003e Using `stroke_width` may result in an OSError: array allocation size too large error with certain text.\n\u003e\n\u003e ```python\n\u003e Using `stroke_width` may cause an OSError: array allocation size too large error with certain text.\n\u003e This is a known issue with the `Pillow` library (see https://github.com/python-pillow/Pillow/issues/7287) and cannot be resolved directly.\n\u003e ```\n\u003e\n\u003e We found in testing that using `stroke_width` in `Pillow` may intermittently result in an `OSError`. This is a known issue with `Pillow`, and we have linked the relevant issue in the warning. You can click the link to view it.\n\n### Multi-line Text\n\nYou can use the `\\n` newline character to create multi-line text.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas()\n\ntext = '你好！\\nHello, World!'\nimg = gen(text)\n```\n\n![sample30](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample30.jpg?raw=true)\n\nIn the case of multi-line text, you can combine it with most of the features mentioned above, for example:\n\n```python\nfrom wordcanvas import WordCanvas, AlignMode\n\ngen = WordCanvas(\n  text_color=(0, 0, 255), # Red text\n  output_size=(128, 512), # Height 128, Width 512\n  background_color=(0, 0, 0), # Black background\n  align_mode=AlignMode.Center, # Center alignment\n  stroke_width=2, # Stroke width\n  stroke_fill=(0, 255, 0), # Green stroke\n)\n\ntext = '你好！\\nHello, World!'\nimg = gen(text)\n```\n\n![sample31](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/sample31.jpg?raw=true)\n\n\u003e [!WARNING]\n\u003e\n\u003e The following situations do not support multi-line text:\n\u003e\n\u003e 1. **`align_mode` does not support `AlignMode.Scatter`**\n\u003e\n\u003e    ```python\n\u003e    gen = WordCanvas(align_mode=AlignMode.Scatter)\n\u003e    ```\n\u003e\n\u003e 2. **`direction` does not support `ttb`**\n\u003e\n\u003e    ```python\n\u003e     gen = WordCanvas(direction='ttb')\n\u003e    ```\n\u003e\n\u003e If you need these features, please avoid using multi-line text.\n\n### Dashboard\n\nThe basic functionality is more or less as described.\n\nFinally, let's introduce the dashboard feature.\n\n```python\nfrom wordcanvas import WordCanvas\n\ngen = WordCanvas()\nprint(gen)\n```\n\nYou can also directly output without using `print`, as we have implemented the `__repr__` method.\n\nOnce output, you will see a simple dashboard.\n\n![dashboard](https://github.com/DocsaidLab/WordCanvas/blob/main/docs/dashboard.jpg?raw=true)\n\nHere you can see:\n\n- The first column is **Property**, which lists all the setting parameters.\n- The second column is **Current Value**, showing the current value of the parameter.\n- The third column is **SetMethod**, which shows how the parameter is set.\n  - Parameters set with `set` can be directly modified;\n  - Parameters set with `reinit` require reinitialization of the `WordCanvas` object.\n- The fourth column is **DType**, which shows the data type of the parameter.\n- The fifth column is **Description**, which describes the parameter. (This column is not shown in the image above to save space.)\n\nMost parameters can be directly set, meaning that when you need to modify output characteristics, you don't need to create a new object. Just modify the settings directly. Parameters that require `reinit` usually involve the initialization of font formats, such as text height (`font_size`) and others.\n\n```python\ngen.output_size = (64, 1024)\ngen.text_color = (0, 255, 0)\ngen.align_mode = AlignMode.Center\ngen.direction = 'ltr'\ngen.output_direction = OutputDirection.Horizontal\n```\n\nAfter setting, you can directly call the function to get the new text image. Additionally, if you modify parameters related to `reinit`, you will receive the corresponding error:\n\n- **AttributeError: can't set attribute**\n\n  ```python\n  gen.font_size = 128\n  # \u003e\u003e\u003e AttributeError: can't set attribute\n  ```\n\n\u003e [!CAUTION]\n\u003e\n\u003e Of course, you can still forcefully modify the parameters, but as a fellow Python user, I can't stop you:\n\u003e\n\u003e ```python\n\u003e gen._font_size = 128\n\u003e ```\n\u003e\n\u003e However, this will cause errors when generating the image later!\n\u003e\n\u003e Don't insist; just reinitialize the object.\n\n## Summary\n\nMany features haven't been mentioned, but the basic functionality has been covered.\n\nThis concludes the basic usage of the project. For more detailed information and usage methods, please refer directly to [**WordCanvas Advanced Usage**](https://docsaid.org/en/docs/wordcanvas/advance/).\n\n## Citation\n\nIf you find our work helpful, please cite the following:\n\n```bibtex\n@misc{yuan2024wordcanvas,\n  author = {Ze Yuan},\n  title = {WordCanvas},\n  year = {2024},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  howpublished = {\\url{https://github.com/DocsaidLab/WordCanvas}}\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdocsaidlab%2Fwordcanvas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdocsaidlab%2Fwordcanvas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdocsaidlab%2Fwordcanvas/lists"}