37

I have a large library of PDF documents (papers, lectures, handouts) that I want to be able to quickly navigate through. For that I need thumbnails.

At the same time however, I see that the ~/.thumbnails folder is piling up with thumbs I don't really need. Deleting thumbnail junk without removing the important thumbs is impossible. If I were to delete them, I'd have to go to each and every folder with important PDF documents and let the thumbnail cache regenerate.

I would love to be able to automate this process. Is there any way I can tell nautilus to pre-cache the thumbs for a set of given directories?

Note: I did find a set of bash scripts that appear to do this for pictures and videos, but not for any other documents. Maybe someone more experienced with scripting might be able to adjust these for PDF documents or at least point me in the right direction on what I'd have to modify for this to work with PDF documents as well.


Edit:

The response to this question has been quite overwhelming. Let me first thank everyone who participated in solving this. The question, its answers and all the discussion around it are a great example of how the collaborative effort of many parties can lead to an optimal solution. This is exactly what makes Linux and Open Source so great.

All of the provided answers would deserve the bounty I originally put up for this question. Still, there's only one bounty to award. I owe it to all future readers to choose the answer that solves the problem in the most efficient way. To determine which solution that is, I did a final test run, comparing the three scripts in compatibility, speed and output quality. Here are the results:


Thumbnailer 1, by rosch:

Compatibility: ✔ spaces in file name ; ✔ spaces in directory name ; ✘ freedesktop compliant

Speed: 95 PDFs in 12,6 sec

Quality: stock nautilus quality

Additional Perks: 1.) automatically skips files with preexisting thumbs ; 2.) No additional packages needed

Thumbnailer 2, by Martin Orda:

Compatibility: ✔ spaces in file name ; ✔ spaces in directory name ; ✘ freedesktop compliant

Speed: 95 PDFs in 70,0 sec

Quality: significantly better scaling than the stock images.

Additional Perks: 1.) automatically skips files with preexisting thumbs 2.) compatible with a wide range of image formats besides PDF 3.) platform-independent, does not rely on GNOME-components

Thumbnailer 3, by James Henstridge:

Compatibility: ✔ spaces in file name ; ✔ spaces in directory name ; ✔ freedesktop compliant

Speed: 95 PDFs in 10,8 sec

Quality: stock nautilus quality

Additional Perks: 1.) automatically skips files with preexisting thumbs 2.) compatible with all file formats that are identified by the preinstalled thumbnailers


All three scripts are excellent. Each has its distinct set of advantages and disadvantages. Rosch's solution works out of the box and might be the right choice for users with a minimal installation.

Marcin Kaminski created a very versatile script that works with a variety of file formats and is DE-independent. It excels at thumbnail quality but does so at the expense of speed.

In the end it was James' solution that fit my use case best. It's fast, versatile and offers the options to skip over files with preexisting thumbnails.


Overall winner: James Henstridge


Additional information: All three scripts are fully compatible with nautilus-scripts. You can easily install them following this tutorial.


Edit 2: Updated review with improved script by rosch.

