summary refs log tree commit diff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--doc/Viewing Large Images with Seadragon and Python.html539
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/0491830b8e929f46ffba2b9e3920b307.pngbin0 -> 1565 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/06a26aadf9c62b93ec5d5d0154f6e3cf.pngbin0 -> 2211 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/139f37ae067ee7e473f71e849f63e82f.pngbin0 -> 1796 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017463815_e69a2d1edd_t.jpgbin0 -> 7307 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017467267_31165b2faa_t.jpgbin0 -> 6833 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/3018292436_4472ec4cb4_t.jpgbin0 -> 6859 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/317094104136ef2e6487bf5a61fb8217.pngbin0 -> 2177 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/34e36e0508f23947d839a8bff4d413cd.jpegbin0 -> 1718 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/51add0b18aa2a784ee43ecd046b99724.pngbin0 -> 3182 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/55ebe3141eb327cb93a05159fd50d70a.pngbin0 -> 2437 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/7e5c476f7ed6fcbb67eee738e304f066.jpegbin0 -> 1678 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/81955202e1a0524d206bd3f7b3967065.pngbin0 -> 1966 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/analytics.js59
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/ba08a1813ff5e44f655ee9ea58d1c992.pngbin0 -> 2176 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/comment-reply.js1
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/g.gifbin0 -> 50 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/g_002.gifbin0 -> 50 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/ga.js41
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/global.css16
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_smile.gifbin0 -> 174 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_wink.gifbin0 -> 170 bytes
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/kapilt1
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/quant.js92
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/style.css543
-rw-r--r--doc/Viewing Large Images with Seadragon and Pythonhtml_files/w.js48
-rw-r--r--doc/tilemaker.py222
27 files changed, 1562 insertions, 0 deletions
diff --git a/doc/Viewing Large Images with Seadragon and Python.html b/doc/Viewing Large Images with Seadragon and Python.html
new file mode 100644
index 0000000..93e677f
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Python.html
@@ -0,0 +1,539 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml" lang="en"><head profile="http://gmpg.org/xfn/11">
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Viewing Large Images - OpenLayers, GSIV, ModestMaps, DeepZoom, and Python  « Itinerant Source</title>
+<meta name="generator" content="WordPress.com"> 
+<link rel="stylesheet" href="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/style.css" type="text/css" media="screen">
+<link rel="alternate" type="application/rss+xml" title="Itinerant Source RSS Feed" href="http://blog.kapilt.com/feed/">
+<link rel="pingback" href="http://blog.kapilt.com/xmlrpc.php">
+		<script src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/remote-login.html" type="text/javascript"></script>
+		<style type="text/css">
+#flickr_badge_source_txt {padding:0; font: 11px Arial, Helvetica, Sans serif; color:#666666;}
+#flickr_badge_icon {display:block !important; margin:0 !important; border: 1px solid rgb(0, 0, 0) !important;}
+#flickr_icon_td {padding:0 5px 0 0 !important;}
+.flickr_badge_image {text-align:center !important;}
+.flickr_badge_image img {border: 1px solid black !important;}
+#flickr_badge_uber_wrapper {width:150px;}
+#flickr_www {display:block; text-align:center; padding:0 10px 0 10px !important; font: 11px Arial, Helvetica, Sans serif !important; color:#3993ff !important;}
+#flickr_badge_uber_wrapper a:hover,
+#flickr_badge_uber_wrapper a:link,
+#flickr_badge_uber_wrapper a:active,
+#flickr_badge_uber_wrapper a:visited {text-decoration:none !important; background:inherit !important;color:#3993ff;}
+#flickr_badge_wrapper {background-color:#ffffff;border: solid 1px #000000}
+#flickr_badge_source {padding:0 !important; font: 11px Arial, Helvetica, Sans serif !important; color:#666666 !important;}
+</style>
+<link rel="alternate" type="application/rss+xml" title="Itinerant Source » Viewing Large Images - OpenLayers, GSIV, ModestMaps, DeepZoom, and&nbsp;Python Comments Feed" href="http://blog.kapilt.com/2008/11/30/viewing-large-images-openlayers-gsiv-modestmaps-deepzoom-and-python/feed/">
+<script type="text/javascript">
+/* <![CDATA[ */
+function addLoadEvent(func) {
+	var oldonload = window.onload;
+	if (typeof window.onload != 'function') {
+		window.onload = func;
+	} else {
+		window.onload = function() { oldonload(); func(); }
+	}
+}
+/* ]]> */
+</script>
+<link rel="stylesheet" href="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/global.css" type="text/css">
+<script type="text/javascript" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/comment-reply.js"></script>
+<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://blog.kapilt.com/xmlrpc.php?rsd">
+<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://blog.kapilt.com/wp-includes/wlwmanifest.xml"> 
+<script type="text/javascript">
+	window.google_analytics_uacct = "UA-52447-2";
+</script>
+	<link rel="introspection" type="application/atomserv+xml" title="Atom API" href="http://blog.kapilt.com/wp-app.php">
+<link rel="shortcut icon" type="image/x-icon" href="http://www.gravatar.com/blavatar/3c906e874cc0b7361487097fc04b0f0c?s=16&amp;d=http://s.wordpress.com/favicon.ico">
+<link rel="icon" type="image/x-icon" href="http://www.gravatar.com/blavatar/3c906e874cc0b7361487097fc04b0f0c?s=16&amp;d=http://s.wordpress.com/favicon.ico">
+<link rel="apple-touch-icon" href="http://www.gravatar.com/blavatar/1630a9deba420111303d4191ab273ecf?s=158&amp;d=http://s.wordpress.com/wp-content/themes/h4/i/webclip.png">
+<link rel="openid.server" href="http://kapilt.wordpress.com/?openidserver=1">
+<link rel="openid.delegate" href="http://kapilt.wordpress.com/">
+<style type="text/css">
+#headerimage {
+	background: url(http://s2.wordpress.com/wp-content/themes/pub/mistylook/img/misty.jpg) no-repeat;
+}
+</style>
+</head><body id="section-index">
+
+
+<div id="navigation">
+<ul>
+	<li><a href="http://blog.kapilt.com/" title="Home">Home</a></li>
+		<li class="page_item page-item-2"><a href="http://blog.kapilt.com/about/" title="About">About</a></li>
+	<li class="search"><form method="get" id="searchform" action="http://blog.kapilt.com"><input class="textbox" value="" name="s" id="s" type="text"><input id="searchsubmit" value="Search" type="submit"></form></li>
+</ul>
+</div><!-- end id:navigation -->
+
+
+<div id="container">
+
+
+<div id="header">
+<h1><a href="http://blog.kapilt.com/" title="Itinerant Source">Itinerant Source</a></h1>
+<h2>Python and Zope Programming</h2>
+</div><!-- end id:header -->
+
+
+<div id="feedarea">
+<dl>
+	<dt><strong>Feed on</strong></dt>
+	<dd><a href="http://blog.kapilt.com/feed/">Posts</a></dd>
+	<dd><a href="http://blog.kapilt.com/comments/feed/">Comments</a></dd>		
+</dl>
+</div><!-- end id:feedarea -->
+
+  
+  <div id="headerimage">
+</div><!-- end id:headerimage -->
+<div id="content">
+<div id="content-main">
+		
+						
+			<div class="post hentry category-python" id="post-25">
+				<div class="posttitle">
+					<h2>Viewing Large Images - OpenLayers, GSIV, ModestMaps, DeepZoom, and&nbsp;Python</h2>
+					<p class="post-info">November 30, 2008 by <a href="http://blog.kapilt.com/author/kapilt/" title="Posts by kapilt">kapilt</a>  </p>
+				</div>
+				
+				<div class="entry">
+					<div class="snap_preview"><p>Lately
+I’ve been experimenting with displaying very large images on the
+internet via a web browser, with pan and zoom functionality. The guts
+of this functionality are the same regardless of implementation. On the
+server, a tile cutter processes a large image, and constructs an image
+pyramid. The image pyramid is a hierarchical structure composed of n
+levels of the same image at different resolutions. Starting with the
+bottom level as the original image, each successive level reduces the
+image size by half, and the process is repeated log_2( max( width,
+height)) times until finally an image of only 1 pixel (average of
+entire image) is generated as the top of the pyramid. Each level’s
+image is split into a set of fixed size tiles. A web browser client
+implementation ( flash, ajax, etc) constructs&nbsp; a zoom interface,
+that responds to zoom in events by moving the viewport progressively
+further down the pyramid, showing tile images of the larger resolution
+to give the effect of zooming into an image. A nice illustrated write
+up of the concept can be found <a href="http://gasi.ch/blog/inside-deep-zoom-1/">here</a>. I’ve probably made it sound more complicated than it really is.</p>
+<p>The initial implementation I was working with utilized <a href="http://openlayers.org/">OpenLayers</a>, which implements a client for accessing OpenGIS Web Feature Servers (<a href="http://www.opengeospatial.org/standards/wfs">WFS</a>) and Web Mapping Servers (<a href="http://www.opengeospatial.org/standards/wms">WMS</a>).
+Unfortunately the size of the library seems to be constantly increasing
+(~200K in the last year) and currently weighs in at 560K uncompressed,
+and requires a special implementation to serve up the tile images, ie.
+a WMS Compliant system, in this case <a href="http://tilecache.org/">TileCache</a>. For scaling and efficiency purposes, I’d much prefer to directly serve these images off a <a href="http://en.wikipedia.org/wiki/Content_Delivery_Network">CDN</a>, disk (<a href="http://nginx.net/">nginx</a>), or via <a href="http://varnish.projects.linpro.no/">varnish</a>
+and bypass any application code. Additionally the sheer size of the
+OpenLayers code was unwieldy for the integrations requirements I had,
+which did not include any GIS functionality.</p>
+<p>Surveying the land for other non-commercial image viewers, turned up a few of interest. <a href="http://code.google.com/p/panojs/">GSIV</a>
+( Giant Scalable Image Viewer), was a fairly basic but capable
+javascript based viewer, that fit my requirements bill, small size at
+26Kb uncompressed, and focused on pan and zoom functionality (<a href="http://www.mojavelinux.com/cooker/demos/gsv/">demo</a>).
+However as a project it appears to be abandoned, and hasn’t been
+touched in two years, although several patches have been submitted
+which retrofit the implementation using jquery are extant.</p>
+<p>I came across <a href="http://modestmaps.com/">ModestMaps</a> next, which is a flash (2 &amp; 3 ) based implementation, with a small size (<a href="http://modestmaps.com/example.html">demo</a>).
+One nice feature of modest maps, is that it performs interpolation
+between successive levels giving a smooth zoom experience to an end
+user unlike somewhat jerky experience that GSIV produced. Unfortunately
+being flash based meant a whole different chain of development tools. I
+looked around at what was available for an opensource flash compiler
+toolchain and found <a href="http://www.mtasc.org/">MTASC</a> (Motion Twin Action Script Compiler ) and <a href="http://www.haxe.org/">Haxe</a>.
+In the end i decided against it, partly due to its GIS focus, and the
+customization/ maintenance cost for developing on propretiary platform
+(Flash). Despite that, i think its the best of the opensource viewer
+implementations if your already have/use an adobe flash development
+stack.</p>
+<p>I was set on using GSIV, and then i came across a<a href="http://ajaxian.com/archives/seadragon"> blurb on ajaxian</a>
+about Seadragon Ajax and Deep Zoom from Microsoft’s Live Labs.
+Microsoft’s done some impressive work with image manipulation over the
+last few years. The <a href="http://www.ted.com/index.php/talks/blaise_aguera_y_arcas_demos_photosynth.html">PhotoSynth TED talk</a> is one of the most impressive technology demos i’ve seen to date. <a href="http://en.wikipedia.org/wiki/Deep_Zoom">Deep Zoom</a> is a <a href="http://en.wikipedia.org/wiki/Silverlight">SilverLight</a> technology ( more propretiary platform lockin), that allows for multiscale image zooming with smooth zooming. The<a href="http://livelabs.com/seadragon-ajax/library/"> Seadragon Ajax</a>
+is a javascript implementation of the same functionality in a 154k
+library ( 20k minimized and gzipped). It fit the bill perfectly,
+standards (javascript) based, image zoom and pan, with a great user
+experience. One problem unlike all the other tools mentioned here,
+which have python based tile cutting implementations, Deep Zoom was
+utilizing a Windows only based program to process images and cut tiles.
+I had a couple of hundred gigabytes of images to cut, and not a windows
+system in sight. But based on this <a href="http://gasi.ch/blog/inside-deep-zoom-2/">excellent blog write up by  Daniel Gasienica</a>,
+I constructed a python program using PIL that can be used as a command
+line tool or library for constructing Deep Zoom Compatible image
+pyramids. It can be found <a href="http://kapilt.com/files/seadragon.py">here</a>,
+hopefully its useful to others. As a bonus, it runs in a fraction of
+the memory (1/6 by my measurements) needed by the GSIV image tile
+cutter and faster as well ( 100 images in 5m vs 1.25hr). Unfortunately
+the Seadragon Ajax Library is not opensource, but non commercial usage
+seems to be okay with the license, and i’ll give it over to some
+lawyers to figure it out.</p>
+<p>To process the several hundred gigabytes of images, i utilized this library and wrote a batch driver utilizing&nbsp; <a href="http://pyprocessing.berlios.de/">pyprocessing remote queues</a>, a small <a href="http://pypi.python.org/pypi/zc.buildout">zc.buildout</a> and <a href="http://code.google.com/p/cloudcontrol/">cloudcontrol</a> to process the images across a cluster, but thats left as an implementation detail for the reader <img src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/icon_smile.gif" alt=":-)" class="wp-smiley"> </p>
+<p><a href="http://kapilt.com/files/seadragon.py">Python Deep Zoom TileCutter</a></p>
+</div>									</div>
+		
+				<p class="postmetadata">Posted in <a href="http://en.wordpress.com/tag/python/" title="View all posts in python" rel="category tag">python</a> | 14 Comments</p>
+				
+<!-- You can start editing here. -->
+
+<h3 id="comments">14 Responses to “Viewing Large Images - OpenLayers, GSIV, ModestMaps, DeepZoom, and&nbsp;Python”</h3>
+
+	<ol class="commentlist">
+			<li class="comment even thread-even depth-1" id="comment-68">
+		<div id="div-comment-68">
+		<div class="cmtinfo"><em> on <a href="#comment-68" title="">November 30, 2008 at 6:03 am</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/139f37ae067ee7e473f71e849f63e82f.png" class="avatar avatar-48" width="48" height="48"> <cite><a href="http://akishore.com/" rel="external nofollow" class="url">Aseem Kishore</a></cite></div>
+						
+			<p>Hi Kapil,</p>
+<p>I’m part of the Seadragon Ajax team, and it’s great to hear that you
+like our work! Please feel free to pass on feedback as you use it. =)</p>
+<p>Best,<br>
+Aseem</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment odd alt thread-odd thread-alt depth-1" id="comment-70">
+		<div id="div-comment-70">
+		<div class="cmtinfo"><em> on <a href="#comment-70" title="">November 30, 2008 at 5:26 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/ba08a1813ff5e44f655ee9ea58d1c992.png" class="avatar avatar-48" width="48" height="48"> <cite>Henning</cite></div>
+						
+			<p>Sounds interesting. As you already have investigated those libraries, you could perhaps help me.<br>
+I was thinking about creating an AJAX function plotter (using
+matplotlib). Until now I only found OpenLayers but I don’t need these
+GIS features. What would you suggest for my project? I am mainly
+interested in the interactive dragging and zooming feature. The image
+would be generated on the fly.</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment even thread-even depth-1" id="comment-71">
+		<div id="div-comment-71">
+		<div class="cmtinfo"><em> on <a href="#comment-71" title="">November 30, 2008 at 7:44 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/81955202e1a0524d206bd3f7b3967065.png" class="avatar avatar-48" width="48" height="48"> <cite><a href="http://iipimage.sourceforge.net/" rel="external nofollow" class="url">Ruven</a></cite></div>
+						
+			<p>Another image viewer you may be interested in is IIPImage (<a href="http://iipimage.sf.net/" rel="nofollow">http://iipimage.sf.net</a>)
+which is a fully Open Source system with various alternative clients
+such as a flash, java and ajax. I’m the maintainer, so possibly biased <img src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/icon_wink.gif" alt=";)" class="wp-smiley"> </p>
+<p>One advantage is that we can run off a single TIFF file rather than
+having to store thousands of tile pieces. On the other hand, it
+requires you to install an FCGI server.</p>
+<p>Anyway, it’ll be interesting to see how this Deep Zoom format develops.</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment odd alt thread-odd thread-alt depth-1" id="comment-74">
+		<div id="div-comment-74">
+		<div class="cmtinfo"><em> on <a href="#comment-74" title="">December 1, 2008 at 9:24 am</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/7e5c476f7ed6fcbb67eee738e304f066.jpeg" class="avatar avatar-48" width="48" height="48"> <cite><a href="http://mockit.blogspot.com/" rel="external nofollow" class="url">Malthe</a></cite></div>
+						
+			<p>Long
+time ago I had a similar requirement; I ended up converting all image
+files to uncompressed 32-bit TIFF files and wrote the image cutter in
+C, then piped the result to an imagemagick converter.</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment even thread-even depth-1" id="comment-75">
+		<div id="div-comment-75">
+		<div class="cmtinfo"><em> on <a href="#comment-75" title="">December 1, 2008 at 5:28 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/0491830b8e929f46ffba2b9e3920b307.png" class="avatar avatar-48" width="48" height="48"> <cite><a href="http://crschmidt.net/" rel="external nofollow" class="url">Christopher Schmidt</a></cite></div>
+						
+			<p>It looks like you’ve already moved on, but I wanted to point out two things about OpenLayers for the record:</p>
+<p> 1. OpenLayers supports custom build profiles including only the
+pieces you care about. A simple map — just dragging and WMS tiles —
+clocks in at about 110k — and has been within 20% of that for most of
+the 2.x series (now two years running). Information on using the build
+tools to build your own build are available at <a href="http://trac.openlayers.org/wiki/Profiles" rel="nofollow">http://trac.openlayers.org/wiki/Profiles</a>
+. Once you take the 110k and run it through gzip, you’re down to ~25k —
+not that much larger than the binary ModestMaps builds that I checked
+out (which clocked in at 18kb, but didn’t compress much/at all with
+gzip).</p>
+<p> 2. OpenLayers can load all kinds of tiles, including tiles stored in a flat filesystem on a CDN or similar. <a href="http://trac.openlayers.org/wiki/UsingCustomTiles" rel="nofollow">http://trac.openlayers.org/wiki/UsingCustomTiles</a>
+documents how, and even documents how to set up OpenLayers for
+projectionless images, which is what you’re currently working with
+based on my quick skim.</p>
+<p>This isn’t to say that OpenLayers is always the right tool, but
+using the TMS layer and custom profiles would probably significantly
+change the experience with regard to the two complaints that you had
+with OpenLayers.</p>
+<p>(Also, I’m clearly biased an OpenLayers + TileCache developer.)</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment odd alt thread-odd thread-alt depth-1" id="comment-76">
+		<div id="div-comment-76">
+		<div class="cmtinfo"><em> on <a href="#comment-76" title="">December 1, 2008 at 8:59 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/317094104136ef2e6487bf5a61fb8217.png" class="avatar avatar-48" width="48" height="48"> <cite>Vince</cite></div>
+						
+			<p>@ Henning,</p>
+<p>Have you tried Flot:</p>
+<p><a href="http://code.google.com/p/flot/" rel="nofollow">http://code.google.com/p/flot/</a></p>
+<p>Vince</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="pingback even thread-even depth-1" id="comment-77">
+		<div id="div-comment-77">
+		<div class="cmtinfo"><em> on <a href="#comment-77" title="">December 2, 2008 at 12:19 am</a></em>  <cite><a href="http://botd.wordpress.com/2008/12/01/top-posts-948/" rel="external nofollow" class="url">Top Posts « WordPress.com</a></cite></div>
+						
+			<p>[...]
+Viewing Large Images - OpenLayers, GSIV, ModestMaps, DeepZoom, and
+Python Lately I’ve been experimenting with displaying very large images
+on the internet via a web browser, with pan and [...] [...]</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment odd alt thread-odd thread-alt depth-1" id="comment-78">
+		<div id="div-comment-78">
+		<div class="cmtinfo"><em> on <a href="#comment-78" title="">December 2, 2008 at 5:22 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/51add0b18aa2a784ee43ecd046b99724.png" class="avatar avatar-48" width="48" height="48"> <cite><a href="http://www.ridethecity.com/" rel="external nofollow" class="url">Jordan Anderson</a></cite></div>
+						
+			<p>I’m
+currently using OpenLayers and TileCache with Amazon’s new CoudFront
+CDN service on a development version of ridethecity.com (soon to be
+released to the public).</p>
+<p>I used TileCache with Geoserver to generate several thousand PNG tiles using its seed script. Then I:</p>
+<p>1. Uploaded the images to Amazon S3 using the directory structure generated by TileCache<br>
+2. Created a CloudFront distribution<br>
+3. Turned off both TileCache and Geoserver (since I seeded 100% of the
+zoom levels and extent I’m dealing with — in my case, New York City and
+environs)<br>
+4. Used OpenLayers’ Tile Map Service (TMS) support to grab the correct tiles from CloudFront</p>
+<p>Wow, it’s fast. And my bill last month — even after all the PNG PUT
+requests and prorating to account for the partial month of CloudFront
+service — was just under one dollar.</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="pingback even thread-even depth-1" id="comment-79">
+		<div id="div-comment-79">
+		<div class="cmtinfo"><em> on <a href="#comment-79" title="">December 10, 2008 at 11:02 pm</a></em>  <cite><a href="http://dragonosticism.wordpress.com/2008/12/10/deep-zoom-image-creation-with-python/" rel="external nofollow" class="url">Deep Zoom Image creation with Python « Dragonosticism</a></cite></div>
+						
+			<p>[...]
+images into DZI format. In addition to Python, you’ll need the Python
+Imaging Library. See his blog post for more information, along with an
+analysis of why he chose DZI over other zooming [...]</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment byuser comment-author-igilman odd alt thread-odd thread-alt depth-1" id="comment-80">
+		<div id="div-comment-80">
+		<div class="cmtinfo"><em> on <a href="#comment-80" title="">December 10, 2008 at 11:12 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/06a26aadf9c62b93ec5d5d0154f6e3cf.png" class="avatar avatar-48" width="48" height="48"> <cite>igilman</cite></div>
+						
+			<p>Kapil,</p>
+<p>Thank you for making this Python script! It’s a great service to the
+Deep Zoom community. I’ve mentioned it now on my Dragonosticism blog: </p>
+<p><a href="http://dragonosticism.wordpress.com/2008/12/10/deep-zoom-image-creation-with-python/" rel="nofollow">http://dragonosticism.wordpress.com/2008/12/10/deep-zoom-image-creation-with-python/</a></p>
+<p>I tried it on a 5,000 pixel square image, and it worked perfectly. I
+then tried it on the 20,000 pixel square World Wide Music Scene image
+from the Seadragon Ajax Gallery, and it ground my system to a halt and
+then failed with a memory error. This isn’t surprising, as most tools
+break down at those sizes, but we’re hoping to help get us all past
+that. </p>
+<p>Are you planning on continuing to develop this script?</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment byuser comment-author-kapilt bypostauthor even thread-even depth-1" id="comment-81">
+		<div id="div-comment-81">
+		<div class="cmtinfo"><em> on <a href="#comment-81" title="">December 11, 2008 at 2:52 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/55ebe3141eb327cb93a05159fd50d70a.png" class="avatar avatar-48" width="48" height="48"> <cite><a href="http://kapilt.wordpress.com/" rel="external nofollow" class="url">kapilt</a></cite></div>
+						
+			<p>@christopher
+thanks for the clarifications regarding openlayers build profiles and
+custom tile options. its a very capable project. I recently went to
+SearchCampDC ( <a href="http://barcamp.org/SearchCampDC" rel="nofollow">http://barcamp.org/SearchCampDC</a>
+) and saw several impressive gis applications built on top of
+openlayers. However, for this particular use primarily as a large image
+viewer, the continuous/fluid zoom offered by deepzoom offers a better
+end user experience imo.</p>
+<p>@igilman for jpeg images, the memory usage seems to be total pixel
+size (w*h) * 4.3. The largest image i’m working with is about 110M
+pixels. I was unable to find the source image for the referenced world
+wide music scene, and the very very large image group on flickr all
+seem to be well below 110M pixels. most of the memory constraints seem
+to be related to the underlying image functionality offered by the
+python image library (PIL). While there are other cross platform
+libraries, their installation and language bindings for python are
+typically non trivial on non linux platforms (my production environment
+for this app is solaris). In terms of future development, if there are
+additional feature requests, i’m open to them, and if there is interest
+i can set up a project on a hosted platform. alternatively if there’s
+interest in folding this into a deep zoom hosted download, i’d be happy
+to sign it over. outside of distribution as a python egg for easier
+installation, and a verbose/progress option, i’m pretty happy with the
+script.</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment byuser comment-author-igilman odd alt thread-odd thread-alt depth-1" id="comment-82">
+		<div id="div-comment-82">
+		<div class="cmtinfo"><em> on <a href="#comment-82" title="">December 11, 2008 at 7:02 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/06a26aadf9c62b93ec5d5d0154f6e3cf.png" class="avatar avatar-48" width="48" height="48"> <cite>igilman</cite></div>
+						
+			<p>@kapilt
+The full music image isn’t available online. I agree it’s hard to find
+big images; that’s one of the things we’re trying to fix! One large one
+(half a gigapixel) is here:</p>
+<p><a href="http://onemansblog.com/2008/04/04/gigapixel-photo-of-1906-san-francisco-earthquake-aftermath/" rel="nofollow">http://onemansblog.com/2008/04/04/gigapixel-photo-of-1906-san-francisco-earthquake-aftermath/</a></p>
+<p>To deal with large images properly, you may have to get aggressive
+about purging memory. The music image successfully loaded into memory,
+and all but the highest resolution tile set was correctly created with
+your script; it was just the last set of tiles where it ran out of
+memory. </p>
+<p>As for feature requests, besides handling larger images
+successfully, the only other thing I’d want at the moment would be some
+sort of progress indication (like a verbose mode). </p>
+<p>I’ll continue pointing people in your direction, and we’ll see what
+sort of interest the script gets. I’m excited about all the new
+developments!</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="comment byuser comment-author-gasi even thread-even depth-1" id="comment-83">
+		<div id="div-comment-83">
+		<div class="cmtinfo"><em> on <a href="#comment-83" title="">December 15, 2008 at 6:32 pm</a></em> <img alt="" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/34e36e0508f23947d839a8bff4d413cd.jpeg" class="avatar avatar-48" width="48" height="48"> <cite><a href="http://gasi.ch/blog" rel="external nofollow" class="url">gasi</a></cite></div>
+						
+			<p>Hello Kapil<br>
+First of all, thanks for referencing the articles on my blog&nbsp;—I’m&nbsp;glad they helped you out.</p>
+<p>For anyone interested in incorporating very large images into their
+applications, check out the open source OpenZoom framework I’ve started
+at <a href="http://openzoom.org/" rel="nofollow">http://openzoom.org/</a><br>
+Basically, OpenZoom provides you with some building blocks to create
+ZUI applications like mapping, e-commerce, medical that need to present
+multi-scale images in formats such as Zoomify, Deep Zoom or others in a
+dynamic fashion.<br>
+To see some examples of things you can do with OpenZoom, I encourage you to check out my blog <a href="http://gasi.ch/blog/flex-multiscaleimage-component/" rel="nofollow">http://gasi.ch/blog/flex-multiscaleimage-component/</a> or tandem, a proof of concept for browsing Flickr at <a href="http://tandem.gasi.ch/" rel="nofollow">http://tandem.gasi.ch/</a></p>
+<p>Cheers,<br>
+Daniel</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+		<li class="pingback odd alt thread-odd thread-alt depth-1" id="comment-85">
+		<div id="div-comment-85">
+		<div class="cmtinfo"><em> on <a href="#comment-85" title="">December 19, 2008 at 3:34 am</a></em>  <cite><a href="http://gasi.ch/blog/openzoom-description-format/" rel="external nofollow" class="url">OpenZoom Description Format — RTFM / Daniel Gasienica</a></cite></div>
+						
+			<p>[...]
+Viewing Large Images - OpenLayers, GSIV, ModestMaps, DeepZoom, and
+Python — Create Deep Zoom Images on Windows, Mac and Linux with Python
+and PIL. [...]</p>
+			<br style="clear: both;">	
+		</div>
+</li>
+	</ol>
+
+	<div class="navigation">
+		<div class="alignleft"></div>
+		<div class="alignright"></div>
+	</div>
+	<br>
+
+  <div class="post-content">
+<p>
+	<span class="trackback"><a href="http://blog.kapilt.com/2008/11/30/viewing-large-images-openlayers-gsiv-modestmaps-deepzoom-and-python/trackback/">Trackback URI</a></span> | 
+	<span class="commentsfeed"><a href="http://blog.kapilt.com/2008/11/30/viewing-large-images-openlayers-gsiv-modestmaps-deepzoom-and-python/feed/">Comments RSS</a></span>
+</p>
+</div>
+
+
+<div id="respond">
+
+<h3>Leave a Reply</h3>
+
+<div class="cancel-comment-reply">
+	<small><a rel="nofollow" id="cancel-comment-reply-link" href="http://blog.kapilt.com/2008/11/30/viewing-large-images-openlayers-gsiv-modestmaps-deepzoom-and-python/#respond" style="display: none;">Click here to cancel reply.</a></small>
+</div>
+
+
+<form action="http://blog.kapilt.com/wp-comments-post.php" method="post" id="commentform">
+
+
+<p><input class="textbox" name="author" id="author" value="" size="22" tabindex="1" type="text">
+<label for="author"><small>Name (required)</small></label></p>
+
+<p><input class="textbox" name="email" id="email" value="" size="22" tabindex="2" type="text">
+<label for="email"><small>Mail (will not be published) (required)</small></label></p>
+
+<p><input class="textbox" name="url" id="url" value="" size="22" tabindex="3" type="text">
+<label for="url"><small>Website</small></label></p>
+
+
+<!--<p><small><strong>XHTML:</strong> You can use these tags: &lt;a href=&quot;&quot; title=&quot;&quot;&gt; &lt;abbr title=&quot;&quot;&gt; &lt;acronym title=&quot;&quot;&gt; &lt;b&gt; &lt;blockquote cite=&quot;&quot;&gt; &lt;cite&gt; &lt;code&gt; &lt;del datetime=&quot;&quot;&gt; &lt;em&gt; &lt;i&gt; &lt;q cite=&quot;&quot;&gt; &lt;strike&gt; &lt;strong&gt; </small></p>-->
+
+<p><textarea name="comment" id="comment" cols="100" rows="10" tabindex="4"></textarea></p>
+
+<p><input name="submit" id="submit" tabindex="5" value="Submit Comment" type="submit">
+<input name="comment_post_ID" value="25" id="comment_post_ID" type="hidden">
+<input name="comment_parent" id="comment_parent" value="0" type="hidden">
+</p>
+<p><input name="subscribe" id="subscribe" value="subscribe" style="width: auto;" type="checkbox">
+		<label for="subscribe" id="subscribe-label">Notify me of follow-up comments via email.</label></p>
+</form>
+
+
+</div>
+
+			</div>
+	
+		
+		<p align="center"></p>
+		
+	</div><!-- end id:content-main -->
+<div id="sidebar">
+<ul>
+<li class="sidebox"><h2>Archives</h2>		<ul>
+			<li><a href="http://blog.kapilt.com/2008/11/" title="November 2008">November 2008</a></li>
+	<li><a href="http://blog.kapilt.com/2008/07/" title="July 2008">July 2008</a></li>
+	<li><a href="http://blog.kapilt.com/2008/05/" title="May 2008">May 2008</a></li>
+	<li><a href="http://blog.kapilt.com/2008/04/" title="April 2008">April 2008</a></li>
+	<li><a href="http://blog.kapilt.com/2008/01/" title="January 2008">January 2008</a></li>
+	<li><a href="http://blog.kapilt.com/2007/11/" title="November 2007">November 2007</a></li>
+	<li><a href="http://blog.kapilt.com/2007/08/" title="August 2007">August 2007</a></li>
+	<li><a href="http://blog.kapilt.com/2006/12/" title="December 2006">December 2006</a></li>
+	<li><a href="http://blog.kapilt.com/2006/09/" title="September 2006">September 2006</a></li>
+		</ul>
+</li>		<li class="sidebox">			<h2><a href="http://del.icio.us/kapilt">Bookmarks</a></h2><div id="delicious-box" style="border: medium none ; margin: 0pt; padding: 0pt;"> <ul id="delicious-list"><li><a href="http://www.loc.gov/standards/sru/specs/cql.html">CQL: the Contextual Query Language: Specifications (SRU: Search/Retrieval via URL, Standards, Library of Congress)</a></li><li><a href="http://jangle.org/">jangle.org</a></li><li><a href="http://lericson.blogg.se/code/2008/november/pylibmc-051.html">pylibmc</a></li><li><a href="http://sourceforge.net/projects/enomalism">Enomaly Elastic Computing</a></li><li><a href="http://www.convirture.com/wiki/index.php?title=Main_Page">ConVirt</a></li><li><a href="http://gate.ac.uk/">GATE, A General Architecture for Text Engineering</a></li><li><a href="http://www.zeromq.org/">zeromq: Fastest. Messaging. Ever.</a></li><li><a href="http://highscalability.com/numbers-everyone-should-know">AppEngine - Numbers Everyone Should Know</a></li><li><a href="http://blogs.digitar.com/jjww/2009/01/rabbits-and-warrens/">AMQP Server Comparison and Py</a></li><li><a href="https://launchpad.net/txamqp">txAMQP: Twisted AMQP in Launchpad</a></li></ul></div>
+			<script type="text/javascript" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/kapilt"></script>
+			<script type="text/javascript">
+			function showImage(img){ return (function(){ img.style.display='inline'; }) }
+			var ul = document.createElement('ul');
+			for (var i=0, post; post = Delicious.posts[i]; i++) {
+				var li = document.createElement('li');
+				var a = document.createElement('a');
+				a.setAttribute('href', post.u);
+				a.appendChild(document.createTextNode(post.d));
+				li.appendChild(a);
+				ul.appendChild(li);
+			}
+			ul.setAttribute('id', 'delicious-list');
+			document.getElementById('delicious-box').appendChild(ul);
+			</script>
+		</li>	<li class="sidebox">	<h2>Photos</h2><!-- Start of Flickr Badge -->
+<table id="flickr_badge_uber_wrapper" border="0" cellpadding="0" cellspacing="10"><tbody><tr><td><table id="flickr_badge_wrapper" border="0" cellpadding="0" cellspacing="10">
+<tbody><tr><td align="center">
+<a href="http://www.flickr.com/photos/k_vertigo/3017467267/"><img alt="DSC_0060.JPG" title="DSC_0060.JPG" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/3017467267_31165b2faa_t.jpg" border="0"></a><br><br><a href="http://www.flickr.com/photos/k_vertigo/3017463815/"><img alt="DSC_0059.JPG" title="DSC_0059.JPG" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/3017463815_e69a2d1edd_t.jpg" border="0"></a><br><br><a href="http://www.flickr.com/photos/k_vertigo/3018292436/"><img alt="DSC_0058.JPG" title="DSC_0058.JPG" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/3018292436_4472ec4cb4_t.jpg" border="0"></a><br><br><a href="http://www.flickr.com/photos/k_vertigo/">More Photos</a>
+</td></tr>
+</tbody></table>
+</td></tr></tbody></table>
+<!-- End of Flickr Badge -->
+
+		</li></ul>
+</div><!-- end id:sidebar -->
+</div><!-- end id:content -->
+</div><!-- end id:container -->
+<div id="footer">
+<p><a href="http://wordpress.com/" rel="generator">Blog at WordPress.com</a>. | Theme: Mistylook by <a href="http://wpthemes.info/" rel="designer">Sadish</a>.</p>
+<br class="clear">
+</div><!-- end id:footer -->
+<script type="text/javascript" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/analytics.js"></script>
+<script type="text/javascript">_amefin.setZoneId(20).track()</script><script src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/analytics" type="text/javascript"></script>
+
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/ga.js" type="text/javascript"></script>
+	
+<script type="text/javascript">
+var wpcomPageTracker = _gat._getTracker("UA-52447-2");
+wpcomPageTracker._setDomainName("none");
+wpcomPageTracker._setAllowLinker(true);
+wpcomPageTracker._initData();
+wpcomPageTracker._trackPageview();
+</script>
+<script type="text/javascript" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/quant.js"></script>
+<script type="text/javascript">_qoptions = { labels:"adt.0,language.en" };_qacct="p-18-mFEk4J448M";quantserve();</script>
+<noscript><p><img src="http://pixel.quantserve.com/pixel/p-18-mFEk4J448M.gif" style="display: none" height="1" width="1" alt="" /></p></noscript>
+<script src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/w.js" type="text/javascript"></script>
+<script type="text/javascript">
+st_go({'blog':'785435','v':'wpcom','user_id':'0','post':'25','subd':'kapilt'});
+ex_go({'crypt':'D6%7C%2CY1mqtiRa%3DV%26%7CQbTtZOw5UrDNB%7E-74y%2Cw2gxh.v7%2FdeIyyB%7C%2Bk%2CMFYido%3Fcv6P_Smz.Y51c%7EMH%5B0alflYUmJ66x%2539nU-%2BQ%5Bm3oV%2FUqiJ%3Fc%2C1jaDYI%269Ko9T75IY7uw3c%3DlSe%2BfF4_vced%256MddVvogBDnFWj9%7EAqEYUYw%26Y%7ClfBOZRycP2vi9-pa2-2KWJEJy4.uy%7CVs_d'});
+addLoadEvent(function(){linktracker_init('785435',25);});
+</script><img id="wpstats" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/g.gif" alt=""><img id="wpstats2" src="Viewing%20Large%20Images%20with%20Seadragon%20and%20Pythonhtml_files/g_002.gif" alt="" style="display: none;">
+
+</body></html>
\ No newline at end of file
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/0491830b8e929f46ffba2b9e3920b307.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/0491830b8e929f46ffba2b9e3920b307.png
new file mode 100644
index 0000000..45a96b5
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/0491830b8e929f46ffba2b9e3920b307.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/06a26aadf9c62b93ec5d5d0154f6e3cf.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/06a26aadf9c62b93ec5d5d0154f6e3cf.png
new file mode 100644
index 0000000..8353a05
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/06a26aadf9c62b93ec5d5d0154f6e3cf.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/139f37ae067ee7e473f71e849f63e82f.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/139f37ae067ee7e473f71e849f63e82f.png
new file mode 100644
index 0000000..e0c0ddc
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/139f37ae067ee7e473f71e849f63e82f.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017463815_e69a2d1edd_t.jpg b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017463815_e69a2d1edd_t.jpg
new file mode 100644
index 0000000..23e95f0
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017463815_e69a2d1edd_t.jpg
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017467267_31165b2faa_t.jpg b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017467267_31165b2faa_t.jpg
new file mode 100644
index 0000000..a123b27
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3017467267_31165b2faa_t.jpg
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3018292436_4472ec4cb4_t.jpg b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3018292436_4472ec4cb4_t.jpg
new file mode 100644
index 0000000..f9252fa
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/3018292436_4472ec4cb4_t.jpg
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/317094104136ef2e6487bf5a61fb8217.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/317094104136ef2e6487bf5a61fb8217.png
new file mode 100644
index 0000000..8f85df0
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/317094104136ef2e6487bf5a61fb8217.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/34e36e0508f23947d839a8bff4d413cd.jpeg b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/34e36e0508f23947d839a8bff4d413cd.jpeg
new file mode 100644
index 0000000..2acf784
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/34e36e0508f23947d839a8bff4d413cd.jpeg
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/51add0b18aa2a784ee43ecd046b99724.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/51add0b18aa2a784ee43ecd046b99724.png
new file mode 100644
index 0000000..6922618
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/51add0b18aa2a784ee43ecd046b99724.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/55ebe3141eb327cb93a05159fd50d70a.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/55ebe3141eb327cb93a05159fd50d70a.png
new file mode 100644
index 0000000..9f5a04b
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/55ebe3141eb327cb93a05159fd50d70a.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/7e5c476f7ed6fcbb67eee738e304f066.jpeg b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/7e5c476f7ed6fcbb67eee738e304f066.jpeg
new file mode 100644
index 0000000..214e860
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/7e5c476f7ed6fcbb67eee738e304f066.jpeg
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/81955202e1a0524d206bd3f7b3967065.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/81955202e1a0524d206bd3f7b3967065.png
new file mode 100644
index 0000000..ea58992
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/81955202e1a0524d206bd3f7b3967065.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/analytics.js b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/analytics.js
new file mode 100644
index 0000000..3aa054e
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/analytics.js
@@ -0,0 +1,59 @@
+var _amefin = {
+  pingImage: null,
+  setZoneId: function(zoneId)
+  {
+    this.zoneId = zoneId;
+    return this;
+  },
+  shouldUseCurrent: false,
+  setUseCurrent: function(shouldUseCurrent)
+  {
+    this.shouldUseCurrent = shouldUseCurrent;
+    return this;
+  },
+  searchToUse: null,
+  useSearch: function(searchToUse)
+  {
+    this.searchToUse = searchToUse;
+    return this;
+  },
+  isSearchReferrer: function()
+  {
+    var engines = ["google", "search\\.yahoo", "search\\.msn", "search\\.live", "search\\.aol", "ask\\.com", "searchservice\\.myspace", "facebook"];
+
+    for(var i = 0; i < engines.length; i++)
+    {
+      var regexString = "^http:\\/\\/(www\\.)?" + engines[i];
+      if(engines[i] != "ask\\.com")
+      {
+        regexString += "\\.";
+      }
+      var regex = new RegExp(regexString, "i");
+      if(regex.test(this.shouldUseCurrent ? document.URL : document.referrer))
+      {
+        return true;
+      }
+    }
+    return false;
+  },
+  track: function()
+  {
+    if(this.searchToUse || this.isSearchReferrer())
+    {
+      document.write("<script src='http://amefin.com/analytics?url=" + encodeURIComponent(document.URL) + "&referrer=" + encodeURIComponent(document.referrer) + "&search=" + this.searchToUse + "&shouldUseCurrent=" + this.shouldUseCurrent + "&zoneId=" + this.zoneId + "&width=" + screen.width + "&height=" + screen.height + "' type='text/javascript'></script>");
+    }
+    return this;
+  },
+  druvoid: function()
+  {
+    return this;
+  },
+  hit_pixel: function(slot, url)
+  {
+    var pix = new Image(1,1);
+    pix.alt = '';
+    pix.src = url;
+    pix.onload = function () {_amefin.druvoid();};
+    this[slot] = pix;
+  }
+}
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/ba08a1813ff5e44f655ee9ea58d1c992.png b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/ba08a1813ff5e44f655ee9ea58d1c992.png
new file mode 100644
index 0000000..ee06357
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/ba08a1813ff5e44f655ee9ea58d1c992.png
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/comment-reply.js b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/comment-reply.js
new file mode 100644
index 0000000..524f2ed
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/comment-reply.js
@@ -0,0 +1 @@
+addComment={moveForm:function(d,f,i,c){var m=this,a,h=m.I(d),b=m.I(i),l=m.I("cancel-comment-reply-link"),j=m.I("comment_parent"),k=m.I("comment_post_ID");if(!h||!b||!l||!j){return}m.respondId=i;c=c||false;if(!m.I("wp-temp-form-div")){a=document.createElement("div");a.id="wp-temp-form-div";a.style.display="none";b.parentNode.insertBefore(a,b)}h.parentNode.insertBefore(b,h.nextSibling);if(k&&c){k.value=c}j.value=f;l.style.display="";l.onclick=function(){var n=addComment,e=n.I("wp-temp-form-div"),o=n.I(n.respondId);if(!e||!o){return}n.I("comment_parent").value="0";e.parentNode.insertBefore(o,e);e.parentNode.removeChild(e);this.style.display="none";this.onclick=null;return false};try{m.I("comment").focus()}catch(g){}return false},I:function(a){return document.getElementById(a)}};
\ No newline at end of file
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/g.gif b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/g.gif
new file mode 100644
index 0000000..69a1627
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/g.gif
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/g_002.gif b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/g_002.gif
new file mode 100644
index 0000000..69a1627
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/g_002.gif
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/ga.js b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/ga.js
new file mode 100644
index 0000000..caaf7e8
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/ga.js
@@ -0,0 +1,41 @@
+var _gat=new Object({c:"length",lb:"4.3",m:"cookie",b:undefined,cb:function(d,a){this.zb=d;this.Nb=a},r:"__utma=",W:"__utmb=",ma:"__utmc=",Ta:"__utmk=",na:"__utmv=",oa:"__utmx=",Sa:"GASO=",X:"__utmz=",lc:"http://www.google-analytics.com/__utm.gif",mc:"https://ssl.google-analytics.com/__utm.gif",Wa:"utmcid=",Ya:"utmcsr=",$a:"utmgclid=",Ua:"utmccn=",Xa:"utmcmd=",Za:"utmctr=",Va:"utmcct=",Hb:false,_gasoDomain:undefined,_gasoCPath:undefined,e:window,a:document,k:navigator,t:function(d){var a=1,c=0,h,
+o;if(!_gat.q(d)){a=0;for(h=d[_gat.c]-1;h>=0;h--){o=d.charCodeAt(h);a=(a<<6&268435455)+o+(o<<14);c=a&266338304;a=c!=0?a^c>>21:a}}return a},C:function(d,a,c){var h=_gat,o="-",k,l,s=h.q;if(!s(d)&&!s(a)&&!s(c)){k=h.w(d,a);if(k>-1){l=d.indexOf(c,k);if(l<0)l=d[h.c];o=h.F(d,k+h.w(a,"=")+1,l)}}return o},Ea:function(d){var a=false,c=0,h,o;if(!_gat.q(d)){a=true;for(h=0;h<d[_gat.c];h++){o=d.charAt(h);c+="."==o?1:0;a=a&&c<=1&&(0==h&&"-"==o||_gat.P(".0123456789",o))}}return a},d:function(d,a){var c=encodeURIComponent;
+return c instanceof Function?(a?encodeURI(d):c(d)):escape(d)},J:function(d,a){var c=decodeURIComponent,h;d=d.split("+").join(" ");if(c instanceof Function)try{h=a?decodeURI(d):c(d)}catch(o){h=unescape(d)}else h=unescape(d);return h},Db:function(d){return d&&d.hash?_gat.F(d.href,_gat.w(d.href,"#")):""},q:function(d){return _gat.b==d||"-"==d||""==d},Lb:function(d){return d[_gat.c]>0&&_gat.P(" \n\r\t",d)},P:function(d,a){return _gat.w(d,a)>-1},h:function(d,a){d[d[_gat.c]]=a},T:function(d){return d.toLowerCase()},
+z:function(d,a){return d.split(a)},w:function(d,a){return d.indexOf(a)},F:function(d,a,c){c=_gat.b==c?d[_gat.c]:c;return d.substring(a,c)},uc:function(){var d=_gat.b,a=window;if(a&&a.gaGlobal&&a.gaGlobal.hid)d=a.gaGlobal.hid;else{d=Math.round(Math.random()*2147483647);a.gaGlobal=a.gaGlobal?a.gaGlobal:{};a.gaGlobal.hid=d}return d},wa:function(){return Math.round(Math.random()*2147483647)},Gc:function(){return(_gat.wa()^_gat.vc())*2147483647},vc:function(){var d=_gat.k,a=_gat.a,c=_gat.e,h=a[_gat.m]?
+a[_gat.m]:"",o=c.history[_gat.c],k,l,s=[d.appName,d.version,d.language?d.language:d.browserLanguage,d.platform,d.userAgent,d.javaEnabled()?1:0].join("");if(c.screen)s+=c.screen.width+"x"+c.screen.height+c.screen.colorDepth;else if(c.java){l=java.awt.Toolkit.getDefaultToolkit().getScreenSize();s+=l.screen.width+"x"+l.screen.height}s+=h;s+=a.referrer?a.referrer:"";k=s[_gat.c];while(o>0)s+=o--^k++;return _gat.t(s)}});_gat.hc=function(){var d=this,a=_gat.cb;function c(h,o){return new a(h,o)}d.db="utm_campaign";d.eb="utm_content";d.fb="utm_id";d.gb="utm_medium";d.hb="utm_nooverride";d.ib="utm_source";d.jb="utm_term";d.kb="gclid";d.pa=0;d.I=0;d.wb="15768000";d.Tb="1800";d.ea=[];d.ga=[];d.Ic="cse";d.Gb="q";d.ab="google";d.fa=[c(d.ab,d.Gb),c("yahoo","p"),c("msn","q"),c("aol","query"),c("aol","encquery"),c("lycos","query"),c("ask","q"),c("altavista","q"),c("netscape","query"),c("cnn","query"),c("looksmart","qt"),c("about",
+"terms"),c("mamma","query"),c("alltheweb","q"),c("gigablast","q"),c("voila","rdata"),c("virgilio","qs"),c("live","q"),c("baidu","wd"),c("alice","qs"),c("yandex","text"),c("najdi","q"),c("aol","q"),c("club-internet","query"),c("mama","query"),c("seznam","q"),c("search","q"),c("wp","szukaj"),c("onet","qt"),c("netsprint","q"),c("google.interia","q"),c("szukacz","q"),c("yam","k"),c("pchome","q"),c("kvasir","searchExpr"),c("sesam","q"),c("ozu","q"),c("terra","query"),c("nostrum","query"),c("mynet","q"),
+c("ekolay","q"),c("search.ilse","search_for")];d.B=undefined;d.Kb=false;d.p="/";d.ha=100;d.Da="/__utm.gif";d.ta=1;d.ua=1;d.G="|";d.sa=1;d.qa=1;d.pb=1;d.g="auto";d.D=1;d.Ga=1000;d.Yc=10;d.nc=10;d.Zc=0.2};_gat.Y=function(d,a){var c,h,o,k,l,s,q,f=this,n=_gat,w=n.q,x=n.c,g,z=a;f.a=d;function B(i){var b=i instanceof Array?i.join("."):"";return w(b)?"-":b}function A(i,b){var e=[],j;if(!w(i)){e=n.z(i,".");if(b)for(j=0;j<e[x];j++)if(!n.Ea(e[j]))e[j]="-"}return e}function p(){return u(63072000000)}function u(i){var b=new Date,e=new Date(b.getTime()+i);return"expires="+e.toGMTString()+"; "}function m(i,b){f.a[n.m]=i+"; path="+z.p+"; "+b+f.Cc()}function r(i,b,e){var j=f.V,t,v;for(t=0;t<j[x];t++){v=j[t][0];
+v+=w(b)?b:b+j[t][4];j[t][2](n.C(i,v,e))}}f.Jb=function(){return n.b==g||g==f.t()};f.Ba=function(){return l?l:"-"};f.Wb=function(i){l=i};f.Ma=function(i){g=n.Ea(i)?i*1:"-"};f.Aa=function(){return B(s)};f.Na=function(i){s=A(i)};f.Hc=function(){return g?g:"-"};f.Cc=function(){return w(z.g)?"":"domain="+z.g+";"};f.ya=function(){return B(c)};f.Ub=function(i){c=A(i,1)};f.K=function(){return B(h)};f.La=function(i){h=A(i,1)};f.za=function(){return B(o)};f.Vb=function(i){o=A(i,1)};f.Ca=function(){return B(k)};
+f.Xb=function(i){k=A(i);for(var b=0;b<k[x];b++)if(b<4&&!n.Ea(k[b]))k[b]="-"};f.Dc=function(){return q};f.Uc=function(i){q=i};f.pc=function(){c=[];h=[];o=[];k=[];l=n.b;s=[];g=n.b};f.t=function(){var i="",b;for(b=0;b<f.V[x];b++)i+=f.V[b][1]();return n.t(i)};f.Ha=function(i){var b=f.a[n.m],e=false;if(b){r(b,i,";");f.Ma(f.t());e=true}return e};f.Rc=function(i){r(i,"","&");f.Ma(n.C(i,n.Ta,"&"))};f.Wc=function(){var i=f.V,b=[],e;for(e=0;e<i[x];e++)n.h(b,i[e][0]+i[e][1]());n.h(b,n.Ta+f.t());return b.join("&")};
+f.bd=function(i,b){var e=f.V,j=z.p,t;f.Ha(i);z.p=b;for(t=0;t<e[x];t++)if(!w(e[t][1]()))e[t][3]();z.p=j};f.dc=function(){m(n.r+f.ya(),p())};f.Pa=function(){m(n.W+f.K(),u(z.Tb*1000))};f.ec=function(){m(n.ma+f.za(),"")};f.Ra=function(){m(n.X+f.Ca(),u(z.wb*1000))};f.fc=function(){m(n.oa+f.Ba(),p())};f.Qa=function(){m(n.na+f.Aa(),p())};f.cd=function(){m(n.Sa+f.Dc(),"")};f.V=[[n.r,f.ya,f.Ub,f.dc,"."],[n.W,f.K,f.La,f.Pa,""],[n.ma,f.za,f.Vb,f.ec,""],[n.oa,f.Ba,f.Wb,f.fc,""],[n.X,f.Ca,f.Xb,f.Ra,"."],[n.na,
+f.Aa,f.Na,f.Qa,"."]]};_gat.jc=function(d){var a=this,c=_gat,h=d,o,k=function(l){var s=(new Date).getTime(),q;q=(s-l[3])*(h.Zc/1000);if(q>=1){l[2]=Math.min(Math.floor(l[2]*1+q),h.nc);l[3]=s}return l};a.O=function(l,s,q,f,n,w,x){var g,z=h.D,B=q.location;if(!o)o=new c.Y(q,h);o.Ha(f);g=c.z(o.K(),".");if(g[1]<500||n){if(w)g=k(g);if(n||!w||g[2]>=1){if(!n&&w)g[2]=g[2]*1-1;g[1]=g[1]*1+1;l="?utmwv="+_gat.lb+"&utmn="+c.wa()+(c.q(B.hostname)?"":"&utmhn="+c.d(B.hostname))+(h.ha==100?"":"&utmsp="+c.d(h.ha))+l;if(0==z||2==z){var A=
+new Image(1,1);A.src=h.Da+l;var p=2==z?function(){}:x||function(){};A.onload=p}if(1==z||2==z){var u=new Image(1,1);u.src=("https:"==B.protocol?c.mc:c.lc)+l+"&utmac="+s+"&utmcc="+a.wc(q,f);u.onload=x||function(){}}}}o.La(g.join("."));o.Pa()};a.wc=function(l,s){var q=[],f=[c.r,c.X,c.na,c.oa],n,w=l[c.m],x;for(n=0;n<f[c.c];n++){x=c.C(w,f[n]+s,";");if(!c.q(x))c.h(q,f[n]+x+";")}return c.d(q.join("+"))}};_gat.i=function(){this.la=[]};_gat.i.bb=function(d,a,c,h,o,k){var l=this;l.cc=d;l.Oa=a;l.L=c;l.sb=h;l.Pb=o;l.Qb=k};_gat.i.bb.prototype.S=function(){var d=this,a=_gat.d;return"&"+["utmt=item","utmtid="+a(d.cc),"utmipc="+a(d.Oa),"utmipn="+a(d.L),"utmiva="+a(d.sb),"utmipr="+a(d.Pb),"utmiqt="+a(d.Qb)].join("&")};_gat.i.$=function(d,a,c,h,o,k,l,s){var q=this;q.v=d;q.ob=a;q.bc=c;q.ac=h;q.Yb=o;q.ub=k;q.$b=l;q.xb=s;q.ca=[]};_gat.i.$.prototype.mb=function(d,a,c,h,o){var k=this,l=k.Eb(d),s=k.v,q=_gat;if(q.b==
+l)q.h(k.ca,new q.i.bb(s,d,a,c,h,o));else{l.cc=s;l.Oa=d;l.L=a;l.sb=c;l.Pb=h;l.Qb=o}};_gat.i.$.prototype.Eb=function(d){var a,c=this.ca,h;for(h=0;h<c[_gat.c];h++)a=d==c[h].Oa?c[h]:a;return a};_gat.i.$.prototype.S=function(){var d=this,a=_gat.d;return"&"+["utmt=tran","utmtid="+a(d.v),"utmtst="+a(d.ob),"utmtto="+a(d.bc),"utmttx="+a(d.ac),"utmtsp="+a(d.Yb),"utmtci="+a(d.ub),"utmtrg="+a(d.$b),"utmtco="+a(d.xb)].join("&")};_gat.i.prototype.nb=function(d,a,c,h,o,k,l,s){var q=this,f=_gat,n=q.xa(d);if(f.b==
+n){n=new f.i.$(d,a,c,h,o,k,l,s);f.h(q.la,n)}else{n.ob=a;n.bc=c;n.ac=h;n.Yb=o;n.ub=k;n.$b=l;n.xb=s}return n};_gat.i.prototype.xa=function(d){var a,c=this.la,h;for(h=0;h<c[_gat.c];h++)a=d==c[h].v?c[h]:a;return a};_gat.gc=function(d){var a=this,c="-",h=_gat,o=d;a.Ja=screen;a.qb=!self.screen&&self.java?java.awt.Toolkit.getDefaultToolkit():h.b;a.a=document;a.e=window;a.k=navigator;a.Ka=c;a.Sb=c;a.tb=c;a.Ob=c;a.Mb=1;a.Bb=c;function k(){var l,s,q,f,n="ShockwaveFlash",w="$version",x=a.k?a.k.plugins:h.b;if(x&&x[h.c]>0)for(l=0;l<x[h.c]&&!q;l++){s=x[l];if(h.P(s.name,"Shockwave Flash"))q=h.z(s.description,"Shockwave Flash ")[1]}else{n=n+"."+n;try{f=new ActiveXObject(n+".7");q=f.GetVariable(w)}catch(g){}if(!q)try{f=
+new ActiveXObject(n+".6");q="WIN 6,0,21,0";f.AllowScriptAccess="always";q=f.GetVariable(w)}catch(z){}if(!q)try{f=new ActiveXObject(n);q=f.GetVariable(w)}catch(z){}if(q){q=h.z(h.z(q," ")[1],",");q=q[0]+"."+q[1]+" r"+q[2]}}return q?q:c}a.xc=function(){var l;if(self.screen){a.Ka=a.Ja.width+"x"+a.Ja.height;a.Sb=a.Ja.colorDepth+"-bit"}else if(a.qb)try{l=a.qb.getScreenSize();a.Ka=l.width+"x"+l.height}catch(s){}a.Ob=h.T(a.k&&a.k.language?a.k.language:(a.k&&a.k.browserLanguage?a.k.browserLanguage:c));a.Mb=
+a.k&&a.k.javaEnabled()?1:0;a.Bb=o?k():c;a.tb=h.d(a.a.characterSet?a.a.characterSet:(a.a.charset?a.a.charset:c))};a.Xc=function(){return"&"+["utmcs="+h.d(a.tb),"utmsr="+a.Ka,"utmsc="+a.Sb,"utmul="+a.Ob,"utmje="+a.Mb,"utmfl="+h.d(a.Bb)].join("&")}};_gat.n=function(d,a,c,h,o){var k=this,l=_gat,s=l.q,q=l.b,f=l.P,n=l.C,w=l.T,x=l.z,g=l.c;k.a=a;k.f=d;k.Rb=c;k.ja=h;k.o=o;function z(p){return s(p)||"0"==p||!f(p,"://")}function B(p){var u="";p=w(x(p,"://")[1]);if(f(p,"/")){p=x(p,"/")[1];if(f(p,"?"))u=x(p,"?")[0]}return u}function A(p){var u="";u=w(x(p,"://")[1]);if(f(u,"/"))u=x(u,"/")[0];return u}k.Fc=function(p){var u=k.Fb(),m=k.o;return new l.n.s(n(p,m.fb+"=","&"),n(p,m.ib+"=","&"),n(p,m.kb+"=","&"),k.ba(p,m.db,"(not set)"),k.ba(p,m.gb,"(not set)"),
+k.ba(p,m.jb,u&&!s(u.R)?l.J(u.R):q),k.ba(p,m.eb,q))};k.Ib=function(p){var u=A(p),m=B(p);if(f(u,k.o.ab)){p=x(p,"?").join("&");if(f(p,"&"+k.o.Gb+"="))if(m==k.o.Ic)return true}return false};k.Fb=function(){var p,u,m=k.Rb,r,i,b=k.o.fa;if(z(m)||k.Ib(m))return;p=A(m);for(r=0;r<b[g];r++){i=b[r];if(f(p,w(i.zb))){m=x(m,"?").join("&");if(f(m,"&"+i.Nb+"=")){u=x(m,"&"+i.Nb+"=")[1];if(f(u,"&"))u=x(u,"&")[0];return new l.n.s(q,i.zb,q,"(organic)","organic",u,q)}}}};k.ba=function(p,u,m){var r=n(p,u+"=","&"),i=!s(r)?
+l.J(r):(!s(m)?m:"-");return i};k.Nc=function(p){var u=k.o.ea,m=false,r,i;if(p&&"organic"==p.da){r=w(l.J(p.R));for(i=0;i<u[g];i++)m=m||w(u[i])==r}return m};k.Ec=function(){var p="",u="",m=k.Rb;if(z(m)||k.Ib(m))return;p=w(x(m,"://")[1]);if(f(p,"/")){u=l.F(p,l.w(p,"/"));if(f(u,"?"))u=x(u,"?")[0];p=x(p,"/")[0]}if(0==l.w(p,"www."))p=l.F(p,4);return new l.n.s(q,p,q,"(referral)","referral",q,u)};k.sc=function(p){var u="";if(k.o.pa){u=l.Db(p);u=""!=u?u+"&":u}u+=p.search;return u};k.zc=function(){return new l.n.s(q,
+"(direct)",q,"(direct)","(none)",q,q)};k.Oc=function(p){var u=false,m,r,i=k.o.ga;if(p&&"referral"==p.da){m=w(l.d(p.ia));for(r=0;r<i[g];r++)u=u||f(m,w(i[r]))}return u};k.U=function(p){return q!=p&&p.Fa()};k.yc=function(p,u){var m="",r="-",i,b,e=0,j,t,v=k.f;if(!p)return"";t=k.a[l.m]?k.a[l.m]:"";m=k.sc(k.a.location);if(k.o.I&&p.Jb()){r=p.Ca();if(!s(r)&&!f(r,";")){p.Ra();return""}}r=n(t,l.X+v+".",";");i=k.Fc(m);if(k.U(i)){b=n(m,k.o.hb+"=","&");if("1"==b&&!s(r))return""}if(!k.U(i)){i=k.Fb();if(!s(r)&&
+k.Nc(i))return""}if(!k.U(i)&&u){i=k.Ec();if(!s(r)&&k.Oc(i))return""}if(!k.U(i))if(s(r)&&u)i=k.zc();if(!k.U(i))return"";if(!s(r)){var y=x(r,"."),E=new l.n.s;E.Cb(y.slice(4).join("."));j=w(E.ka())==w(i.ka());e=y[3]*1}if(!j||u){var F=n(t,l.r+v+".",";"),I=F.lastIndexOf("."),G=I>9?l.F(F,I+1)*1:0;e++;G=0==G?1:G;p.Xb([v,k.ja,G,e,i.ka()].join("."));p.Ra();return"&utmcn=1"}else return"&utmcr=1"}};_gat.n.s=function(d,a,c,h,o,k,l){var s=this;s.v=d;s.ia=a;s.ra=c;s.L=h;s.da=o;s.R=k;s.vb=l};_gat.n.s.prototype.ka=
+function(){var d=this,a=_gat,c=[],h=[[a.Wa,d.v],[a.Ya,d.ia],[a.$a,d.ra],[a.Ua,d.L],[a.Xa,d.da],[a.Za,d.R],[a.Va,d.vb]],o,k;if(d.Fa())for(o=0;o<h[a.c];o++)if(!a.q(h[o][1])){k=h[o][1].split("+").join("%20");k=k.split(" ").join("%20");a.h(c,h[o][0]+k)}return c.join("|")};_gat.n.s.prototype.Fa=function(){var d=this,a=_gat.q;return!(a(d.v)&&a(d.ia)&&a(d.ra))};_gat.n.s.prototype.Cb=function(d){var a=this,c=_gat,h=function(o){return c.J(c.C(d,o,"|"))};a.v=h(c.Wa);a.ia=h(c.Ya);a.ra=h(c.$a);a.L=h(c.Ua);a.da=
+h(c.Xa);a.R=h(c.Za);a.vb=h(c.Va)};_gat.Z=function(){var d=this,a=_gat,c={},h="k",o="v",k=[h,o],l="(",s=")",q="*",f="!",n="'",w={};w[n]="'0";w[s]="'1";w[q]="'2";w[f]="'3";var x=1;function g(m,r,i,b){if(a.b==c[m])c[m]={};if(a.b==c[m][r])c[m][r]=[];c[m][r][i]=b}function z(m,r,i){return a.b!=c[m]&&a.b!=c[m][r]?c[m][r][i]:a.b}function B(m,r){if(a.b!=c[m]&&a.b!=c[m][r]){c[m][r]=a.b;var i=true,b;for(b=0;b<k[a.c];b++)if(a.b!=c[m][k[b]]){i=false;break}if(i)c[m]=a.b}}function A(m){var r="",i=false,b,e;for(b=0;b<k[a.c];b++){e=m[k[b]];if(a.b!=
+e){if(i)r+=k[b];r+=p(e);i=false}else i=true}return r}function p(m){var r=[],i,b;for(b=0;b<m[a.c];b++)if(a.b!=m[b]){i="";if(b!=x&&a.b==m[b-1]){i+=b.toString();i+=f}i+=u(m[b]);a.h(r,i)}return l+r.join(q)+s}function u(m){var r="",i,b,e;for(i=0;i<m[a.c];i++){b=m.charAt(i);e=w[b];r+=a.b!=e?e:b}return r}d.Kc=function(m){return a.b!=c[m]};d.N=function(){var m=[],r;for(r in c)if(a.b!=c[r])a.h(m,r.toString()+A(c[r]));return m.join("")};d.Sc=function(m){if(m==a.b)return d.N();var r=[m.N()],i;for(i in c)if(a.b!=
+c[i]&&!m.Kc(i))a.h(r,i.toString()+A(c[i]));return r.join("")};d._setKey=function(m,r,i){if(typeof i!="string")return false;g(m,h,r,i);return true};d._setValue=function(m,r,i){if(typeof i!="number"&&(a.b==Number||!(i instanceof Number)))return false;if(Math.round(i)!=i||i==NaN||i==Infinity)return false;g(m,o,r,i.toString());return true};d._getKey=function(m,r){return z(m,h,r)};d._getValue=function(m,r){return z(m,o,r)};d._clearKey=function(m){B(m,h)};d._clearValue=function(m){B(m,o)}};_gat.ic=function(d,a){var c=this;c.jd=a;c.Pc=d;c._trackEvent=function(h,o,k){return a._trackEvent(c.Pc,h,o,k)}};_gat.kc=function(d){var a=this,c=_gat,h=c.b,o=c.q,k=c.w,l=c.F,s=c.C,q=c.P,f=c.z,n="location",w=c.c,x=h,g=new c.hc,z=false;a.a=document;a.e=window;a.ja=Math.round((new Date).getTime()/1000);a.H=d;a.yb=a.a.referrer;a.va=h;a.j=h;a.A=h;a.M=false;a.aa=h;a.rb="";a.l=h;a.Ab=h;a.f=h;a.u=h;function B(){if("auto"==g.g){var b=a.a.domain;if("www."==l(b,0,4))b=l(b,4);g.g=b}g.g=c.T(g.g)}function A(){var b=g.g,e=k(b,"www.google.")*k(b,".google.")*k(b,"google.");return e||"/"!=g.p||k(b,"google.org")>-1}function p(b,
+e,j){if(o(b)||o(e)||o(j))return"-";var t=s(b,c.r+a.f+".",e),v;if(!o(t)){v=f(t,".");v[5]=v[5]?v[5]*1+1:1;v[3]=v[4];v[4]=j;t=v.join(".")}return t}function u(){return"file:"!=a.a[n].protocol&&A()}function m(b){if(!b||""==b)return"";while(c.Lb(b.charAt(0)))b=l(b,1);while(c.Lb(b.charAt(b[w]-1)))b=l(b,0,b[w]-1);return b}function r(b,e,j){if(!o(b())){e(c.J(b()));if(!q(b(),";"))j()}}function i(b){var e,j=""!=b&&a.a[n].host!=b;if(j)for(e=0;e<g.B[w];e++)j=j&&k(c.T(b),c.T(g.B[e]))==-1;return j}a.Bc=function(){if(!g.g||
+""==g.g||"none"==g.g){g.g="";return 1}B();return g.pb?c.t(g.g):1};a.tc=function(b,e){if(o(b))b="-";else{e+=g.p&&"/"!=g.p?g.p:"";var j=k(b,e);b=j>=0&&j<=8?"0":("["==b.charAt(0)&&"]"==b.charAt(b[w]-1)?"-":b)}return b};a.Ia=function(b){var e="",j=a.a;e+=a.aa?a.aa.Xc():"";e+=g.qa?a.rb:"";e+=g.ta&&!o(j.title)?"&utmdt="+c.d(j.title):"";e+="&utmhid="+c.uc()+"&utmr="+a.va+"&utmp="+a.Tc(b);return e};a.Tc=function(b){var e=a.a[n];b=h!=b&&""!=b?c.d(b,true):c.d(e.pathname+unescape(e.search),true);return b};a.$c=
+function(b){if(a.Q()){var e="";if(a.l!=h&&a.l.N().length>0)e+="&utme="+c.d(a.l.N());e+=a.Ia(b);x.O(e,a.H,a.a,a.f)}};a.qc=function(){var b=new c.Y(a.a,g);return b.Ha(a.f)?b.Wc():h};a._getLinkerUrl=function(b,e){var j=f(b,"#"),t=b,v=a.qc();if(v)if(e&&1>=j[w])t+="#"+v;else if(!e||1>=j[w])if(1>=j[w])t+=(q(b,"?")?"&":"?")+v;else t=j[0]+(q(b,"?")?"&":"?")+v+"#"+j[1];return t};a.Zb=function(){var b;if(a.A&&a.A[w]>=10&&!q(a.A,"=")){a.u.Uc(a.A);a.u.cd();c._gasoDomain=g.g;c._gasoCPath=g.p;b=a.a.createElement("script");
+b.type="text/javascript";b.id="_gasojs";b.src="https://www.google.com/analytics/reporting/overlay_js?gaso="+a.A+"&"+c.wa();a.a.getElementsByTagName("head")[0].appendChild(b)}};a.Jc=function(){var b=a.a[c.m],e=a.ja,j=a.u,t=a.f+"",v=a.e,y=v?v.gaGlobal:h,E,F=q(b,c.r+t+"."),I=q(b,c.W+t),G=q(b,c.ma+t),C,D=[],H="",K=false,J;b=o(b)?"":b;if(g.I){E=c.Db(a.a[n]);if(g.pa&&!o(E))H=E+"&";H+=a.a[n].search;if(!o(H)&&q(H,c.r)){j.Rc(H);if(!j.Jb())j.pc();C=j.ya()}r(j.Ba,j.Wb,j.fc);r(j.Aa,j.Na,j.Qa)}if(!o(C))if(o(j.K())||
+o(j.za())){C=p(H,"&",e);a.M=true}else{D=f(j.K(),".");t=D[0]}else if(F)if(!I||!G){C=p(b,";",e);a.M=true}else{C=s(b,c.r+t+".",";");D=f(s(b,c.W+t,";"),".")}else{C=[t,c.Gc(),e,e,e,1].join(".");a.M=true;K=true}C=f(C,".");if(v&&y&&y.dh==t){C[4]=y.sid?y.sid:C[4];if(K){C[3]=y.sid?y.sid:C[4];if(y.vid){J=f(y.vid,".");C[1]=J[0];C[2]=J[1]}}}j.Ub(C.join("."));D[0]=t;D[1]=D[1]?D[1]:0;D[2]=undefined!=D[2]?D[2]:g.Yc;D[3]=D[3]?D[3]:C[4];j.La(D.join("."));j.Vb(t);if(!o(j.Hc()))j.Ma(j.t());j.dc();j.Pa();j.ec()};a.Lc=
+function(){x=new c.jc(g)};a._initData=function(){var b;if(!z){a.Lc();a.f=a.Bc();a.u=new c.Y(a.a,g)}if(u())a.Jc();if(!z){if(u()){a.va=a.tc(a.Ac(),a.a.domain);if(g.sa){a.aa=new c.gc(g.ua);a.aa.xc()}if(g.qa){b=new c.n(a.f,a.a,a.va,a.ja,g);a.rb=b.yc(a.u,a.M)}}a.l=new c.Z;a.Ab=new c.Z;z=true}if(!c.Hb)a.Mc()};a._visitCode=function(){a._initData();var b=s(a.a[c.m],c.r+a.f+".",";"),e=f(b,".");return e[w]<4?"":e[1]};a._cookiePathCopy=function(b){a._initData();if(a.u)a.u.bd(a.f,b)};a.Mc=function(){var b=a.a[n].hash,
+e;e=b&&""!=b&&0==k(b,"#gaso=")?s(b,"gaso=","&"):s(a.a[c.m],c.Sa,";");if(e[w]>=10){a.A=e;if(a.e.addEventListener)a.e.addEventListener("load",a.Zb,false);else a.e.attachEvent("onload",a.Zb)}c.Hb=true};a.Q=function(){return a._visitCode()%10000<g.ha*100};a.Vc=function(){var b,e,j=a.a.links;if(!g.Kb){var t=a.a.domain;if("www."==l(t,0,4))t=l(t,4);g.B.push("."+t)}for(b=0;b<j[w]&&(g.Ga==-1||b<g.Ga);b++){e=j[b];if(i(e.host))if(!e.gatcOnclick){e.gatcOnclick=e.onclick?e.onclick:a.Qc;e.onclick=function(v){var y=
+!this.target||this.target=="_self"||this.target=="_top"||this.target=="_parent";y=y&&!a.oc(v);a.ad(v,this,y);return y?false:(this.gatcOnclick?this.gatcOnclick(v):true)}}}};a.Qc=function(){};a._trackPageview=function(b){if(u()){a._initData();if(g.B)a.Vc();a.$c(b);a.M=false}};a._trackTrans=function(){var b=a.f,e=[],j,t,v,y;a._initData();if(a.j&&a.Q()){for(j=0;j<a.j.la[w];j++){t=a.j.la[j];c.h(e,t.S());for(v=0;v<t.ca[w];v++)c.h(e,t.ca[v].S())}for(y=0;y<e[w];y++)x.O(e[y],a.H,a.a,b,true)}};a._setTrans=
+function(){var b=a.a,e,j,t,v,y=b.getElementById?b.getElementById("utmtrans"):(b.utmform&&b.utmform.utmtrans?b.utmform.utmtrans:h);a._initData();if(y&&y.value){a.j=new c.i;v=f(y.value,"UTM:");g.G=!g.G||""==g.G?"|":g.G;for(e=0;e<v[w];e++){v[e]=m(v[e]);j=f(v[e],g.G);for(t=0;t<j[w];t++)j[t]=m(j[t]);if("T"==j[0])a._addTrans(j[1],j[2],j[3],j[4],j[5],j[6],j[7],j[8]);else if("I"==j[0])a._addItem(j[1],j[2],j[3],j[4],j[5],j[6])}}};a._addTrans=function(b,e,j,t,v,y,E,F){a.j=a.j?a.j:new c.i;return a.j.nb(b,e,
+j,t,v,y,E,F)};a._addItem=function(b,e,j,t,v,y){var E;a.j=a.j?a.j:new c.i;E=a.j.xa(b);if(!E)E=a._addTrans(b,"","","","","","","");E.mb(e,j,t,v,y)};a._setVar=function(b){if(b&&""!=b&&A()){a._initData();var e=new c.Y(a.a,g),j=a.f;e.Na(j+"."+c.d(b));e.Qa();if(a.Q())x.O("&utmt=var",a.H,a.a,a.f)}};a._link=function(b,e){if(g.I&&b){a._initData();a.a[n].href=a._getLinkerUrl(b,e)}};a._linkByPost=function(b,e){if(g.I&&b&&b.action){a._initData();b.action=a._getLinkerUrl(b.action,e)}};a._setXKey=function(b,e,
+j){a.l._setKey(b,e,j)};a._setXValue=function(b,e,j){a.l._setValue(b,e,j)};a._getXKey=function(b,e){return a.l._getKey(b,e)};a._getXValue=function(b,e){return a.l.getValue(b,e)};a._clearXKey=function(b){a.l._clearKey(b)};a._clearXValue=function(b){a.l._clearValue(b)};a._createXObj=function(){a._initData();return new c.Z};a._sendXEvent=function(b){var e="";a._initData();if(a.Q()){e+="&utmt=event&utme="+c.d(a.l.Sc(b))+a.Ia();x.O(e,a.H,a.a,a.f,false,true)}};a._createEventTracker=function(b){a._initData();
+return new c.ic(b,a)};a._trackEvent=function(b,e,j,t){var v=true,y=a.Ab;if(h!=b&&h!=e&&""!=b&&""!=e){y._clearKey(5);y._clearValue(5);v=y._setKey(5,1,b)?v:false;v=y._setKey(5,2,e)?v:false;v=h==j||y._setKey(5,3,j)?v:false;v=h==t||y._setValue(5,1,t)?v:false;if(v)a._sendXEvent(y)}else v=false;return v};a.ad=function(b,e,j){a._initData();if(a.Q()){var t=new c.Z;t._setKey(6,1,e.href);var v=j?function(){a.rc(b,e)}:undefined;x.O("&utmt=event&utme="+c.d(t.N())+a.Ia(),a.H,a.a,a.f,false,true,v)}};a.rc=function(b,
+e){if(!b)b=a.e.event;var j=true;if(e.gatcOnclick)j=e.gatcOnclick(b);if(j||typeof j=="undefined")if(!e.target||e.target=="_self")a.e.location=e.href;else if(e.target=="_top")a.e.top.document.location=e.href;else if(e.target=="_parent")a.e.parent.document.location=e.href};a.oc=function(b){if(!b)b=a.e.event;var e=b.shiftKey||b.ctrlKey||b.altKey;if(!e)if(b.modifiers&&a.e.Event)e=b.modifiers&a.e.Event.CONTROL_MASK||b.modifiers&a.e.Event.SHIFT_MASK||b.modifiers&a.e.Event.ALT_MASK;return e};a._setDomainName=
+function(b){g.g=b};a.dd=function(){return g.g};a._addOrganic=function(b,e){c.h(g.fa,new c.cb(b,e))};a._clearOrganic=function(){g.fa=[]};a.hd=function(){return g.fa};a._addIgnoredOrganic=function(b){c.h(g.ea,b)};a._clearIgnoredOrganic=function(){g.ea=[]};a.ed=function(){return g.ea};a._addIgnoredRef=function(b){c.h(g.ga,b)};a._clearIgnoredRef=function(){g.ga=[]};a.fd=function(){return g.ga};a._setAllowHash=function(b){g.pb=b?1:0};a._setCampaignTrack=function(b){g.qa=b?1:0};a._setClientInfo=function(b){g.sa=
+b?1:0};a._getClientInfo=function(){return g.sa};a._setCookiePath=function(b){g.p=b};a._setTransactionDelim=function(b){g.G=b};a._setCookieTimeout=function(b){g.wb=b};a._setDetectFlash=function(b){g.ua=b?1:0};a._getDetectFlash=function(){return g.ua};a._setDetectTitle=function(b){g.ta=b?1:0};a._getDetectTitle=function(){return g.ta};a._setLocalGifPath=function(b){g.Da=b};a._getLocalGifPath=function(){return g.Da};a._setLocalServerMode=function(){g.D=0};a._setRemoteServerMode=function(){g.D=1};a._setLocalRemoteServerMode=
+function(){g.D=2};a.gd=function(){return g.D};a._getServiceMode=function(){return g.D};a._setSampleRate=function(b){g.ha=b};a._setSessionTimeout=function(b){g.Tb=b};a._setAllowLinker=function(b){g.I=b?1:0};a._setAllowAnchor=function(b){g.pa=b?1:0};a._setCampNameKey=function(b){g.db=b};a._setCampContentKey=function(b){g.eb=b};a._setCampIdKey=function(b){g.fb=b};a._setCampMediumKey=function(b){g.gb=b};a._setCampNOKey=function(b){g.hb=b};a._setCampSourceKey=function(b){g.ib=b};a._setCampTermKey=function(b){g.jb=
+b};a._setCampCIdKey=function(b){g.kb=b};a._getAccount=function(){return a.H};a._getVersion=function(){return _gat.lb};a.kd=function(b){g.B=[];if(b)g.B=b};a.md=function(b){g.Kb=b};a.ld=function(b){g.Ga=b};a._setReferrerOverride=function(b){a.yb=b};a.Ac=function(){return a.yb}};_gat._getTracker=function(d){var a=new _gat.kc(d);return a};
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/global.css b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/global.css
new file mode 100644
index 0000000..66e2450
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/global.css
@@ -0,0 +1,16 @@
+img.latex { vertical-align: middle; border: none; }
+
+form.contact-form { width: 100%; text-align: left; }
+form.contact-form textarea { width: 96%; }
+form.contact-form label { float: none; display: inline; }
+.form-error, form.contact-form p label.form-error { color: maroon; }
+
+.video-player { margin: auto; padding: 5px; text-align:center; border: 0px;}
+.wpvidavee_title { text-align:left; font-weight:bold; font-family:Tahoma,Arial,sans-serif; font-size:10px; line-height:12px; padding: 2px 5px; }
+.wpvidavee_footer { text-align:right; font-family:Tahoma,Arial,sans-serif; font-size:9px; line-height:11px; padding: 2px 5px; }
+.wpvidavee_footer a { text-decoration: none; }
+.wpvidavee_p { color: red; }
+
+.hidden { display: none; }
+
+.possibly-related { clear: both; }
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_smile.gif b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_smile.gif
new file mode 100644
index 0000000..7b1f6d3
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_smile.gif
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_wink.gif b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_wink.gif
new file mode 100644
index 0000000..d148288
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/icon_wink.gif
Binary files differdiff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/kapilt b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/kapilt
new file mode 100644
index 0000000..95c3039
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/kapilt
@@ -0,0 +1 @@
+if(typeof(Delicious) == 'undefined') Delicious = {}; Delicious.posts = [{"u":"http:\/\/www.loc.gov\/standards\/sru\/specs\/cql.html","d":"CQL: the Contextual Query Language: Specifications (SRU: Search\/Retrieval via URL, Standards, Library of Congress)","t":["rest","search","ils"],"dt":"2009-03-15T14:47:11Z","n":"","a":"kapilt"},{"u":"http:\/\/jangle.org\/","d":"jangle.org","t":["rest","ils"],"dt":"2009-03-15T14:45:48Z","n":"atompub for libraries","a":"kapilt"},{"u":"http:\/\/lericson.blogg.se\/code\/2008\/november\/pylibmc-051.html","d":"pylibmc","t":["python"],"dt":"2009-03-15T02:25:17Z","n":"fast python memcached binding","a":"kapilt"},{"u":"http:\/\/sourceforge.net\/projects\/enomalism","d":"Enomaly Elastic Computing","t":["sysadmin","cloud","virtualization"],"dt":"2009-03-14T17:17:37Z","n":"python virtualization management","a":"kapilt"},{"u":"http:\/\/www.convirture.com\/wiki\/index.php?title=Main_Page","d":"ConVirt","t":["sysadmin","cluster","virtualimage","cloud"],"dt":"2009-03-14T17:17:03Z","n":"python virtualization management gui","a":"kapilt"},{"u":"http:\/\/gate.ac.uk\/","d":"GATE, A General Architecture for Text Engineering","t":["semanticweb","tools","search"],"dt":"2009-03-09T13:51:23Z","n":"","a":"kapilt"},{"u":"http:\/\/www.zeromq.org\/","d":"zeromq: Fastest. Messaging. Ever.","t":["distributed","cluster","messaging","performance"],"dt":"2009-02-23T15:30:48Z","n":"","a":"kapilt"},{"u":"http:\/\/highscalability.com\/numbers-everyone-should-know","d":"AppEngine - Numbers Everyone Should Know","t":["performance","gae"],"dt":"2009-02-23T13:18:16Z","n":"","a":"kapilt"},{"u":"http:\/\/blogs.digitar.com\/jjww\/2009\/01\/rabbits-and-warrens\/","d":"AMQP Server Comparison and Py","t":["python","messaging","erlang"],"dt":"2009-02-22T23:43:29Z","n":"","a":"kapilt"},{"u":"https:\/\/launchpad.net\/txamqp","d":"txAMQP: Twisted AMQP in Launchpad","t":["python","messaging"],"dt":"2009-02-22T23:40:47Z","n":"","a":"kapilt"}];
\ No newline at end of file
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/quant.js b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/quant.js
new file mode 100644
index 0000000..c897e41
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/quant.js
@@ -0,0 +1,92 @@
+function _qcdst(){if(_qctzoff(0)!=_qctzoff(6))return 1;return 0;}
+function _qctzoff(m){
+var d1=new Date(2000,m,1,0,0,0,0);
+var t=d1.toGMTString();
+var d3=new Date(t.substring(0,t.lastIndexOf(" ")-1));
+return d1-d3;
+}
+function _qceuc(s){
+if(typeof(encodeURIComponent)=='function'){return encodeURIComponent(s);}
+else{return escape(s);}
+}
+function _qcrnd(){return Math.round(Math.random()*2147483647);}
+function _qvoid(){return;}
+function _qcgc(n){
+ var v='';
+ var c=document.cookie;if(!c)return v;
+ var i=c.indexOf(n+"=");
+ var len=i+n.length+1;
+ if(i>-1){
+  var end=c.indexOf(";", len);
+  if(end<0)end=c.length;
+  v=c.substring(len,end);
+ }
+ return v;
+}
+function _qcdomain(){
+ var d=document.domain;
+ if(d.substring(0,4)=="www.")d=d.substring(4,d.length);
+ var a=d.split(".");var len=a.length;
+ if(len<3)return d;
+ var e=a[len-1];
+ if(e.length<3)return d;
+ d=a[len-2]+"."+a[len-1];
+ return d;
+}
+function _qcsc(dc){
+ var s="",u=document;var d=_qcdomain();var a=_qcgc("__qca");
+ if(a.length>0){s+=";fpan=0;fpa="+a;}
+ else{
+  u.cookie="__qca="+dc+"; expires=Sun, 18 Jan 2038 00:00:00 GMT; path=/; domain="+d;
+  a=_qcgc("__qca");
+  if(a.length>0){s+=";fpan=1;fpa="+dc;}
+  else{s+=";fpan=u;fpa=";}
+ }
+ var b=_qcgc("__qcb");
+ if(b.length>0){s+=";fpbn=0;fpb="+b;}
+ else{b=_qcrnd();
+  u.cookie="__qcb="+b+"; path=/; domain="+d;
+  b=_qcgc("__qcb");
+  if(b.length>0){s+=";fpbn=1;fpb="+b;}
+  else{s+=";fpbn=u;fpb=";}
+ }
+ return s;
+}
+function quantserve(){
+ var r=_qcrnd();
+ var sr='',qo='',qm='',url='',ref='',je='u',ns='1',media='webpage',event='load';
+ if(typeof _qoptions !="undefined" && _qoptions!=null){
+  for(var k in _qoptions){
+   if(typeof(_qoptions[k])!='string'){continue;}
+   if(k=='qacct'){_qacct=_qoptions[k];}
+   else{qo+=';'+k+'='+_qceuc(_qoptions[k]);}
+   if(k=='media'){media=_qoptions[k];}
+   if(k=='event'){event=_qoptions[k];}
+  }
+  _qoptions=null;
+ }
+ if((typeof _qacct =="undefined")||(_qacct.length==0))return;
+ if(media=='webpage' && event=='load'){
+  if((typeof _qpixelsent !="undefined")&&(_qpixelsent==_qacct))return;
+  _qpixelsent=_qacct;}
+ var ce=(navigator.cookieEnabled)?"1":"0";
+ if(typeof navigator.javaEnabled !='undefined')je=(navigator.javaEnabled())?"1":"0";
+ if(typeof _qmeta !="undefined" && _qmeta!=null){qm=';m='+_qceuc(_qmeta);_qmeta=null;}
+ if(self.screen){sr=screen.width+"x"+screen.height+"x"+screen.colorDepth;}
+ var d=new Date();
+ var dst=_qcdst();
+  
+ 
+
+ var dc="1224977220-93203384-61894334";
+ var qs="http://pixel.quantserve.com";
+ var fp=_qcsc(dc);
+ if(window.location && window.location.href)url=_qceuc(window.location.href);
+ if(window.document && window.document.referrer)ref=_qceuc(window.document.referrer);
+ if(self==top)ns='0';
+ var img=new Image(1,1);
+ img.alt="";
+ img.src=qs+'/pixel'+';r='+r+fp+';ns='+ns+';url='+url+';ref='+ref+';ce='+ce+';je='+je+';sr='+sr+';dc='+dc+';dst='+dst+';et='+d.getTime()+';tzo='+d.getTimezoneOffset()+';a='+_qacct+qo+qm;
+ img.onload=function() {_qvoid();}
+}
+quantserve();
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/style.css b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/style.css
new file mode 100644
index 0000000..131bb08
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/style.css
@@ -0,0 +1,543 @@
+/*  
+Theme Name: MistyLook
+Theme URI: http://wpthemes.info
+Description: A two-column white theme with top-level page navigation and large custom header.
+Version: 3.1-wpcom
+Author: Sadish
+Author URI: http://simpleinside.com/
+Tags: custom header, two columns, fixed width
+*/
+* {
+	padding: 0; 
+	margin:0;
+}
+p {
+	margin: 0.7em 0;
+	line-height:1.6em;
+}
+dl {
+	margin:1em 0;
+}
+dt 
+{
+	font-weight:bold;
+}
+dd 
+{
+	margin:0.5em;
+	padding:0;
+}
+.entry img 
+{
+	background:url(img/shadow.gif) no-repeat right bottom;
+	padding:4px 10px 10px 4px;	
+	border:none;
+	border-top:#eee 1px solid;
+	border-left:#eee 1px solid;	
+}
+.entry a img {
+	border:none;
+	background:none;
+	padding:none;
+	background:url(img/shadow.gif) no-repeat right bottom;
+	padding:4px 10px 10px 4px;	
+	border-top:#eee 1px solid;
+	border-left:#eee 1px solid;	
+}
+.entry .wp-smiley, #wpstats {
+	background: none;
+	border: 0;
+	padding: 0;
+}
+.clear {
+	clear:both;
+	height:20px;
+}
+
+blockquote
+{
+	color:#666;
+	margin: 1em;
+	padding: 0 0 10px 50px;
+	background: url(img/blockquote.gif) no-repeat left top;	
+}
+fieldset 
+{
+	border:none;
+}
+body 
+{
+	background: #f9f9f0;
+	margin: 0; 
+	font: 76%/1.6em verdana, tahoma, arial,  sans-serif; 
+	color: #333; 
+	text-align: center;
+}
+a 
+{
+    text-decoration:none;
+}
+a:link, a:visited {
+	color: #265e15;	
+}
+a:hover, a:active {
+	border-bottom:#963 1px solid;
+}
+h1, h2, h3, h4, h5, h6 
+{
+	font-family:Georgia, Verdana, Arial, Serif;
+}
+
+#container {
+	border: #ccc 1px solid; 
+	background: #fff; 
+	margin: 0 auto; 
+	width: 780px; 	
+	position: relative; 
+	text-align: left;
+}
+#navigation {
+	background: transparent; 
+	margin: 20px auto 0; 
+	overflow: hidden; 
+	width: 760px; 
+	position: relative; 
+	text-align: left;
+	font-family: Trebuchet MS,Tahoma, Verdana, Arial, Serif;
+	letter-spacing:1px;
+}
+ html #navigation {
+	height: 1%;
+}
+#navigation ul li {
+	float: left; 
+	margin: 0 5px 0 0; 
+	list-style-type: none;
+}
+#navigation ul li a {
+	border: #dedede 1px solid; 
+	border-bottom:none;
+	padding: 2px 10px; 
+	display: block; 
+	font-weight:bold;
+	color:#666;		
+	text-decoration: none;
+	background:#ededed;
+}
+#navigation ul li a:hover, #navigation ul li a:active, #navigation ul li.current_page_item a {
+	background: #fff;
+	color: #333;	
+	border: #ccc 1px solid; 
+	border-bottom:none;		
+}
+#navigation ul li.search {
+	font-size: 0.9em; 
+	right: 0; 
+	position: absolute; 
+	top: 0;
+}
+#navigation ul li.search input#searchsubmit {
+	border: #999 1px solid; 
+	font-size: 0.9em; 
+	background: #ddd; 
+	margin: 0 0 0 2px; 
+	color: #265e15; 
+	padding: 2px; 		
+}
+#header {
+	clear: both; 
+	float: left; 
+	margin: 10px 5px; 
+	width: 450px;
+}
+#header h1 
+{
+	font-size:1.8em;
+	margin:10px 0 0 10px;
+	font-variant:small-caps;
+	letter-spacing:1px;		
+}
+#header h1 a {
+	
+	text-decoration:none;	
+	border:none;
+}
+#header h2 
+{
+	margin:5px 0 0 10px;
+	font-size:1em;
+	font-weight:normal;
+	font-family:Tahoma, Verdana, Arial, Serif;
+	letter-spacing:1px;		
+}
+#feedarea {
+	padding:10px 10px 0 0; 
+	float: right; 	
+	text-align: right;
+}
+html #feedarea {
+	padding-top: 10px;
+}
+#feedarea dl dt {
+	display: inline; 
+	margin-right: 5px; 
+	height: 45px;
+}
+#feedarea dl dd {
+	display: inline; 
+	margin-right: 5px; 
+	height: 45px;
+	background:url(img/icon_feed.gif) no-repeat left center;
+	padding-left:16px;
+}
+#headerimage {
+	clear: both; 
+	background: #fff url(img/misty.jpg) no-repeat 0 0;
+	margin: 10px; 
+	color: #fff; 
+	height: 200px;
+}
+ html #headerimage {
+	margin-top: 0;
+}
+#content {
+	margin: 10px 10px 10px 30px; 	
+}
+ html #content {
+	height: 1%;
+}
+#content h3 {
+	font-size: 1.4em; 
+	font-weight:normal;
+	margin: 1em 0 0;
+	color: #265e15;	
+}
+#content h4 {
+	font-size: 1.1em; 
+	margin: 1em 0 0 0;
+}
+#content h5 {
+	font-size: 1em; 
+	margin: 1em 0;
+}
+#content-main ul 
+{
+    margin:1em;
+    padding:0 1em;
+    list-style-image:url(img/bullet.png);
+}
+#content-main ul.asides 
+{
+	margin:0;
+	padding:2em;
+	border-bottom:#ddd 1px dashed;
+}
+#content ol 
+{
+    list-style-type:decimal;
+    margin:2em;
+    padding:0 2em;
+}
+#content-main {
+	float: left; 
+	width: 520px; 
+	margin-right: 20px;
+	overflow: hidden;
+}
+ html #section-index #content-main {
+	margin-right: 20px;
+}
+#content .post 
+{
+	padding:0 0 2em 0;
+	border-bottom:#ddd 1px dashed;
+}
+#content p img.right {
+	float: right;
+	margin:10px 0 0 10px;	
+}
+#content p img.left {
+	float: left; 
+	margin:0 10px 10px 0;
+}
+#content .post h2 
+{
+	font-size: 1.4em; 
+	margin: 1em 0 0;	
+	letter-spacing:1px;
+	font-weight:normal;	
+}
+#content .entry 
+{
+    margin:1em 0;
+    padding-right:1em;    
+}
+
+#content .sticky {
+background: #f7f7f7;
+padding: 0 10px 10px 10px;
+}
+#content .sticky .posttitle h2 {
+padding-top: 10px;
+}
+#content .entry a:link, #content .entry a:visited
+{
+    border-bottom:#963 1px dashed;    
+}
+#content .entry a:hover, #content .entry a:active
+{
+    border-bottom:#963 1px solid;    
+}
+#content .post-info , #content .postmetadata
+{
+	font-size:0.9em;
+	color:#999;
+	margin:0;
+	padding:0;	
+}
+#content .post-info 
+{
+	background:url(img/underline1.jpg) no-repeat left bottom;
+	padding-bottom:12px;	
+}
+#sidebar {
+	float: left; 
+	width: 200px;
+	font-size:0.9em;
+	overflow: hidden;
+}
+#sidebar ul
+{
+	list-style:none;
+	margin:0;
+	padding:0;
+}
+#sidebar ul ul
+{
+	list-style:none;
+	margin:0.5em 0 0 1em;
+}
+#sidebar ul ul ul
+{
+	margin:0 0 0 1em;
+}
+li.sidebox {
+	padding:10px;
+	background: url(img/sideheadtop.gif) #ededed no-repeat left top; 
+	margin-bottom: 10px; 	
+}
+html li.sidebox {
+	padding-bottom: 10px;
+}
+li.sidebox h2 {
+	font-weight: normal; 
+	font-size: 1.6em; 
+	text-align: left;
+	color: #242;	
+	font-variant:small-caps;
+}
+#sidebar li.sidebox p img {
+	margin:0;
+	padding:3px;
+	border:#ccc 1px solid;
+	background:none;
+}
+
+#footer {
+	clear: both; 	
+	background: transparent; 
+	margin: 0 auto; 
+	width: 760px; 	
+	text-align: left;
+}
+ html #footer {
+	height: 1%;
+}
+#footer p {
+	float: left; 
+	width: 50%; 
+	line-height: 1.2em;
+}
+#footer p.right {
+	float: right; 
+	margin: 1em 0; 
+	width: 50%; 
+	text-align: right;
+	font-size: 0.9em; 
+	color:#999;
+}
+#comments, #respond{
+	margin: 2em 0 10px 5px;
+}
+#commentform 
+{
+	margin:10px 0;	
+	padding:10px;
+	background:#f9fcfc;
+	border-top: #ddd 1px solid;
+	border-bottom: #ddd 1px solid;
+}
+.commentnum 
+{
+	font-size:1.5em;
+	font-weight:bold;	
+	margin:0 5px 0 0;
+}
+#container .commentlist {
+	margin: 0;
+	padding: 0;		
+	border-top: #ddd 1px solid;
+}
+.commentlist li 
+{
+	list-style:none;
+	margin: 0;
+	padding: 0.5em;	
+	border-bottom: #ddd 1px solid;
+	
+}
+.commentlist li.thread-alt 
+{
+    background:#f9f9f9;    
+}
+.commentlist li .cmtinfo 
+{
+	font-size:1em;		
+}
+.commentlist li cite 
+{
+	font-style:normal;
+	font-weight:bold;
+}
+.commentlist li .cmtinfo em 
+{
+	float:right;
+	margin:0;
+	padding:0;
+	font-style:normal;
+	font-size:0.9em;
+	color:#999;
+}
+/* threaded comments */
+.commentlist .children li {
+	border-bottom: 0px;
+	
+}
+#content-main .commentlist .children {
+	margin: 10px 0 10px 10px;
+	padding:  0;
+	border-left: 1px solid #ddd;
+}
+
+#content .commentsfeed 
+{
+	background:url(img/icon_feed.gif) no-repeat left center;
+	padding-left:16px;
+}
+#content .trackback 
+{
+	background:url(img/link.gif) no-repeat left center;
+	padding-left:20px;
+}
+input.textbox
+{
+	border:#ccc 1px solid;
+	background:#fff url(img/shadow_top.gif) repeat-x top;
+	font:1em Verdana, Arial, Serif;
+	padding:2px;
+	width:150px;
+}
+textarea{
+	width: 80%;
+	padding:10px;
+	line-height:2em;
+	height: 20em;
+	border: 1px solid #ccc;	
+	background:#fff url(img/shadow_top.gif) repeat-x top;
+	font:1em Verdana, Arial, Serif;
+}
+.textbox:focus, textarea:focus
+{
+	background:#fff url(img/shadow_top.gif) repeat-x top;
+	border:#999 1px solid;
+}
+.post h4 
+{
+	font-size:1em;
+	font-weight:normal;
+	font-family:Verdana, Tahoma, Arial, Serif;
+}
+.post h4 em
+{
+	font-style:normal;
+	float:right;
+	font-weight:normal;
+}
+#header, #content, #sidebar, #footer, .widget, .entry {
+    overflow: hidden;
+}
+
+.avatar { clear: both; float: right; margin-left: 5px; }
+
+.navigation { clear: both; } 
+
+img.centered, img.aligncenter {
+	display: block;
+	margin-left: auto;
+	margin-right: auto;
+}
+
+img.alignright {
+	margin: 0 0 2px 7px;
+	display: inline;
+}
+
+img.alignleft {
+	margin: 0 7px 2px 0;
+	display: inline;
+}
+
+.alignright {
+	float: right;
+}
+
+.alignleft {
+	float: left;
+}
+.aligncenter, div.aligncenter {
+	display: block;
+	margin-left: auto;
+	margin-right: auto;
+}
+
+.wp-caption {
+	border: 1px solid #ddd;
+	text-align: center;
+	background-color: #f3f3f3;
+	padding-top: 4px;
+	margin: 10px;
+	-moz-border-radius: 3px;
+	-khtml-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+}
+
+.wp-caption img, .wp-caption a img {
+	margin: 0;
+	padding: 0;
+	border: 0 none;
+}
+
+#content .wp-caption a:hover,
+#content .wp-caption a:active,
+#content .wp-caption a:link,
+#content .wp-caption a:visited {
+	border: none;
+}
+
+.wp-caption p.wp-caption-text {
+	font-size: 11px;
+	line-height: 17px;
+	padding: 0 4px 5px;
+	margin: 0;
+}
diff --git a/doc/Viewing Large Images with Seadragon and Pythonhtml_files/w.js b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/w.js
new file mode 100644
index 0000000..5944dc0
--- /dev/null
+++ b/doc/Viewing Large Images with Seadragon and Pythonhtml_files/w.js
@@ -0,0 +1,48 @@
+function st_go(a){var i,u=document.location.protocol+'//stats.wordpress.com/g.gif?host='+escape(document.location.host)+'&rand='+Math.random();for(i in a){u=u+'&'+i+'='+escape(a[i]);}u=u+'&ref='+escape(document.referrer);document.open();document.write("<img id=\"wpstats\" src=\""+u+"\" alt=\"\" />");document.close();}
+function ex_go(a){var i,u=document.location.protocol+'//stats.wordpress.com/g.gif?v=wpcom2&rand='+Math.random();for(i in a){u=u+'&'+i+'='+escape(a[i]);}document.open();document.write("<img id=\"wpstats2\" src=\""+u+"\" alt=\"\" style=\"display:none\" />");document.close();}
+function re_go(a){var i,u=document.location.protocol+'//stats.wordpress.com/g.gif?rand='+Math.random();for(i in a){u=u+'&'+i+'='+escape(a[i]);}document.open();document.write("<img id=\"wpstats\" src=\""+u+"\" alt=\"\" style=\"display:none\" />");document.close();}
+
+function clicktrack(e){var t;if(e){t=e.target;}else{t=window.event.srcElement;}linktrack(t,500);}
+function contexttrack(e){var t;if(e){t=e.target;}else{t=window.event.srcElement;}linktrack(t,0);}
+function linktracker_init(b,p){
+	_blog=b;
+	_post=p;
+	_host=document.location.host?document.location.host:document.location.toString().replace(/^[^\/]*\/+([^\/]*)(\/.*)?/,'$1');
+	if(document.body){document.body.onclick=clicktrack;document.body.oncontextmenu=contexttrack;}else if(document){document.onclick=clicktrack;document.oncontextmenu=contexttrack;}else{}
+}
+function linktrack(a,d){try{
+	if (!a||a==null) return;
+	while (a.nodeName != "A") {
+		if ( typeof a.parentNode == 'undefined' ) return;
+		a = a.parentNode;
+		if ( !a ) return;
+	}
+	b=a;
+	while (b.nodeName != "BODY") {
+		if ( typeof a.parentNode == 'undefined' ) return;
+		b = b.parentNode;
+		if ( b.id == 'wpcombar' ) return;
+	}
+	if(a.href.match(eval('/^(http(s)?:\\/\\/)?'+_host+'/'))) return;
+	if(a.href.match(eval('/^javascript/'))) return;
+	var bh=a.href;
+	var pr=document.location.protocol||'http:';
+	var r=(typeof a.rel != 'undefined')?escape(a.rel):'0';
+	var b=(typeof _blog != 'undefined')?_blog:'0';
+	var p=(typeof _post != 'undefined')?_post:'0';
+	//var x=document.createElement('IMG');
+	var src=pr+'//stats.wordpress.com/c.gif?b='+b+'&p='+p+'&r='+r+'&u='+escape(bh)+"&rand="+Math.random();
+	if ( a.className.match('flaptor') ) {
+		var fx=function(c){return c.replace(/flaptor\s*/, '')};
+		var f='b'+_blog+'p'+_post+' '+fx(a.className);
+		var links=document.getElementsByTagName('A');
+		for ( i=0; i<links.length; i++ ) {
+			if ( links[i].className.match('flaptor') )
+				f=f+' '+fx(links[i].className);
+		}
+		src=src+'&f='+f;
+	}
+	var x=new Image(1,1);
+	x.src = src;
+	if(d){var now=new Date();var end=now.getTime()+d;while(true){now=new Date();if(now.getTime()>end){break}}}
+}catch(e){}}
diff --git a/doc/tilemaker.py b/doc/tilemaker.py
new file mode 100644
index 0000000..a02c7d2
--- /dev/null
+++ b/doc/tilemaker.py
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+
+"""
+This program assists with cutting down large images into square tiles.  It can
+take an image of arbitrary size and create tiles of any size.
+
+python tilemaker.py -s256 -Q9 -t"tile-%d-%d-%d.png" -bFFFFFF -v canvas.png
+
+Copyright, 2005-2006: Michal Migurski, Serge Wroclawski
+License: Apache 2.0
+"""
+
+import math
+from os.path import split, splitext
+from PIL import Image
+
+chatty_default = False
+background_default = "FFFFFF"
+efficient_default = True
+scaling_filter = Image.BICUBIC
+
+from sys import exit
+
+def main():
+    """Main method"""
+    from optparse import OptionParser
+    
+    parser = OptionParser(usage = "usage: %prog [options] filename")
+    # Now, Dan wants tile height and width.
+    parser.add_option('-s', '--tile-size', dest = "size", type="int",
+                      default=512, help = 'The tile height/width')
+    parser.add_option('-t', '--template', dest = "template",
+                      default = None,
+                      help = "Template filename pattern")
+    parser.add_option('-v', '--verbose', dest = "verbosity",
+                      action = "store_true", default = False,
+                      help = "Increase verbosity")
+    parser.add_option('-Q', '--quality', dest="quality", type="int",
+                      help = 'Set the quality level of the image')
+    parser.add_option('-b', '--background', dest="background",
+                      help = 'Set the background color')
+    
+    # Location based arguments are always a pain
+    (options, args) = parser.parse_args()
+    if len(args) != 1:
+        parser.error("incorrect number of arguments")
+    filename = args[0]
+    if not options.template:
+        fname, extension = splitext(split(filename)[1])
+        options.template = fname + '-%d-%d-%d' + extension
+    if not options.background:
+        options.background = background_default
+
+    verbosity = options.verbosity
+    size = options.size
+    quality = options.quality
+    template = options.template
+    background = options.background
+    
+    # Split the image up into "squares"
+    img = prepare(filename, bgcolor = background, chatty = verbosity)
+
+    subdivide(img, size = (size, size),
+              quality = quality, filename = template, chatty = verbosity)
+
+
+def prepare(filename, bgcolor = background_default, chatty = chatty_default):
+    """
+    Prepare a large image for tiling.
+    
+    Load an image from a file. Resize the image so that it is square,
+    with dimensions that are an even power of two in length (e.g. 512,
+    1024, 2048, ...). Then, return it.
+    """
+
+    src = Image.open(filename)
+
+    if chatty:
+        print "original size: %s" % str(src.size)
+    
+    full_size = (1, 1)
+
+    while full_size[0] < src.size[0] or full_size[1] < src.size[1]:
+        full_size = (full_size[0] * 2, full_size[1] * 2)
+    
+    img = Image.new('RGBA', full_size)
+    img.paste("#" + bgcolor)
+    
+    src.thumbnail(full_size, scaling_filter)
+    img.paste(src, (int((full_size[0] - src.size[0]) / 2),
+                    int((full_size[1] - src.size[1]) / 2)))
+    
+    if chatty:
+        print "full size: %s" % str(full_size)
+        
+    return img
+
+
+
+def tile(im, level, quadrant=(0, 0), size=(512, 512),
+         efficient=efficient_default, chatty=chatty_default):
+    """
+    Extract a single tile from a larger image.
+    
+    Given an image, a zoom level (int), a quadrant (column, row tuple;
+    ints), and an output size, crop and size a portion of the larger
+    image. If the given zoom level would result in scaling the image up,
+    throw an error - no need to create information where none exists.
+    """
+
+    scale = int(math.pow(2, level))
+    
+    if efficient:
+        #efficient: crop out the area of interest first, then scale and copy it
+
+        inverse_size    = (float(im.size[0]) / float(size[0] * scale),
+                           float(im.size[1]) / float(size[1] * scale))
+        top_left        = (int(quadrant[0] *  size[0] * inverse_size[0]),
+                           int(quadrant[1] *  size[1] * inverse_size[1]))
+        bottom_right    = (int(top_left[0] + (size[0] * inverse_size[0])),
+                           int(top_left[1] + (size[1] * inverse_size[1])))
+    
+        if inverse_size[0] < 1.0 or inverse_size[1] < 1.0:
+            raise Exception('Requested zoom level (%d) is too high' % level)
+    
+        if chatty:
+            print "crop(%s).resize(%s)" % (str(top_left + bottom_right),
+                                           str(size))
+
+        zoomed = im.crop(top_left + bottom_right).resize(size, scaling_filter).copy()
+        return zoomed
+
+    else:
+        # inefficient: copy the whole image, scale it and then crop
+        # out the area of interest
+
+        new_size        = (size[0] * scale,         size[1] * scale)
+        top_left        = (quadrant[0] * size[0],   quadrant[1] * size[1])
+        bottom_right    = (top_left[0] + size[0],   top_left[1] + size[1])
+        
+        if new_size[0] > im.size[0] or new_size[1] > im.size[1]:
+            raise Exception('Requested zoom level (%d) is too high' % level)
+    
+        if chatty:
+            print "resize(%s).crop(%s)" % (str(new_size),
+                                           str(top_left + bottom_right))
+
+        zoomed = im.copy().resize(new_size, scaling_filter).crop(top_left + bottom_right).copy()
+        return zoomed
+
+
+
+def subdivide(img, level=0, quadrant=(0, 0), size=(512, 512),
+              filename='tile-%d-%d-%d.jpg',
+              quality = None, chatty = chatty_default):
+    """
+    Recursively subdivide a large image into small tiles.
+
+    Given an image, a zoom level (int), a quadrant (column, row tuple;
+    ints), and an output size, cut the image into even quarters and
+    recursively subdivide each, then generate a combined tile from the
+    resulting subdivisions. If further subdivision would result in
+    scaling the image up, use tile() to turn the image itself into a
+    tile.
+    """
+
+    if img.size[0] <= size[0] * math.pow(2, level):
+
+        # looks like we've reached the bottom - the image can't be
+        # subdivided further. # extract a tile from the passed image.
+        out_img = tile(img, level, quadrant=quadrant, size=size)
+        out_img.save(filename % (level, quadrant[0], quadrant[1]))
+
+        if chatty:
+            print '.', '  ' * level, filename % (level, quadrant[0], quadrant[1])
+        return out_img
+
+    # haven't reach the bottom.
+    # subdivide deeper, construct the current image out of deeper images.
+    out_img = Image.new('RGBA', (size[0] * 2, size[1] * 2))
+    out_img.paste(subdivide(img = img,
+                            level = (level + 1),
+                            quadrant=((quadrant[0] * 2) + 0,
+                                      (quadrant[1] * 2) + 0),
+                            size = size,
+                            filename=filename, chatty=chatty), (0,0))
+    out_img.paste(subdivide(img = img,
+                            level=(level + 1),
+                            quadrant=((quadrant[0] * 2) + 0,
+                                      (quadrant[1] * 2) + 1),
+                            size = size,
+                            filename=filename, chatty=chatty), (0,size[1]))
+    out_img.paste(subdivide(img = img,
+                            level=(level + 1),
+                            quadrant=((quadrant[0] * 2) + 1,
+                                      (quadrant[1] * 2) + 0),
+                            size = size,
+                            filename=filename, chatty=chatty), (size[0], 0))
+    out_img.paste(subdivide(img,
+                            level=(level + 1),
+                            quadrant=((quadrant[0] * 2) + 1,
+                                      (quadrant[1] * 2) + 1),
+                            size = size,
+                            filename=filename, chatty=chatty), (size[0], size[1]))
+
+    out_img = out_img.resize(size, scaling_filter)
+
+    # In the future, we may want to verify the quality. Right now we let
+    # the underlying code handle bad values (other than a non-int)
+    if not quality:
+        out_img.save(filename % (level, quadrant[0], quadrant[1]))
+    else:
+        out_img.save(filename % (level, quadrant[0], quadrant[1]),
+                     quality=quality)
+    if chatty:
+        print '-', '  ' * level, filename % (level, quadrant[0], quadrant[1])
+    return out_img
+
+
+
+if __name__ == '__main__':
+    exit(main())