Skip to content

Commit 6d2952b

Browse files
committed
v0.1.0
1 parent 4592d31 commit 6d2952b

File tree

9 files changed

+250
-35
lines changed

9 files changed

+250
-35
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ko_fi: obfusk

.github/workflows/ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: CI
2+
on: [push, pull_request, workflow_dispatch]
3+
jobs:
4+
build:
5+
runs-on: ubuntu-20.04
6+
strategy:
7+
matrix:
8+
python-version:
9+
- 3.5
10+
- 3.6
11+
- 3.7
12+
- 3.8
13+
- 3.9
14+
- '3.10.0-alpha - 3.10'
15+
- pypy3
16+
steps:
17+
- uses: actions/checkout@v2
18+
- name: Set up Python ${{ matrix.python-version }}
19+
uses: actions/setup-python@v2
20+
with:
21+
python-version: ${{ matrix.python-version }}
22+
- name: Test
23+
run: make test

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include LICENSE.AGPLv3
2+
include Makefile

Makefile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
SHELL := /bin/bash
2+
PYTHON ?= python3
3+
VERBOSE ?= --verbose
4+
5+
export PYTHONWARNINGS := default
6+
7+
.PHONY: all test clean cleanup install
8+
9+
all:
10+
11+
test:
12+
$(PYTHON) -m kanjidraw.gui $(VERBOSE) --doctest
13+
$(PYTHON) -m kanjidraw.lib $(VERBOSE) --doctest
14+
15+
clean: cleanup
16+
17+
cleanup:
18+
find -name '*~' -delete -print
19+
rm -fr kanjidraw/__pycache__/
20+
rm -fr build/ dist/ kanjidraw.egg-info/
21+
rm -fr .coverage htmlcov/
22+
23+
install:
24+
$(PYTHON) -mpip install -e .
25+
26+
.PHONY: _package _publish
27+
28+
_package:
29+
$(PYTHON) setup.py sdist bdist_wheel
30+
twine check dist/*
31+
32+
_publish: cleanup _package
33+
read -r -p "Are you sure? "; \
34+
[[ "$$REPLY" == [Yy]* ]] && twine upload dist/*

README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<!-- {{{1
2+
3+
File : README.md
4+
Maintainer : Felix C. Stegerman <[email protected]>
5+
Date : 2021-05-09
6+
7+
Copyright : Copyright (C) 2021 Felix C. Stegerman
8+
Version : v0.1.0
9+
License : AGPLv3+
10+
11+
}}}1 -->
12+
13+
[![GitHub Release](https://img.shields.io/github/release/obfusk/kanjidraw.svg?logo=github)](https://github.com/obfusk/kanjidraw/releases)
14+
[![CI](https://github.com/obfusk/kanjidraw/workflows/CI/badge.svg)](https://github.com/obfusk/kanjidraw/actions?query=workflow%3ACI)
15+
[![AGPLv3+](https://img.shields.io/badge/license-AGPLv3+-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.html)
16+
[![Sponsor](https://img.shields.io/badge/%E2%99%A5-support-violet.svg)](https://ko-fi.com/obfusk)
17+
18+
<!--
19+
[![PyPI Version](https://img.shields.io/pypi/v/kanjidraw.svg)](https://pypi.python.org/pypi/kanjidraw)
20+
[![Python Versions](https://img.shields.io/pypi/pyversions/kanjidraw.svg)](https://pypi.python.org/pypi/kanjidraw)
21+
-->
22+
23+
## kanjidraw - handwritten kanji recognition
24+
25+
`kanjidraw` is a simple Python library + GUI for matching (the strokes
26+
of a) handwritten kanji against its database.
27+
28+
You can use the GUI to draw and subsequently select a kanji from the
29+
list of probable matches, which will then be copied to the clipboard.
30+
31+
The database is based on KanjiVG and the algorithms are based on the
32+
[Kanji draw](https://github.com/onitake/kanjirecog) Android app.
33+
34+
## Requirements
35+
36+
* Python >= 3.5 (w/ Tk support for the GUI).
37+
38+
### Debian/Ubuntu
39+
40+
```bash
41+
$ apt install python3-tk
42+
```
43+
44+
## Installing
45+
46+
### Using pip
47+
48+
```bash
49+
$ pip install kanjidraw
50+
```
51+
52+
NB: depending on your system you may need to use e.g. `pip3 --user`
53+
instead of just `pip`.
54+
55+
### From git
56+
57+
NB: this installs the latest development version, not the latest
58+
release.
59+
60+
```bash
61+
$ git clone https://github.com/obfusk/kanjidraw.git
62+
$ cd kanjidraw
63+
$ pip install -e .
64+
```
65+
66+
NB: you may need to add e.g. `~/.local/bin` to your `$PATH` in order
67+
to run `kanjidraw`.
68+
69+
To update to the latest development version:
70+
71+
```bash
72+
$ cd kanjidraw
73+
$ git pull --rebase
74+
```
75+
76+
## License
77+
78+
### Code
79+
80+
© Felix C. Stegerman
81+
82+
[![AGPLv3+](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.html)
83+
84+
### KanjiVG (stroke data)
85+
86+
© Ulrich Apel
87+
88+
[![CC-BY-SA](https://licensebuttons.net/l/by-sa/3.0/88x31.png)](https://github.com/KanjiVG/kanjivg/blob/master/COPYING)
89+
90+
<!-- vim: set tw=70 sw=2 sts=2 et fdm=marker : -->

kanjidraw/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
from .__main__ import *
1+
from .lib import *
2+
from .lib import __version__

kanjidraw/gui.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,40 @@
1616
# {{{1
1717
r"""
1818
19-
...
19+
Tkinter GUI.
2020
2121
""" # }}}1
2222

2323
import sys
2424

25+
import tkinter as tk
26+
import tkinter.font as tk_font
27+
from tkinter import Tk, Button, Canvas, Frame, Label
28+
2529
from . import load_json, matches
2630

27-
def tkinter_main(): # {{{1
28-
import tkinter as tk
29-
import tkinter.font as tk_font
30-
from tkinter import Tk, Button, Canvas, Frame, Label
31+
NAME, TITLE = "kanjidraw", "Kanji Draw"
32+
HEIGHT, WIDTH, BACKGROUND = 400, 400, "#ccc"
33+
ROWS, LINEWIDTH, FONTSIZE = 5, 5, 35
34+
35+
def gui(): # {{{1
36+
"""Tkinter GUI."""
3137

3238
win = Tk()
33-
win.title("Kanji Draw")
39+
win.title(TITLE)
3440
win.columnconfigure(0, weight = 1)
3541
win.rowconfigure(0, weight = 1)
36-
37-
height, width, bg, rows = 400, 400, "#ccc", 5
38-
font = tk_font.Font(size = 35)
42+
font = tk_font.Font(size = FONTSIZE)
3943

4044
data = load_json()
4145
max_strokes = max(data.keys())
4246
drawing, x, y, strokes, lines = False, 0, 0, [], []
4347

4448
def on_mousedown(event):
49+
nonlocal drawing, x, y
4550
if len(strokes) < max_strokes:
46-
nonlocal drawing, x, y
4751
drawing, x, y = True, event.x, event.y
48-
strokes.append([x * 255.0 / height, y * 255.0 / width])
52+
strokes.append([x * 255.0 / HEIGHT, y * 255.0 / WIDTH])
4953
lines.append([])
5054
enable_buttons()
5155

@@ -60,7 +64,7 @@ def on_mouseup(event):
6064
if drawing:
6165
draw_line(x, y, event.x, event.y)
6266
drawing, x, y = False, event.x, event.y
63-
strokes[-1] += [x * 255.0 / height, y * 255.0 / width]
67+
strokes[-1] += [x * 255.0 / HEIGHT, y * 255.0 / WIDTH]
6468
update_strokes()
6569

6670
def on_undo():
@@ -81,11 +85,12 @@ def on_clear():
8185
def on_done():
8286
results_frame = Frame(win)
8387
for i, (_, kanji) in enumerate(matches(strokes, data)):
84-
results_frame.columnconfigure(i % rows, weight = 1)
85-
results_frame.rowconfigure(i // rows, weight = 1)
88+
col, row = i % ROWS, i // ROWS
89+
results_frame.columnconfigure(col, weight = 1)
90+
results_frame.rowconfigure(row, weight = 1)
8691
btn = Button(results_frame, text = kanji, font = font,
8792
command = on_select_kanji(results_frame, kanji))
88-
btn.grid(column = i % rows, row = i // rows, sticky = "nsew")
93+
btn.grid(column = col, row = row, sticky = "nsew")
8994
results_frame.grid(row = 0, column = 0, sticky = "nsew")
9095

9196
def on_select_kanji(results_frame, kanji):
@@ -96,7 +101,8 @@ def handler():
96101
return handler
97102

98103
def draw_line(x1, y1, x2, y2):
99-
l = canvas.create_line(x1, y1, x2, y2, width = 5, capstyle = tk.ROUND)
104+
l = canvas.create_line(x1, y1, x2, y2, width = LINEWIDTH,
105+
capstyle = tk.ROUND)
100106
lines[-1].append(l)
101107

102108
def disable_buttons():
@@ -114,15 +120,15 @@ def copy_to_clipboard(text):
114120
win.clipboard_clear()
115121
win.clipboard_append(text)
116122

117-
draw_frame = Frame(win)
118-
btns = Frame(draw_frame)
119-
btn_undo = Button(btns, text = "Undo", command = on_undo)
120-
btn_clear = Button(btns, text = "Clear", command = on_clear)
123+
draw_frame = Frame(win)
124+
btns = Frame(draw_frame)
125+
btn_undo = Button(btns, text = "Undo", command = on_undo)
126+
btn_clear = Button(btns, text = "Clear", command = on_clear)
121127
lbl_strokes = Label(btns, text = "Strokes: 0")
122-
btn_done = Button(btns, text = "Done", command = on_done)
128+
btn_done = Button(btns, text = "Done", command = on_done)
123129
disable_buttons()
124130

125-
canvas = Canvas(draw_frame, height = height, width = width, bg = bg)
131+
canvas = Canvas(draw_frame, height = HEIGHT, width = WIDTH, bg = BACKGROUND)
126132
canvas.bind("<ButtonPress-1>", on_mousedown)
127133
canvas.bind("<B1-Motion>", on_mousemove)
128134
canvas.bind("<ButtonRelease-1>", on_mouseup)
@@ -132,16 +138,22 @@ def copy_to_clipboard(text):
132138
btns.pack()
133139
canvas.pack()
134140
draw_frame.grid(row = 0, column = 0, sticky = "nsew")
135-
136141
win.mainloop()
137142
# }}}1
138143

144+
def main():
145+
if "--version" in sys.argv:
146+
from .lib import __version__
147+
print("{} v{}".format(NAME, __version__))
148+
else:
149+
gui()
150+
139151
if __name__ == "__main__":
140152
if "--doctest" in sys.argv:
141153
verbose = "--verbose" in sys.argv
142154
import doctest
143155
if doctest.testmod(verbose = verbose)[0]: sys.exit(1)
144156
else:
145-
tkinter_main()
157+
main()
146158

147159
# vim: set tw=70 sw=2 sts=2 et fdm=marker :

0 commit comments

Comments
 (0)