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 new in each release. Whether you consider yourself a developer or an end user, you'll find resources to help get you started building galleries with thumbspage here.

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. For a quick preview, try a demo, examples, or code. For screenshots, click the image above. For this program's license, see its main script. To download this program, visit its web page.



This section introduces the basics of thumbspage's roles and operation. Read this if you're looking for a quick summary.

Why thumbspage?

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.

What thumbspage Does

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 generated HTML viewer pages with navigation links, or the full-size images directly using browser-native (i.e., built-in) display.

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.

Using thumbspage Galleries

After running this program, you can view or publish its results in a number of ways:

To view results
Use any web browser to open the generated index page created in your images folder (the page is named index.html by default).
To publish results
Copy the entire images folder, including its generated thumbs subfolder and index file (named _thumbspage and index.html by default, respectively).
To publish results to a remote website
Upload the entire images folder—index page, images, and thumbs subfolder—to the folder representing your gallery on your site's web-server host. Zip or otherwise bundle the folder first for convenience.

Latest thumbspage Features

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.

User Guide

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.

Installs and Platforms

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:

thumbspage 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 and Pillow, and has the required folder and file access permissions. For example, this program has been verified on Windows, Mac OS, and Linux (Android may impose extra access requirements beyond this guide's scope). For a recent Pillow install pointer, see this page.

A note for developers: Pillow is used from Python for thumbnail generation, image rotation, and Exif-tag processing, all at gallery-build time. Images are scaled at image-display time instead by JavaScript code in generated viewer pages—which mix HTML, CSS, and JavaScript in a tangled and browser-specific morass that is the norm for web development today.

Running thumbspage

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.

Usage Example

To launch, run script thumbspage.py 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 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 prompts, inputs are described in [], and defaults are given in () (on Windows, use py -3 in your command line, and \ instead of / in your pathnames):

/.../thumbspage/test$ python3 /MY-STUFF/Code/thumbspage/thumbspage.py 
Clean thumbs folder [y or n] (enter=n)? y
Thumbs per row [int] (enter=4)? 
Thumb max size [x, y] (enter=(100, 100))? 
Images folder path [. or dir] (enter=.)? trnpix
Use image-viewer pages [y or n] (enter=n)? y
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.

Prompts and Replies

You should generally clean the thumbs folder (reply #1) 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 #2 and #3 allow you to tailor index-page thumbnails on each run:

Reply #4 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 /folder/folder and C:\folder\folder denote absolute paths to your image folder on Unix and Windows, respectively. A solitary . means the directory where the script is being run, and is the default.

For more thumbspage usage examples, browse its examples folder. The console input prompts 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.

A Brief Primer on Pathnames

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 #4 can be either:

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=.)? imagefolderhere
Or, 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.

User Configurations File

A set of additional customizations are available as Python settings in file user_configs.py. 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).

Header and Footer Insert Files

For more custom behavior, add unique HTML code to the top and bottom of the index page by placing it in files named HEADER.html and 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 folder examples/ here. In brief:

Provides all of the page's HTML code up to the generated thumbnails table (or subfolder links, if used). It should include a full HTML preamble, with <!doctype>, <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, <style>, <title>, <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 outputEncoding 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 ahead. 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.

Provides the remainder of the page's HTML following the generated thumbnails table. It should add any post-table content and close both <body> and <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. Conversely, a 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 here.

Viewer-Page Template File

As of 1.6, viewer pages can also be changed arbitrarily by editing the template file template-viewpage.html 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.

Summary: thumbspage Folders

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
        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...
Edit user_configs.py and template-viewpage.html as 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.

Usage Notes

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.

