🔥 obsolete scripts

This commit is contained in:
Mislav Marohnić
2019-05-05 01:58:35 +02:00
parent 3bc9fe0694
commit 987463b50b
6 changed files with 4 additions and 344 deletions

View File

@@ -16,9 +16,6 @@ gem 'gemoji'
### Extract images
To obtain image files as fallbacks for browsers and OS's that don't support
emoji, run the `gemoji extract` command **on macOS Sierra or later**:
``` sh
bundle exec gemoji extract public/images/emoji
```
@@ -26,7 +23,6 @@ bundle exec gemoji extract public/images/emoji
This will extract images into filenames such as:
* `public/images/emoji/octocat.png`
* `public/images/emoji/unicode/1f9c0.png` (the `:cheese:` emoji)
Example Rails Helper

View File

@@ -1,13 +0,0 @@
set jsCode to "document.getElementById('output').value"
set json to missing value
tell application "Safari"
repeat
set json to (do JavaScript jsCode in current tab of window 1)
if (json is not missing value) then exit repeat
delay 0.5
end repeat
close current tab of window 1
end tell
return json

View File

@@ -1,86 +0,0 @@
<!DOCTYPE html>
<title>Emoji alias detection</title>
<style>
textarea {
font-family: monospace;
}
</style>
<p>Save the following as <tt>emoji.json</tt>:</p>
<textarea id="output" rows="50" cols="80"></textarea>
<script>
const VARIATION_SELECTOR_16 = /\ufe0f$/
function detectAliases(db) {
const canvas = document.createElement('canvas')
for (const emoji of db) {
const raw = emoji.emoji
if (!raw) continue
const candidates = [raw]
if (VARIATION_SELECTOR_16.test(raw)) {
candidates.unshift(raw.replace(VARIATION_SELECTOR_16, ''))
} else {
candidates.push(`${raw}\u{fe0f}`)
}
const newRaw = candidates.filter(e => detectEmoji(canvas, e))[0]
if (newRaw && newRaw != raw) {
emoji.emoji = newRaw
console.info('new raw representation found for %s :%s:', raw, emoji.aliases[0])
}
if (!newRaw) {
console.warn('no raw representation for %s :%s:', raw, emoji.aliases[0])
}
}
dump(db)
}
function detectEmoji(canvas, emoji) {
const context = canvas.getContext('2d')
drawEmoji(context, emoji)
let supported = false
const data = context.getImageData(0, 16, 64, 1).data
for (let x = 0; x <= 64; x++) {
if (x <= 32) {
// character is supported if there are any colored pixels found
if (data[4*x] || data[4*x + 1] || data[4*x + 2]) supported = true
} else if (x >= 48 && data[4*x + 3] > 0) {
// however, if more than one character got rendered, treat as unsupported
supported = false
break
}
}
return supported
}
function drawEmoji(context, emoji) {
context.clearRect(0, 0, 400, 400)
context.fillStyle = '#000'
context.textBaseline = 'top'
context.font = '32px sans-serif, "Apple Color Emoji", "Segoe UI", "Segoe UI Emoji", "Segoe UI Symbol"'
context.fillText(emoji+'___', 0, 0)
}
function dump(db) {
var json = JSON.stringify(db, null, ' ')
.replace(/^( +)(.+)\[\](,?)$/mg, "$1$2[\n$1]$3")
.replace(/,\n( *) /g, "\n$1, ")
document.getElementById('output').value = `${json}\n`
}
var xhr = new XMLHttpRequest
xhr.onload = function() {
detectAliases(JSON.parse(xhr.responseText))
};
xhr.open('GET', 'emoji.json', false)
xhr.send(null)
</script>

View File

