neots 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. neots-0.1.1/.github/workflows/workflow.yml +168 -0
  2. neots-0.1.1/.gitignore +46 -0
  3. neots-0.1.1/CMakeLists.txt +84 -0
  4. neots-0.1.1/LICENSE +21 -0
  5. neots-0.1.1/PKG-INFO +285 -0
  6. neots-0.1.1/README.md +270 -0
  7. neots-0.1.1/bindings.cpp +48 -0
  8. neots-0.1.1/glyph_cache.cpp +21 -0
  9. neots-0.1.1/glyph_cache.hpp +39 -0
  10. neots-0.1.1/main.cpp +176 -0
  11. neots-0.1.1/neo_synthesizer.cpp +323 -0
  12. neots-0.1.1/neo_synthesizer.hpp +62 -0
  13. neots-0.1.1/pyproject.toml +34 -0
  14. neots-0.1.1/python/neots/__init__.py +248 -0
  15. neots-0.1.1/python/neots/cli.py +596 -0
  16. neots-0.1.1/python/neots/data/configs/minimal.json +28 -0
  17. neots-0.1.1/python/neots/data/configs/preset.json +69 -0
  18. neots-0.1.1/python/neots/data/default_dictionary.txt +14230 -0
  19. neots-0.1.1/python/neots/data/s2t.txt +1495 -0
  20. neots-0.1.1/python/neots/data/symbols_characters/characters.txt +8105 -0
  21. neots-0.1.1/python/neots/data/symbols_characters/jp_characters.txt +183 -0
  22. neots-0.1.1/python/neots/data/symbols_characters/ko_characters.txt +2441 -0
  23. neots-0.1.1/python/neots/data/symbols_characters/kokuji.txt +1655 -0
  24. neots-0.1.1/python/neots/data/symbols_characters/symbols.txt +325 -0
  25. neots-0.1.1/python/neots/data/symbols_characters/traditional_chars.txt +1520 -0
  26. neots-0.1.1/python/neots/flatten_wikipedia_generator.py +151 -0
  27. neots-0.1.1/renderer.cpp +574 -0
  28. neots-0.1.1/renderer.hpp +126 -0
  29. neots-0.1.1/textsampler.cpp +511 -0
  30. neots-0.1.1/textsampler.hpp +80 -0
  31. neots-0.1.1/utils.cpp +152 -0
  32. neots-0.1.1/utils.hpp +33 -0
  33. neots-0.1.1/vcpkg.json +18 -0
  34. neots-0.1.1/worker.cpp +196 -0
  35. neots-0.1.1/worker.hpp +81 -0
  36. neots-0.1.1/writer.cpp +121 -0
  37. neots-0.1.1/writer.hpp +41 -0
  38. neots-0.1.1/yaml_utils.cpp +200 -0
  39. neots-0.1.1/yaml_utils.hpp +27 -0
