ajout du filtre pour les emojis et changement des marges par défaut

This commit is contained in:
Francois Pelletier 2023-02-11 22:04:35 -05:00
parent 6984195392
commit e2c54f4d84
4 changed files with 282 additions and 22 deletions

248
latex-emoji.lua Normal file
View file

@ -0,0 +1,248 @@
-- latex-emoji.lua
--
-- @copyright 2020 Takayuki YATO (aka. "ZR")
-- GitHub: https://github.com/zr-tex8r
-- Twitter: @zr_tex8r
-- This program is distributed under the MIT License.
--
local filter_name = 'latex-emoji'
---------------------------------------- helpers
--- Show debug log?
local show_log = true
--- The default emoji font
local default_emojifont = 'TwemojiMozilla.ttf'
--- Use bxcoloremoji package?
local bxcoloremoji = false
--- The emoji font to use
local emojifont, emojifontoptions = nil
--- All used codepoints
local ucs_used = {}
--- The number of emoji text spans.
local text_count = 0
local utils = require 'pandoc.utils'
local concat, insert, pack, unpack =
table.concat, table.insert, table.pack, table.unpack
--- Shows a debug log.
local function log(fmt, ...)
if not show_log then return end
io.stderr:write(filter_name..": "..fmt:format(...).."\n")
end
--- Aborts with an error message.
local function abort(fmt, ...)
error(filter_name..": "..fmt:format(...))
end
--- Returns the Pandoc-or-ordinary type of v.
-- @return A string that says type name.
local function pantype(v)
local t = type(v)
return (t == 'table') and v.t or t
end
--- Makes a comma-separated value string.
-- @return A string.
local function clist(...)
local t, u = pack(...), {}
for i = 1, t.n do
local v = (t[i] == nil) and '' or tostring(t[i])
if v ~= '' then insert(u, v) end
end
return concat(u, ',')
end
--- Makes the sorted sequence of all keys of a given table.
-- @return A sequence of strings.
local function keys(t)
local u = {}
for k in pairs(t) do insert(u, k) end
table.sort(u)
return u
end
--- Converts a singleton sequence to its element.
-- @return The sole element of v if v is a singleton;
-- v if v is not a table; otherwise an error is issued.
local function tosingle(v, l)
if type(v) ~= 'table' then return v end
if #v == 1 then return tosingle(v[1], l) end
abort("multiple values given: %s", l)
end
--- Converts a value to a singleton sequence.
-- @return The empty table if v is nil; v if v is a table;
-- otherwise the singleton of v.
local function toseq(v)
if v == nil then return {}
elseif type(v) == 'table' then return v
else return {v}
end
end
--- Converts MetaInlines values inside a MetaValue to strings.
-- @return The converted value. (v is not modified.)
local function tostring_meta(v, l)
if type(v) ~= 'table' then return v end
if v.t == 'MetaList' or v.t == nil then
local r = {}
for k, e in pairs(v) do r[k] = tostring_meta(e, l) end
return r
elseif v.t == 'MetaInlines' then
return utils.stringify(v)
else abort("cannot stringify: %s", v.t, l)
end
end
--- Gets the source to go into the header.
-- @return LaTeX source string
local function get_header()
if not bxcoloremoji or not next(ucs_used) then
return nil
end
return ([[
\usepackage[%s]{bxcoloremoji}
\newcommand*{\panEmoji}{\coloremoji}
]]):format(clist(emojifont, unpack(emojifontoptions)))
end
--- Gets the source to go into the head of body.
-- @return LaTeX source string
local function get_prologue()
if bxcoloremoji or not next(ucs_used) then
return nil
end
local fname = emojifont or default_emojifont
local fopts = clist('Renderer=HarfBuzz', unpack(emojifontoptions));
local ucs = keys(ucs_used)
for i = 1, #ucs do
ucs[i] = ('"%X'):format(ucs[i])
end
local dcrsrc = concat(ucs, ',\n')
return ([[
\makeatletter
\ifnum0\ifdefined\directlua\directlua{
if ("\luaescapestring{\luatexbanner}"):match("LuaHBTeX") then tex.write("1") end
}\fi>\z@ %% LuaHBTeX is ok
\setfontface\p@emoji@font{%s}[%s]
\else
\@latex@error{You must install a new TeX system (TeX Live 2020)\MessageBreak
and then use 'lualatex' engine to print emoji}
{The compilation will be aborted.}
\let\p@emoji@font\relax
\fi
\ifdefined\ltjdefcharrange
\ltjdefcharrange{208}{
%s}
\ltjsetparameter{jacharrange={-208}}
\fi
\newcommand*{\panEmoji}[1]{{\p@emoji@font#1}}
\makeatother
]]):format(fname, fopts, dcrsrc)
end
--- For debug.
local function inspect(v)
local t = type(v)
if t == 'userdata' or t == 'function' or t == 'nil' then return t
elseif t == 'table' then
local u, tag = {}, (v.t or 'table')
if tag == 'Str' then return tag..'{'..v.text..'}' end
for i = 1, #v do u[i] = inspect(v[i]) end
return tag..'{'..concat(u, ';')..'}'
else return tostring(v)
end
end
---------------------------------------- phase 'readmeta'
--- For Meta elements.
local function readmeta_Meta (meta)
-- bxcoloremoji
if meta.bxcoloremoji == nil then
bxcoloremoji = false
elseif type(meta.bxcoloremoji) == 'boolean' then
bxcoloremoji = meta.bxcoloremoji
else
abort("not a boolean value: bxcoloremoji")
end
log('bxcoloremoji = %s', bxcoloremoji)
-- emojifont
emojifont = tostring_meta(meta.emojifont, "emojifont")
emojifont = tosingle(emojifont, "emojifont")
log('emojifont = %s', emojifont)
-- emojifontoptions
emojifontoptions = tostring_meta(meta.emojifontoptions, "emojifontoptions")
emojifontoptions = toseq(emojifontoptions)
for i in ipairs(emojifontoptions) do
emojifontoptions[i] = tosingle(emojifontoptions[i], "emojifontoptions element")
log('emojifontoptions = %s', emojifontoptions[i])
end
end
---------------------------------------- phase 'mainproc'
--- For Span element.
local function mainproc_Span(span)
if span.classes:includes('emoji', 1) then
text_count = text_count + 1
local str = utils.stringify(span.content)
for p, uc in utf8.codes(str) do
if not ucs_used[uc] and uc >= 0x100 then
log("emoji character: U+%04X", uc)
ucs_used[uc] = true
end
end
insert(span.content, 1, pandoc.RawInline('latex', [[\panEmoji{]]))
insert(span.content, pandoc.RawInline('latex', [[}]]))
return span.content
end
end
--- For Meta elements.
local function mainproc_Meta(meta)
local src = get_header()
if src then
local headers = meta['header-includes']
if headers == nil then
headers = pandoc.MetaList({})
elseif pantype(headers) == 'MetaList' then
abort("unexpected metavalue type: header-includes")
end
insert(headers, pandoc.MetaBlocks{pandoc.RawBlock('latex', src)})
meta['header-includes'] = headers
log("header successfully appended")
return meta
end
end
--- For the whole document.
local function mainproc_Pandoc(doc)
log("number of emoji spans: %s", text_count)
local src = get_prologue()
if src then
insert(doc.blocks, 1, pandoc.RawBlock('latex', src))
log("prologue successfully inserted")
return doc
end
end
---------------------------------------- the filter
if FORMAT == 'latex' then
return {
{-- phase 'readmeta'
Meta = readmeta_Meta;
};
{-- phase 'mainproc'
Span = mainproc_Span;
Meta = mainproc_Meta;
Pandoc = mainproc_Pandoc;
};
}
else
log("format '%s' in not supported", FORMAT)
end
---------------------------------------- done

17
main.py
View file

@ -122,7 +122,7 @@ async def generer(specs: DocumentSpecs):
datef = datetime.datetime.now().strftime("%m-%d-%Y")
os.makedirs("out", exist_ok=True)
output_file = f"./out/{specs.style}-{specs.format}-{datef}-output.pdf"
filters = []
filters = ['latex-emoji.lua']
pdoc_args = [
f'--include-in-header={header_file}',
f'--include-after-body={cover_file}',
@ -144,7 +144,7 @@ async def generer(specs: DocumentSpecs):
result = pypandoc.convert_text(source=specs.content,
to='pdf',
format='markdown+implicit_figures+smart',
format='markdown+implicit_figures+smart+emoji',
encoding='utf-8',
extra_args=pdoc_args,
filters=filters,
@ -157,13 +157,18 @@ async def generer(specs: DocumentSpecs):
except OSError as oerr:
logging.exception(oerr)
if specs.extension in ["png", "jpg"]:
zip_filename = os.path.splitext(os.path.basename(output_file))[0]
png_output_dir = "./png_output"
zip_filename = os.path.join("out", os.path.splitext(os.path.basename(output_file))[0])
png_output_dir = "./out/png_output"
if not os.path.exists(png_output_dir):
os.mkdir(png_output_dir)
try:
convert_pdf(output_file, specs.extension, png_output_dir, resolution=300)
shutil.make_archive(zip_filename, 'zip', png_output_dir)
convert_pdf(output_file,
specs.extension,
png_output_dir,
resolution=300)
shutil.make_archive(base_name=zip_filename,
format='zip',
root_dir=png_output_dir)
shutil.rmtree(png_output_dir)
except Exception as e:
logging.exception(e)

View file

@ -8,7 +8,7 @@
"paperheight": 3507,
"ratio": 100,
"margin": 248,
"vmargin": 350,
"vmargin": 525,
"extension": "pdf"
},
"lettre": {
@ -20,7 +20,7 @@
"paperheight": 3300,
"ratio": 100,
"margin": 255,
"vmargin": 330,
"vmargin": 495,
"extension": "pdf"
},
"linkedin": {
@ -31,8 +31,8 @@
"paperwidth": 1200,
"paperheight": 1200,
"ratio": 100,
"margin": 120,
"vmargin": 120,
"margin": 180,
"vmargin": 180,
"extension": "jpg"
},
"instagram": {
@ -44,7 +44,7 @@
"paperheight": 1920,
"ratio": 100,
"margin": 108,
"vmargin": 192,
"vmargin": 244,
"extension": "jpg"
},
"pinterest": {
@ -56,7 +56,7 @@
"paperheight": 1102,
"ratio": 100,
"margin": 75,
"vmargin": 110,
"vmargin": 165,
"extension": "jpg"
},
"slide43": {
@ -68,7 +68,7 @@
"paperheight": 1920,
"ratio": 100,
"margin": 256,
"vmargin": 192,
"vmargin": 288,
"extension": "pdf"
},
"slide169": {
@ -80,7 +80,7 @@
"paperheight": 1440,
"ratio": 100,
"margin": 256,
"vmargin": 144,
"vmargin": 216,
"extension": "pdf"
}
}

View file

@ -10,11 +10,13 @@ Accept: application/zip
"linkcolor": "blue",
"tocdepth": 2,
"pdfengine": "lualatex",
"content": "# Ceci est un titre\n## Ceci est un sous-titre\n\nCeci est un paragraphe\n\n## Ceci est un autre sous-titre\n\n> Ceci est du code",
"content": "# Ceci est un titre\n## Ceci est un sous-titre\n\nCeci est un paragraphe\n\n## Ceci est un autre sous-titre\n\n> Ceci est du code\n\nCeci est un emoji :heart_eyes:",
"fontsize": 14,
"paperwidth": 1080,
"paperheight": 1920,
"ratio": 100,
"margin": 180,
"vmargin": 180,
"extension": "jpg"
}
@ -30,11 +32,13 @@ Accept: application/pdf
"linkcolor": "blue",
"tocdepth": 2,
"pdfengine": "lualatex",
"content": "# Ceci est un titre\n## Ceci est un sous-titre\n\nCeci est un paragraphe\n\n## Ceci est un autre sous-titre\n\n> Ceci est du code",
"content": "# Ceci est un titre\n## Ceci est un sous-titre\n\nCeci est un paragraphe\n\n## Ceci est un autre sous-titre\n\n> Ceci est du code\n\nCeci est un emoji :heart_eyes:",
"fontsize": 14,
"paperwidth": 1080,
"paperheight": 1080,
"ratio": 100,
"margin": 90,
"vmargin": 90,
"extension": "pdf"
}
@ -50,10 +54,11 @@ Accept: application/pdf
"linkcolor": "blue",
"tocdepth": 2,
"pdfengine": "lualatex",
"content": "# Comment améliorer ma sécurité informatique\n\n20 défis gratuits de 2 minutes chacun !",
"content": "# Ceci est un titre\n## Ceci est un sous-titre\n\nCeci est un paragraphe\n\n## Ceci est un autre sous-titre\n\n> Ceci est du code\n\nCeci est un emoji :heart_eyes:",
"fontsize": 20,
"paperwidth": 1080,
"paperheight": 1080,
"ratio": 100,
"margin": 180,
"extension": "jpg",
"vmargin": 300
@ -67,15 +72,17 @@ Accept: application/pdf
{
"format": "slide169",
"style": "jevalideca",
"style": "lcm",
"linkcolor": "blue",
"tocdepth": 2,
"pdfengine": "lualatex",
"content": "# Ceci est un titre\n## Ceci est un sous-titre\n\nCeci est un paragraphe\n\n## Ceci est un autre sous-titre\n\n> Ceci est du code",
"content": "# Ceci est un titre\n## Ceci est un sous-titre\n\nCeci est un paragraphe\n\n## Ceci est un autre sous-titre\n\n> Ceci est du code\n\nCeci est un emoji :heart_eyes:",
"fontsize": 14,
"paperwidth": 1920,
"paperheight": 1080,
"margin": 90,
"paperwidth": 2560,
"paperheight": 1440,
"ratio": 100,
"margin": 256,
"vmargin": 216,
"extension": "jpg"
}