Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

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.

Martin Orda 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.

share|improve this question
    
Because a lot of little files always ends badly. Do you know the size of your ~/.thumbnails folder ? –  Antoine Rodriguez Oct 14 '12 at 15:46
    
You mean the size it is right now? about 85MB after ~1 month of use. –  Glutanimate Oct 14 '12 at 15:56
    
And how much files does your library have ? (that's for technical reason/limitations) –  Antoine Rodriguez Oct 14 '12 at 18:07
    
ah wait, I miscalculated; that's including some data files. Documents only its about 2000. –  Glutanimate Oct 14 '12 at 18:45
    
Just to update you : I have a solution for you. It's long to redact so allow me a couple of days. Regards ;) –  Antoine Rodriguez Oct 15 '12 at 19:22

4 Answers 4

up vote 24 down vote accepted
+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.

share|improve this answer
    
Thank you, James, for taking the time to write this script. It works just as advertised for single files. Out of the posted solutions it is the only one whose output is recognized by the system (correct file name 48eebea785a185cdfc9d8f1a2ed34400.png is used). At this point, however, it does not seem to support directories. Is there any way you could make it go through directories recursively? –  Glutanimate Oct 17 '12 at 15:08
    
Done. I also simplified the output a little too. –  James Henstridge Oct 18 '12 at 1:39
    
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. –  Glutanimate Oct 18 '12 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. –  James Henstridge Oct 19 '12 at 0:44

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

share|improve this answer
    
First of all thank you for your answer and the effort you put into it. I did some test runs and here are my results: 1.) thumbnail generation does not work for directories with spaces in their names; 2.) thumbnails created with both your script and @Martin Orda's are not recognized by the system; files processed with your script are handled as if there's no thumbnail present --> the result: duplicate thumbs in the thumbnail directory –  Glutanimate Oct 17 '12 at 5:18
    
Hm, well my tests were positive so far: nautilus recognized the thumbnails and did not regenerate them. Ugh, spaces in folder names is something I find bad practice..but I will modify the script. Duplicate thumbnails? What is the name of the new tumbnail for a give file then? –  rosch Oct 17 '12 at 8:39
    
Ok, tried it out again and I'm afraid it's the same result as last time. Here's the filename of a thumbnail your script generated: 2a43dc2774e3dfe45a4337e0304e5b0a.png. This is how the same thumbnail is named by nautilus: 48eebea785a185cdfc9d8f1a2ed34400.png. I have also noticed that thumbs created with your script are 128x171px while the inbuilt thumbnailer only creates 96x128px thumbnails. –  Glutanimate Oct 17 '12 at 14:52
    
Here's a comparison. –  Glutanimate Oct 17 '12 at 15:01
    
About your comment on evince-thumbnailer not adding the PNG tags, that is correct: the code that calls the external thumbnailers actually rewrites the images to include the the tags. You should be able to verify this by running strings -a on one of the thumbnails generated by Nautilus. –  James Henstridge Oct 18 '12 at 1:49

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
  echo "Processing directory ${dir}"
  for file in $(find "${dir}" -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.
share|improve this answer
    
Thank you, as well, for providing an excellent script. I did some test runs and here are my results: 1.) thumbnail generation works well and is faster than evince-thumbnailer; 2.) thumbnails created both with your script and @rosch's are not recognized by the system; files processed with your script are handled as if there's no thumbnail present. New thumbs are created when manually accessing the directories --> the result: duplicate thumbs in the thumbnail directory –  Glutanimate Oct 17 '12 at 5:23
    
You're right - I've checked this again and found that nautilus generates them again (I think that wasn't the case when I tested it last night but I could be wrong, it was already late). If it's indeed faster as you wrote (I haven't used other methods yet), I'll work on it in a few hours. The only issue I find with this is both files generated by my script and nautilus exhibit the same properties: "PNG 97x128 97x128+0+0 8-bit DirectClass 20.4KB 0.000u 0:00.000" when I use identify <thumbnail>. –  Marcin Kaminski Oct 17 '12 at 9:45
    
Nope, we were both wrong :) Turns out I forgot that the thumbnail's filename is an md5 hash of 'file://'+absolute_path and mistakenly ran my script as ./mkthumb.sh -s Downloads/pdf/test instead of ./mkthumb.sh -s /home/user/Downloads/pdf/test. Try to give it a go again. –  Marcin Kaminski Oct 17 '12 at 9:51
    
Alright, I did another test run and the peculiar thing is that both your script rosch's seem to have the same problem: filename with your script is 2a43dc2774e3dfe45a4337e0304e5b0a.png while nautilus names it as 48eebea785a185cdfc9d8f1a2ed34400.png. The dimensions, however, are correct with your script. Here's a comparison –  Glutanimate Oct 17 '12 at 14:59
    
I'd like to add that your script still is the fastest out of the ones posted here. imagemagick also seems to handle scaling much better than evince-thumbnailer (see the comparison above for reference). –  Glutanimate Oct 17 '12 at 15:17

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.