Skip to content

Commit

Permalink
Various EPUB font related enhancements, including automatic font conv…
Browse files Browse the repository at this point in the history
…ersion.
  • Loading branch information
Avdi Grimm committed Aug 20, 2013
1 parent 8d74953 commit dcd74cd
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 23 deletions.
2 changes: 2 additions & 0 deletions fontforge/convert.pe
@@ -0,0 +1,2 @@
Open($1)
Generate($2)
6 changes: 4 additions & 2 deletions lib/quarto/build.rb
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
require 'rake'
require 'nokogiri'
require 'open3'
Expand Down Expand Up @@ -50,11 +51,12 @@ class Build
[Etc.getpwnam(Etc.getlogin).gecos.split(',')[0]]
}
fattr :title => "Untitled Book"
fattr(:name) { title.downcase.tr_s("^a-z0-9", "-") }
fattr :description => ""
fattr :language => ENV["LANG"].to_s.split(".").first
fattr :language => "en"
fattr(:date) { Time.now.iso8601 }
fattr(:rights) {
"Copyright © #{Time.parse(date).year} #{author}"
"Copyright © #{Time.parse(date).year} #{author}"
}
fattr(:stylesheets) { FileList[base_stylesheet, code_stylesheet] }
fattr(:extensions_to_source_formats) { {} }
Expand Down
4 changes: 3 additions & 1 deletion lib/quarto/epubcheck.rb
Expand Up @@ -15,7 +15,9 @@ def define_tasks
task :epubcheck => [epubcheck_jar, :epub] do |t|
files = FileList["#{main.deliverable_dir}/*.epub"]
files.each do |epub_file|
sh *%W[java -jar #{epubcheck_jar} #{epub_file} -v 3.0]
sh(*%W[java -jar #{epubcheck_jar} #{epub_file} -v 3.0]) do
# Ignore errors for now
end
end
end

Expand Down
8 changes: 7 additions & 1 deletion lib/quarto/font.rb
Expand Up @@ -24,7 +24,13 @@ def local_url
end

def format
Pathname(file).extname[1..-1]
case ext = Pathname(file).extname[1..-1]
when "ttf" then "truetype"
when "otf" then "opentype"
when "woff" then "woff"
when "svg" then "svg"
else ext
end
end
end
end
82 changes: 72 additions & 10 deletions lib/quarto/pandoc_epub.rb
@@ -1,5 +1,6 @@
require "quarto/plugin"
require "nokogiri"
require "delegate"

module Quarto
class PandocEpub < Plugin
Expand All @@ -11,7 +12,7 @@ module BuildExt

fattr(:flags) { %W[-w epub3 --epub-chapter-level 2 --no-highlight --toc] }
fattr(:xml_write_options) {
Nokogiri::XML::Node::SaveOptions::DEFAULT_XHTML |
Nokogiri::XML::Node::SaveOptions::DEFAULT_XML |
Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
}

Expand All @@ -31,10 +32,12 @@ def define_tasks

file epub_file => [exploded_epub] do |t|
replace_listings(exploded_epub, main.highlights_dir)
fix_font_mimetypes("#{exploded_epub}/content.opf")
target = Pathname(t.name).relative_path_from(Pathname(exploded_epub))
cd exploded_epub do

sh "zip -r #{target} *"
files = FileList["**/*"]
files.exclude("mimetype")
sh "zip -X -r #{target} mimetype #{files}"
end
end

Expand All @@ -49,13 +52,15 @@ def define_tasks
main.assets_file,
main.deliverable_dir,
stylesheet,
metadata_file
metadata_file,
*font_files
] do |t|
create_epub_file(
t.name,
main.master_file,
stylesheet: stylesheet,
metadata_file: metadata_file)
metadata_file: metadata_file,
font_files: font_files)
end

file stylesheet => [pandoc_epub_dir, *main.stylesheets, fonts_stylesheet] do |t|
Expand All @@ -72,20 +77,26 @@ def define_tasks
end
open(t.name, 'w') do |f|
master_doc.css("meta").each do |meta|
if meta["name"] =~ /^DC\.(.*)$/
if meta["name"] =~ /^DC\.(.*)$/ && meta["content"].size > 0
f.puts "<dc:#{$1}>#{meta["content"]}</dc:#{$1}>"
end
end
end
end

rule %r(^#{pandoc_epub_dir}/fonts/.*\.woff$) => [->(f){source_font_for(f)}] do |t|
mkdir_p t.name.pathmap("%d") unless File.exist?(t.name.pathmap("%d"))
convert_font(t.source, t.name)
end

directory pandoc_epub_dir
end

private

def create_epub_file(epub_file, master_file, options={})
metadata_file = options.fetch(:metadata_file) { self.metadata_file }
font_files = options.fetch(:font_files) { [] }
pandoc_flags = flags.dup
master_dir = master_file.pathmap("%d")
epub_file = Pathname(epub_file)
Expand All @@ -96,8 +107,8 @@ def create_epub_file(epub_file, master_file, options={})
.relative_path_from(Pathname(master_dir))
pandoc_flags.concat(%W[--epub-stylesheet #{stylesheet_file}])
end
main.fonts.each do |font|
font_path = Pathname(font.file).relative_path_from(Pathname(master_dir))
font_files.each do |font_file|
font_path = Pathname(font_file).relative_path_from(Pathname(master_dir))
pandoc_flags.concat(%W[--epub-embed-font #{font_path}])
end
metadata_path =
Expand Down Expand Up @@ -149,14 +160,31 @@ def replace_listings(epub_dir, highlights_dir)
def create_fonts_stylesheet(file=fonts_stylesheet)
puts "generate #{file}"
open(file, 'w') do |f|
main.fonts.each do |font|
fonts.each do |font|
f.puts(font.to_font_face_rule)
end
end
end

# Replace Pandoc mimetypes with the ones recognized by the IDPF
def fix_font_mimetypes(package_file)
doc = open(package_file) {|f|
Nokogiri::XML(f)
}
doc.css("manifest item[media-type='application/x-font-woff']").each do |elt|
elt["media-type"] = "application/font-woff"
end
doc.css("manifest item[media-type='application/x-font-opentype']").each do
|elt|
elt["media-type"] = "application/vnd.ms-opentype"
end
open(package_file, 'w') do |f|
doc.write_xml_to(f)
end
end

def epub_file
"#{main.deliverable_dir}/book.epub"
"#{main.deliverable_dir}/#{main.name}.epub"
end

def stylesheet
Expand Down Expand Up @@ -186,5 +214,39 @@ def fonts_stylesheet
def metadata_file
"#{pandoc_epub_dir}/metadata.xml"
end

def font_files
orig_files = FileList[*main.fonts.map(&:file)]
supported, unsupported = orig_files.partition{|f|
%W[.otf .woff].include?(f.pathmap("%x"))
}
(supported + unsupported.pathmap("#{pandoc_epub_dir}/fonts/%n.woff"))
end

def source_font_for(target_font)
orig_files = main.fonts.map(&:file)
orig_files.detect{|f| f.pathmap("%n") == target_font.pathmap("%n")}
end

def convert_font(source_font, target_font)
convert_script = File.expand_path("../../../fontforge/convert.pe", __FILE__)
sh "fontforge", "-script", convert_script, source_font, target_font
end

def font_file_for_epub(orig_file)
font_files.detect{|f| orig_file.pathmap("%n") == f.pathmap("%n")}
end

def fonts
main.fonts.map{|font|
if %W[.otf .woff].include?(font.file.pathmap("%x"))
font
else
font = font.dup
font.file = font_file_for_epub(font.file)
font
end
}
end
end
end
2 changes: 1 addition & 1 deletion lib/quarto/prince.rb
Expand Up @@ -44,7 +44,7 @@ def define_tasks
end

def pdf_file
"#{main.deliverable_dir}/book.pdf"
"#{main.deliverable_dir}/#{main.name}.pdf"
end

def prince_master_file
Expand Down
8 changes: 0 additions & 8 deletions templates/base.scss
Expand Up @@ -193,14 +193,6 @@ figure {
}
}

.coffeescript {
background-image: url(../images/cs_logo.png);
background-repeat: no-repeat;
background-position: 5px 0px;
background-size: 10px;
background-image-resolution: 400dpi;
}

/* figures and tables*/

div.figure {
Expand Down
115 changes: 115 additions & 0 deletions templates/pages.scss
@@ -0,0 +1,115 @@
@page {
margin: 27mm 16mm 27mm 16mm;
size: $print_page_width $print_page_height;

@footnotes {
border-top: thin solid black;
padding-top: 0.3em;
margin-top: 0.6em;
margin-left: 0%;
margin-bottom: 1em;
}
}


/* define default page and names pages: cover, blank, frontmatter */

@page :left {
@top-left {
font: 11pt $font, serif;
content: $title;
vertical-align: bottom;
padding-bottom: 0.5em;
border-bottom: thin solid black;
}

@bottom-left {
font: 11pt $font, serif;
content: counter(page);
padding-top: 0.5em;
vertical-align: top;
border-top: thin solid black;
}

@bottom-right {
font: 11pt $font, serif;
content: $rslug;
padding-top: 0.5em;
text-align: right;
vertical-align: top;
border-top: thin solid black;
}
}

@page :right {
@top-right {
font: 11pt $font, serif;
content: string(header, first);
vertical-align: bottom;
padding-bottom: 0.5em;
margin-bottom: 0.5 em;
border-bottom: thin solid black;
}

@bottom-left {
font: 11pt $font, serif;
content: $lslug;
padding-top: 0.5em;
vertical-align: top;
border-top: thin solid black;
}

@bottom-right {
font: 11pt $font, serif;
content: counter(page);
text-align: right;
vertical-align: top;
padding-top: 0.5em;
border-top: thin solid black;
}
}

@page frontmatter :left {
@top-left {
font: 11pt $font, serif;
content: string(title);
vertical-align: bottom;
padding-bottom: 2em;
}

@bottom-left {
font: 11pt $font, serif;
content: counter(page, lower-roman);
padding-top: 2em;
vertical-align: top;
}
}

@page cover { margin: 0; }

@page frontmatter :right {
@top-right {
font: 11pt $font, serif;
content: string(header, first);
vertical-align: bottom;
padding-bottom: 2em;
}

@bottom-right {
font: 11pt $font, serif;
content: counter(page, lower-roman);
text-align: right;
vertical-align: top;
padding-top: 2em;
}
}

@page blank :left {
@top-left { content: normal }
@bottom-left { content: normal }
}

@page blank :right {
@top-right { content: normal }
@bottom-right { content: normal }
}

0 comments on commit dcd74cd

Please sign in to comment.