#! /usr/bin/python # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab # For use with Topaz Scripts Version 2.6 class Unbuffered: def __init__(self, stream): self.stream = stream def write(self, data): self.stream.write(data) self.stream.flush() def __getattr__(self, attr): return getattr(self.stream, attr) import sys sys.stdout=Unbuffered(sys.stdout) import os, getopt # local routines import convert2xml import decode_meta class GParser(object): def __init__(self, flatxml): self.flatdoc = flatxml.split('\n') self.dpi = 1440 self.gh = self.getData('info.glyph.h') self.gw = self.getData('info.glyph.w') self.guse = self.getData('info.glyph.use') if self.guse : self.count = len(self.guse) else : self.count = 0 self.gvtx = self.getData('info.glyph.vtx') self.glen = self.getData('info.glyph.len') self.gdpi = self.getData('info.glyph.dpi') self.vx = self.getData('info.vtx.x') self.vy = self.getData('info.vtx.y') self.vlen = self.getData('info.len.n') if self.vlen : self.glen.append(len(self.vlen)) elif self.glen: self.glen.append(0) if self.vx : self.gvtx.append(len(self.vx)) elif self.gvtx : self.gvtx.append(0) def getData(self, path): result = None cnt = len(self.flatdoc) for j in xrange(cnt): item = self.flatdoc[j] if item.find('=') >= 0: (name, argt) = item.split('=') argres = argt.split('|') else: name = item argres = [] if (name == path): result = argres break if (len(argres) > 0) : for j in xrange(0,len(argres)): argres[j] = int(argres[j]) return result def getGlyphDim(self, gly): maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly] maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly] return maxh, maxw def getPath(self, gly): path = '' if (gly < 0) or (gly >= self.count): return path tx = self.vx[self.gvtx[gly]:self.gvtx[gly+1]] ty = self.vy[self.gvtx[gly]:self.gvtx[gly+1]] p = 0 for k in xrange(self.glen[gly], self.glen[gly+1]): if (p == 0): zx = tx[0:self.vlen[k]+1] zy = ty[0:self.vlen[k]+1] else: zx = tx[self.vlen[k-1]+1:self.vlen[k]+1] zy = ty[self.vlen[k-1]+1:self.vlen[k]+1] p += 1 j = 0 while ( j < len(zx) ): if (j == 0): # Start Position. path += 'M %d %d ' % (zx[j] * self.dpi / self.gdpi[gly], zy[j] * self.dpi / self.gdpi[gly]) elif (j <= len(zx)-3): # Cubic Bezier Curve path += 'C %d %d %d %d %d %d ' % (zx[j] * self.dpi / self.gdpi[gly], zy[j] * self.dpi / self.gdpi[gly], zx[j+1] * self.dpi / self.gdpi[gly], zy[j+1] * self.dpi / self.gdpi[gly], zx[j+2] * self.dpi / self.gdpi[gly], zy[j+2] * self.dpi / self.gdpi[gly]) j += 2 elif (j == len(zx)-2): # Cubic Bezier Curve to Start Position path += 'C %d %d %d %d %d %d ' % (zx[j] * self.dpi / self.gdpi[gly], zy[j] * self.dpi / self.gdpi[gly], zx[j+1] * self.dpi / self.gdpi[gly], zy[j+1] * self.dpi / self.gdpi[gly], zx[0] * self.dpi / self.gdpi[gly], zy[0] * self.dpi / self.gdpi[gly]) j += 1 elif (j == len(zx)-1): # Quadratic Bezier Curve to Start Position path += 'Q %d %d %d %d ' % (zx[j] * self.dpi / self.gdpi[gly], zy[j] * self.dpi / self.gdpi[gly], zx[0] * self.dpi / self.gdpi[gly], zy[0] * self.dpi / self.gdpi[gly]) j += 1 path += 'z' return path class PParser(object): def __init__(self, flatxml): self.flatdoc = flatxml.split('\n') self.temp = [] foo = self.getData('page.h') or self.getData('book.h') self.ph = foo[0] foo = self.getData('page.w') or self.getData('book.w') self.pw = foo[0] self.gx = self.getData('info.glyph.x') self.gy = self.getData('info.glyph.y') self.gid = self.getData('info.glyph.glyphID') def getData(self, path): result = None cnt = len(self.flatdoc) for j in xrange(cnt): item = self.flatdoc[j] if item.find('=') >= 0: (name, argt) = item.split('=') argres = argt.split('|') else: name = item argres = [] if (name.endswith(path)): result = argres break if (len(argres) > 0) : for j in xrange(0,len(argres)): argres[j] = int(argres[j]) return result def getDataTemp(self, path): result = None cnt = len(self.temp) for j in xrange(cnt): item = self.temp[j] if item.find('=') >= 0: (name, argt) = item.split('=') argres = argt.split('|') else: name = item argres = [] if (name.endswith(path)): result = argres self.temp.pop(j) break if (len(argres) > 0) : for j in xrange(0,len(argres)): argres[j] = int(argres[j]) return result def getImages(self): result = [] self.temp = self.flatdoc while (self.getDataTemp('img') != None): h = self.getDataTemp('img.h')[0] w = self.getDataTemp('img.w')[0] x = self.getDataTemp('img.x')[0] y = self.getDataTemp('img.y')[0] src = self.getDataTemp('img.src')[0] result.append('\n' % (src, x, y, w, h)) return result def getGlyphs(self,glyfname): result = [] if (self.gid != None) and (len(self.gid) > 0): glyphs = [] for j in set(self.gid): glyphs.append(j) glyphs.sort() gfile = open(glyfname, 'r') j = 0 while True : inp = gfile.readline() if (inp == ''): break id='id="gl%d"' % glyphs[j] if (inp.find(id) > 0): result.append(inp) j += 1 if (j == len(glyphs)): break gfile.close() return result def usage(): print 'Usage: ' print ' ' print ' gensvg.py [options] unencryptedBookDir' print ' ' print ' -x : output browseable XHTML+SVG pages (default)' print ' -r : output raw SVG images' def main(argv): bookDir = '' if len(argv) == 0: argv = sys.argv try: opts, args = getopt.getopt(argv[1:], "xrh") except getopt.GetoptError, err: print str(err) usage() sys.exit(1) if len(opts) == 0 and len(args) == 0 : usage() sys.exit(1) raw = 0 for o, a in opts: if o =="-h": usage() sys.exit(0) if o =="-x": raw = 0 if o =="-r": raw = 1 bookDir = args[0] if not os.path.exists(bookDir) : print "Can not find directory with unencrypted book" sys.exit(1) dictFile = os.path.join(bookDir,'dict0000.dat') if not os.path.exists(dictFile) : print "Can not find dict0000.dat file" sys.exit(1) pageDir = os.path.join(bookDir,'page') if not os.path.exists(pageDir) : print "Can not find page directory in unencrypted book" sys.exit(1) imgDir = os.path.join(bookDir,'img') if not os.path.exists(imgDir) : print "Can not find image directory in unencrypted book" sys.exit(1) glyphsDir = os.path.join(bookDir,'glyphs') if not os.path.exists(glyphsDir) : print "Can not find glyphs directory in unencrypted book" sys.exit(1) metaFile = os.path.join(bookDir,'metadata0000.dat') if not os.path.exists(metaFile) : print "Can not find metadata0000.dat in unencrypted book" sys.exit(1) svgDir = os.path.join(bookDir,'svg') if not os.path.exists(svgDir) : os.makedirs(svgDir) print 'Processing Meta Data ... ' print ' ', 'metadata0000.dat' fname = os.path.join(bookDir,'metadata0000.dat') metadata = decode_meta.getMetaArray(fname) print 'Processing Glyphs ... ' filenames = os.listdir(glyphsDir) filenames = sorted(filenames) glyfname = os.path.join(svgDir,'glyphs.svg') glyfile = open(glyfname, 'w') glyfile.write('\n') glyfile.write('\n') glyfile.write('\n') glyfile.write('Glyphs for %s\n' % metadata['Title']) glyfile.write('\n') counter = 0 for filename in filenames: print ' ', filename fname = os.path.join(glyphsDir,filename) pargv=[] pargv.append('convert2xml.py') pargv.append('--flat-xml') pargv.append(dictFile) pargv.append(fname) flat_xml = convert2xml.main(pargv) gp = GParser(flat_xml) for i in xrange(0, gp.count): path = gp.getPath(i) maxh, maxw = gp.getGlyphDim(i) # glyfile.write('\n' % (counter * 256 + i, path)) glyfile.write('\n' % (counter * 256 + i, path, maxw, maxh )) counter += 1 glyfile.write('\n') glyfile.write('\n') glyfile.close() print 'Processing Pages ... ' # Books are at 1440 DPI. This is rendering at twice that size for # readability when rendering to the screen. scaledpi = 1440 filenames = os.listdir(pageDir) filenames = sorted(filenames) counter = 0 for filename in filenames: print ' ', filename fname = os.path.join(pageDir,filename) pargv=[] pargv.append('convert2xml.py') pargv.append('--flat-xml') pargv.append(dictFile) pargv.append(fname) flat_xml = convert2xml.main(pargv) pp = PParser(flat_xml) if (raw) : pfile = open(os.path.join(svgDir,filename.replace('.dat','.svg')), 'w') else : pfile = open(os.path.join(svgDir,'page%04d.xhtml' % counter), 'w') pfile.write('\n') if (raw): pfile.write('\n') pfile.write('\n' % (pp.pw / scaledpi, pp.ph / scaledpi, pp.pw -1, pp.ph -1)) pfile.write('Page %d - %s by %s\n' % (counter, metadata['Title'],metadata['Authors'])) else: pfile.write('\n'); pfile.write('\n'); pfile.write('Page %d - %s by %s\n' % (counter, metadata['Title'],metadata['Authors'])) pfile.write('\n') pfile.write('\n') pfile.write('\n') pfile.write('\n') if (counter == 0) : pfile.write('\n') else: pfile.write('\n') pfile.write('' % (pp.pw, pp.ph)) if (pp.gid != None): pfile.write('\n') gdefs = pp.getGlyphs(glyfname) for j in xrange(0,len(gdefs)): pfile.write(gdefs[j]) pfile.write('\n') img = pp.getImages() if (img != None): for j in xrange(0,len(img)): pfile.write(img[j]) if (pp.gid != None): for j in xrange(0,len(pp.gid)): pfile.write('\n' % (pp.gid[j], pp.gx[j], pp.gy[j])) if (img == None or len(img) == 0) and (pp.gid == None or len(pp.gid) == 0): pfile.write('This page intentionally left blank.\nUntil this notice unintentionally gave it content. (gensvg.py)\n'); if (raw) : pfile.write('') else : pfile.write('\n') if (counter == len(filenames) - 1) : pfile.write('\n') else : pfile.write('\n') pfile.write('\n') pfile.write('zoom in - zoom out\n') pfile.write('\n') pfile.write('\n') pfile.close() counter += 1 print 'Processing Complete' return 0 if __name__ == '__main__': sys.exit(main(''))