2018-05-09 14:10:04 -07:00
|
|
|
import os
|
2018-08-10 15:12:49 -07:00
|
|
|
import hashlib
|
|
|
|
|
2018-12-24 12:37:51 -08:00
|
|
|
from manimlib.constants import TEX_DIR
|
|
|
|
from manimlib.constants import TEX_TEXT_TO_REPLACE
|
|
|
|
from manimlib.constants import TEX_USE_CTEX
|
2018-05-09 14:10:04 -07:00
|
|
|
|
|
|
|
|
2018-08-11 19:38:59 -07:00
|
|
|
def tex_hash(expression, template_tex_file_body):
|
|
|
|
id_str = str(expression + template_tex_file_body)
|
2018-08-10 15:12:49 -07:00
|
|
|
hasher = hashlib.sha256()
|
|
|
|
hasher.update(id_str.encode())
|
|
|
|
# Truncating at 16 bytes for cleanliness
|
|
|
|
return hasher.hexdigest()[:16]
|
2018-05-09 14:10:04 -07:00
|
|
|
|
|
|
|
|
2018-08-11 19:38:59 -07:00
|
|
|
def tex_to_svg_file(expression, template_tex_file_body):
|
|
|
|
tex_file = generate_tex_file(expression, template_tex_file_body)
|
2018-05-09 14:10:04 -07:00
|
|
|
dvi_file = tex_to_dvi(tex_file)
|
|
|
|
return dvi_to_svg(dvi_file)
|
|
|
|
|
|
|
|
|
2018-08-11 19:38:59 -07:00
|
|
|
def generate_tex_file(expression, template_tex_file_body):
|
2018-05-09 14:10:04 -07:00
|
|
|
result = os.path.join(
|
|
|
|
TEX_DIR,
|
2018-08-11 19:38:59 -07:00
|
|
|
tex_hash(expression, template_tex_file_body)
|
2018-05-09 14:10:04 -07:00
|
|
|
) + ".tex"
|
|
|
|
if not os.path.exists(result):
|
|
|
|
print("Writing \"%s\" to %s" % (
|
|
|
|
"".join(expression), result
|
|
|
|
))
|
2018-08-11 19:38:59 -07:00
|
|
|
new_body = template_tex_file_body.replace(
|
|
|
|
TEX_TEXT_TO_REPLACE, expression
|
|
|
|
)
|
2018-05-09 14:10:04 -07:00
|
|
|
with open(result, "w") as outfile:
|
2018-08-11 19:38:59 -07:00
|
|
|
outfile.write(new_body)
|
2018-05-09 14:10:04 -07:00
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
def get_null():
|
|
|
|
if os.name == "nt":
|
|
|
|
return "NUL"
|
|
|
|
return "/dev/null"
|
|
|
|
|
|
|
|
|
|
|
|
def tex_to_dvi(tex_file):
|
2018-09-26 21:09:04 +08:00
|
|
|
result = tex_file.replace(".tex", ".dvi" if not TEX_USE_CTEX else ".xdv")
|
2018-05-09 14:10:04 -07:00
|
|
|
if not os.path.exists(result):
|
|
|
|
commands = [
|
|
|
|
"latex",
|
|
|
|
"-interaction=batchmode",
|
|
|
|
"-halt-on-error",
|
|
|
|
"-output-directory=" + TEX_DIR,
|
|
|
|
tex_file,
|
|
|
|
">",
|
|
|
|
get_null()
|
2018-09-26 21:09:04 +08:00
|
|
|
] if not TEX_USE_CTEX else [
|
|
|
|
"xelatex",
|
|
|
|
"-no-pdf",
|
|
|
|
"-interaction=batchmode",
|
|
|
|
"-halt-on-error",
|
|
|
|
"-output-directory=" + TEX_DIR,
|
|
|
|
tex_file,
|
|
|
|
">",
|
|
|
|
get_null()
|
2018-05-09 14:10:04 -07:00
|
|
|
]
|
|
|
|
exit_code = os.system(" ".join(commands))
|
|
|
|
if exit_code != 0:
|
|
|
|
log_file = tex_file.replace(".tex", ".log")
|
|
|
|
raise Exception(
|
2018-09-26 21:09:04 +08:00
|
|
|
("Latex error converting to dvi. " if not TEX_USE_CTEX
|
|
|
|
else "Xelatex error converting to xdv. ") +
|
2018-05-09 14:10:04 -07:00
|
|
|
"See log output above or the log file: %s" % log_file)
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
def dvi_to_svg(dvi_file, regen_if_exists=False):
|
|
|
|
"""
|
|
|
|
Converts a dvi, which potentially has multiple slides, into a
|
|
|
|
directory full of enumerated pngs corresponding with these slides.
|
|
|
|
Returns a list of PIL Image objects for these images sorted as they
|
|
|
|
where in the dvi
|
|
|
|
"""
|
2018-09-26 21:09:04 +08:00
|
|
|
result = dvi_file.replace(".dvi" if not TEX_USE_CTEX else ".xdv", ".svg")
|
2018-05-09 14:10:04 -07:00
|
|
|
if not os.path.exists(result):
|
|
|
|
commands = [
|
|
|
|
"dvisvgm",
|
|
|
|
dvi_file,
|
|
|
|
"-n",
|
|
|
|
"-v",
|
|
|
|
"0",
|
|
|
|
"-o",
|
|
|
|
result,
|
|
|
|
">",
|
|
|
|
get_null()
|
|
|
|
]
|
|
|
|
os.system(" ".join(commands))
|
|
|
|
return result
|