Viewer pages (or not)
The image-viewer pages added in version 1.5 are optional. If subpar in your use case, they can be disabled via the last console reply (see Running thumbspage above) to use the former browser-native display. As of 1.6, though, these pages scale displayed images well everywhere: images grow and shrink with the window or display, without changing their aspect ratio, distorting content, or overflowing their bounds. As a fallback (and for better zooms in some contexts), users may also click these pages' "Raw" links for browser-native view.
Image filenames text and length
Although thumbspage properly escapes and handles arbitrary image filenames, those in your galleries should generally avoid characters illegal on some filesystems (e.g., "), 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.

Supported image types
Images in the source folder are detected by MIME type (i.e., filename extension). All files there with an image MIME type are considered an image by thumbspage and included in the generated gallery, whether they have camera-oriented Exif tags or not. For example, JPEGs, PNGs, GIFs, BMPs, TIFFs, and more all qualify.

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:

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.

Other image-folder content
Because images in the source folder are detected by their MIME types (per the prior note), all non-image items in the source folder are simply ignored. Hence, it's safe to include arbitrary files and folders in the images folder; apart from the next note's special case, all unrelated items, including Unix hidden files, are always skipped and ignored by thumbspage.
Subfolder bullet lists
As a special content case, subfolders in the images folder not named with a leading _ character will show up on the index page in a subfolder-links bullet list, if this feature is enabled in the configurations file. This allows your pages to provide access to nested content—including details about the folder, or image folders within image folders—if useful in your galleries. For example, you might use this to describe a gallery's images, instead of text in a custom header file. See version 1.1's details ahead.
Linking to results with URLs
When referencing this program's results in hyperlink URLs, note that links to generated folders of forms .../folder and .../folder/ work only when a web server is present. Use the more complete and explicit form ...folder/index.html to also (or only) view results offline.
Tilted-image rotation
As of version 1.6, any images that are "tilted" (stored by cameras and smartphones with orientation tags, and content shifted to a side) are by default automatically rotated to display right-side up—both the image itself and its thumbnail. This works for all images with usable Exif orientation tags, which generally includes all JPEG photos created by recent devices.

Because rotation changes the source image file in-place for browser inline display, the original image is by default first saved with a .original filename extension in the source folder as a backup copy. See user_configs.py for settings that allow users to disable this feature and/or its backups; the included utility script that restores all originals from backups; and 1.6 release notes in Version History ahead for more background.

Cleaning the thumbs folder
thumbspage always regenerates viewer pages for each image on each run, so they correctly reflect your image set. For speed, though, image thumbnails created in prior runs are reused if present in the thumbs subfolder: new versions are not created, even if images have changed. Hence, you should always select the "Clean thumbs folder" console option in reply #1 (see Running thumbspage earlier) to force regeneration of thumbnails if any images have been changed or removed.

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.

Thumbs-folder name
The nested folder used to store generated thumbnails and viewer pages is named _thumbspage by 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).
Extra-files overhead
This script adds two files for every one source image (thumbnail and viewer page). That's negligible in most use cases, but may become significant in archives with very many files (10k images means 20k extra files). Incremental backup tools like Mergeall, for instance, may need to analyze and skip all files added. If this impacts your usage, thumbs folders can be zipped into single file archives where appropriate and needed.
Beware browser settings
Some browser settings that may appear harmless can adversely impact thumbspage galleries. In particular, the native image display on some Android Chromes may initially render some images oddly and too large in portrait orientation, but if and only if the seemingly unrelated "Force enable zoom" is selected in Accessibility Settings.

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...)

GUI Mode

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.

Usage Caution

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 the 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 restore-originals.py; and both image rotations and their backups can be disabled in user_configs.py. 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.

Version History

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 for "[1.6]" will turn up version 1.6 code changes in most code files; try a release year or date in others.

1.6: Scaling, Rotation

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). This did not change thumbspage behavior or results, but the tkinter module is now required only when running the simple GUI viewer. For more details, see this program's web page.

Dynamic Image Scaling

Despite the prior version's hand-waving, thumbspage's image-viewer pages now use JavaScript in their generated HTML to dynamically scale images to available display size, while preserving original aspect ratio and avoiding content screen overflow. The net effect emulates browser-native scaling in viewer pages, while allowing for extra control widgets. The former CSS scaling scheme is still used, but only for no-JavaScript views and iOS landscape mode. In more detail:

On desktop browsers
This is a complete solution. Images are now scaled to fill but not overflow available window space both initially and when windows are resized, on all desktop browsers and platforms tested—including Chrome, Firefox, Safari, Edge, and Internet Explorer 9 and 11, across Mac OS, Windows, and Linux. Users may freely resize their window to change the size of the image, but need no longer resize to view it in full.
On mobile browsers
This is a major improvement. Images are now scaled to fill but not overflow available display space both initially and on device orientation changes, on all mobile browsers and platforms tested—including Chrome and Firefox on Android, and Chrome, Safari, and Firefox on iOS. Taller images, for example, may now occupy more available space.

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.

On both device types, a "Loading..." message is also posted as a visual status indicator. Version 1.5 deemed JavaScript a "nonstarter" partly because of the added complexity, but mostly because locking out users who don't wish to run JavaScript is a rude non-option. Here, though, pages still work when JavaScript is disabled—they use the former 1.5 CSS scaling, with a note recommending JavaScript results. Turn off JS in your browser to see how 1.5 CSS scaling compares, and see the code for more details.

