Initial code commit

* inserted scripts
* changed README
This commit is contained in:
Jan Schilbach
2022-09-22 13:37:46 +02:00
parent 5ca6ff13fa
commit 337dfa050e
77 changed files with 1419532 additions and 81 deletions
+17
View File
@@ -0,0 +1,17 @@
require "#{File.dirname(File.expand_path(__FILE__))}/extract_info_lib.rb"
require 'yaml'
base_font_directory = ARGV[0]
search_font_directory = ARGV[1]
base_font_infos = {}
(Dir.glob("#{base_font_directory}/*.[ot]tf") + Dir.glob("#{base_font_directory}/**/*.[ot]tf")).each{|font_file|
_infos = extract_infos_for_font(font_file)
base_font_infos[_infos['Family']] = {} unless base_font_infos[_infos['Family']]
base_font_infos[_infos.delete('Family')][_infos.delete('Subfamily')] = _infos
}
puts base_font_infos.to_yaml
+38
View File
@@ -0,0 +1,38 @@
def extract_infos_for_font(font_file)
infos_string = `otfinfo -i '#{font_file}'`
unless $?.to_i == 0
infos = {}
else
infos = {}
key = nil
infos_string.each_line{|line|
if not(line =~ /^This license is/) and line =~ /(?=\n|^)([A-Za-z ]+):[[:space:]]/
if key and infos[key]
infos[key] = infos[key].strip
end
key = $1
line.gsub!(/(?=\n|^)([A-Za-z ]+):[[:space:]]/,'')
end
if key
if infos[key]
infos[key] += line
else
infos[key] = line
end
end
}
if key and infos[key]
infos[key] = infos[key].strip
end
end
features = `otfinfo -f '#{font_file}'`.lines.to_a.collect{|line| line.split(/[[:space:]]+/,2).collect(&:strip)}
features = [] unless $?.to_i == 0
glyphs = `otfinfo -u '#{font_file}'`.lines.to_a.collect{|line| line.strip.split(/[[:space:]]+/)}
glyphs = [] unless $?.to_i == 0
return infos.merge(:features => features, :glyphs => glyphs)
end
+390
View File
@@ -0,0 +1,390 @@
# coding: utf-8
require "yaml"
require "csv"
require "unicode/categories"
class FontManager
require "#{File.dirname(__FILE__)}/models/font_db_connection.rb"
require "#{File.dirname(__FILE__)}/models/feature.rb"
require "#{File.dirname(__FILE__)}/models/font_feature.rb"
require "#{File.dirname(__FILE__)}/models/font_glyph.rb"
require "#{File.dirname(__FILE__)}/models/font.rb"
require "#{File.dirname(__FILE__)}/models/glyph.rb"
require "#{File.dirname(__FILE__)}/extract_info_lib.rb"
require "#{File.dirname(__FILE__)}/extract_info_lib.rb"
require "#{File.dirname(__FILE__)}/pdf_creator.rb"
RANKING_CONFIGURATION = {
:features => 1,
:glyphs => 10,
:sub_families => 50
}
DIACRITICS = ("0300".hex.."036F".hex).to_a + ("1AB0".hex.."1AFF".hex).to_a + ("1DC0".hex.."1DFF".hex).to_a + ("20D0".hex.."20FF".hex).to_a + ("FE20".hex.."FE2F".hex).to_a
SERIF_FAMILIES = ["EB Garamond 08", "Literata Book Medium", "Literata Book SemiBold", "Literata", "Alegreya Black", "Alegreya ExtraBold", "Alegreya Medium", "EB Garamond 12", "Libertinus Serif Semibold", "Noto Serif Blk", "Noto Serif Cond Blk", "Noto Serif Cond ExtBd", "Noto Serif Cond ExtLt", "Noto Serif Cond Light", "Noto Serif Cond Med", "Noto Serif Cond SemBd", "Noto Serif Cond Thin", "Noto Serif ExtBd", "Noto Serif ExtCond Blk", "Noto Serif ExtCond ExtBd", "Noto Serif ExtCond ExtLt", "Noto Serif ExtCond Light", "Noto Serif ExtCond Med", "Noto Serif ExtCond SemBd", "Noto Serif ExtCond Thin", "Noto Serif ExtLt", "Noto Serif Light", "Noto Serif Med", "Noto Serif SemBd", "Noto Serif SemCond Blk", "Noto Serif SemCond ExtBd", "Noto Serif SemCond ExtLt", "Noto Serif SemCond Light", "Noto Serif SemCond Med", "Noto Serif SemCond SemBd", "Noto Serif SemCond Thin", "Noto Serif Thin", "Alegreya", "Literata Book", "Linux Libertine O", "Libertinus Serif", "Noto Serif Cond", "Noto Serif ExtCond", "Noto Serif SemCond", "Noto Serif"]
SANS_SERIF_FAMILIES = ["Fira Sans Condensed ExtraLight", "Fira Sans Condensed ExtraBold", "Fira Sans Condensed Light", "Fira Sans Condensed Medium", "Fira Sans Condensed SemiBold", "Fira Sans Condensed Thin", "Fira Sans Compressed ExtraBold", "Fira Sans Compressed Heavy", "Fira Sans Compressed Medium", "Fira Sans Compressed SemiBold", "Fira Sans Compressed Book", "Fira Sans Compressed Eight", "Fira Sans Compressed ExtraLight", "Fira Sans Compressed Four", "Fira Sans Compressed Hair", "Fira Sans Compressed Light", "Fira Sans Compressed Thin", "Fira Sans Compressed Two", "Fira Sans Compressed UltraLight", "Fira Sans Eight", "Fira Sans Four", "Fira Sans Hair", "Fira Sans Two", "Fira Sans Ultra", "Fira Sans Black", "Fira Sans Condensed Black", "Fira Sans Extra Condensed Black", "Fira Sans Extra Condensed ExtraBold", "Fira Sans Extra Condensed ExtraLight", "Fira Sans Extra Condensed Light", "Fira Sans Extra Condensed Medium", "Fira Sans Extra Condensed SemiBold", "Fira Sans Extra Condensed Thin", "Fira Sans Book", "Fira Sans ExtraBold", "Fira Sans ExtraLight", "Fira Sans Heavy", "Fira Sans SemiBold", "Fira Sans Thin", "Fira Sans UltraLight", "Fira Sans Light", "Fira Sans Medium", "Alegreya Sans Black", "Alegreya Sans ExtraBold", "Alegreya Sans Light", "Alegreya Sans Medium", "Alegreya Sans Thin", "Noto Sans Blk", "Noto Sans Cond Blk", "Noto Sans Cond ExtBd", "Noto Sans Cond ExtLt", "Noto Sans Cond Light", "Noto Sans Cond Med", "Noto Sans Cond SemBd", "Noto Sans Cond Thin", "Noto Sans ExtBd", "Noto Sans ExtCond Blk", "Noto Sans ExtCond ExtBd", "Noto Sans ExtCond ExtLt", "Noto Sans ExtCond Light", "Noto Sans ExtCond Med", "Noto Sans ExtCond SemBd", "Noto Sans ExtCond Thin", "Noto Sans ExtLt", "Noto Sans Light", "Noto Sans Med", "Noto Sans SemBd", "Noto Sans SemCond Blk", "Noto Sans SemCond ExtBd", "Noto Sans SemCond ExtLt", "Noto Sans SemCond Light", "Noto Sans SemCond Med", "Noto Sans SemCond SemBd", "Noto Sans SemCond Thin", "Noto Sans Thin", "Libertinus Sans", "Fira Sans Condensed", "Alegreya Sans", "Fira Sans", "Fira Sans Compressed", "Fira Sans Extra Condensed", "Noto Sans", "Noto Sans Cond", "Noto Sans ExtCond", "Noto Sans SemCond", "Linux Biolinum O"]
LOW_GLYPH_COVERAGE = ["PT Serif", "Junicode", "Libre Caslon Text", "PT Serif Caption", "Fanwood Text", "Alegreya Sans", "Fira Sans", "Fira Sans Condensed", "Alegreya Sans Thin", "Alegreya Sans Medium", "Alegreya Sans ExtraBold", "Alegreya Sans Black", "Fira Sans Condensed Thin", "Fira Sans Condensed Thin", "Fira Sans Condensed SemiBold", "Fira Sans Condensed Medium", "Fira Sans Condensed Light", "Fira Sans Condensed ExtraBold", "Fira Sans Condensed ExtraLight", "Alegreya Sans Light", "Alegreya", "Alegreya Medium", "Alegreya ExtraBold", "Alegreya Black", "EB Garamond 08"]
SENSELESS_FONTS = ["Fira Sans Two", "Fira Sans Hair", "Fira Sans Four", "Fira Sans Eight", "Fira Sans Compressed Two", "Fira Sans Compressed Four", "Fira Sans Compressed Eight"]
NO_FRENCH_REN_ANTIGUA_FONTS = ["Noto Serif", "Noto Serif Blk", "Noto Serif Cond Blk", "Noto Serif Cond ExtBd", "Noto Serif Cond ExtLt", "Noto Serif Cond Light", "Noto Serif Cond Med", "Noto Serif Cond SemBd", "Noto Serif Cond Thin", "Noto Serif ExtBd", "Noto Serif ExtCond Blk", "Noto Serif ExtCond ExtBd", "Noto Serif ExtCond ExtLt", "Noto Serif ExtCond Light", "Noto Serif ExtCond Med", "Noto Serif ExtCond SemBd", "Noto Serif ExtCond Thin", "Noto Serif ExtLt", "Noto Serif Light", "Noto Serif Med", "Noto Serif SemBd", "Noto Serif SemCond Blk", "Noto Serif SemCond ExtBd", "Noto Serif SemCond ExtLt", "Noto Serif SemCond Light", "Noto Serif SemCond Med", "Noto Serif SemCond SemBd", "Noto Serif SemCond Thin", "Noto Serif Thin", "Noto Serif Cond", "Noto Serif ExtCond", "Noto Serif SemCond", "Literata Book", "Literata Book"]
class << self
def fill_font_lib(directory)
font_files = (Dir.glob("#{directory}/*.[ot]tf") + Dir.glob("#{directory}/**/*.[ot]tf"))
font_files.sort!
count = font_files.length
font_files.each_with_index{|font_file, index|
puts "#{(index + 1).to_s.rjust(7)}/#{count} (#{(((index + 1)/count.to_f)*100).round(2)}%) #{font_file}"
font_info_hash = extract_infos_for_font(font_file)
import_into_db(font_file, font_info_hash)
}
end
def import_into_db(font_file, info_hash)
begin
raise "Name, Family und Subfamily werden erwartet (gefunden: #{info_hash.keys}) #{font_file}" unless info_hash["Family"] and (info_hash["Subfamily"] or info_hash["Preferred subfamily"]) and info_hash["Full name"]
font = Font.where(:name => info_hash["Full name"], :family => info_hash["Family"], :sub_family => (info_hash["Subfamily"] ? info_hash["Subfamily"] : info_hash["Preferred subfamily"])).first_or_initialize
font.add_file_location(font_file)
font.add_infos_from_hash(info_hash)
font.save!
rescue StandardError => e
puts "Problem mit #{font_file}"
puts e.message
end
end
def all_fonts
Font.all
end
def create_csv(csv_file_name: 'config/chars.csv', base_font_name: 'De-Gruyter-Regular', first_alt_sans_font_family: 'Noto Sans SemCond', first_alt_serif_font_family: 'Noto Serif SemCond')
all_unicode_points = Font.where(name: base_font_name).first.glyphs.pluck(:unicode_point)
all_unicode_points += (Font.where(family: first_alt_sans_font_family).first.glyph_code_points_contained_in_all_sub_families & Font.where(family: first_alt_serif_font_family).first.glyph_code_points_contained_in_all_sub_families)
all_unicode_points.uniq!
all_unicode_points.sort!
sans_regular_alt = Font.where(family: first_alt_sans_font_family).first.regular_font
sans_italic_alt = Font.where(family: first_alt_sans_font_family).first.italic_font
sans_bold_alt = Font.where(family: first_alt_sans_font_family).first.bold_font
sans_bold_italic_alt = Font.where(family: first_alt_sans_font_family).first.bold_italic_font
serif_regular_alt = Font.where(family: first_alt_serif_font_family).first.regular_font
serif_italic_alt = Font.where(family: first_alt_serif_font_family).first.italic_font
serif_bold_alt = Font.where(family: first_alt_serif_font_family).first.bold_font
serif_bold_italic_alt = Font.where(family: first_alt_serif_font_family).first.bold_italic_font
sans_regular_alt_file = File.basename(sans_regular_alt.file_locations.first)
sans_italic_alt_file = File.basename(sans_italic_alt.file_locations.first)
sans_bold_alt_file = File.basename(sans_bold_alt.file_locations.first)
sans_bold_italic_alt_file = File.basename(sans_bold_italic_alt.file_locations.first)
serif_regular_alt_file = File.basename(serif_regular_alt.file_locations.first)
serif_italic_alt_file = File.basename(serif_italic_alt.file_locations.first)
serif_bold_alt_file = File.basename(serif_bold_alt.file_locations.first)
serif_bold_italic_alt_file = File.basename(serif_bold_italic_alt.file_locations.first)
CSV::open(csv_file_name, 'w:utf-8', col_sep: ';') do |csv_object|
csv_object << ["char",'codepoint','sans-regular','sans-italic','sans-bold','sans-bold-italic','serif-regular','serif-italic','serif-bold','serif-bold-italic',"in-#{base_font_name.downcase}"]
all_unicode_points.each do |unicode_point|
code_point = unicode_point.gsub('uni','')
char = code_point.hex.chr(Encoding::UTF_8)
sans_regular = (sans_regular_alt.glyphs.where(unicode_point: unicode_point).exists? ? sans_regular_alt_file : nil)
sans_italic = (sans_italic_alt.glyphs.where(unicode_point: unicode_point).exists? ? sans_italic_alt_file : nil)
sans_bold = (sans_bold_alt.glyphs.where(unicode_point: unicode_point).exists? ? sans_bold_alt_file : nil)
sans_bold_italic = (sans_bold_italic_alt.glyphs.where(unicode_point: unicode_point).exists? ? sans_bold_italic_alt_file : nil)
serif_regular = (serif_regular_alt.glyphs.where(unicode_point: unicode_point).exists? ? serif_regular_alt_file : nil)
serif_italic = (serif_italic_alt.glyphs.where(unicode_point: unicode_point).exists? ? serif_italic_alt_file : nil)
serif_bold = (serif_bold_alt.glyphs.where(unicode_point: unicode_point).exists? ? serif_bold_alt_file : nil)
serif_bold_italic = (serif_bold_italic_alt.glyphs.where(unicode_point: unicode_point).exists? ? serif_bold_italic_alt_file : nil)
in_base = Font.where(name: base_font_name).first.glyphs.where(unicode_point: unicode_point).exists?
csv_object << [char, code_point, sans_regular, sans_italic, sans_bold, sans_bold_italic, serif_regular, serif_italic, serif_bold, serif_bold_italic, in_base]
end
end
end
def find_alternative_family(source_family,
must_have_features: ["c2sc", "case", "ccmp", "frac", "kern", "liga", "onum", "pnum", "tnum", "smcp"],
must_have_glyphs: [
"uni0041", # A -> Latin
"uni00C0", # À -> Latin extended
"uni0396", # Ζ -> griechisch
"uni1F00" # ἀ -> altgriechisch
])
font = Font.where(:family => source_family).first
source_sub_families = font.sub_families
source_glyph_code_points = font.glyph_code_points_contained_in_all_sub_families
source_features = font.feature_short_names_contained_in_all_sub_families
source_sub_families_count = source_sub_families.length
source_glyph_code_points_count = source_glyph_code_points.length
source_features_count = source_features.length
all_fonts = Font.all
fonts_with_all_must_have_features = all_fonts.select{|font| (must_have_features - font.features.pluck(:short_name)).empty?}
fonts_with_all_must_have_glyphs_and_all_must_have_features = fonts_with_all_must_have_features.select{|font| (must_have_glyphs - font.glyphs.pluck(:unicode_point)).empty?}
other_families_array = (fonts_with_all_must_have_glyphs_and_all_must_have_features.collect(&:family) - [source_family]).uniq.collect{|other_family|
first_family_font = Font.where(:family => other_family).first
_sub_families = first_family_font.sub_families
_glyph_code_points = first_family_font.glyph_code_points_contained_in_all_sub_families
_features = first_family_font.feature_short_names_contained_in_all_sub_families
missing_sub_families_count = (source_sub_families - _sub_families).length
missing_glyph_code_points_count = (source_glyph_code_points - _glyph_code_points).length
missing_features_count = (source_features - _features).length
percentage_sub_families = ((source_sub_families_count - missing_sub_families_count) / source_sub_families_count.to_f)
percentage_glyphs = ((source_glyph_code_points_count - missing_glyph_code_points_count) / source_glyph_code_points_count.to_f)
percentage_features = ((source_features_count - missing_features_count) / source_features_count.to_f)
[percentage_sub_families, percentage_glyphs, percentage_features, other_family, first_family_font]
}.sort_by{|family_array|
percentage_sub_families = family_array[0]
percentage_glyphs = family_array[1]
percentage_features = family_array[2]
other_family = family_array[3]
###
### Calculate Ranking
((percentage_sub_families * RANKING_CONFIGURATION[:sub_families]) + (percentage_glyphs * RANKING_CONFIGURATION[:glyphs]) + (percentage_features * RANKING_CONFIGURATION[:features])) / (RANKING_CONFIGURATION[:sub_families] + RANKING_CONFIGURATION[:glyphs] + RANKING_CONFIGURATION[:features]).to_f
}
other_families_array.reject!{|family_array|
(["Regular", "Italic"] - family_array[4].family_fonts.pluck(:sub_family)).length > 0
}
other_families_array.each{|family_array|
percentage_sub_families = family_array[0]
percentage_glyphs = family_array[1]
percentage_features = family_array[2]
other_family = family_array[3]
font = family_array[4]
puts "#{font.id.to_s.ljust(6)} #{other_family.ljust(60)} #{(percentage_sub_families * 100).to_s.ljust(5)} #{(percentage_glyphs * 100).round(2).to_s.ljust(5)} #{(percentage_features * 100).to_s.ljust(5)} #{font.family_fonts.pluck(:sub_family).join(", ")}"
}
return other_families_array.collect{|family_array| family_array[3]}
end
def pdf_for_best_alternative_fonts(source_family, output_pdf: 'test.pdf', exclude: [])
other_families = find_alternative_family(source_family)
other_families -= exclude
#PdfCreator.create_comparison_pdf(output_pdf, other_families.last(limit).reverse, base_font_family: source_family)
PdfCreator.create_fonts_tex_pdf(output_pdf, other_families.reverse, source_family)
end
def create_new_fonts(chars_config_file: 'config/chars.csv', config_file: 'config/config.yaml', source_font_dir: 'source_fonts/', target_font_dir: 'output/', new_font_name: 'De Gruyter', base_font_regex: nil)
table = CSV.parse(File.read(chars_config_file), headers: true, col_sep: ';')
font_config = YAML.load(File.read(config_file))
code_points = table.by_col[1]
FileUtils.mkdir_p(target_font_dir) unless File.directory?(target_font_dir)
table.headers.each_with_index{|table_header, table_header_index|
next if table_header == 'char'
next if table_header == 'codepoint'
next if table_header.start_with?("in-")
all_font_definitions = table.by_col[table_header_index]
recombined_fonts = all_font_definitions.compact.select{|fd| fd.gsub(/\([^)]+\)$/,'') != fd}.uniq.collect{|fd| fd.gsub(/\([^)]+\)$/,'')}
all_used_fonts = table.by_col[table_header_index].collect{|font|
if font
font.gsub(/\([^)]*\)$/,'')
else
nil
end
}
used_fonts = all_used_fonts.compact
base_font = used_fonts.max_by{|uf| used_fonts.count(uf)}
if base_font_regex and regex_base_font = used_fonts.find{|uf| uf =~ base_font_regex}
base_font = regex_base_font
end
sub_family = table_header.to_s.gsub("-",' ').split(" ").collect(&:capitalize).join(" ")
type = "Sans"
if sub_family =~ /Serif/
type = "Serif"
end
sub_family.gsub!("Sans","")
sub_family.gsub!("Serif","")
sub_family.strip!
puts "##########################################"
puts "##########################################"
puts "##########################################"
puts "Subfamily: #{sub_family}"
puts "Type: #{type}"
puts "BaseFont: #{base_font}"
additional_fonts = recombined_fonts + (used_fonts.uniq - [base_font])
additional_fonts.uniq!
puts "AdditionalFonts: #{additional_fonts}"
output_font_name = "#{new_font_name.gsub(' ', '-')}-#{type}-#{sub_family.gsub(" ","-")}"
output_font_family_name = "#{new_font_name} #{type}"
Dir.mktmpdir do |tmp_dir|
_tmp_base_font = File.join(source_font_dir, base_font)
if additional_fonts.empty?
puts "Rename Original Font #{base_font} to #{new_font_name.gsub(' ', '-')}-#{sub_family.gsub(" ","-")}"
insert_glyphs_in_font_file(
source_font: _tmp_base_font,
target_font: _tmp_base_font,
output_font_family_name: output_font_family_name,
output_font_name: output_font_name,
output_path: "#{tmp_dir}/",
code_points: []
)
_tmp_base_font = File.join(tmp_dir, "#{new_font_name.gsub(' ', '-')}-#{type}-#{sub_family.gsub(" ","-")}.otf")
else
additional_fonts.each{|additional_font|
puts "Additional Font #{additional_font}"
code_points_to_replace = code_points.select.with_index{|code_point, index|
all_used_fonts[index] == additional_font
}.collect{|code_point| "uni#{code_point}"}
code_points_to_replace = [] if additional_font == base_font
code_points_to_replace_with_other = code_points.collect.with_index{|code_point, index|
if all_font_definitions[index] && all_font_definitions[index].gsub(/\([^)]+\)$/,'') != all_font_definitions[index] && all_font_definitions[index].gsub(/\([^)]+\)$/,'') == additional_font
["uni#{code_point}", all_font_definitions[index].gsub(/.*\(([^)]*)\)$/,'\1').codepoints.collect{|cp| "uni#{cp.to_s(16)}"}]
else
nil
end
}.compact.to_h
puts "Insert #{code_points_to_replace} from #{additional_font} into #{_tmp_base_font}"
insert_glyphs_in_font_file(
source_font: File.join(source_font_dir, additional_font),
target_font: _tmp_base_font,
output_font_family_name: output_font_family_name,
output_font_name: output_font_name,
output_path: "#{tmp_dir}/",
code_points: code_points_to_replace,
code_points_to_replace_with_other: code_points_to_replace_with_other
)
_tmp_base_font = File.join(tmp_dir, "#{new_font_name.gsub(' ', '-')}-#{type}-#{sub_family.gsub(" ","-")}.otf")
puts "AAAAAAAAAAAAAAAAAAA"
puts _tmp_base_font
puts Dir.glob("#{tmp_dir}/*")
}
end
adjust_font(
source_font_file: _tmp_base_font,
target_font_file: "#{target_font_dir}/#{output_font_name}.otf",
font_name: output_font_name,
family_name: output_font_family_name,
weight: sub_family,
scaling: font_config[:scaling],
ascent: font_config[:ascent],
descent: font_config[:descent],
version: font_config[:version],
copyright: font_config[:copyright]
)
end
}
end
def insert_glyphs_in_font_file(source_font: Font.find(9), target_font: Font.find(2000), output_font_name: "NewFont", output_font_family_name: "NewFont Sans", output_path: "#{File.dirname(__FILE__)}/", code_points: ["uni0041", "uni0393", "uni0394", "uni0395", "uni0396", "uni0397"], code_points_to_replace_with_other: {})
puts code_points_to_replace_with_other.to_yaml
source_font_location = source_font.file_locations.first if source_font.is_a?(Font)
target_font_location = target_font.file_locations.first if target_font.is_a?(Font)
source_font_location ||= source_font
target_font_location ||= target_font
Dir.mktmpdir do |dir|
FileUtils.cp(source_font_location, "#{dir}/source_font#{File.extname(source_font_location)}")
FileUtils.cp(target_font_location, "#{dir}/target_font#{File.extname(target_font_location)}")
unless code_points.empty?
File.open("#{dir}/glyphs.txt",'w+'){|file|
code_points.each{|code_point| file.puts code_point }
}
FileUtils.cp("bin/merge_fonts.py", "#{dir}/")
puts `cd #{dir}; fontforge -lang=py -script merge_fonts.py glyphs.txt source_font#{File.extname(source_font_location)} #{dir}/target_font#{File.extname(target_font_location)} #{output_font_name} '#{output_font_family_name}'`
end
if !code_points_to_replace_with_other.keys.empty?
code_points_to_replace_with_other.each{|target_glyph, source_glyphs|
if File.exists?("#{dir}/#{output_font_name}.otf")
FileUtils.cp("#{dir}/#{output_font_name}.otf", "#{dir}/source_font#{File.extname(source_font_location)}")
else
FileUtils.cp("#{dir}/target_font#{File.extname(target_font_location)}", "#{dir}/source_font#{File.extname(source_font_location)}")
end
FileUtils.cp("bin/combine_glyphs.ff", "#{dir}/")
command = "cd #{dir}; fontforge -script combine_glyphs.ff source_font#{File.extname(source_font_location)} #{output_font_name} '#{output_font_family_name}' #{target_glyph} #{source_glyphs.join(" ")}"
puts command
puts `#{command}`
}
end
FileUtils.cp("#{dir}/#{output_font_name}.otf", "#{output_path}/")
end
end
def adjust_font(source_font_file: , target_font_file:, font_name:, family_name:, unique_id: nil, weight: "Regular", scaling: 1.0, version: 1.00, ascent: 800, descent: 200, copyright: "" )
unless unique_id
name_1 = font_name.gsub(/[[:punct:][:space:]]/,'').upcase
unique_id = "#{version};#{name_1.upcase[0..3]};#{font_name}"
end
command = "fontforge -script #{File.join(File.dirname(__FILE__), '..', 'bin')}/adjust_font.ff #{source_font_file} #{target_font_file} '#{font_name}' '#{weight}' '#{family_name}' '#{unique_id}' '#{version}' '#{copyright}' #{scaling} #{ascent} #{descent}"
puts command
puts `#{command}`
end
def create_math_font(new_font_name: "De Gruyter", type: "Sans", sub_family: "Regular", config_file: 'config/config.yaml', source_math_font: 'source_fonts/NotoSansMath-Regular.ttf', target_font_dir: "output/", copyright: "Based on Noto Sans Math (Noto: Copyright 2015 Google Inc. All Rights Reserved.)")
font_config = YAML.load(File.read(config_file))
output_font_name = "#{new_font_name.gsub(' ', '-')}-#{type}-Math-#{sub_family.gsub(" ","-")}"
output_font_family_name = "#{new_font_name} #{type} Math"
adjust_font(
source_font_file: source_math_font,
target_font_file: "#{target_font_dir}/#{output_font_name}.otf",
font_name: output_font_name,
family_name: output_font_family_name,
weight: sub_family,
scaling: font_config[:scaling],
ascent: font_config[:ascent],
descent: font_config[:descent],
version: font_config[:version],
copyright: copyright
)
end
end
end
+4
View File
@@ -0,0 +1,4 @@
class Feature < FontDbConnection
has_many :font_features
has_many :features, through: :font_features
end
+181
View File
@@ -0,0 +1,181 @@
# coding: utf-8
class Font < FontDbConnection
has_many :font_glyphs
has_many :glyphs, -> { distinct }, through: :font_glyphs
has_many :font_features
has_many :features, -> { distinct }, through: :font_features
serialize :license, JSON
serialize :file_locations, JSON
serialize :misc_informations, JSON
def add_infos_from_hash(hash)
add_license_informations(hash)
add_misc_informations(hash)
add_feature_informations(hash)
add_glyph_informations(hash)
end
def add_license_informations(hash)
self.license = hash.slice("License", "License URL", "License Description", "Copyright")
end
def add_misc_informations(hash)
_hash = hash.dup
_hash.delete("Family")
_hash.delete("Subfamily")
_hash.delete("Full name")
_hash.delete("License")
_hash.delete("License URL")
_hash.delete("License Description")
_hash.delete("Copyright")
_hash.delete(:features)
_hash.delete(:glyphs)
self.misc_informations = _hash
end
def add_file_location(location)
self.file_locations ||= []
self.file_locations << location
self.file_locations = self.file_locations.uniq
end
def add_feature_informations(hash)
_features = hash[:features]
_features.each{|feature|
self.features << Feature.where(:short_name => feature[0], :description => feature[1]).first_or_create
} if _features
end
def add_glyph_informations(hash)
_glyphs = hash[:glyphs]
_glyphs.each{|glyph|
self.glyphs << Glyph.where(:unicode_point => glyph[0], :glyph_number => glyph[1], :glyph_description => glyph[2]).first_or_create
} if _glyphs
end
def feature_short_names
features.pluck(:short_name).collect{|short_name|
italic = !!(short_name =~ /It/i or short_name =~ /Obl/i)
bold = !!(short_name =~ /[B]d/i or short_name =~ /Bold/i)
if italic and bold
"BoldItalic"
elsif italic
"Italic"
elsif bold
"Bold"
else
"Regular"
end
}
end
def feature_short_names_contained_in_all_sub_families
family_fonts.collect(&:feature_short_names).inject(nil){|array_containing_all, actual_array|
array_containing_all = actual_array if array_containing_all.nil?
array_containing_all = array_containing_all & actual_array
}
end
def sub_families
family_fonts.pluck(:sub_family)
end
def glyph_code_points
glyphs.pluck(:unicode_point)
end
def glyph_code_points_contained_in_all_sub_families
family_fonts.collect(&:glyph_code_points).inject(nil){|array_containing_all, actual_array|
array_containing_all = actual_array if array_containing_all.nil?
array_containing_all = array_containing_all & actual_array
}
end
def family_fonts
Font.where(:family => self.family)
end
def compare_family(source_family)
font = Font.where(:family => source_family).first
source_sub_families = font.sub_families
source_glyph_code_points = font.glyph_code_points_contained_in_all_sub_families
source_features = font.feature_short_names_contained_in_all_sub_families
source_sub_families_count = source_sub_families.length
source_glyph_code_points_count = source_glyph_code_points.length
source_features_count = source_features.length
other_family = self.family
first_family_font = Font.where(:family => other_family).first
_sub_families = first_family_font.sub_families
_glyph_code_points = first_family_font.glyph_code_points_contained_in_all_sub_families
_features = first_family_font.feature_short_names_contained_in_all_sub_families
return {
:missing_sub_families_count => (source_sub_families - _sub_families).length,
:missing_glyph_code_points_count => (source_glyph_code_points - _glyph_code_points).length,
:missing_features_count => (source_features - _features).length,
:percentage_sub_families => ((source_sub_families_count - missing_sub_families_count) / source_sub_families_count.to_f),
:percentage_glyphs => ((source_glyph_code_points_count - missing_glyph_code_points_count) / source_glyph_code_points_count.to_f),
:percentage_features => ((source_features_count - missing_features_count) / source_features_count.to_f)
}
end
def compare(source_family)
source_font = comparison_font(source_family)
return {} unless source_font
return {
:missing_glyph_code_points_count => (source_font.glyph_code_points - self.glyph_code_points).length,
:missing_features_count => (source_font.features - self.features).length,
:percentage_glyphs => ((source_font.glyph_code_points.length - (source_font.glyph_code_points - self.glyph_code_points).length) / source_font.glyph_code_points.length.to_f) * 100.0,
:percentage_features => ((source_font.features.length - (source_font.features - self.features).length) / source_font.features.length.to_f) * 100.0
}
end
def comparison_font(source_family)
Font.where(:family => source_family, :sub_family => self.sub_family).first
end
def replace_missing_glyphs(text)
_text = text.dup
missing_symbols = (text.codepoints.collect{|cp| "uni" + cp.to_s(16).upcase.rjust(4, '0')} - self.glyphs.pluck(:unicode_point)).collect{|up| up.gsub("uni",'').hex.chr(Encoding::UTF_8)}
missing_symbols.each{|ms| _text.gsub!(ms, '□')}
return _text
end
def fontspec(path)
"\\setmainfont{#{File.basename(regular_font&.file_locations&.first).gsub(/[\[\]]/,'_')}}[
Path = #{path},
BoldFont= #{File.basename(bold_font&.file_locations&.first.to_s).gsub(/[\[\]]/,'_')},
ItalicFont = #{File.basename(italic_font&.file_locations&.first.to_s).gsub(/[\[\]]/,'_')},
BoldItalicFont = #{File.basename(bold_italic_font&.file_locations&.first.to_s).gsub(/[\[\]]/,'_')}]"
end
def regular_font
Font.where(:family => self.family, :sub_family => 'Regular').first
end
def bold_font
Font.where(:family => self.family, :sub_family => 'Bold').first
end
def bold_italic_font
Font.where(:family => self.family, :sub_family => 'Bold Italic').first
end
def italic_font
Font.where(:family => self.family, :sub_family => 'Italic').first
end
end
+47
View File
@@ -0,0 +1,47 @@
require 'active_record'
class FontDbConnection < ActiveRecord::Base
self.abstract_class = true
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:database => "fonts",
:username => 'jasch',
:password => 'gehe1m',
:encoding => 'utf8'
)
# ActiveRecord::Schema.define do
# create_table :fonts do |table|
# table.column :name, :string
# table.column :family, :string
# table.column :sub_family, :string
# table.column :license, :text
# table.column :file_locations, :text
# table.column :misc_informations, :text
# end
# create_table :features do |table|
# table.column :short_name, :string
# table.column :description, :string
# end
# create_table :glyphs do |table|
# table.column :unicode_point, :string
# table.column :glyph_number, :string
# table.column :glyph_description, :string
# end
# create_table :font_features do |table|
# table.column :font_id, :integer, :index => true
# table.column :feature_id, :integer, :index => true
# end
# create_table :font_glyphs do |table|
# table.column :font_id, :integer, :index => true
# table.column :glyph_id, :integer, :index => true
# end
# end
end
+4
View File
@@ -0,0 +1,4 @@
class FontFeature < FontDbConnection
belongs_to :font
belongs_to :feature
end
+4
View File
@@ -0,0 +1,4 @@
class FontGlyph < FontDbConnection
belongs_to :glyph
belongs_to :font
end
+5
View File
@@ -0,0 +1,5 @@
class Glyph < FontDbConnection
has_many :font_glyphs
has_many :fonts, -> { distinct }, through: :font_glyphs
end
+458
View File
@@ -0,0 +1,458 @@
# coding: utf-8
require 'pdfkit'
require 'nokogiri'
class PdfCreator
include Singleton
BLINDTEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ abcdefghijklmnopqrstuvwxyzäöüß 1234567890 Dies ist ein Typoblindtext. An ihm kann man sehen, ob alle Buchstaben da sind und wie sie aussehen. Manchmal benutzt man Worte wie Hamburgefonts, Rafgenduks oder Handgloves, um Schriften zu testen. Manchmal Sätze, die alle Buchstaben des Alphabets enthalten man nennt diese Sätze »Pangrams«. Sehr bekannt ist dieser: The quick brown fox jumps over the lazy old dog. Oft werden in Typoblindtexte auch fremdsprachige Satzteile eingebaut (AVAIL® and Wefox™ are testing aussi la Kerning), um die Wirkung in anderen Sprachen zu testen. In Lateinisch sieht zum Beispiel fast jede Schrift gut aus. Quod erat demonstrandum. Seit 1975 fehlen in den meisten Testtexten die Zahlen, weswegen nach TypoGb. 204 § ab dem Jahr 2034 Zahlen in 86 der Texte zur Pflicht werden. Nichteinhaltung wird mit bis zu 245 € oder 368 $ bestraft. Genauso wichtig in sind mittlerweile auch Âçcèñtë, die in neueren Schriften aber fast immer enthalten sind. Ein wichtiges aber schwierig zu integrierendes Feld sind OpenType-Funktionalitäten. Je nach Software und Voreinstellungen können eingebaute Kapitälchen, Kerning oder Ligaturen (sehr pfiffig) nicht richtig dargestellt werden. Griechisches Lorem Ipsum: Λορεμ ιπσθμ δολορ σιτ αμετ, νοvθμ φαβελλασ πετεντιθμ vελ νε, ατ νισλ σονετ οπορτερε εθμ. Αλιι δοcτθσ μει ιδ, νο αθτεμ αθδιρε ιντερεσσετ μελ, δοcενδι cομμθνε οπορτεατ τε cθμ. Russisches Lorem Ipsum: Лорем ипсум долор сит амет, пер цлита поссит ех, ат мунере фабулас петентиум сит. Иус цу цибо саперет сцрипсерит, нец виси муциус лабитур ид. Ет хис нонумес нолуиссе дигниссим."
TEX_HEADER = <<-END
\\documentclass[10pt,twocolumn]{report}
\\usepackage{geometry}
\\geometry{
a4paper,
total={190mm,277mm},
left=10mm,
top=10mm,
}
\\usepackage{fontspec}
\\setlength{\\parindent}{0pt}
\\pagestyle{empty}
\\begin{document}
\\newcommand{\\blindtext}{%
\\noindent{}aäb cde fgh ijk lmn oöp qrsß tuü vwx yz AÄBC DEF GHI JKL MNO ÖPQ RST UÜV WXYZ !"§ \\$\\%\\& /() =?* ' \\# \\symbol{"7E} ²³ @`´ ©«» ¼ \\{\\} € - -- ---
Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch
Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick
den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. ,,Fix, Schwyz!'' quäkt Jürgen blöd vom
Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren
Zwerg. Heizölrückstoßabdämpfung.
%% Ligaturen: ff, fi, fl, ft, ffi, ffl, fk, fj, fh, fb, fz, ll, st, ch, ck, ct, th, tt, tz, kk, Qu, ſi, ſſ, ſt, ſch
%%
%% Λορεμ ιπσθμ δολορ σιτ αμετ, νοvθμ φαβελλασ πετεντιθμ vελ νε, ατ νισλ σονετ οπορτερε εθμ. Αλιι δοcτθσ μει ιδ, νο αθτεμ αθδιρε ιντερεσσετ μελ, δοcενδι cομμθνε οπορτεατ τε cθμ.
%%
%% Лорем ипсум долор сит амет, пер цлита поссит ех, ат мунере фабулас петентиум сит. Иус цу цибо саперет сцрипсерит, нец виси муциус лабитур ид. Ет хис нонумес нолуиссе дигниссим.
%%
%% ÀÁ ÃÄÅ ÆÇÈ ÉÊË ÌÍÎ ÏÐÑ ÒÓÔ ÕÖ× ØÙÚ ÛÜÝ Þßà áâã äåæ çèé êëì íîï ðñò óôõ ö÷ø ùúû üýþ ÿ Āāà 㥹 ĆćĈ ĉĊċ ČčĎ ďĐđ ĒēĔ ĕĖė ĘęĚ ěĜĝ ĞğĠ ġĢģ ĤĥĦ ħĨĩ ĪīĬ ĭĮį İıIJ ijĴĵ Ķķĸ ĹĺĻ ļĽľ ĿŀŁ łŃń ŅņŇ ňʼnŊ ŋŌō ŎŏŐ őŒœ ŔŕŖ ŗŘř ŚśŜ ŝŞş ŠšŢ ţŤť ŦŧŨ ũŪū ŬŭŮ ůŰű ŲųŴ ŵŶŷ ŸŹź ŻżŽ žſ ḀḁḂ ḃḄḅ ḆḇḈ ḉḊḋ ḌḍḎ ḏḐḑ ḒḓḔ ḕḖḗ ḘḙḚ ḛḜḝ ḞḟḠ ḡḢḣ ḤḥḦ ḧḨḩ ḪḫḬ ḭḮḯ ḰḱḲ ḳḴḵ ḶḷḸ ḹḺḻ ḼḽḾ ḿṀṁ ṂṃṄ ṅṆṇ ṈṉṊ ṋṌṍ ṎṏṐ ṑṒṓ ṔṕṖ ṗṘṙ ṚṛṜ ṝṞṟ ṠṡṢ ṣṤṥ ṦṧṨ ṩṪṫ ṬṭṮ ṯṰṱ ṲṳṴ ṵṶṷ ṸṹṺ ṻṼṽ Ṿṿ
%%
%% SmallCaps: \\textsc{abcd efgh ijkl mnop qrst uvwx yzāă ąćĉċ čďđē ĕėęě ĝğġģ ĥħĩī ĭįi̇ı ijĵķĸ ĺļľŀ łńņň ʼnŋōŏ őœŕŗ řśŝş šţťŧ ũūŭů űųŵŷ ÿźżž ſƀɓƃ ƅɔƈɖ ɗƌƍǝ əɛƒɠ ɣƕɩɨ ƙƚƛɯ ɲƞɵơ ƣƥʀƨ ʃƪƫƭ ʈưʊʋ ƴƶʒƹ ƺƻƽƾ ƿǀǁǂ ǃdžljnj ǎǐǒ ǔǖǘǚ ǜǟǡ ǣǥǧǩ ǫǭǯǰ dzǵǹǻ ǽǿḁḃ ḅḇḉḋ ḍḏḑḓ ḕḗḙḛ ḝḟḡḣ ḥḧḩḫ ḭḯḱḳ ḵḷḹḻ ḽḿṁṃ ṅṇṉṋ ṍṏṑṓ ṕṗṙṛ ṝṟṡṣ ṥṧṩṫ ṭṯṱṳ ṵṷṹṻ ṽṿ}
%%
%% ƀƁƂ ƃƄƅ ƆƇƈ ƉƊƋ ƌƍƎ ƏƐƑ ƒƓƔ ƕƖƗ Ƙƙƚ ƛƜƝ ƞƟƠ ơƢƣ ƤƥƦ ƧƨƩ ƪƫƬ ƭƮƯ ưƱƲ ƳƴƵ ƶƷƸ ƹƺƻ Ƽƽƾ ƿǀǁ ǂǃDŽ DždžLJ LjljNJ NjnjǍ ǎǏǐ ǑǒǓ ǔǕǖ ǗǘǙ ǚǛǜ ǝǞǟ ǠǡǢ ǣǤǥ ǦǧǨ ǩǪǫ ǬǭǮ ǯǰDZ DzdzǴ ǵǶǷ ǸǹǺ ǻǼǽ Ǿǿ
%%
%% ἀἁἂ ἃἄἅ ἆἇἈ ἉἊἋ ἌἍἎ Ἇἐἑ ἒἓἔ ἕ἖἗ ἘἙἚ ἛἜἝ ἞἟ἠ ἡἢἣ ἤἥἦ ἧἨἩ ἪἫἬ ἭἮἯ ἰἱἲ ἳἴἵ ἶἷἸ ἹἺἻ ἼἽἾ Ἷὀὁ ὂὃὄ ὅ὆὇ ὈὉὊ ὋὌὍ ὎὏ὐ ὑὒὓ ὔὕὖ ὗ὘Ὑ ὚Ὓ὜ Ὕ὞Ὗ ὠὡὢ ὣὤὥ ὦὧὨ ὩὪὫ ὬὭὮ Ὧὰά ὲέὴ ήὶί ὸόὺ ύὼώ ὾὿
%%
%% ͰͱͲ ͳʹ͵ Ͷͷ͸ ͹ͺͻ ͼͽ; Ϳ΀΁ ΂΃΄ ΅Ά· ΈΉΊ ΋Ό΍ ΎΏΐ ΑΒΓ ΔΕΖ ΗΘΙ ΚΛΜ ΝΞΟ ΠΡ΢ ΣΤΥ ΦΧΨ ΩΪΫ άέή ίΰα βγδ εζη θικ λμν ξοπ ρςσ τυφ χψω ϊϋό ύώϏ ϐϑϒ ϓϔϕ ϖϗϘ ϙϚϛ ϜϝϞ ϟϠϡ ϢϣϤ ϥϦϧ ϨϩϪ ϫϬϭ Ϯϯ
%%
⌀⌁⌂ ⌃⌄⌅⌆ ⌇⌈⌉⌊ ⌋⌌ ⌍⌎⌏⌐ ⌑⌒⌓ ⌔⌕⌖ ⌗⌘⌙ ⌚⌛⌜ ⌝⌞⌟ ⌠⌡⌢ ⌣⌤⌥ ⌦⌧⌨ 〈〉⌫ ⌬⌭⌮ ⌯⌰⌱ ⌲⌳⌴ ⌵⌶⌷ ⌸⌹⌺ ⌻⌼⌽ ⌾⌿⍀ ⍁⍂⍃ ⍄⍅⍆ ⍇⍈ ⍉⍊ ⍋⍌⍍ ⍎⍏⍐ ⍑⍒⍓ ⍔⍕⍖ ⍗⍘⍙ ⍚⍛⍜
⍝⍞⍟ ⍠⍡⍢ ⍣⍤⍥ ⍦⍧⍨ ⍩⍪⍫ ⍬⍭⍮ ⍯⍰⍱ ⍲⍳⍴ ⍵⍶⍷ ⍸⍹⍺ ⍻⍼⍽ ⍾⍿⎀ ⎁⎂⎃ ⎄⎅⎆ ⎇⎈⎉ ⎊⎋⎌ ⎍⎎⎏ ⎐⎑⎒ ⎓⎔⎕ ⎖⎗⎘ ⎙⎚⎛ ⎜⎝⎞ ⎟⎠⎡ ⎢⎣⎤ ⎥⎦⎧ ⎨⎩⎪ ⎫⎬⎭ ⎮⎯⎰ ⎱⎲⎳ ⎴⎵⎶ ⎷⎸⎹ ⎺⎻⎼
⎽⎾ ⎿⏀⏁ ⏂⏃⏄ ⏅⏆⏇ ⏈⏉⏊ ⏋⏌⏍ ⏎⏏⏐ ⏑⏒⏓ ⏔⏕⏖ ⏗⏘⏙ ⏚⏛⏜ ⏝⏞⏟ ⏠⏡⏢ ⏣⏤⏥ ⏦⏧⏨ ⏩⏪⏫ ⏬⏭⏮ ⏯⏰⏱ ⏲⏳⏴ ⏵⏶⏷ ⏸⏹⏺ ⏻⏼⏽ ⏾⏿
}
END
TEX_FOOTER = "\\end{document}"
class << self
def create_comparison_pdf(pdf_file, font_families, base_font_family: "DeGruyter")
base_fonts = Font.where(:family => base_font_family).collect{|font| font.family_fonts}.flatten.uniq.sort_by{|font|
style_index = 100
if font.sub_family == "Regular"
style_index = 0
elsif font.sub_family == "Bold"
style_index = 2
elsif font.sub_family == "Italic"
style_index = 1
elsif font.sub_family == "Bold Italic"
style_index = 3
end
[font_families.index(font.family), style_index]
}
fonts = Font.where(:family => font_families).collect{|font| font.family_fonts}.flatten.uniq.sort_by{|font|
style_index = 100
if font.sub_family == "Regular"
style_index = 0
elsif font.sub_family == "Bold"
style_index = 2
elsif font.sub_family == "Italic"
style_index = 1
elsif font.sub_family == "Bold Italic"
style_index = 3
end
[font_families.index(font.family), style_index]
}
File.open("#{File.dirname(__FILE__)}/test.css", 'w+'){|file|
(fonts + base_fonts).each_with_index{|font, index|
file.puts "@font-face {"
file.puts " font-family: '#{font.family}';"
file.puts " src: url(data:font/#{File.extname(font.file_locations.first) == '.otf' ? 'opentype' : 'truetype'};charset=utf-8;base64,#{Base64.encode64(File.read(font.file_locations.first)).gsub(/\s+/, "")});"
if font.sub_family == "Regular"
elsif font.sub_family == "Bold"
file.puts " font-weight: bold;"
elsif font.sub_family == "Italic"
file.puts " font-style: italic;"
elsif font.sub_family == "Bold Italic"
file.puts " font-weight: bold;"
file.puts " font-style: italic;"
end
file.puts "}"
file.puts
file.puts ".font-#{font.id} {"
file.puts " "
file.puts " font-family: '#{font.family}';"
if font.sub_family == "Regular"
elsif font.sub_family == "Bold"
file.puts " font-weight: bold;"
elsif font.sub_family == "Italic"
file.puts " font-style: italic;"
elsif font.sub_family == "Bold Italic"
file.puts " font-weight: bold;"
file.puts " font-style: italic;"
end
file.puts " font-size: 12pt;"
file.puts "}"
file.puts ".font-comparison {"
file.puts " clear: both;"
file.puts " "
file.puts "}"
file.puts ".page-break {"
file.puts " page-break-after: always;"
file.puts " "
file.puts "}"
}
}
builder = Nokogiri::HTML::Builder.new do |doc|
doc.html {
doc.body {
fonts.each_with_index{|font, index|
_hash = font.compare(base_font_family)
doc.div(class: 'font-comparison') {
doc.div(class: 'left' , style: "float:left; width:45%;") {
doc.div(class: 'font_id') {
doc.text "ID: #{font.id}"
}
doc.div(class: 'font_name') {
doc.text "Name: #{font.family}"
}
doc.div(class: 'font_name') {
doc.text "Stil: #{font.sub_family}"
}
doc.div(class: 'font_information') {
doc.text "% Glyphen: #{_hash[:percentage_glyphs]}"
}
doc.div(class: 'font_information') {
doc.text "% Features: #{_hash[:percentage_features]}"
}
doc.div(class: 'font_information') {
doc.text "Anzahl fehlende Gylphen: #{_hash[:missing_glyph_code_points_count]}"
}
doc.div(class: 'font_information') {
doc.text "Anzahl fehlende Features: #{_hash[:missing_features_count]}"
}
doc.div(class: "font-#{font.id}") {
doc.text font.replace_missing_glyphs(BLINDTEXT)
}
}
compare_font = font.comparison_font(base_font_family)
doc.div(class: 'right', style: "float:right; width:45%;") {
if compare_font
doc.div(class: 'font_id') {
doc.text "ID: #{compare_font.id}"
}
doc.div(class: 'font_name') {
doc.text "Name: #{compare_font.family}"
}
doc.div(class: 'font_name') {
doc.text "Stil: #{compare_font.sub_family}"
}
doc.div(class: 'font_information') {
doc.text " "
}
doc.div(class: 'font_information') {
doc.text " "
}
doc.div(class: 'font_information') {
doc.text " "
}
doc.div(class: 'font_information') {
doc.text " "
}
doc.div(class: "font-#{compare_font.id}") {
doc.text compare_font.replace_missing_glyphs(BLINDTEXT)
}
end
}
}
doc.div(class: 'page-break') {
doc.text " "
}
}
}
}
end
kit = PDFKit.new(builder.to_html, :page_size => 'Letter')
kit.stylesheets << "#{File.dirname(__FILE__)}/test.css"
file = kit.to_file(pdf_file)
end
def create_font_test_pdf(pdf_file, regular_font_location)
Dir.mktmpdir do |dir|
FileUtils.mkdir_p("#{dir}/fonts/1/")
FileUtils.cp(regular_font_location, "#{dir}/fonts/1/#{File.basename(regular_font_location).gsub(/[\[\]]/,'_')}")
File.open("#{dir}/main.tex",'w+'){|file|
file.puts TEX_HEADER
file.puts "\\XeTeXtracingfonts=1"
file.puts "\\newfontfamily{\\nf}[Path=./fonts/1/]{NewFont}"
file.puts "\\nf"
file.puts "ΔΕΖ"
file.puts
file.puts "\\blindtext"
file.puts TEX_FOOTER
}
#puts File.read("#{dir}/main.tex")
puts `cd #{dir}; /usr/local/texlive/2015/bin/x86_64-linux/xelatex --interaction=batchmode main`
FileUtils.cp("#{dir}/main.pdf", pdf_file)
end
end
def create_fonts_tex_pdf(pdf_file, font_families, base_font_family, type: :blind )
regular_base_font = Font.where(family: base_font_family).first.regular_font
bold_base_font = Font.where(family: base_font_family).first.bold_font
italic_base_font = Font.where(family: base_font_family).first.italic_font
bold_italic_base_font = Font.where(family: base_font_family).first.bold_italic_font
Dir.mktmpdir do |dir|
base_font_spec = regular_base_font.fontspec("#{dir}/fonts/#{regular_base_font.id}/")
FileUtils.mkdir_p("#{dir}/fonts/#{regular_base_font.id}")
FileUtils.cp(regular_base_font&.file_locations&.first, "#{dir}/fonts/#{regular_base_font.id}/#{File.basename(regular_base_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if regular_base_font&.file_locations&.first
FileUtils.cp(bold_base_font&.file_locations&.first, "#{dir}/fonts/#{regular_base_font.id}/#{File.basename(bold_base_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if bold_base_font&.file_locations&.first
FileUtils.cp(italic_base_font&.file_locations&.first, "#{dir}/fonts/#{regular_base_font.id}/#{File.basename(italic_base_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if italic_base_font&.file_locations&.first
FileUtils.cp(bold_italic_base_font&.file_locations&.first, "#{dir}/fonts/#{regular_base_font.id}/#{File.basename(bold_italic_base_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if bold_italic_base_font&.file_locations&.first
File.open("#{dir}/main.tex",'w+'){|file|
file.puts TEX_HEADER
font_families.each{|font_family|
regular_font = Font.where(family: font_family).first.regular_font
bold_font = Font.where(family: font_family).first.bold_font
italic_font = Font.where(family: font_family).first.italic_font
bold_italic_font = Font.where(family: font_family).first.bold_italic_font
next unless regular_font
_regular_hash = {}
_bold_hash = {}
_italic_hash = {}
_bold_italic_hash = {}
_regular_hash = regular_font.compare(base_font_family) if regular_font
_bold_hash = bold_font.compare(base_font_family) if bold_font
_italic_hash = italic_font.compare(base_font_family) if italic_font
_bold_italic_hash = bold_italic_font.compare(base_font_family) if bold_italic_font
font_spec = regular_font.fontspec("#{dir}/fonts/#{regular_font.id}/")
FileUtils.mkdir_p("#{dir}/fonts/#{regular_font.id}")
FileUtils.cp(regular_font&.file_locations&.first, "#{dir}/fonts/#{regular_font.id}/#{File.basename(regular_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if regular_font&.file_locations&.first and File.exist?(regular_font&.file_locations&.first)
FileUtils.cp(bold_font&.file_locations&.first, "#{dir}/fonts/#{regular_font.id}/#{File.basename(bold_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if bold_font&.file_locations&.first and File.exist?(bold_font&.file_locations&.first)
FileUtils.cp(italic_font&.file_locations&.first, "#{dir}/fonts/#{regular_font.id}/#{File.basename(italic_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if italic_font&.file_locations&.first and File.exist?(italic_font&.file_locations&.first)
FileUtils.cp(bold_italic_font&.file_locations&.first, "#{dir}/fonts/#{regular_font.id}/#{File.basename(bold_italic_font&.file_locations&.first).gsub(/[\[\]]/,'_')}") if bold_italic_font&.file_locations&.first and File.exist?(bold_italic_font&.file_locations&.first)
#[regular_font, bold_font, italic_font, bold_italic_font].each{|font|
if type == :blind
file.puts "#{font_spec}
Fontname: #{regular_font.family} #{regular_font.sub_family} #{regular_font.id}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {%
Glyphen: #{_regular_hash[:percentage_glyphs].round(2)}\\% (#{_regular_hash[:missing_glyph_code_points_count]} fehlen) Features: #{_regular_hash[:percentage_features].round(2)}\\% (#{_regular_hash[:missing_features_count]} fehlen)\\hfill\\break
Schnittmenge Features: #{(regular_font.features.pluck(:short_name) & regular_base_font.features.pluck(:short_name)).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
\\blindtext\\vfill\\break
#{base_font_spec}
Fontname: #{regular_base_font.family} #{regular_base_font.sub_family}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {vorhandene Features: #{regular_base_font.features.pluck(:short_name).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
\\blindtext
\\vfill\\break" if regular_font
file.puts "#{font_spec}
Fontname: #{italic_font.family} #{italic_font.sub_family} #{italic_font.id}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {%
Glyphen: #{_italic_hash[:percentage_glyphs].round(2)}\\% (#{_italic_hash[:missing_glyph_code_points_count]} fehlen) Features: #{_italic_hash[:percentage_features].round(2)}\\% (#{_italic_hash[:missing_features_count]} fehlen)\\hfill\\break
Schnittmenge Features: #{(italic_font.features.pluck(:short_name) & italic_base_font.features.pluck(:short_name)).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
{\\noindent\\textit{\\blindtext}}
\\vfill\\break
#{base_font_spec}
Fontname: #{italic_base_font.family} #{italic_base_font.sub_family}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {vorhandene Features: #{italic_base_font.features.pluck(:short_name).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
{\\noindent\\textit{\\blindtext}}
\\vfill\\break" if italic_font
file.puts "#{font_spec}
Fontname: #{bold_font.family} #{bold_font.sub_family} #{bold_font.id}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {%
Glyphen: #{_bold_hash[:percentage_glyphs].round(2)}\\% (#{_bold_hash[:missing_glyph_code_points_count]} fehlen) Features: #{_bold_hash[:percentage_features].round(2)}\\% (#{_bold_hash[:missing_features_count]} fehlen)\\hfill\\break
Schnittmenge Features: #{(bold_font.features.pluck(:short_name) & bold_base_font.features.pluck(:short_name)).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
{\\noindent
\\textbf{\\blindtext}
}
\\vfill\\break
#{base_font_spec}
Fontname: #{bold_base_font.family} #{bold_base_font.sub_family}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {vorhandene Features: #{bold_base_font.features.pluck(:short_name).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
{\\noindent
\\textbf{\\blindtext}
}
\\vfill\\break" if bold_font
file.puts "#{font_spec}
Fontname: #{bold_italic_font.family} #{bold_italic_font.sub_family} #{bold_italic_font.id}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {%
Glyphen: #{_bold_italic_hash[:percentage_glyphs].round(2)}\\% (#{_bold_italic_hash[:missing_glyph_code_points_count]} fehlen) Features: #{_bold_italic_hash[:percentage_features].round(2)}\\% (#{_bold_italic_hash[:missing_features_count]} fehlen)\\hfill\\break
Schnittmenge Features: #{(bold_italic_font.features.pluck(:short_name) & bold_italic_base_font.features.pluck(:short_name)).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
{\\bf\\noindent
\\textit{
\\blindtext
}
}\\vfill\\break
#{base_font_spec}
Fontname: #{bold_italic_base_font.family} #{bold_italic_base_font.sub_family}\\hfill\\break\\vskip1mm
\\vbox to 16.2mm {vorhandene Features: #{bold_italic_base_font.features.pluck(:short_name).join(", ")}}
Schriftbeispiele\\hfill\\break\\noindent
{\\bf\\noindent
\\textit{
\\blindtext
}
}\\vfill\\break
%
" if bold_italic_font
elsif type == :numbers
file.puts "#{base_font_spec}#{regular_font.family}\\hfill\\break"
file.puts "Fontname: #{regular_base_font.family} #{regular_base_font.sub_family}\\hfill\\break
Fontname: #{regular_font.family} #{regular_font.sub_family} #{regular_font.id}\\hfill\\break
\\noindent{1234567890}\\hfill\\break
#{font_spec}
\\noindent{1234567890}\\hfill\\break
#{base_font_spec}" if regular_font
file.puts "#{base_font_spec}
Fontname: #{italic_base_font.family} #{italic_base_font.sub_family}\\hfill\\break
Fontname: #{italic_font.family} #{italic_font.sub_family} #{italic_font.id}\\hfill\\break
{\\noindent\\textit{1234567890}}\\hfill\\break
#{font_spec}
{\\noindent\\textit{1234567890}}\\hfill\\break
#{base_font_spec}" if italic_font
file.puts "#{base_font_spec}
Fontname: #{bold_base_font.family} #{bold_base_font.sub_family}\\hfill\\break
Fontname: #{bold_font.family} #{bold_font.sub_family} #{bold_font.id}\\hfill\\break
{\\noindent\\textbf{1234567890}}\\hfill\\break
#{font_spec}
{\\noindent\\textbf{1234567890}}\\hfill\\break
#{base_font_spec}" if bold_font
file.puts "#{base_font_spec}
Fontname: #{bold_italic_base_font.family} #{bold_italic_base_font.sub_family}\\hfill\\break
Fontname: #{bold_italic_font.family} #{bold_italic_font.sub_family} #{bold_italic_font.id}\\hfill\\break
{\\bf\\noindent\\textit{1234567890}}\\hfill\\break
#{font_spec}
{\\bf\\noindent\\textit{1234567890}}\\hfill\\break
#{base_font_spec}" if bold_italic_font
file.puts "\\vfill\\break"
end
}
file.puts TEX_FOOTER
}
puts `cd #{dir}; /usr/local/texlive/2015/bin/x86_64-linux/xelatex --interaction=batchmode main`
FileUtils.cp("#{dir}/main.pdf", pdf_file)
end
end
end
end