--- /dev/null
+/* $Id: thumb.js,v 1.1 2006/11/05 10:57:55 mmondor Exp $ */
+
+/*
+ * Copyright (c) 2006, Matthew Mondor
+ * ALL RIGHTS RESERVED.
+ */
+
+/*
+ * TODO:
+ * - Implement getopt-like class and allow to provide command line arguments
+ * - Generate multiple indexes with list of index links at top and bottom
+ * for large directories
+ * - Instead of showing directory name link, show one of the thumbnails inside
+ * as clickable collection preview link
+ * - Work on better presentation
+ */
+
+function thumbnail(from, to, xmax, ymax)
+{
+ var ofh, oimg, ox, oy, timg, tfh;
+ var ret = false;
+ var type = undefined;
+ var i, to;
+
+ /* Set type relative to file extension */
+ if (from.match(/\.jpg$|\.jpeg$/))
+ type = 'JPG';
+ else if (from.match(/\.png$/))
+ type = 'PNG';
+ else if (from.match(/\.gif$/))
+ type = 'GIF';
+
+ /*
+ * We use a single try block which breaks out of for before setting
+ * res to true. We use a dummy for loop since goto doesn't work.
+ */
+ for (;;) {
+ try {
+ ofh = new File(from, 'r');
+ switch (type) {
+ case 'JPG':
+ oimg = GD.createFromJpeg(ofh);
+ break;
+ case 'PNG':
+ oimg = GD.createFromPng(ofh);
+ break;
+ case 'GIF':
+ oimg = GD.createFromGif(ofh);
+ break;
+ }
+
+ ox = oimg.imageSX();
+ oy = oimg.imageSY();
+ if (ox <= xmax && oy <= ymax) {
+ tx = ox;
+ ty = oy;
+ } else if (ox < oy) {
+ tx = Math.round((xmax / oy) * ox);
+ ty = ymax;
+ } else {
+ tx = xmax;
+ ty = Math.round((ymax / ox) * oy);
+ }
+
+ timg = GD.createTrueColor(tx, ty);
+ //oimg.copyResampled(timg, 0, 0, 0, 0, tx, ty, ox, oy);
+ oimg.copyResized(timg, 0, 0, 0, 0, tx, ty, ox, oy);
+
+ tfh = new File(to, 'w');
+ switch (type) {
+ case 'JPG':
+ timg.jpeg(tfh, 50);
+ break;
+ case 'PNG':
+ timg.png(tfh);
+ break;
+ case 'GIF':
+ timg.gif(tfh);
+ break;
+ }
+ } catch (x) {
+ Syslog.log(Syslog.LOG_NOTICE, x + ' (' + from + ')');
+ break;
+ }
+
+ /* Success */
+ ret = true;
+ break;
+ }
+
+ /*
+ * We close/destroy the objects in the same order they appeared since
+ * if we get an exception the others won't execute. Although the
+ * language supports a GC and objects will eventually be destroyed,
+ * there's no point in leaving them dangling unnecessary resources for
+ * a while. File descriptors shouldn't be open for nothing, and
+ * images take up a lot of memory.
+ */
+ try {
+ ofh.close();
+ oimg.destroy();
+ timg.destroy();
+ tfh.close();
+ } catch (x) {}
+
+ return ret;
+}
+
+function thumbnail_dir(path, xmax, ymax)
+{
+ var dir, fh;
+ var ret = false;
+ var i, f, index = [];
+
+ for (;;) {
+ try {
+ dir = new Dir(path);
+ while ((e = dir.read()) != null) {
+ if ((e.type & Dir.DT_DIR) != 0 &&
+ e.name.charAt(0) != '.') {
+ index.push({t: 'DIR', l: e.name});
+ if (!thumbnail_dir(path + '/' +
+ e.name, xmax, ymax))
+ break;
+ } else if ((e.type & Dir.DT_REG) != 0 &&
+ e.name.match(
+ /\.jpg$|\.jpeg$|\.png$|\.gif$/)) {
+ if (e.name.match(/_thumb/))
+ continue;
+ i = e.name.lastIndexOf('.');
+ newname = e.name.substring(0, i) +
+ '_thumb' + e.name.substring(i);
+ if (!thumbnail(path + '/' + e.name,
+ path + '/' + newname, xmax, ymax))
+ break;
+ index.push({t: 'IMG', o: e.name,
+ n: newname});
+ }
+ }
+ if (index.length > 0) {
+ /* XXX sort */
+ fh = new File(path + '/index.html', 'w');
+ fh.write("<html><head></head><body>\n" +
+ '<br><a href="../index.html">../</a><br>' +
+ "\n");
+ for (i in index) {
+ f = index[i];
+ if (f.t == 'DIR')
+ fh.write('<a href="' + f.l +
+ '/index.html">' + f.l +
+ "/</a><br>\n");
+ }
+ for (i in index) {
+ f = index[i];
+ if (f.t == 'IMG')
+ fh.write('<a target="_blank"' +
+ 'href="' + f.o +
+ '"><img src="' + f.n +
+ '"></a>' + "\n");
+ }
+ fh.write("</body></html>\n");
+ fh.close();
+ }
+ } catch (x) {
+ Syslog.log(Syslog.LOG_NOTICE, x.toString());
+ break;
+ }
+
+ ret = true;
+ break;
+ }
+
+ try {
+ dir.close();
+ fh.close();
+ } catch (x) {}
+
+ return ret;
+}
+
+thumbnail_dir('/home/data/jshttpd/mmondor/testimg', 128, 128);