add pdf generation

This commit is contained in:
Laila van Reenen 2025-09-24 12:16:57 +02:00
parent 7b622c2577
commit abfb65c7d4
Signed by: LailaTheElf
GPG Key ID: 8A3EF0226518C12D
11 changed files with 1161 additions and 21 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/latex
/build
/pdf
.obsidian
.trash

View File

@ -0,0 +1,9 @@
\documentclass[a4paper]{article}
\usepackage{pdfpages}
\begin{document}
\includepdf[pages=-, nup=2x1, frame, signature*=4, landscape, angle=180]{?pdf?}
\end{document}

644
converters/diagrams.lua Normal file
View File

@ -0,0 +1,644 @@
--[[
diagram create images and figures from code blocks.
MIT License
Copyright © 2019-2023 Albert Krewinkel
Copyright © 2019 Thorsten Sommer
Copyright © 2018 Florian Schätzig
Copyright © 2018 John MacFarlane
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
-- The filter uses the Figure AST element, which was added in pandoc 3.
PANDOC_VERSION:must_be_at_least '3.0'
local version = pandoc.types.Version '1.2.0'
-- Report Lua warnings to stderr if the `warn` function is not plugged into
-- pandoc's logging system.
if not warn then
-- fallback
warn = function(...) io.stderr:write(table.concat({ ... })) end
elseif PANDOC_VERSION < '3.1.4' then
-- starting with pandoc 3.1.4, warnings are reported to pandoc's logging
-- system, so no need to print warnings to stderr.
warn '@on'
end
local io = require 'io'
local pandoc = require 'pandoc'
local system = require 'pandoc.system'
local utils = require 'pandoc.utils'
local List = require 'pandoc.List'
local stringify = utils.stringify
local with_temporary_directory = system.with_temporary_directory
local with_working_directory = system.with_working_directory
--- Returns a filter-specific directory in which cache files can be
--- stored, or nil if no such directory is available.
local function cachedir ()
local cache_home = os.getenv 'XDG_CACHE_HOME'
if not cache_home or cache_home == '' then
local user_home = system.os == 'windows'
and os.getenv 'USERPROFILE'
or os.getenv 'HOME'
if not user_home or user_home == '' then
return nil
end
cache_home = pandoc.path.join{user_home, '.cache'} or nil
end
-- Create filter cache directory
return pandoc.path.join{cache_home, 'pandoc-diagram-filter'}
end
--- Path holding the image cache, or `nil` if the cache is not used.
local image_cache = nil
local mimetype_for_extension = {
jpeg = 'image/jpeg',
jpg = 'image/jpeg',
pdf = 'application/pdf',
png = 'image/png',
svg = 'image/svg+xml',
}
local extension_for_mimetype = {
['application/pdf'] = 'pdf',
['image/jpeg'] = 'jpg',
['image/png'] = 'png',
['image/svg+xml'] = 'svg',
}
--- Converts a list of format specifiers to a set of MIME types.
local function mime_types_set (tbl)
local set = {}
local mime_type
for _, image_format_spec in ipairs(tbl) do
mime_type = mimetype_for_extension[image_format_spec] or image_format_spec
set[mime_type] = true
end
return set
end
--- Reads the contents of a file.
local function read_file (filepath)
local fh = io.open(filepath, 'rb')
local contents = fh:read('a')
fh:close()
return contents
end
--- Writes the contents into a file at the given path.
local function write_file (filepath, content)
local fh = io.open(filepath, 'wb')
fh:write(content)
fh:close()
end
--- Like `pandoc.pipe`, but allows "multi word" paths:
-- Supplying a list as the first argument will use the first element as
-- the executable path and prepend the remaining elements to the list of
-- arguments.
local function pipe (command, args, input)
local cmd
if pandoc.utils.type(command) == 'List' then
command = command:map(stringify)
cmd = command:remove(1)
args = command .. args
else
cmd = stringify(command)
end
return pandoc.pipe(cmd, args, input)
end
--
-- Diagram Engines
--
-- PlantUML engine; assumes that there's a `plantuml` binary.
local plantuml = {
line_comment_start = [[']],
mime_types = mime_types_set{'pdf', 'png', 'svg'},
compile = function (self, puml)
local mime_type = self.mime_type or 'image/svg+xml'
-- PlantUML format identifiers correspond to common file extensions.
local format = extension_for_mimetype[mime_type]
if not format then
format, mime_type = 'svg', 'image/svg+xml'
end
local args = {'-t' .. format, "-pipe", "-charset", "UTF8"}
return pipe(self.execpath or 'plantuml', args, puml), mime_type
end,
}
--- GraphViz engine for the dot language
local graphviz = {
line_comment_start = '//',
mime_types = mime_types_set{'jpg', 'pdf', 'png', 'svg'},
mime_type = 'image/svg+xml',
compile = function (self, code)
local mime_type = self.mime_type
-- GraphViz format identifiers correspond to common file extensions.
local format = extension_for_mimetype[mime_type]
if not format then
format, mime_type = 'svg', 'image/svg+xml'
end
return pipe(self.execpath or 'dot', {"-T"..format}, code), mime_type
end,
}
--- Mermaid engine
local mermaid = {
line_comment_start = '%%',
mime_types = mime_types_set{'pdf', 'png', 'svg'},
compile = function (self, code)
local mime_type = self.mime_type or 'image/svg+xml'
local file_extension = extension_for_mimetype[mime_type]
return with_temporary_directory("diagram", function (tmpdir)
return with_working_directory(tmpdir, function ()
local infile = 'diagram.mmd'
local outfile = 'diagram.' .. file_extension
write_file(infile, code)
pipe(
self.execpath or 'mmdc',
{"--pdfFit", "--input", infile, "--output", outfile},
''
)
return read_file(outfile), mime_type
end)
end)
end,
}
--- TikZ
--
--- LaTeX template used to compile TikZ images.
local tikz_template = pandoc.template.compile [[
\documentclass{standalone}
\usepackage{tikz}
$for(header-includes)$
$it$
$endfor$
$additional-packages$
\begin{document}
$body$
\end{document}
]]
--- The TikZ engine uses pdflatex to compile TikZ code to an image
local tikz = {
line_comment_start = '%%',
mime_types = {
['application/pdf'] = true,
},
--- Compile LaTeX with TikZ code to an image
compile = function (self, src, user_opts)
return with_temporary_directory("tikz", function (tmpdir)
return with_working_directory(tmpdir, function ()
-- Define file names:
local file_template = "%s/tikz-image.%s"
local tikz_file = file_template:format(tmpdir, "tex")
local pdf_file = file_template:format(tmpdir, "pdf")
-- Treat string values as raw LaTeX
local meta = {
['header-includes'] = user_opts['header-includes'],
['additional-packages'] = {pandoc.RawInline(
'latex',
stringify(user_opts['additional-packages'] or '')
)},
}
local tex_code = pandoc.write(
pandoc.Pandoc({pandoc.RawBlock('latex', src)}, meta),
'latex',
{template = tikz_template}
)
write_file(tikz_file, tex_code)
-- Execute the LaTeX compiler:
local success, result = pcall(
pipe,
self.execpath or 'pdflatex',
{ '-interaction=nonstopmode', '-output-directory', tmpdir, tikz_file },
''
)
if not success then
warn(string.format(
"The call\n%s\nfailed with error code %s. Output:\n%s",
result.command,
result.error_code,
result.output
))
end
return read_file(pdf_file), 'application/pdf'
end)
end)
end
}
--- Asymptote diagram engine
local asymptote = {
line_comment_start = '%%',
mime_types = {
['application/pdf'] = true,
},
compile = function (self, code)
return with_temporary_directory("asymptote", function(tmpdir)
return with_working_directory(tmpdir, function ()
local pdf_file = "pandoc_diagram.pdf"
local args = {'-tex', 'pdflatex', "-o", "pandoc_diagram", '-'}
pipe(self.execpath or 'asy', args, code)
return read_file(pdf_file), 'application/pdf'
end)
end)
end,
}
--- Cetz diagram engine
local cetz = {
line_comment_start = '%%',
mime_types = mime_types_set{'jpg', 'pdf', 'png', 'svg'},
mime_type = 'image/svg+xml',
compile = function (self, code)
local mime_type = self.mime_type
local format = extension_for_mimetype[mime_type]
if not format then
format, mime_type = 'svg', 'image/svg+xml'
end
local preamble = [[
#import "@preview/cetz:0.3.4"
#set page(width: auto, height: auto, margin: .5cm)
]]
local typst_code = preamble .. code
return with_temporary_directory("diagram", function (tmpdir)
return with_working_directory(tmpdir, function ()
local outfile = 'diagram.' .. format
local execpath = self.execpath
if not execpath and quarto and quarto.version >= '1.4' then
-- fall back to the Typst exec shipped with Quarto.
execpath = List{'quarto', 'typst'}
end
pipe(
execpath or 'typst',
{"compile", "-f", format, "-", outfile},
typst_code
)
return read_file(outfile), mime_type
end)
end)
end,
}
local default_engines = {
asymptote = asymptote,
dot = graphviz,
mermaid = mermaid,
plantuml = plantuml,
tikz = tikz,
cetz = cetz,
}
--
-- Configuration
--
--- Options for the output format of the given name.
local function format_options (name)
local pdf2svg = name ~= 'latex' and name ~= 'context'
local is_office_format = name == 'docx' or name == 'odt'
-- Office formats seem to work better with PNG than with SVG.
local preferred_mime_types = is_office_format
and pandoc.List{'image/png', 'application/pdf'}
or pandoc.List{'application/pdf', 'image/png'}
-- Prefer SVG for non-PDF output formats, except for Office formats
if is_office_format then
preferred_mime_types:insert('image/svg+xml')
elseif pdf2svg then
preferred_mime_types:insert(1, 'image/svg+xml')
end
return {
name = name,
pdf2svg = pdf2svg,
preferred_mime_types = preferred_mime_types,
best_mime_type = function (self, supported_mime_types, requested)
return self.preferred_mime_types:find_if(function (preferred)
return supported_mime_types[preferred] and
(not requested or
(pandoc.utils.type(requested) == 'List' and
requested:includes(preferred)) or
(pandoc.utils.type(requested) == 'table' and
requested[preferred]) or
-- Assume string, Inlines, and Blocks values specify the only
-- acceptable MIME type.
stringify(requested) == preferred)
end)
end
}
end
--- Returns a configured diagram engine.
local function get_engine (name, engopts, format)
local engine = default_engines[name] or
select(2, pcall(require, stringify(engopts.package)))
-- Sanity check
if not engine then
warn(PANDOC_SCRIPT_FILE, ": No such engine '", name, "'.")
return nil
elseif engopts == false then
-- engine is disabled
return nil
elseif engopts == true then
-- use default options
return engine
end
local execpath = engopts.execpath or os.getenv(name:upper() .. '_BIN')
local mime_type = format:best_mime_type(
engine.mime_types,
engopts['mime-type'] or engopts['mime-types']
)
if not mime_type then
warn(PANDOC_SCRIPT_FILE, ": Cannot use ", name, " with ", format.name)
return nil
end
return {
execpath = execpath,
compile = engine.compile,
line_comment_start = engine.line_comment_start,
mime_type = mime_type,
opt = engopts or {},
}
end
--- Returns the diagram engine configs.
local function configure (meta, format_name)
local conf = meta.diagram or {}
local format = format_options(format_name)
meta.diagram = nil
-- cache for image files
if conf.cache then
image_cache = conf['cache-dir']
and stringify(conf['cache-dir'])
or cachedir()
pandoc.system.make_directory(image_cache, true)
end
-- engine configs
local engine = {}
for name, engopts in pairs(conf.engine or default_engines) do
engine[name] = get_engine(name, engopts, format)
end
return {
engine = engine,
format = format,
cache = image_cache and true,
image_cache = image_cache,
}
end
--
-- Format conversion
--
--- Converts a PDF to SVG.
local pdf2svg = function (imgdata)
-- Using `os.tmpname()` instead of a hash would be slightly cleaner, but the
-- function causes problems on Windows (and wasm). See, e.g.,
-- https://github.com/pandoc-ext/diagram/issues/49
local pdf_file = 'diagram-' .. pandoc.utils.sha1(imgdata) .. '.pdf'
write_file(pdf_file, imgdata)
local args = {
'--export-type=svg',
'--export-plain-svg',
'--export-filename=-',
pdf_file
}
return pandoc.pipe('inkscape', args, ''), os.remove(pdf_file)
end
local function properties_from_code (code, comment_start)
local props = {}
local pattern = comment_start:gsub('%p', '%%%1') .. '| ' ..
'([-_%w]+): ([^\n]*)\n'
for key, value in code:gmatch(pattern) do
if key == 'fig-cap' then
props['caption'] = value
else
props[key] = value
end
end
return props
end
local function diagram_options (cb, comment_start)
local attribs = comment_start
and properties_from_code(cb.text, comment_start)
or {}
for key, value in pairs(cb.attributes) do
attribs[key] = value
end
local alt
local caption
local fig_attr = {id = cb.identifier}
local filename
local image_attr = {}
local user_opt = {}
for attr_name, value in pairs(attribs) do
if attr_name == 'alt' then
alt = value
elseif attr_name == 'caption' then
-- Read caption attribute as Markdown
caption = attribs.caption
and pandoc.read(attribs.caption).blocks
or nil
elseif attr_name == 'filename' then
filename = value
elseif attr_name == 'label' then
fig_attr.id = value
elseif attr_name == 'name' then
fig_attr.name = value
else
-- Check for prefixed attributes
local prefix, key = attr_name:match '^(%a+)%-(%a[-%w]*)$'
if prefix == 'fig' then
fig_attr[key] = value
elseif prefix == 'image' or prefix == 'img' then
image_attr[key] = value
elseif prefix == 'opt' then
user_opt[key] = value
else
-- Use as image attribute
image_attr[attr_name] = value
end
end
end
return {
['alt'] = alt or
(caption and pandoc.utils.blocks_to_inlines(caption)) or
{},
['caption'] = caption,
['fig-attr'] = fig_attr,
['filename'] = filename,
['image-attr'] = image_attr,
['opt'] = user_opt,
}
end
local function get_cached_image (hash, mime_type)
if not image_cache then
return nil
end
local filename = hash .. '.' .. extension_for_mimetype[mime_type]
local imgpath = pandoc.path.join{image_cache, filename}
local success, imgdata = pcall(read_file, imgpath)
if success then
return imgdata, mime_type
end
return nil
end
local function cache_image (codeblock, imgdata, mimetype)
-- do nothing if caching is disabled or not possible.
if not image_cache then
return
end
local ext = extension_for_mimetype[mimetype]
local filename = pandoc.sha1(codeblock.text) .. '.' .. ext
local imgpath = pandoc.path.join{image_cache, filename}
write_file(imgpath, imgdata)
end
-- Executes each document's code block to find matching code blocks:
local function code_to_figure (conf)
return function (block)
-- Check if a converter exists for this block. If not, return the block
-- unchanged.
local diagram_type = block.classes[1]
if not diagram_type then
return nil
end
local engine = conf.engine[diagram_type]
if not engine then
return nil
end
-- Unified properties.
local dgr_opt = diagram_options(block, engine.line_comment_start)
for optname, value in pairs(engine.opt or {}) do
dgr_opt.opt[optname] = dgr_opt.opt[optname] or value
end
local run_pdf2svg = engine.mime_type == 'application/pdf'
and conf.format.pdf2svg
-- Try to retrieve the image data from the cache.
local imgdata, imgtype
if conf.cache then
imgdata, imgtype = get_cached_image(
pandoc.sha1(block.text),
run_pdf2svg and 'image/svg+xml' or engine.mime_type
)
end
if not imgdata or not imgtype then
-- No cached image; call the converter
local success
success, imgdata, imgtype =
pcall(engine.compile, engine, block.text, dgr_opt.opt)
-- Bail if an error occurred; imgdata contains the error message
-- when that happens.
if not success then
warn(PANDOC_SCRIPT_FILE, ': ', tostring(imgdata))
return nil
elseif not imgdata then
warn(PANDOC_SCRIPT_FILE, ': Diagram engine returned no image data.')
return nil
elseif not imgtype then
warn(PANDOC_SCRIPT_FILE, ': Diagram engine did not return a MIME type.')
return nil
end
-- Convert SVG if necessary.
if imgtype == 'application/pdf' and conf.format.pdf2svg then
imgdata, imgtype = pdf2svg(imgdata), 'image/svg+xml'
end
-- If we got here, then the transformation went ok and `img` contains
-- the image data.
cache_image(block, imgdata, imgtype)
end
-- Use the block's filename attribute or create a new name by hashing the
-- image content.
local basename, _extension = pandoc.path.split_extension(
dgr_opt.filename or pandoc.sha1(imgdata)
)
local fname = basename .. '.' .. extension_for_mimetype[imgtype]
-- Store the data in the media bag:
pandoc.mediabag.insert(fname, imgtype, imgdata)
-- Create the image object.
local image = pandoc.Image(dgr_opt.alt, fname, "", dgr_opt['image-attr'])
-- Create a figure if the diagram has a caption; otherwise return
-- just the image.
return dgr_opt.caption and
pandoc.Figure(
pandoc.Plain{image},
dgr_opt.caption,
dgr_opt['fig-attr']
) or
pandoc.Plain{image}
end
end
return setmetatable(
{{
Pandoc = function (doc)
local conf = configure(doc.meta, FORMAT)
return doc:walk {
CodeBlock = code_to_figure(conf),
}
end
}},
{
version = version,
}
)

View File

@ -0,0 +1,127 @@
--- include-files.lua filter to include Markdown files
---
--- Copyright: © 20192021 Albert Krewinkel
--- License: MIT see LICENSE file for details
-- Module pandoc.path is required and was added in version 2.12
PANDOC_VERSION:must_be_at_least '2.12'
local List = require 'pandoc.List'
local path = require 'pandoc.path'
local system = require 'pandoc.system'
--- Get include auto mode
local include_auto = false
function get_vars (meta)
if meta['include-auto'] then
include_auto = true
end
end
--- Keep last heading level found
local last_heading_level = 0
function update_last_level(header)
last_heading_level = header.level
end
--- Update contents of included file
local function update_contents(blocks, shift_by, include_path)
local update_contents_filter = {
-- Shift headings in block list by given number
Header = function (header)
if shift_by then
header.level = header.level + shift_by
end
return header
end,
-- If link paths are relative then prepend include file path
Link = function (link)
if path.is_relative(link.target) and string.sub(path.filename(link.target), 1, 1) ~= '#' then
link.target = path.normalize(path.join({include_path, link.target}))
end
return link
end,
-- If image paths are relative then prepend include file path
Image = function (image)
if path.is_relative(image.src) then
image.src = path.normalize(path.join({include_path, image.src}))
end
return image
end,
-- Update path for include-code-files.lua filter style CodeBlocks
CodeBlock = function (cb)
if cb.attributes.include and path.is_relative(cb.attributes.include) then
cb.attributes.include =
path.normalize(path.join({include_path, cb.attributes.include}))
end
return cb
end
}
return pandoc.walk_block(pandoc.Div(blocks), update_contents_filter).content
end
--- Filter function for code blocks
local transclude
function transclude (cb)
-- ignore code blocks which are not of class "include".
if not cb.classes:includes 'include' then
return
end
-- Markdown is used if this is nil.
local format = cb.attributes['format']
-- Attributes shift headings
local shift_heading_level_by = 0
local shift_input = cb.attributes['shift-heading-level-by']
if shift_input then
shift_heading_level_by = tonumber(shift_input)
else
if include_auto then
-- Auto shift headings
shift_heading_level_by = last_heading_level
end
end
--- keep track of level before recusion
local buffer_last_heading_level = last_heading_level
local blocks = List:new()
for line in cb.text:gmatch('[^\n]+') do
if line:sub(1,2) ~= '//' then
local fh = io.open(line)
if not fh then
io.stderr:write("Cannot open file " .. line .. " | Skipping includes\n")
else
-- read file as the given format with global reader options
local contents = pandoc.read(
fh:read '*a',
format,
PANDOC_READER_OPTIONS
).blocks
last_heading_level = 0
-- recursive transclusion
contents = system.with_working_directory(
path.directory(line),
function ()
return pandoc.walk_block(
pandoc.Div(contents),
{ Header = update_last_level, CodeBlock = transclude }
)
end).content
--- reset to level before recursion
last_heading_level = buffer_last_heading_level
blocks:extend(update_contents(contents, shift_heading_level_by,
path.directory(line)))
fh:close()
end
end
end
return blocks
end
return {
{ Meta = get_vars },
{ Header = update_last_level, CodeBlock = transclude }
}

85
converters/mdToLatex.sh Normal file
View File

@ -0,0 +1,85 @@
MD_FILE="$1"
BASE_DIR="$(pwd)"
TEX_FILE="${BASE_DIR}/latex/$(basename "$MD_FILE" | sed -e 's/\.md$/.latex/')"
BUILD_DIR="${BASE_DIR}/build/$(basename "$MD_FILE" | sed -e 's/\.md$//')"
TEMP_MD_FILE="$BUILD_DIR/$(basename "$MD_FILE")"
TEMP_TEX_FILE="$BUILD_DIR/$(basename "$MD_FILE" | sed -e 's|md$|latex|')"
mkdir -p "$(dirname "$TEMP_MD_FILE")"
cp "$MD_FILE" "$TEMP_MD_FILE"
function download_images() {
echo "download images for $1"
for line in $(grep '!\[.*\](https://.*\.png)' "$1" | sed -e 's/ /%20;/g')
do
src=$(echo "$line" | sed -e 's/^.*(//' -e 's/).*$//' -e 's/%20;/ /g')
echo "remote image found: $src"
mkdir -p "${BASE_DIR}/latex/images"
name=$(echo "$src" | sed -e 's|^.*/\([^/]*\)$|\1|')
curl "$src" > "${BASE_DIR}/latex/images/$name"
done
echo "download done"
}
for line in $(grep '^!\[.*\](.*\.md)$' "$TEMP_MD_FILE" | sed -e 's/ /%20;/g')
do
md_src=$(echo "$line" | sed -e 's/^.*(//' -e 's/).*$//' -e 's/%20;/ /g')
echo "include found: $md_src"
download_images "$(pwd)$md_src"
cp "$(pwd)$md_src" "$BUILD_DIR/$(basename "$md_src")"
sed -i "$BUILD_DIR/$(basename "$md_src")" \
-e 's|\[toc\]||' \
-e 's|^\[parent\].*$||' \
-e 's|^# |\\newpage\n# |' \
-e 's|^## |\\newpage\n## |' \
-e 's|\[\([^]]*\)\](#\([^)]*\))|[\1](#\L\2)|' \
-e "s|https://live.kladjes.nl/uploads|${BASE_DIR}/latex/images|" \
-e "s|\`\`\`mermaid|\`\`\`{.mermaid loc=${BASE_DIR}/latex/images/$(basename "$md_src")}|"
sed -i "$TEMP_MD_FILE" \
-e "s|^\!\[.*\]($md_src)\$|\`\`\`\\{.include\\}\n$(basename "$md_src")\n\`\`\`|"
done
download_images "$TEMP_MD_FILE"
title="$(grep '^# ' "$MD_FILE" | head -n 1 | sed 's|^# ||')"
sed -i "$TEMP_MD_FILE" \
-e 's|\[toc\]|\\tableofcontents|' \
-e 's|^\[parent\].*$||' \
-e 's|^# .*$||' \
-e 's|^#||' \
-e 's|^# |\\newpage\n# |' \
-e 's|\[\([^]]*\)\](#\([^)]*\))|[\1](#\L\2)|' \
-e "s|https://live.kladjes.nl/uploads|${BASE_DIR}/latex/images|" \
-e "s|\`\`\`mermaid|\`\`\`{.mermaid loc=${BASE_DIR}/latex/images/$(basename "$MD_FILE")}|"
# -e 's|```\([^ \t]\)=|```\1 {linenumbers}|'
mkdir -p ${BASE_DIR}/latex/images/$(basename "$MD_FILE")
cd "$BUILD_DIR"
pandoc --lua-filter=../../converters/include-files.lua \
--to=latex \
--from=markdown+abbreviations \
--template "${BASE_DIR}/converters/template.latex" \
-o "$TEX_FILE" \
--dpi 300 \
"$(basename "$TEMP_MD_FILE")"
cd "$BASE_DIR"
# for line in $(grep '^!\[.*\](.*\.md)$' "$TEMP_MD_FILE" | sed 's/ /%20;/g')
# do
# src=$(echo "$line" | sed -e 's/^.*(//' -e 's/).*$//' -e 's/%20;/ /g')
# sed -i "$TEMP_MD_FILE" \
# -e "s/^!\[.*\]($src)\$/\\include{$src}/"
# done
sed --in-place \
-e "s|?title?|$title|" \
"$TEX_FILE"

142
converters/template.latex Normal file
View File

@ -0,0 +1,142 @@
\documentclass[11pt]{article}
\usepackage[a4paper, portrait, includehead, includefoot, margin=1.5cm]{geometry}
\usepackage[english]{babel}
\usepackage{pdfpages}
\usepackage{xcolor}
\usepackage{makecell}
\usepackage{tabularx}
\usepackage{adjustbox}
\usepackage{framed}
\usepackage{longtable}
\providecommand{\tightlist}{\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\usepackage{booktabs}
\usepackage{fontspec}
\usepackage{xunicode}
\usepackage{xltxtra}
\newfontfamily\fontRoboto[]{Roboto}
\newfontfamily\fontUbuntu[]{Ubuntu}
\setmainfont{Roboto}
% \usepackage[style=ieee]{biblatex}
% \usepackage{csquotes}
% \addbibresource{bibliography.bib}
% header and footer
\usepackage{fancyhdr}
\renewcommand{\headrule}{}
\usepackage[nodayofweek]{datetime}
\definecolor{darkishyellow}{rgb}{177, 179, 173}
% for images
\usepackage{graphbox}
\usepackage{sectsty}
\sectionfont{\clearpage}
\setkeys{Gin}{width=.99\linewidth}
% add bookmarks with \hypertarget
\usepackage{bookmark}
\usepackage{hyperref}
% heading numberging
\setcounter{secnumdepth}{3}
\renewcommand\thesection{{\fontUbuntu\arabic{section}}}
\renewcommand\thesubsection{{\fontUbuntu\arabic{section}.\arabic{subsection}}}
\renewcommand\thesubsubsection{{\fontUbuntu\arabic{section}.\arabic{subsection}.\arabic{subsubsection}}}
\usepackage{sectsty}
\allsectionsfont{\fontUbuntu}
\setlength{\headheight}{14pt}
% no indent at paragraphs
\usepackage{parskip}
\usepackage{setspace}
\setstretch{1.1}
\let\tmpitem\itemize
\let\tmpenditem\enditemize
\renewenvironment{itemize}{\tmpitem\setlength\itemsep{-.4em}}{\tmpenditem}
$if(highlighting-macros)$
$highlighting-macros$
$endif$
\begin{document}
\raggedright
\pagecolor{darkishyellow}
\begin{titlepage}
.
\vskip 10em
\begin{center}
{\Huge\fontUbuntu ?title? \par}
\vskip 3em
{\huge\fontUbuntu $sub_title$ \par}
\end{center}
\null\vfill
{
\large
\lineskip .75em
\begin{tabular}{r l}
Auther: $for(auther)$& $auther.name$ <$auther.email$> \\
$endfor$\\
Class code: & ELERTS10 \\\\
Exported on: &\today
\end{tabular}
}
\end{titlepage}
\pagestyle{fancy}
\fancyhead{} % clear all header fields
\fancyhead[LO]{\color{gray}\fontUbuntu ?title?}
\fancyhead[RO]{\color{gray}\fontUbuntu $sub_title$}
\fancyfoot{} % clear all footer fields
\fancyfoot[LO]{\color{gray}\fontUbuntu $for(auther)$$auther.name_short$${sep}, $endfor$}
\fancyfoot[CO]{\color{gray}\fontUbuntu }
\fancyfoot[RO]{\color{gray}\fontUbuntu \thepage}
$if(lof)$
\listoffigures
$endif$
$if(lot)$
\listoftables
$endif$
$if(linestretch)$
\setstretch{$linestretch$}
$endif$
$body$
$if(nocite-ids)$
\nocite{$for(nocite-ids)$$it$$sep$, $endfor$}
$endif$
$if(natbib)$
$if(bibliography)$
$if(biblio-title)$
$if(has-chapters)$
\renewcommand\bibname{$biblio-title$}
$else$
\renewcommand\refname{$biblio-title$}
$endif$
$endif$
\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
$endif$
$endif$
$if(biblatex)$
\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
$endif$
\end{document}

99
makefile Normal file
View File

@ -0,0 +1,99 @@
all: all_booklets all_docduments
all_docduments: prepare pdf/assambly_report.pdf pdf/c_report.pdf
all_booklets: prepare pdf/assambly_report.booklet.pdf pdf/c_report.booklet.pdf
prepare:
mkdir -p latex pdf
clean:
rm -r build latex
clean_all:
rm -r build latex pdf
install_arch:
mkdir -p build/install
pacman -Sy --noconfirm --needed curl unzip texlive-basic texlive-langeuropean pandoc
test -e build/install/ubuntu.zip || curl https://assets.ubuntu.com/v1/0cef8205-ubuntu-font-family-0.83.zip -o build/install/ubuntu.zip
test -d build/install/ubuntu && rm -r build/install/ubuntu || echo
mkdir build/install/ubuntu
unzip build/install/ubuntu.zip -d build/install/ubuntu
mkdir -p /usr/share/fonts/ubuntu
cp build/install/ubuntu/ubuntu-font-family-0.83/*.ttf /usr/share/fonts/ubuntu/
chmod 0775 /usr/share/fonts/ubuntu
chmod 0664 /usr/share/fonts/ubuntu/*
test -e build/install/roboto.zip || curl https://dl.dafont.com/dl/?f=roboto -o build/install/roboto.zip
test -d build/install/roboto && rm -r build/install/roboto || echo
mkdir build/install/roboto
unzip build/install/roboto.zip -d build/install/roboto
mkdir -p /usr/share/fonts/roboto
cp build/install/roboto/*.ttf /usr/share/fonts/roboto/
chmod 0775 /usr/share/fonts/roboto
chmod 0664 /usr/share/fonts/roboto/*
install_ubuntu:
mkdir -p build/install
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
curl unzip texlive texlive-lang-european texlive-lang-greek texlive-xetex pandoc
test -e build/install/ubuntu.zip || curl https://assets.ubuntu.com/v1/0cef8205-ubuntu-font-family-0.83.zip -o build/install/ubuntu.zip
test -d build/install/ubuntu && rm -r build/install/ubuntu || echo
mkdir build/install/ubuntu
unzip build/install/ubuntu.zip -d build/install/ubuntu
mkdir -p /usr/share/fonts/ubuntu
cp build/install/ubuntu/ubuntu-font-family-0.83/*.ttf /usr/share/fonts/ubuntu/
chmod 0775 /usr/share/fonts/ubuntu
chmod 0664 /usr/share/fonts/ubuntu/*
test -e build/install/roboto.zip || curl https://dl.dafont.com/dl/?f=roboto -o build/install/roboto.zip
test -d build/install/roboto && rm -r build/install/roboto || echo
mkdir build/install/roboto
unzip build/install/roboto.zip -d build/install/roboto
mkdir -p /usr/share/fonts/roboto
cp build/install/roboto/*.ttf /usr/share/fonts/roboto/
chmod 0775 /usr/share/fonts/roboto
chmod 0664 /usr/share/fonts/roboto/*
# =======================================
# === latex generation ==================
# =======================================
latex/assambly_report.latex: converters/mdToLatex.sh converters/template.latex report-1/*.md
mkdir -p build/assambly_report
bash converters/mdToLatex.sh report-1/assambly_report.md latex/assambly_report.latex
latex/c_report.latex: converters/mdToLatex.sh converters/template.latex report-1/*.md
mkdir -p build/c_report
bash converters/mdToLatex.sh report-1/c_report.md latex/c_report.latex
# =======================================
# === pdf generation ====================
# =======================================
pdf/assambly_report.pdf: latex/assambly_report.latex
cd build/assambly_report && xelatex ../../latex/assambly_report.latex
cd build/assambly_report && xelatex ../../latex/assambly_report.latex
cd build/assambly_report && xelatex ../../latex/assambly_report.latex
mv build/assambly_report/assambly_report.pdf pdf/assambly_report.pdf
pdf/assambly_report.booklet.pdf: converters/bookletify.latex pdf/assambly_report.pdf
mkdir -p build/assambly_report.booklet
sed -e 's|?pdf?|../../pdf/assambly_report.pdf|' converters/bookletify.latex >build/assambly_report.booklet/bookletify.latex
pdflatex -interaction=nonstopmode -output-directory="build/assambly_report.booklet" "build/assambly_report.booklet/bookletify.latex"
mv build/assambly_report.booklet/bookletify.pdf pdf/assambly_report.booklet.pdf
pdf/c_report.pdf: latex/c_report.latex
cd build/c_report && xelatex ../../latex/c_report.latex
cd build/c_report && xelatex ../../latex/c_report.latex
cd build/c_report && xelatex ../../latex/c_report.latex
mv build/c_report/c_report.pdf pdf/c_report.pdf
pdf/c_report.booklet.pdf: converters/bookletify.latex pdf/c_report.pdf
mkdir -p build/c_report.booklet
sed -e 's|?pdf?|../../pdf/c_report.pdf|' converters/bookletify.latex >build/c_report.booklet/bookletify.latex
pdflatex -interaction=nonstopmode -output-directory="build/c_report.booklet" "build/c_report.booklet/bookletify.latex"
mv build/c_report.booklet/bookletify.pdf pdf/c_report.booklet.pdf

View File

@ -1,12 +1,11 @@
---
path: /elektro/hr/rts10/
tags: kladjes, elektro, elektro/hr, elektro/hr/rts10
auther:
- Finley van Reenen (0964590@hr.nl)
auther_short: "E.L.F. van Reenen"
---
# Assembly Assignments
[parent](/lLnsoW2yQlWpblaVBRFsYw)
# Assembly Assignment
This is the first report for _realtime systems 10_. I needed to do the following assignments:
@ -38,8 +37,8 @@ I applied the same fix as last year. In the debug config, replace the `\` with a
The algorithm in question is given in C code.
```c-like=
unsigned int multiply(unsigned int a , unsigned int b)
```c {.numberLines}
unsigned int multiply(unsigned int a, unsigned int b)
{
unsigned int m = 0;
for (unsigned int i = 0; i != a; i ++)
@ -52,8 +51,8 @@ unsigned int multiply(unsigned int a , unsigned int b)
This code can be simplified without changing the algorithm by replacing the variable `i` with `b`. This will result in the following code.
```c-like=
unsigned int multiply ( unsigned int a , unsigned int b)
```c {.numberLines}
unsigned int multiply(unsigned int a, unsigned int b)
{
unsigned int m = 0;
for (; b > 0; b --)
@ -66,7 +65,7 @@ unsigned int multiply ( unsigned int a , unsigned int b)
This is also the code I have implemented. The compiler puts _a_ in `R0` and _b_ in `R1`, I accepted them in place and used `R2` for _m_. At the end _m_ (`R2`) is moved to `R0` to set it as the return value.
```ass=
```asm {.numberLines}
.cpu cortex-m4
.thumb
.syntax unified
@ -88,8 +87,8 @@ mul_exit:
a better representation of the essembly code in C would be:
```c-like=
unsigned int multiply ( unsigned int a , unsigned int b)
```c {.numberLines}
unsigned int multiply(unsigned int a, unsigned int b)
{
unsigned int m = 0;
if (b == 0) {
@ -98,7 +97,7 @@ unsigned int multiply ( unsigned int a , unsigned int b)
do
{
m = m + b;
m = m + a;
b --;
} while (b > 0)
@ -117,7 +116,7 @@ It does not take the branch at line 10 and at line 14 it takes the branch 65535
Now a smarter version.
```c-like=
```c {.numberLines}
unsigned int multiply(unsigned int a , unsigned int b)
{
unsigned int m = 0;
@ -134,7 +133,7 @@ unsigned int multiply(unsigned int a , unsigned int b)
}
```
```asm=
```asm {.numberLines}
.cpu cortex-m4
.thumb
.syntax unified
@ -162,8 +161,8 @@ bmul_exit:
a better representation of the essembly code in C would be:
```c-like=
unsigned int multiply ( unsigned int a , unsigned int b)
```c {.numberLines}
unsigned int multiply(unsigned int a, unsigned int b)
{
unsigned int m = 0;
if (b == 0) {
@ -192,7 +191,7 @@ There are 7 instructions in the loop where one only runs every `1` bit in `b`. T
## Assignment 10: Using your multiply function to calculate the dot product of two vectors
```c-like=
```c {.numberLines}
unsigned int dotProduct(unsigned int a[], unsigned int b[], size_t n)
{
unsigned int p = 0;
@ -206,7 +205,7 @@ unsigned int dotProduct(unsigned int a[], unsigned int b[], size_t n)
This function needs to call another and remember 5 variables (`*a`, `*b`, `n`, `p` and `i`). `R0` through `R3` are expected to change with a function call. There are only `R4` through `R7` left, only four spots. To solve this problem, I reversed the for loop by using n and decrementing it. This will not change the result since addition is not order sensitive. The code I implemented is the following.
```c-like=
```c {.numberLines}
unsigned int dotProduct(unsigned int a[] , unsigned int b[], size_t n)
{
unsigned int p = 0;
@ -225,7 +224,7 @@ unsigned int dotProduct(unsigned int a[] , unsigned int b[], size_t n)
My assembly code:
```asm=
```asm {.numberLines}
.cpu cortex-m4
.thumb
.syntax unified
@ -252,5 +251,4 @@ dotp_loop:
dotp_exit:
MOVS.N R0, R7 // move m to R0
POP.N {R4, R5, R6, R7, PC}
BX.N LR
```

View File

@ -0,0 +1,16 @@
---
sub_title: "Real Time Systems 10"
auther:
- name: "Finley van Reenen (0964590)"
email: "mail@lailatheelf.nl"
name_short: "E.L.F. van Reenen"
---
# Assambly Report
[toc]
![](/report-1/assambly_assignments.md)
![](/report-1/week_1.2.md)

View File

@ -146,7 +146,9 @@ while ((FLASH->ACR & /* ... */ ) == 0);
Finaly we configur the PLL itself.
$$
f_{(VCO\ clock)} = f_{(PLL\ clock\ input)} \cdot (\frac{PLLN}{PLLM}) \\
f_{(VCO\ clock)} = f_{(PLL\ clock\ input)} \cdot (\frac{PLLN}{PLLM})
$$
$$
f_{(PLL\ general\ clock\ output)} = \frac{f_{(VCO\ clock)}}{PLLP}
$$

13
report-2/c_report.md Normal file
View File

@ -0,0 +1,13 @@
---
sub_title: "Real Time Systems 10"
auther:
- name: "Finley van Reenen (0964590)"
email: "mail@lailatheelf.nl"
name_short: "E.L.F. van Reenen"
---
# C Report
[toc]
![](/report-2/week_1.3.md)