diff --git a/generate_emoji_thumbnails.py b/generate_emoji_thumbnails.py new file mode 100755 index 000000000..8ca9d4523 --- /dev/null +++ b/generate_emoji_thumbnails.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# Copyright 2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Generate 72x72 thumbnails including aliases. + +Takes a source directory of images named using our emoji filename +conventions and writes thumbnails of them into the destination +directory. If a file is a target of one or more aliases, creates +copies named for the aliases.""" + + +import argparse +import collections +import logging +import os +from os import path +import shutil +import subprocess + +import add_aliases + +from nototools import tool_utils +from nototools import unicode_data + +logger = logging.getLogger('emoji_thumbnails') + +def create_thumbnail(src_path, dst_path): + # uses imagemagik + # we need imagex exactly 72x72 in size, with transparent background + subprocess.check_call([ + 'convert', '-thumbnail', '72x72', '-gravity', 'center', '-background', + 'none', '-extent', '72x72', src_path, dst_path]) + + +def get_inv_aliases(): + """Return a mapping from target to list of sources for all alias + targets in either the default alias table or the unknown_flag alias + table.""" + + inv_aliases = collections.defaultdict(list) + + standard_aliases = add_aliases.read_default_emoji_aliases() + for k, v in standard_aliases.iteritems(): + inv_aliases[v].append(k) + + unknown_flag_aliases = add_aliases.read_emoji_aliases( + 'unknown_flag_aliases.txt') + for k, v in unknown_flag_aliases.iteritems(): + inv_aliases[v].append(k) + + return inv_aliases + + +def filename_to_sequence(filename, prefix, suffix): + if not filename.startswith(prefix) and filename.endswith(suffix): + raise ValueError('bad prefix or suffix: "%s"' % filename) + seq_str = filename[len(prefix): -len(suffix)] + seq = unicode_data.string_to_seq(seq_str) + if not unicode_data.is_cp_seq(seq): + raise ValueError('sequence includes non-codepoint: "%s"' % filename) + return seq + + +def sequence_to_filename(seq, prefix, suffix): + return ''.join((prefix, unicode_data.seq_to_string(seq), suffix)) + + +def create_thumbnails_and_aliases(src_dir, dst_dir, dst_prefix): + """Creates thumbnails in dst_dir based on sources in src.dir, using + dst_prefix. Assumes the source prefix is 'emoji_u' and the common suffix + is '.png'.""" + + if not path.isdir(src_dir): + raise ValueError('"%s" is not a directory') + dst_dir = tool_utils.ensure_dir_exists(dst_dir) + + src_prefix = 'emoji_u' + suffix = '.png' + + inv_aliases = get_inv_aliases() + + for src_file in os.listdir(src_dir): + try: + seq = unicode_data.strip_emoji_vs( + filename_to_sequence(src_file, src_prefix, suffix)) + except ValueError as ve: + logger.warning('Error (%s), skipping' % ve) + continue + + src_path = path.join(src_dir, src_file) + + dst_file = sequence_to_filename(seq, dst_prefix, suffix) + dst_path = path.join(dst_dir, dst_file) + + create_thumbnail(src_path, dst_path) + logger.info('wrote thumbnail: %s' % dst_file) + + for alias_seq in inv_aliases.get(seq, ()): + alias_file = sequence_to_filename(alias_seq, dst_prefix, suffix) + alias_path = path.join(dst_dir, alias_file) + shutil.copy2(dst_path, alias_path) + logger.info('wrote alias: %s' % alias_file) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-s', '--src_dir', help='source images', metavar='dir', required=True) + parser.add_argument( + '-d', '--dst_dir', help='destination directory', metavar='dir', + required=True) + parser.add_argument( + '-p', '--prefix', help='prefix for thumbnail', metavar='str', + default='android_') + parser.add_argument( + '-v', '--verbose', help='write log output', metavar='level', + choices='warning info debug'.split(), const='info', + nargs='?') + args = parser.parse_args() + + if args.verbose is not None: + logging.basicConfig(level=getattr(logging, args.verbose.upper())) + + create_thumbnails_and_aliases( + args.src_dir, args.dst_dir, args.prefix) + + +if __name__ == '__main__': + main() diff --git a/unknown_flag_aliases.txt b/unknown_flag_aliases.txt new file mode 100644 index 000000000..3708463ab --- /dev/null +++ b/unknown_flag_aliases.txt @@ -0,0 +1,25 @@ +# alias table +# from;to +# the 'from' sequence should be represented by the image for the 'to' sequence +# these are flags we explicitly omit + +# flag aliases +1f1e7_1f1f1;fe82b # BL +1f1e7_1f1f6;fe82b # BQ +1f1e9_1f1ec;fe82b # DG +1f1ea_1f1e6;fe82b # EA +1f1ea_1f1ed;fe82b # EH +1f1eb_1f1f0;fe82b # FK +1f1ec_1f1eb;fe82b # GF +1f1ec_1f1f5;fe82b # GP +1f1ec_1f1f8;fe82b # GS +1f1f2_1f1eb;fe82b # MF +1f1f2_1f1f6;fe82b # MQ +1f1f3_1f1e8;fe82b # NC +1f1f5_1f1f2;fe82b # PM +1f1f7_1f1ea;fe82b # RE +1f1f9_1f1eb;fe82b # TF +1f1fc_1f1eb;fe82b # WF +1f1fd_1f1f0;fe82b # XK +1f1fe_1f1f9;fe82b # YT +