-
Notifications
You must be signed in to change notification settings - Fork 25
/
kanji_colorizer.py
executable file
·189 lines (153 loc) · 6.4 KB
/
kanji_colorizer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# kanji_colorizer.py is part of kanji-colorize which makes KanjiVG data
# into colored stroke order diagrams; this is the anki2 addon file.
#
# Copyright 2012 Cayenne Boyer
#
# The code to do this automatically when the Kanji field is exited was
# originally based on the Japanese support reading generation addon by
# Damien Elmes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
# Installation: copy this file and the kanjicolorizer directory to your
# Anki addons folder.
# Usage: Add a "Diagram" field to a model with "Japanese"
# in the name and a field named "Kanji". When you finish editing the
# kanji field, if it contains precisely one character, a colored stroke
# order diagram will be added to the Diagram field in the same way that
# the Japanese support plugin adds readings.
#
# To add diagrams to all such fields, or regenerate them with new
# settings, use the "Kanji Colorizer: (re)generate all" option in the
# tools menu.
from anki.hooks import addHook
from aqt import mw
from aqt.utils import showInfo, askUser
from aqt.qt import *
from .kanjicolorizer.colorizer import (KanjiVG, KanjiColorizer,
InvalidCharacterError)
# Configuration
addon_config = mw.addonManager.getConfig(__name__)
config = "--mode "
config += addon_config["mode"]
if addon_config["group-mode"]:
config += " --group-mode "
config += " --saturation "
config += str(addon_config["saturation"])
config += " --value "
config += str(addon_config["value"])
config += " --image-size "
config += str(addon_config["image-size"])
modelNameSubstring = 'japanese'
srcField = 'Kanji'
dstField = 'Diagram'
# avoid errors due to invalid config
if 'model' in addon_config and type(addon_config['model']) is str:
modelNameSubstring = addon_config['model'].lower()
if 'src-field' in addon_config and type(addon_config['src-field']) is str:
srcField = addon_config['src-field']
if 'dst-field' in addon_config and type(addon_config['dst-field']) is str:
dstField = addon_config['dst-field']
kc = KanjiColorizer(config)
def modelIsCorrectType(model):
'''
Returns True if model has Japanese in the name and has both srcField
and dstField; otherwise returns False
'''
# Does the model name have Japanese in it?
model_name = model['name'].lower()
fields = mw.col.models.fieldNames(model)
return (modelNameSubstring in model_name and
srcField in fields and
dstField in fields)
def characters_to_colorize(s):
'''
Given a string, returns a lost of characters to colorize
If the string consists of only a single character, returns a list
containing that character. If it is longer, returns a list of only the
kanji.
'''
if len(s) <= 1:
return list(s)
return [c for c in s if ord(c) >= 19968 and ord(c) <= 40879]
def addKanji(note, flag=False, currentFieldIndex=None):
'''
Checks to see if a kanji should be added, and adds it if so.
'''
if not modelIsCorrectType(note.model()):
return flag
if currentFieldIndex != None: # We've left a field
# But it isn't the relevant one
if note.model()['flds'][currentFieldIndex]['name'] != srcField:
return flag
srcTxt = mw.col.media.strip(note[srcField])
oldDst = note[dstField]
dst=''
for character in characters_to_colorize(str(srcTxt)):
# write to file; anki works in the media directory by default
try:
filename = KanjiVG(character).ascii_filename
except InvalidCharacterError:
# silently ignore non-Japanese characters
continue
char_svg = kc.get_colored_svg(character).encode('utf_8')
anki_fname = mw.col.media.writeData(filename, char_svg)
dst += '<img src="{!s}">'.format(anki_fname)
if dst != oldDst and dst != '':
note[dstField] = dst
note.flush()
return True
return flag
# Add a colorized kanji to a Diagram whenever leaving a Kanji field
def onFocusLost(flag, note, currentFieldIndex):
return addKanji(note, flag, currentFieldIndex)
addHook('editFocusLost', onFocusLost)
# menu item to regenerate all
def regenerate_all():
# Find the models that have the right name and fields; faster than
# checking every note
if not askUser("Do you want to regenerate all kanji diagrams? "
'This may take some time and will overwrite the '
'destination Diagram fields.'):
return
models = [m for m in mw.col.models.all() if modelIsCorrectType(m)]
# Find the notes in those models and give them kanji
for model in models:
for nid in mw.col.models.nids(model):
addKanji(mw.col.getNote(nid))
showInfo("Done regenerating colorized kanji diagrams!")
def generate_for_new():
if not askUser("This option will generate diagrams for notes with "
"an empty {} field only. "
"Proceed?".format(dstField)):
return
model_ids = [mid for mid in mw.col.models.ids() if modelIsCorrectType(mw.col.models.get(mid))]
# Generate search string in the format
# (mid:123 or mid:456) Kanji:_* Diagram:
search_str = '({}) {}:_* {}:'.format(
' or '.join(('mid:'+mid for mid in model_ids)), srcField, dstField)
# Find the notes
for note_id in mw.col.findNotes(search_str):
addKanji(mw.col.getNote(note_id))
showInfo("Done generating colorized kanji diagrams!")
# add menu items
submenu = mw.form.menuTools.addMenu("Kanji Colorizer")
do_generate_new = QAction("generate all new", mw)
do_generate_new.triggered.connect(generate_for_new)
submenu.addAction(do_generate_new)
do_regenerate_all = QAction("(re)generate all", mw)
do_regenerate_all.triggered.connect(regenerate_all)
submenu.addAction(do_regenerate_all)