refactor latex into media support

This commit is contained in:
Damien Elmes 2008-12-23 18:00:12 +09:00
parent 6a21be9d19
commit 3b3fef4ebc
3 changed files with 83 additions and 50 deletions

View file

@ -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)

View file

@ -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."

View file

@ -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)