thumbspage — Image-Gallery Web Pages for Folders
This is the thumbspage content-creators guide. It includes an overview of the program, detailed usage information, and a look at what's been upgraded in each release. Whether you consider yourself a developer or an end user, you'll find resources here to help get you started building galleries with thumbspage.
Because thumbspage adds items to the images source folder and may rotate images there, you are encouraged to read this guide first—especially its caution—before running thumbspage on valued photo collections. But if you're in a hurry: for a quick preview, try a live demo, packaged examples, or the code; for screenshots, click the image above; for this program's license, see its main script; and to download this program, visit its web page. This doc's content was last updated on March 6, 2020.
This section introduces the basics of thumbspage's roles and operation. Read this if you're looking for a quick summary.
In short, this program allows you to view or display a folder of images in a web browser, in a format that's both simple and noticeably better than browser defaults.
thumbspage turns an images folder into an easily viewed gallery. It automatically makes image thumbnails, an HTML thumbnail-links index page, and HTML image-viewer pages for all the images in a source folder, all of which can be customized by content creators. The static results can be viewed offline or online in any web browser.
In a bit more detail, given a folder of image files, this program generates an HTML index page with generated thumbnail links for each image in the folder. This page's links in turn open either the full-size images directly using browser-native (i.e., built-in) display; or generated HTML viewer pages with the image scaled to your view, gallery navigation links, and file-info popups on filename clicks.
The net effect is intentionally static: generated results reflect the folder's contents at build time only, but do not require a web server, and can be viewed both offline and online in any desktop or mobile browser. As such, this program can be used both for websites, and non-web use cases such as program documentation and general viewing.
When run (using the techniques explored ahead), this script skips non-image files; uses optional header and footer HTML index inserts; makes an optional bullet list for subfolders in the images folder; and creates the output index page in the images folder itself, along with a subfolder for thumbnail images and viewer pages' HTML.
After running this program, you can view or publish its results in a number of ways:
index.htmlby default, respectively).
thumbspage began as a builder of simple index pages that used generated thumbnail images for their links, but its feature set has evolved over time in response to usage experience. Among its new highlights added in recent releases:
You can read the full story on new releases ahead. Read on to the next section to learn how to use thumbspage to view and display your photos.
This section describes thumbspage install requirements, inputs and results, customization options, and other operational details. It's a comprehensive tutorial that doesn't assume you are already a command-line wizard—which means advanced readers may want to skim parts meant for others.
If you enjoy learning by example, you can also study the thumbspage demo sites online here and here for sparse but fast tutorials. These sites list their run logs, and use custom headers and settings which you don't need to code if the defaults work for your galleries.
thumbspage is a Python program that runs on all major platforms, and is provided in source-code form which you run with your local Python. To install the program itself, download its zipfile from the following web page and unzip it on your computer:
https://learning-python.com/thumbspage.htmlthumbspage also requires installs of Python 3.X (any X) to run its source code, plus the third-party Pillow (a.k.a. PIL) image library to extend the installed Python 3.X with image-processing tools. If they're not already present, fetch and install both these items from the following sites, respectively (or search the web for other links):
thumbspage will work on any platform that runs Python 3.X and Pillow, and has the required folder and file access permissions. For example, this program has been verified to run on Windows, Mac OS, Linux, and Android. Be sure to adhere to the latter's unique permission rules when generating galleries in Python Android apps. thumbspage likely works on the similarly constrained iOS too, but this is untested. For a recent Pillow install pointer, see this page.
As discussed ahead, as of version 1.7 thumbspage also uses the pure-Python and third-party piexif library to update image Exif tags, but this library's code is included and shipped with thumbspage itself, and does not require a separate install.
Once you've installed thumbspage and its required tools per the prior section, you're ready to start turning your image folders into galleries. This section demonstrates how to run thumbspage on your computer. It also goes over command-line basics for users new to the technique.
For a basic launch of thumbspage, run script
from a command line with no command-line arguments.
It can be run from a console (e.g., Terminal on Mac OS
and Linux, and Command Prompt on Windows) and after opening it in most Python IDEs
(e.g., PyEdit and IDLE).
thumbspage's main options are selected with five console replies, or their enter-key defaults,
on each run. The following example session gives user inputs in bold font. In its
prompts, inputs are described in
, and defaults are given in
() (on Windows, be sure to use
py -3 at the start of
your command line, and
\ instead of
/ in your pathnames):
/.../content$ python3 /MY-STUFF/Code/thumbspage/thumbspage.py Images folder path [. or dir] (enter=.)? trnpix Clean thumbs folder [y or n] (enter=y)? y Thumbs per row [int] (enter=4)? Thumb max size [x, y] (enter=(100, 100))? Use image-viewer pages [y or n] (enter=y)? y Running Cleaning: trnpix/_thumbspage/1996-first-pybook.png Cleaning: trnpix/_thumbspage/1996-first-pybook.png.html ... Skipping: .DS_Store Making thumbnail: trnpix/_thumbspage/1996-first-pybook.png Making thumbnail: trnpix/_thumbspage/1998-puertorico-1.jpg ... Skipping: _cut Skipping: _HOW.txt ... Generating thumbnails index page Generating view page for: 1996-first-pybook.png Generating view page for: 1998-puertorico-1.jpg ... Finished: see results in images folder.
This section documents the input replies in the preceding usage example, numbering
them from the first
? prompt to the last. As we'll see in the
next section, the first of these can now be provided with a command-line argument
instead; this bumps the others up in the list, but the options work the same either way.
Reply #1 is where you specify the source-image folder, which is also
where results will appear. This reply accepts an absolute or relative folder
pathname. For example, entering
folder means that folder in the directory
where the script is being run, and
denote absolute paths to your image folder on Unix and Windows, respectively.
. means the directory where the script is being run, and is the
You should generally clean the thumbs folder (reply #2) unless images have only been added, and use viewer pages unless they don't work well in your use case (reply #5). There's more on both of these options in usage notes ahead.
Replies #3 and #4 allow you to tailor index-page thumbnails on each run:
Besides the basic console interaction of the prior section, thumbspage also
allows you to pass in the folder name as a sole command-line argument instead
of a prompt reply. This allows you to use shell auto-completion on long folder
names, though it's probably more useful in a console window than an IDE.
Folder argument or not, you can also automate a launch by using command-line
< syntax to provide canned parameter inputs one per line in
a piped-in text file. These options yield at least three ways to start the
$ python3 thumbspage.py Images folder path [. or dir] (enter=.)? trnpix ...4 other parameters prompted from input... $ python3 thumbspage.py trnpix ...4 other parameters prompted from input... $ python3 thumbspage.py < inputs.txt
In the last of these modes, parameters in the piped-in file
would like look this (use an empty line to accept a prompt's default, and omit the
first line if you provide foldername in the command line):
trnpix y 4 y
Naturally, you can combine all these with shell syntax for pipes and output
> file) which are beyond this
guide's scope. For more thumbspage usage examples, browse its
The console input prompts and arguments above are really just the first level of
options on thumbspage. The sections Customization
and Usage Notes that follow
cover additional configuration options and usage details.
First, the next section covers more basics for users new to running
programs from command lines.
Update: the optional folder-name command-line argument was added in version 1.7. To better reflect this, 1.7 also moved folder name to be the first prompt when not provided on the command line; this invalidates some older session logs where folder name was asked later, but the difference is trivial.
Because thumbspage is run from a command line, you need to know the basics of folder pathnames in the console realm. This is probably simpler than it sounds; as noted, the pathname you input at reply #1 can be either:
.for the current folder,
..for one level up, or the name of a local item)
/Users/you/photoson Unix, or
For instance, when running thumbspage via command lines, you can "cd" to the folder containing your source image folder, and give a folder path relative to where you are working:
$ cd /MY-STUFF/camerauploads $ python3 /Code/thumbspage/thumbspage.py Images folder path [. or dir] (enter=.)? imagefolderhereOr, run the program anywhere and give an absolute path to your images folder:
$ python3 /Code/thumbspage/thumbspage.py Images folder path [. or dir] (enter=.)? /MY-STUFF/camerauploads/imagefolderhere
Absolute paths are generally required when running thumbspage from an IDE such as PyEdit, if they run code in the program's folder. Also see your file explorer's options for copy/paste of a pathname to which you've navigated; it can often avoid having to type a long pathname at thumbspage prompts.
As usual, the
thumbspage.py script's path in console command lines can be
relative or absolute too, depending on your console's current directory. For instance,
py -3 thumbspage.py suffices to start the program on Windows if run in
the thumbspage install folder, though your images folder will reside elsewhere—and
may be relative or absolute:
> py -3 thumbspage.py Images folder path [. or dir] (enter=.)? C:\MY-STUFF\camerauploads\imagefolderhere
If you'd like more background on command-line use, you'll find both online and brick-and-mortar resources that go into more detail. Here, the next section moves on to show you how to make your galleries more unique.
The most common thumbspage options are available as console inputs on each run, as described in the preceding section. This section covers additional customization options enabled by file edits.
A set of additional customizations are available as Python settings in file
See that file for its options, documentation on their roles, and
their preset values.
As examples, that file defines Unicode encodings; gives the names of the
generated index page and thumbs folder; turns subfolder-link lists on
or off; as of 1.5, configures most colors; and as of 1.6, allows images
to expand beyond actual sizes, and users to control auto-rotation of
images (described ahead).
For more custom behavior, add unique HTML code to the top and bottom
of the index page by placing it in files named
FOOTER.html, respectively, and storing these files
in the images folder alongside your images.
You can use both, one, or neither of these files; if not present, generic
HTML and text is automatically generated in the index page around the
thumbs table. For details on how to code these files, see the examples in
examples/ here. In brief:
<html>, and the
<head>section with all the usual components if used by your index page:
<meta>tags for mobile viewport and content-type Unicode encoding,
<script>, and so on. This preamble should be followed by the start of the
<body>section with any informational
<p>paragraphs or other content. For instance, header content can be used to describe the images on the page.
Subtlety: a Unicode type listed in a custom header file's content-type
<meta> tag should generally be the same as the
setting in the user configurations file,
because the latter is used when saving the whole index page,
including its generated thumbnails table. See version 1.3 release notes
The UTF-8 default is recommended in all contexts.
Also note that header files may wish to accommodate or disable
automatic subfolder links: see version 1.1 notes ahead.
<html>. For example, footer content might include navigation links or informational text.
The generated thumbnail index table's code is self-contained, and requires
no support code in a custom header.
HEADER.html file can use CSS style code to
alter the thumbs table in ways not supported by basic user settings (e.g.,
to tailor index-table font).
For examples of this technique, see the docstring in
user_configs.py, as well as
the online demo site
As of 1.6, viewer pages can also be changed arbitrarily by editing
the template file
in this program's install folder
(use "view source" in your browser to see its code).
For example, such edits might add site icons or navigation widgets
specific to your usage or site.
Edit with care (this file's code is fragile!) and rerun thumbspage
to use your customized template.
To tie together the ideas covered so far, the following sketches the structure of an images folder processed by thumbspage, with generated parts in bold font and default names and behavior applied:
Your image source folder/ Your images' files... Optional HEADER.html Optional FOOTER.html index.html _thumbspage/ Thumbnail-image files... Viewer-page files...
Open the generated
index.html file to view the thumbspage gallery,
and package the entire images source folder to distribute.
In addition, some files in the thumbspage install (unzipped) folder are available
for user customizations:
thumbspage install folder/ Implementation files... user_configs.py template-viewpage.htmlEdit
template-viewpage.htmlas you like for your galleries. Not shown above, your image folders may also contain subfolders that might show up in bullet lists on the index page; but to explore special cases like this we have to move on to the next section.
This section collects assorted usage pointers for thumbspage users. Though arguably random, it covers some of the most common issues and border cases that may arise when using the program.
Update: as of version 1.7, viewer pages are even more functional—with info-dialog popups on filename taps, and easier Raw-display access via image clicks—and repair some former large-font issues (see the release notes). These pages are now broadly recommended.
"), especially if they are to be viewed on multiple devices. By contrast, galleries uploaded to a web server need satisfy only their server's filename rules.
Also note that because filenames used on labels are not line-wrapped, their width largely determines column spacing on the index page. As a rule of thumb (pun intended...), use shorter filenames for narrower columns.
That said, thumbspage galleries can display only image types supported by both the Pillow library used to build their thumbnails, and the web browsers used to view their pages. While Pillow happily creates thumbnails for nearly every image type under the sun, web browsers are much more limited. TIFFs, for example, yield correct thumbnails and display well in Safari, Edge, and Internet Explorer, but cannot be displayed by Chrome or Firefox. Because of these constraints, the support story today reads as follows:
Some browsers may ask to auto-open some exotic image types in another program, but this isn't the same as in-page support. If your TIFFs (or rarer) images don't display in a browser you use, your best recourse is to convert them to a more widely supported format for use in thumbspage, such as PNG or JPG. A "Save as" in your local image editor will generally suffice. For a demo of common supported image types, see examples/mixedtypes. For more on browser image support, try this page or this search.
One browser-specific caution: a somewhat dated Safari (2015's version 9) on Mac OS has been seen to crash altogether when trying to display a PBM in the mixed-types demo pages, for unknown reasons that are well beyond the scope of the thumbspage project. Safari updates or image conversions are the suggested remedies.
.character are not included in the bullet list; the former is considered developer private per Python convention, and the latter is hidden per Unix convention. See version 1.1's details ahead.
.../folder/work only when a web server is present. Use the more complete and explicit form
...folder/index.htmlto also (or only) view results offline.
Because rotation changes the source
image file in-place for browser inline display, the original image
is by default first saved with a
extension in the source folder as a backup copy. See
settings that allow users to disable this feature and/or its backups;
that restores all originals from backups;
and 1.6 release notes in Version History ahead
for more background.
Conversely, folder cleaning is not required if images are only added to the images folder—thumbnails will be made for new images only, and thumbs for previously added images will be retained. This can save substantial time when extending large image folders. But when in doubt, clean; this script's work is done once, before any views.
_thumbspageby default, in
user_configs.py. It is not named with a leading
.character to make it a Unix hidden file, because hidden files are rude (you should really see what programs do to your computer), and may be skipped by some compression and backup programs (e.g., see ziptools and Mergeall at learning-python.com). The default name can be freely changed to be hidden if
.tradeoffs are acceptable in your usage (but you didn't hear that here).
The "Raw" links of thumbspage viewer pages trigger this effect, but it is not caused by this program—it also happens when visiting images' URLs directly, completely outside the script's pages. It's also limited in scope—it occurs for some images only, and never when the setting is cleared.
Users may be best served by clearing this setting in this use case. For context, try a search on "android chrome force enable zoom displays images too large" like this, or the possibly related bug report here. At the end of the day, thumbspage is completely dependent on browsers which change frequently and arbitrarily, and this issue is sadly typical of their current fragility. (Indeed, at times it seems a website could be laid low by a good sneeze...)
The issue: when published online, thumbspage's thumbnail-index pages load quickly, but its image-viewer pages must download images in full before scaling them to browser windows. As a consequence, some large images in thumbspage galleries may download slowly on some servers or clients. In early 2020, for example, large (e.g., 2-6M) image transfers on the business-hosting server that houses thumbspage were usually very quick (e.g., 2-3 seconds), but sporadically throttled down to an outright crawl (e.g., 20-30 seconds). It's unclear if this speed hit was due to traffic on the server itself or the broadband and cellular client networks accessing it, but similar delays may occur in other contexts. Such delays can obviously be discouraging to site visitors, and posting large images in general might even be rude to users with limited or metered bandwidth.
The remedy: if the full-size images in galleries you build with thumbspage load too slowly, your recourses include moving to a faster hosting server, and downscaling the size or quality of very large images. Of these, downscaling images may be easiest, cheapest, and politest. The Pillow library, for instance, has tools that you can leverage in a Python script to reduce image filesize by scaling down image dimensions and quality. Better yet, get the new shrinkpix program for a precoded solution that uses Pillow this way to reduce the size of one or all image files in your website. However you opt to shrink, be sure to regenerate thumbspage galleries to reflect your newly shrunk images' information displayed in info popups.
A faster, and perhaps dedicated, server may help too, but not for users on metered connections or slow client networks; for such visitors, smaller images (e.g., < 500K) may be the only fix, and even then will solve speed issues only if network throttling isn't extreme. The website hosting thumbspage has resisted downscaling its images in the past for the sake of both image quality and usage demonstration, but at this writing is in the process of shrinking images globally. Downscaled or not, if images here are still slow for you, you can always view most of this site's thumbspage demos by downloading and unzipping to your machine and viewing locally. This includes thumbspage's own examples—fetch its full package for quick off-line image views.
In a perfect world, online images would by now be immune to the scourges of metered access and traffic bottlenecks. In the world we inhabit, profit will probably always trump societal need, and the web's mass popularity will probably always best its technological progress.
Update: per testing so far, shrinking large images with the shrinkpix program mentioned above both removes observed slowdowns, and yields noticeably faster views. The primary downsides are minor and rare reductions in full-size image quality (described in shrinkpix's caveats), and potentially degraded quality for thumbnails. thumbspage 1.7 solved the latter issue by converting some images to "RGBA" color mode temporarily when making their thumbnails; this produces results as good as for unshrunk originals, and has the added benefit of improving thumbnail quality for some unshrunk GIF images too. See the 1.7 update note and shrinkpix docs for more details.
Besides its HTML galleries, you can also view and click thumbspage's generated thumbnails in GUI mode (i.e., without a web browser), by running the included example from the book where parts of thumbspage first appeared. It works on Windows (any version) or Unix (Mac OS and Linux) as follows:
c:\...\thumbspage> py -3.3 viewer_thumbs.py examples\unicode\images # Windows /.../thumbspage$ python3 viewer_thumbs.py examples/unicode/images # Unix
This is, however, a very basic and limited viewer GUI (and today even confesses as much). The book's later PyPhoto example is a much more useful GUI, with navigation, image scaling and zooms, and scrollbars for both indexes and images (as seen here and here). More recently, a much-upgraded PyPhoto is now available standalone, at the following site (it's a bundled PyGadget):
Also note that thumbspage itself can serve as an image viewer too. Because its results can be viewed both online and offline in any desktop or mobile browser, they can be used for same-device viewing; your browser becomes the GUI.
Finally, a word from the legal department. thumbspage has been tested extensively and used successfully on all types of photo collections, and will likely perform well on yours too. It is provided freely because it can help you view and display your photo libraries. Given the many ways that computers can fail, however, a word of caution is in order:
By design, this program will modify your images source
folder in-place. It adds an HTML index-page file (by default named
index.html) and a subfolder with thumbnails and HTML viewer pages
(by default named
_thumbspage), and as preconfigured rotates any
tilted images after saving backup copies of their originals with
.original extensions. Run this program on folder copies if you
don't want it to change your valued photo collections directly.
All that being said, keep in mind that you can easily delete the file
and folder added; original versions of rotated images can be easily restored
with the included script
and both image rotations and their backups can be disabled in
Moreover, if you always run thumbspage on a copy of your source
images folder, your originals will never be changed by the program in any way.
Still, the importance of your photos merits a complete understanding of
any tool that modifies them—this one included.
Like much in life, thumbspage improves with time and experience. This section describes changes made in thumbspage releases, most recent first. It goes into implementation details that may be primarily of interest to developers, though users may find additional context here too (and the border between thumbspage users and developers is porous at best).
For readers of code: you can generally find changes made to code by searching
source files for a version number enclosed in square brackets. For example, looking
[1.6] will turn up version 1.6 code changes in most
code files; a release year or date may also work in some contexts.
Version 1.7 was first released on February 17, 2020. It was repackaged on March 6, 2020 as a point release, with edits to this guide, and new screenshots; shortened labels and a new display-size line in the new info popup; a new usage note about image size in thumbspage galleries published online, with a link to a new program that can shrink images for you; an upgrade to thumbnail quality for shrunken images and some GIFs; retained and updated Exif tags for rotated JPEG images; and a new command-line argument for folder name.
With its initial February release, thumbspage 1.7 now handles large-font user settings without clipping images or running toolbar buttons together; uses more of the page for larger image displays; responds to both filename taps (with a new image-info popup), and image taps (with a full-size browser display, just like the Raw button); and drops hover effects which are unevenly supported on mobile browsers.
Most of the initial 1.7 changes appear on generated image-viewer pages, and all can
be found by searching for
[1.7] in the system's code files
as usual. For examples of all the visual changes in 1.7, see its
Here is a more detailed review of 1.7's upgrades:
To fix, 1.7 now calculates that actual space used by non-image page elements, instead of using a constant. See the results here, here, and here. As a bonus, this allows viewer pages to use all available space for the image, yielding a larger image display in most contexts. There is no downside to this change, and thumbspage users are encouraged to regenerate their pages with 1.7.
1.25emin CSS). Though very rare, this could cause the buttons to run together badly on some browsers if the user applied a very large font setting. This was observed on only one of dozens of mobile and desktop browsers tested, and at a font setting large enough to break the design of many a site on the web, but was still subpar.
To fix this for the sole known offending context, and make it less likely to occur in general, 1.7 abandons the prior font scale up for toolbar buttons altogether. See the result here. As a bonus, this allows more space for the image, yielding a larger image display on all mobile browsers tested. The only potential downside to this change is slightly smaller toolbar buttons on mobile devices, but the new button size is more symmetric with the filename's font (see the next note), and users can still scale up text as desired.
Note that both this and the preceding change invalidate some examples screenshots in trivial ways: toolbar buttons are now slightly smaller on mobiles, and the image display is slightly larger in general (e.g., see the befores and afters starting here). Older screenshots will be retaken if and as time allows, but are unlikely to be updated soon; to sample thumbspage's current behavior, be sure to try the examples in the thumbspage package, and the live demos at thumbspage's hosting website.
Note that, apart from display dimensions, the info displayed by the new popup is static: it reflects the image at the time that thumbspage generated the viewer page, not the time that the image is viewed. For accurate info, be sure to rerun thumbspage if images are modified—just as you would if images are added or deleted. Also note that the new dialog is simplistic and filename taps are somewhat subtle, but both pass as usable without overly convoluting the display or its code.
<!-- Generated. They may be useful in auditing or revision-tracking roles.
y(yes), instead of its former
n(no), because viewer pages are now mature enough to broadly recommend over raw browser displays. The default for the clean-thumbs prompt is now also
y, because this is the normal and recommended response. These are minor usage enhancements, but invalidate some console logs created under prior versions (two prompts differ trivially); these examples are being updated for the 1.7 release, but please pardon any remaining dust.
<shell syntax to pipe in a file of precoded replies, one per line, from a text file. To better reflect the new argument, 1.7 also changes the order of inputs, moving file name to be asked first. Like the prior note's change, this invalidates some older session logs (where folder name is asked later); also like the prior note, the difference is negligible, and examples are being updated in the 1.7 package as they are found.
.*hidden names in subfolders bullet lists
.and thus hidden per Unix convention no longer appear in subfolder bullet lists on index pages. Formerly, folders with leading
_s were skipped as gallery private, but hidden folders are now ignored too; use either to omit from bullet lists.
__main__test). This change does not impact the content or behavior of the pages that thumbspage generates, which work on any browser as before; but it allows thumbspage itself to be run to create galleries in contexts that support Pillow but not tkinter.
While generally helpful, this upgrade's main impetus was Python Android apps.
For instance, thumbspage is now usable on Android devices in both the tkinter-less
Termux after running both
(sans its "-y") and
pip install Pillow;
as well as the tkinter-aware
after running the same
pip command in its Terminal or using its Pip.
Especially when using a keyboard or tablet, this makes running thumbspage
on Android a reasonable goal.
For example, hover effects commonly get stuck on after a tap on Android mobile browsers, and aren't cleared until the next user event; this is especially poor if the tap does not switch to a next page—like the new filename tap in 1.7 above. Hover effects may also require a double tap to activate the main action on iOS devices (one tap for the hover, one to activate). In thumbspage, hovering was formerly disabled for smaller screens via CSS media queries, but its problems could still crop up in landscape mode on mobile devices. Hover effects may be superfluous for toolbar buttons which also invoke a URL popup; but the filename does not, and neither do some hoverable touchscreens.
Unfortunately, the only full remedy for this today is to avoid hover effects altogether on pages that wish to support both desktop and mobile devices—including thumbspage viewer pages as of 1.7. This is an unfair penalty on desktop browsers, where hovers work correctly, and are a common and even expected behavior. But it's also typical of the quality issues that mire the mobile realm, and one of far too many interoperability issues that plague the web domain. Alas, both seem to have been more accumulated than designed to date. For more on hover problems, see the note on this MDN page, and the iOS results for this search.
To fix this, version 1.7 now internally and temporarily converts some images to "RGBA" color mode when creating their thumbnails. This produces thumbnails that look the same and are at least as good as those made from original, unshrunk images by prior versions. As a bonus, using "RGBA" for some unshrunk GIFs renders their thumbnails much better than before; to show how, here are two pages with GIF-image thumbs before and after the change.
For more technical details on this change, see the
[1.7] notes in
This fix is not applied to JPEG images (which yield the same thumb quality
when shrunk), or GIFs with transparencies (whose transparent parts would render
black). An alternative "RGB" conversion was less constrained, but rendered
Mac OS screenshot shadows fully black, which matched shadows on
full-size viewer-page displays only coincidentally when the default black
background color was used.
These shadows may be best avoided as a rule, but this lesson comes too
late for the hundreds of captures on thumbspage's website.
One catch to this process: when Exif tags are propagated directly, they reflect the original image, not the rotated copy. Among the possible consequences, width/height dimension tags won't reflect the new swapped dimensions of the rotation. This isn't crucial, because rotated images are meant for use in thumbspage galleries only, and prior values document originally recorded size (though they may confuse other tools).
The orientation tag, however, cannot be propagated to saved rotations unchanged; if it's not updated to the normal-rotation value, other viewers will incorrectly reorient already-reoriented images, resulting in flipped displays. This happens even in the underlying web browsers that display such images directly in thumbspage's own Raw mode (a.k.a. image tap). Perhaps worse, if the orientation tag isn't adjusted, thumbspage itself will reorient the image and its thumbnail on every new run—with erroneous, if comical, results.
To fix this, thumbspage updates both orientation and dimension values in the Exif data while propagating it from original to rotation. This both saves date taken, and rights the Raw apes. To perform these updates, thumbspage now uses the third-party piexif library, and ships this library's code in its download package. The much broader Pillow library used elsewhere in thumbspage must already be separately installed, but has almost no support for Exif tags, apart from fetching and saving their raw bytes data. The pure-Python piexif both parses and composes Exif data, and provides read/write access to individual tags.
All of which is substantial added complexity. Without Exif propagation, though, date-taken would not be displayed for rotated images alone; without Exif tag updates, rotated images would be flipped by browsers and reoriented on each thumbspage run. The former would probably qualify as a bug, and the latter would be worse.
Also note that Exif propagation is currently applied only to JPEG images. PNGs have some notion of Exifs too, but it's just recently been standardized, was largely ad-hoc in the past, and the priority here is on commonly available photo data that thumbspage galleries display. If present at all, PNG tags seem unlikely to be as widely useful as the information slavishly stamped onto JPEG photos by our cameras and smartphones.
Version 1.6 was finalized on October 28, 2018. This version was released multiple times with new features in each release; release dates identify point releases. Its main extensions are dynamic image scaling and image auto-rotation, but it introduces numerous enhancements to the program—including this HTML guide.
This version was last repackaged in February 2019 with a minor change to avoid a tkinter dependency for contexts that have Pillow but not tkinter (e.g., some Android Python apps). The tkinter module is now required only when running the simple GUI viewer. For more details, see the update note above for version 1.7, which formally adopted this change.
Exception: on iOS only, images are always fully scaled in portrait device orientation, but for implementation reasons fall back on version 1.5's CSS scrollable scaling result in landscape device mode (in short, display size returned by iOS in this mode is unusable). Android fully scales images always, which yields smaller but complete landscape images—which is arguably better, but open to feedback.
thumbspage now automatically reorients (rotates) tilted source images and their generated thumbnails to be right-side up (top edge on top), if they have valid "Orientation" Exif tags. This is really just an automatic alternative to manually rotating tilted images before making thumbs, but is especially useful for photos shot on smartphones that commonly tilt photos shot in the natural portrait (vertical) device orientation.
Less positively, this feature applies only to images with reliable Exif tags (JPEG and TIFF) from cameras and tools that tag as expected. More intrusively, this feature must rotate source-image files too (not just their thumbnails), because not all viewers will rotate images when opened from thumbnails. In thumbspage specifically, web browsers will not rotate tilted source images (except on "Raw" clicks), because its viewer pages display source images as in-page elements. The related PyPhoto program now also adjusts for orientation in memory only and does not require image copies, but uses forked thumbnail-generation code (see its website).
Because this feature modifies source images in-place, it by default saves
them to backup copies with a
.original extension before making
changes. Users may also control the feature with two new settings in
autoRotateImages can turn the feature off,
backupRotatedImages can skip its
backups. Disable rotation if needed or desired, and manually rotate
tilted images before running thumbspage as preferred.
for a test case's results; that folder's
utility to restore from backups; and module
viewer_thumbs.py for implementation code
(rotation is neither automatic nor easy option for Pillow/PIL thumbnails).
Caveat: rotated source images drop the originals' Exif tags,
but rotated images are not the same as the original (some tags might not apply);
they are meant to be viewed in HTML galleries only; and some other image-processing
tools drop the tags too.
Update: version 1.7 now retains and updates Exif tags in JPEG images rotated and saved (read the details). This grew more important with 1.7's new info dialogs which display date-taken tag data.
In addition to the main items above, version 1.6 also:
Adds the HTML user/developer guide you are reading, as a replacement for the former in-code and text-based documentation. Text is easier to code, but HTML can be much nicer to read.
Moves configuration options and viewer-page HTML to separate files for easier viewing and edits. See Customization above for links and story.
_thumbspage as the default name of its thumbnails +
viewer-pages subfolder, to avoid clashing with other content.
The former "thumbs" name default may still appear in some docs and screenshots.
Prior-Version users: your "thumbs" folder will be unused; manually
delete or rename, or set
Expands image-folder name
. to its true basename in generated
default-header text, and appends a
/ to subfolder hyperlinks
so they will not trigger redirects or clash with files if and where
it matters. Because the
. fix uses Python's
to expand the dot, it also properly names image-folder paths with any "."
or ".." (e.g., ".", "..", "../..", "../Desktop/trnpix/../trnpix/.", and other oddities).
a new configuration setting,
allows the Unicode encoding of the viewer page template file to be easily configured,
and differ from that of index-page header and footer files. Its preset default and
generally recommended setting is the broad UTF-8;
user_configs.py to tailor.
Note that this new setting is used for loading the template file only;
generated viewer pages instead use the same Unicode setting for saves as
outputEncoding. The two settings may be the same or
differ, depending on your usage. The Unicode encoding declared in viewer-page
<meta> tags also uses
outputEncoding automatically so that it
agrees with page content; if you manually edit this tag, it should similarly agree.
expandSmallImages option in
If False, the maximum viewer-page scale ratio is 1.0, which
constrains images to an actual-size maximum, and thereby
avoids stretching and possibly blurring small images. If
True, smaller images are always expanded to display size.
The preset default is False, because this is generally better when smaller images are present (e.g., icons, and small-window screenshots). Use True for the prior expanding behavior which may be preferred in some contexts. Note that this setting applies only to small images; most digital photos and scans are far larger than display areas, and will only be scaled down.
This feature works and is used in Chrome on Android+Windows+Mac;
in Safari+Firefox on iOS; and in all other 20+ browsers tested
(including Internet Explorer 9, and other Android browsers). The failure
in Chrome on iOS is clearly a bug in its
of versions 64 and 68 tested; if used in this browser, Back clicks
redisplay the same page N times for N image views, which is
worse than stacking pages.
Because this might be fixed in the future,
chromeiOSBackFixed controls the iOS Chrome disabling.
At present, though, Chrome on iOS is just 0.40% of the audience at the
site hosting this program (just 10.96% of iOS, which is itself just 3.67%
overall); it makes no sense to omit an enhancement for 99.6% of users,
for the sake of just 0.40%. For more of this site's analytics,
visit this page.
Works around a Pillow library bug that could occur only in limited usage contexts for folders having very many images. In brief, Pillow's auto-close of loaded image files does not work as documented, which can lead to "Too many open files" errors after many thumbnails have been generated. Here, this meant that results could reflect partial source content for very large folders, though only on Mac OS in general.
The best and applied fix is to manually open and close image files,
instead of passing filenames to Pillow. With this change,
arbitrarily large folders are supported in all contexts.
For more details on both the bug and its workaround, see
where the fix is coded.
around a Chrome issue on Windows and Linux, by using
auto-scroll: hidden CSS for the body, to forcibly
hide the vertical scrollbar. Else, Chrome (and possibly
older Firefox) flash a scrollbar momentarily during viewer-page
loads. This setting doesn't impact displays in any other
way, and scrollbars are never required on viewer pages (images
are scaled, not scrolled).
Caveat: Chrome on Android (only) may still sometimes very briefly flash a vertical scrollbar anyhow. This may be an indicator or other normal behavior, but seems more likely a browser bug with no known workaround—applying the hidden setting to "html" in CSS doesn't help. This is minor and cosmetic, but like much web experience, has to be chalked up to browser idiosyncrasy.
around a Chrome desktop peculiarity, by using
thin instead of
<img> border-width in both index
and viewer pages (for thumbs and images). On this browser only,
1px can cause some image borders to not be
drawn at zoom levels < 100% due to fractional pixel math.
thin is equivalent to
1px in size today (not
2px, as once rumored on the web), but does not suffer from
pixel-math cloaking, and doesn't impact displays otherwise.
This works through Chrome desktop zoom level 50%; below that
Chrome (again, only) may drop viewer-page bottom borders for some
window sizes, but that's a reasonable usage cutoff (pages requiring
a microscope are off-table). Using a
1.5px almost works,
but can add empty space between border and content. To test borders, see
As part of this workaround, image border color was also made
configurable for both page types; set border color to background color
to omit borders altogether. Note that index-page table top/bottom borders work
1px, and this 1.6 change is disjoint from 1.5's
<hr> Chrome fix noted ahead.
Version 1.5 was finalized on August 12, 2018. This version's main feature is the introduction of image viewer pages, which were further improved in version 1.6 (see its notes). A set of extra enhancements rounds out the release.
In addition to its former thumbnail-index pages, thumbspage now generates a styled viewer page for each image in the folder, instead of relying on each browser's native image display.
Viewer pages are opened on index-page thumbnail clicks, and have filename, the image scaled per CSS, view-native and go-to-index links, and previous/next-image links that cycle through all images without having to return to the index page. Viewer pages center images horizontally, but not vertically; the latter is too jarring during next/previous navigation.
Viewer pages are generated in the thumbs folder, along with the prior version's thumbnail-index image files. They can also be suppressed via console input prompts; when omitted, images open in browsers directly and natively, as before. To view an example client live, visit this site.
In addition to the main items above, version 1.5 also:
Formalizes index-page and navigation ordering. It's now
case sensitive by default everywhere, but can be changed in
if case-neutral (Windows-like) ordering is preferred;
see that file's setting
for more details.
URL-escapes' Unicode encoding, which determines the content
%xx-formatted bytes. It's now always UTF-8,
regardless of the encoding used for whole HTML pages, because this
seems to be required by both standards and browsers.
for more details.
Sets body font to Arial (sans serif) for default-header index
pages. This is cosmetically nicer, and matches the new viewer pages' precoded font.
This font is set for the body in a default header
<style> block only and not
inlined in generated page components, so that global font can differ in a custom
Works around a desktop Chrome
which botches the separator line (it's much lighter at some zoom levels than
others). To fix, the thumbs table was restyled to use table top and bottom
borders instead of
<hr>s. As a consequence, the thumbs table now
always stretches to 100% window width, to extend the border
lines (this was formerly a configuration,
off by default). See also the 1.6 Chrome fix for vanishing
Sets thumbs-table background color to light grey as part of
the former note's
<hr> restyling, and allows it to be changed
The new viewer pages' colors (and others) can be similarly tailored
in that file.
Refactors its code to functions (it's now large enough that top-level code is difficult to navigate), and cleans up its page output (HTML/CSS is tough to read as it is).
Still uses all-inline styles for the thumbnails tables on index pages,
<style> blocks, so that custom
need not include or link to styles for the generated table. Conversely,
viewer pages use a
<style> block, as they are not customizable
without HTML edits (yet?).
Version 1.4 was finalized on March 4, 2018. In this release, this script's output page better supports browsers on smaller screens (e.g., mobile phones and tablets), and looks nicer in general. Its new generated CSS code:
Autoscrolls the thumbs table to appease mobile browsers.
Adds padding to thumb cells to reduce run-together.
Center-aligns thumbs images for a more even look; this helps overall, but especially for narrow/portrait images.
Uses nowrap paragraphs for image labels; the former
<br>+wrap scheme looked jumbled, and made Chrome (only!)
arrange thumbs-table columns unevenly in small windows
(the leftmost was narrower).
This version also adds a mobile-friendly viewport tag to
default headers if
useViewPort is True in
user_configs.py (this is its
preset default). This may impact other page components; use a custom
HEADER.html file for more
options and control where needed.
Tip: because filenames used on labels are now not wrapped, their width largely determines column spacing in the index page; use shorter filenames for less space between (i.e., narrower) columns.
Version 1.3 was finalized on August 8, 2016. This version makes several changes to better accommodate arbitrary non-ASCII Unicode filenames and page content (see the live demo). Specifically, this release:
HTML-escapes all added text—image, folder, subfolder names.
URL-escapes all added links—to thumbs, images, subfolders, and viewer pages in 1.5.
Outputs the generated index file in UTF-8 Unicode encoding by
default, with a content-type
<meta> tag. ASCII content is
unchanged, as it is a subset of UTF-8. Other encodings may be used for
the output file via setting
This setting is also used to save viewer pages, per the 1.5 update below.
Loads any header and footer inserts per UTF-8 Unicode encoding
by default, as it is general and supports ASCII directly.
Other encodings, including the platform's default, may be
used for inserts via setting
Note that this setting is used for insert-file loads only; generated
pages are always saved per
outputEncoding, which may or
may not differ in your usage.
Assumes any inserts are both HTML-safe and compatible with the default or configured inserts encoding. Be sure to verify your inserts before using this program's results.
See examples/unicode/images for the results of a comprehensive Unicode-content test case.
Note: if you use a custom
make sure that the Unicode type declared in its content-type
tag matches the setting for
outputEncoding (#3 above).
thumbspage uses the latter to save the whole index-page (including the content
of its thumbnails table), so these two encodings must be the same or compatible.
version 1.5 further refines URL escapes to use UTF-8 encoding for escape
and loads its new viewer pages as UTF-8 by default
(configurable as of 1.6 by setting
viewer pages are still output per
The Unicode test's folder also moved to the new path named above, and
thumbspage development switched from Windows ("\") to Mac OS ("/")
along the way, though some docs may still retain their former Windows bias.
Version 1.2 was finalized on August 1, 2016.
This version adds assorted cosmetic tweaks, mainly in the name of
better thumbnails-table styling, and subject to settings now in
Primarily, this release:
Uses uniform-width columns, instead of sizing columns
per content (on by default; see setting
Stretches the thumbs table to fill the whole window or display
(off by default; see setting
Update: this is now always on to
expand the table borders added for the 1.5
Adds a scrollbar if the window is too small? (prototyped but skipped in 1.2).
Update: this was obsoleted by version 1.4's auto-scrolls.
Version 1.1 was finalized on July 27, 2016.
This version adds an automatic
to the index page just before the thumbnails table, if enabled by
listSubfolders in file
This is on by default, and skips folders whose names are prefixed
. character, as well as the generated
thumbnails folder (whether it's named with a
prefix or not).
Note: if enabled, the subfolder-links list is generated whether you
use a custom
HEADER.html file or
not. When a custom header is used, the list appears after the header's text.
Hence, pages that use a custom header should either accommodate the list in
the header's opening content, or disable this feature and code the list
manually as desired. Naturally, this matters only if there are subfolders
in your images folder.
Tip: thumbspage must be run on each image subfolder in a tree separately (the tree is not walked automatically because its folders may have arbitrary content); and when viewing offline, index pages in subfolders must be clicked manually (online viewing normally opens image subfolder indexes automatically).
Version 1.0 was finalized on July 24, 2016. It provides a basic thumbnails-index page, with generated thumbnail images that open browser-native views. Its functionality is limited, but its results already beat default folder pages.
As normal, later releases were spurred by using this program over time. Where thumbspage goes next is limited only by developer availability and user experience. The next and final section sketches a few TBDs for future consideration—and argues against most of them.
Like all software, thumbspage is an open-ended project. In closing, this section collects implementation-related issues that remain open in the latest release. It's likely of most interest to developers, though some usage context may also be gleaned along the way. Some of these items are also outstanding questions, open to your feedback.
Also note that this list may not be complete; search for "caveat" in code files for additional items, and see Version History above for more on version changes noted here.
Update: 1.7 now retains and updates Exif tags in JPEG images rotated and saved (read the details). This grew more important with 1.7's new info dialogs which display date-taken tag data.
Update: 1.7 shows Android landscape images slightly larger, and makes it more natural to view images full size by making an image tap the same as the Raw button (see the details here). This helps, but the Android landscape scaling question is still open.
location.replace()bug that required disabling a Back feature on that browser, per version 1.6 notes above. Watch for a browser fix and change the configuration if and when it appears.
user_configs.py, and custom index-page fonts can be had via CSS in a
HEADER.html(see the configurations file for pointers). Still, user customization is open ended—and pending usage feedback. For example, default-header title and text could be configurable too, though they naturally vary per folder and might have to be changed often.
Update: 1.7 added an image-info
dialog, but kept the program simple by
alert() call, and avoided GUI clutter by invoking the
dialog with a tap on the existing filename field. This dialog's information
is mostly build-time static, and could be more grandiose, but it probably shouldn't be.
In the end, thumbspage is really about trying to do something useful in the stunningly ad-hoc and convoluted domain that is today's web development. As usual, fork with care.
You've reached the end of this guide, but there's more to the thumbspage story:
And may all your monkeys be right-side up.