mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 06:52:21 -04:00
refactor latex into media support
This commit is contained in:
parent
6a21be9d19
commit
3b3fef4ebc
3 changed files with 83 additions and 50 deletions
|
@ -1940,6 +1940,8 @@ create index if not exists ix_fields_value on fields (value)""")
|
||||||
# media
|
# media
|
||||||
deck.s.statement("""
|
deck.s.statement("""
|
||||||
create unique index if not exists ix_media_filename on media (filename)""")
|
create unique index if not exists ix_media_filename on media (filename)""")
|
||||||
|
deck.s.statement("""
|
||||||
|
create index if not exists ix_media_originalPath on media (originalPath)""")
|
||||||
# deletion tracking
|
# deletion tracking
|
||||||
deck.s.statement("""
|
deck.s.statement("""
|
||||||
create index if not exists ix_cardsDeleted_cardId on cardsDeleted (cardId)""")
|
create index if not exists ix_cardsDeleted_cardId on cardsDeleted (cardId)""")
|
||||||
|
@ -2182,6 +2184,7 @@ where interval < 1""")
|
||||||
if deck.version < 18:
|
if deck.version < 18:
|
||||||
deck.version = 18
|
deck.version = 18
|
||||||
deck.s.commit()
|
deck.s.commit()
|
||||||
|
DeckStorage._addIndices(deck)
|
||||||
deck.s.statement("analyze")
|
deck.s.statement("analyze")
|
||||||
return deck
|
return deck
|
||||||
_upgradeDeck = staticmethod(_upgradeDeck)
|
_upgradeDeck = staticmethod(_upgradeDeck)
|
||||||
|
|
108
anki/latex.py
108
anki/latex.py
|
@ -8,14 +8,10 @@ Latex support
|
||||||
"""
|
"""
|
||||||
__docformat__ = 'restructuredtext'
|
__docformat__ = 'restructuredtext'
|
||||||
|
|
||||||
import re, tempfile, os, sys, subprocess
|
import re, tempfile, os, sys, subprocess, stat, time
|
||||||
|
from anki.utils import genID, checksum
|
||||||
|
from anki.media import copyToMedia
|
||||||
from htmlentitydefs import entitydefs
|
from htmlentitydefs import entitydefs
|
||||||
try:
|
|
||||||
import hashlib
|
|
||||||
md5 = hashlib.md5
|
|
||||||
except ImportError:
|
|
||||||
import md5
|
|
||||||
md5 = md5.new
|
|
||||||
|
|
||||||
latexPreamble = ("\\documentclass[12pt]{article}\n"
|
latexPreamble = ("\\documentclass[12pt]{article}\n"
|
||||||
"\\special{papersize=3in,5in}"
|
"\\special{papersize=3in,5in}"
|
||||||
|
@ -74,13 +70,14 @@ def call(*args, **kwargs):
|
||||||
break
|
break
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def generatedFile(latexCode):
|
def latexImgFile(deck, latexCode):
|
||||||
return "%s.png" % md5(latexCode).hexdigest()
|
key = checksum(latexCode)
|
||||||
|
return deck.s.scalar("select filename from media where originalPath = :k",
|
||||||
|
k=key)
|
||||||
|
|
||||||
def generatedPath(deck, latexCode):
|
def latexImgPath(deck, file):
|
||||||
"Return the path to the cache file in system encoding format."
|
"Return the path to the cache file in system encoding format."
|
||||||
path = os.path.join(deck.mediaDir(create=True),
|
path = os.path.join(deck.mediaDir(create=True), file)
|
||||||
generatedFile(latexCode))
|
|
||||||
return path.encode(sys.getfilesystemencoding())
|
return path.encode(sys.getfilesystemencoding())
|
||||||
|
|
||||||
def mungeLatex(latex):
|
def mungeLatex(latex):
|
||||||
|
@ -92,38 +89,65 @@ def mungeLatex(latex):
|
||||||
latex = latex.encode("utf-8")
|
latex = latex.encode("utf-8")
|
||||||
return latex
|
return latex
|
||||||
|
|
||||||
|
def deleteAllLatexImages(deck):
|
||||||
|
for f in deck.s.column0(
|
||||||
|
"select filename from media where description = 'latex'"):
|
||||||
|
path = latexImgPath(deck, f)
|
||||||
|
try:
|
||||||
|
os.unlink(path)
|
||||||
|
except (OSError, IOError):
|
||||||
|
pass
|
||||||
|
deck.s.statement("delete from media where description = 'latex'")
|
||||||
|
deck.flushMod()
|
||||||
|
|
||||||
|
def cacheAllLatexImages(deck):
|
||||||
|
fields = deck.s.column0("select value from fields")
|
||||||
|
for field in fields:
|
||||||
|
renderLatex(deck, field)
|
||||||
|
|
||||||
|
def buildImg(deck, latex):
|
||||||
|
log = open(os.path.join(tmpdir, "latex_log.txt"), "w+")
|
||||||
|
texpath = os.path.join(tmpdir, "tmp.tex")
|
||||||
|
texfile = file(texpath, "w")
|
||||||
|
texfile.write(latexPreamble + "\n")
|
||||||
|
texfile.write(latex + "\n")
|
||||||
|
texfile.write(latexPostamble + "\n")
|
||||||
|
texfile.close()
|
||||||
|
texpath = texpath.encode(sys.getfilesystemencoding())
|
||||||
|
oldcwd = os.getcwd()
|
||||||
|
if sys.platform == "win32":
|
||||||
|
si = subprocess.STARTUPINFO()
|
||||||
|
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
|
else:
|
||||||
|
si = None
|
||||||
|
try:
|
||||||
|
os.chdir(tmpdir)
|
||||||
|
errmsg = _(
|
||||||
|
"Error executing 'latex' or 'dvipng'.\n"
|
||||||
|
"A log file is available here:\n%s") % tmpdir
|
||||||
|
if call(["latex", "-interaction=nonstopmode",
|
||||||
|
texpath], stdout=log, stderr=log, startupinfo=si):
|
||||||
|
return (False, errmsg)
|
||||||
|
if call(latexDviPngCmd + ["tmp.dvi", "-o", "tmp.png"],
|
||||||
|
stdout=log, stderr=log, startupinfo=si):
|
||||||
|
return (False, errmsg)
|
||||||
|
# add to media
|
||||||
|
path = copyToMedia(deck, "tmp.png", latex=checksum(latex))
|
||||||
|
return (True, path)
|
||||||
|
finally:
|
||||||
|
os.chdir(oldcwd)
|
||||||
|
|
||||||
def imageForLatex(deck, latex):
|
def imageForLatex(deck, latex):
|
||||||
"Return an image that represents 'latex', building if necessary."
|
"Return an image that represents 'latex', building if necessary."
|
||||||
imagePath = generatedPath(deck, latex)
|
imageFile = latexImgFile(deck, latex)
|
||||||
if not os.path.exists(imagePath):
|
if imageFile:
|
||||||
log = open(os.path.join(tmpdir, "latex_log.txt"), "w+")
|
path = latexImgPath(deck, imageFile)
|
||||||
texpath = os.path.join(tmpdir, "tmp.tex")
|
ok = True
|
||||||
texfile = file(texpath, "w")
|
if not imageFile or not os.path.exists(path):
|
||||||
texfile.write(latexPreamble + "\n")
|
(ok, imageFile) = buildImg(deck, latex)
|
||||||
texfile.write(latex + "\n")
|
if not ok:
|
||||||
texfile.write(latexPostamble + "\n")
|
return (False, imageFile)
|
||||||
texfile.close()
|
return (True, imageFile)
|
||||||
texpath = texpath.encode(sys.getfilesystemencoding())
|
|
||||||
oldcwd = os.getcwd()
|
|
||||||
if sys.platform == "win32":
|
|
||||||
si = subprocess.STARTUPINFO()
|
|
||||||
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
||||||
else:
|
|
||||||
si = None
|
|
||||||
try:
|
|
||||||
os.chdir(tmpdir)
|
|
||||||
errmsg = _(
|
|
||||||
"Error executing 'latex' or 'dvipng'.\n"
|
|
||||||
"A log file is available here:\n%s") % tmpdir
|
|
||||||
if call(["latex", "-interaction=nonstopmode",
|
|
||||||
texpath], stdout=log, stderr=log, startupinfo=si):
|
|
||||||
return (False, errmsg)
|
|
||||||
if call(latexDviPngCmd + ["tmp.dvi", "-o", imagePath],
|
|
||||||
stdout=log, stderr=log, startupinfo=si):
|
|
||||||
return (False, errmsg)
|
|
||||||
finally:
|
|
||||||
os.chdir(oldcwd)
|
|
||||||
return (True, imagePath)
|
|
||||||
|
|
||||||
def imgLink(deck, latex):
|
def imgLink(deck, latex):
|
||||||
"Parse LATEX and return a HTML image representing the output."
|
"Parse LATEX and return a HTML image representing the output."
|
||||||
|
|
|
@ -51,9 +51,15 @@ def mediaFilename(path):
|
||||||
ext = os.path.splitext(path)[1].lower()
|
ext = os.path.splitext(path)[1].lower()
|
||||||
return "%s%s" % (new, ext)
|
return "%s%s" % (new, ext)
|
||||||
|
|
||||||
def copyToMedia(deck, path):
|
def copyToMedia(deck, path, latex=None):
|
||||||
"""Copy PATH to MEDIADIR, and return new filename.
|
"""Copy PATH to MEDIADIR, and return new filename.
|
||||||
Update media table. If file already exists, don't copy."""
|
Update media table. If file already exists, don't copy."""
|
||||||
|
if latex:
|
||||||
|
origPath = latex
|
||||||
|
description = "latex"
|
||||||
|
else:
|
||||||
|
origPath = path
|
||||||
|
description = os.path.splitext(os.path.basename(path))[0]
|
||||||
newBase = mediaFilename(path)
|
newBase = mediaFilename(path)
|
||||||
new = os.path.join(deck.mediaDir(create=True), newBase)
|
new = os.path.join(deck.mediaDir(create=True), newBase)
|
||||||
# copy if not existing
|
# copy if not existing
|
||||||
|
@ -80,9 +86,9 @@ values (:id, :filename, :size, :created, :originalPath,
|
||||||
filename=newBase,
|
filename=newBase,
|
||||||
size=newSize,
|
size=newSize,
|
||||||
created=time.time(),
|
created=time.time(),
|
||||||
originalPath=path,
|
originalPath=origPath,
|
||||||
description=os.path.splitext(
|
description=description)
|
||||||
os.path.basename(path))[0])
|
deck.flushMod()
|
||||||
return newBase
|
return newBase
|
||||||
|
|
||||||
def _modifyFields(deck, fieldsToUpdate, modifiedFacts, dirty):
|
def _modifyFields(deck, fieldsToUpdate, modifiedFacts, dirty):
|
||||||
|
@ -118,8 +124,6 @@ def rebuildMediaDir(deck, deleteRefs=False, dirty=True):
|
||||||
oldPath = os.path.join(deck.mediaDir(), oldBase)
|
oldPath = os.path.join(deck.mediaDir(), oldBase)
|
||||||
if oldBase.startswith("."):
|
if oldBase.startswith("."):
|
||||||
continue
|
continue
|
||||||
if oldBase.startswith("latex-"):
|
|
||||||
continue
|
|
||||||
if os.path.isdir(oldPath):
|
if os.path.isdir(oldPath):
|
||||||
continue
|
continue
|
||||||
newBase = copyToMedia(deck, oldPath)
|
newBase = copyToMedia(deck, oldPath)
|
||||||
|
@ -164,12 +168,14 @@ def rebuildMediaDir(deck, deleteRefs=False, dirty=True):
|
||||||
deck.deleteTags(unmodifiedFacts.keys(), _("Media Missing"))
|
deck.deleteTags(unmodifiedFacts.keys(), _("Media Missing"))
|
||||||
# build cache of db records
|
# build cache of db records
|
||||||
mediaIds = dict(deck.s.all("select filename, id from media"))
|
mediaIds = dict(deck.s.all("select filename, id from media"))
|
||||||
|
# assume latex files exist
|
||||||
|
for f in deck.s.column0(
|
||||||
|
"select filename from media where description = 'latex'"):
|
||||||
|
usedFiles[f] = 1
|
||||||
# look through the media dir for any unused files, and delete
|
# look through the media dir for any unused files, and delete
|
||||||
for f in os.listdir(unicode(deck.mediaDir())):
|
for f in os.listdir(unicode(deck.mediaDir())):
|
||||||
if f.startswith("."):
|
if f.startswith("."):
|
||||||
continue
|
continue
|
||||||
if f.startswith("latex-"):
|
|
||||||
continue
|
|
||||||
path = os.path.join(deck.mediaDir(), f)
|
path = os.path.join(deck.mediaDir(), f)
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
|
|
Loading…
Reference in a new issue