8
  • Because a lot of little files always ends badly. Do you know the size of your ~/.thumbnails folder ? Oct 14, 2012 at 15:46
  • You mean the size it is right now? about 85MB after ~1 month of use. Oct 14, 2012 at 15:56
  • And how much files does your library have ? (that's for technical reason/limitations) Oct 14, 2012 at 18:07
  • ah wait, I miscalculated; that's including some data files. Documents only its about 2000. Oct 14, 2012 at 18:45
  • I while ago I wrote a script to clean up the unused/broke thumbnails. blogs.gnome.org/gpoo/2006/08/30/… and updated version in github.com/gpoo/wasteland However, it seems you already delete your .thumbnail directory.
    – gpoo
    Oct 17, 2012 at 19:00

5 Answers 5

41
+100

Nautilus's thumbnailing routines actually come from the libgnome-desktop library, so it is possible to run the same thumbnailers outside of the file manager.

The API is a little complex, but the following Python script should help:

#!/usr/bin/python
import os
import sys

from gi.repository import Gio, GnomeDesktop

def make_thumbnail(factory, filename):
    mtime = os.path.getmtime(filename)
    # Use Gio to determine the URI and mime type
    f = Gio.file_new_for_path(filename)
    uri = f.get_uri()
    info = f.query_info(
        'standard::content-type', Gio.FileQueryInfoFlags.NONE, None)
    mime_type = info.get_content_type()

    if factory.lookup(uri, mtime) is not None:
        print "FRESH       %s" % uri
        return False

    if not factory.can_thumbnail(uri, mime_type, mtime):
        print "UNSUPPORTED %s" % uri
        return False

    thumbnail = factory.generate_thumbnail(uri, mime_type)
    if thumbnail is None:
        print "ERROR       %s" % uri
        return False

    print "OK          %s" % uri
    factory.save_thumbnail(thumbnail, uri, mtime)
    return True

def thumbnail_folder(factory, folder):
    for dirpath, dirnames, filenames in os.walk(folder):
        for filename in filenames:
            make_thumbnail(factory, os.path.join(dirpath, filename))

def main(argv):
    factory = GnomeDesktop.DesktopThumbnailFactory()
    for filename in argv[1:]:
        if os.path.isdir(filename):
            thumbnail_folder(factory, filename)
        else:
            make_thumbnail(factory, filename)

if __name__ == '__main__':
    sys.exit(main(sys.argv))

Save this to a file and mark it executable. You may also need to install the gir1.2-gnomedesktop-3.0 package if it is not already installed.

After that, simply invoke the script with the files or folders you want to thumbnail as arguments. Thumbnails will be saved to ~/.thumbnails where applications like Nautilus expect to find them.

6
  • Your script works absolutely great. It's exactly what I was looking for, so I awarded you with the bounty. I did encounter some error messages while doing my final test run, but they did not seem to hamper thumbnail generation. The errors might be related to the fact that some of the file names included German Umlauts ("ä,ü,ö"). Thank you, again, for providing this excellent solution. It will make my life much easier from now on. Oct 18, 2012 at 4:06
  • 1
    Those errors are coming from an XML parser being used by one of the thumbnailers, so would be related to the content of some file rather than its name. The above thumbnailer script will process all files in the directory, so it might not be a PDF it is having trouble with. Oct 19, 2012 at 0:44
  • I'm unable to create thumbnails for plain text files. Is there something I need to configure to make this work?
    – krasnaya
    Oct 21, 2015 at 23:20
  • This is fantastic, thanks! On Fedora 29 I had to use Python3 (so changed the shebang to /usr/bin/python3) and then turn the print statements into method calls, but other than that, it works perfectly!
    – jacderida
    May 2, 2019 at 14:25
  • 1
    It's also worth noting that this only generates 'normal' sized thumbnails. There's also a 'large' thumbnail type. You can also generate large thumbnails by using the size argument of GnomeDesktop.DesktopThumnailFactory(). Documentation here: lazka.github.io/pgi-docs/GnomeDesktop-3.0/classes/…
    – jacderida
    May 2, 2019 at 19:01
19
+100

The script below should do the job. It uses evince-thumbnailer which - as far as I know - comes with every gnome installation and is the default thumbnailer.
Save as pdfthumbnailer.sh and make it executable.
Usage: pdfthumbnailer.sh dir1 [dir2, ...]

#!/bin/bash

F1=$HOME/.thumbnails/normal
F2=$HOME/.cache/thumbnails/normal
SAVE_FOLDER=$F1
[ -e $F2 ] && SAVE_FOLDER=$F2

# the thumbnailing function
evincethumb() {
    outname=$(echo -n "$(readlink -f "$0")" | \
    perl -MURI::file -MDigest::MD5=md5_hex -ne 'print md5_hex(URI::file->new($_));')
    # no work if thumbnail already present
    [ ! -e $SAVE_FOLDER/${outname}.png ] && {
        echo "$0"
        #uncomment only one of both thumbnailers
        #convert -thumbnail 128x128 "$0"[0] $SAVE_FOLDER/${outname}.png 2>/dev/null
        evince-thumbnailer -s 128 "$0" $SAVE_FOLDER/${outname}.png 2>/dev/null
    }
}

# make our function visible to the subshell in "find -exec" below
export -f evincethumb

# loop through all given folders
for folder in "$@" ; do
    find "$folder" -type f -exec bash -c evincethumb {} \;
done

Restriction:

  • does not add Thumb::URI and Thumb::MTime attributes to the thumbnails as pointed out by James Henstridge. So far I have seen no evidence that the default evince-thumbnailer is doing so. In other words..as long as nautilus does not regenerate the thumbnails the script can be used for the job.

Notes:

  • prints the name of the file when generating a new thumbnail, skips generation if existing
  • speed: 37 pdf files tested with both evince-thumbnailer and convert (from imagemagick): 3seconds for evince-thumbnailer and 14seconds for convert.
  • generates thumbnails recognized by nautilus
  • path names handled by the perl URL:file module (spaces and other characters are correctly translated into a file uri)
  • needs perl, present in a default installation
  • files unhandled by evince-thumbnailer will simply output an error - muted with 2>/dev/null
  • look at the MimeType line in /usr/share/thumbnailers/evince.thumbnailer to see a list of handled file types
  • updates: starting from 12.04 the thumbnail folder seems to be ~/.cache/thumbnails.
    More robust paths using readlink.

Inspiration:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683394

0
11

Got distracted for a while and rosch beat me to it :) Didn't know evince-thumbnailer existed (I'm not a Gnome user) but anyway, since I've already written it, here it goes. It requires imagemagick installed, check and install if not there with:

which convert || sudo apt-get install imagemagick

