Adding rest of the files
This commit is contained in:
448
Qalbum.py
Executable file
448
Qalbum.py
Executable file
@@ -0,0 +1,448 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2011 Ville Rantanen
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys,os
|
||||
import re
|
||||
import urllib
|
||||
import shutil
|
||||
import csv
|
||||
import subprocess
|
||||
from math import ceil
|
||||
from datetime import datetime
|
||||
|
||||
# (c) ville.rantanen@helsinki.fi
|
||||
|
||||
webfilesearch=re.compile('.*index.html$|.*gallerystyle.css$|.*galleryscript.js$|.*descriptions.csv$|\..*',re.I)
|
||||
imagesearch=re.compile('.*\.jpg$|.*\.jpeg$|.*\.gif$|.*\.png$|.*\.svg$|.*\.pdf$',re.I)
|
||||
vectorsearch=re.compile('.*\.svg$|.*\.pdf$',re.I)
|
||||
#gifsearch=re.compile('.*gif$',re.I)
|
||||
excludepaths=re.compile('_med|_tn|\..*')
|
||||
doublequotes=re.compile('"')
|
||||
singlequotes=re.compile("'")
|
||||
stripquotes=re.compile('^"|"$')
|
||||
|
||||
def getheader(path,parent,title=""):
|
||||
if title=="":
|
||||
title=unicode(os.path.basename(path),encoding="utf8").encode('ascii', 'xmlcharrefreplace')
|
||||
return '''<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>'''+title+'''</TITLE>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" type="text/css" href="'''+parent+'''gallerystyle.css">
|
||||
<script language="javascript" src="'''+parent+'''galleryscript.js"></script>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
'''
|
||||
|
||||
def getimagelist(path):
|
||||
''' Returns a list of images matching the regex '''
|
||||
list=os.listdir(path)
|
||||
imgs=[]
|
||||
for f in list:
|
||||
if (imagesearch.match(f)) and (os.path.isfile(os.path.join(path,f))):
|
||||
imgs.append(f)
|
||||
if options.timesort:
|
||||
imgs.sort(key=lambda f: os.path.getmtime(os.path.join(path, f)),reverse=options.reverse)
|
||||
else:
|
||||
imgs.sort(reverse=options.reverse)
|
||||
return imgs
|
||||
|
||||
def getfiletimes(path,list):
|
||||
''' Returns a list of modification times '''
|
||||
times=[]
|
||||
for p in list:
|
||||
times.append(os.path.getmtime(os.path.join(path,p)))
|
||||
return times
|
||||
|
||||
def getnonimagelist(path):
|
||||
''' Returns a list of files not matching the image match regex '''
|
||||
list=os.listdir(path)
|
||||
files=[]
|
||||
if not options.attachments:
|
||||
return files
|
||||
for f in list:
|
||||
if (not webfilesearch.match(f)) and (not imagesearch.match(f)) and (os.path.isfile(os.path.join(path,f))):
|
||||
files.append(f)
|
||||
if options.timesort:
|
||||
files.sort(key=lambda f: os.path.getmtime(os.path.join(path, f)),reverse=options.reverse)
|
||||
else:
|
||||
files.sort(reverse=options.reverse)
|
||||
return files
|
||||
|
||||
def getpathlist(path):
|
||||
''' Returns a list of subfolders not matching the exclusion regex '''
|
||||
list=os.listdir(path)
|
||||
paths=[]
|
||||
for d in list:
|
||||
if (not excludepaths.match(d)) and (os.path.isdir(os.path.join(path,d))):
|
||||
paths.append(d)
|
||||
if options.timesort:
|
||||
paths.sort(key=lambda f: os.path.getmtime(f),reverse=options.reverse)
|
||||
else:
|
||||
paths.sort(reverse=options.reverse)
|
||||
return paths
|
||||
|
||||
def pathscript(path,list):
|
||||
''' Returns the javascript string of pathlist and pathimage arrays '''
|
||||
scrstr='<script language="javascript">'
|
||||
for p in list:
|
||||
imglist=getimagelist(os.path.join(path,p))
|
||||
pathlist=getpathlist(os.path.join(path,p))
|
||||
scrstr+='pathlist.push(["'+unicode(p,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'",'+str(len(imglist)+len(pathlist))+']);'
|
||||
if len(imglist)>0:
|
||||
scrstr+='pathimage.push("'+unicode(p,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'/_tn/tn_'+unicode(imglist[0],encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'.jpg");'
|
||||
else:
|
||||
scrstr+='pathimage.push("");'
|
||||
scrstr+='</script>'
|
||||
return scrstr
|
||||
|
||||
def pathlinks(path,list):
|
||||
''' Returns the HTML string of subfolders '''
|
||||
pathstr='<div id="pathcontainer">'
|
||||
pathstr+='<h1>Subfolders</h1>'
|
||||
for p in list:
|
||||
nice=nicestring(p)
|
||||
imglist=getimagelist(os.path.join(path,p))
|
||||
nsum=str(len(imglist))
|
||||
imgstr=""
|
||||
if len(imglist)>0:
|
||||
imgstr='<span class="pathbox" style="background-image:url(\''+urllib.quote(p)+'/_tn/tn_'+urllib.quote(imglist[0])+'.jpg\');">'
|
||||
else:
|
||||
imgstr='<span class="pathbox">'
|
||||
pathstr+='<a title="'+unicode(p,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'" href="'+urllib.quote(p)+'/index.html">'+imgstr+'<span class="pathlink"><span class="pathlinktext">'+unicode(nice,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+' ('+nsum+')</span></span></span></a>';
|
||||
pathstr+='</script>'
|
||||
pathstr+='</div>'
|
||||
return pathstr
|
||||
|
||||
def imagescript(path,list):
|
||||
''' Returns the javascript string of imagelist and imagedesc '''
|
||||
strout='<script language="javascript">'
|
||||
descriptions=getdescriptions(path,list)
|
||||
times=getfiletimes(path,list)
|
||||
n=0
|
||||
for i in list:
|
||||
desc=singlequotes.sub("\\'",unicode(descriptions[n],encoding="utf8").encode('ascii', 'xmlcharrefreplace'))
|
||||
strout+='imagelist.push("'+unicode(i,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'");'
|
||||
strout+='imagedesc.push(\''+desc+'\');\n'
|
||||
strout+='imagetime.push('+str(times[n])+');\n'
|
||||
n+=1
|
||||
strout+='</script>'
|
||||
return strout
|
||||
|
||||
def imagelinks(path,list):
|
||||
''' Returns the HTML string of images '''
|
||||
strout='<div id="thumbcontainer">'
|
||||
strout+='<h1>Images</h1>'
|
||||
descriptions=getdescriptions(path,list)
|
||||
n=0
|
||||
for i in list:
|
||||
nice=nicestring(i)
|
||||
desc=doublequotes.sub('',unicode(descriptions[n],encoding="utf8").encode('ascii', 'xmlcharrefreplace'))
|
||||
strout+='<span class="imagebox thumbbox" id="n'+str(n)+'"><a href="'+urllib.quote(i)+'"><img class="thumbimage" "title="'+desc+'" src="_tn/tn_'+urllib.quote(i)+'.jpg"><br/>'+unicode(nice,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'</a></span>'
|
||||
n+=1
|
||||
strout+='</div>'
|
||||
return strout
|
||||
|
||||
def filescript(path,list):
|
||||
''' Returns the javascript string of filelist '''
|
||||
strout='<script language="javascript">'
|
||||
n=0
|
||||
for i in list:
|
||||
strout+='filelist.push("'+unicode(i,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'");'
|
||||
n+=1
|
||||
strout+='</script>'
|
||||
return strout
|
||||
|
||||
def filelinks(path,list):
|
||||
''' Returns the HTML string of non image files '''
|
||||
strout='<div id="attachmentcontainer">'
|
||||
if len(list)>0:
|
||||
strout+='<h2>Attachments</h1>'
|
||||
n=0
|
||||
for i in list:
|
||||
nice=nicestring(i)
|
||||
size=sizestring(os.path.getsize(os.path.join(path,i)))
|
||||
strout+='<span class="attachmentbox" id="a'+str(n)+'"><a href="'+urllib.quote(i)+'">'+unicode(nice,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+' ['+size+']</a></span>'
|
||||
n+=1
|
||||
strout+='</div>'
|
||||
return strout
|
||||
|
||||
def createthumbs(path,list):
|
||||
''' Runs imagemagick Convert to create medium sized and thumbnail images '''
|
||||
if len(list)==0:
|
||||
return
|
||||
if not os.path.exists(os.path.join(path,'_tn')):
|
||||
os.mkdir(os.path.join(path,'_tn'))
|
||||
if not os.path.exists(os.path.join(path,'_med')):
|
||||
os.mkdir(os.path.join(path,'_med'))
|
||||
n=1
|
||||
nsum=len(list)
|
||||
for i in list:
|
||||
if (vectorsearch.match(i)):
|
||||
if not os.path.exists(os.path.join(path,'_med','med_'+i+'.jpg')):
|
||||
print('.. '+i+' '+str(n)+'/'+str(nsum))
|
||||
convargs=['convert','-density','300x300',os.path.join(path,i)+'[0]','-background','white','-flatten','-resize','1000x1000>','-quality','97',os.path.join(path,'_med','med_'+i+'.jpg')]
|
||||
convp=subprocess.call(convargs)
|
||||
if not os.path.exists(os.path.join(path,'_tn','tn_'+i+'.jpg')):
|
||||
convargs=['convert','-density','300x300',os.path.join(path,'_med','med_'+i+'.jpg'),'-background','white','-flatten','-thumbnail','90x90^','-gravity','Center','-crop','90x90+0+0','+repage','-quality','75',os.path.join(path,'_tn','tn_'+i+'.jpg')]
|
||||
convp=subprocess.call(convargs)
|
||||
else:
|
||||
if not os.path.exists(os.path.join(path,'_med','med_'+i+'.jpg')):
|
||||
print('.. '+i+' '+str(n)+'/'+str(nsum))
|
||||
convargs=['convert','-define','jpeg:size=1200x1200',os.path.join(path,i)+'[0]','-background','white','-flatten','-resize','1000x1000>','-quality','85',os.path.join(path,'_med','med_'+i+'.jpg')]
|
||||
convp=subprocess.call(convargs)
|
||||
if not os.path.exists(os.path.join(path,'_tn','tn_'+i+'.jpg')):
|
||||
convargs=['convert','-define','jpeg:size=300x300',os.path.join(path,'_med','med_'+i+'.jpg'),'-background','white','-flatten','-thumbnail','90x90^','-gravity','Center','-crop','90x90+0+0','+repage','-quality','75',os.path.join(path,'_tn','tn_'+i+'.jpg')]
|
||||
convp=subprocess.call(convargs)
|
||||
n+=1
|
||||
return
|
||||
|
||||
def getdescriptions(path,list):
|
||||
''' Read descriptions.csv file and returns a list of descriptions.
|
||||
Missing descriptions are replaced with the file name. '''
|
||||
if not os.path.exists(os.path.join(path,'descriptions.csv')):
|
||||
return list
|
||||
desc=[i for i in list]
|
||||
reader = csv.reader(open(os.path.join(path,'descriptions.csv'),'rb'),
|
||||
delimiter='\t',
|
||||
doublequote=False,
|
||||
escapechar='\\',
|
||||
quoting=csv.QUOTE_NONE)
|
||||
for row in reader:
|
||||
if row[0] in list:
|
||||
i=list.index(stripquotes.sub('',row[0]))
|
||||
desc[i]=stripquotes.sub('',row[1])
|
||||
return desc
|
||||
|
||||
def crumblinks(crumbs):
|
||||
''' Create the HTML string for crumb trails '''
|
||||
strout='<div id="crumbcontainer">'
|
||||
i=1
|
||||
for c in crumbs:
|
||||
cname=os.path.basename(c)
|
||||
if i==1:
|
||||
cname="Home"
|
||||
cdepth=len(crumbs)-i
|
||||
clink="../"*cdepth
|
||||
strout+='<a href="'+clink+'index.html">'+unicode(cname,encoding="utf8").encode('ascii', 'xmlcharrefreplace')+'</a>: '
|
||||
i+=1
|
||||
strout+='</div>'
|
||||
return strout
|
||||
|
||||
def nicestring(s):
|
||||
''' Returns a nice version of a long string '''
|
||||
if len(s)<20:
|
||||
return s
|
||||
s=s.replace("_"," ")
|
||||
s=s.replace("-"," ")
|
||||
if len(s)>30:
|
||||
s=s[0:26]+".."+s[-3:]
|
||||
return s
|
||||
|
||||
def sizestring(size):
|
||||
''' Returns human readable file size string '''
|
||||
for x in ['b','kb','Mb','Gb','Tb']:
|
||||
if size < 1024.0:
|
||||
if (x=='b') | (x=='kb'):
|
||||
return "%d%s" % (size, x)
|
||||
else:
|
||||
return "%3.1f%s" % (size, x)
|
||||
size /= 1024.0
|
||||
|
||||
def traverse(path,crumbs):
|
||||
''' The recursive main function to create the index.html and seek sub folders '''
|
||||
print(path)
|
||||
if len(crumbs)==1:
|
||||
header=getheader(path,'../'*(len(crumbs)-1),inputs[0][1])
|
||||
else:
|
||||
header=getheader(path,'../'*(len(crumbs)-1))
|
||||
print(len(crumbs))
|
||||
pathlist=getpathlist(path)
|
||||
imagelist=getimagelist(path)
|
||||
filelist=getnonimagelist(path)
|
||||
print(str(len(pathlist))+' paths')
|
||||
print(str(len(imagelist))+' images')
|
||||
print(str(len(filelist))+' other files')
|
||||
crumbstring=crumblinks(crumbs)
|
||||
if len(pathlist)>0:
|
||||
pathstring=pathlinks(path,pathlist)
|
||||
pathjs=pathscript(path,pathlist)
|
||||
else:
|
||||
pathstring='<div id="pathcontainer"></div>'
|
||||
pathjs=''
|
||||
filestring=filelinks(path,filelist)
|
||||
filejs=filescript(path,filelist)
|
||||
if len(imagelist)>0:
|
||||
imagestring=imagelinks(path,imagelist)
|
||||
imagejs=imagescript(path,imagelist)
|
||||
else:
|
||||
imagestring='<div id="thumbcontainer"></div>'
|
||||
imagejs=''
|
||||
|
||||
f=open(os.path.join(path,"index.html"),"w")
|
||||
f.write(header)
|
||||
f.write('<div id="preloadcontainer"></div>')
|
||||
f.write(pathjs)
|
||||
f.write(imagejs)
|
||||
f.write(filejs)
|
||||
f.write(crumbstring)
|
||||
f.write(pathstring)
|
||||
f.write('<div id="imagecontainer"></div>')
|
||||
f.write('<div id="desccontainer"></div>')
|
||||
f.write(imagestring)
|
||||
f.write(filestring)
|
||||
f.write('<div id="listcontainer"></div>')
|
||||
f.write(footer)
|
||||
f.close()
|
||||
createthumbs(path,imagelist)
|
||||
for p in pathlist:
|
||||
nextcrumbs=[i for i in crumbs]
|
||||
nextcrumbs.append(os.path.join(path,p))
|
||||
traverse(os.path.join(path,p),nextcrumbs)
|
||||
return
|
||||
|
||||
class AndurilOptions:
|
||||
'''Object featuring same variables as arguments from command line.'''
|
||||
|
||||
def __init__(self, timesort, reverse):
|
||||
'''Initializes the person's data.'''
|
||||
self.timesort=timesort
|
||||
self.reverse=reverse
|
||||
self.attachments=True
|
||||
|
||||
def execute(cf):
|
||||
global footer
|
||||
footer='''
|
||||
<div id="footer">Generated with Anduril ('''+datetime.today().strftime("%y-%m-%d %H:%M")+''')</div>
|
||||
<script language="javascript">setup();</script>
|
||||
</BODY>
|
||||
</HTML>'''
|
||||
global inputs
|
||||
global options
|
||||
inputs=[]
|
||||
inputs.append((cf.get_input('folderRoot'),'',cf.get_input('csvRoot')))
|
||||
for i in range(8):
|
||||
inputs.append((cf.get_input('folder'+str(i+1)),cf.get_parameter('title'+str(i+1)),cf.get_input('csv'+str(i+1))))
|
||||
fileCol=cf.get_parameter('fileCol')
|
||||
annotationCol=cf.get_parameter('annotationCol')
|
||||
options=AndurilOptions(cf.get_parameter('sortTime','boolean'),
|
||||
cf.get_parameter('sortReverse','boolean'))
|
||||
outDir = cf.get_output('gallery')
|
||||
# the folderRoot demands that the outDir is not created earlier.
|
||||
if inputs[0][0]==None:
|
||||
os.mkdir(outDir)
|
||||
else:
|
||||
shutil.copytree(inputs[0][0],os.path.join(outDir,inputs[0][1]))
|
||||
|
||||
for d in inputs:
|
||||
if (d[0]==None):
|
||||
continue
|
||||
if not os.path.exists(d[0]):
|
||||
continue
|
||||
print('Copying gallery '+d[1])
|
||||
cf.write_log('Copying gallery '+d[1])
|
||||
if not os.path.exists(os.path.join(outDir,d[1])):
|
||||
shutil.copytree(d[0],os.path.join(outDir,d[1]))
|
||||
# Find the annotations
|
||||
if (d[2] is not None):
|
||||
reader = csv.DictReader(open(d[2],'rb'),
|
||||
delimiter='\t',
|
||||
doublequote=False,
|
||||
escapechar='\\',
|
||||
quoting=csv.QUOTE_ALL)
|
||||
for row in reader:
|
||||
break
|
||||
if (fileCol not in reader.fieldnames):
|
||||
cf.write_error("Column \""+fileCol+"\" not found.")
|
||||
exit()
|
||||
if (annotationCol not in reader.fieldnames):
|
||||
cf.write_error("Column \""+annotationCol+"\" not found.")
|
||||
exit()
|
||||
reader = csv.DictReader(open(d[2],'rb'),
|
||||
delimiter='\t',
|
||||
doublequote=False,
|
||||
escapechar=None,
|
||||
quotechar='"',
|
||||
quoting=csv.QUOTE_NONE)
|
||||
annotations=[]
|
||||
header=['file','description']
|
||||
for row in reader:
|
||||
annotations.append( (stripquotes.sub('',row.get('"'+fileCol+'"')), stripquotes.sub('',row.get('"'+annotationCol+'"')) ) )
|
||||
writefid=open(os.path.join(outDir,d[1],'descriptions.csv'),'wb')
|
||||
writer = csv.writer(writefid,
|
||||
delimiter='\t',
|
||||
doublequote=False,escapechar='\\',
|
||||
quotechar='"',
|
||||
quoting=csv.QUOTE_NONE)
|
||||
writer.writerow(header)
|
||||
for r in annotations:
|
||||
writer.writerow([r[0],r[1]])
|
||||
writefid.close()
|
||||
# Copy all resources to target folder
|
||||
shutil.copyfile('gallerystyle.css',os.path.join(outDir,'gallerystyle.css'))
|
||||
shutil.copyfile('galleryscript.js',os.path.join(outDir,'galleryscript.js'))
|
||||
inputs[0]=((cf.get_input('folderRoot'),cf.get_parameter('titleRoot'),cf.get_input('csvRoot')))
|
||||
startpath=os.path.abspath(outDir)
|
||||
traverse(startpath,[startpath])
|
||||
return 0
|
||||
|
||||
def execute_plain():
|
||||
''' Execute this if run outside anduril '''
|
||||
from optparse import OptionParser
|
||||
usage='''Usage: %prog [options] folder
|
||||
folder is the root folder of the image album.'''
|
||||
parser=OptionParser(usage=usage)
|
||||
parser.add_option("-r",action="store_true",dest="reverse",default=False,
|
||||
help="Reverse sort orded")
|
||||
parser.add_option("-t",action="store_true",dest="timesort",default=False,
|
||||
help="Sort by file modification time")
|
||||
parser.add_option("-a",action="store_false",dest="attachments",default=True,
|
||||
help="Disable attachments")
|
||||
global options
|
||||
(options,args)=parser.parse_args()
|
||||
if len(args) != 1:
|
||||
#sys.exit(0)
|
||||
startpath=os.path.abspath('.')
|
||||
else:
|
||||
startpath=os.path.abspath(args[0])
|
||||
pathname=os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
fullpath=os.path.abspath(pathname)
|
||||
# Copy all resources to target folder
|
||||
shutil.copyfile(os.path.join(fullpath,'gallerystyle.css'),os.path.join(startpath,'gallerystyle.css'))
|
||||
shutil.copyfile(os.path.join(fullpath,'galleryscript.js'),os.path.join(startpath,'galleryscript.js'))
|
||||
global footer
|
||||
footer='''
|
||||
<div id="footer">Generated with Qalbum ('''+datetime.today().strftime("%y-%m-%d %H:%M")+''')</div>
|
||||
<script language="javascript">setup();</script>
|
||||
</BODY>
|
||||
</HTML>'''
|
||||
global inputs
|
||||
inputs=[]
|
||||
inputs.append((None,'Gallery',None))
|
||||
|
||||
traverse(startpath,[startpath])
|
||||
return
|
||||
|
||||
try:
|
||||
import component_skeleton.main
|
||||
except ImportError:
|
||||
execute_plain()
|
||||
sys.exit(0)
|
||||
|
||||
component_skeleton.main.main(execute)
|
||||
|
||||
Reference in New Issue
Block a user