gemoji 3.0.1 → 4.0.0.pre0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +22 -0
- data/README.md +1 -16
- data/db/emoji.json +10585 -7016
- data/lib/emoji.rb +132 -50
- data/lib/emoji/character.rb +2 -0
- data/lib/gemoji.rb +2 -0
- metadata +8 -29
- data/bin/gemoji +0 -5
- data/db/Category-Emoji.json +0 -71
- data/images/basecamp.png +0 -0
- data/images/basecampy.png +0 -0
- data/images/bowtie.png +0 -0
- data/images/feelsgood.png +0 -0
- data/images/finnadie.png +0 -0
- data/images/goberserk.png +0 -0
- data/images/godmode.png +0 -0
- data/images/hurtrealbad.png +0 -0
- data/images/neckbeard.png +0 -0
- data/images/octocat.png +0 -0
- data/images/rage1.png +0 -0
- data/images/rage2.png +0 -0
- data/images/rage3.png +0 -0
- data/images/rage4.png +0 -0
- data/images/shipit.png +0 -0
- data/images/suspect.png +0 -0
- data/images/trollface.png +0 -0
- data/lib/emoji/cli.rb +0 -68
- data/lib/emoji/extractor.rb +0 -190
data/lib/emoji/extractor.rb
DELETED
@@ -1,190 +0,0 @@
|
|
1
|
-
require 'emoji'
|
2
|
-
require 'fileutils'
|
3
|
-
|
4
|
-
module Emoji
|
5
|
-
class Extractor
|
6
|
-
EMOJI_TTF = "/System/Library/Fonts/Apple Color Emoji.ttc"
|
7
|
-
|
8
|
-
attr_reader :size, :images_path
|
9
|
-
|
10
|
-
def initialize(size, images_path)
|
11
|
-
@size = size
|
12
|
-
@images_path = images_path
|
13
|
-
end
|
14
|
-
|
15
|
-
def each(&block)
|
16
|
-
return to_enum(__method__) unless block_given?
|
17
|
-
|
18
|
-
File.open(EMOJI_TTF, 'rb') do |file|
|
19
|
-
font_offsets = parse_ttc(file)
|
20
|
-
file.pos = font_offsets[0]
|
21
|
-
|
22
|
-
tables = parse_tables(file)
|
23
|
-
glyph_index = extract_glyph_index(file, tables)
|
24
|
-
|
25
|
-
each_glyph_bitmap(file, tables, glyph_index, &block)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def extract!
|
30
|
-
each do |glyph_name, type, binread|
|
31
|
-
if emoji = glyph_name_to_emoji(glyph_name)
|
32
|
-
image_filename = "#{images_path}/#{emoji.image_filename}"
|
33
|
-
FileUtils.mkdir_p(File.dirname(image_filename))
|
34
|
-
File.open(image_filename, 'wb') { |f| f.write binread.call }
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
GENDER_MAP = {
|
42
|
-
"M" => "\u{2642}",
|
43
|
-
"W" => "\u{2640}",
|
44
|
-
}
|
45
|
-
|
46
|
-
FAMILY_MAP = {
|
47
|
-
"B" => "\u{1f466}",
|
48
|
-
"G" => "\u{1f467}",
|
49
|
-
"M" => "\u{1f468}",
|
50
|
-
"W" => "\u{1f469}",
|
51
|
-
}.freeze
|
52
|
-
|
53
|
-
FAMILY = "1F46A"
|
54
|
-
COUPLE = "1F491"
|
55
|
-
KISS = "1F48F"
|
56
|
-
|
57
|
-
def glyph_name_to_emoji(glyph_name)
|
58
|
-
return if glyph_name =~ /\.[1-5]($|\.)/
|
59
|
-
zwj = Emoji::ZERO_WIDTH_JOINER
|
60
|
-
v16 = Emoji::VARIATION_SELECTOR_16
|
61
|
-
|
62
|
-
if glyph_name =~ /^u(#{FAMILY}|#{COUPLE}|#{KISS})\.([#{FAMILY_MAP.keys.join('')}]+)$/
|
63
|
-
if $1 == FAMILY ? $2 == "MWB" : $2 == "WM"
|
64
|
-
raw = [$1.hex].pack('U')
|
65
|
-
else
|
66
|
-
if $1 == COUPLE
|
67
|
-
middle = "#{zwj}\u{2764}#{v16}#{zwj}" # heavy black heart
|
68
|
-
elsif $1 == KISS
|
69
|
-
middle = "#{zwj}\u{2764}#{v16}#{zwj}\u{1F48B}#{zwj}" # heart + kiss mark
|
70
|
-
else
|
71
|
-
middle = zwj
|
72
|
-
end
|
73
|
-
raw = $2.split('').map { |c| FAMILY_MAP.fetch(c) }.join(middle)
|
74
|
-
end
|
75
|
-
candidates = [raw]
|
76
|
-
else
|
77
|
-
raw = glyph_name.gsub(/(^|_)u([0-9A-F]+)/) { ($1.empty?? $1 : zwj) + [$2.hex].pack('U') }
|
78
|
-
raw.sub!(/\.0\b/, '')
|
79
|
-
raw.sub!(/\.(#{GENDER_MAP.keys.join('|')})$/) { v16 + zwj + GENDER_MAP.fetch($1) }
|
80
|
-
candidates = [raw]
|
81
|
-
candidates << raw.sub(v16, '') if raw.include?(v16)
|
82
|
-
candidates << raw.gsub(zwj, '') if raw.include?(zwj)
|
83
|
-
candidates.dup.each { |c| candidates << (c + v16) }
|
84
|
-
end
|
85
|
-
|
86
|
-
candidates.map { |c| Emoji.find_by_unicode(c) }.compact.first
|
87
|
-
end
|
88
|
-
|
89
|
-
# https://www.microsoft.com/typography/otspec/otff.htm
|
90
|
-
def parse_ttc(io)
|
91
|
-
header_name = io.read(4).unpack('a*')[0]
|
92
|
-
raise unless "ttcf" == header_name
|
93
|
-
header_version, num_fonts = io.read(4*2).unpack('l>N')
|
94
|
-
# parse_version(header_version) #=> 2.0
|
95
|
-
io.read(4 * num_fonts).unpack('N*')
|
96
|
-
end
|
97
|
-
|
98
|
-
def parse_tables(io)
|
99
|
-
sfnt_version, num_tables = io.read(4 + 2*4).unpack('Nn')
|
100
|
-
# sfnt_version #=> 0x00010000
|
101
|
-
num_tables.times.each_with_object({}) do |_, tables|
|
102
|
-
tag, checksum, offset, length = io.read(4 + 4*3).unpack('a4N*')
|
103
|
-
tables[tag] = {
|
104
|
-
checksum: checksum,
|
105
|
-
offset: offset,
|
106
|
-
length: length,
|
107
|
-
}
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
GlyphIndex = Struct.new(:length, :name_index, :names) do
|
112
|
-
def name_for(glyph_id)
|
113
|
-
index = name_index[glyph_id]
|
114
|
-
names[index - 257]
|
115
|
-
end
|
116
|
-
|
117
|
-
def each(&block)
|
118
|
-
length.times(&block)
|
119
|
-
end
|
120
|
-
|
121
|
-
def each_with_name
|
122
|
-
each do |glyph_id|
|
123
|
-
yield glyph_id, name_for(glyph_id)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def extract_glyph_index(io, tables)
|
129
|
-
postscript_table = tables.fetch('post')
|
130
|
-
io.pos = postscript_table[:offset]
|
131
|
-
end_pos = io.pos + postscript_table[:length]
|
132
|
-
|
133
|
-
parse_version(io.read(32).unpack('l>')[0]) #=> 2.0
|
134
|
-
num_glyphs = io.read(2).unpack('n')[0]
|
135
|
-
glyph_name_index = io.read(2*num_glyphs).unpack('n*')
|
136
|
-
|
137
|
-
glyph_names = []
|
138
|
-
while io.pos < end_pos
|
139
|
-
length = io.read(1).unpack('C')[0]
|
140
|
-
glyph_names << io.read(length)
|
141
|
-
end
|
142
|
-
|
143
|
-
GlyphIndex.new(num_glyphs, glyph_name_index, glyph_names)
|
144
|
-
end
|
145
|
-
|
146
|
-
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html
|
147
|
-
def each_glyph_bitmap(io, tables, glyph_index)
|
148
|
-
io.pos = sbix_offset = tables.fetch('sbix')[:offset]
|
149
|
-
strike = extract_sbix_strike(io, glyph_index.length, size)
|
150
|
-
|
151
|
-
glyph_index.each_with_name do |glyph_id, glyph_name|
|
152
|
-
glyph_offset = strike[:glyph_data_offset][glyph_id]
|
153
|
-
next_glyph_offset = strike[:glyph_data_offset][glyph_id + 1]
|
154
|
-
|
155
|
-
if glyph_offset && next_glyph_offset && glyph_offset < next_glyph_offset
|
156
|
-
io.pos = sbix_offset + strike[:offset] + glyph_offset
|
157
|
-
x, y, type = io.read(2*2 + 4).unpack('s2A4')
|
158
|
-
yield glyph_name, type, -> { io.read(next_glyph_offset - glyph_offset - 8) }
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def extract_sbix_strike(io, num_glyphs, image_size)
|
164
|
-
sbix_offset = io.pos
|
165
|
-
version, flags, num_strikes = io.read(2*2 + 4).unpack('n2N')
|
166
|
-
strike_offsets = num_strikes.times.map { io.read(4).unpack('N')[0] }
|
167
|
-
|
168
|
-
strike_offsets.each do |strike_offset|
|
169
|
-
io.pos = sbix_offset + strike_offset
|
170
|
-
ppem, resolution = io.read(4*2).unpack('n2')
|
171
|
-
next unless ppem == size
|
172
|
-
|
173
|
-
data_offsets = io.read(4 * (num_glyphs+1)).unpack('N*')
|
174
|
-
return {
|
175
|
-
ppem: ppem,
|
176
|
-
resolution: resolution,
|
177
|
-
offset: strike_offset,
|
178
|
-
glyph_data_offset: data_offsets,
|
179
|
-
}
|
180
|
-
end
|
181
|
-
return nil
|
182
|
-
end
|
183
|
-
|
184
|
-
def parse_version(num)
|
185
|
-
major = num >> 16
|
186
|
-
minor = num & 0xFFFF
|
187
|
-
"#{major}.#{minor}"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|