Image Auto-Rotation

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 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 user_configs.py: autoRotateImages can turn the feature off, and backupRotatedImages can skip its .original backups. Disable rotation if needed or desired, and manually rotate tilted images before running thumbspage as preferred.

See examples/reorientation for a test case's results; that folder's restore-originals.py 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 they are not the same, and are viewed in HTML pages only, and some other image-processing tools do the same.

Other 1.6 Changes

In addition to the main items above, version 1.6 also:

  1. 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.

  2. Moves configuration options and viewer-page HTML to separate files for easier viewing and edits. See Customization above for links and story.

  3. Uses _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 THUMBS='thumbs' in user_configs.py.

  4. 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 os.path.abspath() to expand the dot, it also properly names image-folder paths with any "." or ".." (e.g., ".", "..", "../..", "../Desktop/trnpix/../trnpix/.", and other oddities).

  5. Adds a new configuration setting, templateEncoding, which 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; edit 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 index pages—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.

  6. Adds an expandSmallImages option in user_configs.py. 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.

  7. Uses JavaScript viewer-page code to avoid adding viewer pages to browser history where supported, so that N image views don't require N browser Back clicks to get back to pre-gallery context. This destacking works everywhere but Chrome on iOS, where the feature is disabled (i.e., viewer pages are stacked on history and retraced by Back clicks for this browser only). The JS template file hosts most of the implementation's code (view its source).

    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 location.replace() 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, user_configs.py's new 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.

  8. 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 module viewer_thumbs.py, where the fix is coded.

  9. Works 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.

  10. Works around a Chrome desktop peculiarity, by using thin instead of 1px for CSS <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 this site.

    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 unchanged as 1px, and this 1.6 change is disjoint from 1.5's <hr> Chrome fix noted ahead.

1.5: Viewer Pages

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.

Image Viewer Pages

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.

Caveat: because image scaling is weak with CSS alone (and JavaScript seems both overkill and non-starter for this project), 1.5 image-viewer pages should be considered an optional feature. See "1.5 Usage Note" for deployment suggestions, and in-code documentation in the main script for more details.

Update: version 1.6 later replaced 1.5's CSS scaling with much better JavaScript dynamic image scaling for most use cases, and deleted the now-moot "1.5 Usage Note" referenced above. See the 1.6's release notes above.

Other 1.5 Changes

In addition to the main items above, version 1.5 also:

  1. Formalizes index-page and navigation ordering. It's now case sensitive by default everywhere, but can be changed in user_configs.py if case-neutral (Windows-like) ordering is preferred; see that file's setting caseSensOrder. See also orderedListing() in thumbspage.py for more details.

  2. Formalizes URL-escapes' Unicode encoding, which determines the content of %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. See also url_escape() in thumbspage.py for more details.

  3. 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 HEADER.html file.

  4. Works around a desktop Chrome <hr> bug 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 <img> borders.

  5. Sets thumbs-table background color to light grey as part of the former note's <hr> restyling, and allows it to be changed in user_configs.py. The new viewer pages' colors (and others) can be similarly tailored in that file.

  6. 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).

  7. Still uses all-inline styles for the thumbnails tables on index pages, not <style> blocks, so that custom HEADER.html files 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?).

1.4: Mobile

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:

  1. Autoscrolls the thumbs table to appease mobile browsers.

  2. Adds padding to thumb cells to reduce run-together.

  3. Center-aligns thumbs images for a more even look; this helps overall, but especially for narrow/portrait images.

  4. 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.

1.3: Unicode

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:

  1. HTML-escapes all added text—image, folder, subfolder names.

  2. URL-escapes all added links—to thumbs, images, subfolders, and viewer pages in 1.5.

  3. 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 outputEncoding in file user_configs.py. This setting is also used to save viewer pages, per the 1.5 update below.

  4. 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 insertEncoding in file user_configs.py. 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.

  5. 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 HEADER.html file, make sure that the Unicode type declared in its content-type <meta> 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.

Update: version 1.5 further refines URL escapes to use UTF-8 encoding for escape byte values, and loads its new viewer pages as UTF-8 by default (configurable as of 1.6 by setting templateEncoding; viewer pages are still output per outputEncoding). 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.

1.2: Styling

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 file user_configs.py. Primarily, this release:

  1. Uses uniform-width columns, instead of sizing columns per content (on by default; see setting uniformColumns).

  2. Stretches the thumbs table to fill the whole window or display (off by default; see setting spanFullWindow).

    Update: this is now always on to expand the table borders added for the 1.5 <hr> fix.

  3. 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.

