emin

Wed, 26 Feb 2020 12:48:21 +0000

author
Andy Buckley <andy@insectnation.org>
date
Wed, 26 Feb 2020 12:48:21 +0000
changeset 28
1088bb11189f
parent 26
79167c58c3a5
permissions
-rwxr-xr-x

Update to the 2020s

andy@28 1 #! /usr/bin/env python3
andy@1 2 # -*- python -*-
andy@1 3
andy@28 4 """%prog [opts] dir [outdir=./gallery]
andy@3 5
andy@14 6 emin - a static web gallery builder
andy@3 7
andy@24 8 emin makes static Web pages for presenting lots of imagey things: photos, PDFs,
andy@24 9 graphs with thumbnails as well as links to the image/doc file proper.
andy@3 10
andy@24 11 It's primarily intended for making Web photo galleries for the sorts of people
andy@24 12 who don't want to install some PHP monstrosity just to put their photos
andy@24 13 online. On the assumption that most people will want to tweak their gallery's
andy@24 14 appearance, the output is fully customisable using the Cheetah templating
andy@24 15 engine.
andy@3 16
andy@24 17 Supported image formats are JPEG, PNG, GIF, TIFF, PDF and EPS, with the latter
andy@24 18 two being converted to PNG for Web display. Image resizing, renaming and
andy@24 19 thumbnailing is supported, as is building a zip file to download the whole
andy@24 20 set. Large image sets can be split over several pages.
andy@24 21
andy@24 22 As for the name, this is a program to make pretty simple galleries, so it's
andy@14 23 named after a pretty crappy artist. And, thankfully, e-m-i-n is not many
andy@24 24 characters to type.
andy@3 25
andy@3 26 TODO:
andy@24 27 * Make Cheetah templating optional, or use Genshi/Jinja/Mako?
andy@26 28 * Clean up image filenames to avoid/minimise duplicate extensions
andy@24 29 * Try to validate the HTML output
andy@14 30 * Add all on one page option
andy@11 31 * Resize option
andy@11 32 * Rename option
andy@13 33 * Crop-to-thumb option
andy@16 34 * Auto-rotate by EXIF orientation
andy@13 35 * Copy Lightbox stuff into place
andy@6 36 * Allow complete rollback if any failure (or on demand?)
andy@24 37
andy@24 38 Author: Andy Buckley, http://www.insectnation.org\
andy@3 39 """
andy@2 40
andy@24 41 __author__ = "Andy Buckley <andy@insectnation.org>"
andy@28 42 __version__ = "0.4.0"
andy@14 43
andy@3 44
andy@5 45 import logging
andy@2 46 from optparse import OptionParser, OptionGroup
andy@24 47 parser = OptionParser(usage=__doc__, version=__version__)
andy@26 48 parser.add_option("-t", "--title", dest="TITLE", default=None,
andy@5 49 help="title of this gallery")
andy@14 50 parser.add_option("--template", dest="TEMPLATE", default=None,
andy@5 51 help="specify the template file to be used for the index pages")
andy@14 52 parser.add_option("--zipfile", dest="ZIPFILE", default=None,
andy@5 53 help="name of zip archive file. Default is based on the title.")
andy@6 54 parser.add_option("--no-zipfile", action="store_false",
andy@14 55 dest="WRITE_ZIPFILE", default=True,
andy@5 56 help="disable writing out of a zipped archive of photos from this gallery")
andy@24 57 parser.add_option("-1", "--one-page", dest="ONE_PAGE", action="store_true", default=False,
andy@24 58 help="put all thumbnails on one page (default: %default)")
andy@24 59 parser.add_option("-c", "--num-cols", "--cols", dest="NUM_COLS", default=5, type=int,
andy@24 60 help="max number of thumbnail columns on one page (default: %default)")
andy@24 61 parser.add_option("-r", "--num-rows", "--rows", dest="NUM_ROWS", default=6, type=int,
andy@24 62 help="max number of thumbnail rows on one page (default: %default). Set < 1 for unlimited (i.e. all on one page)")
andy@28 63 parser.add_option("--thumb-height", dest="THUMB_HEIGHT", default=250, type=int,
andy@24 64 help="thumbnail height, in pixels (default: %default)")
andy@5 65 parser.add_option("--max-imgsize", dest="MAX_IMGSIZE", default=800, type=int,
andy@24 66 help="max large image dimension in pixels (default: %default)")
andy@24 67 parser.add_option("--exclude", dest="EXCLUDE", default=None,
andy@24 68 help="a regex pattern specifying image files to be excludes (default: %default)")
andy@14 69 parser.add_option("--no-js", dest="USE_JS", action="store_false", default=True,
andy@5 70 help="disable use of funky JavaScript display stuff")
andy@14 71 parser.add_option("--force", dest="FORCE", action="store_true", default=False,
andy@5 72 help="force creation of gallery: regen thumbnails etc.")
andy@14 73 parser.add_option("--no-table", dest="USE_TABLE", action="store_false", default=True,
andy@5 74 help="don't use an HTML table for thumbnail presentation: just let the thumbs flow into the browser window")
andy@5 75 verbgroup = OptionGroup(parser, "Verbosity control")
andy@16 76 verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL",
andy@5 77 default=logging.INFO, help="print debug (very verbose) messages")
andy@16 78 verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL",
andy@5 79 default=logging.INFO, help="be very quiet")
andy@5 80 parser.add_option_group(verbgroup)
andy@3 81 opts, args = parser.parse_args()
andy@5 82 logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s")
andy@1 83
andy@1 84
andy@24 85 ## More imports
andy@24 86 import sys, os, glob, re, math, shutil, fnmatch
andy@24 87 try:
andy@24 88 from Cheetah.Template import Template
andy@28 89 except Exception as e:
andy@24 90 logging.error("Couldn't import required Cheetah package")
andy@24 91 exit(1)
andy@24 92 try:
andy@24 93 import PIL.Image as PILI
andy@28 94 except Exception as e:
andy@28 95 logging.error("Couldn't import required Python Imaging Library / Pillow package")
andy@24 96 exit(1)
andy@5 97
andy@5 98
andy@5 99 ## Set processing/output dir
andy@9 100 if len(args) < 1 or len(args) > 2:
andy@24 101 parser.print_usage()
andy@9 102 exit(1)
andy@9 103 if len(args) >= 1:
andy@9 104 opts.SRCDIR = os.path.normpath(args[0])
andy@28 105 opts.OUTDIR = os.path.normpath("./gallery") #args[0])
andy@9 106 if len(args) == 2:
andy@9 107 opts.OUTDIR = os.path.normpath(args[1])
andy@5 108
andy@5 109
andy@24 110 ## Deal with consequences of interacting optional settings
andy@24 111 if opts.ONE_PAGE:
andy@24 112 opts.NUM_ROWS = -1
andy@24 113 # TODO: These should be options...
andy@24 114 opts.RENAME = False
andy@24 115 opts.CONVERT = False
andy@2 116
andy@2 117
andy@3 118 def safeencode(s):
andy@2 119 """Encode a string for use as a filename."""
andy@3 120 newstr = s.replace(" ", "-").replace(",", "").replace("/", "").replace(".", "")
andy@3 121 return newstr
andy@1 122
andy@26 123 ## Better title autodetection
andy@26 124 if not opts.TITLE:
andy@26 125 opts.TITLE = os.path.basename(os.path.abspath(opts.SRCDIR))
andy@24 126
andy@5 127 logging.debug("Title: %s" % opts.TITLE)
andy@5 128 logging.debug("Thumb height: %d" % opts.THUMB_HEIGHT)
andy@5 129
andy@1 130
andy@9 131 class ImageInfo(object):
andy@6 132 def __init__(self):
andy@9 133 self.name = None
andy@6 134 self.path = None
andy@9 135 self.thumbname = None
andy@9 136 self.thumbpath = None
andy@9 137 self.thumbx = None
andy@9 138 self.thumby = None
andy@9 139
andy@9 140 def setsize(self, sizetuple):
andy@9 141 self.thumbx = sizetuple[0]
andy@9 142 self.thumby = sizetuple[1]
andy@9 143
andy@7 144 def _getsize(self):
andy@9 145 return self.thumbx, self.thumby
andy@9 146
andy@9 147 thumbsize = property(_getsize, setsize)
andy@6 148
andy@6 149
andy@2 150 ## Go to the gallery directory and test if it's writeable
andy@2 151 if not os.access(opts.OUTDIR, os.W_OK):
andy@9 152 try:
andy@28 153 logging.debug("Making output dir in %s" % opts.OUTDIR)
andy@9 154 os.makedirs(opts.OUTDIR)
andy@28 155 except Exception as e:
andy@9 156 logging.error("Problem when making output dir %s... exiting" % opts.OUTDIR)
andy@9 157 exit(1)
andy@1 158
andy@14 159
andy@9 160 ## Make thumbnail directory if needed
andy@9 161 opts.THUMBDIR = "thumbs"
andy@9 162 THUMBDIR = os.path.join(opts.OUTDIR, opts.THUMBDIR)
andy@5 163 try:
andy@9 164 if not os.path.isdir(THUMBDIR):
andy@28 165 logging.debug("Making thumbs dir in %s" % THUMBDIR)
andy@9 166 os.makedirs(THUMBDIR)
andy@28 167 except Exception as e:
andy@5 168 logging.error("Problem when making thumbnails dir... exiting")
andy@9 169 exit(1)
andy@5 170
andy@2 171
andy@9 172 ## Build the list of pictures to display
andy@24 173 # TODO: types: PNG/GIF, JPEG, PDF
andy@24 174 # TODO: match formats & store thumb filenames
andy@9 175 EXTENSIONS = \
andy@9 176 ["*.jpg", "*.jpeg"] + \
andy@9 177 ["*.png", "*.gif"] + \
andy@9 178 ["*.tif", "*.tiff"] + \
andy@9 179 ["*.eps", "*.pdf"]
andy@9 180 imgs = []
andy@9 181 for img in os.listdir(opts.SRCDIR):
andy@9 182 for e in EXTENSIONS:
andy@24 183 if not fnmatch.fnmatch(img.lower(), e):
andy@24 184 continue
andy@24 185 if opts.EXCLUDE and re.search(opts.EXCLUDE, img):
andy@24 186 continue
andy@24 187 imgpath = os.path.join(opts.SRCDIR, img)
andy@24 188 imgs.append(imgpath)
andy@24 189 break
andy@9 190
andy@3 191 ## Count the pictures
andy@9 192 logging.debug("Number of pictures = %d" % len(imgs))
andy@9 193 if len(imgs) == 0:
andy@2 194 logging.debug("No pictures from which to build a gallery...")
andy@9 195 exit(2)
andy@9 196 logging.debug("Images: " + str(sorted(imgs)))
andy@2 197
andy@5 198
andy@9 199 ## Rename/move if needed
andy@9 200 outimgs = []
andy@9 201 for n, imgpath in enumerate(imgs):
andy@9 202 imgname = os.path.basename(imgpath)
andy@9 203 imgnameparts = os.path.splitext(imgname)
andy@9 204 targetname = imgname
andy@9 205 if opts.RENAME:
andy@9 206 targetname = "%s-%03d%s" % (safename(opts.OUTDIR), n, imgnameparts[1])
andy@9 207 targetpath = os.path.join(opts.OUTDIR, targetname)
andy@9 208 outimgs.append(targetpath)
andy@9 209 if imgpath != targetpath:
andy@9 210 logging.debug("Copying %s -> %s" % (imgpath, targetpath))
andy@9 211 import shutil
andy@9 212 shutil.copy(imgpath, targetpath)
andy@9 213
andy@9 214
andy@28 215 ## Process images
andy@28 216 logging.info("Processing {:d} images...".format(len(outimgs)))
andy@9 217 imgsinfo = {}
andy@9 218 for picpath in outimgs:
andy@9 219 picname = os.path.basename(picpath)
andy@9 220 picbase = os.path.splitext(picname)[0]
andy@9 221
andy@9 222 ## Convert EPS, PDF, TIFF to Web-viewable formats
andy@9 223 picversions = {}
andy@9 224 picpathparts = os.path.splitext(picpath)
andy@9 225 picnameparts = os.path.splitext(picname)
andy@9 226 extn = picnameparts[1].lower()
andy@28 227 pictype = extn[1:].upper(); pictype = "TIFF" if pictype == "TIF" else pictype
andy@28 228 picversions[pictype] = picname
andy@9 229 convcmd = None
andy@28 230 if pictype in ["TIFF", "EPS"]:
andy@28 231 newpictype = "PNG" if pictype == "EPS" else "JPG"
andy@28 232 newextn = "." + newpictype.lower()
andy@28 233 newpicname = picname + newextn
andy@28 234 newpicpath = picpath + newextn
andy@28 235 picversions[newpictype] = newpicname
andy@28 236 logging.debug("Converting {} to {}".format(picpath, newpicpath))
andy@28 237 img = PILI.open(picpath, "r")
andy@28 238 img.save(newpicpath)
andy@9 239 picname = newpicname
andy@9 240 picpath = newpicpath
andy@28 241 elif extn in [".pdf"]:
andy@9 242 newpicname = picname + ".png"
andy@9 243 newpicpath = picpath + ".png"
andy@9 244 picversions["PNG"] = newpicname
andy@28 245 logging.debug("Converting {} to {}".format(picpath, newpicpath))
andy@28 246 try:
andy@28 247 import pdf2image, tempfile
andy@28 248 with tempfile.TemporaryDirectory() as tmppath:
andy@28 249 pdfimgs = pdf2image.convert_from_path(picpath, output_folder=tmppath, first_page=0, last_page=1) #, fmt="png")
andy@28 250 #pdfimgs = pdf2image.convert_from_path(picpath, output_folder=tmppath)
andy@28 251 pdfimg = pdfimgs[0].save(newpicpath)
andy@28 252 if len(pdfimgs) > 1:
andy@28 253 logging.warning("Multi-page PDF {}: showing only page 1".format(picpath))
andy@28 254 except ImportError:
andy@28 255 import subprocess
andy@28 256 try:
andy@28 257 convcmd = ["convert", "-density", "200", "-resize", "800x700", picpath, newpicpath]
andy@28 258 subprocess.check_call(convcmd)
andy@28 259 except:
andy@28 260 logging.error("PDF conversion failed for {}... skipping".format(picpath))
andy@28 261 continue
andy@9 262 picname = newpicname
andy@9 263 picpath = newpicpath
andy@9 264
andy@9 265 ## Main pic info
andy@9 266 info = ImageInfo()
andy@9 267 info.name = picname
andy@9 268 info.path = picpath
andy@9 269 info.versions = picversions
andy@9 270
andy@9 271 ## Thumb info
andy@9 272 ## TODO: Un-hard-code PNG thumb format
andy@9 273 thumbname = picname + ".png"
andy@9 274 thumbpath = os.path.join(THUMBDIR, thumbname)
andy@9 275 info.thumbname = thumbname
andy@9 276 info.thumbpath = thumbpath
andy@9 277
andy@9 278 ## Make thumbnail
andy@9 279 ## TODO: Be lazy!
andy@9 280 #if opts.FORCE or not os.access(thumbpath, os.R_OK) or os.stat(thumbpath).st_mtime > os.stat(pic).st_mtime:
andy@9 281 try:
andy@28 282 logging.debug("Making new thumbnail %s for %s (max height %d)" % (thumbpath, picname, opts.THUMB_HEIGHT))
andy@9 283 thumbimg = PILI.open(picpath, "r")
andy@9 284 thumbimg.thumbnail((100000000, opts.THUMB_HEIGHT), resample=PILI.ANTIALIAS)
andy@9 285 thumbimg.save(thumbpath)
andy@9 286 info.thumbsize = thumbimg.size
andy@28 287 except Exception as e:
andy@9 288 logging.warning("Problem when making thumbnail from %s... exiting" % picpath)
andy@9 289 exit(1)
andy@9 290
andy@9 291 ## Store info
andy@9 292 imgsinfo[picname] = info
andy@9 293
andy@9 294
andy@9 295 #####################
andy@9 296
andy@5 297
andy@3 298 ## Calculate how many pages will be needed
andy@24 299 if opts.NUM_ROWS >= 1:
andy@24 300 NUM_PER_PAGE = opts.NUM_ROWS * opts.NUM_COLS
andy@24 301 NUM_PAGES = int(math.ceil( len(imgs)/float(NUM_PER_PAGE) ))
andy@24 302 else:
andy@24 303 NUM_PER_PAGE = len(imgs)
andy@24 304 NUM_PAGES = 1
andy@24 305
andy@24 306
andy@24 307 if NUM_PAGES > 1:
andy@25 308 logging.warn("%d gallery pages will be made. If you just want one page, use the -1 or --one-page option" % NUM_PAGES)
andy@1 309
andy@1 310
andy@14 311 ## TODO: Move HTML extension-setting to option parser
andy@6 312 ## (or take from template name, e.g. page.html.template -> html)
andy@6 313 opts.EXTN = "html"
andy@6 314
andy@6 315
andy@3 316 def getPageFilename(pagenum):
andy@9 317 if pagenum == 1:
andy@3 318 pagefile = "index.%s" % opts.EXTN
andy@3 319 else:
andy@3 320 pagefile = "index%02d.%s" % (pagenum, opts.EXTN)
andy@8 321 return pagefile
andy@3 322
andy@3 323
andy@3 324 def mkPageLinkStr(pagenum):
andy@14 325 "Write the linked page list"
andy@3 326 global NUM_PAGES
andy@14 327 out = ''
andy@3 328 if NUM_PAGES > 1:
andy@6 329 out += ""
andy@3 330 ## Previous
andy@3 331 prev = pagenum - 1
andy@3 332 if prev > 0:
andy@14 333 out += '<a href="%s">prev</a>' % getPageFilename(prev)
andy@3 334 else:
andy@14 335 out += 'prev'
andy@14 336 out += '&nbsp;'
andy@3 337 ## Numbers
andy@14 338 for n in range(1, NUM_PAGES+1):
andy@3 339 if n != pagenum:
andy@14 340 out += '<a href="%s">%d</a>' % (getPageFilename(n), n)
andy@14 341 else:
andy@14 342 out += "%d" % n
andy@14 343 out += '&nbsp;'
andy@3 344 ## Next
andy@3 345 next = pagenum + 1
andy@3 346 if next <= NUM_PAGES:
andy@14 347 out += '<a href="%s">next</a>' % getPageFilename(next)
andy@3 348 else:
andy@14 349 out += 'next'
andy@3 350 return out
andy@3 351
andy@3 352
andy@9 353 ## Make a zip archive
andy@9 354 ZIPFILE = "photo-album.zip"
andy@9 355 if True: #opts.WRITE_ZIPFILE:
andy@3 356 logging.debug("Making zipped picture archive")
andy@6 357 if opts.ZIPFILE is not None:
andy@6 358 ZIPFILE = opts.ZIPFILE
andy@6 359 elif opts.TITLE is not None or len(opts.TITLE) > 0:
andy@3 360 ZIPFILE = safeencode(opts.TITLE)
andy@8 361 #ZIPFILE = safename(opts.OUTDIR)
andy@9 362 if not "." in ZIPFILE or os.path.splitextn(ZIPFILE)[1] != ".zip":
andy@6 363 ZIPFILE += ".zip"
andy@9 364 ## Do the zipping
andy@13 365 if ZIPFILE:
andy@13 366 from zipfile import ZipFile
andy@13 367 zf = ZipFile(os.path.join(opts.OUTDIR, ZIPFILE), "w")
andy@13 368 for img in imgs:
andy@13 369 zf.write(img, os.path.basename(img))
andy@13 370 zf.close()
andy@13 371 else:
andy@13 372 logging.warning("No zip file made because zip filename is empty")
andy@3 373
andy@3 374
andy@24 375 ## Copy Lightbox stuff into ZIP
andy@9 376 #if opts.USE_JS:
andy@9 377 # from zipfile import ZipFile
andy@9 378 # zf = ZipFile(os.path.join(opts.OUTDIR, "lightbox.zip"), "r")
andy@9 379 # for img in imgs:
andy@9 380 # zf.write(img, os.path.basename(img))
andy@9 381 # zf.close()
andy@14 382
andy@9 383
andy@9 384 ## Default template
andy@9 385 tmplstr = \
andy@24 386 '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
andy@9 387 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
andy@9 388 <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
andy@9 389 <head>
andy@13 390 #set title = $PAGETITLE
andy@13 391 #if $NUM_PAGES > 1
andy@13 392 #set title = $title + " (page %s)" % $PAGENUM
andy@13 393 #end if
andy@9 394 <title>$title</title>
andy@9 395 <style>
andy@13 396 img { border:0; padding:10 10 0 0; }
andy@9 397 body { padding:1em; background:white; font-family:sans-serif; }
andy@9 398 h1 { font-family:sans-serif; }
andy@13 399 a.format { text-decoration:none; font-variant:small-caps; color:grey; font-size:small; }
andy@13 400 a.format:hover { color:deeppink; }
andy@13 401 a.format:active { color:deeppink; }
andy@14 402 .pagelinks { text-decoration:none; font-variant:small-caps; color:grey; margin-top:1em; margin-bottom:1em; }
andy@14 403 .pagelinks a:link { color:#22c; text-decoration:none; }
andy@14 404 .pagelinks a:hover { color:#55c; text-decoration:none; }
andy@14 405 .pagelinks a:active { color:#55c; text-decoration:none; }
andy@9 406 </style>
andy@9 407 #if $OPTS.USE_JS:
andy@14 408 <link rel="stylesheet" href="lightbox/css/lightbox.css" type="text/css" media="screen" />
andy@9 409 <script src="lightbox/js/prototype.js" type="text/javascript"></script>
andy@9 410 <script src="lightbox/js/scriptaculous.js?load=effects,builder" type="text/javascript"></script>
andy@9 411 <script src="lightbox/js/lightbox.js" type="text/javascript"></script>
andy@9 412 #end if
andy@9 413 </head>
andy@9 414 <body>
andy@9 415 <h1>$PAGETITLE</h1>
andy@9 416 #if $NUM_PAGES > 1
andy@9 417 <div class="pagelinks">Pages: $LINKSTR</div>
andy@9 418 #end if
andy@9 419
andy@9 420 <table>
andy@9 421 <tr>
andy@9 422 #set jsrel = ''
andy@9 423 #if $OPTS.USE_JS:
andy@9 424 #set jsrel = 'rel="lightbox[emin]"'
andy@9 425 #end if
andy@9 426 #for n, thumb in enumerate($PAGEPICS)
andy@9 427 #if $n % $NUM_COLS == 0 and $n not in (0, len($PAGEPICS)-1)
andy@9 428 <tr/><tr>
andy@9 429 #end if
andy@9 430 #set info = $PICINFO[$thumb]
andy@28 431 <td style="text-align:right;">
andy@23 432 <a href="$info.relpath" $jsrel><img alt="$thumb" src="$info.relthumbpath" style="border:0;" width="$info.thumbx" height="$info.thumby" /></a><br/>
andy@28 433 #for fmt, name in $info.versions.items()
andy@13 434 <a class="format" href="$name">$fmt.lower()</a>
andy@9 435 #end for
andy@9 436 </td>
andy@9 437 #end for
andy@9 438 </tr>
andy@9 439 </table>
andy@9 440
andy@9 441 #if $NUM_PAGES > 1
andy@9 442 <div class="pagelinks">Pages: $LINKSTR</div>
andy@9 443 #end if
andy@9 444
andy@13 445 #if $OPTS.WRITE_ZIPFILE and $ZIPFILE:
andy@9 446 <p>All zipped up: <a href="$ZIPFILE">$ZIPFILE</a></p>
andy@9 447 #end if
andy@9 448 </body>
andy@9 449 </html>
andy@24 450 '''
andy@9 451
andy@9 452
andy@9 453 ## Override default template with a template file
andy@9 454 if opts.TEMPLATE is not None:
andy@9 455 logging.info("Using index template file %s" % opts.TEMPLATE)
andy@9 456 tf = open(opts.TEMPLATE, "r")
andy@9 457 tmplstr = tf.read()
andy@9 458 tf.close()
andy@8 459
andy@8 460
andy@3 461 ## Make each index page
andy@3 462 for n in range(NUM_PAGES):
andy@6 463 PAGENUM = n + 1
andy@3 464
andy@3 465 ## Choose and open page file
andy@14 466 PAGEFILE = getPageFilename(PAGENUM)
andy@9 467 PAGEPATH = os.path.join(opts.OUTDIR, PAGEFILE)
andy@8 468
andy@3 469 ## Write the title
andy@26 470 PAGETITLE = opts.TITLE
andy@14 471
andy@3 472 ## Write the linked page list
andy@8 473 LINKSTR = mkPageLinkStr(PAGENUM)
andy@14 474
andy@9 475 ## Work out the picture offsets for this page
andy@3 476 pics_start = n * NUM_PER_PAGE
andy@3 477 pics_end = (n+1) * NUM_PER_PAGE - 1
andy@9 478 if pics_end >= len(imgs):
andy@9 479 pics_end = len(imgs) - 1
andy@1 480
andy@16 481 PAGEPICS = sorted(imgsinfo.keys())[pics_start: pics_end+1]
andy@9 482 PAGEPICNUMS = range(len(PAGEPICS))
andy@9 483 relthumbdir = opts.THUMBDIR
andy@9 484 #relthumbdir = os.path.relpath(THUMBDIR, OUTDIR)
andy@9 485 reloutdir = "."
andy@9 486 for k in imgsinfo.keys():
andy@9 487 imgsinfo[k].relthumbpath = os.path.normpath(os.path.join(relthumbdir, imgsinfo[k].thumbname))
andy@9 488 imgsinfo[k].relpath = os.path.normpath(os.path.join(reloutdir, imgsinfo[k].name))
andy@9 489 PICINFO = imgsinfo
andy@9 490 # THUMBNAMES = [t.name for t in thumbsinfo.values()[pics_start : pics_end]]
andy@9 491 # print THUMBNAMES
andy@9 492 # THUMBPATHS = [os.path.join(relthumbdir, name) for name in THUMBNAMES]
andy@9 493 # print THUMBPATHS
andy@9 494 # THUMBDIMS = [t.size for t in thumbsinfo.values()[pics_start : pics_end]]
andy@1 495
andy@28 496 logging.debug("Writing to index file %s" % PAGEPATH)
andy@9 497 f = open(PAGEPATH, "w")
andy@16 498 logging.debug("Images on page: %s" % PAGEPICS)
andy@8 499 tdict = {}
andy@8 500 tdict["NUM_PAGES"] = NUM_PAGES
andy@9 501 tdict["NUM_PER_PAGE"] = NUM_PER_PAGE
andy@9 502 tdict["NUM_COLS"] = opts.NUM_COLS
andy@8 503 tdict["PAGEPICS"] = PAGEPICS
andy@8 504 tdict["PAGENUM"] = PAGENUM
andy@8 505 tdict["PAGETITLE"] = PAGETITLE
andy@8 506 tdict["LINKSTR"] = LINKSTR
andy@8 507 tdict["PAGEPICNUMS"] = PAGEPICNUMS
andy@9 508 tdict["PICINFO"] = imgsinfo
andy@9 509 # tdict["THUMBS"] = thumbsinfo
andy@9 510 # tdict["THUMBNAMES"] = THUMBNAMES
andy@9 511 # tdict["THUMBPATHS"] = THUMBPATHS
andy@9 512 # tdict["THUMBDIMS"] = THUMBDIMS
andy@8 513 tdict["ZIPFILE"] = ZIPFILE
andy@8 514 tdict["OPTS"] = opts
andy@8 515 indexstr = Template(tmplstr, searchList=[tdict])
andy@9 516 #print indexstr
andy@8 517 f.write(str(indexstr))
andy@3 518 f.close()
andy@3 519
andy@3 520 ## It's over. Nothing to see here.
andy@3 521 logging.debug("All done!")

mercurial