@@ -1,6 +1,5 @@
# frozen_string_literal: true
require 'emoji/extractor'
require 'fileutils'
require 'optparse'
@@ -37,25 +36,14 @@ module Emoji
puts usage_text
end
VALID_SIZES = [ 20, 32, 40, 48, 64, 96, 160 ]
def extract(argv)
size = 64
OptionParser.new do |opts|
opts.on("--size=#{size}", Integer) do |val|
if VALID_SIZES.include?(val)
size = val
else
raise InvalidUsage, "size should be one of: #{VALID_SIZES.join(', ')}"
end
end
end.parse!(argv)
# OptionParser.new do |opts|
# opts.on("--size=64", Integer) do |size|
# end.parse!(argv)
raise InvalidUsage unless argv.size == 1
path = argv[0]
Emoji::Extractor.new(size, path).extract!
Dir["#{Emoji.images_path}/*.png"].each do |png|
FileUtils.cp(png, File.join(path, File.basename(png)))
end
@@ -63,7 +51,7 @@ module Emoji
def usage_text
<<EOF
Usage: gemoji extract <path> [--size=64]
Usage: gemoji extract <path>
EOF
end
end

View File

@@ -1,192 +0,0 @@
# frozen_string_literal: true
require 'emoji'
require 'fileutils'
module Emoji
class Extractor
EMOJI_TTF = "/System/Library/Fonts/Apple Color Emoji.ttc"
attr_reader :size, :images_path
def initialize(size, images_path)
@size = size
@images_path = images_path
end
def each(&block)
return to_enum(__method__) unless block_given?
File.open(EMOJI_TTF, 'rb') do |file|
font_offsets = parse_ttc(file)
file.pos = font_offsets[0]
tables = parse_tables(file)
glyph_index = extract_glyph_index(file, tables)
each_glyph_bitmap(file, tables, glyph_index, &block)
end
end
def extract!
each do |glyph_name, type, binread|
if emoji = glyph_name_to_emoji(glyph_name)
image_filename = "#{images_path}/#{emoji.image_filename}"
FileUtils.mkdir_p(File.dirname(image_filename))
File.open(image_filename, 'wb') { |f| f.write binread.call }
end
end
end
private
GENDER_MAP = {
"M" => "\u{2642}",
"W" => "\u{2640}",
}
FAMILY_MAP = {
"B" => "\u{1f466}",
"G" => "\u{1f467}",
"M" => "\u{1f468}",
"W" => "\u{1f469}",
}.freeze
FAMILY = "1F46A"
COUPLE = "1F491"
KISS = "1F48F"
def glyph_name_to_emoji(glyph_name)
return if glyph_name =~ /\.[1-5]($|\.)/
zwj = Emoji::ZERO_WIDTH_JOINER
v16 = Emoji::VARIATION_SELECTOR_16
if glyph_name =~ /^u(#{FAMILY}|#{COUPLE}|#{KISS})\.([#{FAMILY_MAP.keys.join('')}]+)$/
if $1 == FAMILY ? $2 == "MWB" : $2 == "WM"
raw = [$1.hex].pack('U')
else
if $1 == COUPLE
middle = "#{zwj}\u{2764}#{v16}#{zwj}" # heavy black heart
elsif $1 == KISS
middle = "#{zwj}\u{2764}#{v16}#{zwj}\u{1F48B}#{zwj}" # heart + kiss mark
else
middle = zwj
end
raw = $2.split('').map { |c| FAMILY_MAP.fetch(c) }.join(middle)
end
candidates = [raw]
else
raw = glyph_name.gsub(/(^|_)u([0-9A-F]+)/) { ($1.empty?? $1 : zwj) + [$2.hex].pack('U') }
raw.sub!(/\.0\b/, '')
raw.sub!(/\.(#{GENDER_MAP.keys.join('|')})$/) { v16 + zwj + GENDER_MAP.fetch($1) }
candidates = [raw]
candidates << raw.sub(v16, '') if raw.include?(v16)
candidates << raw.gsub(zwj, '') if raw.include?(zwj)
candidates.dup.each { |c| candidates << (c + v16) }
end
candidates.map { |c| Emoji.find_by_unicode(c) }.compact.first
end
# https://www.microsoft.com/typography/otspec/otff.htm
def parse_ttc(io)
header_name = io.read(4).unpack('a*')[0]
raise unless "ttcf" == header_name
header_version, num_fonts = io.read(4*2).unpack('l>N')
# parse_version(header_version) #=> 2.0
io.read(4 * num_fonts).unpack('N*')
end
def parse_tables(io)
sfnt_version, num_tables = io.read(4 + 2*4).unpack('Nn')
# sfnt_version #=> 0x00010000
num_tables.times.each_with_object({}) do |_, tables|
tag, checksum, offset, length = io.read(4 + 4*3).unpack('a4N*')
tables[tag] = {
checksum: checksum,
offset: offset,
length: length,
}
end
end
GlyphIndex = Struct.new(:length, :name_index, :names) do
def name_for(glyph_id)
index = name_index[glyph_id]
names[index - 257]
end
def each(&block)
length.times(&block)
end
def each_with_name
each do |glyph_id|
yield glyph_id, name_for(glyph_id)
end
end
end
def extract_glyph_index(io, tables)
postscript_table = tables.fetch('post')
io.pos = postscript_table[:offset]
end_pos = io.pos + postscript_table[:length]
parse_version(io.read(32).unpack('l>')[0]) #=> 2.0
num_glyphs = io.read(2).unpack('n')[0]
glyph_name_index = io.read(2*num_glyphs).unpack('n*')
glyph_names = []
while io.pos < end_pos
length = io.read(1).unpack('C')[0]
glyph_names << io.read(length)
end
GlyphIndex.new(num_glyphs, glyph_name_index, glyph_names)
end
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html
def each_glyph_bitmap(io, tables, glyph_index)
io.pos = sbix_offset = tables.fetch('sbix')[:offset]
strike = extract_sbix_strike(io, glyph_index.length, size)
glyph_index.each_with_name do |glyph_id, glyph_name|
glyph_offset = strike[:glyph_data_offset][glyph_id]
next_glyph_offset = strike[:glyph_data_offset][glyph_id + 1]
if glyph_offset && next_glyph_offset && glyph_offset < next_glyph_offset
io.pos = sbix_offset + strike[:offset] + glyph_offset
x, y, type = io.read(2*2 + 4).unpack('s2A4')
yield glyph_name, type, -> { io.read(next_glyph_offset - glyph_offset - 8) }
end
end
end
def extract_sbix_strike(io, num_glyphs, image_size)
sbix_offset = io.pos
version, flags, num_strikes = io.read(2*2 + 4).unpack('n2N')
strike_offsets = num_strikes.times.map { io.read(4).unpack('N')[0] }
strike_offsets.each do |strike_offset|
io.pos = sbix_offset + strike_offset
ppem, resolution = io.read(4*2).unpack('n2')
next unless ppem == size
data_offsets = io.read(4 * (num_glyphs+1)).unpack('N*')
return {
ppem: ppem,
resolution: resolution,
offset: strike_offset,
glyph_data_offset: data_offsets,
}
end
return nil
end
def parse_version(num)
major = num >> 16
minor = num & 0xFFFF
"#{major}.#{minor}"
end
end
end

View File

@@ -1,33 +0,0 @@
#!/bin/bash
# Usage: script/regenerate
#
# Note: only usable on OS X
#
# Combines `rake db:dump` and `db/aliases.html` filter to regenerate the
# `db/emoji.json` file using only emoji that are guaranteed to not render as
# ordinary characters on OS X.
set -e
case "$1" in
-h | --help )
sed -ne '/^#/!q;s/.\{1,2\}//;1d;p' < "$0"
exit 0
;;
esac
if [ "$(uname -s)" != "Darwin" ]; then
echo "Error: this script must be run under Mac OS X." >&2
exit 1
fi
bundle exec rake db:dump > db/emoji2.json
mv db/emoji2.json db/emoji.json
open -g -a Safari db/aliases.html
osascript db/aliases.applescript | sed '/^$/d' > db/emoji2.json
mv db/emoji2.json db/emoji.json
if git diff --exit-code --stat -- db/emoji.json; then
echo "Done. The file \`db/emoji.json\` remains unchanged."
fi