Module tf.convert.iiif
Expand source code Browse git
from ..core.files import (
readYaml,
readJson,
writeJson,
fileOpen,
initTree,
dirExists,
dirCopy,
dirContents,
stripExt,
)
from ..core.helpers import console
from .helpers import parseIIIF, fillinIIIF
DS_STORE = ".DS_Store"
class IIIF:
def __init__(self, teiVersion, app, pageInfoFile, prod=False, silent=False):
self.teiVersion = teiVersion
self.app = app
self.pageInfoFile = pageInfoFile
self.prod = prod
self.silent = silent
teiVersionRep = f"/{teiVersion}" if teiVersion else teiVersion
F = app.api.F
repoLocation = app.repoLocation
staticDir = f"{repoLocation}/static{teiVersionRep}/{'prod' if prod else 'dev'}"
self.staticDir = staticDir
self.manifestDir = f"{staticDir}/manifests"
self.thumbDir = (
f"{repoLocation}/{app.context.provenanceSpec['graphicsRelative']}"
)
scanDir = f"{repoLocation}/scans"
self.scanDir = scanDir
coversDir = f"{scanDir}/covers"
self.coversDir = coversDir
self.pagesDir = f"{scanDir}/pages"
self.logoInDir = f"{scanDir}/logo"
self.logoDir = f"{staticDir}/logo"
self.coversHtmlIn = f"{repoLocation}/programs/covers.html"
self.coversHtmlOut = f"{staticDir}/covers.html"
settings = readYaml(asFile=f"{repoLocation}/programs/iiif.yaml", plain=True)
self.settings = settings
self.templates = parseIIIF(settings, prod, "templates")
self.getSizes()
self.getRotations()
self.getPageSeq()
pages = self.pages
folders = [F.folder.v(f) for f in F.otype.s("folder")]
self.folders = folders
self.console("Collections:")
for folder in folders:
n = len(pages["pages"][folder])
self.console(f"{folder:>5} with {n:>4} pages")
def console(self, msg, **kwargs):
"""Print something to the output.
This works exactly as `tf.core.helpers.console`
When the silent member of the object is True, the message will be suppressed.
"""
silent = self.silent
if not silent:
console(msg, **kwargs)
def getRotations(self):
prod = self.prod
thumbDir = self.thumbDir
scanDir = self.scanDir
rotateFile = f"{scanDir if prod else thumbDir}/rotation_pages.tsv"
rotateInfo = {}
self.rotateInfo = rotateInfo
with fileOpen(rotateFile) as rh:
next(rh)
for line in rh:
fields = line.rstrip("\n").split("\t")
p = fields[0]
rot = int(fields[1])
rotateInfo[p] = rot
def getSizes(self):
prod = self.prod
thumbDir = self.thumbDir
scanDir = self.scanDir
self.sizeInfo = {}
for kind in ("covers", "pages"):
sizeFile = f"{scanDir if prod else thumbDir}/sizes_{kind}.tsv"
sizeInfo = {}
self.sizeInfo[kind] = sizeInfo
maxW, maxH = 0, 0
n = 0
totW, totH = 0, 0
ws, hs = [], []
with fileOpen(sizeFile) as rh:
next(rh)
for line in rh:
fields = line.rstrip("\n").split("\t")
p = fields[0]
(w, h) = (int(x) for x in fields[1:3])
sizeInfo[p] = (w, h)
ws.append(w)
hs.append(h)
n += 1
totW += w
totH += h
if w > maxW:
maxW = w
if h > maxH:
maxH = h
avW = int(round(totW / n))
avH = int(round(totH / n))
devW = int(round(sum(abs(w - avW) for w in ws) / n))
devH = int(round(sum(abs(h - avH) for h in hs) / n))
self.console(f"Maximum dimensions: W = {maxW:>4} H = {maxH:>4}")
self.console(f"Average dimensions: W = {avW:>4} H = {avH:>4}")
self.console(f"Average deviation: W = {devW:>4} H = {devH:>4}")
def getPageSeq(self):
coversDir = self.coversDir
pageInfoFile = self.pageInfoFile
covers = sorted(
stripExt(f) for f in dirContents(coversDir)[0] if f is not DS_STORE
)
self.covers = covers
self.pages = dict(
pages=readJson(asFile=pageInfoFile, plain=True), covers=dict(covers=covers)
)
def genPages(self, kind, folder=None):
if kind == "covers":
folder = kind
templates = self.templates
sizeInfo = self.sizeInfo[kind]
rotateInfo = None if kind == "covers" else self.rotateInfo
pages = self.pages[kind]
thesePages = pages[folder]
pageItem = templates.coverItem if kind == "covers" else templates.pageItem
items = []
for p in thesePages:
item = {}
w, h = sizeInfo.get(p, (0, 0))
rot = 0 if rotateInfo is None else rotateInfo.get(p, 0)
for k, v in pageItem.items():
v = fillinIIIF(v, folder=folder, page=p, width=w, height=h, rot=rot)
item[k] = v
items.append(item)
pageSequence = (
templates.coverSequence if kind == "covers" else templates.pageSequence
)
manifestDir = self.manifestDir
data = {}
for k, v in pageSequence.items():
v = fillinIIIF(v, folder=folder)
data[k] = v
data["items"] = items
writeJson(data, asFile=f"{manifestDir}/{folder}.json")
def manifests(self):
folders = self.folders
manifestDir = self.manifestDir
logoInDir = self.logoInDir
logoDir = self.logoDir
coversHtmlIn = self.coversHtmlIn
coversHtmlOut = self.coversHtmlOut
prod = self.prod
settings = self.settings
with fileOpen(coversHtmlIn) as fh:
coversHtml = fh.read()
server = settings["switches"]["prod" if prod else "dev"]["server"]
coversHtml = coversHtml.replace("«server»", server)
with fileOpen(coversHtmlOut, "w") as fh:
fh.write(coversHtml)
initTree(manifestDir, fresh=True)
self.genPages("covers")
for folder in folders:
self.genPages("pages", folder=folder)
if dirExists(logoInDir):
dirCopy(logoInDir, logoDir)
else:
console(f"Directory with logos not found: {logoInDir}", error=True)
self.console(f"IIIF manifests generated in {manifestDir}")
Classes
class IIIF (teiVersion, app, pageInfoFile, prod=False, silent=False)
-
Expand source code Browse git
class IIIF: def __init__(self, teiVersion, app, pageInfoFile, prod=False, silent=False): self.teiVersion = teiVersion self.app = app self.pageInfoFile = pageInfoFile self.prod = prod self.silent = silent teiVersionRep = f"/{teiVersion}" if teiVersion else teiVersion F = app.api.F repoLocation = app.repoLocation staticDir = f"{repoLocation}/static{teiVersionRep}/{'prod' if prod else 'dev'}" self.staticDir = staticDir self.manifestDir = f"{staticDir}/manifests" self.thumbDir = ( f"{repoLocation}/{app.context.provenanceSpec['graphicsRelative']}" ) scanDir = f"{repoLocation}/scans" self.scanDir = scanDir coversDir = f"{scanDir}/covers" self.coversDir = coversDir self.pagesDir = f"{scanDir}/pages" self.logoInDir = f"{scanDir}/logo" self.logoDir = f"{staticDir}/logo" self.coversHtmlIn = f"{repoLocation}/programs/covers.html" self.coversHtmlOut = f"{staticDir}/covers.html" settings = readYaml(asFile=f"{repoLocation}/programs/iiif.yaml", plain=True) self.settings = settings self.templates = parseIIIF(settings, prod, "templates") self.getSizes() self.getRotations() self.getPageSeq() pages = self.pages folders = [F.folder.v(f) for f in F.otype.s("folder")] self.folders = folders self.console("Collections:") for folder in folders: n = len(pages["pages"][folder]) self.console(f"{folder:>5} with {n:>4} pages") def console(self, msg, **kwargs): """Print something to the output. This works exactly as `tf.core.helpers.console` When the silent member of the object is True, the message will be suppressed. """ silent = self.silent if not silent: console(msg, **kwargs) def getRotations(self): prod = self.prod thumbDir = self.thumbDir scanDir = self.scanDir rotateFile = f"{scanDir if prod else thumbDir}/rotation_pages.tsv" rotateInfo = {} self.rotateInfo = rotateInfo with fileOpen(rotateFile) as rh: next(rh) for line in rh: fields = line.rstrip("\n").split("\t") p = fields[0] rot = int(fields[1]) rotateInfo[p] = rot def getSizes(self): prod = self.prod thumbDir = self.thumbDir scanDir = self.scanDir self.sizeInfo = {} for kind in ("covers", "pages"): sizeFile = f"{scanDir if prod else thumbDir}/sizes_{kind}.tsv" sizeInfo = {} self.sizeInfo[kind] = sizeInfo maxW, maxH = 0, 0 n = 0 totW, totH = 0, 0 ws, hs = [], [] with fileOpen(sizeFile) as rh: next(rh) for line in rh: fields = line.rstrip("\n").split("\t") p = fields[0] (w, h) = (int(x) for x in fields[1:3]) sizeInfo[p] = (w, h) ws.append(w) hs.append(h) n += 1 totW += w totH += h if w > maxW: maxW = w if h > maxH: maxH = h avW = int(round(totW / n)) avH = int(round(totH / n)) devW = int(round(sum(abs(w - avW) for w in ws) / n)) devH = int(round(sum(abs(h - avH) for h in hs) / n)) self.console(f"Maximum dimensions: W = {maxW:>4} H = {maxH:>4}") self.console(f"Average dimensions: W = {avW:>4} H = {avH:>4}") self.console(f"Average deviation: W = {devW:>4} H = {devH:>4}") def getPageSeq(self): coversDir = self.coversDir pageInfoFile = self.pageInfoFile covers = sorted( stripExt(f) for f in dirContents(coversDir)[0] if f is not DS_STORE ) self.covers = covers self.pages = dict( pages=readJson(asFile=pageInfoFile, plain=True), covers=dict(covers=covers) ) def genPages(self, kind, folder=None): if kind == "covers": folder = kind templates = self.templates sizeInfo = self.sizeInfo[kind] rotateInfo = None if kind == "covers" else self.rotateInfo pages = self.pages[kind] thesePages = pages[folder] pageItem = templates.coverItem if kind == "covers" else templates.pageItem items = [] for p in thesePages: item = {} w, h = sizeInfo.get(p, (0, 0)) rot = 0 if rotateInfo is None else rotateInfo.get(p, 0) for k, v in pageItem.items(): v = fillinIIIF(v, folder=folder, page=p, width=w, height=h, rot=rot) item[k] = v items.append(item) pageSequence = ( templates.coverSequence if kind == "covers" else templates.pageSequence ) manifestDir = self.manifestDir data = {} for k, v in pageSequence.items(): v = fillinIIIF(v, folder=folder) data[k] = v data["items"] = items writeJson(data, asFile=f"{manifestDir}/{folder}.json") def manifests(self): folders = self.folders manifestDir = self.manifestDir logoInDir = self.logoInDir logoDir = self.logoDir coversHtmlIn = self.coversHtmlIn coversHtmlOut = self.coversHtmlOut prod = self.prod settings = self.settings with fileOpen(coversHtmlIn) as fh: coversHtml = fh.read() server = settings["switches"]["prod" if prod else "dev"]["server"] coversHtml = coversHtml.replace("«server»", server) with fileOpen(coversHtmlOut, "w") as fh: fh.write(coversHtml) initTree(manifestDir, fresh=True) self.genPages("covers") for folder in folders: self.genPages("pages", folder=folder) if dirExists(logoInDir): dirCopy(logoInDir, logoDir) else: console(f"Directory with logos not found: {logoInDir}", error=True) self.console(f"IIIF manifests generated in {manifestDir}")
Methods
def console(self, msg, **kwargs)
-
Print something to the output.
This works exactly as
console()
When the silent member of the object is True, the message will be suppressed.
def genPages(self, kind, folder=None)
def getPageSeq(self)
def getRotations(self)
def getSizes(self)
def manifests(self)