mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 22:42:25 -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
|
||||
deck.s.statement("""
|
||||
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
|
||||
deck.s.statement("""
|
||||
create index if not exists ix_cardsDeleted_cardId on cardsDeleted (cardId)""")
|
||||
|
@ -2182,6 +2184,7 @@ where interval < 1""")
|
|||
if deck.version < 18:
|
||||
deck.version = 18
|
||||
deck.s.commit()
|
||||
DeckStorage._addIndices(deck)
|
||||
deck.s.statement("analyze")
|
||||
return deck
|
||||
_upgradeDeck = staticmethod(_upgradeDeck)
|
||||
|
|
108
anki/latex.py
108
anki/latex.py
|
@ -8,14 +8,10 @@ Latex support
|
|||
"""
|
||||
__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
|
||||
try:
|
||||
import hashlib
|
||||
md5 = hashlib.md5
|
||||
except ImportError:
|
||||
import md5
|
||||
md5 = md5.new
|
||||
|
||||
latexPreamble = ("\\documentclass[12pt]{article}\n"
|
||||
"\\special{papersize=3in,5in}"
|
||||
|
@ -74,13 +70,14 @@ def call(*args, **kwargs):
|
|||
break
|
||||
return ret
|
||||
|
||||
def generatedFile(latexCode):
|
||||
return "%s.png" % md5(latexCode).hexdigest()
|
||||
def latexImgFile(deck, latexCode):
|
||||
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."
|
||||
path = os.path.join(deck.mediaDir(create=True),
|
||||
generatedFile(latexCode))
|
||||
path = os.path.join(deck.mediaDir(create=True), file)
|
||||
return path.encode(sys.getfilesystemencoding())
|
||||
|
||||
def mungeLatex(latex):
|
||||
|
@ -92,38 +89,65 @@ def mungeLatex(latex):
|
|||
latex = latex.encode("utf-8")
|
||||
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):
|
||||
"Return an image that represents 'latex', building if necessary."
|
||||
imagePath = generatedPath(deck, latex)
|
||||
if not os.path.exists(imagePath):
|
||||
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", imagePath],
|
||||
stdout=log, stderr=log, startupinfo=si):
|
||||
return (False, errmsg)
|
||||
finally:
|
||||
os.chdir(oldcwd)
|
||||
return (True, imagePath)
|
||||
imageFile = latexImgFile(deck, latex)
|
||||
if imageFile:
|
||||
path = latexImgPath(deck, imageFile)
|
||||
ok = True
|
||||
if not imageFile or not os.path.exists(path):
|
||||
(ok, imageFile) = buildImg(deck, latex)
|
||||
if not ok:
|
||||
return (False, imageFile)
|
||||
return (True, imageFile)
|
||||
|
||||
def imgLink(deck, latex):
|
||||
"Parse LATEX and return a HTML image representing the output."
|
||||
|
|
|
@ -51,9 +51,15 @@ def mediaFilename(path):
|
|||
ext = os.path.splitext(path)[1].lower()
|
||||
return "%s%s" % (new, ext)
|
||||
|
||||
def copyToMedia(deck, path):
|
||||
def copyToMedia(deck, path, latex=None):
|
||||
"""Copy PATH to MEDIADIR, and return new filename.
|
||||
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)
|
||||
new = os.path.join(deck.mediaDir(create=True), newBase)
|
||||
# copy if not existing
|
||||
|
@ -80,9 +86,9 @@ values (:id, :filename, :size, :created, :originalPath,
|
|||
filename=newBase,
|
||||
size=newSize,
|
||||
created=time.time(),
|
||||
originalPath=path,
|
||||
description=os.path.splitext(
|
||||
os.path.basename(path))[0])
|
||||
originalPath=origPath,
|
||||
description=description)
|
||||
deck.flushMod()
|
||||
return newBase
|
||||
|
||||
def _modifyFields(deck, fieldsToUpdate, modifiedFacts, dirty):
|
||||
|
@ -118,8 +124,6 @@ def rebuildMediaDir(deck, deleteRefs=False, dirty=True):
|
|||
oldPath = os.path.join(deck.mediaDir(), oldBase)
|
||||
if oldBase.startswith("."):
|
||||
continue
|
||||
if oldBase.startswith("latex-"):
|
||||
continue
|
||||
if os.path.isdir(oldPath):
|
||||
continue
|
||||
newBase = copyToMedia(deck, oldPath)
|
||||
|
@ -164,12 +168,14 @@ def rebuildMediaDir(deck, deleteRefs=False, dirty=True):
|
|||
deck.deleteTags(unmodifiedFacts.keys(), _("Media Missing"))
|
||||
# build cache of db records
|
||||
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
|
||||
for f in os.listdir(unicode(deck.mediaDir())):
|
||||
if f.startswith("."):
|
||||
continue
|
||||
if f.startswith("latex-"):
|
||||
continue
|
||||
path = os.path.join(deck.mediaDir(), f)
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
|
|
Loading…
Reference in a new issue