Save as mkthumb.sh (for instance), chmod +x mkthumb.sh it and execute it with absolute paths as arguments (you can use -s as its first paramterer to skip generating thumbnails that already exist) i.e.:

user@host $ ./mkthumb.sh -s /home/user/Downloads /home/user/blah
Processing directory /home/user/Downloads/pics/
OK   /home/user/Downloads/pics/FeO08.jpg
OK   /home/user/Downloads/pics/UrOCu.jpg
OK   /home/user/Downloads/pics/34ATZ.gif
OK   /home/user/Downloads/pics/WBRE3.jpg
OK   /home/user/Downloads/pics/LjLdH.jpg
OK   /home/user/Downloads/pics/xvvae (1).jpg
SKIP /home/user/Downloads/pics/itcrowd.jpg
OK   /home/user/Downloads/pics/76180344.jpg
OK   /home/user/Downloads/pics/fgk5N.jpg
....

The script (I've modified it slightly to support most images, you can add more extensions if you need them):

#!/bin/bash

# USAGE: mkthumb.sh [-s] <abs_path> [abs_path]
# create nautilus thumbnails for images and PDFs in the directories (and their
# sub-directories) given as parameters.
# -s is used to skip generating thumbnails that already exist

skip_existing=0
if [[ "${1}" == "-s" ]]; then
  skip_existing=1
  shift
fi

mkthumb() {
  file="${1}"
  dest="${2}"
  convert -thumbnail 128x128 "${file}[0]" "${dest}" &>/dev/null
  if (( $? == 0 )); then
    echo "OK   ${file}"
  else
    echo "FAIL ${file}"
  fi
}

OLDIFS="${IFS}"
IFS=$'\n'
for dir in $@; do
  realdir=`realpath "${dir}"`
  echo "Processing directory ${realdir}"
  for file in $(find "${realdir}" -regextype posix-egrep -iregex \
  '.*\.(pdf|png|jpg|gif|jpeg)'); do
    md5=$(echo -n "${file}" | perl -MURI::file -MDigest::MD5=md5_hex -ne \
          'print md5_hex(URI::file->new($_));')
    dest="${HOME}/.thumbnails/normal/${md5}.png"
    if [[ -f "${dest}" ]]; then
      if [[ "${skip_existing}" == "0" ]]; then
        mkthumb "${file}" "${dest}"
      else
        echo "SKIP ${file}"
      fi
    else
      mkthumb "${file}" "${dest}"
    fi
  done
done
IFS="${OLDIFS}"

It handles files with spaces in their names without issues.

A bit of testing here:

user@host $ find .thumbnails/
.thumbnails/
.thumbnails/fail
.thumbnails/fail/gnome-thumbnail-factory
.thumbnails/normal

# ok - no thumbnails present.

user@host $ ./mkthumb.sh -s /home/user/Downloads/pdf/test/
Processing directory /home/user/Downloads/pdf/test/
OK   /home/user/Downloads/pdf/test/800pdf.pdf
OK   /home/user/Downloads/pdf/test/3_TO_pricelist.pdf
OK   /home/user/Downloads/pdf/test/111011-speisekarte-mit-desserts.pdf
OK   /home/user/Downloads/pdf/test/1186157_r4f3a355eb104a (1).pdf

user@host $ touch tstamp

user@host $ ./mkthumb.sh -s /home/user/Downloads/pdf/test/
Processing directory /home/user/Downloads/pdf/test/
SKIP /home/user/Downloads/pdf/test/800pdf.pdf
SKIP /home/user/Downloads/pdf/test/3_TO_pricelist.pdf
SKIP /home/user/Downloads/pdf/test/111011-speisekarte-mit-desserts.pdf
SKIP /home/user/Downloads/pdf/test/1186157_r4f3a355eb104a (1).pdf

# running nautilus once now to see if it generates new thumbnails

# checking for new thumbnails:

user@host $ find .thumbnails/ -newer tstamp

# None.
0
3

I wrote a package that modified James' script to include multiprocessing and the option to recursively generate thumbnails. The package is pip-installable. Check here for installation instructions.

An example of usage is:

thumbgen -w 4 -r -d your_directory
  • -r: recursively generate thumbnails

  • -w: number of cores to use

1
  • Requires Gnome DE fyi
    – a coder
    Aug 30, 2022 at 18:17
2

The thumbnail specification includes shared thumbnail repositories , which allow for pre-generating thumbnails to be distributed along with the associated files rather than have every user generate their own thumbnail. So in theory you could generate thumbnails and then add them to a shared repository thus removing the need to generate them in future if you cleared out your thumbnails directory, or moved them all to a different machine or whatever.

http://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#DIRECTORY

This Ask Ubuntu page come up in the results of a search when I was trying to find out if any application supports shared thumbnail repositories. Sadly it appears that no application supports them.

1
  • Wow - very good point. I hope someone fills this gap!
    – nealmcb
    Feb 27, 2021 at 19:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .