Compare commits
48 commits
master
...
jk-bakalar
Author | SHA1 | Date | |
---|---|---|---|
27ff4b7d58 | |||
ef18947916 | |||
7ee84470e9 | |||
9255f77d93 | |||
a9f41eb83e | |||
17920077da | |||
5a61ea5fac | |||
73af3473c7 | |||
6bfb62fcdd | |||
4e2ea4173e | |||
8bcb087979 | |||
2a5fd812e3 | |||
c46a1f0302 | |||
9a993676dc | |||
87961754e8 | |||
08df4dbd78 | |||
57e69cbee4 | |||
f86815e8ff | |||
bb05a3c913 | |||
9dcf87915e | |||
ac2c3475e4 | |||
2fd0efe3a7 | |||
4bd05b098b | |||
86839a9269 | |||
774af0fedf | |||
38029e3587 | |||
6d629137fb | |||
ed40bc4db8 | |||
292fcba574 | |||
d783c7ae9c | |||
71e5c5bbdc | |||
fb80c61139 | |||
7230d87f6b | |||
bf46105db8 | |||
41f51bf6fe | |||
f1f2f63cb5 | |||
a2468b54e1 | |||
945bb760e8 | |||
88d653af15 | |||
4dd1eb0314 | |||
48e34eaf8e | |||
37c8ec4e2e | |||
62263fbe0f | |||
f97ee7de52 | |||
7783dc25f4 | |||
405a4f396c | |||
affc2c4279 | |||
a15a711d0f |
18 changed files with 546 additions and 98 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -2,5 +2,5 @@
|
|||
path = ucwmac
|
||||
url = git://git.ucw.cz/ucwmac.git
|
||||
[submodule "src/formatitko/katex-server"]
|
||||
path = src/formatitko/katex-server
|
||||
path = src/formatitko/katex_server
|
||||
url = https://gitea.ks.matfyz.cz:/KSP/formatitko-katex-server
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
\input luatex85.sty
|
||||
\input ucwmac2.tex
|
||||
\parskip=5pt plus 3pt minus 2pt
|
||||
\parindent=0sp
|
||||
|
||||
\def\strong#1{{%
|
||||
\def\emph##1{{\bi{}##1}}%
|
||||
\bf{}#1%
|
||||
}}
|
||||
\def\emph#1{{%
|
||||
\def\strong##1{{\bi{}##1}}%
|
||||
\it{}#1%
|
||||
}}
|
||||
|
||||
|
||||
\def\superscript#1{\leavevmode\raise3pt\hbox{\fiverm#1}}
|
||||
\def\subscript#1{\leavevmode\lower1pt\hbox{\fiverm#1}}
|
||||
\newcount\fncount
|
||||
\fncount=1
|
||||
\def\fnmark{\superscript{\the\fncount}}
|
||||
\def\fn#1{\footnote\fnmark{#1}\advance\fncount by 1}
|
||||
\def\section#1{{\parskip1em\settextsize{18}\bf #1}}
|
||||
\def\subsection#1{{\parskip1em\settextsize{16}\bf #1}}
|
||||
\def\subsubsection#1{{\parskip1em\settextsize{14}\bf #1}}
|
||||
\def\subsubsubsection#1{{\parskip1em\settextsize{12}\bf #1}}
|
||||
\def\subsubsubsubsection#1{{\parskip1em\settextsize{10}\bf #1}}
|
||||
\def\subsubsubsubsubsection#1{{\parskip1em\settextsize{10}\bi #1}}
|
||||
\long\def\blockquote#1{\vskip\lineskip\vskip\parskip\hbox{\vrule\hskip5pt\vbox{#1}}}
|
||||
\def\strikeout#1{FIXME: Strikeout not implemented}
|
||||
\def\underline#1{FIXME: Underline not implemented}
|
|
@ -33,11 +33,19 @@ dependencies = [
|
|||
[project.scripts]
|
||||
formatitko = "formatitko.formatitko:main"
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
"formatitko.katex_server" = [
|
||||
"*",
|
||||
"node_modules/*",
|
||||
"node_modules/katex/*",
|
||||
"node_modules/katex/src/*",
|
||||
"node_modules/katex/dist/*",
|
||||
]
|
||||
|
||||
[tool.setuptools_scm]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
exclude = ["src/formatitko/katex-server/node_modules"]
|
||||
|
||||
[tool.pyright]
|
||||
strictParameterNoneValue = false
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from panflute import Doc, Element, Div, Span
|
||||
from panflute import Doc, Element, Div, Span, Header, Figure
|
||||
|
||||
from typing import Union, Callable
|
||||
from types import ModuleType
|
||||
|
@ -19,6 +19,23 @@ CommandCallable = Callable[[Command, 'Context', 'NOPProcessor'], list[Element]]
|
|||
#
|
||||
# This class is basically an extension to panflute's doc, this is why metadata
|
||||
# is read directly from it.
|
||||
def default_section_number_generator(e: Header, context: 'Context') -> list[Union[str, int]]:
|
||||
l = e.level
|
||||
section_counters = context.get_data("section_counters")
|
||||
section_counters[l-1] += 1
|
||||
for i in range(l, len(section_counters)):
|
||||
section_counters[i] = 0
|
||||
return list(section_counters[:l])
|
||||
|
||||
def default_figure_number_generator(e: Figure, context: 'Context') -> Union[str, int]:
|
||||
figure_type = e.attributes.get("type", "img")
|
||||
figure_counters = context.get_data("figure_counters")
|
||||
figure_counters.setdefault(figure_type, 0)
|
||||
figure_counters[figure_type] += 1
|
||||
return figure_counters[figure_type]
|
||||
|
||||
|
||||
|
||||
class Context:
|
||||
parent: Union["Context", None]
|
||||
_commands: dict[str, Union[CommandCallable, None]]
|
||||
|
@ -32,6 +49,9 @@ class Context:
|
|||
rel_dir: str # Relative path to the current dir from the root dir
|
||||
deps: set[str]
|
||||
|
||||
section_counters: list[int]
|
||||
number_generator: Callable[[Header, 'Context'], str]
|
||||
|
||||
def __init__(self, doc: Doc, path: str, parent: Union['Context', None]=None, trusted: bool=True):
|
||||
self.parent = parent
|
||||
self._commands = {}
|
||||
|
@ -47,6 +67,12 @@ class Context:
|
|||
self.add_dep(path)
|
||||
if self.get_metadata("flags", immediate=True) is None:
|
||||
self.set_metadata("flags", {})
|
||||
if not parent:
|
||||
self.set_data('section_number_generator', default_section_number_generator)
|
||||
self.set_data('figure_number_generator', default_figure_number_generator)
|
||||
self.set_data('section_counters', [0 for i in range(6)])
|
||||
self.set_data('figure_counters', {})
|
||||
self.set_data('obj_map', {})
|
||||
|
||||
def get_command(self, command: str) -> Union[CommandCallable, None]:
|
||||
if command in self._commands:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from panflute import Quoted, Link
|
||||
from panflute import Quoted, Emph, Link, Div
|
||||
|
||||
|
||||
from .command import Command, InlineCommand, BlockCommand, CodeCommand
|
||||
|
@ -14,6 +14,22 @@ class FQuoted(Quoted):
|
|||
del kwargs["style"]
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
class Slanted(Emph):
|
||||
pass
|
||||
|
||||
class FLink(Link):
|
||||
obj_map: map
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.obj_map = kwargs["obj_map"]
|
||||
del kwargs["obj_map"]
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
class FileLink(Link):
|
||||
pass
|
||||
|
||||
class FLineMarkup(Div):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.color = kwargs["color"]
|
||||
del kwargs["color"]
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
import subprocess
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
# Import local files
|
||||
from .util import import_md
|
||||
|
@ -112,7 +114,12 @@ def main():
|
|||
else:
|
||||
filename = args.output_tex
|
||||
outdir = tempfile.TemporaryDirectory(prefix="formatitko")
|
||||
subprocess.run(["pdfcsplain", "-halt-on-error", "-output-directory="+outdir.name, "-jobname=formatitko", filename], check=True)
|
||||
|
||||
env = os.environ.copy()
|
||||
d = Path("/".join(__file__.split("/")[:-1]))
|
||||
env["TEXINPUTS"]=".:"+str(d/"tex")+":"+env.get("TEXINPUTS", "")
|
||||
|
||||
subprocess.run(["luatex", "-halt-on-error", "-output-directory="+outdir.name, "-jobname=formatitko", filename], check=True, env=env)
|
||||
shutil.move(outdir.name+"/formatitko.pdf", args.output_pdf)
|
||||
|
||||
if args.deps is not None:
|
||||
|
|
|
@ -111,7 +111,7 @@ class HTMLGenerator(OutputGenerator):
|
|||
|
||||
def generate_CodeBlock(self, e: CodeBlock):
|
||||
lexer = None
|
||||
if e.classes and len(e.classes) > 0 and (e.attributes["highlight"] == True or e.attributes["highlight"] == 'True'):
|
||||
if e.classes and len(e.classes) > 0 and (e.attributes.get("highlight", False) in [True, 'True']):
|
||||
# Syntax highlighting using pygments
|
||||
for cl in e.classes:
|
||||
try:
|
||||
|
@ -123,7 +123,7 @@ class HTMLGenerator(OutputGenerator):
|
|||
warnings.warn(f"Syntax highligher does not have lexer for element with these classes: {e.classes}", UserWarning)
|
||||
|
||||
if lexer:
|
||||
formatter = HtmlFormatter(style=e.attributes["style"], noclasses=True)
|
||||
formatter = HtmlFormatter(style=e.attributes.get("style", self.context.get_metadata("highlight-style")), noclasses=True)
|
||||
result = highlight(e.text, lexer, formatter)
|
||||
self.writeraw(result)
|
||||
else:
|
||||
|
@ -344,6 +344,9 @@ class HTMLGenerator(OutputGenerator):
|
|||
def generate_DefinitionList(self, e: DefinitionList):
|
||||
self.writeln("<!-- FIXME: DefinitionLists not implemented -->")
|
||||
|
||||
def generate_SmallCaps(self, e: SmallCaps):
|
||||
self.generate_simple_tag(e, attributes=self.common_attributes(e) | {"style": "font-variant: small-caps;"})
|
||||
|
||||
|
||||
class StandaloneHTMLGenerator(HTMLGenerator):
|
||||
def generate_Doc(self, e: Doc):
|
||||
|
|
|
@ -46,20 +46,20 @@ class KatexClient:
|
|||
srcdir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# Test if `node_modules` directory exists and if not, run `npm install`
|
||||
if not os.path.isdir(srcdir + "/katex-server/node_modules"):
|
||||
if not os.path.isdir(srcdir + "/katex_server/node_modules"):
|
||||
print("Installing node dependencies for the first time...")
|
||||
npm = shutil.which("npm") or shutil.which("yarnpkg")
|
||||
if npm is None:
|
||||
raise NPMNotFoundError("npm not found. Node.js is required to use KaTeX.")
|
||||
subprocess.run([npm, "install"], cwd=srcdir+"/katex-server", check=True)
|
||||
subprocess.run([npm, "install"], cwd=srcdir+"/katex_server", check=True)
|
||||
|
||||
self._katex_server_path = srcdir + "/katex-server/index.mjs"
|
||||
self._katex_server_path = srcdir + "/katex_server/index.mjs"
|
||||
|
||||
self._server_process = subprocess.Popen(["node", self._katex_server_path, self._socket_file], stdout=subprocess.PIPE)
|
||||
|
||||
ok = self._server_process.stdout.readline()
|
||||
if ok != b"OK\n":
|
||||
raise KatexServerError("Failed to connect to katex-server")
|
||||
raise KatexServerError("Failed to connect to katex_server")
|
||||
|
||||
def connect(self):
|
||||
self._client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
|
|
|
@ -6,7 +6,7 @@ from panflute import MetaValue
|
|||
from typing import Union, Callable
|
||||
|
||||
from .whitespace import NBSP
|
||||
from .elements import FQuoted, FileLink
|
||||
from .elements import FQuoted, Slanted, FLink, FileLink
|
||||
from .context import Group, InlineGroup, BlockGroup, Context
|
||||
from .whitespace import Whitespace
|
||||
from .command import BlockCommand, InlineCommand, CodeCommand, Command
|
||||
|
@ -69,6 +69,7 @@ class NOPProcessor:
|
|||
Cite: self.transform_Cite,
|
||||
Code: self.transform_Code,
|
||||
Emph: self.transform_Emph,
|
||||
Slanted: self.transform_Slanted,
|
||||
Image: self.transform_Image,
|
||||
LineBreak: self.transform_LineBreak,
|
||||
Link: self.transform_Link,
|
||||
|
@ -88,6 +89,7 @@ class NOPProcessor:
|
|||
Underline: self.transform_Underline,
|
||||
NBSP: self.transform_NBSP,
|
||||
FQuoted: self.transform_FQuoted,
|
||||
FLink: self.transform_FLink,
|
||||
FileLink: self.transform_FileLink,
|
||||
|
||||
InlineCommand: self.transform_InlineCommand,
|
||||
|
@ -264,6 +266,10 @@ class NOPProcessor:
|
|||
e.content = self.transform(e.content)
|
||||
return e
|
||||
|
||||
def transform_Slanted(self, e: Slanted) -> Slanted:
|
||||
e.content = self.transform(e.content)
|
||||
return e
|
||||
|
||||
def transform_Link(self, e: Link) -> Link:
|
||||
e.content = self.transform(e.content)
|
||||
return e
|
||||
|
@ -300,6 +306,9 @@ class NOPProcessor:
|
|||
e.content = self.transform(e.content)
|
||||
return e
|
||||
|
||||
def transform_FLink(self, e: FLink) -> FLink:
|
||||
return self.transform_Link(e)
|
||||
|
||||
def transform_FileLink(self, e: FileLink) -> FileLink:
|
||||
e.content = self.transform(e.content)
|
||||
return e
|
||||
|
|
|
@ -7,7 +7,7 @@ from panflute import stringify
|
|||
from typing import Union, Callable
|
||||
|
||||
from .whitespace import NBSP
|
||||
from .elements import FQuoted, FileLink
|
||||
from .elements import FQuoted, Slanted, FLink, FileLink, FLineMarkup
|
||||
from .context import Group, InlineGroup, BlockGroup, Context
|
||||
|
||||
|
||||
|
@ -88,6 +88,7 @@ class OutputGenerator:
|
|||
DefinitionItem: self.generate_DefinitionItem,
|
||||
DefinitionList: self.generate_DefinitionList,
|
||||
Div: self.generate_Div,
|
||||
FLineMarkup: self.generate_FLineMarkup,
|
||||
Figure: self.generate_Figure,
|
||||
Header: self.generate_Header,
|
||||
HorizontalRule: self.generate_HorizontalRule,
|
||||
|
@ -108,6 +109,7 @@ class OutputGenerator:
|
|||
Cite: self.generate_Cite,
|
||||
Code: self.generate_Code,
|
||||
Emph: self.generate_Emph,
|
||||
Slanted: self.generate_Slanted,
|
||||
Image: self.generate_Image,
|
||||
LineBreak: self.generate_LineBreak,
|
||||
Link: self.generate_Link,
|
||||
|
@ -127,6 +129,7 @@ class OutputGenerator:
|
|||
Underline: self.generate_Underline,
|
||||
NBSP: self.generate_NBSP,
|
||||
FQuoted: self.generate_FQuoted,
|
||||
FLink: self.generate_FLink,
|
||||
FileLink: self.generate_FileLink,
|
||||
InlineGroup: self.generate_InlineGroup
|
||||
}
|
||||
|
@ -379,11 +382,17 @@ class OutputGenerator:
|
|||
def generate_Emph(self, e: Emph):
|
||||
self.generate_simple_tag(e)
|
||||
|
||||
def generate_Slanted(self, e: Slanted):
|
||||
self.generate_Emph(e)
|
||||
|
||||
def generate_Image(self, e: Image):
|
||||
self.generate_simple_tag(e)
|
||||
|
||||
def generate_Link(self, e: Link):
|
||||
self.generate_simple_tag(e)
|
||||
|
||||
def generate_FLink(self, e: FLink):
|
||||
self.generate_Link(e)
|
||||
|
||||
def generate_Note(self, e: Note):
|
||||
self.generate_simple_tag(e)
|
||||
|
@ -454,6 +463,9 @@ class OutputGenerator:
|
|||
def generate_Div(self, e: Div):
|
||||
self.generate_simple_tag(e)
|
||||
|
||||
def generate_FLineMarkup(self, e: FLineMarkup):
|
||||
self.generate_Div(e)
|
||||
|
||||
def generate_Header(self, e: Header):
|
||||
self.generate_simple_tag(e)
|
||||
|
||||
|
|
189
src/formatitko/tex/formatitko.tex
Normal file
189
src/formatitko/tex/formatitko.tex
Normal file
|
@ -0,0 +1,189 @@
|
|||
\input ltluatex.tex
|
||||
\input luatex85.sty
|
||||
\input ucwmac2.tex
|
||||
\ucwmodule{luaofs}
|
||||
\ucwmodule{verb}
|
||||
\ucwmodule{link}
|
||||
\clickablefalse
|
||||
|
||||
\pdfglyphtounicode{summationtext}{2211}
|
||||
\pdfglyphtounicode{summationdisplay}{2211}
|
||||
\pdfglyphtounicode{summation}{2211}
|
||||
|
||||
\pdfglyphtounicode{parenleftbig}{0028}
|
||||
\pdfglyphtounicode{parenrightbig}{0029}
|
||||
\pdfglyphtounicode{parenleftBig}{0028}
|
||||
\pdfglyphtounicode{parenrightBig}{0029}
|
||||
\pdfglyphtounicode{parenleftbigg}{0028}
|
||||
\pdfglyphtounicode{parenrightbigg}{0029}
|
||||
\pdfglyphtounicode{parenleftBigg}{0028}
|
||||
\pdfglyphtounicode{parenrightBigg}{0029}
|
||||
|
||||
\pdfglyphtounicode{radicalbig}{221A}
|
||||
\pdfglyphtounicode{radicalBig}{221A}
|
||||
\pdfglyphtounicode{radicalbigg}{221A}
|
||||
\pdfglyphtounicode{radicalBigg}{221A}
|
||||
\pdfglyphtounicode{hatwidest}{0302}
|
||||
|
||||
\input formatitkolib.tex
|
||||
|
||||
|
||||
\input minim-xmp.tex
|
||||
\startmetadata
|
||||
pdfaid:part 2
|
||||
pdfaid:conformance U
|
||||
stopmetadata
|
||||
|
||||
|
||||
\pdfcompresslevel=0
|
||||
\pdfobjcompresslevel=0
|
||||
% \pdfobj{/Alternate /DeviceRGB}
|
||||
|
||||
\input glyphtounicode.tex
|
||||
\pdfgentounicode=1
|
||||
|
||||
|
||||
%Create an OutputIntent in order to correctly specify colours
|
||||
\immediate\pdfobj stream attr{/N 3} file{sRGB.icc}
|
||||
\pdfcatalog{%
|
||||
/OutputIntents [
|
||||
<<
|
||||
/Type /OutputIntent
|
||||
/S /GTS_PDFA1
|
||||
/DestOutputProfile \the\pdflastobj\space 0 R
|
||||
/OutputConditionIdentifier (sRGB)
|
||||
/Info (sRGB)
|
||||
>>
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\parskip=5pt plus 3pt minus 2pt
|
||||
\parindent=0sp
|
||||
|
||||
|
||||
|
||||
|
||||
% Fonty
|
||||
\ofsdeclarefamily [Pagella] {%
|
||||
\loadtextfam qplr;%
|
||||
qplb;%
|
||||
qpli;%
|
||||
qplbi;;%
|
||||
}
|
||||
|
||||
% doporučen je horní, dolní a pravý okraj 25 mm, levý okraj 40 mm.
|
||||
% Protože doba tisknutí prací je už pryč, my máme stejně velkou stránku uprostřed papíru
|
||||
\voffset 25mm
|
||||
|
||||
\hoffset 32.5mm
|
||||
|
||||
\vsize\pdfpageheight
|
||||
\advance\vsize -2\voffset
|
||||
|
||||
\hsize\pdfpagewidth
|
||||
\advance\hsize -2\hoffset
|
||||
|
||||
\advance\voffset -\pdfvorigin
|
||||
\advance\hoffset -\pdfhorigin
|
||||
|
||||
\def\MSfeat#1{:mode=node;script=latn;+tlig}
|
||||
\registertfm qplr - file:texgyrepagella-regular.otf\MSfeat{}
|
||||
\registertfm qplb - file:texgyrepagella-bold.otf\MSfeat{}
|
||||
\registertfm qpli - file:texgyrepagella-italic.otf\MSfeat{}
|
||||
\registertfm qplbi - file:texgyrepagella-bolditalic.otf\MSfeat{}
|
||||
|
||||
%\setfonts[Pagella/10]
|
||||
%\def\h{\it} % hint
|
||||
%\def\bh{\bi} % bold hint
|
||||
|
||||
|
||||
\def\mod{\mathrel{\rm mod}}
|
||||
|
||||
\settextsize{12}
|
||||
|
||||
|
||||
\long\def\floatinsert#1{\par{
|
||||
\setbox0=\vbox{\boxmaxdepth=2pt\relax #1}
|
||||
\dimen0=\dimexpr \ht0 + \dp0 + \baselineskip + \pagetotal - \pageshrink \relax
|
||||
\ifdim\dimen0 > \pagegoal
|
||||
\insert\topins{
|
||||
\penalty 100
|
||||
\splittopskip=0pt
|
||||
\splitmaxdepth=\maxdimen
|
||||
\floatingpenalty=0
|
||||
\box0
|
||||
\nobreak\bigskip\medskip
|
||||
}
|
||||
\else
|
||||
\goodbreak\bigskip
|
||||
\box0
|
||||
\goodbreak\bigskip
|
||||
\unparskip
|
||||
\fi
|
||||
}}
|
||||
|
||||
% Obecny plovouci objekt: \float{objekt}{popisek}{mezera pred}{mezera po}
|
||||
\long\def\figure#1#2#3#4{
|
||||
\medskip#3
|
||||
\hbox to \hsize{\hfil\vtop{
|
||||
\parindent=0pt
|
||||
\leftskip=0pt plus 0.2\hsize
|
||||
\rightskip=0pt plus 0.2\hsize
|
||||
\parfillskip=0pt
|
||||
\spaceskip=0.3333em
|
||||
\settextsize{10}
|
||||
#1
|
||||
}\hfil}#4
|
||||
\medskip
|
||||
\smallskip
|
||||
{
|
||||
\setbox0=\hbox{\settextsize{10}#2}
|
||||
\ifdim\wd0 < 0.8\hsize
|
||||
\centerline{\box0}
|
||||
\else
|
||||
\centerline{\vtop{
|
||||
\hsize=0.8\hsize
|
||||
\parindent=0pt
|
||||
\leftskip=0pt plus 0.3\hsize
|
||||
\rightskip=0pt plus 0.3\hsize
|
||||
\parfillskip=0pt
|
||||
\spaceskip=0.3333em
|
||||
\settextsize{10}#2
|
||||
}}
|
||||
\fi
|
||||
}}
|
||||
|
||||
\long\def\floatpage#1{
|
||||
\pageinsert
|
||||
\vbox to \vsize{#1}
|
||||
\endinsert
|
||||
}
|
||||
|
||||
% Dva floaty vedle sebe: \float{objekt1}{popisek1}{id1}{objekt2}{popisek2}{id2}
|
||||
\def\twofloats#1#2#3#4#5#6{\floatinsert{
|
||||
\medskip
|
||||
\centerline{\vbox{\halign{\hss##\hss&\qquad\hss##\hss\cr
|
||||
#1\cr
|
||||
\noalign{\medskip\smallskip}
|
||||
#2\cr
|
||||
}}}
|
||||
}}
|
||||
|
||||
|
||||
|
||||
|
||||
% Obsah a odkazy
|
||||
\newwrite\tocfile
|
||||
\immediate\openout\tocfile=toc-new.aux
|
||||
|
||||
% Voláme: \addtoc\tocmacro{number}{asterisks}{title}
|
||||
\long\def\addtoc#1#2#3#4{%
|
||||
\edef\brum{%
|
||||
\write\tocfile{\string#1{\noexpand\the\noexpand\count0}{#2}{#3}{#4}}%
|
||||
}
|
||||
\brum%
|
||||
}
|
79
src/formatitko/tex/formatitkolib.tex
Normal file
79
src/formatitko/tex/formatitkolib.tex
Normal file
|
@ -0,0 +1,79 @@
|
|||
\def\strong#1{{%
|
||||
\def\emph##1{{\bi{}##1}}%
|
||||
\bf{}#1%
|
||||
}}
|
||||
\def\emph#1{{%
|
||||
\def\strong##1{{\bi{}##1}}%
|
||||
\it{}#1%
|
||||
}}
|
||||
|
||||
\def\textasciitilde{$\sim$}
|
||||
|
||||
|
||||
|
||||
\def\N{{\bb N}}
|
||||
\def\R{{\bb R}}
|
||||
\def\E{{\bb E}}
|
||||
\def\O{{\cal O}}
|
||||
\def\SYM{{\rm SYM}}
|
||||
\def\frac#1#2{{{#1} \over {#2}}}
|
||||
|
||||
\def\superscript#1{$^{\hbox{\settextsize{0.8\textsize}#1}}$}
|
||||
\def\subscript#1{$_{\hbox{\settextsize{0.8\textsize}#1}}$}
|
||||
\newcount\fncount
|
||||
\fncount=1
|
||||
\def\fnmark{$^{\the\fncount}$}
|
||||
\def\fn#1{\footnote\fnmark{#1}\advance\fncount by 1}
|
||||
\def\sectioneject{\vfil\supereject}
|
||||
\def\section#1#2{
|
||||
\sectioneject
|
||||
\vskip 16pt\vbox{\settextsize{20}\bf #1\kern 1em\relax#2%
|
||||
\addtoc\tocsection{#1}{}{#2}%
|
||||
}\nobreak\vskip 12pt
|
||||
}
|
||||
\def\subsection#1#2{
|
||||
\vskip 12pt\vbox{\settextsize{18}\bf #1\kern 1em\relax#2%
|
||||
\addtoc\tocsubsection{#1}{}{#2}%
|
||||
}\nobreak\vskip 7pt
|
||||
}
|
||||
\def\subsubsection#1#2{
|
||||
\vskip 10pt\vbox{\settextsize{16}\bf #1\kern 1em\relax#2%
|
||||
\addtoc\tocsubsubsection{#1}{}{#2}%
|
||||
}\nobreak\vskip 6pt
|
||||
}
|
||||
\def\subsubsubsection#1#2{
|
||||
\vskip 8pt\vbox{\settextsize{14}\bf #1\kern 1em\relax#2}\nobreak\vskip 5pt
|
||||
}
|
||||
\def\subsubsubsubsection#1#2{
|
||||
\vskip 7pt\vbox{\settextsize{12}\bf #1\kern 1em\relax#2}\nobreak\vskip 5pt
|
||||
}
|
||||
\def\subsubsubsubsubsection#1#2{
|
||||
\vskip 7pt\vbox{\settextsize{12}\bf #1\kern 1em\relax#2}\nobreak\vskip 5pt
|
||||
}
|
||||
\long\def\blockquote#1{\vskip\lineskip\vskip\parskip\hbox{\vrule\hskip5pt\vbox{#1}}}
|
||||
\def\strikeout#1{FIXME: Strikeout not implemented}
|
||||
\def\underline#1{FIXME: Underline not implemented}
|
||||
|
||||
|
||||
\def\mathbb#1{\hbox{\bb #1}}
|
||||
|
||||
\def\unparskip{\vskip-\parskip}
|
||||
|
||||
\catcode`@=11
|
||||
\def\vecoverrightarrow#1{\mathpalette\vecoverrightarrowtmp{#1}}
|
||||
\def\vecoverrightarrowtmp#1#2{\vbox{\m@th\ialign{##\crcr
|
||||
\vecrightarrowfill\crcr\noalign{\kern-\p@\kern 0.09em\nointerlineskip}
|
||||
$\hfil#1{#2\,}\hfil$\crcr}}}
|
||||
\def\vecrightarrowfill{$\settextsize{5}\m@th\smash-\mkern-7mu%
|
||||
\cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
|
||||
\settextsize{5}\mkern-7mu\mathord\rightarrow$}
|
||||
\catcode`@=12
|
||||
|
||||
|
||||
\long\def\linemarkup#1#2{%
|
||||
\par\noindent\hbox{%
|
||||
\hbox{}\hskip -6pt {\colorlocal{#1}\vrule width 1pt \hskip 5pt}%
|
||||
\hbox to \hsize{\vbox{#2}\hfil}%
|
||||
%\hbox{}\hskip 5pt {\colorlocal{#1}\vrule width 1pt \hskip -6pt}%
|
||||
}\par%
|
||||
}
|
22
src/formatitko/tex/table_of_contents.tex
Normal file
22
src/formatitko/tex/table_of_contents.tex
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
|
||||
\def\pagelink#1{#1}
|
||||
\def\toclink#1#2{%
|
||||
#2
|
||||
}
|
||||
|
||||
\def\stdskip{\vskip 3pt}
|
||||
\def\tocsection#1#2#3#4{
|
||||
\line{\bf\hbox to 2em{#2\hfil}#4~\hfil\pagelink{#1}}
|
||||
}
|
||||
\def\tocsubsection#1#2#3#4{
|
||||
\line{\hskip 1.5cm \hbox to 3em{#2\hfil}#4~\hfil\pagelink{#1}}
|
||||
}
|
||||
\def\tocsubsubsection#1#2#3#4{
|
||||
\line{\hskip 3cm \hbox to 4em{#2\hfil}#4~\hfil\pagelink{#1}}
|
||||
}
|
||||
\def\tocpicture#1#2#3#4{}
|
||||
|
||||
\vskip 1cm
|
||||
\input toc.aux
|
||||
}
|
18
src/formatitko/tex/table_of_contents_pictures.tex
Normal file
18
src/formatitko/tex/table_of_contents_pictures.tex
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
|
||||
\def\pagelink#1{#1}
|
||||
\def\toclink#1#2{%
|
||||
#2
|
||||
}
|
||||
|
||||
\def\stdskip{\vskip 3pt}
|
||||
\def\tocsection#1#2#3#4{}
|
||||
\def\tocsubsection#1#2#3#4{}
|
||||
\def\tocsubsubsection#1#2#3#4{}
|
||||
\def\tocpicture#1#2#3#4{
|
||||
\line{\hbox to 2em{#2\hfil}#4~\hfil\pagelink{#1}}\stdskip
|
||||
}
|
||||
|
||||
\vskip 1cm
|
||||
\input toc.aux
|
||||
}
|
|
@ -11,10 +11,14 @@ from .output_generator import OutputGenerator
|
|||
from .images import ImageProcessor, ImageProcessorNamespaceSearcher
|
||||
|
||||
from .whitespace import NBSP
|
||||
from .elements import FQuoted
|
||||
from .elements import FQuoted, FLineMarkup
|
||||
from .context import Group, InlineGroup, BlockGroup, Context
|
||||
from .util import inlinify
|
||||
|
||||
def color_to_rgb(color):
|
||||
import matplotlib.colors
|
||||
return matplotlib.colors.to_rgb(color)
|
||||
|
||||
class UCWTexGenerator(OutputGenerator):
|
||||
imageProcessor: ImageProcessor
|
||||
_bold: int
|
||||
|
@ -24,22 +28,30 @@ class UCWTexGenerator(OutputGenerator):
|
|||
self.imageProcessor = imageProcessor
|
||||
self._bold = 0
|
||||
self._italic = 0
|
||||
|
||||
self._floatpages = {}
|
||||
super().__init__(output_file, *args, **kwargs)
|
||||
|
||||
def escape_special_chars(self, text: str) -> str:
|
||||
text = text.replace("&", r"\&")
|
||||
text = text.replace("%", r"\%")
|
||||
text = text.replace("$", r"\$")
|
||||
text = text.replace("#", r"\#")
|
||||
text = text.replace("_", r"\_")
|
||||
text = text.replace("{", r"\{")
|
||||
text = text.replace("}", r"\}")
|
||||
text = text.replace("~", r"\textasciitilde{}")
|
||||
text = text.replace("^", r"\textasciicircum{}")
|
||||
text = text.replace("\\", r"\textbackslash{}")
|
||||
text = text.replace(" ", "~") # We use unicode no-break spaces to force nbsp in output
|
||||
text = text.replace("", "")
|
||||
return text
|
||||
if '\\' in text:
|
||||
print("ESCAPE", text)
|
||||
out = ""
|
||||
for char in text:
|
||||
out += {
|
||||
'&': r"\&",
|
||||
'%': r"\%",
|
||||
'$': r"\$",
|
||||
'#': r"\#",
|
||||
'_': r"\_",
|
||||
'{': r"\{",
|
||||
'}': r"\}",
|
||||
'~': r"\textasciitilde{}",
|
||||
'^': r"\textasciicircum{}",
|
||||
'\\': r"\textbackslash{}",
|
||||
' ': r"~",
|
||||
'': r"",
|
||||
}.get(char, char)
|
||||
return out
|
||||
|
||||
def generate(self, e: Union[Element, ListContainer]):
|
||||
if hasattr(e, "attributes") and "only" in e.attributes and e.attributes["only"] != "tex":
|
||||
|
@ -67,21 +79,17 @@ class UCWTexGenerator(OutputGenerator):
|
|||
self.writepar(r"\vskip5pt\hrule\hfil\vskip5pt{}")
|
||||
|
||||
def generate_Doc(self, e: Doc):
|
||||
self.writeln(r"\input ucwmac2.tex")
|
||||
self.writeln(r"\ucwmodule{ofs}")
|
||||
self.writeln(r"\ucwmodule{verb}")
|
||||
self.writeln(r"\ucwmodule{link}")
|
||||
self.writeln(r"\input formatitko.tex")
|
||||
self.generate(e.content)
|
||||
self.writeln(r"\bye")
|
||||
|
||||
def get_language_macro(self, lang: str):
|
||||
if lang == "cs":
|
||||
return r"\chyph\lefthyphenmin=2\righthyphenmin=2{}"
|
||||
return r"\uselanguage{czech}\frenchspacing\lefthyphenmin=2\righthyphenmin=2{}"
|
||||
elif lang == "sk":
|
||||
return r"\shyph\lefthyphenmin=2\righthyphenmin=2{}"
|
||||
return r"\uselanguage{slovak}\frenchspacing\lefthyphenmin=2\righthyphenmin=2{}"
|
||||
elif lang == "en":
|
||||
return r"\ehyph\lefthyphenmin=2\righthyphenmin=2{}"
|
||||
return r"\uselanguage{USenglish}\nonfrenchspacing\lefthyphenmin=2\righthyphenmin=2{}"
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
@ -101,7 +109,7 @@ class UCWTexGenerator(OutputGenerator):
|
|||
|
||||
def generate_Header(self, e: Header):
|
||||
self.ensure_empty(2)
|
||||
self.write("\\"+"sub"*(e.level-1)+"section{")
|
||||
self.write("\\"+"sub"*(e.level-1)+"section{"+".".join(map(str, e.attributes["number"]))+"}{")
|
||||
self.generate(e.content)
|
||||
self.write(r"}")
|
||||
self.ensure_empty(2)
|
||||
|
@ -147,31 +155,58 @@ class UCWTexGenerator(OutputGenerator):
|
|||
width = str(int(e.attributes["width"][:-1])/100) + "\\hsize"
|
||||
width = "width " + width
|
||||
|
||||
if isinstance(e.parent.parent, Figure):
|
||||
self.writeln(f'\\putimage{{{width}}}{{{url}}}')
|
||||
else:
|
||||
self.writepar(f'\\putimage{{{width}}}{{{url}}}')
|
||||
self.writeln(f'\\centerline{{\\putimage{{{width}}}{{{url}}}}}')
|
||||
|
||||
def generate_Code(self, e: Code):
|
||||
self.write(r"\verb`")
|
||||
self.write(e.text)
|
||||
self.write(r"`")
|
||||
|
||||
def generate_Figure(self, e: Figure):
|
||||
self.ensure_empty(2)
|
||||
self.writeln(r"\vskip5pt")
|
||||
self.writeln(r"\centerline{")
|
||||
def generate_nonfloat_Figure(self, e: Figure):
|
||||
self.writeln(r"\figure{")
|
||||
self.indent_more()
|
||||
self.generate(e.content)
|
||||
self.indent_less()
|
||||
self.writeln(r"}")
|
||||
self.writeln(r"\centerline{")
|
||||
self.writeln(r"}{")
|
||||
self.indent_more()
|
||||
if 'number' in e.attributes:
|
||||
type_text = e.attributes.get("type_text", "Obrázek")
|
||||
self.writeln(f"{type_text} {e.attributes['number']}:")
|
||||
self.generate(e.caption)
|
||||
if 'number' in e.attributes:
|
||||
tocmac = e.attributes.get("tocmac", "tocpicture")
|
||||
if tocmac:
|
||||
self.writeln("\\addtoc\\"+tocmac+r"{"+str(e.attributes['number'])+"}{}{")
|
||||
self.indent_more()
|
||||
self.generate(e.caption.content)
|
||||
self.indent_less()
|
||||
self.writeln("}")
|
||||
self.indent_less()
|
||||
self.writeln(r"}")
|
||||
self.writeln(r"\vskip5pt{}")
|
||||
self.ensure_empty(2)
|
||||
self.writeln(r"}{}{}")
|
||||
|
||||
|
||||
def generate_Figure(self, e: Figure):
|
||||
if "floatpage" in e.attributes:
|
||||
fp = e.attributes["floatpage"]
|
||||
flush = fp[-1]=="!"
|
||||
if flush:
|
||||
fp = fp[:-1]
|
||||
self._floatpages.setdefault(fp, [])
|
||||
self._floatpages[fp].append(e)
|
||||
if flush:
|
||||
self.writeln(r"\floatpage{")
|
||||
self.writeln(r"\vfill")
|
||||
for x in self._floatpages[fp]:
|
||||
self.generate_nonfloat_Figure(x)
|
||||
self.writeln(r"\vfill")
|
||||
self.writeln(r"}")
|
||||
del self._floatpages[fp]
|
||||
else:
|
||||
self.ensure_empty(2)
|
||||
self.writeln(r"\floatinsert{")
|
||||
self.generate_nonfloat_Figure(e)
|
||||
self.writeln(r"}")
|
||||
self.ensure_empty(2)
|
||||
|
||||
def generate_Emph(self, e: Emph):
|
||||
if self._bold > 0:
|
||||
|
@ -183,6 +218,11 @@ class UCWTexGenerator(OutputGenerator):
|
|||
self._italic-=1
|
||||
self.write(r"}")
|
||||
|
||||
def generate_Slanted(self, e: Emph):
|
||||
self.write(r"{\sl{}")
|
||||
self.generate(e.content)
|
||||
self.write(r"}")
|
||||
|
||||
def generate_Strong(self, e: Strong):
|
||||
if self._italic > 0:
|
||||
self.write(r"{\bi{}")
|
||||
|
@ -194,15 +234,15 @@ class UCWTexGenerator(OutputGenerator):
|
|||
self.write(r"}")
|
||||
|
||||
def generate_Caption(self, e: Caption):
|
||||
self.generate_Emph(e)
|
||||
self.generate(e.content)
|
||||
|
||||
def generate_Math(self, e: Math):
|
||||
if e.format == "DisplayMath":
|
||||
self.ensure_empty(2)
|
||||
self.ensure_empty(1)
|
||||
self.writeraw("$$")
|
||||
self.writeraw(e.text.strip())
|
||||
self.writeraw("$$")
|
||||
self.ensure_empty(2)
|
||||
self.ensure_empty(1)
|
||||
else:
|
||||
self.write("$")
|
||||
self.write(e.text)
|
||||
|
@ -214,22 +254,23 @@ class UCWTexGenerator(OutputGenerator):
|
|||
self.write(r"}")
|
||||
|
||||
def generate_Table(self, e: Table):
|
||||
hskip = r"\hskip 0.6em\relax"
|
||||
aligns = {
|
||||
"AlignLeft": r"\quad#\quad\hfil",
|
||||
"AlignRight": r"\quad\hfil#\quad",
|
||||
"AlignCenter": r"\quad\hfil#\hfil\quad",
|
||||
"AlignDefault": r"\quad#\quad\hfil"
|
||||
"AlignLeft": hskip+r"\relax#\hfil"+hskip,
|
||||
"AlignRight": hskip+r"\hfil#"+hskip,
|
||||
"AlignCenter": hskip+r"\hfil#\hfil"+hskip,
|
||||
"AlignDefault": hskip+r"#\hfil"+hskip,
|
||||
}
|
||||
self.writeln(r"\vskip1em")
|
||||
self.writeln(r"\halign{\strut"+"&".join([aligns[col[0]] for col in e.colspec])+r"\cr")
|
||||
self.writeln(r"\leavevmode\vbox{\halign{\strut"+"&".join([aligns[col[0]] for col in e.colspec])+r"\cr")
|
||||
self.indent_more()
|
||||
self.generate(e.head.content)
|
||||
self.writeln(r"\noalign{\hrule}")
|
||||
self.writeln(r"\noalign{\vskip 0.3em\hrule\vskip 0.3em}")
|
||||
self.generate(e.content[0].content)
|
||||
self.writeln(r"\noalign{\hrule}")
|
||||
self.writeln(r"\noalign{\vskip 0.3em\hrule\vskip 0.3em}")
|
||||
self.generate(e.foot.content)
|
||||
self.indent_less()
|
||||
self.writeln("}")
|
||||
self.writeln("}}")
|
||||
self.writeln(r"\vskip1em")
|
||||
|
||||
def generate_TableRow(self, e: TableRow):
|
||||
|
@ -263,6 +304,16 @@ class UCWTexGenerator(OutputGenerator):
|
|||
|
||||
def generate_Div(self, e: Div):
|
||||
self.generate(e.content)
|
||||
|
||||
def generate_FLineMarkup(self, e: FLineMarkup):
|
||||
self.ensure_empty(2)
|
||||
r,g,b = color_to_rgb(e.color)
|
||||
self.writeln(r"\linemarkup{\rgb{"+f"{r} {g} {b}"+"}}{")
|
||||
self.indent_more()
|
||||
self.generate(e.content)
|
||||
self.indent_less()
|
||||
self.writeln(r"}")
|
||||
self.ensure_empty(2)
|
||||
|
||||
def generate_LineBlock(self, e: LineBlock):
|
||||
self.writeln()
|
||||
|
@ -323,6 +374,11 @@ class UCWTexGenerator(OutputGenerator):
|
|||
self.writeln(r"}")
|
||||
|
||||
def generate_Link(self, e: Link):
|
||||
if len(e.content) == 0:
|
||||
if e.url.startswith('#'):
|
||||
obj = e.obj_map[e.url[1:]]
|
||||
self.write(str(obj.attributes["number"]))
|
||||
return
|
||||
if len(e.content) == 1 and isinstance(e.content[0], Str) and e.content[0].text == e.url:
|
||||
self.write(r"\url{")
|
||||
else:
|
||||
|
@ -348,7 +404,7 @@ class UCWTexGenerator(OutputGenerator):
|
|||
self.writeln("% FIXME: Citations not implemented")
|
||||
|
||||
def generate_Cite(self, e: Cite):
|
||||
self.writeln("% FIXME: Cites not implemented")
|
||||
self.generate(e.content)
|
||||
|
||||
def generate_Definition(self, e: Definition):
|
||||
self.writeln("% FIXME: Definitions not implemented")
|
||||
|
@ -364,3 +420,8 @@ class UCWTexGenerator(OutputGenerator):
|
|||
|
||||
def generate_Strikeout(self, e: Strikeout):
|
||||
self.writeln("% FIXME: Strikeouts not implemented")
|
||||
|
||||
def generate_SmallCaps(self, e: Strikeout):
|
||||
self.write(r"{\csc{}")
|
||||
self.generate(e.content)
|
||||
self.write(r"}")
|
||||
|
|
|
@ -14,7 +14,7 @@ import importlib
|
|||
import json
|
||||
|
||||
from .whitespace import NBSP
|
||||
from .elements import FQuoted
|
||||
from .elements import FQuoted, Slanted, FLink
|
||||
from .context import Group, InlineGroup, BlockGroup
|
||||
from .util import nullify, import_md
|
||||
from .context import Context, CommandCallable
|
||||
|
@ -228,12 +228,12 @@ class TransformProcessor(NOPProcessor):
|
|||
importedDoc = import_md(open(filename, "r").read())
|
||||
self.transform(importedDoc.content)
|
||||
elif e.attributes["type"] == "module":
|
||||
matches = re.match(r"^(\w+)(?: as (\w+))?$", e.content[0].text[1:])
|
||||
matches = re.match(r"^([\w\.]+)(?: as (\w+))?$", e.content[0].text[1:])
|
||||
if not matches:
|
||||
raise SyntaxError(f"`{e.content[0].text[1:]}`: invalid syntax")
|
||||
module = importlib.import_module(matches.group(1))
|
||||
module_name = matches.group(1) if matches.group(2) is None else matches.group(2)
|
||||
self.context.add_commands_from_module(module, module_name)
|
||||
self.context.add_commands_from_module(module, "")
|
||||
elif e.attributes["type"] == "metadata":
|
||||
filename = self.context.dir + "/" + e.content[0].text[1:]
|
||||
self.context.add_dep(filename)
|
||||
|
@ -260,6 +260,11 @@ class TransformProcessor(NOPProcessor):
|
|||
raise TypeError(f"Cannot print value of metadatum '{e.content[0].text[1:]}' of type '{type(val)}'")
|
||||
return e
|
||||
|
||||
if "slanted" in e.classes:
|
||||
# `.slanted` class for Span
|
||||
# Content of Span is enclosed into Slanted (subclass os Emph)
|
||||
return self.transform(Slanted(*e.content))
|
||||
|
||||
return super().transform_Span(e)
|
||||
|
||||
def transform_CodeBlock(self, e: CodeBlock) -> Union[CodeBlock, Div, Null]:
|
||||
|
@ -306,3 +311,26 @@ class TransformProcessor(NOPProcessor):
|
|||
else:
|
||||
return e
|
||||
|
||||
def transform_Header(self, e: Header) -> Header:
|
||||
if "number" not in e.attributes:
|
||||
if 'unnumbered' in e.classes:
|
||||
e.attributes["number"] = ""
|
||||
else:
|
||||
e.attributes["number"] = self.context.get_data("section_number_generator")(e, self.context)
|
||||
return e
|
||||
|
||||
def transform_Figure(self, e: Figure) -> Figure:
|
||||
if "number" not in e.attributes:
|
||||
if 'unnumbered' in e.classes:
|
||||
e.attributes["number"] = ""
|
||||
else:
|
||||
e.attributes["number"] = self.context.get_data("figure_number_generator")(e, self.context)
|
||||
self.context.get_data("obj_map")[e.identifier] = e
|
||||
self.context.set_data("current_figure", e)
|
||||
r = super().transform_Figure(e)
|
||||
self.context.unset_data("current_figure")
|
||||
return r
|
||||
|
||||
def transform_Link(self, e: Link) -> Link:
|
||||
e = FLink(*e.content, url=e.url, identifier=e.identifier, attributes=e.attributes, classes=e.classes, obj_map=self.context.get_data("obj_map"))
|
||||
return super().transform_Link(e)
|
||||
|
|
|
@ -66,14 +66,14 @@ raise Exception("Jsem piča")
|
|||
-->
|
||||
|
||||
![This is a figure, go figure...](logo.svg){width=25%}What
|
||||
|
||||
![This is a figure, go figure...](logo.pdf){width=50%}
|
||||
![Fakt epesní reproduktor](reproduktor.jpeg){width=10em}
|
||||
![Fakt epesní reproduktor](reproduktor.png "Hodně rozpixelovaný obrázek reproduktoru"){width=10em file-width=1000}
|
||||
|
||||
```
|
||||
|
||||
|
||||
![This is a figure, go figure...](logo.jpg){width=50%}
|
||||
|
||||
![This is a figure, go figure...](logo1.png){width=10em}
|
||||
|
||||
![Fakt epesní reproduktor](reproduktor.jpeg){width=10em}
|
||||
|
||||
![Fakt epesní reproduktor](reproduktor.png "Hodně rozpixelovaný obrázek reproduktoru"){width=10em file-width=1000}
|
||||
|
||||
|
|
Loading…
Reference in a new issue