Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2007-213
$eventId
ID of event: wwdc2007
$eventContentId
ID of session without event part: 213
$eventShortId
Shortened ID of event: wwdc07
$year
Year of session: 2007
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2007] [Session 213] Getting Sta...

WWDC07 • Session 213

Getting Started with Spotlight and Quick Look

Leopard Innovations • 53:20

Make sure the Spotlight search engine in Mac OS X can find your files by adding a Spotlight plug-in to your application. And new in Mac OS X Leopard, Quick Look plug-ins make your files previewable using the new Quick Look feature found throughout Leopard. These plug-in technologies are very similar, so building one makes it simple to build the other. Gain an understanding of Spotlight and Quick Look starting at the beginning, and come away with practical knowledge on how to build them into your product.

Speakers: Jonah Petri, Julien Jalon

Unlisted on Apple Developer site

Downloads from Apple

SD Video (215.5 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

This is Session 213. Getting Started with Spotlight and Quick Look. My name is Jonah Petri. I'm a Spotlight engineer. And I hope you guys are ready for a big brain-dump because we're covering a lot of stuff today. So let's get started. The first thing I wanted to do if we could quickly go to demo, is show you a couple of the things that we want the Leopard Finder experience to be.

In Leopard Finder we've done -- if you saw the keynote, a lot of integration between your apps and the Finder itself. So that users can see the applications -- sorry -- the documents that they've created in the Finder itself. And this is a new level of integration that no one's really done with file manager and the document content. And so you can see, you know, if we go to an images search you can see your actual images.

And of course, this is nothing new for images, but we do this with PDFs, we do this with Keynote presentations, we do this with all sorts of documents. And most importantly, we want you to do it with your documents. Because users are going to expect this level of integration in the future. So let's go back to slides. If I can avoid losing this, that would be good.

So, how are you going to do this? Well, there's two technologies that you need to integrate with in order to get your apps to the level of user experience in the Finder that users are going to come to expect. And these two technologies are Spotlight and Quick Look.

And Spotlight is a system-wide metadata and text index that's been around since Tiger. And it's integrated with Apple and third- party documents via a plug-in architecture. Quick Look is a system-wide document preview architecture that generates those nice previews that you saw. And it's also integrated with Apple and third-party documents via a very similar plug-in architecture. And I'm pointing that out because a lot of the stuff that you see for the Spotlight section is also relevant for the Quick Look section, and vice versa.

So we thought that today you were probably coming here with an example -- your application -- wanting to integrate it. And so we integrated -- we -- sorry -- we created a demo app that we're going to go through the process of integrating with these two technologies and it's called MyBooks.

And so we've got a bunch of -- what this application does with some apologies to Delicious Monster, is it just tracks your books. And you've got the cover image, you've got the title, and you've got the author, and you've got a big chunk of review text. And this just allows you to basically, you know, have your books.

But the experience that you get when you look for your books is not ideal. I can't search for any of the text. And these are the book documents that I've got on my system. And that's not really compelling. And that's not what the users are promised with Leopard. So if we can go back to slides.

We're going to go through the process of integrating MyBooks into Spotlight and Quick Look to get that full Finder user experience. So, in order to do this, we have to do a little bit of talking about the architecture. Spotlight and QuickLook, like I said, use plug-ins to extend their capabilities to other document types.

And these plug-ins declare the types of files that they handle, so that Spotlight and Quick Look can load the appropriate plug-in for a file. Well, what do we mean by type on Mac OS X? Types on Mac OS X are composed of uniform type identifiers. We call them UTIs.

And UTIs are an identifier that uses a reverse DNS naming convention, and they're freely extensible by anyone. So you guys can all come up with your own UTIs if you have a custom document format. All that we ask is that you let us own the public domain. So that we can provide the standard type so that -- standard types can work across applications.

So what do these UTIs actually represent? Well, in this example you see public.mp3, that's a UTI. And it represents both the description and an icon that the user might see as well as the information that the OS itself needs to map the type from the file system into the UTI itself. Such as the extension or the OS type, or the mime type of the data. And these UTIs also belong in a big hierarchy, which tells you more about the UTI via it's place in the hierarchy.

For instance, an MP3 descends from public.audio. And so that would tell you that an MP3, if you didn't know, was a kind of audio, and so on up the tree. So it's important to place your UTIs appropriately within the tree so that they are providing information via their placement.

So how are types organized? The first way that they're organized is via a physical hierarchy. And this is a low-level view of how your file is actually packaged on disk. And that can either be a flat file or a package, as we'll see in a moment. The second hierarchy is a functional hierarchy. And this is a high-level user view of what is this content, what does this mean to me, is it an image or is it a movie? And every type -- and this is key -- has a place in both hierarchies.

So if you're going to be defining your UTI you need to place it in both hierarchies. So here's a sort of pared down physical hierarchy. public.item is the top level. The two that I want you to pay attention to are these two leaf nodes. public.data and public.package. Because if you've got a custom document format, your document format must descend from public.data if it's a flat file, or public.package if it's a package. And on Mac OS X, for those maybe new to the platform we have packages which are really directories containing a hierarchy of elements, but they're exposed to the user as a single file.

The functional hierarchy, on the other hand, is very broad. And describes all sorts of content that the user might be interested in. Such as images, or text, or audio, or movies. And we encourage you to if you're defining your own UTI, find the place in the functional hierarchy that is most appropriate for your content. So in the future when we make more use of the hierarchy itself, we will treat your document type accordingly.

So, when you're working with UTIs, the first thing to do is check whether the UTI that your document type has, whether we've already provided a UTI for it. And you can check for that in the CoreTypes.bundle in /System/Library/CoreServices. There is an Info.plist in there that's very extensive and defines a lot of UTIs for standard types.

And you declare support for a UTI in your bundle's Info.plist a little bit like this. In this example you see that I've declared the com.mycompany.mybook, which is the UTI we're going to be using for the MyBooks example. And I'm going to be -- I've declared that my bundle is an editor for that UTI type. And you could use other roles too. For instance, if you are a Quick Look plug-in you would use that role, and if you were a Spotlight plug-in, use that role. But don't really pay attention to that too much.

What is important is to understand the structure of how these things are defined. And there's plenty of documentation on UTIs. So if it feels like I'm breezing through this a little bit, rest assured there's plenty of docs out there for you to take advantage of. So if you don't have a UTI that's already defined by the system you'll have to declare your own.

And that's not too hard. The basics are when you're declaring a new UTI the type that you're going to be declaring is declared in your bundle's Info.plist. And that can be your application's bundle or it can be your Spotlight or QuickLook plug-in, or other bundles on the system.

In general, types that you own, that you are declaring, should be exported. And this is a very strong declaration. And we encourage you to use this for your application bundle, where you're being the authoritive source of information on this type. Types that you use in the bundle, on the other hand, should be imported. And this is somewhat a weaker declaration of type.

And the exception to this, of course, is system-defined types. You don't have to -- you don't have to import those at all because they'll be on the system for you to use. And we encourage you if you're developing a plug-in, either a Spotlight plug-in or a Quick Look plug-in where you're going to be using UTIs to import the types there and leave the exporting of the types to the applications themselves.

So now that I've talked a little bit about UTIs, let's see them in practice. Let's look at what we did for MyBooks for UTIs. So here's the MyBooks app. And I'm just going to go into by showing the package contents. Contents, info.plist. And I'm going to open that up in Xcode.

And the two things you should pay attention to here is this UTExportedTypeDeclarations, and this is where we're exporting the type. And we're saying, hey, our content type conforms to public.data. Meaning it's a flat file. And public.content. Meaning this is content that we couldn't figure out a better place in the functional hierarchy. So we're just putting it as a child of public.content. Here we name the UTI itself, com.mycompany.mybook.

And here's the file name extension that allows the OS to map from a file on disk to our UTI. So anything ending in mybook is going to be mapped to thecom.mycompany.mybook UTI. Also, since this is an app bundle appeared at the top, you see that we've declared ourselves as an editor for the com.mycompany.mybook UTI.

So that's the way that you would go about integrating UTIs with your app. If we could go back to slides. One thing I wanted to mention is that you should be careful when going to UTIs because your reading and writing code for document types will be called with the UTI rather than the file name extension or other Legacy type information. So your code needs to be prepared for that. And we've seen that bite people for NSDocument and other frameworks. So just be prepared.

So why do we talk about all this type stuff anyway? It seems like kind of a segue. But in fact, UTIs are really important for Spotlight and Quick Look integration, because Spotlight and Quick Look only integrate using UTIs. If you're going to build a Spotlight or a Quick Look plug-in, you must declare the UTIs that you handle. You can't say I handle everything that ends in .jpg. And then Quick Look and Spotlight once they determine the UTI of the file on the disck can unload the appropriate plug-in and proceed.

So let's talk a little specifically about Spotlight. Spotlight is, as I said, an architecture for metadata and text indexing. And for you as a plug-in developer, the key process you want to be aware of is this mdworker process. And this is the process that's going to load the plug- ins that you develop and also the system plug-ins, and it's going to take the files on disk and call your plug-in with the path to these files on disk as appropriate for the UTI of the file itself. And your plug-in is expected to extract the attributes and text content of these documents and mdworker will feed that information to mds, which will store it in the various databases that mds has. mds is the metadata server, by the way.

And once mds has stored that it can be used, but, like, by the Finder, for example. And you can see, this is an image that I had on my computer. And there's all this juicy metadata that the user might want to take advantage of, like the dimensions or the make and model of the camera. That's all stamped into the JPEG itself by the camera at photo time. And we've extracted that in the image Spotlight plug-in. And we can provide that to the user. And you can do the same thing with your document's metadata.

What is all this stuff actually coming from? Well, like I said, it's attributes and values, and the image Spotlight plug-in is going to be extracting the metadata in terms of attributes and values. And you can see a couple of examples here. Like the kMDItemPixelWidth and the kMDItemPixelHeight. Or the AcquisitionMake or the AcquisitionModel of the camera. So you can see attributes and values are a very simple key value way to talk about metadata, and we support a couple types, strings, numbers, and booleans -- but it's not a very structured metadata schema.

So once you've figured out -- actually wait -- I'm going to talk a little more about attributes. So that we support a lot of attributes on the system. And you should decide what attributes are most appropriate for your document types. There is a lot of general predefined attributes that you can use. You can see a couple of examples up there.

There is also a lot of specialized attributes that might only be appropriate for certain types of files, like a video bitrate, or the album of an MP3 file. And there's a full list of attributes available in MDItem.h, in the Metadata.framework under CoreServices. And you can also look in the docs for good descriptions of what these attributes actually mean, if kMDAcquisitionMake is not self-explanatory for some reason.

So the other one I wanted to call out is the kMDItemTextContent. This is an attribute that's treated specially by Spotlight. It is write and query only. Meaning that clients cannot get the text content back after the fact. But it's a -- the contents of the kMDItemTextContent are placed into a very fast text index that we can search very quickly, especially on Leopard. And this is useful for any representation of your document format as text.

And that can be if you're a word processor, obviously the text content of the document as the user would see it. But you can also be more creative. For example, Automator takes the strings from the actions that you've laid out, the actual strings that would be on the screen, and concatenates them together into the text content. And that forms a pretty good representation of the document in text form. So be creative with your apps, if your app is slightly graphical or not necessarily directly text based.

So now that you've decided what your application's attributes -- metadata attributes might be, let's talk about how you're actually going to build one of these plug-ins. There's three steps. The first is to start with Xcode. And we provide these templates for you for both Spotlight and Quick Look.

And start with those because they've got a lot of glue code in them that's very dicey to work out on your own. And we've done that for you, so don't bother, basically. Then edit the info.plist to declare the UTI types that your plug-in is going to handle. And that would also be a step where you could import the type declarations if you've got your own UTI type. And then implement the callback function.

Which in the case of Spotlight would be GetMetadataForFile. In the case of Quick Look, it would be GeneratePreview ForFile, and a couple of others that we'll see later. So now that we've got these three steps in front of us, let's talk about building a Spotlight plug-in. So I'd like to invite Julien Jalon up on stage to walk us through this.

( Applause )

So the first thing we're going to do, step one, was to go and make a new project. And use the Spotlight Xcode template. Which is all the way down at the bottom of the list. And we're going to name our project, let's say, MyBooksSpotlight. Let's throw in the desktop so that we can find it easier.

And so the second step, if you remember, was to edit the info.plist, to use -- to declare that our plug-in is going to handle the UTI type that we chose for our app. Now, there's all this helpful information at the top of your -- at the top of the template's info.plist about exporting or importing a type declaration. We provide all of this commented-out XML for you to use. But we're not going to go into that right now. We're just going to remove it because it's not necessary in the case where your UTI is already defined.

So, you'll see that we have this nice capitalized text for you to fill in, the supported UTI type. Go ahead and let's fill in com.mycompany.mybook, what was the UTI that we chose. And the one other thing that you have to do in info.plist is you have to declare the unique bundle identifier for this bundle. And that's down there under CFBundleIdentifier. And we're going to change that com.mycompany.mybook.spotlight to uniquely identify our Spotlight importer plug-in bundle.

So once we've done that, we can actually go and write code. So for this code we're going to actually change the type of this file from a .C to an Objective-C file. Because we want to take advantage of Foundation. And that's fine to do. The other thing you have to do when you do that is to add in the Foundation framework. Because you're going to be using Foundation.

And then we've also got a couple utility files that we created in advance that parse the document format that we used. This would be where you fill in your document's parsing code. So the contents of those files are not super-important. But once you've got those added in the project, you can open up GetMetadataForFile.m, or .C. There's also all these helpful comments in here about what you should be doing and different options that you have. We're just going to remove those for the sake of the demo.

We're going to move all the contents of this one callback file, that's GetMetadataForFile. Like I said earlier. And what this function does is it calls your plug-in with a path. You can see the fourth parameter is path to a file. And you're directed to take that path, open it, and do whatever you're going to do with it, extract the attributes, the metadata attributes of that file, and put them -- add them into the attributes dictionary that passes the second parameter. And then return true or false depending on your success or failure in dealing with file.

So we're just going to add some imports to use the code that we added in the Foundation. And here's the entire contents of our Spotlight plug-in. The first thing we do is we parse the document out. And if we couldn't parse it we're going to say, ah, we give up and return false. If we could parse it, we're going to keep going, and we're going to say, okay, let's extract the title from our document. And we're going to use the title as a kMDItemTitle and the kMDItemDisplayName attributes.

And then we're going to go on and extract the author and use that as the kMDItemAuthors attribute for the metadata. And we're also going to extract that review text. Remember that MyBooks app allowed you to track the review text of these books. And we're going to extract that and put that as the kMDItemTextContent so the users could search on something that was in the review and find their documents. And then once we've done that we've successfully parsed and added the metadata attributes, and so we're going to return true. And so that's it. We've just created a Spotlight plug-in. We're going to build it, and build succeeded -- and so let's go back to slides.

So, once you've built it, we do encourage you to test it. And there's this nice command-line utility called mdimport, which has been around since Tiger, but we've enhanced it in Leopard with this -g switch. So the way you probably want to use mdimport now is to call mdimport -g and then a path to your import -- your Spotlight plug-in. And that will cause mdimport to load only your plug-in.

And so you can bypass some of the launch services UTI registration issues that some people have run into in the past. And also provide a file that you like it to run on or an entire hierarchy of files. And mdimport will run your plug-in in a similar environment to mdworker.

And you can debug it there, you can test to see the performance of your plug-in, etc. A couple of switches that are useful. -d will give you useful diagnostics about what mdimport is doing and what your plug-in is doing. And you can increase the level of debug output up to four. -p summarizes your performance.

So if you give mdimport the entire hierarchy it's going to import that whole hierarchy and then report if you pass -p, what the most expensive files were, and how long the average file took, and all sorts of good, juicy performance numbers. And there's a bunch of other switches too that are helpful, and I encourage you to look man mdimport for those.

So what are we actually looking for when we're testing a Spotlight plug-in? Well, the first thing is performance. And this is super important. Because these plug-ins are run in the background and the user may not understand why their computer is all of a sudden slow whenever they save one of your documents.

So you should really work to minimize the VM impact. Don't leak memory, don't leak threads, and definitely minimize the disk impact of your code. If your code is going to be loading a whole bunch of stuff and then scanning back and forth across the file, it may be worth it to refactor your code a little bit to make it more streamlined for Spotlight importing.

And the second is stability. Because if the program -- sorry, if your plug-in crashes you're going to be -- not only is your metadata not going to get imported so users won't be able to find anything, but you're going to disrupt the user because they're going to be having these crashing processes in the background all the time. And that does churn the disk a lot, etc.

And the third thing is scalability. And this is even more important in Leopard than it was in Tiger, because we're pushing Spotlight on to the server, and so you're going to have an order of magnitude or two orders of magnitude more files to deal with than you did in Tiger.

So, you know, test on thousands of files, or tens of thousands of files. Whatever you would expect. And test on edge case files, zero byte files, fuzz your Spotlight plug-in, if you like. You know, really beat it up so that it's proof against the server case. So, let's just go back to the demo machine and I'll show you a little bit of mdimport.

So -- here's our built plug-in. So I'm going to run mdimport -d1. To get a little bit of debug output. And then -- oops, I want to pass the -g flag before the path to my plug-in. And then I've got a bunch of files here. I've picked one. MyBook file.

And you can see the mdimport is pretty sparse with -d1. It says, hey, I imported this document which is the one I said of the right UTI. And that's something that can be tricky, if you're not seeing your imports work properly, check to see if the UTI is properly registered. And this is the plug-in that I used.

Okay. That all looks great, but did I get the right attributes? Well, if I bump the debug level up one more and clear the screen to make it a little bigger because it's going to be a more spewy -- you'll see that, hey, you know, I got the authors correctly, and I got the UTIs correctly imported, and the title is right. And here's the text content. Hey, there's all this good stuff. So that seems to work properly. So it looks like my plug-in is working. Now let's go back to slides. But -- just -- we would do more testing in the real world than just that.

But that's just a demo of where mdimport can go. So once you've got a tested and working Spotlight plug-in, where are you going to put it? This is very similar to the Quick Look case. So if you've been sleeping through this so far you might want to wake up. The Spotlight plug-in can go in two places. It can go in your application bundle inside your Application -- inside the Contents/Library/Spotlight directory. Or you can put it in as a stand-alone importer in Library/Spotlight.

And this would be a good -- it's also good to provide your plug-in as a stand-alone plug-in for the server case, because server admins may not want to install your app, but they still may want your files to be indexed on the server. So that's something to think about.

And there's a precedence for these plug-ins. But that only happens if two plug-ins claim the same UTI. So in the general case of custom document formats that's not something you have to worry about. So let's go back to the demo machine and I'll show you what happens when we install this thing.

So I've still got the content of this file that I -- that I ran my plug-in against. And there's this unique term here, Eiji, which is one of the characters from this book. So I am going copy that and save that off for demo purposes in a moment. But I just wanted to call that guy out. So I'm going go back into my released build. And here's my Spotlight importer. I am just going to drop it into the Library/Spotlight folder.

Now I'm going to replace the one that was there. And then I'm going to run mdimport -r on that plug-in. This is something that you'll see on the mdimport man page. And this will cause all of the documents that were associated with the UTIs of this plug-in claims to be reprocessed with the newly installed plug-in.

So that might be something good to do at install time for your apps so the documents on the system that have your UTI will be reprocessed and indexed so the users can find them without saving them again. So I am going to run that. It runs very quickly. Now if I go in here and type Eiji, like I had before, hey, I find that file. Great. My Spotlight plug-in works. And we can go back to the slides.

( Applause )

So this was Spotlight. And that's a really important part of the fFinder user experience in Leopard. But I know you're all saying, it wasn't pretty enough. We didn't have that beautiful, Cover Flow experience. All we had was these generic document icons. And I don't really know what I'm looking at when I'm looking at those.

Well, the technology that you need to provide those awesome inline previews and thumbnails for your documents is Quick Look. In order to talk about Quick Look I'd like to invite once again Julien Jalon up to the stage. And hand you over to him.

- Thank you, Jonah

( Applause )

Hello, everyone. My name is Julien, and I am a Quick Look engineer, and we will talk about Quick Look really is, and how it works. And how you can participate in Quick Look to make your documents look great in Finder.

So as we mentioned earlier, Quick Look is a system-wide preview service. And it's mainly used in Finder. We wanted to move away from the generic icons and only provide view information on your document types. And we wanted to move to visual informations that provide information on your document contents.

And that's what really -- what we do in finder now, so you can really find your document and identify them in the code. And what's even more important is generation of the Cover Flow. Because the main feature of Cover Flow is for you to spread through a lot of documents and visually identifies your document and stop on it when you find it.

We will also introduce what we call the Quick Look panel. The Quick Look panel let's you take a different look in your document content. And the QuickLook panel is very, very interesting in Time Machine. It's a great help for Time Machine because it let's you find the precise version of your documents when you go back in time.

We are also building -- the Quick Look panel in Mail and iCal so you can take a look -- take a look at your documents, your mail, and even attachments. Also, Quick Look is compatible with iChat so you can really easily share your documents in video chat using the Quick Look panel.

So really, Quick Look is a technology that helps all of this technology, like Spotlight, Finder, Time Machine, Mail, iChat, etc., so it's really an important technology for (Inaudible). Technically, while QuickLook is really about previews we have two very different terms for the previews Quick Look provides. The first one is Thumbnails which is a static image that represent your document in a compact form as a static image.

We also have what we call previews, full previews. That's what you see in the Quick Look panel. In fact, previews are a representation of your document's content in several different common types, like, essentially images, movies, audios, QuickTime supported, PDF, and HTML. The goal of the panel is to for you to navigate through your documents. Not for everything. It's really not about replacing your applications.

But to support every kind of document, Quick Look comes with a side kick. It's a small daemon process named quicklookd. And quicklookd can take any kind of document and uses -- using the same plug-in architecture that you have already listened to for Spotlight, quicklookd can produce thumbail documents or translate your documents that the QuickLook panel supports.

In your part, we have already built in support for several document types. Maybe you have already seen the support for Word or Excel documents, but we are also supporting V-cards, events, mails, fonts, or iChat transcripts which is quite handy when you are searching for a description in your iChats. And since we really want to support any kind of document, we are asking you to support your own kind of documents in Quick Look.

So how do you do that? We tried to make that as simple as possible. You have two ways to do that. If your document type is a document bundle or document package, you can pre-generate your previews and thumbnails and put them inside -- inside your document bundle. Or you can create them on demand.

As Jonah already mentioned, document bundles are just folders, and Mac OS X is smart enough to just display a flat file to the user. And it's a very, very useful way to just pack all of your document resources in your document. And since it's just a folder, you can create a subfolder in it, named quicklookd. You can do that at save time. And you can put an image file that will be used as your document thumbnail and the preview file be HTML, QuickTime, whatever the Quick Look panel supports, and it will be used as your document previews.

Pre-generated previews are really nice. Nice for you because it's most probably the simplest way for you to support Quick Look. Since additional code will reside in your application code and will be executed inside your application you will probably not have to refactor all your code a lot. It's really so nice for us, because it's really cheap to display. quicklookd knows how to find these files inside your document bundles, and view them directly as native previews.

Of course, pre-generated previews comes at the expense of your document size. Because putting a preview file inside your document naturally significantly increases your document size. And so it will make your saving longer as you will have to produce these additional files at save time. And of course, it only works for document bundles.

So that's why we provide the more active way to support Quick Look. In fact, we are using the same kind of ideas that you have already seen in Spotlight. You just have to write a specific Quick Look plug-in binded to your document's UTI. And whenever a client, for example, is assigned to ask for a thumbnail or a preview, quicklookd will load your plug-in and call some -- callback you have to implement.

And you will have just thrown back the main difference with Spotlight is you don't have to provide attributes and values in a dictionary. Instead you will get an object reference to the request itself, and using the QuickLook.framework API we just answer to that request, and we have different ways to do that.

So let's take a look at really what the code looks like. So, here is a Generate Thumbnail callback you will have to implement. As you can see there is this QLThumbnailRequestRef object, which represents the request itself. That is the one that will manipulate transfer to Quick Look. You have the URL for the file UTI, same kind of things you already seen in Spotlight. So there is this maxSize parameter which is, which is the desired maximum size the ThumbnailRequst asks for.

Generally, you won't have to worry about it, because Quick Look will enforce it. But sometimes it can be useful to take a look at it. Because -- the smaller the thumbnail is we won't -- there is less attention to put in there, and generally, the faster we want you to do be.

So, how do you produce your thumbnail callback. We have two ways to do that. The first way, just draw it. Just ask for CGContext to the request. And you draw your thumbnail in there and once you're done you flush the context. At this point Quick Look will create the resulting image and send it back to the client. But if you are -- your image directly available, for example as jpgData or any image-supported format, just send it to QuickLook using the QLThumbnailRequestSetImageWithData API. QuickLook knows how to render that and will create the image accordingly.

And there is a callback you have to implement to generate previews. Almost the same thing as except there is no maximum size because we don't have the notion of maximum size for previews. At this point when you have to implement your preview callback you will have to decide what kind of type you will provide to Quick Look. You have several choice. We have already seen that. QuickTime, HTML, PDF -- whatever. We tried to make it as simple -- as simple as possible for you to implement that callback.

If you decide to provide PDF for images you can just draw your preview directly using the same kind of ideas we provide for thumbnails you just ask for context, CGContext, you draw in it, and once you're done you flush it. We also provide the same kind of APIs what you see here to create a full PDF multipage context, which is, QLPreviewRequestCreatePDFContext so you can provid real full page previews.

Also, there is a way to provide previews is just to give us -- the raw data after preview in one of the types your documents supports. And one of the good examples for that is to create -- is to use HTML previews. You -- you use generally, HTML previews if your document presentation or the one you want to provide to Quick Look has no particular layout or texture. So it's a good way to provide previews for some documents, like you create HTML dynamically and send it back to Quick Look.

The preview API lets you specify some properties that will be sent alongside your previewed data. It's generally -- generally useful when you want to add Quick Look under your preview. One of the good examples for that is for HTML previews. Because if you are using HTML previews you will likely have to include some images in your HTML. So we will have to provide these images to Quick Look so that it can display HTML correctly.

So these attachments will just have to pack them and put them in the kQLPreviewPropertyAttachmentsKey and send them alongside your preview data with the properties. And in your HTML you will just have to reference these images or attachments, whatever attachments you are using, your HTML that you are using, (Inaudible).

So -- now we have enough knowledge to make this MyBooks documents look much nicer and finer. So we won't go through all the set up we have already seen for Spotlight. And we will just take a look at the code. So first we have to do thumbnails. We have to decide what we will put in the thumbnail for my document.

A very good candidate is just the cover. So that's what we'll do. And in fact the good thing is that the cover is stored inside the document as JPEG. So let's use that. So let's take a look at the thumbnail -- thumbnail callback. So really simple. First you parse the document.

Second thing. This is a main difference between Spotlight and Quick Look. Quick Look callbacks once an error has returned and (inaudible) just have to return no error whatever happens. Even if your parsing fails. It's not yours, and you are free to use noErr, for example. So you parse your document. And then you just get to your cover JPEG data from the document. And send it back to Quick Look using the QLThumbnailRequestSetImageWithData API. And that's it. You support thumbnails.

So now we'll go in the preview part. And we have to decide what kind of preview we will use. Our books are just to cover title, author, and review, not specifically (Inaudible) very graphical. So what we'll use is just HTML previews. So that's what we'll do. And to do that we start from very basic HTML templates. Something that I designed very fast.

Not very nice, but maybe sufficient. So you will see that on the top left you will have the cover, then the title, and below the review. That will be our preview. That's what we'll use to create previews for MyBooks documents. So let's get a look at the real code.

First, yeah -- so first thing we start by parsing the document. Same thing as for thumbnails. And then we have a very great API to manipulate XML or HTML data. It is an XML document. And that's what we will use. In fact we will really start from the HTML we were just in.

Read it using NSXMLDocument and filling the node using the API NSXMLElement, NSXMLNode, stuff like that. It's very, very handy if you are producing HTML previews that is a very good way to do that because NSXML will undo all the programs of escaping stuff and creating correct and valid HTML. So this is there.

Then we'll have to -- we have an attachment for our previews. It's a cover that -- it's a small image. And we want to send it alongside the preview that I sent. The HTML that I sent. So that's what we'll do then. We get the cover data like we did for the thumbnail and we pack it in attachments.

The formatting of the packing is very simple. It's just a dictionary telling, okay, this is data, it's jpeg. And it will be named cover.jpg. Which means that in the HTML file we just refer to data using CID: converted JPEG. And that's it. We have our properties, we have our HTML data, we just send it to Quick Look using the QLPreviewRequestSetData Representation API and we have our plug-in.

So that be that. Should be quite -- great. So, we'll test it right away. So -- we will install it. Same thing as for Spotlight. Library/QuickLook. And no -- oh. Yes, sometimes Quick Look takes one or two minutes to detect that there is a new plug-in and refreshes its plug-in database. So what we will do is manually force QuickLook to reset the data, so there is a small tool we'll talk about in a minute, which is qlmanage. Okay. Great. And now let's try it again. And that's it.

( Applause )

These things I find very nice to browse books, and we can take a deeper look in the book description. We also added some links so that you can search in Google for the photo of the books. And you can do everything you want since it's HTML.

I think that's all. Let's go back to the presentation. Thank you, Jonah.

( Applause )

So as for Spotlight to provide a small tool, which is a Swiss Army Knife for Quick Look. You have already seen that in the demonstration to reset the plug-in database, to make sure everything is nice so that you can test it.

It is very handy when you develop your plug-ins because you are continually installing it -- them -- and removing them, modifying them. So it's really useful to use that. But qlmanage can do more. And especially can let you really debug your plug-in. Because qlmanage can execute your plug-in in a very similar environment as quicklookd. So you can use qlmanage in Xcode as a custom executable.

Just use -p or -t to test previews of thumbnails. And you can use GDB Graphical Interface to break in your code using qlmanage. So it's very, very useful. And also since your plug-in won't be properly registered until it's installed, we provide -c and -g to override the UTI checking launch services registration of everything so you can force everything, You can force Xcode or qlmanage to use your plug-in and don't care about installing your plug-in first.

qlmanage can do a lot of stuff. So really let's -- go through the man page. And once you are done just install your plug-in, nothing new here. It's exactly the same as for Spotlight. You can use your plug-in as standalone and put it in a well-known location, like /Library /QuickLook, or embedded in your application.

So let's talk about optimization. You will have to help Quick Look under your plug-in. You can do that in two ways. The first way -- the first thing you have to do is optimize how Quick Look will call your plug-in. You can specify static properties inside your info-plist of your plug-in, so QuickLook knows even before loading your plug-in, even before calling your callbacks what to do with your plug-in and how to call it. And once your plug-in is called you can specify some dynamic properties. We have already seen some with attachment stuff, but there are more. So you can help Quick Look previews once you have produced them.

So the main thing you will have to tell Quick Look is how thread friendly is your plug-in. Because quicklookd is multithreaded so we can dispatch several requests at the same time. By default we consider that your plug-in is not thread- safe, which means that we never, will never dispatch or pull in -- call your plug-in twice at the same time.

But if your code is thread-safe tell us you are using the QLSupportsConcurrentRequests property. But maybe your code does not even like being dispatched in a thread. Not just because of your code, but maybe because of the underlying frameworks you are using. For example, WebView does not like to be called in the non-main thread. So if this is the case you just have to tell Quick Look using the QLNeedsToBeRunInMainThread property.

The other static properties you can provide are the minimum thumbnail size, such as who else is calling your plug-in. Because maybe your thumbnail will produce if they are too small, they will be unreadable, not very useful, and in fact it's not worth calling them. So we'll just use the generic icon, and this will make things faster.

And so you can provide roughly the size of the preview, you will -- you will provide in the end. Maybe it won't be the exact size. But it is very important because the Quick Look panel has to be very reactive. When the users ask for the Quick Look panel, if your plug-in takes too long, the panel will still open. So if you provide that size in your info.plist we will be able to open it in a good size. So you won't have to resize it too much.

But once you are in your code, you know what the size of your previews will exactly be. So you can provide them using the PropertyWidth and PropertyHeightKey, so we can really size the prepanel accordingly. So the last property you can provide is display name. The display name is used as the Quick Look panel title. When developing your plug-ins you will have to have two concerns. The first is performance.

It's as important as for Spotlight. Thumbnails need to be extremely fast, insanely fast. Because we are generally displaying a bunch of them. So if your plug-in takes time the user experience will be very bad. And it's even more important with the Cover Flow, because if your plug-in takes a real long time to produce thumbnails, the user will only see placeholders. This will defeat the whole purpose of the Cover Flow.

So you will have to find a balance between speed of generation and quality, and level of details. And we really think that the best way to provide thumbnails is just to pregenerate them inside your document and provide them directly using the QLThumbnailRequestSetImageWithData() API. Like we did for the MyBooks document.

It generally is the best way to provide thumbnails because it won't take too much size inside your document, and it will be very, very cheap to display. You won't have to load the whole document to see how you will lay out the whole thumbnail and stuff like that.

Previews need to be fast too. Maybe not as extremely fast, but really, really fast still. Because the user experience we expect from new parties, the user sees a thumbnail, an icon in Cover Flow, and opens a panel, and immediately you're sending him off to the QuickLook panel. And sees exactly what's in -- what's in the document.

But if your preview takes too long we will have to open the panel. And the user will see the loading indicator. And it's really, really a bad experience because we expect to really see the contents of the document right away. It's what all Quick Look is about. That it's quick.

So like for thumbnails you will have to find a proper balance. And in fact quicklookd won't let you take too much time. So -- think about reducing the number of pages if you are producing multipage previews for very large files. You don't need to provide the full details of your documents. We are not your application. So we -- thumbnails need to be extremely fast. Previews need to be fast too.

The other concern you might have is design. Of course, your thumbnails and previews have to be very good looking. But just focus on the content, because we are focusing on the decor. You focus on the content, and we will try to add the proper decor around your thumbnail. For example, we will add a nice icon touch, you will see in the Finder. Or we can -- we will be able to use a thumbnail in the 3D environment like the Cover Flow.

So don't add -- don't add bells and whistles in your thumbnails. Just the content. The same thing is true for your previews. Because you should not assume that your previews will just be displayed in the Quick Look panel. And in fact, they are not. They are also displayed inside the Cover Flow, for example. You have already seen that you can scroll through pages in Cover Flow. This is a preview. And this -- the previews are also used in the info panel of preview -- of Finder. And -- or the column preview, too. And we can use it everywhere, in fact.

So what should you remember about Quick Look? The goal of Quick Look was to move away from generic icons and to provide a visual information about the document contents using thumbnails. So thumbnails are compact so we can display a bunch of them. And if a user wants to he can really get a deeper look at his document content. But Quick Look is not about replacing your application. Your application provides the full level of details and full editing capabilities. This is your application, not Quick Look.

Previews are an interpretation of your document using a limited set of types. We have already seen that. Essentially, PDF, HTML, QuickTime, images, other stuff is not very useful, so don't worry about them. And you will have to pick the ones that is best suited to your documents for presentation. So really, it's very easy to provide thumbnails and previews for your documents.

It will -- they will integrate very nicely in Finder and other parts of the OS. So this is something very important for us. And once you have done that, it is very simple. Just use the Xcode template, fill in the info.plist implement the callback, and your documents will be in Quick Look in no time. Thank you.

( Applause )

[Jonah Petri]

So that's Spotlight and Quick Look. For more information Matt Formica is standing right over there. He's the Spotlight and the Quick Look evangelist. There is also a spotlight-dev mailing list, and there's tons of documentation on both of these technologies available. So please make use of that.

Also, we have a Spotlight and Quick Look Lab tomorrow from noon to 3 in the Mac OS X Lab. So please come down, bring your code, and a lot of people have actually made Spotlight plug-ins in the previous WWDCs right in the Lab and left with it basically in good shape. So we think you can do that with Quick Look also. So come by, and we will be there answering questions.