Wednesday, July 12, 2006

Nautilus thumbnailer for XPS/Office 11 files




Thanks to the gnome isv guide I managed to muck my way through a thumbnailer for the new XPS and Office formats. They work the same as they both use the same container format.

While doing so I had the following questions:

  1. Does performance matter much on these things?
  2. Is there a way to fall back to the default icon without failing?
  3. Why can't I install a thumbnailer for a list of types at once?
    (e.g. both XPS and the new office formats)
  4. What image formats are supported/preferred?


The frustrating parts:

  • installing a gconf schema to register the thumbnailer
    (copy the evince one and replace PDF with XPS and the mimetype with application/vnd.ms-xpsdocument)
  • registering the new mimetype as always (fdo spec)
  • playing guess the style uri nautilus will use


Code below, feel free to use it.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Xml;

using ICSharpCode.SharpZipLib.Zip;

// A thumbnailer for XPS, and Office 11 Docs
// (anything that uses Open Packaging Conventions)
namespace Opc.Thumbnailer
{
class Thumbnailer
{
static ZipFile zip;

static int Main (string[] args)
{
if (args.Length != 2) {
PrintUsage ();
return -1;
}

// strip file://
string file;
if (args[0].StartsWith ("file://"))
file = args[0].Substring (7);
else
file = args[0];

if (!File.Exists (file)) {
Console.Out.WriteLine ("file not found");
return -1;
}

zip = new ZipFile (file);

string t = FindThumbnail ();
if (t == null) {
Console.Out.WriteLine ("no thumbnail found");
return -1;
}

int index = zip.FindEntry (t, false);
Image image = Image.FromStream (zip.GetInputStream (index));
// FIXME: convert to a .png?
image.Save (args[1]);

return 0;
}

static string FindThumbnail ()
{
XmlDocument doc = new XmlDocument ();
int index = zip.FindEntry ("_rels/.rels", false);
doc.Load (zip.GetInputStream (index));

foreach (XmlNode n in doc.GetElementsByTagName ("Relationship"))
{
if (n.Attributes["Type"].Value == "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail")
return n.Attributes["Target"].Value;
}

return null;
}

static void PrintUsage ()
{
Console.Out.WriteLine ("usage: opc-thumbnailer <input> <output>");
}
}
}