Skip to content

Instantly share code, notes, and snippets.

@ihaque
Created February 28, 2012 17:57
Show Gist options
  • Save ihaque/1933998 to your computer and use it in GitHub Desktop.
Save ihaque/1933998 to your computer and use it in GitHub Desktop.
Thesis compilation tools
all: master.pdf
clean:
rm -f *.pdf *.log *.aux *.blg *.bbl *.lof *.lot *.out *.toc
rm -f *_lores.tex
rm -f images/*/downsampled/*
master.pdf: master.tex PAPER_lores.tex SIML.tex GPUCG_lores.tex SCISSORS_lores.tex \
kernelnoise_lores.tex kernelnoise_chapter.tex nips_abstract.tex nips_appendices.tex\
bibliography.bib introduction.tex master-macros.sty conclusion.tex \
bounds.tex realtime_lores.tex acknowledgement.tex abstract.tex
pdflatex master && bibtex master && pdflatex master && pdflatex master
PAPER_lores.tex: resample.py PAPER.tex
python resample.py PAPER.tex
SCISSORS_lores.tex: resample.py SCISSORS.tex
python resample.py SCISSORS.tex
GPUCG_lores.tex: resample.py GPUCG.tex
python resample.py GPUCG.tex
kernelnoise_lores.tex: resample.py kernelnoise.tex
python resample.py kernelnoise.tex
realtime_lores.tex: resample.py realtime.tex
python resample.py realtime.tex
import sys,os,re,os.path
from subprocess import Popen,PIPE
from time import sleep
class Environment:
def __init__(self):
# units = inches; quantities taken from suthesis-2e.sty
env = {'textwidth': 6, 'textheight': 8.1}
self.stack = [env]
def enter(self,width=None,height=None):
if width is None:
width = self.width()
if height is None:
height = self.height()
env = {'textwidth': width, 'textheight': height}
self.stack.insert(0,env)
#print "Entering new environment with width =",self.width(),"height =",self.height()
return
def leave(self):
del self.stack[0]
#print "Leaving environment, now width =",self.width(),"height =",self.height()
return
def height(self):
return self.stack[0]["textheight"]
def width(self):
return self.stack[0]["textwidth"]
class ProcessQueue:
def __init__(self,maxProcs = 16):
self.q = []
self.maxprocs = maxProcs
def append(self,p):
if len(self.q) == self.maxprocs:
self.waitfirst()
self.q.append(p)
def waitfirst(self):
if len(self.q) == 0:
return
while self.q[0].poll() is None:
sleep(0.2)
del self.q[0]
return
def wait(self):
while len(self.q) > 0:
self.waitfirst()
return
def resize(fnfrom,fnto,outw,outh,inpw,inph,dpi=150):
#print "\tResizing",fnfrom,"to",fnto,"to width = %.2f in and height = %.2f in"%(outw,outh)
print "\tResizing",fnfrom,"to width = %.2f in and height = %.2f in"%(outw,outh)
out_pw = int(round(dpi*outw))
out_ph = int(round(dpi*outh))
if out_pw > inpw or out_ph > inph:
print "\tRefusing to scale up image",fnfrom
return False
size_ratio = float(inpw*inph)/(out_pw*out_ph)
print "\t(%d,%d) -> (%d,%d) pixels (%.2fx reduction)"%(inpw,inph,out_pw,out_ph,size_ratio)
args = ['convert',fnfrom,"-resize","%dx%d!"%(out_pw,out_ph),fnto]
#print "\t",args
return True,Popen(args)
def getDims(filename):
# Uses ImageMagick 'identify' to get dimensions
p = Popen(["identify",filename],stdout=PIPE)
(out,err) = p.communicate()
(w,h) = map(int,out.split()[2].split("x"))
return w,h
def processJPG(env,opts,filename):
optarr = opts.split(",")
#print "JPEG file:",filename,"with options",optarr
width = None
height = None
for o in optarr:
if o.startswith("width="):
width = parseSize(env,o.split("=")[1])
elif o.startswith("height="):
height = parseSize(env,o.split("=")[1])
else:
raise ValueError,"Don't know how to handle option %s in JPEG processor"%o
(fw,fh) = getDims(filename)
#print "\tFile",filename,"is",fw,"x",fh,"pixels"
aspect = float(fw)/float(fh)
if height is None and not width is None:
height = width/aspect
elif width is None and not height is None:
width = aspect*height
elif width is None and height is None:
raise ValueError,"No size information specified for file",filename
(dir,fn) = os.path.split(filename)
newdir = os.path.join(dir,"downsampled")
newfn = os.path.join(newdir,fn)
retcode,p = resize(filename,newfn,width,height,fw,fh)
if retcode:
return newfn,p
else:
return filename,None
def processPDF(env,opts,filename):
#print "Skipping PDF file",filename
return filename,None
def parseSize(env,w):
#print "Parsing sizespec",w
w = w.replace("linewidth","textwidth")
w = w.replace("columnwidth","textwidth")
w = w.replace(r"\textwidth","*%.2f"%env.width())
w = w.replace(r"\textheight","*%.2f"%env.width())
w = w.replace("in","*1")
w = w.replace("cm","*(1.0/2.54)")
if w[0] == "*":
w = "1"+w
#print "\tevaluating",w
return eval(w)
def parseFile(texfile):
handlers = {'.pdf':processPDF,'.jpg':processJPG}
re_gfx = re.compile(r"\includegraphics\[([^\]]*)\]\{([^\}]*)\}")
re_mp_start = re.compile(r"begin{minipage}\[[^\]]*\]\{([^\}]*)\}")
re_mp_end = re.compile(r"end\{minipage\}")
env = Environment()
newfile = []
changedgfx = False
pq = ProcessQueue()
f = open(texfile,"rt")
for line in f:
line = line.rstrip("\n")
# This parser assumes you're not interspersing commands on the same line
mp_start = re_mp_start.search(line)
mp_end = re_mp_end.search(line)
gfx = re_gfx.search(line)
if mp_start:
env.enter(width=parseSize(env,mp_start.group(1)))
newfile.append(line)
elif mp_end:
env.leave()
newfile.append(line)
elif gfx:
filename = gfx.group(2)
opts = gfx.group(1)
filetype = os.path.splitext(filename)[1]
if filetype not in handlers:
raise ValueError,"Found file %s of type %s with no handler"%(filename,filetype)
newfn,p = handlers[filetype](env,opts,filename)
if newfn != filename:
newfile.append("\\includegraphics[%s]{%s}"%(opts,newfn))
changedgfx = True
pq.append(p)
else:
newfile.append(line)
else:
newfile.append(line)
f.close()
newfile.append("") #newline at end of file
if changedgfx:
newtex = os.path.splitext(texfile)[0]+"_lores.tex"
print "Writing modified texfile to",newtex
f = open(newtex,"wt")
f.write("\n".join(newfile))
f.close()
pq.wait()
return
def main(files):
for f in files:
if not f.endswith(".tex"):
raise ValueError,"Error, given non-LaTeX file %s"%f
parseFile(f)
return
if __name__ == "__main__":
main(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment