Skip to content

Commit d2cc3fd

Browse files
committed
rel 2023.1
1 parent 6c10eef commit d2cc3fd

18 files changed

+253
-53
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
All major and minor version changes will be documented in this file. Details of
44
patch-level version changes can be found in [commit messages](../../commits/master).
55

6+
## 2023.1 - 2023/06/25
7+
8+
- Add `asyncTrace` and `skimageTrace`
9+
- Raise OSError "svgtrace.trace/ asyncTrace is not supported in Windows Jupyter Notebooks"
10+
- Documentation: Add Tutorials
11+
612
## 2023.0.1 - 2023/03/12
713

814
- Raise `FileNotFoundError` when input does not exist

README.md

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
Leverage playwright and the imagetrace.js library to trace a bitmap to SVG in
1717
python
1818

19-
- [Example](#example)
2019
- [Documentation](#documentation)
2120
- [Install With PIP](#install-with-pip)
2221
- [Language information](#language-information)
@@ -49,45 +48,13 @@ python
4948
- [Support](#support)
5049
- [Rationale](#rationale)
5150

52-
## Example
53-
54-
Convert the following files:
55-
<div>
56-
<img src="tests/data/logo-bw.png" alt="Screenshot 1" width="300">
57-
<img src="tests/data/logo.png" alt="Screenshot 2" width="300">
58-
</div>
59-
60-
```python
61-
"""Test the image tracer."""
62-
from pathlib import Path
63-
64-
from svgtrace import trace
65-
66-
THISDIR = str(Path(__file__).resolve().parent)
67-
logoFile = f"{THISDIR}/data/logo"
68-
69-
Path(f"{logoFile}-bw.svg").write_text(trace(f"{logoFile}-bw.png", True), encoding="utf-8")
70-
71-
Path(f"{logoFile}.svg").write_text(trace(f"{logoFile}.png"), encoding="utf-8")
72-
73-
```
74-
75-
Output
76-
77-
<div>
78-
<img src="tests/data/logo-bw.svg" alt="Screenshot 1" width="300">
79-
<img src="tests/data/logo.svg" alt="Screenshot 2" width="300">
80-
</div>
81-
8251
## Documentation
8352

8453
A high-level overview of how the documentation is organized organized will help you know
8554
where to look for certain things:
8655

87-
<!--
8856
- [Tutorials](/documentation/tutorials) take you by the hand through a series of steps to get
8957
started using the software. Start here if you’re new.
90-
-->
9158
- The [Technical Reference](/documentation/reference) documents APIs and other aspects of the
9259
machinery. This documentation describes how to use the classes and functions at a lower level
9360
and assume that you have a good high-level understanding of the software.

documentation/reference/svgtrace/index.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,70 @@ Svgtrace
66
> Auto-generated documentation for [svgtrace](../../../svgtrace/__init__.py) module.
77
88
- [Svgtrace](#svgtrace)
9+
- [asyncTrace](#asynctrace)
10+
- [skimageTrace](#skimagetrace)
911
- [trace](#trace)
1012

13+
## asyncTrace
14+
15+
[Show source in __init__.py:41](../../../svgtrace/__init__.py#L41)
16+
17+
Do a trace of an image on the filesystem using the playwright library.
18+
19+
#### Arguments
20+
21+
- `filename` *str* - The location of the file on the filesystem, use an
22+
absolute filepath for this
23+
- `blackAndWhite` *bool, optional* - Trace a black and white SVG. Defaults to False.
24+
- `mode` *str, optional* - Set the mode. See https://github.com/jankovicsandras/imagetracerjs
25+
for more information. Defaults to "default".
26+
27+
#### Returns
28+
29+
- `str` - SVG string
30+
31+
#### Raises
32+
33+
FileNotFoundError f"{filename} does not exist!"
34+
OSError "svgtrace.trace/ asyncTrace is not supported in Windows Jupyter Notebooks"
35+
36+
#### Signature
37+
38+
```python
39+
async def asyncTrace(
40+
filename: str, blackAndWhite: bool = False, mode: str = "default"
41+
) -> str:
42+
...
43+
```
44+
45+
46+
47+
## skimageTrace
48+
49+
[Show source in __init__.py:98](../../../svgtrace/__init__.py#L98)
50+
51+
Do a trace of an pillow image using the skimage library.
52+
53+
#### Arguments
54+
55+
- `image` *Image.Image* - pillow image to trace
56+
57+
#### Returns
58+
59+
- `str` - SVG string
60+
61+
#### Signature
62+
63+
```python
64+
def skimageTrace(image: Image.Image) -> str:
65+
...
66+
```
67+
68+
69+
1170
## trace
1271

13-
[Show source in __init__.py:17](../../../svgtrace/__init__.py#L17)
72+
[Show source in __init__.py:22](../../../svgtrace/__init__.py#L22)
1473

1574
Do a trace of an image on the filesystem using the playwright library.
1675

documentation/tutorials/README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<!-- omit in toc -->
2+
# Tutorial
3+
4+
See below for a step-by-step tutorial on how to use svgtrace
5+
6+
- [Using the `trace` function](#using-the-trace-function)
7+
- [Using the `asyncTrace` function](#using-the-asynctrace-function)
8+
- [Using the `skimageTrace` function](#using-the-skimagetrace-function)
9+
10+
## Using the `trace` function
11+
12+
1. Create the following files (`logo-bw.png` and `logo.png`)
13+
<div>
14+
<img src="../../tests/data/logo-bw.png" alt="Screenshot 1" width="300">
15+
<img src="../../tests/data/logo.png" alt="Screenshot 2" width="300">
16+
</div>
17+
18+
2. Import `svgtrace` and convert a file on disk (with `trace`) to an svg, andsave this back to disk
19+
(with `Path().write_text`)
20+
```python
21+
from pathlib import Path
22+
from svgtrace import trace
23+
24+
Path("logo-bw.svg").write_text(trace("logo-bw.png", True), encoding="utf-8")
25+
Path("logo.svg").write_text(trace("logo.png"), encoding="utf-8")
26+
```
27+
28+
3. Output
29+
<div>
30+
<img src="../../tests/data/logo-bw.svg" alt="logo-wb.svg" width="300">
31+
<img src="../../tests/data/logo.svg" alt="logo.svg" width="300">
32+
</div>
33+
34+
## Using the `asyncTrace` function
35+
36+
1. Import `svgtrace` and convert a file on disk (with `asyncTrace`) to an svg, andsave this back to disk
37+
(with `Path().write_text`)
38+
```python
39+
from pathlib import Path
40+
from svgtrace import trace
41+
42+
Path("logo-asyncBw.svg").write_text(asyncio.run(asyncTrace("logo-bw.png", True)), encoding="utf-8")
43+
Path("logo-async.svg").write_text(asyncio.run(asyncTrace("logo.png")), encoding="utf-8")
44+
```
45+
46+
2. Output is identical to above
47+
48+
## Using the `skimageTrace` function
49+
50+
1. Import `svgtrace` and convert a pillow image (with `skimageTrace`) to an svg, andsave this back to disk
51+
(with `Path().write_text`)
52+
```python
53+
from pathlib import Path
54+
from PIL import Image
55+
from svgtrace import trace
56+
57+
Path("logo-skimageBw.svg").write_text(skimageTrace(Image.open("logo-bw.png")), encoding="utf-8")
58+
Path("logo-skimage.svg").write_text(skimageTrace(Image.open("logo.png")), encoding="utf-8")
59+
```
60+
61+
2. Output
62+
<div>
63+
<img src="../../tests/data/logo-skimageBw.svg" alt="logo-skimageBw.svg" width="300">
64+
<img src="../../tests/data/logo-skimage.svg" alt="logo-skimage.svg" width="300">
65+
</div>

pyproject.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "svgtrace"
3-
version = "2023.0.1"
3+
version = "2023.1"
44
license = "mit"
55
description = "Leverage playwright and the imagetrace.js library to trace a bitmap to svg in python"
66
authors = ["FredHappyface"]
@@ -21,9 +21,12 @@ documentation = "https://github.com/FHPythonUtils/SvgTrace/blob/master/README.md
2121
readme = "README.md"
2222

2323
[tool.poetry.dependencies]
24-
python = "^3.8"
25-
playwright = "<2,>=1.29.1"
24+
python = "^3.9"
25+
playwright = "<2,>=1.35.0"
2626
install-playwright = "<2,>=0.0.0"
27+
scikit-image = "<2,>=0.21.0"
28+
pillow = "<10,>=9.5.0"
29+
numpy = "<2,>=1.25.0"
2730

2831
[tool.poetry.group.dev.dependencies]
2932
nocairosvg = "^2023"
@@ -73,7 +76,6 @@ env_list =
7376
py311
7477
py310
7578
py39
76-
py38
7779
7880
[testenv]
7981
deps =

requirements.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
install-playwright<2,>=0.0.0
2-
playwright<2,>=1.29.1
2+
numpy<2,>=1.25.0
3+
pillow<10,>=9.5.0
4+
playwright<2,>=1.35.0
5+
scikit-image<2,>=0.21.0

svgtrace/__init__.py

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@
66
from __future__ import annotations
77

88
import asyncio
9+
import sys
10+
import warnings
911
from pathlib import Path
1012

13+
import numpy as np
1114
from install_playwright import install
12-
from playwright.sync_api import sync_playwright
15+
from PIL import Image
16+
from playwright.async_api import async_playwright
17+
from skimage import feature, measure
1318

1419
THISDIR = str(Path(__file__).resolve().parent)
1520

@@ -30,6 +35,40 @@ def trace(filename: str, blackAndWhite: bool = False, mode: str = "default") ->
3035
Raises:
3136
FileNotFoundError f"{filename} does not exist!"
3237
"""
38+
return asyncio.run(asyncTrace(filename, blackAndWhite, mode))
39+
40+
41+
async def asyncTrace(filename: str, blackAndWhite: bool = False, mode: str = "default") -> str:
42+
"""Do a trace of an image on the filesystem using the playwright library.
43+
44+
Args:
45+
filename (str): The location of the file on the filesystem, use an
46+
absolute filepath for this
47+
blackAndWhite (bool, optional): Trace a black and white SVG. Defaults to False.
48+
mode (str, optional): Set the mode. See https://github.com/jankovicsandras/imagetracerjs
49+
for more information. Defaults to "default".
50+
51+
Returns:
52+
str: SVG string
53+
54+
Raises:
55+
FileNotFoundError f"{filename} does not exist!"
56+
OSError "svgtrace.trace/ asyncTrace is not supported in Windows Jupyter Notebooks"
57+
"""
58+
# Detecting Default event loop in Notebook 6.1.6 on Windows is not ProactorEventLoop
59+
# (https://github.com/jupyter/notebook/issues/5916)
60+
if sys.platform.startswith("win") and sys.version_info >= (3, 8):
61+
try:
62+
from asyncio import WindowsSelectorEventLoopPolicy
63+
except ImportError:
64+
pass
65+
else:
66+
if isinstance(asyncio.get_event_loop_policy(), WindowsSelectorEventLoopPolicy):
67+
raise OSError(
68+
"svgtrace.trace/ asyncTrace is not supported in Windows Jupyter Notebooks"
69+
)
70+
71+
#
3372
if mode.find("black") >= 0 or blackAndWhite:
3473
mode = "posterized1"
3574

@@ -38,19 +77,46 @@ def trace(filename: str, blackAndWhite: bool = False, mode: str = "default") ->
3877
if not Path(filename).exists():
3978
raise FileNotFoundError(f"{filename} does not exist!")
4079

41-
with sync_playwright() as p:
80+
async with async_playwright() as p:
4281
install(p.chromium)
43-
browser = p.chromium.launch(
82+
browser = await p.chromium.launch(
4483
args=["--no-sandbox", "--disable-web-security", "--allow-file-access-from-files"]
4584
)
4685

47-
page = browser.new_page()
48-
page.goto(f"file:///{THISDIR}/imagetracer.html")
49-
page.evaluate(
86+
page = await browser.new_page()
87+
await page.goto(f"file:///{THISDIR}/imagetracer.html")
88+
await page.evaluate(
5089
f"ImageTracer.imageToSVG('file:///{filename}',function(svgstr){{ ImageTracer.appendSVGString( svgstr, 'svg-container' ); }},'{mode}');"
5190
)
52-
element = page.query_selector("div")
53-
svg = page.evaluate("(element) => element.innerHTML", element)
91+
element = await page.query_selector("div")
92+
svg = await page.evaluate("(element) => element.innerHTML", element)
93+
94+
await browser.close()
95+
return svg
96+
97+
98+
def skimageTrace(image: Image.Image) -> str:
99+
"""Do a trace of an pillow image using the skimage library.
100+
101+
Args:
102+
image (Image.Image): pillow image to trace
103+
104+
Returns:
105+
str: SVG string
106+
"""
107+
with warnings.catch_warnings():
108+
warnings.filterwarnings("ignore")
109+
imageGreyscale = image.convert("L")
110+
edges = feature.canny(np.array(imageGreyscale))
111+
paths = []
112+
contours = measure.find_contours(edges, 0.5)
113+
for contour in contours:
114+
pathData = " L ".join([f"{coord[1]},{coord[0]}" for coord in contour])
115+
paths.append(f'<path d="M {pathData} Z" stroke="black" fill="none" />')
54116

55-
browser.close()
117+
svg = (
118+
f'<svg xmlns="http://www.w3.org/2000/svg" width="{image.width}" height="{image.height}">'
119+
+ "".join(paths)
120+
+ "</svg>"
121+
)
56122
return svg

tests/data/logo-actual-bw.png

2.59 KB
Loading

tests/data/logo-actual-skimage.png

2.87 KB
Loading

tests/data/logo-actual-skimagebw.png

8.57 KB
Loading

0 commit comments

Comments
 (0)