kymostudio-core 0.3.3__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,4 @@
1
+ /target
2
+ /pkg
3
+ /dist
4
+ *.whl
@@ -0,0 +1,712 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 3
4
+
5
+ [[package]]
6
+ name = "adler2"
7
+ version = "2.0.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
10
+
11
+ [[package]]
12
+ name = "arrayref"
13
+ version = "0.3.9"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
16
+
17
+ [[package]]
18
+ name = "arrayvec"
19
+ version = "0.7.6"
20
+ source = "registry+https://github.com/rust-lang/crates.io-index"
21
+ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
22
+
23
+ [[package]]
24
+ name = "autocfg"
25
+ version = "1.5.1"
26
+ source = "registry+https://github.com/rust-lang/crates.io-index"
27
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
28
+
29
+ [[package]]
30
+ name = "base64"
31
+ version = "0.22.1"
32
+ source = "registry+https://github.com/rust-lang/crates.io-index"
33
+ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
34
+
35
+ [[package]]
36
+ name = "bitflags"
37
+ version = "2.13.0"
38
+ source = "registry+https://github.com/rust-lang/crates.io-index"
39
+ checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
40
+
41
+ [[package]]
42
+ name = "bumpalo"
43
+ version = "3.20.3"
44
+ source = "registry+https://github.com/rust-lang/crates.io-index"
45
+ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
46
+
47
+ [[package]]
48
+ name = "bytemuck"
49
+ version = "1.25.0"
50
+ source = "registry+https://github.com/rust-lang/crates.io-index"
51
+ checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
52
+
53
+ [[package]]
54
+ name = "byteorder-lite"
55
+ version = "0.1.0"
56
+ source = "registry+https://github.com/rust-lang/crates.io-index"
57
+ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
58
+
59
+ [[package]]
60
+ name = "cfg-if"
61
+ version = "1.0.4"
62
+ source = "registry+https://github.com/rust-lang/crates.io-index"
63
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
64
+
65
+ [[package]]
66
+ name = "color_quant"
67
+ version = "1.1.0"
68
+ source = "registry+https://github.com/rust-lang/crates.io-index"
69
+ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
70
+
71
+ [[package]]
72
+ name = "core_maths"
73
+ version = "0.1.1"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30"
76
+ dependencies = [
77
+ "libm",
78
+ ]
79
+
80
+ [[package]]
81
+ name = "crc32fast"
82
+ version = "1.5.0"
83
+ source = "registry+https://github.com/rust-lang/crates.io-index"
84
+ checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
85
+ dependencies = [
86
+ "cfg-if",
87
+ ]
88
+
89
+ [[package]]
90
+ name = "data-url"
91
+ version = "0.3.2"
92
+ source = "registry+https://github.com/rust-lang/crates.io-index"
93
+ checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
94
+
95
+ [[package]]
96
+ name = "euclid"
97
+ version = "0.22.14"
98
+ source = "registry+https://github.com/rust-lang/crates.io-index"
99
+ checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06"
100
+ dependencies = [
101
+ "num-traits",
102
+ ]
103
+
104
+ [[package]]
105
+ name = "fdeflate"
106
+ version = "0.3.7"
107
+ source = "registry+https://github.com/rust-lang/crates.io-index"
108
+ checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
109
+ dependencies = [
110
+ "simd-adler32",
111
+ ]
112
+
113
+ [[package]]
114
+ name = "flate2"
115
+ version = "1.1.9"
116
+ source = "registry+https://github.com/rust-lang/crates.io-index"
117
+ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
118
+ dependencies = [
119
+ "crc32fast",
120
+ "miniz_oxide",
121
+ ]
122
+
123
+ [[package]]
124
+ name = "float-cmp"
125
+ version = "0.9.0"
126
+ source = "registry+https://github.com/rust-lang/crates.io-index"
127
+ checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
128
+
129
+ [[package]]
130
+ name = "fontconfig-parser"
131
+ version = "0.5.8"
132
+ source = "registry+https://github.com/rust-lang/crates.io-index"
133
+ checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
134
+ dependencies = [
135
+ "roxmltree 0.20.0",
136
+ ]
137
+
138
+ [[package]]
139
+ name = "fontdb"
140
+ version = "0.23.0"
141
+ source = "registry+https://github.com/rust-lang/crates.io-index"
142
+ checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905"
143
+ dependencies = [
144
+ "fontconfig-parser",
145
+ "log",
146
+ "memmap2",
147
+ "slotmap",
148
+ "tinyvec",
149
+ "ttf-parser",
150
+ ]
151
+
152
+ [[package]]
153
+ name = "gif"
154
+ version = "0.14.2"
155
+ source = "registry+https://github.com/rust-lang/crates.io-index"
156
+ checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159"
157
+ dependencies = [
158
+ "color_quant",
159
+ "weezl",
160
+ ]
161
+
162
+ [[package]]
163
+ name = "heck"
164
+ version = "0.5.0"
165
+ source = "registry+https://github.com/rust-lang/crates.io-index"
166
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
167
+
168
+ [[package]]
169
+ name = "image-webp"
170
+ version = "0.2.4"
171
+ source = "registry+https://github.com/rust-lang/crates.io-index"
172
+ checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
173
+ dependencies = [
174
+ "byteorder-lite",
175
+ "quick-error",
176
+ ]
177
+
178
+ [[package]]
179
+ name = "imagesize"
180
+ version = "0.14.0"
181
+ source = "registry+https://github.com/rust-lang/crates.io-index"
182
+ checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c"
183
+
184
+ [[package]]
185
+ name = "kurbo"
186
+ version = "0.13.1"
187
+ source = "registry+https://github.com/rust-lang/crates.io-index"
188
+ checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2"
189
+ dependencies = [
190
+ "arrayvec",
191
+ "euclid",
192
+ "polycool",
193
+ "smallvec",
194
+ ]
195
+
196
+ [[package]]
197
+ name = "kymostudio-core"
198
+ version = "0.3.5"
199
+ dependencies = [
200
+ "pyo3",
201
+ "resvg",
202
+ "wasm-bindgen",
203
+ ]
204
+
205
+ [[package]]
206
+ name = "libc"
207
+ version = "0.2.186"
208
+ source = "registry+https://github.com/rust-lang/crates.io-index"
209
+ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
210
+
211
+ [[package]]
212
+ name = "libm"
213
+ version = "0.2.16"
214
+ source = "registry+https://github.com/rust-lang/crates.io-index"
215
+ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
216
+
217
+ [[package]]
218
+ name = "log"
219
+ version = "0.4.32"
220
+ source = "registry+https://github.com/rust-lang/crates.io-index"
221
+ checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
222
+
223
+ [[package]]
224
+ name = "memchr"
225
+ version = "2.8.1"
226
+ source = "registry+https://github.com/rust-lang/crates.io-index"
227
+ checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
228
+
229
+ [[package]]
230
+ name = "memmap2"
231
+ version = "0.9.10"
232
+ source = "registry+https://github.com/rust-lang/crates.io-index"
233
+ checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
234
+ dependencies = [
235
+ "libc",
236
+ ]
237
+
238
+ [[package]]
239
+ name = "miniz_oxide"
240
+ version = "0.8.9"
241
+ source = "registry+https://github.com/rust-lang/crates.io-index"
242
+ checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
243
+ dependencies = [
244
+ "adler2",
245
+ "simd-adler32",
246
+ ]
247
+
248
+ [[package]]
249
+ name = "num-traits"
250
+ version = "0.2.19"
251
+ source = "registry+https://github.com/rust-lang/crates.io-index"
252
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
253
+ dependencies = [
254
+ "autocfg",
255
+ ]
256
+
257
+ [[package]]
258
+ name = "once_cell"
259
+ version = "1.21.4"
260
+ source = "registry+https://github.com/rust-lang/crates.io-index"
261
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
262
+
263
+ [[package]]
264
+ name = "pico-args"
265
+ version = "0.5.0"
266
+ source = "registry+https://github.com/rust-lang/crates.io-index"
267
+ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
268
+
269
+ [[package]]
270
+ name = "png"
271
+ version = "0.18.1"
272
+ source = "registry+https://github.com/rust-lang/crates.io-index"
273
+ checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
274
+ dependencies = [
275
+ "bitflags",
276
+ "crc32fast",
277
+ "fdeflate",
278
+ "flate2",
279
+ "miniz_oxide",
280
+ ]
281
+
282
+ [[package]]
283
+ name = "polycool"
284
+ version = "0.4.0"
285
+ source = "registry+https://github.com/rust-lang/crates.io-index"
286
+ checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6"
287
+ dependencies = [
288
+ "arrayvec",
289
+ ]
290
+
291
+ [[package]]
292
+ name = "portable-atomic"
293
+ version = "1.13.1"
294
+ source = "registry+https://github.com/rust-lang/crates.io-index"
295
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
296
+
297
+ [[package]]
298
+ name = "proc-macro2"
299
+ version = "1.0.106"
300
+ source = "registry+https://github.com/rust-lang/crates.io-index"
301
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
302
+ dependencies = [
303
+ "unicode-ident",
304
+ ]
305
+
306
+ [[package]]
307
+ name = "pyo3"
308
+ version = "0.28.3"
309
+ source = "registry+https://github.com/rust-lang/crates.io-index"
310
+ checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12"
311
+ dependencies = [
312
+ "libc",
313
+ "once_cell",
314
+ "portable-atomic",
315
+ "pyo3-build-config",
316
+ "pyo3-ffi",
317
+ "pyo3-macros",
318
+ ]
319
+
320
+ [[package]]
321
+ name = "pyo3-build-config"
322
+ version = "0.28.3"
323
+ source = "registry+https://github.com/rust-lang/crates.io-index"
324
+ checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e"
325
+ dependencies = [
326
+ "target-lexicon",
327
+ ]
328
+
329
+ [[package]]
330
+ name = "pyo3-ffi"
331
+ version = "0.28.3"
332
+ source = "registry+https://github.com/rust-lang/crates.io-index"
333
+ checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e"
334
+ dependencies = [
335
+ "libc",
336
+ "pyo3-build-config",
337
+ ]
338
+
339
+ [[package]]
340
+ name = "pyo3-macros"
341
+ version = "0.28.3"
342
+ source = "registry+https://github.com/rust-lang/crates.io-index"
343
+ checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813"
344
+ dependencies = [
345
+ "proc-macro2",
346
+ "pyo3-macros-backend",
347
+ "quote",
348
+ "syn",
349
+ ]
350
+
351
+ [[package]]
352
+ name = "pyo3-macros-backend"
353
+ version = "0.28.3"
354
+ source = "registry+https://github.com/rust-lang/crates.io-index"
355
+ checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb"
356
+ dependencies = [
357
+ "heck",
358
+ "proc-macro2",
359
+ "pyo3-build-config",
360
+ "quote",
361
+ "syn",
362
+ ]
363
+
364
+ [[package]]
365
+ name = "quick-error"
366
+ version = "2.0.1"
367
+ source = "registry+https://github.com/rust-lang/crates.io-index"
368
+ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
369
+
370
+ [[package]]
371
+ name = "quote"
372
+ version = "1.0.45"
373
+ source = "registry+https://github.com/rust-lang/crates.io-index"
374
+ checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
375
+ dependencies = [
376
+ "proc-macro2",
377
+ ]
378
+
379
+ [[package]]
380
+ name = "resvg"
381
+ version = "0.47.0"
382
+ source = "registry+https://github.com/rust-lang/crates.io-index"
383
+ checksum = "9be183ad6a216aa96f33e4c8033b0988b8b3ea6fd2359d19af5bac4643fd8e81"
384
+ dependencies = [
385
+ "gif",
386
+ "image-webp",
387
+ "log",
388
+ "pico-args",
389
+ "rgb",
390
+ "svgtypes",
391
+ "tiny-skia",
392
+ "usvg",
393
+ "zune-jpeg",
394
+ ]
395
+
396
+ [[package]]
397
+ name = "rgb"
398
+ version = "0.8.53"
399
+ source = "registry+https://github.com/rust-lang/crates.io-index"
400
+ checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
401
+ dependencies = [
402
+ "bytemuck",
403
+ ]
404
+
405
+ [[package]]
406
+ name = "roxmltree"
407
+ version = "0.20.0"
408
+ source = "registry+https://github.com/rust-lang/crates.io-index"
409
+ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
410
+
411
+ [[package]]
412
+ name = "roxmltree"
413
+ version = "0.21.1"
414
+ source = "registry+https://github.com/rust-lang/crates.io-index"
415
+ checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb"
416
+ dependencies = [
417
+ "memchr",
418
+ ]
419
+
420
+ [[package]]
421
+ name = "rustversion"
422
+ version = "1.0.22"
423
+ source = "registry+https://github.com/rust-lang/crates.io-index"
424
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
425
+
426
+ [[package]]
427
+ name = "rustybuzz"
428
+ version = "0.20.1"
429
+ source = "registry+https://github.com/rust-lang/crates.io-index"
430
+ checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702"
431
+ dependencies = [
432
+ "bitflags",
433
+ "bytemuck",
434
+ "core_maths",
435
+ "log",
436
+ "smallvec",
437
+ "ttf-parser",
438
+ "unicode-bidi-mirroring",
439
+ "unicode-ccc",
440
+ "unicode-properties",
441
+ "unicode-script",
442
+ ]
443
+
444
+ [[package]]
445
+ name = "simd-adler32"
446
+ version = "0.3.9"
447
+ source = "registry+https://github.com/rust-lang/crates.io-index"
448
+ checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
449
+
450
+ [[package]]
451
+ name = "simplecss"
452
+ version = "0.2.2"
453
+ source = "registry+https://github.com/rust-lang/crates.io-index"
454
+ checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c"
455
+ dependencies = [
456
+ "log",
457
+ ]
458
+
459
+ [[package]]
460
+ name = "siphasher"
461
+ version = "1.0.3"
462
+ source = "registry+https://github.com/rust-lang/crates.io-index"
463
+ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
464
+
465
+ [[package]]
466
+ name = "slotmap"
467
+ version = "1.1.1"
468
+ source = "registry+https://github.com/rust-lang/crates.io-index"
469
+ checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038"
470
+ dependencies = [
471
+ "version_check",
472
+ ]
473
+
474
+ [[package]]
475
+ name = "smallvec"
476
+ version = "1.15.1"
477
+ source = "registry+https://github.com/rust-lang/crates.io-index"
478
+ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
479
+
480
+ [[package]]
481
+ name = "strict-num"
482
+ version = "0.1.1"
483
+ source = "registry+https://github.com/rust-lang/crates.io-index"
484
+ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
485
+ dependencies = [
486
+ "float-cmp",
487
+ ]
488
+
489
+ [[package]]
490
+ name = "svgtypes"
491
+ version = "0.16.1"
492
+ source = "registry+https://github.com/rust-lang/crates.io-index"
493
+ checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d"
494
+ dependencies = [
495
+ "kurbo",
496
+ "siphasher",
497
+ ]
498
+
499
+ [[package]]
500
+ name = "syn"
501
+ version = "2.0.117"
502
+ source = "registry+https://github.com/rust-lang/crates.io-index"
503
+ checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
504
+ dependencies = [
505
+ "proc-macro2",
506
+ "quote",
507
+ "unicode-ident",
508
+ ]
509
+
510
+ [[package]]
511
+ name = "target-lexicon"
512
+ version = "0.13.5"
513
+ source = "registry+https://github.com/rust-lang/crates.io-index"
514
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
515
+
516
+ [[package]]
517
+ name = "tiny-skia"
518
+ version = "0.12.0"
519
+ source = "registry+https://github.com/rust-lang/crates.io-index"
520
+ checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea"
521
+ dependencies = [
522
+ "arrayref",
523
+ "arrayvec",
524
+ "bytemuck",
525
+ "cfg-if",
526
+ "log",
527
+ "png",
528
+ "tiny-skia-path",
529
+ ]
530
+
531
+ [[package]]
532
+ name = "tiny-skia-path"
533
+ version = "0.12.0"
534
+ source = "registry+https://github.com/rust-lang/crates.io-index"
535
+ checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9"
536
+ dependencies = [
537
+ "arrayref",
538
+ "bytemuck",
539
+ "strict-num",
540
+ ]
541
+
542
+ [[package]]
543
+ name = "tinyvec"
544
+ version = "1.11.0"
545
+ source = "registry+https://github.com/rust-lang/crates.io-index"
546
+ checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
547
+ dependencies = [
548
+ "tinyvec_macros",
549
+ ]
550
+
551
+ [[package]]
552
+ name = "tinyvec_macros"
553
+ version = "0.1.1"
554
+ source = "registry+https://github.com/rust-lang/crates.io-index"
555
+ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
556
+
557
+ [[package]]
558
+ name = "ttf-parser"
559
+ version = "0.25.1"
560
+ source = "registry+https://github.com/rust-lang/crates.io-index"
561
+ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
562
+ dependencies = [
563
+ "core_maths",
564
+ ]
565
+
566
+ [[package]]
567
+ name = "unicode-bidi"
568
+ version = "0.3.18"
569
+ source = "registry+https://github.com/rust-lang/crates.io-index"
570
+ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
571
+
572
+ [[package]]
573
+ name = "unicode-bidi-mirroring"
574
+ version = "0.4.0"
575
+ source = "registry+https://github.com/rust-lang/crates.io-index"
576
+ checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe"
577
+
578
+ [[package]]
579
+ name = "unicode-ccc"
580
+ version = "0.4.0"
581
+ source = "registry+https://github.com/rust-lang/crates.io-index"
582
+ checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
583
+
584
+ [[package]]
585
+ name = "unicode-ident"
586
+ version = "1.0.24"
587
+ source = "registry+https://github.com/rust-lang/crates.io-index"
588
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
589
+
590
+ [[package]]
591
+ name = "unicode-properties"
592
+ version = "0.1.4"
593
+ source = "registry+https://github.com/rust-lang/crates.io-index"
594
+ checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
595
+
596
+ [[package]]
597
+ name = "unicode-script"
598
+ version = "0.5.8"
599
+ source = "registry+https://github.com/rust-lang/crates.io-index"
600
+ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee"
601
+
602
+ [[package]]
603
+ name = "unicode-vo"
604
+ version = "0.1.0"
605
+ source = "registry+https://github.com/rust-lang/crates.io-index"
606
+ checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
607
+
608
+ [[package]]
609
+ name = "usvg"
610
+ version = "0.47.0"
611
+ source = "registry+https://github.com/rust-lang/crates.io-index"
612
+ checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de"
613
+ dependencies = [
614
+ "base64",
615
+ "data-url",
616
+ "flate2",
617
+ "fontdb",
618
+ "imagesize",
619
+ "kurbo",
620
+ "log",
621
+ "pico-args",
622
+ "roxmltree 0.21.1",
623
+ "rustybuzz",
624
+ "simplecss",
625
+ "siphasher",
626
+ "strict-num",
627
+ "svgtypes",
628
+ "tiny-skia-path",
629
+ "ttf-parser",
630
+ "unicode-bidi",
631
+ "unicode-script",
632
+ "unicode-vo",
633
+ "xmlwriter",
634
+ ]
635
+
636
+ [[package]]
637
+ name = "version_check"
638
+ version = "0.9.5"
639
+ source = "registry+https://github.com/rust-lang/crates.io-index"
640
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
641
+
642
+ [[package]]
643
+ name = "wasm-bindgen"
644
+ version = "0.2.122"
645
+ source = "registry+https://github.com/rust-lang/crates.io-index"
646
+ checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
647
+ dependencies = [
648
+ "cfg-if",
649
+ "once_cell",
650
+ "rustversion",
651
+ "wasm-bindgen-macro",
652
+ "wasm-bindgen-shared",
653
+ ]
654
+
655
+ [[package]]
656
+ name = "wasm-bindgen-macro"
657
+ version = "0.2.122"
658
+ source = "registry+https://github.com/rust-lang/crates.io-index"
659
+ checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
660
+ dependencies = [
661
+ "quote",
662
+ "wasm-bindgen-macro-support",
663
+ ]
664
+
665
+ [[package]]
666
+ name = "wasm-bindgen-macro-support"
667
+ version = "0.2.122"
668
+ source = "registry+https://github.com/rust-lang/crates.io-index"
669
+ checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
670
+ dependencies = [
671
+ "bumpalo",
672
+ "proc-macro2",
673
+ "quote",
674
+ "syn",
675
+ "wasm-bindgen-shared",
676
+ ]
677
+
678
+ [[package]]
679
+ name = "wasm-bindgen-shared"
680
+ version = "0.2.122"
681
+ source = "registry+https://github.com/rust-lang/crates.io-index"
682
+ checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
683
+ dependencies = [
684
+ "unicode-ident",
685
+ ]
686
+
687
+ [[package]]
688
+ name = "weezl"
689
+ version = "0.1.12"
690
+ source = "registry+https://github.com/rust-lang/crates.io-index"
691
+ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
692
+
693
+ [[package]]
694
+ name = "xmlwriter"
695
+ version = "0.1.0"
696
+ source = "registry+https://github.com/rust-lang/crates.io-index"
697
+ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
698
+
699
+ [[package]]
700
+ name = "zune-core"
701
+ version = "0.5.1"
702
+ source = "registry+https://github.com/rust-lang/crates.io-index"
703
+ checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
704
+
705
+ [[package]]
706
+ name = "zune-jpeg"
707
+ version = "0.5.15"
708
+ source = "registry+https://github.com/rust-lang/crates.io-index"
709
+ checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
710
+ dependencies = [
711
+ "zune-core",
712
+ ]
@@ -0,0 +1,54 @@
1
+ [package]
2
+ name = "kymostudio-core"
3
+ version = "0.3.5"
4
+ edition = "2021"
5
+ rust-version = "1.74"
6
+ description = "Type it. See it appear. Watch it animate."
7
+ license = "Apache-2.0"
8
+ repository = "https://github.com/kymostudio/kymostudio"
9
+ homepage = "https://github.com/kymostudio/kymostudio"
10
+ readme = "README.md"
11
+ keywords = ["svg", "png", "rasterizer", "diagram", "resvg"]
12
+ categories = ["multimedia::images", "command-line-utilities", "wasm"]
13
+
14
+ # rlib -> native CLI + tests; cdylib -> Python (pyo3) and wasm (wasm-bindgen).
15
+ [lib]
16
+ name = "kymostudio_core"
17
+ path = "src/lib.rs"
18
+ crate-type = ["rlib", "cdylib"]
19
+
20
+ # The `kymo` CLI (native only — built under default features).
21
+ [[bin]]
22
+ name = "kymo"
23
+ path = "src/main.rs"
24
+
25
+ [dependencies]
26
+ # Core SVG engine. system-fonts + memmap-fonts pull in fs/mmap (no good on
27
+ # wasm) so they live behind the `system-fonts` feature, OFF for the wasm build.
28
+ resvg = { version = "0.47", default-features = false, features = ["text", "raster-images"] }
29
+
30
+ # Binding deps — each pulled in only by its feature.
31
+ pyo3 = { version = "0.28", features = ["extension-module", "abi3-py310"], optional = true }
32
+ wasm-bindgen = { version = "0.2", optional = true }
33
+
34
+ [features]
35
+ # Native builds (CLI, tests, Python wheel) load system fonts so <text> renders.
36
+ default = ["system-fonts"]
37
+ system-fonts = ["resvg/system-fonts", "resvg/memmap-fonts"]
38
+
39
+ # Python extension module (maturin builds the cdylib with this on).
40
+ python = ["dep:pyo3", "system-fonts"]
41
+
42
+ # wasm (browser + Node) — deliberately NO system-fonts (no fs/mmap on wasm).
43
+ wasm = ["dep:wasm-bindgen"]
44
+
45
+ [profile.release]
46
+ opt-level = 3
47
+ lto = true
48
+ strip = true
49
+
50
+ # wasm-pack post-processing. wasm-opt is disabled for deterministic builds
51
+ # across environments (the prebuilt binary is flaky on some hosts); re-enable
52
+ # once a pinned wasm-opt is wired into CI to shrink the ~2.4 MB module.
53
+ [package.metadata.wasm-pack.profile.release]
54
+ wasm-opt = false
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: kymostudio-core
3
+ Version: 0.3.3
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Topic :: Multimedia :: Graphics
7
+ Summary: Type it. See it appear. Watch it animate.
8
+ Keywords: svg,png,rasterizer,diagram,resvg
9
+ Home-Page: https://github.com/kymostudio/kymostudio
10
+ Author-email: rain1024 <anhv.ict91@gmail.com>
11
+ License-Expression: Apache-2.0
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
14
+ Project-URL: Homepage, https://github.com/kymostudio/kymostudio
15
+ Project-URL: Repository, https://github.com/kymostudio/kymostudio
16
+
17
+ # kymostudio-core (Rust)
18
+
19
+ Pure-Rust SVG → PNG rasterizer core for **kymostudio**, built on
20
+ [`resvg`](https://github.com/linebender/resvg). No browser, no headless Chrome,
21
+ no C/Cairo/Skia system dependencies.
22
+
23
+ One core crate, compiled to **four targets** from a single source via feature
24
+ flags — so the Rust CLI, the Python package, and the JS/browser playground all
25
+ share the exact same resvg engine (`resvg` is **CSS-class-aware**, the reason the
26
+ project avoids cairosvg):
27
+
28
+ | Target | Feature | Build tool | Consumer |
29
+ |--------|---------|-----------|----------|
30
+ | Native lib + `kymo` CLI | `system-fonts` (default) | `cargo` | standalone CLI |
31
+ | Python extension (abi3) | `python` | `maturin` → wheel | `packages/python` |
32
+ | wasm (browser + Node) | `wasm` | `wasm-pack` → pkg | `packages/js`, website playground |
33
+
34
+ `svg_to_png(svg: &[u8], scale: f32) -> Result<Vec<u8>, RenderError>` is the one
35
+ core function; each binding (`src/python.rs`, `src/wasm.rs`) is a thin façade.
36
+
37
+ ## CLI — `kymo`
38
+
39
+ ```bash
40
+ kymo -i in.svg out.png # rasterize at intrinsic size
41
+ kymo -i diagram.svg # output defaults to diagram.png
42
+ kymo -i diagram.svg -s 2 hi.png # 2× resolution
43
+ ```
44
+
45
+ | Flag | Meaning |
46
+ |------|---------|
47
+ | `-i, --input <FILE>` | Input SVG (required) |
48
+ | `-o, --output <FILE>` | Output PNG (or pass it positionally) |
49
+ | `-s, --scale <N>` | Scale factor, `1.0` = intrinsic size (default `1`) |
50
+ | `-h, --help` / `-V, --version` | Help / version |
51
+
52
+ ## Build each target
53
+
54
+ ```bash
55
+ # Native (CLI + lib + tests)
56
+ cargo test
57
+ cargo build --release --bin kymo # -> target/release/kymo
58
+
59
+ # Python wheel (abi3, one wheel for CPython ≥ 3.10)
60
+ maturin build --release --out dist # -> dist/kymostudio_core-*-abi3-*.whl
61
+ # import _kymostudio_core; _kymostudio_core.svg_to_png(svg_bytes, scale)
62
+
63
+ # wasm (browser + Node) — system-fonts OFF (no fs/mmap on wasm)
64
+ wasm-pack build --target web --out-dir pkg --out-name kymostudio_core \
65
+ -- --no-default-features --features wasm
66
+ # import { svgToPng } from './pkg/kymostudio_core.js'
67
+ ```
68
+
69
+ CI builds and smoke-tests all of the above across Linux/macOS/Windows —
70
+ see `.github/workflows/rust.yml`.
71
+
72
+ ## Library use (Rust)
73
+
74
+ ```rust
75
+ let svg = std::fs::read("in.svg")?;
76
+ let png: Vec<u8> = kymostudio_core::svg_to_png(&svg, 1.0)?;
77
+ std::fs::write("out.png", png)?;
78
+ ```
79
+
80
+ The version is kept in **lockstep** with the rest of the monorepo
81
+ (`Cargo.toml` → `version`).
82
+
@@ -0,0 +1,65 @@
1
+ # kymostudio-core (Rust)
2
+
3
+ Pure-Rust SVG → PNG rasterizer core for **kymostudio**, built on
4
+ [`resvg`](https://github.com/linebender/resvg). No browser, no headless Chrome,
5
+ no C/Cairo/Skia system dependencies.
6
+
7
+ One core crate, compiled to **four targets** from a single source via feature
8
+ flags — so the Rust CLI, the Python package, and the JS/browser playground all
9
+ share the exact same resvg engine (`resvg` is **CSS-class-aware**, the reason the
10
+ project avoids cairosvg):
11
+
12
+ | Target | Feature | Build tool | Consumer |
13
+ |--------|---------|-----------|----------|
14
+ | Native lib + `kymo` CLI | `system-fonts` (default) | `cargo` | standalone CLI |
15
+ | Python extension (abi3) | `python` | `maturin` → wheel | `packages/python` |
16
+ | wasm (browser + Node) | `wasm` | `wasm-pack` → pkg | `packages/js`, website playground |
17
+
18
+ `svg_to_png(svg: &[u8], scale: f32) -> Result<Vec<u8>, RenderError>` is the one
19
+ core function; each binding (`src/python.rs`, `src/wasm.rs`) is a thin façade.
20
+
21
+ ## CLI — `kymo`
22
+
23
+ ```bash
24
+ kymo -i in.svg out.png # rasterize at intrinsic size
25
+ kymo -i diagram.svg # output defaults to diagram.png
26
+ kymo -i diagram.svg -s 2 hi.png # 2× resolution
27
+ ```
28
+
29
+ | Flag | Meaning |
30
+ |------|---------|
31
+ | `-i, --input <FILE>` | Input SVG (required) |
32
+ | `-o, --output <FILE>` | Output PNG (or pass it positionally) |
33
+ | `-s, --scale <N>` | Scale factor, `1.0` = intrinsic size (default `1`) |
34
+ | `-h, --help` / `-V, --version` | Help / version |
35
+
36
+ ## Build each target
37
+
38
+ ```bash
39
+ # Native (CLI + lib + tests)
40
+ cargo test
41
+ cargo build --release --bin kymo # -> target/release/kymo
42
+
43
+ # Python wheel (abi3, one wheel for CPython ≥ 3.10)
44
+ maturin build --release --out dist # -> dist/kymostudio_core-*-abi3-*.whl
45
+ # import _kymostudio_core; _kymostudio_core.svg_to_png(svg_bytes, scale)
46
+
47
+ # wasm (browser + Node) — system-fonts OFF (no fs/mmap on wasm)
48
+ wasm-pack build --target web --out-dir pkg --out-name kymostudio_core \
49
+ -- --no-default-features --features wasm
50
+ # import { svgToPng } from './pkg/kymostudio_core.js'
51
+ ```
52
+
53
+ CI builds and smoke-tests all of the above across Linux/macOS/Windows —
54
+ see `.github/workflows/rust.yml`.
55
+
56
+ ## Library use (Rust)
57
+
58
+ ```rust
59
+ let svg = std::fs::read("in.svg")?;
60
+ let png: Vec<u8> = kymostudio_core::svg_to_png(&svg, 1.0)?;
61
+ std::fs::write("out.png", png)?;
62
+ ```
63
+
64
+ The version is kept in **lockstep** with the rest of the monorepo
65
+ (`Cargo.toml` → `version`).
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.7,<2"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "kymostudio-core"
7
+ version = "0.3.3"
8
+ description = "Type it. See it appear. Watch it animate."
9
+ readme = "README.md"
10
+ license = "Apache-2.0"
11
+ requires-python = ">=3.10"
12
+ authors = [{ name = "rain1024", email = "anhv.ict91@gmail.com" }]
13
+ keywords = ["svg", "png", "rasterizer", "diagram", "resvg"]
14
+ classifiers = [
15
+ "Programming Language :: Rust",
16
+ "Programming Language :: Python :: 3",
17
+ "Topic :: Multimedia :: Graphics",
18
+ ]
19
+
20
+ [project.urls]
21
+ Homepage = "https://github.com/kymostudio/kymostudio"
22
+ Repository = "https://github.com/kymostudio/kymostudio"
23
+
24
+ [tool.maturin]
25
+ # Build the `python` feature; ship a single abi3 wheel (cp310-abi3).
26
+ features = ["python"]
27
+ module-name = "_kymostudio_core"
@@ -0,0 +1,73 @@
1
+ //! kymostudio core — pure-Rust SVG rasterization built on [`resvg`].
2
+ //!
3
+ //! No browser, no headless Chrome, no C dependencies. This mirrors what the
4
+ //! Python package does via `resvg-py` (`to_webp.py`) so SVG→PNG output stays
5
+ //! consistent across implementations — `resvg` is CSS-class-aware, which is why
6
+ //! the project avoids cairosvg.
7
+
8
+ use resvg::{tiny_skia, usvg};
9
+
10
+ // Language-binding facades — each compiled only when its feature is on.
11
+ #[cfg(feature = "python")]
12
+ mod python;
13
+ #[cfg(feature = "wasm")]
14
+ mod wasm;
15
+
16
+ /// Something went wrong turning SVG bytes into PNG bytes.
17
+ #[derive(Debug)]
18
+ pub enum RenderError {
19
+ /// The SVG could not be parsed.
20
+ Parse(usvg::Error),
21
+ /// The requested raster size was degenerate (zero / overflow).
22
+ Size { width: u32, height: u32 },
23
+ /// PNG encoding failed.
24
+ Encode(String),
25
+ }
26
+
27
+ impl std::fmt::Display for RenderError {
28
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29
+ match self {
30
+ RenderError::Parse(e) => write!(f, "invalid SVG: {e}"),
31
+ RenderError::Size { width, height } => {
32
+ write!(f, "invalid raster size {width}x{height}")
33
+ }
34
+ RenderError::Encode(e) => write!(f, "PNG encoding failed: {e}"),
35
+ }
36
+ }
37
+ }
38
+
39
+ impl std::error::Error for RenderError {}
40
+
41
+ impl From<usvg::Error> for RenderError {
42
+ fn from(e: usvg::Error) -> Self {
43
+ RenderError::Parse(e)
44
+ }
45
+ }
46
+
47
+ /// Render SVG bytes to PNG bytes at the given `scale` (1.0 = intrinsic size).
48
+ ///
49
+ /// On native builds (`system-fonts` feature, the default) system fonts are
50
+ /// loaded so `<text>` elements rasterize correctly. On wasm that feature is
51
+ /// off — supply fonts in the SVG, or the caller resolves them.
52
+ pub fn svg_to_png(svg: &[u8], scale: f32) -> Result<Vec<u8>, RenderError> {
53
+ #[allow(unused_mut)]
54
+ let mut opt = usvg::Options::default();
55
+ #[cfg(feature = "system-fonts")]
56
+ opt.fontdb_mut().load_system_fonts();
57
+
58
+ let tree = usvg::Tree::from_data(svg, &opt)?;
59
+ let size = tree.size();
60
+
61
+ let width = ((size.width() * scale).round() as i64).clamp(1, u32::MAX as i64) as u32;
62
+ let height = ((size.height() * scale).round() as i64).clamp(1, u32::MAX as i64) as u32;
63
+
64
+ let mut pixmap =
65
+ tiny_skia::Pixmap::new(width, height).ok_or(RenderError::Size { width, height })?;
66
+
67
+ let transform = tiny_skia::Transform::from_scale(scale, scale);
68
+ resvg::render(&tree, transform, &mut pixmap.as_mut());
69
+
70
+ pixmap
71
+ .encode_png()
72
+ .map_err(|e| RenderError::Encode(e.to_string()))
73
+ }
@@ -0,0 +1,139 @@
1
+ //! `kymo` CLI — rasterize an SVG to PNG.
2
+ //!
3
+ //! kymo -i in.svg out.png
4
+ //! kymo -i in.svg -o out.png --scale 2
5
+ //!
6
+ //! Pure Rust (resvg) — no browser, no system image libraries.
7
+
8
+ use std::path::PathBuf;
9
+ use std::process::ExitCode;
10
+
11
+ const VERSION: &str = env!("CARGO_PKG_VERSION");
12
+
13
+ const HELP: &str = "\
14
+ kymo — rasterize an SVG to PNG (pure Rust, no browser)
15
+
16
+ USAGE:
17
+ kymo -i <input.svg> [output.png] [options]
18
+
19
+ ARGS:
20
+ <output.png> Output path (positional). Defaults to the input
21
+ path with its extension swapped to .png.
22
+
23
+ OPTIONS:
24
+ -i, --input <FILE> Input SVG file (required)
25
+ -o, --output <FILE> Output PNG file (alternative to the positional arg)
26
+ -s, --scale <N> Scale factor, 1.0 = intrinsic size (default: 1)
27
+ -h, --help Print this help
28
+ -V, --version Print version
29
+
30
+ EXAMPLES:
31
+ kymo -i in.svg out.png
32
+ kymo -i diagram.svg # -> diagram.png
33
+ kymo -i diagram.svg -s 2 hi.png # 2x resolution
34
+ ";
35
+
36
+ struct Args {
37
+ input: PathBuf,
38
+ output: PathBuf,
39
+ scale: f32,
40
+ }
41
+
42
+ enum Parsed {
43
+ Run(Args),
44
+ Help,
45
+ Version,
46
+ }
47
+
48
+ fn parse(argv: &[String]) -> Result<Parsed, String> {
49
+ let mut input: Option<PathBuf> = None;
50
+ let mut output: Option<PathBuf> = None;
51
+ let mut scale: f32 = 1.0;
52
+ let mut positionals: Vec<String> = Vec::new();
53
+
54
+ let mut it = argv.iter();
55
+ while let Some(arg) = it.next() {
56
+ match arg.as_str() {
57
+ "-h" | "--help" => return Ok(Parsed::Help),
58
+ "-V" | "--version" => return Ok(Parsed::Version),
59
+ "-i" | "--input" => {
60
+ let v = it.next().ok_or("missing value for --input")?;
61
+ input = Some(PathBuf::from(v));
62
+ }
63
+ "-o" | "--output" => {
64
+ let v = it.next().ok_or("missing value for --output")?;
65
+ output = Some(PathBuf::from(v));
66
+ }
67
+ "-s" | "--scale" => {
68
+ let v = it.next().ok_or("missing value for --scale")?;
69
+ scale = v.parse().map_err(|_| format!("invalid scale: {v}"))?;
70
+ if !scale.is_finite() || scale <= 0.0 {
71
+ return Err(format!("scale must be positive, got {v}"));
72
+ }
73
+ }
74
+ s if s.starts_with('-') && s.len() > 1 => {
75
+ return Err(format!("unknown option: {s}"));
76
+ }
77
+ _ => positionals.push(arg.clone()),
78
+ }
79
+ }
80
+
81
+ // Allow input as a bare positional too: `kymo in.svg out.png`.
82
+ if input.is_none() && !positionals.is_empty() {
83
+ input = Some(PathBuf::from(positionals.remove(0)));
84
+ }
85
+ if output.is_none() && !positionals.is_empty() {
86
+ output = Some(PathBuf::from(positionals.remove(0)));
87
+ }
88
+ if let Some(extra) = positionals.first() {
89
+ return Err(format!("unexpected argument: {extra}"));
90
+ }
91
+
92
+ let input = input.ok_or("missing required input (use -i <file.svg>)")?;
93
+ let output = output.unwrap_or_else(|| input.with_extension("png"));
94
+ Ok(Parsed::Run(Args {
95
+ input,
96
+ output,
97
+ scale,
98
+ }))
99
+ }
100
+
101
+ fn run(args: Args) -> Result<(), String> {
102
+ let svg = std::fs::read(&args.input)
103
+ .map_err(|e| format!("cannot read {}: {e}", args.input.display()))?;
104
+ let png = kymostudio_core::svg_to_png(&svg, args.scale).map_err(|e| e.to_string())?;
105
+ std::fs::write(&args.output, &png)
106
+ .map_err(|e| format!("cannot write {}: {e}", args.output.display()))?;
107
+ eprintln!(
108
+ "{} -> {} ({} bytes)",
109
+ args.input.display(),
110
+ args.output.display(),
111
+ png.len()
112
+ );
113
+ Ok(())
114
+ }
115
+
116
+ fn main() -> ExitCode {
117
+ let argv: Vec<String> = std::env::args().skip(1).collect();
118
+ match parse(&argv) {
119
+ Ok(Parsed::Help) => {
120
+ print!("{HELP}");
121
+ ExitCode::SUCCESS
122
+ }
123
+ Ok(Parsed::Version) => {
124
+ println!("kymo {VERSION}");
125
+ ExitCode::SUCCESS
126
+ }
127
+ Ok(Parsed::Run(args)) => match run(args) {
128
+ Ok(()) => ExitCode::SUCCESS,
129
+ Err(e) => {
130
+ eprintln!("kymo: {e}");
131
+ ExitCode::FAILURE
132
+ }
133
+ },
134
+ Err(e) => {
135
+ eprintln!("kymo: {e}\n\nTry 'kymo --help'.");
136
+ ExitCode::FAILURE
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,23 @@
1
+ //! Python binding (PyO3). Built by maturin under the `python` feature.
2
+ //!
3
+ //! Exposes module `_kymostudio_core` with:
4
+ //! svg_to_png(svg: bytes, scale: float = 1.0) -> bytes
5
+
6
+ use pyo3::prelude::*;
7
+ use pyo3::types::PyBytes;
8
+
9
+ /// Rasterize `svg` (bytes) to PNG bytes at `scale` (1.0 = intrinsic size).
10
+ #[pyfunction]
11
+ #[pyo3(signature = (svg, scale = 1.0))]
12
+ fn svg_to_png<'py>(py: Python<'py>, svg: &[u8], scale: f32) -> PyResult<Bound<'py, PyBytes>> {
13
+ let png = crate::svg_to_png(svg, scale)
14
+ .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
15
+ Ok(PyBytes::new(py, &png))
16
+ }
17
+
18
+ #[pymodule]
19
+ fn _kymostudio_core(m: &Bound<'_, PyModule>) -> PyResult<()> {
20
+ m.add("__version__", env!("CARGO_PKG_VERSION"))?;
21
+ m.add_function(wrap_pyfunction!(svg_to_png, m)?)?;
22
+ Ok(())
23
+ }
@@ -0,0 +1,19 @@
1
+ //! wasm binding (wasm-bindgen). Built by wasm-pack under the `wasm` feature.
2
+ //! Runs in the browser (website/playground) and in Node.
3
+ //!
4
+ //! JS surface:
5
+ //! svgToPng(svg: Uint8Array, scale?: number): Uint8Array
6
+
7
+ use wasm_bindgen::prelude::*;
8
+
9
+ /// Rasterize `svg` bytes to PNG bytes at `scale` (1.0 = intrinsic size).
10
+ #[wasm_bindgen(js_name = svgToPng)]
11
+ pub fn svg_to_png(svg: &[u8], scale: Option<f32>) -> Result<Vec<u8>, JsError> {
12
+ crate::svg_to_png(svg, scale.unwrap_or(1.0)).map_err(|e| JsError::new(&e.to_string()))
13
+ }
14
+
15
+ /// The crate version, exposed to JS as `version()`.
16
+ #[wasm_bindgen]
17
+ pub fn version() -> String {
18
+ env!("CARGO_PKG_VERSION").to_string()
19
+ }
@@ -0,0 +1,31 @@
1
+ //! Integration tests for the SVG→PNG core.
2
+
3
+ const PNG_MAGIC: &[u8] = b"\x89PNG\r\n\x1a\n";
4
+
5
+ const SQUARE: &[u8] =
6
+ br##"<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><rect width="20" height="20" fill="#7cb342"/></svg>"##;
7
+
8
+ #[test]
9
+ fn renders_valid_png() {
10
+ let png = kymostudio_core::svg_to_png(SQUARE, 1.0).expect("render");
11
+ assert!(png.starts_with(PNG_MAGIC), "output is not a PNG");
12
+ }
13
+
14
+ #[test]
15
+ fn scale_changes_pixel_dimensions() {
16
+ // PNG IHDR stores width/height as big-endian u32 at byte offset 16.
17
+ let dims = |png: &[u8]| {
18
+ let w = u32::from_be_bytes(png[16..20].try_into().unwrap());
19
+ let h = u32::from_be_bytes(png[20..24].try_into().unwrap());
20
+ (w, h)
21
+ };
22
+ let base = kymostudio_core::svg_to_png(SQUARE, 1.0).unwrap();
23
+ let big = kymostudio_core::svg_to_png(SQUARE, 3.0).unwrap();
24
+ assert_eq!(dims(&base), (20, 20));
25
+ assert_eq!(dims(&big), (60, 60));
26
+ }
27
+
28
+ #[test]
29
+ fn rejects_garbage() {
30
+ assert!(kymostudio_core::svg_to_png(b"not an svg at all", 1.0).is_err());
31
+ }