@@ -0,0 +1,168 @@
1
+ name: Build & Publish
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+ jobs:
9
+ build_wheels:
10
+ name: Build wheels on ${{ matrix.os }} (${{ matrix.arch }})
11
+ runs-on: ${{ matrix.runner }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ include:
16
+ # Linux x86_64
17
+ - os: linux
18
+ arch: x86_64
19
+ runner: ubuntu-latest
20
+ cibw_archs: x86_64
21
+ # Linux aarch64
22
+ - os: linux
23
+ arch: aarch64
24
+ runner: ubuntu-24.04-arm
25
+ cibw_archs: aarch64
26
+ # macOS arm64
27
+ - os: macos
28
+ arch: arm64
29
+ runner: macos-14
30
+ cibw_archs: arm64
31
+ # Windows x86_64
32
+ - os: windows
33
+ arch: x86_64
34
+ runner: windows-latest
35
+ cibw_archs: AMD64
36
+
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - name: Setup vcpkg GitHub Actions Cache
41
+ uses: actions/github-script@v7
42
+ with:
43
+ script: |
44
+ core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
45
+ core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
46
+
47
+ - name: Build wheels
48
+ uses: pypa/cibuildwheel@v2.22
49
+ env:
50
+ CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
51
+ CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
52
+
53
+ CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-*"
54
+ CIBW_SKIP: "*-musllinux_* *_i686 *-win32"
55
+ CIBW_ARCHS: ${{ matrix.cibw_archs }}
56
+
57
+ VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
58
+ ACTIONS_CACHE_URL: ${{ env.ACTIONS_CACHE_URL }}
59
+ ACTIONS_RUNTIME_TOKEN: ${{ env.ACTIONS_RUNTIME_TOKEN }}
60
+
61
+ CIBW_BEFORE_ALL_LINUX: >
62
+ yum install -y curl zip unzip tar pkgconfig perl-IPC-Cmd gcc gcc-c++ &&
63
+ pip install cmake ninja &&
64
+ export VCPKG_FORCE_SYSTEM_BINARIES=1 &&
65
+ ( [ -d /opt/vcpkg ] || git clone https://github.com/microsoft/vcpkg.git /opt/vcpkg ) &&
66
+ /opt/vcpkg/bootstrap-vcpkg.sh -disableMetrics &&
67
+ cd {project} &&
68
+ /opt/vcpkg/vcpkg install
69
+
70
+ CIBW_ENVIRONMENT_LINUX: >
71
+ VCPKG_FORCE_SYSTEM_BINARIES=1
72
+ VCPKG_BINARY_SOURCES="clear;x-gha,readwrite"
73
+ ACTIONS_CACHE_URL=$ACTIONS_CACHE_URL
74
+ ACTIONS_RUNTIME_TOKEN=$ACTIONS_RUNTIME_TOKEN
75
+ CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=/opt/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_INSTALLED_DIR={project}/vcpkg_installed -DVCPKG_BUILD_TYPE=release"
76
+
77
+ CIBW_BEFORE_ALL_MACOS: >
78
+ cd {project} &&
79
+ $VCPKG_INSTALLATION_ROOT/vcpkg install
80
+
81
+ CIBW_ENVIRONMENT_MACOS: >
82
+ VCPKG_BINARY_SOURCES="clear;x-gha,readwrite"
83
+ ACTIONS_CACHE_URL=$ACTIONS_CACHE_URL
84
+ ACTIONS_RUNTIME_TOKEN=$ACTIONS_RUNTIME_TOKEN
85
+ CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake -DVCPKG_INSTALLED_DIR={project}/vcpkg_installed -DVCPKG_BUILD_TYPE=release"
86
+
87
+ CIBW_BEFORE_ALL_WINDOWS: >
88
+ cd /d {project} &&
89
+ C:/vcpkg/vcpkg.exe install
90
+
91
+
92
+ CIBW_ENVIRONMENT_WINDOWS: >
93
+ VCPKG_BINARY_SOURCES="clear;x-gha,readwrite"
94
+ ACTIONS_CACHE_URL=$ACTIONS_CACHE_URL
95
+ ACTIONS_RUNTIME_TOKEN=$ACTIONS_RUNTIME_TOKEN
96
+ CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_INSTALLED_DIR={project}/vcpkg_installed -DVCPKG_BUILD_TYPE=release"
97
+
98
+ - uses: actions/upload-artifact@v4
99
+ with:
100
+ name: wheels-${{ matrix.os }}-${{ matrix.arch }}
101
+ path: ./wheelhouse/*.whl
102
+
103
+ build_sdist:
104
+ name: Build source distribution
105
+ runs-on: ubuntu-latest
106
+ steps:
107
+ - uses: actions/checkout@v4
108
+
109
+ - name: Build sdist
110
+ run: pipx run build --sdist
111
+
112
+ - uses: actions/upload-artifact@v4
113
+ with:
114
+ name: sdist
115
+ path: dist/*.tar.gz
116
+
117
+ upload_release:
118
+ name: Upload to GitHub Release
119
+ needs: [build_wheels, build_sdist]
120
+ runs-on: ubuntu-latest
121
+ if: github.event_name == 'release'
122
+ permissions:
123
+ contents: write
124
+ steps:
125
+ - uses: actions/download-artifact@v4
126
+ with:
127
+ path: dist
128
+ merge-multiple: true
129
+
130
+ - name: Upload release assets
131
+ uses: softprops/action-gh-release@v2
132
+ with:
133
+ files: dist/*
134
+
135
+ publish_test_pypi:
136
+ name: Publish to TestPyPI
137
+ needs: [build_wheels, build_sdist]
138
+ runs-on: ubuntu-latest
139
+ permissions:
140
+ id-token: write
141
+ if: github.event_name == 'workflow_dispatch'
142
+ steps:
143
+ - uses: actions/download-artifact@v4
144
+ with:
145
+ path: dist
146
+ merge-multiple: true
147
+
148
+ - name: Publish to TestPyPI
149
+ uses: pypa/gh-action-pypi-publish@release/v1
150
+ with:
151
+ repository-url: https://test.pypi.org/legacy/
152
+ skip-existing: true
153
+
154
+ publish_pypi:
155
+ name: Publish to PyPI
156
+ needs: [build_wheels, build_sdist]
157
+ runs-on: ubuntu-latest
158
+ permissions:
159
+ id-token: write
160
+ if: github.event_name == 'release' && github.event.action == 'published'
161
+ steps:
162
+ - uses: actions/download-artifact@v4
163
+ with:
164
+ path: dist
165
+ merge-multiple: true
166
+
167
+ - name: Publish package distributions to PyPI
168
+ uses: pypa/gh-action-pypi-publish@release/v1
neots-0.1.1/.gitignore ADDED
@@ -0,0 +1,46 @@
1
+ build/
2
+ backgrounds/
3
+ default_fonts/
4
+ fallback_fonts/
5
+ corpuses/
6
+ .venv/
7
+ .vscode/
8
+
9
+ cmake-build-debug/
10
+ cmake-build-release/
11
+ out/
12
+
13
+ *.o
14
+ *.obj
15
+ *.a
16
+ *.lib
17
+ *.so
18
+ *.dylib
19
+ *.dll
20
+
21
+ *.exe
22
+ *.out
23
+ *.app
24
+
25
+ .vscode/
26
+ .idea/
27
+ *.swp
28
+ *.swo
29
+ *~
30
+ .DS_Store
31
+
32
+
33
+ CMakeLists.txt.user
34
+ *.cmake
35
+ CMakeCache.txt
36
+ CMakeFiles/
37
+
38
+ vcpkg_installed/
39
+ conan/
40
+
41
+ generated/
42
+ *.egg-info/
43
+ dist/
44
+ __pycache__/
45
+ *.pyc
46
+ _skbuild/
@@ -0,0 +1,84 @@
1
+ cmake_minimum_required(VERSION 3.16)
2
+
3
+ if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
4
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
5
+ CACHE STRING "")
6
+ endif()
7
+
8
+ project(neots CXX)
9
+
10
+ set(CMAKE_CXX_STANDARD 17)
11
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
12
+
13
+ include(FetchContent)
14
+
15
+ FetchContent_Declare(
16
+ json
17
+ GIT_REPOSITORY https://github.com/nlohmann/json.git
18
+ GIT_TAG v3.12.0
19
+ )
20
+ FetchContent_MakeAvailable(json)
21
+
22
+ FetchContent_Declare(
23
+ indicators
24
+ GIT_REPOSITORY https://github.com/p-ranav/indicators.git
25
+ GIT_TAG v2.3
26
+ )
27
+ FetchContent_MakeAvailable(indicators)
28
+
29
+ find_program(NINJA ninja)
30
+ if(NINJA)
31
+ set(CMAKE_MAKE_PROGRAM ${NINJA})
32
+ endif()
33
+
34
+ find_package(OpenCV REQUIRED)
35
+ find_package(Freetype REQUIRED)
36
+ find_package(Threads REQUIRED)
37
+ find_package(yaml-cpp REQUIRED)
38
+ find_package(harfbuzz CONFIG REQUIRED)
39
+
40
+ set(CORE_SOURCES
41
+ utils.cpp
42
+ textsampler.cpp
43
+ renderer.cpp
44
+ writer.cpp
45
+ worker.cpp
46
+ glyph_cache.cpp
47
+ yaml_utils.cpp
48
+ neo_synthesizer.cpp
49
+ )
50
+
51
+ add_library(ocr_core STATIC ${CORE_SOURCES})
52
+
53
+ target_include_directories(ocr_core PUBLIC
54
+ ${CMAKE_CURRENT_SOURCE_DIR}
55
+ ${OpenCV_INCLUDE_DIRS}
56
+ ${FREETYPE_INCLUDE_DIRS}
57
+ )
58
+
59
+ target_link_libraries(ocr_core PUBLIC
60
+ ${OpenCV_LIBS}
61
+ Freetype::Freetype
62
+ nlohmann_json::nlohmann_json
63
+ indicators::indicators
64
+ yaml-cpp::yaml-cpp
65
+ harfbuzz::harfbuzz
66
+ Threads::Threads
67
+ )
68
+
69
+ # Platform-appropriate optimization flags
70
+ if(MSVC)
71
+ target_compile_options(ocr_core PRIVATE /O2)
72
+ else()
73
+ target_compile_options(ocr_core PRIVATE -O2)
74
+ endif()
75
+
76
+ set_target_properties(ocr_core PROPERTIES POSITION_INDEPENDENT_CODE ON)
77
+
78
+ find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
79
+ find_package(nanobind CONFIG REQUIRED)
80
+
81
+ nanobind_add_module(_core bindings.cpp)
82
+ target_link_libraries(_core PRIVATE ocr_core)
83
+
84
+ install(TARGETS _core DESTINATION ${SKBUILD_PROJECT_NAME})
neots-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 reactor-no8
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
neots-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.2
2
+ Name: neots
3
+ Version: 0.1.1
4
+ Summary: NeoTextSynthesizer - High-performance OCR training data generator
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/reactor-no8/NeoTextSynthesizer
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: numpy>=1.24
9
+ Requires-Dist: Pillow>=9.0
10
+ Requires-Dist: datasets>=2.0
11
+ Requires-Dist: pyyaml>=6.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest; extra == "dev"
14
+ Description-Content-Type: text/markdown
15
+
16
+ # NeoTextSynthesizer (neots)
17
+
18
+ A high-performance, multi-threaded synthetic OCR training data generator built with C++.
19
+
20
+ NeoTextSynthesizer generates realistic text images with diverse fonts, backgrounds, and visual effects — ideal for training Text Recognition models.
21
+
22
+ ## Features
23
+
24
+ - **High Performance**: Multi-threaded C++ core with shared glyph cache, background image cache, and lock-free rendering pipeline
25
+ - **Multi-language Support**: Built-in support for Chinese (Simplified & Traditional), Japanese, Korean, English, German, French, Italian, Spanish, Russian, and extensible to any language
26
+ - **Flexible Text Sampling**: Sequential corpus streaming and random character sampling with nested probability-weighted groups
27
+ - **Rich Visual Effects**: Random fonts, font sizes, scale variations, italic/underline/strikethrough effects, diverse backgrounds (solid colors, gradients, real images)
28
+ - **Python Integration**: Full Python API via nanobind with NumPy/PIL support
29
+ - **CLI Tools**: `neots` for workspace initialization and batch generation, `flat-wiki` for Wikipedia corpus generation
30
+ - **Cross-platform**: Supports Linux x86_64, Linux AArch64, macOS ARM64, and Windows x86_64
31
+
32
+ ## Installation
33
+
34
+ Install pre-built wheels from PyPI:
35
+
36
+ ```bash
37
+ pip install neots
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### CLI Usage
43
+
44
+ ```bash
45
+ # Initialize a workspace
46
+ neots init
47
+
48
+ # Generate 10,000 images
49
+ neots generate --total 10000
50
+
51
+ # Generate with custom config and workers
52
+ neots generate --config config.yaml --total 50000 --workers 8
53
+
54
+ # Show help
55
+ neots help
56
+ ```
57
+
58
+ ### Wikipedia Corpus Generation (CLI)
59
+
60
+ ```bash
61
+ # Generate a Chinese corpus from Wikipedia
62
+ flat-wiki --lang zh --output ./corpuses/zh.txt --min_len 5 --sample_count 10000
63
+
64
+ # Generate with vocabulary filter
65
+ flat-wiki -l en -o ./corpuses/en.txt -v dictionary.txt -n 5000
66
+ ```
67
+
68
+ ### Python API
69
+
70
+ ```python
71
+ from neots import NeoTextSynthesizer
72
+
73
+ # Initialize from config file
74
+ synth = NeoTextSynthesizer.from_config_file("config.yaml")
75
+
76
+ # Initialize from a dictionary
77
+ config = NeoTextSynthesizer.get_default_config()
78
+ config["generate"]["output_height"] = 64
79
+ synth = NeoTextSynthesizer.from_config(config)
80
+
81
+ # Initialize from built-in default preset
82
+ synth = NeoTextSynthesizer.from_default() # full preset
83
+ synth = NeoTextSynthesizer.from_default("minimal") # minimal preset
84
+
85
+ # Batch generate (blocks until complete)
86
+ synth.generate(total=10000, workers=8, show_progress=True)
87
+
88
+ # Generate single image as PIL Image
89
+ img = synth.generate_instance("Hello World", type="PIL")
90
+ img.save("sample.png")
91
+
92
+ # Generate as NumPy array (H, W, 3) RGB
93
+ arr = synth.generate_instance("测试文本", type="numpy")
94
+
95
+ # Save directly to file
96
+ synth.generate_instance("サンプル", type="file", path="output.png")
97
+
98
+ # Export default config
99
+ NeoTextSynthesizer.output_default_dict("my_config.yaml", type="yaml")
100
+ NeoTextSynthesizer.output_default_dict("my_config.json", type="json")
101
+ ```
102
+
103
+ ### Corpus Generation (Python API)
104
+
105
+ ```python
106
+ from neots import FlattenWikipediaGenerator
107
+
108
+ gen = FlattenWikipediaGenerator(
109
+ lang="zh", # Language code
110
+ output="./corpuses/zh.txt", # Output file path
111
+ vocab="dictionary_extended.txt", # Optional: filter by vocabulary
112
+ min_len=5, # Minimum line length
113
+ sample_count=10000, # Number of articles to process
114
+ )
115
+ gen.generate()
116
+ ```
117
+
118
+ ## Configuration
119
+
120
+ Configuration is structured into three sections. See config.yaml for a complete example after initialization.
121
+
122
+ ### `text_sampler`
123
+
124
+ Defines how text strings are sampled for rendering. Each entry has a probability weight and a data source.
125
+
126
+ | Type | Description |
127
+ |------|-------------|
128
+ | `sequential` | Streams text from a flat file. Ideal for natural language corpuses. |
129
+ | `random` | Randomly samples from character files or nested sub-groups. |
130
+
131
+ ```yaml
132
+ text_sampler:
133
+ # Stream Chinese text from a corpus file
134
+ - type: sequential
135
+ prob: 0.20
136
+ from_file: ./corpuses/zh.txt
137
+
138
+ # Random character sampling with nested groups
139
+ - type: random
140
+ prob: 0.20
141
+ sub_items:
142
+ - prob: 0.4
143
+ from_file: ./symbols_characters/characters.txt
144
+ section: [~, 3500] # First 3500 lines only
145
+ - prob: 0.1
146
+ from_string: " " # Inline source
147
+ ```
148
+
149
+ Key parameters:
150
+ - `prob`: Probability weight (auto-normalized)
151
+ - `from_file` / `from_string`: Data source
152
+ - `section: [start, end]`: Slice of lines (`~` = null = beginning/end)
153
+ - `sub_items`: Nested probability groups (recursive)
154
+ - `traditional_prob`: Probability of simplified → traditional Chinese conversion
155
+
156
+ ### `image_processor`
157
+
158
+ Controls visual appearance:
159
+
160
+ | Parameter | Default | Description |
161
+ |-----------|---------|-------------|
162
+ | `bg_image_prob` | 0.3 | Probability of using a real background image |
163
+ | `gray_bg_prob` | 0.7 | Probability of gray vs. colored background |
164
+ | `effect_prob` | 0.2 | Probability of text effects (italic/underline/strikethrough) |
165
+ | `font_size` | 55 | Base font size in pixels |
166
+ | `scale_range` | [0.7, 1.1] | Random scale factor range |
167
+ | `margin_range` | [-5, 20] | Horizontal margin range (pixels) |
168
+ | `offset_prob` | 0.5 | Probability of random position offset |
169
+
170
+ ### `generate`
171
+
172
+ Controls output structure:
173
+
174
+ | Parameter | Default | Description |
175
+ |-----------|---------|-------------|
176
+ | `min_targets` / `max_targets` | 5 / 50 | Character count range per image |
177
+ | `output_height` | 48 | Output image height (width auto-calculated) |
178
+ | `default_font_dir` | ./default_fonts | Primary fonts directory |
179
+ | `fallback_font_dir` | ./fallback_fonts | Fallback fonts directory |
180
+ | `out_dir` | ./generated | Output image directory |
181
+ | `out_jsonl` | ./generated.jsonl | Annotation file path |
182
+ | `hierarchical_structure` | [100, 625] | Directory nesting levels |
183
+
184
+ ## Font Setup
185
+
186
+ ### Primary Fonts (`default_fonts/`)
187
+ Place diverse `.ttf` / `.otf` font files here. A random font is selected for each image. **More fonts = better model generalization.** Aim for 50-200+ fonts covering your target scripts.
188
+
189
+ ### Fallback Fonts (`fallback_fonts/`)
190
+ When the primary font doesn't cover certain characters, the system falls back to these fonts. Place comprehensive Unicode fonts here (e.g., Noto Sans CJK, Noto Sans).
191
+
192
+ ### System Default
193
+ If no fallback fonts are provided, the system automatically tries:
194
+ - **Linux**: `/usr/share/fonts/truetype/DejaVuSans.ttf`
195
+ - **macOS**: `/System/Library/Fonts/Courier New.ttf`
196
+ - **Windows**: `C:\Windows\Fonts\Arial.ttf`
197
+
198
+ If the system font is also unavailable, initialization fails.
199
+
200
+ ## Background Images
201
+
202
+ For realistic training data, add images to `backgrounds/` and set `bg_image_prob > 0`.
203
+
204
+ **Supported formats:** `.jpg`, `.jpeg`, `.png`, `.bmp`, `.webp`
205
+
206
+ ## Output Format
207
+
208
+ Generated images are saved as PNG files in a hierarchical directory structure:
209
+
210
+ ```
211
+ generated/
212
+ ├── 00000001/
213
+ │ ├── 00000001/
214
+ │ │ ├── 00000001.png
215
+ │ │ ├── 00000002.png
216
+ │ │ └── ...
217
+ │ └── ...
218
+ └── ...
219
+ ```
220
+
221
+ Annotations are saved in JSONL format (`generated.jsonl`):
222
+
223
+ ```json
224
+ {"image":"00000001/00000001/00000001.png","text":"示例文本","length":248}
225
+ {"image":"00000001/00000001/00000002.png","text":"Sample text","length":315}
226
+ ```
227
+
228
+ Each line contains:
229
+ - `image`: Relative path to the image file
230
+ - `text`: The rendered text content
231
+ - `length`: Image width in pixels
232
+
233
+ ## Development
234
+
235
+ This project uses [vcpkg](https://github.com/microsoft/vcpkg) to manage native C++ dependencies, and uses [scikit-build-core](https://scikit-build-core.readthedocs.io/) + [nanobind](https://nanobind.readthedocs.io/) for the Python/C++ bridge. Development is now based on configuring the environment with vcpkg and building from source.
236
+
237
+ ### Supported Platforms
238
+
239
+ - Linux x86_64
240
+ - Linux AArch64
241
+ - macOS ARM64
242
+ - Windows x86_64
243
+
244
+ ### Build from Source with vcpkg
245
+
246
+ #### Windows
247
+
248
+ ```powershell
249
+ git clone https://github.com/microsoft/vcpkg.git
250
+ .\vcpkg\bootstrap-vcpkg.bat
251
+ $env:CMAKE_TOOLCHAIN_FILE="$PWD\vcpkg\scripts\buildsystems\vcpkg.cmake"
252
+ pip install -e . --no-build-isolation
253
+ ```
254
+
255
+ #### macOS
256
+
257
+ ```bash
258
+ git clone https://github.com/microsoft/vcpkg.git
259
+ ./vcpkg/bootstrap-vcpkg.sh
260
+ export CMAKE_TOOLCHAIN_FILE="$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake"
261
+ pip install -e . --no-build-isolation
262
+ ```
263
+
264
+ #### Linux
265
+
266
+ ```bash
267
+ git clone https://github.com/microsoft/vcpkg.git
268
+ ./vcpkg/bootstrap-vcpkg.sh
269
+ export CMAKE_TOOLCHAIN_FILE="$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake"
270
+ pip install -e . --no-build-isolation
271
+ ```
272
+
273
+ If you prefer to build the native extension directly with CMake, make sure `CMAKE_TOOLCHAIN_FILE` points to the vcpkg toolchain before configuring the project.
274
+
275
+ ## Donate
276
+
277
+ This project is maintained by a single person, so the documentation is not yet fully comprehensive and the feature set is still relatively limited.
278
+
279
+ If you would like to support the project, the most valuable help is:
280
+ - submitting pull requests
281
+ - actively opening issues when you encounter problems during usage
282
+
283
+ ## License
284
+
285
+ This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.