1.1: Subfolders

Version 1.1 was finalized on July 27, 2016. This version adds an automatic subfolder-links list to the index page just before the thumbnails table, if enabled by setting listSubfolders in file user_configs.py. This is on by default, and skips folders whose names are prefixed with a _ 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).

1.0: The Basics

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.

Open Issues

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.

TIFF images are not universally supported
As described earlier, some web browsers do not support TIFF images directly—most notably, current Chrome and Firefox. TIFFs may work in some such browsers with installed plugins, and may be displayable via complex JavaScript/canvas techniques that are well beyond the scope of this project. Rarer image types are even more unlikely to be supportable (Safari initially displayed, but later crashed on, an index page with TIFFs, TGAs, and PBMs). Ultimately, this seems an inherent tradeoff for viewing images in browsers, and image conversion may be the best workaround. For more pointers, try a search.
Rotations drop Exif tags
As described earlier, rotated images lose their original Exif tags, because this is how the Pillow library saves them. It may be possible to restore some manually, but it's unclear if this should be done; rotated images are not the same as original photos (e.g., former location and date tags don't quite apply).
Android Chrome scrollbar
As described earlier, Chrome on Android (only) may very briefly display a vertical scrollbar when viewer pages are loading, despite this program's best efforts. This is a minor cosmetic issue and is probably a browser bug (or normal idiosyncrasy?), but a workaround proved elusive.
Extra-files overhead
As described earlier, this script adds 2 files for every 1 source image (thumbnail image and viewer page). That's negligible in most use cases, but may become significant in archives with very many files (10k images means 20k extra files). This might be addressed by using a single thumbs file instead of a folder (see PyPhoto's pickle-file scheme), but that would be complex and slow compared to the direct page-to-page and image links generated by thumbspage. It may also require cross-page state, local storage access, or a server, and break cross-platform or offline use. As is, users can generally zip thumbs folders where needed.
Parent-folder links
A ".." parent up-link is not generated in automatic subfolder lists; should it be? The parent may or may not have images, and may be altogether unrelated. Conversely, it's impossible to generate direct down-links to index files in subfolders, because subfolders may not be image folders. Both ideas are probably too automatic to be useful—or even correct—in all cases.
Index-file location
Creating the index file in the image folder might preclude use of some page-generation tools (e.g., the trnpix client's footer must copy HTML code that would be added automatically if accessible to site-generation tools used). Most likely, though, accommodating every site build tool is impractical and impossible.
Meta tags for custom headers
This program might generate a doctype and meta content-type tag in all index cases—not just for default headers—but that would limit doctype and Unicode options in custom headers. As is, custom-header files get complete control of header content, by design.
More code clean up
Even after refactoring to functions in 1.5, there are still a lot of globals in this program's code; clean up more in a future release? Alas, this program's origin as top-level script code is an enduring legacy.
Mobile landscape scaling
Which is better for 1.6 images scaling on mobile devices in landscape orientation: iOS scrollable or Android shrunken? The former was mandated by iOS's lack of display-size support, but may be preferable to some users.
Chrome history destacking bug
Chrome on iOS has a 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.
More user customizations
As noted earlier, colors on both page types (and much more) can now be customized in 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.
Index-page columns
The number of columns on the generated index page might be dynamically configured in JavaScript from viewport size (much like the current dynamic scaling of view-page images), but this may be complex (e.g., font size would matter) and could be too jarring as windows are resized.
Image information display
In principle, this program's results might also display image metadata (e.g., date-taken and location tags) if present. On the other hand, this wouldn't make sense for use cases like program documentation and other screenshots. More fundamentally, this would clutter and complicate viewer pages (minimally, with a new "Info" button), and, given thumbspage's intentionally static, server-optional paradigm, would require build-time generation of JavaScript popup details or additional pages—all of which might suffice to break this program's simplicity and usability.

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.

More Resources

You've reached the end of this guide, but there's more to the thumbspage story:

For more thumbspage documentation
See the archived closed-issues list and additional developer notes, in text file docetc/more-docs-trimmed.
For thumbspage example sites
Check out the live demo and example links in the Resources section of this program's web page.
For related image programs
Explore the tagpix photo-organizer script and PyPhoto image-viewer GUI, both available at learning-python.com.

And may all your monkeys be right-side up.

[Python Logo] News Code Blog Apps Top Email ©M.Lutz