kk-codeimg 0.0.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Python卡皮巴拉
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.
@@ -0,0 +1,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: kk_codeimg
3
+ Version: 0.0.1
4
+ Summary: 把代码渲染成精美的代码图片:12 套主题、16 种预设风格,支持窗口标题与中英文混排,纯 Pillow + Pygments 离线渲染
5
+ Author: Python卡皮巴拉
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/kapikkkk/kk_codeimg
8
+ Project-URL: Repository, https://github.com/kapikkkk/kk_codeimg
9
+ Project-URL: Issues, https://github.com/kapikkkk/kk_codeimg/issues
10
+ Keywords: code-image,codeimg,code-screenshot,carbon,syntax-highlight,png,thumbnail,social-media,代码截图,代码图片,分享图
11
+ Classifier: Development Status :: 2 - Pre-Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Multimedia :: Graphics
23
+ Classifier: Topic :: Software Development :: Documentation
24
+ Classifier: Topic :: Text Processing :: Markup
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.8
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: pillow>=9.0
30
+ Requires-Dist: pygments>=2.10
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0; extra == "dev"
33
+ Requires-Dist: build>=1.0; extra == "dev"
34
+ Requires-Dist: twine>=4.0; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # kk_codeimg
38
+
39
+ **🌟【Python卡皮巴拉】—— 你的Python修炼秘籍,代码界的"神兽"驾到!🌟**
40
+
41
+ **🌟 [Python Capybara] — Your Python cultivation manual; the coding realm's "mythical beast" has arrived! 🌟**
42
+
43
+ [PyPI](https://pypi.org/project/kk_codeimg/) · [MIT License](LICENSE) · [Python 3.8+](https://pypi.org/project/kk_codeimg/)
44
+
45
+ ### 安装
46
+
47
+ ```bash
48
+ pip install kk_codeimg
49
+ ```
50
+
51
+ ### 快速开始
52
+
53
+ ```python
54
+ from kk_codeimg import code_generator
55
+
56
+ code_generator(code, 'python', output='out.png')
57
+ ```
58
+
59
+ 不传 `output` 时返回 `PIL.Image.Image`,可自行 `.save()` 或做后处理。
60
+
61
+ ### 特点
62
+
63
+ - **12 套主题** —— 全部通过 WCAG AA 对比度校验,不是"看着差不多"
64
+ - **16 种预设风格** —— 一行代码切换整套视觉配置
65
+ - **窗口标题** —— 显示文件名,支持中文,字体与代码自动统一
66
+ - **中英文混排** —— 等宽字体没有中文字形?自动回退到系统 CJK 字体
67
+ - **对比度达标** —— 按 WCAG 标准实算,注释不再"灰到看不见"
68
+ - **纯离线** —— 不联网、不开浏览器,CI 里也能跑
69
+ - **零重型依赖** —— 只用 `Pillow` + `Pygments`
70
+ - **主题可扩展** —— 加一套主题只需往 `palette.py` 里加一组色值
71
+
72
+ ### 效果预览
73
+
74
+ 生成全套样图:
75
+
76
+ ```bash
77
+ python scripts/make_samples.py # 在仓库根目录执行
78
+ ```
79
+
80
+ 输出到 `out/`。
81
+
82
+ ### 预设风格
83
+
84
+ 不想逐个记参数就用 `style`,一次套用一整套视觉配置:
85
+
86
+ ```python
87
+ code_generator(code, 'python', style='tokyo', output='out.png')
88
+ ```
89
+
90
+ | 风格 | 说明 |
91
+ |---|---|
92
+ | `default` | 深色经典:One Dark 主题 + 柔和渐变 |
93
+ | `carbon` | 极简纯色底、无窗口控制点、方正小圆角 |
94
+ | `dracula` | Dracula 紫调 + 极光渐变 |
95
+ | `tokyo` | Tokyo Night 夜色 + 深海渐变 |
96
+ | `github` | GitHub 浅色 + 淡雅渐变(不透明底,可读性最佳) |
97
+ | `light-frosted` | 浅色磨砂:保留渐变氛围但垫白底,深字清晰 |
98
+ | `frosted` | 深色磨砂玻璃:大圆角,背景隐约透出 |
99
+ | `minimal` | 极简:无行号、无控制点、大留白 |
100
+ | `neon` | 霓虹酷炫:Cool Glow + 大圆角 |
101
+ | `share` | 社交分享:大字号、大圆角、宽留白 |
102
+ | `print` | 打印友好:白底黑字、无干扰 |
103
+ | `ocean` | 深海蓝:冷色调、克制圆角 |
104
+ | `sunset` | 日落暖橙:亮色系、适合长代码 |
105
+ | `forest` | 森林绿:护眼低饱和 |
106
+ | `grid` | 网格纸:零圆角、细边框控制点、代码排版感 |
107
+ | `sticker` | 贴纸风:浅色、夸张圆角、紧凑 |
108
+
109
+ 还有一批顺手加的**别名**,记不住名字也能用:
110
+ `dark` / `light` / `plain` / `classic` / `night` / `big` / `rounded` / `sharp` / `matrix` / `frost`
111
+
112
+ ```python
113
+ code_generator(code, 'python', style='dark') # 等同 default
114
+ code_generator(code, 'python', style='plain') # 等同 minimal
115
+ ```
116
+
117
+ 显式传入的参数**优先级高于** `style`:
118
+
119
+ ```python
120
+ # style 提供预设,再用 theme 覆盖其中一项
121
+ code_generator(code, 'python', style='minimal', theme='dracula')
122
+ ```
123
+
124
+ ### 常用参数
125
+
126
+ | 参数 | 默认 | 说明 |
127
+ |---|---|---|
128
+ | `code` | 必填 | 代码文本 |
129
+ | `language` | `'python'` | Pygments 语言名:`python` / `javascript` / `sql` / `java` / `go`… |
130
+ | `output` | `None` | PNG 路径;`None` 则只返回 Image |
131
+ | `style` | `None` | 预设风格名,见上表 |
132
+ | `theme` | 随 style | 12 套主题,见下表 |
133
+ | `background` | 随 style | 渐变名 / `single` / `transparent` / 任意 `#hex` |
134
+ | `font` | `None` | 字体名或 `.ttf` 路径;`None` 自动探测 |
135
+ | `font_size` | `15` | 字号(逻辑像素) |
136
+ | `border_radius` | `9` | 编辑器圆角 |
137
+ | `window_controls` | `'color'` | `color` / `gray` / `gray-light` / `outline` / `none` |
138
+ | `line_height` | `1.45` | 行高倍数 |
139
+ | `padding` | `64` | 图片四周留白 |
140
+ | `line_numbers` | `True` | 是否显示行号 |
141
+ | `transparent_editor` | `False` | 编辑器区域透明 |
142
+ | `scrim_alpha` | `None` | 透明模式下的底色不透明度 `0~1`;`None` 时按主题明暗自动决定 |
143
+ | `title` | `None` | 窗口标题,显示在窗口栏居中,支持中文 |
144
+ | `title_alpha` | `0.72` | 标题不透明度,调低可让标题退居次要 |
145
+ | `title_size` | `None` | 标题字号。`None`/`'same'` = 与代码同字号;传数字则单独指定 |
146
+ | `scale` | `2` | 渲染倍率,`2` 适合高清分享 |
147
+
148
+ 传了 `output` 时返回 `RenderResult`,带 `.image`、`.path`、`.editor_box`、`.code_box`。
149
+
150
+ ### 窗口标题
151
+
152
+ `title` 显示在窗口栏居中位置:
153
+
154
+ ```python
155
+ code_generator(code, 'python', title='point.py', output='out.png')
156
+ code_generator(code, 'python', title='几何工具 · 坐标计算', output='out.png') # 支持中文
157
+ ```
158
+
159
+ **字体始终与代码一致**,只有字号可以不同:
160
+
161
+ ```python
162
+ # 标题与代码同字号同字体(默认)
163
+ code_generator(code, 'python', title='main.py')
164
+
165
+ # 标题小一号
166
+ code_generator(code, 'python', title='main.py', font_size=20, title_size=13)
167
+
168
+ # 换个字体,标题自动跟随
169
+ code_generator(code, 'python', title='main.py', font='consolas')
170
+ ```
171
+
172
+ 细节:
173
+
174
+ - 字体统一是硬约束——代码用什么字体,标题就用同一个字体文件
175
+ (同字号时直接复用同一个字体对象);中文回退字体同样统一
176
+ - `title_size` 超过窗口栏容量(40px 栏高,约 48.6px 上限)会**自动钳制**,
177
+ 不会出现标题盖住代码的情况;`0` / 负数 / 非数字会抛 `ValueError`
178
+ - 超长标题自动截断加省略号,不溢出窗口
179
+ - `window_controls='none'` 时标题仍然显示(标题独立于控制点)
180
+ - 配色用主题**前景色**而非行号色——实测行号色在部分主题上对比度仅 2.76:1,
181
+ 前景色全部 ≥ 6.10:1
182
+ - 标题在**整个编辑器宽度上居中**
183
+
184
+ ### 主题(12 套)
185
+
186
+ `one-dark`(默认)、`dracula`、`vscode`、`ayu-light`、`github-light`、
187
+ `github-dark`、`tokyo-night`、`xcode-dark`、`xcode-light`、`amy`、`aura`、`cool-glow`
188
+
189
+ ```python
190
+ code_generator(code, 'python', output='a.png', theme='dracula', background='aurora')
191
+ ```
192
+
193
+ ### 背景
194
+
195
+ 10 套渐变:`mystic`(默认)、`aruba`、`jungle`、`tropical`、`aurora`、`candy`、
196
+ `peach`、`bananas`、`leaf`、`ocean`
197
+
198
+ 外加 `single`(单色)、`transparent`(透明)、以及任意 `#hex` 值:
199
+
200
+ ```python
201
+ code_generator(code, 'python', output='a.png', background='#1d976c')
202
+ ```
203
+
204
+ ### 完整示例
205
+
206
+ ```python
207
+ from kk_codeimg import code_generator
208
+
209
+ code = '''def greet(name: str) -> str:
210
+ # 生成问候语
211
+ return f"Hello, {name}!"
212
+ '''
213
+
214
+ # 默认风格
215
+ code_generator(code, 'python', output='out.png')
216
+
217
+ # 换主题与背景
218
+ code_generator(code, 'python', output='dracula.png',
219
+ theme='dracula', background='ocean')
220
+
221
+ # 带窗口标题
222
+ code_generator(code, 'python', output='titled.png', title='greet.py')
223
+
224
+ # 浅色主题 + 无行号
225
+ code_generator(code, 'python', output='light.png',
226
+ theme='github-light', background='leaf', line_numbers=False)
227
+
228
+ # 不落盘,直接拿 Image 做后处理
229
+ img = code_generator(code, 'python', font_size=18)
230
+ ```
231
+
232
+ ### 设计说明
233
+
234
+ **对比度是算出来的,不是看出来的。** 早期直接采用现成配色,实测发现一批槽位
235
+ 达不到 WCAG AA 标准(4.5:1),实际观感问题例如:
236
+
237
+ - 某浅色主题的 `number` 仅 **1.85:1** —— 白底上几乎看不见
238
+ - 某深色主题的 `comment` 仅 **2.25:1** —— 注释难以辨认
239
+
240
+ 修正方式是**保持色相与饱和度、只调整明度**,直到达到 4.5:1,观感不跑偏。
241
+ 现 12 套主题全部达标(最差 4.50:1,最好 6.74:1)。`kk_codeimg/contrast.py`
242
+ 提供 WCAG 计算与评估工具,`test_all_themes_meet_wcag_aa_on_own_bg` 做回归守卫。
243
+
244
+ 原主题未定义的槽位(如 Xcode 系列的数字/运算符)按其编辑器默认配色补齐,
245
+ 并配 `_FALLBACK` 语义回退链,避免整片 token 退化成前景色。
246
+
247
+ **透明模式下的可读性**:浅色主题(深色文字)若抽掉底色直接压到饱和背景上,
248
+ 文字会糊掉——实测某组合仅 **1.24:1**。因此透明模式下浅色主题会自动垫一层
249
+ 不透明底色(磨砂效果,背景氛围仍在)。深色主题文字本身够亮,保持全透明。
250
+ 手动控制用 `scrim_alpha`(0~1)。
251
+
252
+ **中英文混排**:等宽字体普遍无中文字形,`_TextPen` 会按字符切分,
253
+ CJK 交给系统 CJK 字体(微软雅黑 / Noto Sans SC 等)绘制并按全角宽度计算 advance。
254
+
255
+ **字体**:默认按 `Cascadia Mono`(SIL OFL 1.1)→ `JetBrains Mono`(OFL 1.1)→
256
+ `DejaVu Sans Mono`(Bitstream Vera)顺序探测,**均为免费商用字体**。
257
+
258
+ **圆角**:编辑器圆角通过 alpha 遮罩真实生效(不是只改描边),可用
259
+ `border_radius` 自由调整,`0` 即直角。
260
+
261
+ ### 测试
262
+
263
+ ```bash
264
+ python -m pytest scripts/test_kk_codeimg.py -q
265
+ ```
266
+
267
+ 47 项测试,覆盖缩进保留、中文出字、12 主题 / 12 背景 / 16 风格 / 10 别名渲染、
268
+ **WCAG 对比度守卫**、透明模式垫底、圆角生效、槽位退化防护、参数覆盖优先级、
269
+ 窗口标题(中文/截断/无控制点/透明度/字号独立/字体统一/居中)、多语言、异常输入等。
270
+
271
+ ### 已知限制
272
+
273
+ - 超长单行不自动换行(长代码建议调大 `font_size` 或分屏)
274
+ - 粗体/斜体未实现,部分主题原设计里关键字是加粗的
275
+ - 透明模式 + 浅色主题时,背景渐变基本透不出来(实测需 100% 不透明才达 AA),
276
+ 想要通透感建议用深色主题配 `style='frosted'`
277
+
278
+ ### 许可证
279
+
280
+ [MIT](LICENSE) © 2026 Python卡皮巴拉
281
+
282
+ ---
@@ -0,0 +1,291 @@
1
+ English | [简体中文](docs/README.zh-CN.md)
2
+
3
+ # kk_codeimg
4
+
5
+ **🌟【Python卡皮巴拉】—— 你的Python修炼秘籍,代码界的"神兽"驾到!🌟**
6
+
7
+ **🌟 [Python Capybara] — Your Python cultivation manual; the coding realm's "mythical beast" has arrived! 🌟**
8
+
9
+ [PyPI](https://pypi.org/project/kk_codeimg/) · [MIT License](LICENSE) · [Python 3.8+](https://pypi.org/project/kk_codeimg/)
10
+
11
+
12
+ ---
13
+
14
+ Turn your code into beautiful, share-ready code images.
15
+ Pure Python (`Pillow` + `Pygments`) — **fully offline**: no browser, no headless
16
+ Chrome, no network calls.
17
+
18
+ ## English
19
+
20
+ ### Features
21
+
22
+ - 🎨 **12 themes** — every one verified against WCAG AA contrast, not "close enough"
23
+ - 🖼️ **16 preset styles** — switch an entire look with a single argument
24
+ - 🏷️ **Window title** — file name in the title bar, CJK-ready, font always
25
+ matches the code
26
+ - 🇨🇳 **Mixed CJK + Latin** — monospace fonts lack Chinese glyphs? We fall back
27
+ to a system CJK font automatically
28
+ - 🔒 **Accessible by default** — contrast ratios are *computed*, so comments
29
+ are never too faint to read
30
+ - 🐍 **100% offline** — no network requests, so it works in CI
31
+ - 🪶 **Light dependencies** — just `Pillow` + `Pygments`
32
+ - 🧩 **Extensible** — adding a theme means adding one dict of colours
33
+
34
+ ### Installation
35
+
36
+ ```bash
37
+ pip install kk_codeimg
38
+ ```
39
+
40
+ ### Quick start
41
+
42
+ ```python
43
+ from kk_codeimg import code_generator
44
+
45
+ code_generator(code, 'python', output='out.png')
46
+ ```
47
+
48
+ Without `output`, a `PIL.Image.Image` is returned so you can post-process it yourself.
49
+
50
+ ### Preview
51
+
52
+ **One Dark theme + gradient (default `default`)**
53
+
54
+ ![One Dark theme + gradient (default `default`)](docs/preview-dark.png)
55
+
56
+ **GitHub Light theme (`github`)**
57
+
58
+ ![GitHub Light theme (`github`)](docs/preview-light.png)
59
+
60
+ **`neon`: large radius + Cool Glow**
61
+
62
+ ![`neon`: large radius + Cool Glow](docs/preview-neon.png)
63
+
64
+ **`ocean`: cool and restrained**
65
+
66
+ ![`ocean`: cool and restrained](docs/preview-ocean.png)
67
+
68
+ **`sticker`: exaggerated radius**
69
+
70
+ ![`sticker`: exaggerated radius](docs/preview-sticker.png)
71
+
72
+ **`grid`: square grid paper**
73
+
74
+ ![`grid`: square grid paper](docs/preview-grid.png)
75
+
76
+ Generate the full sample set:/n/n```bash
77
+ python scripts/make_samples.py
78
+ ```
79
+
80
+ Writes to `out/`.
81
+
82
+ ### Preset styles
83
+
84
+ Don't want to memorise parameters? Use `style` to apply a whole look at once:
85
+
86
+ ```python
87
+ code_generator(code, 'python', style='tokyo', output='out.png')
88
+ ```
89
+
90
+ | Style | Description |
91
+ |---|---|
92
+ | `default` | Dark classic: One Dark theme with a soft gradient |
93
+ | `carbon` | Minimal solid background, no window controls, small radius |
94
+ | `dracula` | Dracula purple tones with an aurora gradient |
95
+ | `tokyo` | Tokyo Night on a deep-ocean gradient |
96
+ | `github` | GitHub Light on a soft gradient (opaque, most readable) |
97
+ | `light-frosted` | Light frosted glass: keeps the ambience, adds a white base for legibility |
98
+ | `frosted` | Dark frosted glass: large radius, background softly shows through |
99
+ | `minimal` | Minimal: no line numbers, no window controls, generous padding |
100
+ | `neon` | Neon: Cool Glow theme with a large corner radius |
101
+ | `share` | Social sharing: large font, large radius, wide padding |
102
+ | `print` | Print-friendly: black on white, no distractions |
103
+ | `ocean` | Deep ocean: cool tones, restrained radius |
104
+ | `sunset` | Sunset: warm and bright, good for long snippets |
105
+ | `forest` | Forest: low-saturation greens, easy on the eyes |
106
+ | `grid` | Grid paper: square corners, outlined controls, typographic feel |
107
+ | `sticker` | Sticker: light background, exaggerated radius, compact |
108
+
109
+ Handy **aliases** so you don't have to memorise exact names:
110
+ `dark` / `light` / `plain` / `classic` / `night` / `big` / `rounded` / `sharp` / `matrix` / `frost`
111
+
112
+ ```python
113
+ code_generator(code, 'python', style='dark') # same as default
114
+ code_generator(code, 'python', style='plain') # same as minimal
115
+ ```
116
+
117
+ Explicit arguments always **override** `style`:
118
+
119
+ ```python
120
+ code_generator(code, 'python', style='minimal', theme='dracula')
121
+ ```
122
+
123
+ ### Parameters
124
+
125
+ | Parameter | Default | Description |
126
+ |---|---|---|
127
+ | `code` | required | Source code text |
128
+ | `language` | `'python'` | Pygments lexer name: `python` / `javascript` / `sql` / `java` / `go`… |
129
+ | `output` | `None` | Path to save the PNG; `None` returns the Image instead |
130
+ | `style` | `None` | Preset style name (see table above) |
131
+ | `theme` | follows `style` | One of 12 themes (see below) |
132
+ | `background` | follows `style` | Gradient name / `single` / `transparent` / any `#hex` |
133
+ | `font` | `None` | Font name or `.ttf` path; auto-detected when `None` |
134
+ | `font_size` | `15` | Font size (logical pixels) |
135
+ | `border_radius` | `9` | Editor corner radius |
136
+ | `window_controls` | `'color'` | `color` / `gray` / `gray-light` / `outline` / `none` |
137
+ | `line_height` | `1.45` | Line height multiplier |
138
+ | `padding` | `64` | Outer margin |
139
+ | `line_numbers` | `True` | Show line numbers |
140
+ | `transparent_editor` | `False` | Make the editor area transparent |
141
+ | `scrim_alpha` | `None` | Base opacity (`0`–`1`) in transparent mode; auto-decided from theme brightness when `None` |
142
+ | `title` | `None` | Window title, centred in the title bar; CJK supported |
143
+ | `title_alpha` | `0.72` | Title opacity — lower it to make the title recede |
144
+ | `title_size` | `None` | Title font size. `None`/`'same'` = same as code; pass a number to set it independently |
145
+ | `scale` | `2` | Render scale; `2` is good for sharing |
146
+
147
+ When `output` is given, a `RenderResult` is returned with `.image`, `.path`,
148
+ `.editor_box` and `.code_box`.
149
+
150
+ ### Window title
151
+
152
+ `title` renders in the centre of the title bar:
153
+
154
+ ```python
155
+ code_generator(code, 'python', title='point.py', output='out.png')
156
+ code_generator(code, 'python', title='几何工具 · 坐标计算', output='out.png') # CJK OK
157
+ ```
158
+
159
+ **The font always matches the code** — only the size may differ:
160
+
161
+ ```python
162
+ # Same font, same size (default)
163
+ code_generator(code, 'python', title='main.py')
164
+
165
+ # Smaller title
166
+ code_generator(code, 'python', title='main.py', font_size=20, title_size=13)
167
+
168
+ # Change the font — the title follows automatically
169
+ code_generator(code, 'python', title='main.py', font='consolas')
170
+ ```
171
+
172
+ Details:
173
+
174
+ - Font unification is a hard constraint — whatever the code uses, the title uses
175
+ the exact same font file (the very same font object when sizes match); the CJK
176
+ fallback is unified too
177
+ - A `title_size` larger than the title bar can hold (40 px bar, ~48.6 px limit)
178
+ is **clamped automatically**, so the title never covers the code;
179
+ `0` / negative / non-numeric values raise `ValueError`
180
+ - Overlong titles are truncated with an ellipsis and never overflow
181
+ - The title still shows when `window_controls='none'`
182
+ - Colours come from the theme's **foreground**, not the gutter colour — the
183
+ gutter measures only 2.76:1 on some themes, while every foreground is ≥ 6.10:1
184
+ - The title is centred across the **entire editor width**
185
+
186
+ ### Themes (12)
187
+
188
+ `one-dark` (default), `dracula`, `vscode`, `ayu-light`, `github-light`,
189
+ `github-dark`, `tokyo-night`, `xcode-dark`, `xcode-light`, `amy`, `aura`,
190
+ `cool-glow`
191
+
192
+ ```python
193
+ code_generator(code, 'python', output='a.png', theme='dracula', background='aurora')
194
+ ```
195
+
196
+ ### Backgrounds
197
+
198
+ 10 gradients: `mystic` (default), `aruba`, `jungle`, `tropical`, `aurora`,
199
+ `candy`, `peach`, `bananas`, `leaf`, `ocean`
200
+
201
+ Plus `single` (solid), `transparent`, and any `#hex` value:
202
+
203
+ ```python
204
+ code_generator(code, 'python', output='a.png', background='#1d976c')
205
+ ```
206
+
207
+ ### Full example
208
+
209
+ ```python
210
+ from kk_codeimg import code_generator
211
+
212
+ code = '''def greet(name: str) -> str:
213
+ # say hello
214
+ return f"Hello, {name}!"
215
+ '''
216
+
217
+ # Default look
218
+ code_generator(code, 'python', output='out.png')
219
+
220
+ # Different theme and background
221
+ code_generator(code, 'python', output='dracula.png',
222
+ theme='dracula', background='ocean')
223
+
224
+ # With a window title
225
+ code_generator(code, 'python', output='titled.png', title='greet.py')
226
+
227
+ # Light theme without line numbers
228
+ code_generator(code, 'python', output='light.png',
229
+ theme='github-light', background='leaf', line_numbers=False)
230
+
231
+ # No file written — grab the Image and post-process it
232
+ img = code_generator(code, 'python', font_size=18)
233
+ ```
234
+
235
+ ### Design notes
236
+
237
+ **Contrast is computed, not eyeballed.** Early on we shipped off-the-shelf
238
+ palettes, then measured them and found a number of slots below WCAG AA (4.5:1):
239
+
240
+ - one light theme's `number` measured only **1.85:1** — effectively invisible
241
+ - one dark theme's `comment` measured only **2.25:1** — hard to read
242
+
243
+ The fix keeps **hue and saturation, adjusting only lightness** until 4.5:1 is
244
+ reached, so each palette still looks like itself. All 12 themes now pass (worst
245
+ 4.50:1, best 6.74:1). `kk_codeimg/contrast.py` provides the WCAG maths and
246
+ `test_all_themes_meet_wcag_aa_on_own_bg` guards against regressions.
247
+
248
+ Slots the original themes never defined (e.g. numbers and operators in the Xcode
249
+ family) are filled in from those editors' own defaults, plus a `_FALLBACK`
250
+ semantic chain so whole regions never collapse to the foreground colour.
251
+
252
+ **Readability in transparent mode**: a light theme (dark text) loses its
253
+ background and lands directly on a saturated gradient — one combination measured
254
+ only **1.24:1**. So in transparent mode light themes automatically get an opaque
255
+ base (a frosted effect that keeps the ambience). Dark themes stay fully
256
+ transparent. Override with `scrim_alpha` (0–1).
257
+
258
+ **Mixed CJK + Latin**: monospace fonts rarely carry Chinese glyphs, so
259
+ `_TextPen` splits runs per character and hands CJK to a system CJK font
260
+ (Microsoft YaHei / Noto Sans SC, …), advancing by full-width metrics.
261
+
262
+ **Fonts**: probed in the order `Cascadia Mono` (SIL OFL 1.1) → `JetBrains Mono`
263
+ (OFL 1.1) → `DejaVu Sans Mono` (Bitstream Vera) — **all free for commercial use**.
264
+
265
+ **Corner radius** is applied through a real alpha mask (not just the outline),
266
+ so `border_radius=0` gives you genuinely square corners.
267
+
268
+ ### Tests
269
+
270
+ ```bash
271
+ python -m pytest scripts/test_kk_codeimg.py -q
272
+ ```
273
+
274
+ 47 tests covering indentation preservation, CJK rendering, all 12 themes /
275
+ 12 backgrounds / 16 styles, **WCAG contrast guards**, transparent-mode base
276
+ fill, corner radius, slot-collapse prevention, parameter override precedence,
277
+ window titles (CJK / truncation / no controls / opacity / independent size /
278
+ unified font / centring), multiple languages and invalid input.
279
+
280
+ ### Known limitations
281
+
282
+ - Very long single lines are not wrapped (try a larger `font_size` or split the
283
+ snippet)
284
+ - Bold/italic are not implemented; some original themes bold their keywords
285
+ - In transparent mode a light theme hides the gradient almost completely
286
+ (measured: 100% opacity is required to reach AA). For a translucent look,
287
+ use a dark theme with `style='frosted'`
288
+
289
+ ### License
290
+
291
+ [MIT](LICENSE) © 2026 Python Capybara