From f71a40ca0224f4683054fbb9e1cf9fa26561f829 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 3 Jul 2015 23:26:48 +0000 Subject: tex4ebook (29jul15) git-svn-id: svn://tug.org/texlive/trunk@37751 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/scripts/tex4ebook/config-t4e.lua | 19 ++ Master/texmf-dist/scripts/tex4ebook/exec_epub.lua | 300 +++++++++++++++++++++ Master/texmf-dist/scripts/tex4ebook/exec_epub3.lua | 92 +++++++ Master/texmf-dist/scripts/tex4ebook/exec_mobi.lua | 20 ++ Master/texmf-dist/scripts/tex4ebook/list-fonts.lua | 145 ++++++++++ 5 files changed, 576 insertions(+) create mode 100755 Master/texmf-dist/scripts/tex4ebook/config-t4e.lua create mode 100755 Master/texmf-dist/scripts/tex4ebook/exec_epub.lua create mode 100755 Master/texmf-dist/scripts/tex4ebook/exec_epub3.lua create mode 100755 Master/texmf-dist/scripts/tex4ebook/exec_mobi.lua create mode 100755 Master/texmf-dist/scripts/tex4ebook/list-fonts.lua (limited to 'Master/texmf-dist/scripts') diff --git a/Master/texmf-dist/scripts/tex4ebook/config-t4e.lua b/Master/texmf-dist/scripts/tex4ebook/config-t4e.lua new file mode 100755 index 00000000000..9cc6681efec --- /dev/null +++ b/Master/texmf-dist/scripts/tex4ebook/config-t4e.lua @@ -0,0 +1,19 @@ +-- Config file for tex4ebook + +-- Font config + +Font{ + name = "cmr", + file = "lmroman10-regular.otf", + family = "Latin Modern", + weight = "normal", + style = "normal" +} + +Font{ + name = "cmmi", + file = "lmroman10-italic.otf", + family = "Latin Modern", + weight = "normal", + style = "italic" +} diff --git a/Master/texmf-dist/scripts/tex4ebook/exec_epub.lua b/Master/texmf-dist/scripts/tex4ebook/exec_epub.lua new file mode 100755 index 00000000000..45977c2ee2f --- /dev/null +++ b/Master/texmf-dist/scripts/tex4ebook/exec_epub.lua @@ -0,0 +1,300 @@ +module("exec_epub",package.seeall) +local lfs = require("lfs") +local os = require("os") +local io = require("io") +--local ebookutils = require("ebookutils") +local ebookutils = require "mkutils" +-- font loading doesn't work, font database format changes often +-- and it is different between TL and Miktex +-- local load_font = require("list-fonts") +local outputdir_name="OEBPS" +local metadir_name = "META-INF" +local mimetype_name="mimetype" +outputdir="" +outputfile="" +outputfilename="" +basedir = "" +tidy = false +local include_fonts = false +local metadir="" + + + +function prepare(params) + local randname=tostring(math.random(12000)) + -- if not ebookutils.file_exists("tex4ht.env") then + -- local env_file = kpse.find_file("epub2.env") + --print("Local env file: "..env_file) + -- ebookutils.copy(env_file,"tex4ht.env") + -- end + local makedir= function(path) + local current = lfs.currentdir() + local dir = ebookutils.prepare_path(path .. "/") + if type(dir) == "table" then + local parts,msg = ebookutils.find_directories(dir) + if parts then + ebookutils.mkdirectories(parts) + end + end + lfs.chdir(current) + end + basedir = params.input.."-".. params.format + outputdir= basedir.."/"..outputdir_name --"outdir-"..randname --os.tmpdir() + makedir(outputdir) + -- lfs.mkdir(outputdir) + --ebookutils.mkdirectories(ebookutils.prepare_path(outputdir.."/")) + metadir = basedir .."/" .. metadir_name --"metadir-"..randname + makedir(metadir) + --local dd = ebookutils.prepare_path(metadir.."/") + --for _,d in pairs(dd) do print("metadir path: "..d) end + -- lfs.mkdir(metadir) + --local status, msg = ebookutils.mkdirectories(ebookutils.prepare_path(metadir.."/")) + --if not status then print("make mmetadir error:" ..msg) end + mimetype= basedir .. "/" ..mimetype_name --os.tmpname() + print(outputdir) + print(mimetype) + tidy = params.tidy + include_fonts = params.include_fonts + params["t4ht_par"] = params["t4ht_par"] -- + "-d"..string.format(params["t4ht_dir_format"],outputdir) + return(params) +end + +function run(out,params) + --local currentdir= + outputfilename=out + outputfile = outputfilename..".epub" + print("Output file: "..outputfile) + --lfs.chdir(metadir) + local m= io.open(metadir.."/container.xml","w") + m:write([[ + + + + + + + ]]) + m:close() + --lfs.chdir("..") + m=io.open(mimetype,"w") + m:write("application/epub+zip") + m:close() + local htlatex_run = "${htlatex} ${input} \"${config}${tex4ht_sty_par}\" \"${tex4ht_par}\" \"${t4ht_par}\" \"${latex_par}\"" % params + print("Make4ht run") + print("-------------------") + params.config_file.Make.params = params + local mode = params.mode + if params.config_file.Make:length() < 1 then + if mode == "draft" then + params.config_file.Make:htlatex() + else + params.config_file.Make:htlatex() + params.config_file.Make:htlatex() + params.config_file.Make:htlatex() + end + end + if #params.config_file.Make.image_patterns > 0 then + params["t4ht_par"] = params["t4ht_par"] .." -p" + end + params.config_file.Make:tex4ht() + params.config_file.Make:t4ht() + params.config_file.Make:run() + print("-------------------") + --[[for k,v in pairs(params.config_file.Make) do + print(k.. " : "..type(v)) + end--]] + --print(os.execute(htlatex_run)) +end + +local mimetypes = { + css = "text/css", + png = "image/png", + jpg = "image/jpeg", + gif = "image/gif", + svg = "image/svg+xml", + html= "application/xhtml+xml", + xhtml= "application/xhtml+xml", + ncx = "application/x-dtbncx+xml", + otf = "application/opentype", + ttf = "application/truetype", + woff = "application/font-woff", + js = "text/javascript" +} + +function make_opf() + -- Join files content.opf and content-part2.opf + -- make item record for every converted image + local lg_item = function(item) + -- Find mimetype and make item tag for each converted file in the lg file + local fname,ext = item:match("([%a%d%_%-]*)%p([%a%d]*)$") + local mimetype = mimetypes[ext] or "" + if mimetype == "" then print("Mimetype for "..ext.." is not registered"); return nil end + local dir_part = item:split("/") + table.remove(dir_part,#dir_part) + local id=table.concat(dir_part,"-")..fname.."_"..ext + return "",id + end + local find_all_files= function(s,r) + local r = r or "([%a%d%_%-]*)%.([x]?html)" + local files = {} + for i, ext in s:gmatch(r) do + --local i, ext = s:match(r)-- do + ext = ext or "true" + files[i] = ext + end + return files + end + local tidyconf = nil + if tidy then + tidyconf = kpse.find_file("tidyconf.conf") + end + --local opf_first_part = outputdir .. "/content.opf" + local opf_first_part = "content.opf" + local opf_second_part = "content-part2.opf" + --local opf_second_part = outputdir .. "/content-part2.opf" + if + ebookutils.file_exists(opf_first_part) and ebookutils.file_exists(opf_second_part) + then + local h_first = io.open(opf_first_part,"r") + local h_second = io.open(opf_second_part,"r") + local opf_complete = {} + table.insert(opf_complete,h_first:read("*all")) + local used_html = find_all_files(opf_complete[1]) + local lg_file = ebookutils.parse_lg(outputfilename..".lg") + local used_files = lg_file["files"] + --[[for f in lfs.dir("./OEBPS") do + --table.insert(used_files,f) + --used_files[f] = true + end--]] + local all_html = find_all_files(table.concat(used_files,"\n")) + local outside_spine = {} + -- This was duplicated code + --[[for i, ext in pairs(all_html) do + if not used_html[i] then + print("Prvni insert: ".. i .."."..ext) + local item, id = lg_item(i.."."..ext) + table.insert(opf_complete,item) + table.insert(outside_spine,id) + end + end--]] + local all_used_files = find_all_files(opf_complete[1],"([%a%d%-%_]+%.[%a%d]+)") + local used_paths = {} + for _,k in ipairs(lg_file["files"]) do + local ext = k:match("%.([%a%d]*)$") + local parts = k:split "/" + local fn = parts[#parts] + local allow_in_spine = {html="",xhtml = "", xml = ""} + table.remove(parts,#parts) + --table.insert(parts,1,"OEBPS") + table.insert(parts,1,outputdir) + --print("SSSSS "..fn.." ext .." .. ext) + --if string.find("jpg gif png", ext) and not all_used_files[k] then + local item,id = lg_item(k) + if item then + local path = table.concat(parts) + if not used_paths[path] then + ebookutils.mkdirectories(parts) + used_paths[path]=true + end + if allow_in_spine[ext] and tidy then + if tidyconf then + print("Tidy: "..k) + local run ="tidy -c -w 200 -q -utf8 -m -config " .. tidyconf .." " .. k + os.execute(run) + else + print "Tidy: Cannot load tidyconf.conf" + end + end + ebookutils.copy(k, outputdir .. "/"..k) + if not all_used_files[fn] then + table.insert(opf_complete,item) + if allow_in_spine[ext] then + table.insert(outside_spine,id) + end + end + end + end + for _,f in ipairs(lg_file["images"]) do + local f = f.output + local p = lg_item(f) + ebookutils.copy(f, outputdir .. "/"..f) + table.insert(opf_complete,p) + end + local end_opf = h_second:read("*all") + local spine_items = {} + for _,i in ipairs(outside_spine) do + table.insert(spine_items, + '' % {idref=i}) + end + table.insert(opf_complete,end_opf % {spine = table.concat(spine_items,"\n")}) + h_first:close() + h_second:close() + h_first = io.open(opf_first_part,"w") + local opf_completed = table.concat(opf_complete,"\n") + -- poor man's tidy: remove trailing whitespace befora xml tags + opf_completed = opf_completed:gsub("[ ]*<","<") + h_first:write(opf_completed) + h_first:close() + os.remove(opf_second_part) + --ebookutils.copy(outputfilename ..".css",outputdir.."/") + ebookutils.copy(opf_first_part,outputdir.."/"..opf_first_part) + --for c,v in pairs(lg_file["fonts"]) do + -- print(c, table.concat(v,", ")) + --end + --print(table.concat(opf_complete,"\n")) + else + print("Missing opf file") + end + end + local function find_zip() + if io.popen("zip -v","r"):close() then + return "zip" + elseif io.popen("miktex-zip -v","r"):close() then + return "miktex-zip" + end + print "It appears you don't have zip command installed. I can't pack the ebook" + return "zip" + end + + function pack_container() + if os.execute("tidy -v") > 0 then + print("Warning:\n tidy command seems missing, you need to install it" .. + " in order\n to make valid epub file") + else + print("Tidy ncx ".. + os.execute("tidy -xml -i -q -utf8 -m " .. + outputdir .. "/" .. outputfilename .. ".ncx")) + print("Tidy opf ".. + os.execute("tidy -xml -i -q -utf8 -m " .. + outputdir .. "/" .. "content.opf")) + end + print(mimetype) + local zip = find_zip() + print("Pack mimetype " .. os.execute("cd "..basedir.." && "..zip.." -q0X "..outputfile .." ".. mimetype_name)) + print("Pack metadir " .. os.execute("cd "..basedir.." && "..zip.." -qXr9D " .. outputfile.." "..metadir_name)) + print("Pack outputdir " .. os.execute("cd "..basedir.." && "..zip.." -qXr9D " .. outputfile.." "..outputdir_name)) + print("Copy generated epub ") + ebookutils.cp(basedir .."/"..outputfile, outputfile) +end + + + function writeContainer() + make_opf() + pack_container() + end + local function deldir(path) + for entry in lfs.dir(path) do + if entry~="." and entry~=".." then + os.remove(path.."/"..entry) + end + end + os.remove(path) + --]] + end + + function clean() + --deldir(outputdir) + --deldir(metadir) + --os.remove(mimetype) + end diff --git a/Master/texmf-dist/scripts/tex4ebook/exec_epub3.lua b/Master/texmf-dist/scripts/tex4ebook/exec_epub3.lua new file mode 100755 index 00000000000..55f7f71c309 --- /dev/null +++ b/Master/texmf-dist/scripts/tex4ebook/exec_epub3.lua @@ -0,0 +1,92 @@ +module(...,package.seeall) +local eb = require("exec_epub") + +local outputdir = nil +local input = nil +function prepare(params) + local basedir = params.input.."-".. params.format + local outputdir_name="OEBPS" + outputdir= basedir.."/"..outputdir_name + input = params.input + params.packages = params.packages .. "\\Configure{ext}{xhtml}" + return eb.prepare(params) +end + +function run(out,params) + return eb.run(out, params) +end + + +local function makeTOC(document) + local template = [[ + + +TOC + + + + +]] % {document=document} + return template +end + +local function cleanOPF() + -- in epub3, there must be table of contents + -- if there is no toc in the document, we must add generic one + local opf = "content.opf" + local f = io.open(opf,"r") + if not f then + print("Cannot open "..opf .. " for toc searching") + return nil + end + local content = f:read("*all") + f:close() + if content:find "properties[%s]*=[%s]*\"[^\"]*nav" then + print "TOC nav found" + else + print "no TOC, using generic one" + local pattern = input.."(%..?html)" + local ext = content:match(pattern) + local inputfile = input .. ext + print("Main file name", inputfile) + -- write toc file + local toc_name = "generic_toc" ..ext + local f = io.open(outputdir .. "/" .. toc_name, "w") + f:write(makeTOC(inputfile)) + f:close() + -- add toc file to the conten.opf + content = content:gsub("","\n\n") + content = content:gsub("]*)>", "\n\n") + -- remove empty guide element + end + content = content:gsub("%s*","") + f = io.open(outputdir .. "/" ..opf,"w") + f:write(content) + f:close() + --makeTOC(inputfile) +end + + + +function writeContainer() + --local ret = eb.writeContainer() + eb.make_opf() + cleanOPF() + local ret = eb.pack_container() + return ret +end + +function clean() + return eb.clean() +end diff --git a/Master/texmf-dist/scripts/tex4ebook/exec_mobi.lua b/Master/texmf-dist/scripts/tex4ebook/exec_mobi.lua new file mode 100755 index 00000000000..be9148b5a10 --- /dev/null +++ b/Master/texmf-dist/scripts/tex4ebook/exec_mobi.lua @@ -0,0 +1,20 @@ +module(...,package.seeall) +local eb = require("exec_epub") + +function prepare(params) + return eb.prepare(params) +end + +function run(out,params) + return eb.run(out, params) +end + +function writeContainer() + local ret = eb.writeContainer() + print("Pack mobi "..os.execute("kindlegen " .. eb.outputfile)) + return ret +end + +function clean() + return eb.clean() +end diff --git a/Master/texmf-dist/scripts/tex4ebook/list-fonts.lua b/Master/texmf-dist/scripts/tex4ebook/list-fonts.lua new file mode 100755 index 00000000000..9acd1665f60 --- /dev/null +++ b/Master/texmf-dist/scripts/tex4ebook/list-fonts.lua @@ -0,0 +1,145 @@ +kpse.set_program_name("luatex") +local function exists(fn) + local f = io.open(fn,"r") + if f~=nil then io.close(f) return true else return false end +end +local function load_fontbase(pathtable) + -- path should point to possible location of luaotfload font database + -- pathtable should be array of strings + -- each path should not end with lua + + local path = pathtable + if type(pathtable) =="string" then path = {pathtable} end + if #path == 0 then return nil end + local currentpath = table.remove(path,1) + if exists(currentpath ..".lua") then return require(currentpath) + else return load_fontbase(path) end +end + +--local fontbase = require(kpse.expand_var("$TEXMFSYSVAR") .. "/luatex-cache/generic/names/luaotfload-names.lua") +local sysvar = kpse.expand_var("$TEXMFSYSVAR") +local var = kpse.expand_var("$TEXMFVAR") +local namespath = "/luatex-cache/generic/names/" +local oldnames = "otfl-names" +local newnames = "luaotfload-names" +local compose_path = function(path, name) return path .. namespath .. name end +local fontbase_path = { + compose_path(sysvar, newnames), + compose_path(var, newnames), + compose_path(sysvar, oldnames), + compose_path(var,oldnames) +} + +local fontbase = load_fontbase(fontbase_path) or {} +fontbase.mappings = fontbase.mappings or {} +-- assert(fontbase, "Cannot load font names") + + +-- [[ +-- This is code for querying the database +-- +local search = arg[1] or "" +search = unicode.utf8.lower(search) +--]] +local fonts = {} +for _,record in pairs(fontbase.mappings) do + local familyname = record.familyname + local styles = fonts[familyname] or {} + local sanitized = record.sanitized or record.names + local subfamily = sanitized.subfamily --record.sanitized.subfamily or record.names.subfamily + styles[subfamily] = record -- We add subfamily as key to prevent duplicates + fonts[familyname] = styles +end + +local FontLoader = {} + +FontLoader.__index = FontLoader + +FontLoader.load_family = function(familyname) + local self = setmetatable({},FontLoader) + local family = fonts[familyname] + --[[ for _, record in pairs(fontbase.mappings) do + if record.familyname == familyname then + local style = record.sanitized.subfamily + family[style] = record + end + end + --]] + self.family = family + return self +end +FontLoader.get_path =function(self,style) + local rec = self.family[style] + local filename = rec.filename + if type(filename) == "table" then + filename = filename[1] + end + return kpse.find_file(filename,'opentype fonts') or kpse.find_file(filename,'truetype fonts') +end + + +FontLoader.list = function(self) + for style,rec in pairs(self.family) do + print(style, self:get_path(style)) + end +end + + +local FontNames = {} +FontNames.__index = FontNames + +FontNames.new = function() + self = setmetatable({},FontNames) + self.names = {} + return self +end + +FontNames.add_family = function(self,properties) + local properties = properties or {} + return function(names) + local names = names or {} + for _,n in pairs(names) do + self.names[n] = properties + end + end +end + +FontNames.list = function(self) + for name,prop in pairs(self.names) do + local p = {} + for k,v in pairs(prop) do + table.insert(p,k..'='..v) + end + print(name, table.concat(p)) + end +end + +--[[ +local fontnames = {} +for fontname,_ in pairs(fonts) do + local lowername = unicode.utf8.lower(fontname) + if lowername:find(search) then + table.insert(fontnames, fontname) + end +end + +table.sort(fontnames) +--for fontname, styles in pairs (fonts) do +for _, name in pairs(fontnames) do + local fontname = name + local styles = fonts[fontname] + local t = {} + for n,_ in pairs(styles) do table.insert(t,n) end + print(fontname, table.concat(t,', ')) +end +--]] + +local testfont = FontLoader.load_family("math") +--testfont:list() + +local n= FontNames.new() +n:add_family {type = "serif", name = "LMMono10"} {"cmr"} +n:add_family {type = "serif", name = "TeXGyreTermes"} {"ts1-qtmr", "ec-qtmr","ec-qtmri"} +--n:list() + +return {FontLoader = FontLoader, FontNames = n} -- cgit v1.2.3