1# -*- coding: utf-8 -*- 2# Copyright 2010-2018, Google Inc. 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: 8# 9# * Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# * Redistributions in binary form must reproduce the above 12# copyright notice, this list of conditions and the following disclaimer 13# in the documentation and/or other materials provided with the 14# distribution. 15# * Neither the name of Google Inc. nor the names of its 16# contributors may be used to endorse or promote products derived from 17# this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31"""Generates svg files from templates. 32 33Usage: 34$ mkdir OUTPUT_PATH 35$ python transform.py --input_dir=data/images/android/template --output_dir=OUTPUT_PATH 36 37Note: 38We use half-width characters for following to adjust the position 39on software keyboards. 40See also: b/16722519 41 42"(", ")", "!", "?", ":" 43 44Half-width is also used for "/" for better look. 45""" 46 47import logging 48import optparse 49import os 50import tempfile 51import zipfile 52 53 54_REPLACE_CHAR = '中' 55_REPLACE_CHAR_QWERTY_SUPPORT = '副' 56 57_REPLACE_CHARS = ('中', '左', '上', '右', '下') 58 59_REPLACE_ID_SUFFIXEX = ( 60 '{id_suffix_center}', '{id_suffix_left}', '{id_suffix_up}', 61 '{id_suffix_right}', '{id_suffix_down}') 62 63_EXPAND_SUPPORT_SUFFIXES = ( 64 'center', 'left', 'up', 'right', 'down', 'release') 65 66_GODAN_KANA_SUPPORT_KEY_DEFINITIONS = [ 67 {'name': '01', 68 'chars': ('A', '', '', '', '1'), 69 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 70 {'name': '02', 71 'chars': ('K', '', 'Q', 'G', '2'), 72 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 73 {'name': '03', 74 'chars': ('H', 'P', 'F', 'B', '3'), 75 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 76 {'name': '04', 77 'chars': ('I', '', '', '', '4'), 78 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 79 {'name': '05', 80 'chars': ('S', '', 'J', 'Z', '5'), 81 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 82 {'name': '06', 83 'chars': ('M', '/', 'L', 'ー', '6'), 84 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 85 {'name': '07', 86 'chars': ('U', '', '', '', '7'), 87 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 88 {'name': '08', 89 'chars': ('T', '', 'C', 'D', '8'), 90 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 91 {'name': '09', 92 'chars': ('Y', '(', 'X', ')', '9'), 93 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 94 {'name': '10', 95 'chars': ('E', '', '', '', ''), 96 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 97 {'name': '11', 98 'chars': ('N', ':', '', '・', '0'), 99 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 100 # 12: Needs another template. Defined bellow 101 {'name': '13', 102 'chars': ('O', '', '', '', ''), 103 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 104 # 14: "大小" key(godan__kana__14.svg): Will be modified directly 105 {'name': '15', 106 'chars': ('W', '「', 'V', '」', ''), 107 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 108 ] 109 110_GODAN_KANA_SUPPORT_12_KEY_DEFINITION = [ 111 {'name': '12', 112 'chars': ('R', '。', '?', '!', '、'), 113 'id_suffixes': ('', '-light', '-light', '-light', '-light')}, 114 ] 115 116_GODAN_KANA_SUPPORT_POPUP_KEY_DEFINITIONS = [ 117 {'name': '01', 'chars': ('A', '', '', '', '1')}, 118 {'name': '02', 'chars': ('K', '', 'Q', 'G', '2')}, 119 {'name': '03', 'chars': ('H', 'P', 'F', 'B', '3')}, 120 {'name': '04', 'chars': ('I', '', '', '', '4')}, 121 {'name': '05', 'chars': ('S', '', 'J', 'Z', '5')}, 122 {'name': '06', 'chars': ('M', '/', 'L', 'ー', '6')}, 123 {'name': '07', 'chars': ('U', '', '', '', '7')}, 124 {'name': '08', 'chars': ('T', '', 'C', 'D', '8')}, 125 {'name': '09', 'chars': ('Y', '(', 'X', ')', '9')}, 126 {'name': '10', 'chars': ('E', '', '', '', '')}, 127 # Use half-width ':' to adjust character position. 128 {'name': '11', 'chars': ('N', ':', 'ん', '・', '0')}, 129 {'name': '12', 'chars': ('R', '。', '?', '!', '、')}, 130 {'name': '13', 'chars': ('O', '', '', '', '')}, 131 # 14: "大小" key: godan__kana__14.svg will be used. 132 # Please check mozc/android/resources/res/xml/ 133 {'name': '15', 'chars': ('W', '「', 'V', '」', '')}, 134 ] 135 136_QWERTY_SUPPORT_KEY_MAPPING = { 137 'q': '1', 138 'w': '2', 139 'e': '3', 140 'r': '4', 141 't': '5', 142 'y': '6', 143 'u': '7', 144 'i': '8', 145 'o': '9', 146 'p': '0', 147} 148 149# 'A'-'Z' will be generated by GenerateQwertyAlphabetKeyDefinitions(). 150_QWERTY_KEYICON_KEY_DEFINITIONS = [ 151 {'name': 'digit_zero', 'char': '0'}, 152 {'name': 'digit_one', 'char': '1'}, 153 {'name': 'digit_two', 'char': '2'}, 154 {'name': 'digit_three', 'char': '3'}, 155 {'name': 'digit_four', 'char': '4'}, 156 {'name': 'digit_five', 'char': '5'}, 157 {'name': 'digit_six', 'char': '6'}, 158 {'name': 'digit_seven', 'char': '7'}, 159 {'name': 'digit_eight', 'char': '8'}, 160 {'name': 'digit_nine', 'char': '9'}, 161 162 {'name': 'ampersand', 'char': '&'}, 163 {'name': 'apostrophe', 'char': '''}, 164 {'name': 'asterisk', 'char': '*'}, 165 {'name': 'circumflex_accent', 'char': '^'}, 166 {'name': 'colon', 'char': ':'}, 167 {'name': 'comma', 'char': ','}, 168 {'name': 'commercial_at', 'char': '@'}, 169 {'name': 'dollar_sign', 'char': '$'}, 170 {'name': 'equals_sign', 'char': '='}, 171 {'name': 'exclamation_mark', 'char': '!'}, 172 {'name': 'full_stop', 'char': '.'}, 173 {'name': 'grave_accent', 'char': '`'}, 174 {'name': 'less_than_sign', 'char': '<'}, 175 {'name': 'greater_than_sign', 'char': '>'}, 176 {'name': 'hyphen_minus', 'char': '-'}, 177 {'name': 'ideographic_comma', 'char': '、'}, 178 {'name': 'ideographic_full_stop', 'char': '。'}, 179 {'name': 'katakana_middle_dot', 'char': '・'}, 180 {'name': 'left_corner_bracket', 'char': '「'}, 181 {'name': 'right_corner_bracket', 'char': '」'}, 182 {'name': 'left_curly_bracket', 'char': '{'}, 183 {'name': 'right_curly_bracket', 'char': '}'}, 184 {'name': 'left_parenthesis', 'char': '('}, 185 {'name': 'right_parenthesis', 'char': ')'}, 186 {'name': 'left_square_bracket', 'char': '['}, 187 {'name': 'right_square_bracket', 'char': ']'}, 188 {'name': 'low_line', 'char': '_'}, 189 {'name': 'minus_sign', 'char': '−'}, 190 {'name': 'number_sign', 'char': '#'}, 191 {'name': 'percent_sign', 'char': '%'}, 192 {'name': 'plus_sign', 'char': '+'}, 193 {'name': 'question_mark', 'char': '?'}, 194 {'name': 'quotation_mark', 'char': '"'}, 195 {'name': 'reverse_solidus', 'char': '\\'}, 196 {'name': 'semicolon', 'char': ';'}, 197 {'name': 'solidus', 'char': '/'}, 198 {'name': 'tilde', 'char': '~'}, 199 {'name': 'vertical_line', 'char': '|'}, 200 201 # Use half-width ':' to adjust character position. 202 {'name': 'fullwidth_colon', 'char': ':'}, 203 204 # Use half-width '/' for a better look. 205 # TODO(team): This rule generates qwerty__keyicon__fullwidth__solidus but 206 # currently it's used only by GODAN. Rename it. 207 {'name': 'fullwidth_solidus', 'char': '/'}, 208 ] 209 210_TWELVEKEYS_ALPHABET_KEY_DEFINITIONS = [ 211 # 01, 11 and 12 have spaces among their characters. 212 # Without them shown characters are too close. 213 {'name': '01', 'char': '@ - _ /'}, 214 {'name': '02', 'char': 'ABC'}, 215 {'name': '03', 'char': 'DEF'}, 216 {'name': '04', 'char': 'GHI'}, 217 {'name': '05', 'char': 'JKL'}, 218 {'name': '06', 'char': 'MNO'}, 219 {'name': '07', 'char': 'PQRS'}, 220 {'name': '08', 'char': 'TUV'}, 221 {'name': '09', 'char': 'WXYZ'}, 222 # 10: "a-A" key. Will be modified directly. 223 {'name': '11', 'char': '\' " : ;'}, 224 {'name': '12', 'char': '. , ? !'}, 225 ] 226 227_TWELVEKEYS_ALPHABET_SUPPORT_KEY_DEFINITIONS = [ 228 # 01, 11 and 12 have spaces among their characters. 229 # Without them shown characters are too close. 230 {'name': '01', 'chars': ('@ - _ /', '', '', '', '1')}, 231 {'name': '02', 'chars': ('ABC', '', '', '', '2')}, 232 {'name': '03', 'chars': ('DEF', '', '', '', '3')}, 233 {'name': '04', 'chars': ('GHI', '', '', '', '4')}, 234 {'name': '05', 'chars': ('JKL', '', '', '', '5')}, 235 {'name': '06', 'chars': ('MNO', '', '', '', '6')}, 236 {'name': '07', 'chars': ('PQRS', '', '', '', '7')}, 237 {'name': '08', 'chars': ('TUV', '', '', '', '8')}, 238 {'name': '09', 'chars': ('WXYZ', '', '', '', '9')}, 239 # 10: "a-A" key. Will be modified directly. 240 {'name': '11', 'chars': ('\' " : ;', '', '', '', '0')}, 241 {'name': '12', 'chars': ('. , ? !', '', '', '', '')}, 242 ] 243 244_TWELVEKEYS_ALPHABET_SUPPORT_POPUP_KEY_DEFINITIONS = [ 245 {'name': '01', 'chars': ('@', '-', '_', '/', '1')}, 246 {'name': '02', 'chars': ('A', 'B', 'C', '', '2')}, 247 {'name': '03', 'chars': ('D', 'E', 'F', '', '3')}, 248 {'name': '04', 'chars': ('G', 'H', 'I', '', '4')}, 249 {'name': '05', 'chars': ('J', 'K', 'L', '', '5')}, 250 {'name': '06', 'chars': ('M', 'N', 'O', '', '6')}, 251 {'name': '07', 'chars': ('P', 'Q', 'R', 'S', '7')}, 252 {'name': '08', 'chars': ('T', 'U', 'V', '', '8')}, 253 {'name': '09', 'chars': ('W', 'X', 'Y', 'Z', '9')}, 254 # 10: "a-A" key: twelvekeys__alphabet__10.svg will be used. 255 # Please check mozc/android/resources/res/xml/ 256 {'name': '11', 'chars': (''', '"', ':', ';', '0')}, 257 {'name': '12', 'chars': ('.', ',', '?', '!', '')}, 258 ] 259 260_TWELVEKEYS_KANA_KEYICON_KEY_DEFINITIONS = [ 261 {'name': 'exclamation_mark', 'char': '!'}, 262 {'name': 'ideographic_period', 'char': '。'}, 263 {'name': 'left_parenthesis', 'char': '('}, 264 {'name': 'prolonged_sound_mark', 'char': 'ー'}, 265 {'name': 'question_mark', 'char': '?'}, 266 {'name': 'right_parenthesis', 'char': ')'}, 267 {'name': 'horizontal_ellipsis', 'char': '…'}, 268 {'name': 'wave_dash', 'char': '〜'}, 269 270 {'name': 'a', 'char': 'あ'}, 271 {'name': 'i', 'char': 'い'}, 272 {'name': 'u', 'char': 'う'}, 273 {'name': 'e', 'char': 'え'}, 274 {'name': 'o', 'char': 'お'}, 275 {'name': 'an', 'char': 'あん'}, 276 {'name': 'in', 'char': 'いん'}, 277 {'name': 'un', 'char': 'うん'}, 278 {'name': 'en', 'char': 'えん'}, 279 {'name': 'on', 'char': 'おん'}, 280 {'name': 'axtu', 'char': 'あっ'}, 281 {'name': 'ixtu', 'char': 'いっ'}, 282 {'name': 'uxtu', 'char': 'うっ'}, 283 {'name': 'extu', 'char': 'えっ'}, 284 {'name': 'oxtu', 'char': 'おっ'}, 285 {'name': 'xi', 'char': 'ぃ'}, 286 {'name': 'xe', 'char': 'ぇ'}, 287 288 {'name': 'ka', 'char': 'か'}, 289 {'name': 'ki', 'char': 'き'}, 290 {'name': 'ku', 'char': 'く'}, 291 {'name': 'ke', 'char': 'け'}, 292 {'name': 'ko', 'char': 'こ'}, 293 294 {'name': 'sa', 'char': 'さ'}, 295 {'name': 'shi', 'char': 'し'}, 296 {'name': 'su', 'char': 'す'}, 297 {'name': 'se', 'char': 'せ'}, 298 {'name': 'so', 'char': 'そ'}, 299 300 {'name': 'ta', 'char': 'た'}, 301 {'name': 'chi', 'char': 'ち'}, 302 {'name': 'tsu', 'char': 'つ'}, 303 {'name': 'te', 'char': 'て'}, 304 {'name': 'to', 'char': 'と'}, 305 306 {'name': 'na', 'char': 'な'}, 307 {'name': 'ni', 'char': 'に'}, 308 {'name': 'nu', 'char': 'ぬ'}, 309 {'name': 'ne', 'char': 'ね'}, 310 {'name': 'no', 'char': 'の'}, 311 312 {'name': 'ha', 'char': 'は'}, 313 {'name': 'hi', 'char': 'ひ'}, 314 {'name': 'fu', 'char': 'ふ'}, 315 {'name': 'he', 'char': 'へ'}, 316 {'name': 'ho', 'char': 'ほ'}, 317 318 {'name': 'ma', 'char': 'ま'}, 319 {'name': 'mi', 'char': 'み'}, 320 {'name': 'mu', 'char': 'む'}, 321 {'name': 'me', 'char': 'め'}, 322 {'name': 'mo', 'char': 'も'}, 323 324 {'name': 'ya', 'char': 'や'}, 325 {'name': 'yu', 'char': 'ゆ'}, 326 {'name': 'yo', 'char': 'よ'}, 327 {'name': 'xya', 'char': 'ゃ'}, 328 {'name': 'xyu', 'char': 'ゅ'}, 329 {'name': 'xyo', 'char': 'ょ'}, 330 331 {'name': 'ra', 'char': 'ら'}, 332 {'name': 'ri', 'char': 'り'}, 333 {'name': 'ru', 'char': 'る'}, 334 {'name': 're', 'char': 'れ'}, 335 {'name': 'ro', 'char': 'ろ'}, 336 337 {'name': 'wa', 'char': 'わ'}, 338 {'name': 'wo', 'char': 'を'}, 339 {'name': 'nn', 'char': 'ん'}, 340 ] 341 342_TWELVEKEYS_KANA_SUPPORT_KEY_DEFINITIONS = [ 343 {'name': '01', 344 'chars': ('あ', 'い', 'う', 'え', 'お')}, 345 {'name': '02', 346 'chars': ('か', 'き', 'く', 'け', 'こ')}, 347 {'name': '03', 348 'chars': ('さ', 'し', 'す', 'せ', 'そ')}, 349 {'name': '04', 350 'chars': ('た', 'ち', 'つ', 'て', 'と')}, 351 {'name': '05', 352 'chars': ('な', 'に', 'ぬ', 'ね', 'の')}, 353 {'name': '06', 354 'chars': ('は', 'ひ', 'ふ', 'へ', 'ほ')}, 355 {'name': '07', 356 'chars': ('ま', 'み', 'む', 'め', 'も')}, 357 {'name': '08', 358 'chars': ('や', '(', 'ゆ', ')', 'よ')}, 359 {'name': '09', 360 'chars': ('ら', 'り', 'る', 'れ', 'ろ')}, 361 # 10: "大小" key(twelvekeys__kana__10.svg): Will be modified directly 362 {'name': '11', 363 'chars': ('わ', 'を', 'ん', 'ー', '〜')}, 364 # 12: Needs another template. Defined bellow. 365 ] 366 367_TWELVEKEYS_KANA_SUPPORT_12_KEY_DEFINITION = [ 368 {'name': '12', 369 'chars': ('、', '。', '?', '!', '…')} 370 ] 371 372_TWELVEKEYS_KANA_SUPPORT_POPUP_KEY_DEFINITIONS = [ 373 {'name': '01', 'chars': ('あ', 'い', 'う', 'え', 'お')}, 374 {'name': '02', 'chars': ('か', 'き', 'く', 'け', 'こ')}, 375 {'name': '03', 'chars': ('さ', 'し', 'す', 'せ', 'そ')}, 376 {'name': '04', 'chars': ('た', 'ち', 'つ', 'て', 'と')}, 377 {'name': '05', 'chars': ('な', 'に', 'ぬ', 'ね', 'の')}, 378 {'name': '06', 'chars': ('は', 'ひ', 'ふ', 'へ', 'ほ')}, 379 {'name': '07', 'chars': ('ま', 'み', 'む', 'め', 'も')}, 380 {'name': '08', 'chars': ('や', '(', 'ゆ', ')', 'よ')}, 381 {'name': '09', 'chars': ('ら', 'り', 'る', 'れ', 'ろ')}, 382 # 10: "大小" key: twelvekeys__kana__10.svg will be used. 383 # Please check mozc/android/resources/res/xml/ 384 {'name': '11', 'chars': ('わ', 'を', 'ん', 'ー', '〜')}, 385 {'name': '12', 'chars': ('、', '。', '?', '!', '…')}, 386 ] 387 388_TWELVEKEYS_NUMBER_KEY_DEFINITIONS = [ 389 {'name': 'zero', 'char': '0'}, 390 {'name': 'one', 'char': '1'}, 391 {'name': 'two', 'char': '2'}, 392 {'name': 'three', 'char': '3'}, 393 {'name': 'four', 'char': '4'}, 394 {'name': 'five', 'char': '5'}, 395 {'name': 'six', 'char': '6'}, 396 {'name': 'seven', 'char': '7'}, 397 {'name': 'eight', 'char': '8'}, 398 {'name': 'nine', 'char': '9'}, 399 {'name': 'asterisk', 'char': '*'}, 400 {'name': 'number_sign', 'char': '#'}, 401 ] 402 403_TWELVEKEYS_NUMBER_FUNCTION_KEY_DEFINITIONS = [ 404 {'name': 'comma', 'char': ','}, 405 {'name': 'equals_sign', 'char': '='}, 406 {'name': 'full_stop', 'char': '.'}, 407 {'name': 'hyphen_minus', 'char': '-'}, 408 {'name': 'plus_sign', 'char': '+'}, 409 {'name': 'solidus', 'char': '/'}, 410 ] 411 412_TWELVEKEYS_OTHER_POPUP_DEFINITIONS = [ 413 # number keyboard 414 {'name': 'low_line', 'char': '_'}, 415 {'name': 'quotation_mark', 'char': '"'}, 416 {'name': 'colon', 'char': ':'}, 417 {'name': 'semicolon', 'char': ';'}, 418 # 12keys and godan keyboard 419 {'name': 'ideographic_comma', 'char': '、'}, 420 {'name': 'ideographic_full_stop', 'char': '。'}, 421 # godan keyboard 422 {'name': 'fullwidth_solidus', 'char': '/'}, 423 {'name': 'fullwidth_colon', 'char': ':'}, 424 {'name': 'katakana_middle_dot', 'char': '・'}, 425 {'name': 'left_corner_bracket', 'char': '「'}, 426 {'name': 'right_corner_bracket', 'char': '」'}, 427 ] 428 429def GenerateQwertyAlphabetKeyDefinitions(): 430 """Returns key definitions for qwerty alphabet keys.""" 431 key_definitions = [] 432 for i in range(ord('z') - ord('a') + 1): 433 small = chr(i + ord('a')) 434 capital = chr(i + ord('A')) 435 support = _QWERTY_SUPPORT_KEY_MAPPING.get(small, '') 436 key_definitions.append({ 437 'name': 'latin_capital_letter_' + small, 438 'char': capital, 439 'support': support}) 440 key_definitions.append({ 441 'name': 'latin_small_letter_' + small, 442 'char': small, 443 'support': support}) 444 return key_definitions 445 446 447def GenerateTwelvekeysAlphabetKeyDefinitions(): 448 """Returns key definitions for qwerty alphabet keys.""" 449 key_definitions = [] 450 for i in range(ord('z') - ord('a') + 1): 451 small = chr(i + ord('a')) 452 capital = chr(i + ord('A')) 453 key_definitions.append({ 454 'name': 'latin_' + small, 455 'char': capital}) 456 return key_definitions 457 458 459def ExpandAndWriteSupportKeys(template_file, output_file_basename, output_dir, 460 key_definition_list): 461 """Generates and writes keyicons for support keys from template. 462 463 We will expand keyicons for each flick directions. 464 For example, we will generate XX_center, XX_left, XX_up, XX_right, XX_down 465 adding to XX_release (default, no highlight). 466 Expanded keyicons have highlighted key character corresponding to the flick 467 direction. 468 469 Args: 470 template_file: Path for template file. 471 output_file_basename: A string indicating the base name of the output. 472 output_dir: Destination directory path. 473 key_definition_list: Key definition list. 474 """ 475 for key_definition in key_definition_list: 476 assert len(key_definition['chars']) == len(_REPLACE_CHARS) 477 478 with open(template_file) as template_f: 479 template = template_f.read() 480 481 for i, pattern in enumerate(_REPLACE_CHARS): 482 template = template.replace(pattern, key_definition['chars'][i]) 483 484 for highlight_index, name_suffix in enumerate(_EXPAND_SUPPORT_SUFFIXES): 485 if (highlight_index < len(key_definition['chars']) and 486 not key_definition['chars'][highlight_index]): 487 # We don't need highlighted key for non-existent support. 488 continue 489 490 keytop = template 491 for i, id_pattern in enumerate(_REPLACE_ID_SUFFIXEX): 492 default_id_suffix = ('' if 'id_suffixes' not in key_definition 493 else key_definition['id_suffixes'][i]) 494 id_suffix = default_id_suffix if i != highlight_index else '-highlight' 495 keytop = keytop.replace(id_pattern, id_suffix) 496 497 file_name = '%s__%s_%s.svg' % (output_file_basename, 498 key_definition['name'], 499 name_suffix) 500 with open(os.path.join(output_dir, file_name), 'w') as write_f: 501 write_f.write(keytop) 502 503 504def WriteSupportPopupKeys( 505 template_file, output_file_basename, output_dir, key_definition_list): 506 """Generates and writes keyicons for support popup from template. 507 508 Support popup keys may have 5 key characters to be replaced. 509 510 Args: 511 template_file: Path for template file. 512 output_file_basename: A string indicating the base name of the output. 513 output_dir: Destination directory path. 514 key_definition_list: Key definition list. 515 """ 516 for key_definition in key_definition_list: 517 assert len(key_definition['chars']) == len(_REPLACE_CHARS) 518 519 with open(template_file) as template_f: 520 keytop = template_f.read() 521 for i, pattern in enumerate(_REPLACE_CHARS): 522 keytop = keytop.replace(pattern, key_definition['chars'][i]) 523 524 file_name = '%s__%s.svg' % (output_file_basename, 525 key_definition['name']) 526 with open(os.path.join(output_dir, file_name), 'w') as write_f: 527 write_f.write(keytop) 528 529 530def WriteKeys( 531 template_file, output_file_basename, output_dir, key_definition_list): 532 """Generates and writes keyicons. 533 534 Keys have 1 key character to be replaced. 535 536 Args: 537 template_file: Path for template file. 538 output_file_basename: A string indicating the base name of the output. 539 output_dir: Destination directory path. 540 key_definition_list: Key definition list. 541 """ 542 for key_definition in key_definition_list: 543 assert key_definition['char'] 544 545 with open(template_file) as template_f: 546 keytop = template_f.read() 547 keytop = keytop.replace(_REPLACE_CHAR, key_definition['char']) 548 keytop = keytop.replace(_REPLACE_CHAR_QWERTY_SUPPORT, 549 key_definition.get('support', '')) 550 551 file_name = '%s__%s.svg' % (output_file_basename, 552 key_definition['name']) 553 with open(os.path.join(output_dir, file_name), 'w') as write_f: 554 write_f.write(keytop) 555 556 557def Transform(input_dir, output_dir): 558 """Transforms template .svg files into output_dir.""" 559 ExpandAndWriteSupportKeys( 560 os.path.join(input_dir, 'godan__kana__support__template.svg'), 561 'godan__kana__support', 562 output_dir, 563 _GODAN_KANA_SUPPORT_KEY_DEFINITIONS) 564 565 ExpandAndWriteSupportKeys( 566 os.path.join(input_dir, 'godan__kana__support__12__template.svg'), 567 'godan__kana__support', 568 output_dir, 569 _GODAN_KANA_SUPPORT_12_KEY_DEFINITION) 570 571 WriteSupportPopupKeys( 572 os.path.join(input_dir, 'support__popup__template.svg'), 573 'godan__kana__support__popup', 574 output_dir, 575 _GODAN_KANA_SUPPORT_POPUP_KEY_DEFINITIONS) 576 577 qwerty_definitions = ( 578 _QWERTY_KEYICON_KEY_DEFINITIONS + GenerateQwertyAlphabetKeyDefinitions()) 579 580 WriteKeys( 581 os.path.join(input_dir, 'qwerty__keyicon__template.svg'), 582 'qwerty__keyicon', 583 output_dir, 584 qwerty_definitions) 585 586 WriteKeys( 587 os.path.join(input_dir, 'qwerty__popup__template.svg'), 588 'qwerty__popup', 589 output_dir, 590 [x for x in qwerty_definitions if x.get('support', '')]) 591 592 WriteKeys( 593 os.path.join(input_dir, 'twelvekeys__popup__template.svg'), 594 'twelvekeys__popup', 595 output_dir, 596 GenerateTwelvekeysAlphabetKeyDefinitions()) 597 598 WriteKeys( 599 os.path.join(input_dir, 'twelvekeys__alphabet__template.svg'), 600 'twelvekeys__alphabet', 601 output_dir, 602 _TWELVEKEYS_ALPHABET_KEY_DEFINITIONS) 603 604 WriteKeys( 605 os.path.join(input_dir, 'twelvekeys__alphabet__popup__template.svg'), 606 'twelvekeys__alphabet__popup', 607 output_dir, 608 _TWELVEKEYS_ALPHABET_KEY_DEFINITIONS) 609 610 ExpandAndWriteSupportKeys( 611 os.path.join(input_dir, 612 'twelvekeys__alphabet__support__template.svg'), 613 'twelvekeys__alphabet__support', 614 output_dir, 615 _TWELVEKEYS_ALPHABET_SUPPORT_KEY_DEFINITIONS) 616 617 WriteSupportPopupKeys( 618 os.path.join(input_dir, 'support__popup__template.svg'), 619 'twelvekeys__alphabet__support__popup', 620 output_dir, 621 _TWELVEKEYS_ALPHABET_SUPPORT_POPUP_KEY_DEFINITIONS) 622 623 WriteKeys( 624 os.path.join(input_dir, 'twelvekeys__kana__keyicon__template.svg'), 625 'twelvekeys__kana__keyicon', 626 output_dir, 627 _TWELVEKEYS_KANA_KEYICON_KEY_DEFINITIONS) 628 629 WriteKeys( 630 os.path.join(input_dir, 'twelvekeys__popup__template.svg'), 631 'twelvekeys__popup', 632 output_dir, 633 _TWELVEKEYS_KANA_KEYICON_KEY_DEFINITIONS) 634 635 ExpandAndWriteSupportKeys( 636 os.path.join(input_dir, 'twelvekeys__kana__support__template.svg'), 637 'twelvekeys__kana__support', 638 output_dir, 639 _TWELVEKEYS_KANA_SUPPORT_KEY_DEFINITIONS) 640 641 ExpandAndWriteSupportKeys( 642 os.path.join(input_dir, 643 'twelvekeys__kana__support__12__template.svg'), 644 'twelvekeys__kana__support', 645 output_dir, 646 _TWELVEKEYS_KANA_SUPPORT_12_KEY_DEFINITION) 647 648 WriteSupportPopupKeys( 649 os.path.join(input_dir, 'support__popup__template.svg'), 650 'twelvekeys__kana__support__popup', 651 output_dir, 652 _TWELVEKEYS_KANA_SUPPORT_POPUP_KEY_DEFINITIONS) 653 654 WriteKeys( 655 os.path.join(input_dir, 'twelvekeys__number__template.svg'), 656 'twelvekeys__number', 657 output_dir, 658 _TWELVEKEYS_NUMBER_KEY_DEFINITIONS) 659 660 WriteKeys( 661 os.path.join(input_dir, 'twelvekeys__popup__template.svg'), 662 'twelvekeys__popup', 663 output_dir, 664 _TWELVEKEYS_NUMBER_KEY_DEFINITIONS) 665 666 WriteKeys( 667 os.path.join(input_dir, 668 'twelvekeys__number__function__template.svg'), 669 'twelvekeys__number__function', 670 output_dir, 671 _TWELVEKEYS_NUMBER_FUNCTION_KEY_DEFINITIONS) 672 673 WriteKeys( 674 os.path.join(input_dir, 675 'twelvekeys__popup__template.svg'), 676 'twelvekeys__popup', 677 output_dir, 678 _TWELVEKEYS_NUMBER_FUNCTION_KEY_DEFINITIONS) 679 680 WriteKeys( 681 os.path.join(input_dir, 'twelvekeys__popup__template.svg'), 682 'twelvekeys__popup', 683 output_dir, 684 _TWELVEKEYS_OTHER_POPUP_DEFINITIONS) 685 686 687def ParseOptions(): 688 parser = optparse.OptionParser() 689 parser.add_option('--input_dir', dest='input_dir', 690 help='Input directory containing source svg files.') 691 parser.add_option('--output_dir', dest='output_dir', 692 help='Output directory for generated svg files.') 693 parser.add_option('--output_zip', dest='output_zip', 694 help='Output zip file for generated svg files.') 695 return parser.parse_args()[0] 696 697 698def main(): 699 options = ParseOptions() 700 if not options.input_dir: 701 logging.fatal('You must specify --input_dir.') 702 return 703 if not options.output_dir and not options.output_zip: 704 logging.fatal('You must specify --output_dir and/or --output_zip.') 705 return 706 if options.output_dir: 707 output_dir = options.output_dir 708 if not os.path.exists(output_dir): 709 os.makedirs(output_dir) 710 else: 711 output_dir = tempfile.mkdtemp() 712 Transform(options.input_dir, output_dir) 713 if options.output_zip: 714 with zipfile.ZipFile(options.output_zip, 'w', zipfile.ZIP_DEFLATED) as z: 715 for f in os.listdir(output_dir): 716 if os.path.isdir(f): 717 raise IOError('Restriction: output_dir should not include directory') 718 z.write(os.path.join(output_dir, f), f) 719 720if __name__ == '__main__': 721 main() 722