Created
February 20, 2010 21:32
-
-
Save pyropeter/309925 to your computer and use it in GitHub Desktop.
Organize raw photos in gallery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
thumbpath="thumbs/" | |
size="300" # ufraw needs width and heigth to equal | |
fileext="jpg" | |
convertopts="-strip" | |
ufrawopts="--create-id=no --out-type=jpeg --compression=95 --size=$size" | |
ufrawopts="$ufrawopts --rotate=camera --wb=camera --grayscale=none --noexif" | |
rm -f thumbdata.csv | |
for rawfile in $(find . -type f -name "*.NEF" -prune | sort); do | |
thumbfile="$thumbpath$rawfile.$fileext" | |
if [ ! -e "$thumbfile" ]; then | |
echo "converting $rawfile..." | |
nice -n10 ufraw-batch --output="$thumbfile" $ufrawopts "$rawfile" | |
if [ "$?" != "0" ]; then | |
echo "ERROR, BYE BYE" | |
exit 1 | |
fi | |
fi | |
exiv2 $rawfile | awk '/^Image timestamp/ {foo=substr($0, match($0, " : ")+3); print foo ",'$thumbfile'"}' >> thumbdata.csv | |
done | |
echo "Generating gallery..." | |
nice -n10 python imagegallery.py -x $size -y $size yes | |
echo "done." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import sys | |
import re | |
import time | |
from optparse import OptionParser | |
parser = OptionParser(usage="usage: %prog [options] yes") | |
parser.add_option("-i", "--imagelist", dest="imagelist", | |
help="An csv-file containing [creation-datetime,path-to-thumb]", metavar="FILE", | |
default="thumbdata.csv") | |
parser.add_option("-o", "--output", dest="output", | |
help="gallery output prefix. the index will be $prefix.html, the pages $prefix????.html", | |
metavar="PREFIX", default="gallery") | |
parser.add_option("-x", "--width", dest="width", | |
help="Thumb's width", metavar="CSS-WIDTH", | |
default="100px") | |
parser.add_option("-y", "--height", dest="height", | |
help="Thumb's height", metavar="CSS-HEIGHT", | |
default="100px") | |
parser.add_option("-l", "--limit", dest="limit", type="int", | |
help="Images-per-page limit", metavar="NUM", | |
default=20) | |
(options, args) = parser.parse_args() | |
if not "yes" in args: | |
print "you have to confirm the order with the positional argument 'yes'" | |
sys.exit(1) | |
# ---------------------------- | |
def timestampToText(ts): | |
return time.strftime("%a %d.%m.%Y %H:%M", time.localtime(ts)) | |
# read imagelist and interpret and sort and split | |
filelist = [] | |
for line in open(options.imagelist): | |
line = line.split(",") | |
filelist.append((time.mktime(time.strptime( | |
line[0].strip(), "%Y:%m:%d %H:%M:%S")), line[1].strip())) | |
filelist.sort(key=lambda x: x[0]) | |
# ------------------------------------------------------- | |
#while len(filelist): | |
# pages.append([]) | |
# for x in range(options.limit): | |
# pages[-1].append(filelist.pop(0)) | |
import random | |
import copy | |
def mutate(cut): | |
cut = copy.copy(cut) | |
for i in range(4): | |
if random.choice([True,False]) or len(cut) < 1: | |
cut.append(random.randint(0,len(filelist)-1)) | |
else: | |
cut.pop(random.randint(0,len(cut)-1)) | |
return cut | |
def evaluate(cut): | |
low_factor = 0 | |
target = options.limit | |
target_factor = 1 | |
duration_factor = (60*60*20) | |
cut.sort() | |
res = [] | |
last = 0 | |
for cutpoint in cut + [len(filelist)-1]: | |
res.append( | |
#low_factor/max(1,cutpoint-last) + | |
target_factor*(max(0,(cutpoint-last)-target)) + | |
duration_factor/float(max(1,filelist[cutpoint][0] - filelist[cutpoint-1][0]))) | |
last = cutpoint | |
return sum(res)/len(res) | |
def simulate(): | |
cut = [] | |
temp = 100.0 | |
score = evaluate(cut) | |
for x in range(500): | |
print "loop %3s, temp %8.2f, score %7.2f"%(x, temp, score) | |
children = [] | |
scores = [] | |
better = 5 | |
for y in range(2000): | |
child = mutate(cut) | |
childscore = evaluate(child) | |
if childscore < score: | |
better -= 1 | |
children.append(child) | |
scores.append(childscore) | |
if better < 1: | |
break | |
if temp < 1: | |
break | |
temp /= 1.1 # should be >1 :-P | |
# with 1.2 and 30 tries, avg: 28.0 28.7 27.6 | |
# foo: 40% 50% 48% | |
# with 1.1 and 30 tries, avg: 20.1 19.6 19.4 | |
# foo: 48% 45% 50% | |
# with 1.05 and 30 tires, avg: 14.1 | |
# foo: 40% | |
best = len(scores) and min(scores) or False | |
if best and score > best: | |
temp += (score - best) | |
cut = children[scores.index(best)] | |
score = best | |
return cut | |
def swissArmyKnifeOfStatistics(values): | |
mean = sum(values)/float(len(values)) | |
minimum = min(values) | |
maximum = max(values) | |
ssdev = (sum((x-mean)**2 for x in values)/float(max(len(values)-1,1)))**( | |
1/2.0) | |
return mean,minimum,maximum,ssdev | |
cuts = [simulate() for x in range(5)] | |
scores = [evaluate(x) for x in cuts] | |
print "Simulated. avg %7.3f, min %7.3f, max %7.3f, ssdev %7.3f"%( | |
swissArmyKnifeOfStatistics(scores)) | |
"""( | |
sum(scores)/len(scores), | |
min(scores), | |
max(scores), | |
(max(scores)-min(scores))/(sum(scores)/len(scores))*100)""" | |
cut = cuts[scores.index(min(scores))] | |
pages = [[]] | |
for index,file in enumerate(filelist): | |
if index in cut: | |
pages.append([]) | |
pages[-1].append(file) | |
#raise Exception | |
# ------------------------------------------------------- | |
pagefile = open("%s.html"%(options.output), "w") | |
print >> pagefile, """<html><head><title>Image Gallery Index</title> | |
<style> | |
body {font-family:monospace; } | |
img { | |
vertical-align:middle; | |
max-width:""" + options.width + """; | |
max-height:""" + options.height + """; } | |
div {margin-top:60px; } | |
</style> | |
</head><body>""" | |
print >> pagefile, "<p>Generated by PyroPeter's Gallery-Creation-Script</p>" | |
print >> pagefile, "<p>Generation time: %s</p>"%time.strftime("%a, %d %b %Y %H:%M:%S",time.localtime()) | |
for pagenum,filelist in enumerate(pages): | |
print >> pagefile, " <div>" | |
print >> pagefile, " <a href='gallery%s.html'>%s --- %s"%( | |
pagenum+1, | |
timestampToText(filelist[0][0]), | |
timestampToText(filelist[-1][0])) | |
print >> pagefile, " <br />[%s] %s Files"%( | |
pagenum+1, len(filelist)) | |
print >> pagefile, " <br /><img src='%s' />"%( | |
filelist[0][1]) | |
if len(filelist) > 1: | |
print >> pagefile, " <img src='%s' />"%( | |
filelist[-1][1]) | |
print >> pagefile, " </a>" | |
print >> pagefile, " </div>" | |
print >> pagefile, "</body></html>" | |
# ---------------------------------------- | |
for pagenum,filelist in enumerate(pages): | |
pagenum += 1 | |
pagefile = open("%s%s.html"%(options.output,pagenum), "w") | |
imgs = "" | |
for foo,image in filelist: | |
imgs += "<div><a href='" + image + "' ><img src='" + image + "' /></a></div>\n" | |
print >> pagefile, """<html><head> | |
<title>Image Gallery [""" + str(pagenum) + """]</title> | |
<style> | |
body {font-family:monospace; } | |
img { | |
vertical-align:middle; | |
border:2px solid black; | |
max-width:""" + options.width + """; | |
max-height:""" + options.height + """; } | |
div { | |
height:""" + options.height + """; | |
width:""" + options.width + """; | |
margin:5px 5px 5px 5px; | |
float:left; | |
text-align:center; } | |
</style> | |
</head><body>""" | |
print >> pagefile, "<p>Generated by PyroPeter's Gallery-Creation-Script</p>" | |
print >> pagefile, "<p>Generation time: %s</p>"%time.strftime("%a, %d %b %Y %H:%M:%S",time.localtime()) | |
print >> pagefile, "<p>Image count: %s</p>"%len(filelist) | |
print >> pagefile, "<p>Page: %s/%s</p>"%(pagenum,len(pages)) | |
print >> pagefile, "<p>From: %s</p>"%(timestampToText(filelist[0][0])) | |
print >> pagefile, "<p>To: %s</p>"%(timestampToText(filelist[-1][0])) | |
print >> pagefile, imgs | |
print >> pagefile, "</body></html>" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment