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: wwdc2008-701
$eventId
ID of event: wwdc2008
$eventContentId
ID of session without event part: 701
$eventShortId
Shortened ID of event: wwdc08
$year
Year of session: 2008
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2008] [Session 701] Handling PD...

WWDC08 • Session 701

Handling PDF Content in Your Application

Media • 56:06

PDF Kit makes it easy for your Mac OS X application to display and navigate even the most complex PDF documents. Learn the simple steps for adding PDF viewing, page thumbnails and outlines to your Cocoa application. Understand the structure and content of PDF documents and see how to perform editing and annotation. A great session for any Cocoa developer utilizing PDF.

Speaker: John Calhoun

Unlisted on Apple Developer site

Downloads from Apple

SD Video (601.7 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

So what I'm going to cover today is I'm going to give you kind of an overview of the PDFKit framework, and then I'm going to spend the last three parts of the session talking about how you would use PDFKit. First, I'll show you how you would use PDFKit to display a PDF, which is what probably most people would like to do with PDFKit.

And then I'll show you kind of, I guess, a little more esoteric uses of PDFKit, how to create your own PDF content, and then how to use annotations. And annotations are kind of fun. I think if you came up with a list of fun things in PDFs, I think annotations would be on your short list.

It's an attempt at humor. OK, so let's get started. PDFKit framework-- so what is it? PDFKit is a suite of Cocoa classes, so if your application uses Cocoa or AppKit already, and you're familiar with NSWindow and NSView, PDFKit adds a whole bunch of more Objective-C classes that obviously are tailored towards PDF. And they work really well with the rest of AppKit. It sits on top of Quartz 2D.

So if you're familiar at all with the sort of PDF kind of underpinnings of Mac OS X, then you know that PDFKit sort of sits on top and leverages and extends that. If you've opened a PDF in Preview or opened up a PDF in Safari with the built-in PDF plugin, then you've seen PDFKit. All of the PDF displaying applications on the Mac OS X are using PDFKit. So it's-- it's actually a subframework part of the Quartz framework.

So if you go into System Library Frameworks, you'll have to add Quartz framework to your application. And then Quartz framework is sort of an umbrella. There are several subframeworks within it. PDFKit is one of them. It's been around since Tiger, and since we're talking about Snow Leopard now, that it seems like PDFKit has been around for quite a while.

So here are the classes. I'm not going to go into detail on all of them, but I just kind of wanted to throw them on one slide. I actually couldn't get them all on one slide because PDF annotation, the fifth one down, it has a whole number of subclasses. And I could, I gave you a couple of them kind of to be representative, but I couldn't show them all. And PDF Action also has subclasses. But here's basically, you know, the classes that you get with PDF Kit.

But to sort of kind of... PDF Kit is a great way to categorize PDF view and PDF thumbnail view. It's probably best to pull the first two out and call these the view classes. They have the word "view" in their name, but they're also both subclass of NSView. So all the kinds of things, if you're familiar with NSView, you know, it takes events, mouse clicks, has a draw routine, you add these things into Windows. These are the sorts of kind of properties that PDF view and PDF thumbnail view have.

PDF view, in fact, if you do open up a PDF in preview, the sort of main content area where the PDF is displayed is, in fact, a PDF view. And you probably guessed that the thumbnail view is sort of an accessory view for displaying thumbnails for that document. And the two view classes really integrate well together. And I'll show you an example of that in a few minutes.

The rest of the classes I'm just calling base classes. They're not subclass of NSView, they're subclass of NSObject. So in that way they are sort of more basic or more low level. And in fact the PDFView and ThumbnailView classes are really built on top of these sort of foundation-like classes.

That's not to say though that, I mean you could just use PDFView, but it actually turns out there are a lot of kind of interesting things that your application can do by directly, not indirectly, calling some of these base classes. And I want to just kind of highlight four of these base classes. And I'll call these the core base classes. They're PDF Document, PDF Page, PDF Annotation and PDF Outline.

PDF Document is going to be the object that represents a PDF file. Whether it's a file on disk or a file in memory, PDF Document is the representation of that. Now PDFs are comprised of pages, usually more than one. And so for each page within that PDF document, there's going to be a PDF page object. And PDF Document's going to create these page objects and retain them for each page in that PDF file.

Some pages have outlines on them. Here's a sample. It looks like there's a yellow highlight on the text at the top of that page and then there's a red ellipse at the bottom. These might be annotations and for each annotation that there is on a page, PDF Page will create a PDF annotation object.

And then finally, if a PDF has an outline, then there will be PDF outline objects to represent that outline tree. Now an outline, this is what Adobe Reader calls bookmarks. This is what Preview calls a table of contents. It's not all PDFs have the outline. When they do, it's nice.

It's kind of this tree structure that, you know, might list chapters or have some kind of way that allows the user to easily navigate the PDF file. So if it wasn't clear, I want to kind of summarize on this one slide that there is a kind of hierarchy here.

There's a kind of nestedness. You'll have a single PDF document object and that's the green box here and for each page on that, and that's going to represent this PDF. And each page in that file, there's going to be a PDF page object. And for each annotation on the page, the page will create annotation objects. And then sort of parallel to that, like page array, there's the outline tree.

And the document is going to own the root object and then each of those outline elements, if they have children, will own and retain those. So I've got kind of an example here of the outline root, which is the larger purple box, has two children. The first of which also has a child, just to give you an example. So anyway, that's more or less the framework kind of summary. So let's go ahead and start how we would use PDFKit.

So let's imagine that we want to write a kind of a lightweight PDF viewer. And obviously we want to be able to display PDF files, but we want to be able to, we want the user to be able to interact with these files. They should be able to select text. If there's a link or something in the document, they should be able to click on that link. And it works. If there's an outline for the PDF file, we should be able to display that as well.

Especially for the larger documents that tend to have the outline. I mean, that helps the user navigate. So we'll want to support that. And while we're, you know, making it easier to find things in the PDF, let's go ahead and allow text searching as well. So these are kind of the criteria, or rather the things we want to cover in our application. So how would we do that? Well, first we want to display text.

So we want to display a PDF. And the way we're going to do that is, I'm going to assume that you fire up Xcode and you create a new project. And if you use one of the Xcode templates, you'll probably want to use the document-based Cocoa application template. And so Xcode will create, you know, a nib file for you and a few classes.

And so what we'll probably do then is go into Interface Builder with that nib file and add some of these view classes that I mentioned, these PDF views. And then basically for displaying the PDF, we're using PDFKit. So let me go ahead and show you how you would use Interface Builder.

Just making sure I was on the right machine here. So here's Interface Builder and I'm going to create an application template here. Generally, like I said, if you've used Xcode to create your template, you'll already have this interface. And the important thing is that is this window, this NSWindow object that is created for you.

So here's our window and let me go into the, let me close the inspector here and bring up the library. And here are all your classes. Now, I could scroll through and try to find the PDF classes, but I'll just type PDF and it narrows the field down.

And here, in fact, here are the view classes. Here's the PDF view, the PDF thumbnail view. So I'll start by dragging a PDF view in to the window. And you'll notice that, you know, even as I drag it in and start to resize it, that there's already PDF view.

Now, this is kind of just a trick of an interface builder. Obviously, your application will have to load your own PDF content. And I'll drag a thumbnail view over here and size it. And what I'm going to do is I'm going to go to the window that I'm in and I'm going to go to the interface builder and I'm going to go to the interface builder.

Let me hold down, I'm going to hold the control key down and I'm going to drag over from the thumbnail view to the PDF view. Now in Interface Builder this is how you can wire up outlets. And you'll see that one of the outlets, the second one here is PDF view. So by selecting that I've essentially wired the PDF view outlet from the thumbnail view to the PDF view. So now they kind of have a relationship. The thumbnail view knows from which PDF view to get its thumbnails basically. So I've got my view classes added.

Let me set some springs. You know while I'm at it, if I go into the inspector here you can see for the example for the PDF view I can turn on, I can set some attributes just from Interface Builder. I can turn on automatic scaling. I can have it default to two up mode or single page mode or I'll just leave it in single page continuous.

Thumbnail view I've got set to two up mode. I can turn on automatic scaling. I can have it default to two up mode or single page mode or I'll just leave it in single page continuous. Thumbnail view I've got set to two up mode or I'll just leave it in single page continuous. Thumbnail view I've got set to two up mode or I'll just leave it in single page continuous. Um, thumbnail view I've got some attributes I can set from within Interface Builder as well. I'll just leave the defaults, though.

So, I've got the thumbnail view, the PDF view, I'm gonna select both of those and then embed these inside a split view, and set the springs on that. That way, uh, when the window resizes, the split view will also resize. And, um, now I've got everything kind of wired up, let me go ahead and try it out.

If I go into the file menu and run simulate interface, Interface Builder launches this simulator, and here's our window, it's opened up, and this time, uh, the thumbnail view has been told that there's a new document, and so the thumbnail view has gone off and fetched all the thumbnails here.

And as I'm scrolling the PDF view, I'm using the scroll wheel, by the way, on the mouse, as I'm scrolling the PDF view here, what it's doing is, it's sending out, um, page change notifications. And because we wired the, uh, outlet from the PDF thumbnail view to this PDF view, the thumbnail view knows which PDF view to listen to for these page change notifications.

And as the page is changing, the thumbnail view, um, is selecting the current page. And then similarly, I can click on pages inside the thumbnail view, and it does the hit detection and knows which PDF view to say, you know, go to page three or go to page four, or page five. I can select text in the PDF view.

I could copy and paste into text edit if I wanted. If there's a link, for example, here's a link annotation, the cursor turns into a hand, and I get a tool tip. I can click on that link, let go, and it takes me to that destination in the PDF view.

Um, I can even do some kind of crude editing. There's some drag and drop functionality built into the thumbnail view. Let's see, if I want to, for example, um, rearrange page one and two, I can just drag it like that, and now I've, I've reordered the, the PDF document. I can even drag in, uh, content. Here's an image, and the thumbnail view accepts image dragging, so, uh, dragging images in. I could even drag pages from one PDF document over to, to another PDF document. So, um, That's about it. I'll switch back to my slides.

So the first step there, kind of laying out the nib we did, and that turned out to be fairly straightforward. We added the PDF view, the thumbnail view, we wired up that outlet, and you saw all the text selection, the hit detection, the link traversal, that kind of stuff.

We can check both of the first two items off of our list. So I showed you PDF view and I did want to spend one slide kind of giving you a rundown of some of the methods that you'll find for PDF view. I mean, you can look in PDF view dot h and I think the header is fairly well documented.

There's at least a line or two, a comment for each method and I think it's fairly self-explanatory. But just to kind of give you just an overview of the kinds of methods you'll see in PDF view, there's methods for navigation. So go to page, in, go to preview. Go to previous page, go to next page.

In fact, when I clicked on a thumbnail in the thumbnail view, the thumbnail view itself was calling one of these methods on the PDF view. There are methods for changing the way the PDF view displays the PDF content. And you saw in interface builder I changed it from one up to up. There's a lot of other methods where you can turn on and off anti-aliasing, things like that.

There are methods for zooming in and zooming out. If you want to put some, you know, some text in there, you can do that. There are methods for, toolbar items in your application for zooming. There are methods for select, you saw that I could select text. There's methods for programmatically selecting text as well or getting the current selection.

And then there's print methods if you want to wire up printing to your PDF view. There's conversion routines for mapping between like a mouse click in the view and determining which page that mouse click was on and where sort of in the page's coordinate system that mouse click happened.

And there are notifications as well. And I showed you the one notification or I told you about it, the page changed notification. And your application can listen to that as well. And then there's like, I don't know, a whole host of other notifications as well. And there are other methods as well in the header, but I just kind of wanted to summarize, you know, the bulk of them here.

So let's get back to our application. Like I said, in interface builder, we cheat. I kind of, you know, conjure up some PDF files. I conjure up some PDF content just to make interface builder more interesting so you can see the effect of changing some of these attributes. But in your application, obviously, you've got to provide your own PDF content for your PDF view. Now, this is the line of code that you do that with or the couple lines of code.

Essentially, you're going to create a PDF document object. And I'm going to assume that you've already brought up the NSOpenPanel, for example, and the user has selected a PDF file. So you've got a URL for that PDF file. So to create a PDF document from that URL, you call this initializer on PDF document. So I've got document equals PDF document alloc init with URL, and I pass in that URL that the user has presumably selected.

And if it is a legitimate PDF file, you'll get back a PDF document object. So then the next line of code, my PDF view, I'm going to assume that you've got an outlet to that PDF view in your nib called my PDF view. So my PDF view is just an instance of PDF view. So the method on PDF view we're going to call is set document.

And we pass it that PDF document, and just that one line of code there kind of triggers off this whole kind of cascade of events. The PDF view now has a document. It actually sends out a document change notification. That's what the thumbnail view listens to. So the thumbnail view starts getting busy fetching thumbnails. The PDF view gets busy laying out its subviews and displaying the PDF content.

And so the other thing that the PDF view does is it reads. So that last line of code, I can go ahead and just release that PDF document. And if at any point in my application I need access to that document, I can just ask the PDF view for its document. Just as there's a set document, there's a getter as well. And I'll show you an example of that.

So PDF document, that's kind of the big base class. That's kind of the wellspring of all the other classes in PDF Kit. So I'll spend a slide on PDF document. If you look at PDF document dot H and look at what kinds of methods there are in that class, they kind of fall into these categories. You can find out the number of pages of a document and, for example, the thumbnail view calls that method to determine how many thumbnails to lay out.

You can, given that now you know how many pages there are, you can ask for a specific page. So you can say, give me the page at index zero, for example, to get the first page. And then you'll get back that PDF page object that the document has created for that page. There are methods for adding, removing, removing, and re-adding PDF documents. John Calhoun So PDF document, that's kind of the big base class.

That's kind of the big base class. A great session for any Cocoa application. Learn the simple steps for adding, removing, and annotation. A great session for any Cocoa application. Learn the simple steps for adding, removing, and annotation. removing, reordering pages in the document, and obviously the PDF thumbnail view is calling these methods.

There are, um, there's, like, metadata information about the document, so, um, modification date, um, author, creator. You can get that kind of information from the PDF document class as well. Um, searching. Since we're going to do searching in our application, um, I'll be coming back to this one, but this is where you would do the perform searching is at the PDF document level.

Um, the outline. Um, I kind of hinted at that earlier. Uh, that's where the outline root is, and again, we'll be using this in our application. I'll show you the, I'll show you this API specifically. And then finally, you know, if there have been editing, if pages have been added, removed, reordered, or if pages have been cropped or annotations added or removed, there's methods in PDF document for saving out a new PDF file that represents all those edits and those changes.

[Transcript missing]

It's called PDF Kit Viewer and I'm going to go ahead and open up, I'll open up the PDF spec 1.6.

And here's our PDF view and the split view more or less the same way I laid it out in Interface Builder. But over here on the left side, I kind of, to save screen real estate, I kind of nested the thumbnail view and the NS outline view under inside a tab view. But you'll see here that this particular PDF, it has an outline, but the root only has a single child called PDF reference. That's the label.

But if I twist down the disclosure triangle, you'll see that it has plenty of children. And as I'm clicking on these NS, as I'm clicking on these outline items here, you'll see that I'm getting the action and I'm telling the PDF view to perform that action and then the right thing is happening over here. Here's our search view. I'll type in a word, color, say, for example. And I've got this kind of split view within a split view, kind of Bento application. You'll see that I, I'm going to go ahead and do a little bit of a test.

I'm able to, from that PDF selection object, I'm able to tell them what page it's on, what section it's under, and as the user clicks on this, I can highlight in the PDF view where that instance is and I can scroll to that page as well. So if you want to download the sample code for PDF Kit Viewer and kind of comb through it and look at how all this is wired up, feel free to. I think you'll be surprised at how little code there is. Let's go back to my slides.

So that was the first kind of example of using PDF Kit. So now we're going to get into some slightly more, like I said, kind of esoteric stuff. I'll show you how you would create some new PDF content. So what I want to do for this part is create an application that will do watermarking.

I want to be able to take some string and plaster it on every single page in the PDF document. And I want this to, I guess I want to do it low enough level inside PDF Kit that all the sort of higher level things like the PDF view and the thumbnail view and the printing and the saving and all that stuff kind of picks up that overlay, that watermark. So the way I'm going to do that is to go down to one of the base classes in PDF Kit and subclass PDF Page.

So let me show you first over on the demo machine here what the application does, what it looks like. And then I'll explain to you how you would do that. So this also, PDF Watermarker, this also is an application that you can download. And this has even less code in it. So it's got a fairly simple window. It's got a string here for the watermark. And I've got a button here for selecting a PDF. So let me find a small PDF.

So we've opened up a PDF and the PDF view has populated now and the thumbnail view as well. And you'll see that our string, confidential, has been plastered on every single page. It's probably hard to see. I guess you can kind of make out. The thumbnails also picked up that string as well. And if I change the string, say draft, you'll see that the view is told to redraw and this time, you know, the word draft is superimposed or overlaid on every single page.

And if I save this PDF, I'll call it draft. I get this new PDF file and this is calling the PDF documents routine to write out that. Let me go ahead and open Adobe Reader and I'm going to by the way launch Adobe Reader a few times today just I guess to show you that you know there's no smoke and mirrors here. So here's real PDF content now and sure enough there's our watermark on every page.

So I'll go back to the slides. So the way we did that was subclassing PDF page. Because if you go back to-- if you go down to the PDF page level and can overlay your content, then as I say, every sort of class that sits on top of that is going to reflect that overlay.

The problem is, and this kind of goes back to that slide where I showed the sort of hierarchy or the nestedness of the base classes. The problem is that when I initialize a PDF document with a PDF file, it's going to go ahead and start creating these PDF page objects.

And we're trying to subclass PDF page. So we need a way to tell PDF document, don't create PDF page objects. Create, let's say, PDF page watermark classes. So the bad news is, in order to get PDF document to use our subclass of PDF page, we've got a subclass PDF document.

But the good news is, there's really only one method that we have to override in our PDF document subclass. And that's this method, page class. Now, this is the class that PDF document calls when it's creating pages. Now, the default implementation of page class is just to return PDF page class.

So we override this one method and instead return our own class, PDF page watermark class. So with this one kind of override, now the PDF document, when we initialize it with a file, will create several PDF page watermark classes. So what do we do? With the PDF Page Watermark class, we override this one method, Draw With Box.

But before I show you that code, PDF Page is kind of an important base class, so I'll give you kind of the one slide summary of the kinds of methods that you'll see in PDF Page. Because of that sort of nested nature, a page is owned by a document, so there's a method to find the parent or the owning document of that page.

You can get the bounds from a PDF page. Adobe's PDF spec defines all the coordinates in a PDF in points. That's 72 points to the inch. So the width and height, the bounds that you get back from a PDF page are going to be in points, as are, frankly, all the geometry in PDF Kit.

If the page has a rotation, you can find that out. Generally it doesn't, so you'll get back zero, but you can set that as well. The page creates annotations, so there are methods on PDF Page to get those annotations. There's methods for deleting, for adding annotations as well.

The page is where you get the text of that PDF page. So you can call a method on the page to get the text. And in fact, it's this method that PDF Document calls when you perform a search. It goes through each page of the document, gets its text, and searches through that text.

And then finally, there's Draw Method for the page. And this is important. This is how the page is created. This is how the PDF content gets displayed in a PDF view, as each PDF page is told to draw. And this is also important because this is the class, or rather, this is the method that we're going to override in our subclass, the Draw Method.

And here it is, PDF Page Draw With Box. So here's our override. And the first line of code inside our Draw With Box is to call Super Draw With Box. And the reason we call Super is because we're going to just let PDF Page go ahead and do that. So we'll let PDF Page go ahead and draw the PDF content, the basic PDF content itself. So we'll let PDF Page do the heavy lifting.

But when this function returns, or when this method returns, then we can kind of add any additional content that we want to overlay. So I'm going to assume you have that NSString that the user typed in as an instance called WatermarkString. And so I'm calling an NSString method there, Draw and Rect. And I assume that I've already calculated the destination rectangle. That'll be endpoints, by the way.

And then an attributes dictionary, the font, the size, the color, that sort of thing. So really a few lines of code. And that's why I say if you go and look at the sample code, there's very little code there. But because we did it at that PDF Page level, all the other kind of the view, the thumbnail view, the saving, the printing, we didn't have to touch any of that. It just, it kind of just percolates up.

So... Last part, I'm going through this a lot quicker than I thought I would. The last part has to do with annotations. Well, we'll have some fun with this section. So here's an interesting screen that shows you, by the way, a bunch of annotations. And, you know, I told you earlier I couldn't fit all of the PDF Kit classes on one slide because of all the annotation subclasses. Well, here are those annotation subclasses. And if you look at them, I think most of them, just the name itself is fairly descriptive.

I mean, I won't go into all of them, but I think, you know, a line annotation is a line, a circle. We've seen one of those already. A link annotation, that's when you, you know, those don't actually necessarily draw any content, but when the user clicks on a link, there's some action that happens.

So the PDF annotation class, that was that last base class. Let me just give you a one slide summary of some of the things that we've done. So, you can see here, you can see the methods that you'll find on PDF annotations in general. You can ask the annotation for its type. So, for example, a circle annotation will tell you its type is circle.

You can get the page that the annotation belongs to, get its kind of containing page. You can also get the bounds of the annotation. That's going to be in points, of course. And not only that, but combined with its parent, the page, you can kind of tell, based on the type, based on the parent's bounds and the annotation's bounds, you can determine where on that page that it's going to be displayed.

[Transcript missing]

So rather than talk more about annotations, I'll show you them on demo machine. Annotations are probably one of those things that lend themselves better to kind of showing than talking about. So the application is called PDF Annotation Editor and once again you can download the sample code for this. Here's that PDF that I had on my slide that has all those annotations on it.

I've just opened that up in a PDF view. If I select the text, by the way, you can see that very little of the content of this PDF is actually, you know, part of the PDF page itself. Most of it is our annotations. And for each annotation, I've got this kind of edit and test mode button down here. And suffice it to say, I mean I didn't really talk about this in the session, but you can look at the sample code.

What I'm doing is I'm subclassing PDF view in this case. And when we're in edit mode, I draw little gray boxes around all the annotations and I intercept all the mouse data. So that if I click on an annotation like this circle over here, I can intercept that mouse down and now I note which annotation is selected.

And this is kind of the interesting part of the application is over here I've got this annotation inspector, I guess. And depending on what kind of annotation you click on, I populate this palette with some of the attributes, some of the parameters for that annotation. So this is a circle annotation.

It's got a border color. It's got an interior color. It's got flags set to both display and also be printed if the user prints. It doesn't have an action associated with it. It does have a border with four points thickness and it's set to be dashed. This is a square annotation. It has a border color but no interior color. So I'm just calling in this application, I'm just calling these getters and setters to get these parameters. And I'm populating this inspector over here with that.

Let me open up a PDF that doesn't have any annotations on it though. It's that small one again. And I'll show you the other kind of fun thing about this app. I can go into the annotation menu and create any of those annotations. So let's go ahead and create a circle annotation. So if I go into the inspector I can change, it's got some kind of default values, but I can go and enter in like here's the line width for this annotation and I can bring up the color picker and I'll make it red.

Why not? Set the red, I can make it dashed, I can give it an interior color or not. So there's our circle annotation. It was all created programmatically just calling these classes or these methods in PDF Kit. I can add, let me add a stamp annotation. This is that one annotation, by the way, that I said doesn't really have any parameters that describe how to draw it. So a stamp annotation really pretty much requires an appearance stream.

If you create a stamp annotation with no appearance stream, even Adobe Reader doesn't really know what to do with it. It'll just kind of give you a box. So what I've done, and you can see how I've done this if you take a look at the sample code, is I've subclassed the stamp annotation in PDF Kit. And I overrode the draw method and I'm just drawing the string Apple here. Actually, I think it's a PDF.

So I'm scaling it to fit. I'm going to hit the bounds of the annotation. And if I save this, let me go ahead and place it here and hit save. If I save this PDF, and I'll call it annotated. And now go into Adobe Reader and open it up.

Again, this is kind of my showing you that there's my Apple stamp annotation being rendered from its appearance stream and the circle as well as even though it does have parameters. And in fact, let me just show you that one kind of conundrum since I do have time here. Let me go ahead and open up that annotated PDF again. One of the problems is since that PDF was written out, now there's an appearance stream.

And since the appearance stream wins when there's both parameters and appearance stream, I can go here and uncheck the dashed on the circle for example or change its thickness to one point and you don't see any change because we're still rendering the appearance stream. This is where you get kind of into a schism where like I said the parameters and the appearance stream don't necessarily have to match. In fact, if I do, if I resize this, you'll see that what's really happening is just the appearance stream itself is just being scaled to its bounds.

There's a method in PDFKit for basically stripping off the appearance stream and that's the kind of thing in this application I should probably add a button or something like that so that you could click a button and strip off that appearance stream and then you would see it rendered with its parameters instead.

So let me go back to the slides just for one last little tour through annotations. I was told by the way that this WWDC is kind of going to be geared towards, at least for the Mac OS X content, kind of geared slightly toward power user, power developer. So I thought I'd spend a couple of slides on widget annotations because these are by far the most kind of loaded annotations that the PDF spec defines. So a widget annotation is what most people think of when they talk about forms. These are the text fields, check boxes, radio buttons, the kinds of annotations that you see in a tax form, for example.

The type is actually widget. And why these kind of complicate things is, or why they're kind of the most loaded annotation is, that they kind of introduce a kind of like database-like quality to the PDF document. So if you have a text field, and the user types in a name, now there's kind of a name associated with that text field. So it kind of gets kind of database-like real quick. The annotations that PDFKit exposes for those widget annotations are these three: the button widget, choice widget, and text widget.

And one thing that all three of these have in common is, and this kind of alludes to that sort of database-like nature, is they all have a field name associated with them. So, you know, text widget, button widget, there's going to be a field name. And that name, even though the user never sees what this field name is, that essentially is the key into, or the field of that internal database.

So in global to the PDF document, there's going to be a field for whatever that field name is in that widget. And this is also a bit of a schism here as well, because, you know, while I kind of was implying that, you know, the document owns the pages, the pages own the annotations, that there's this kind of nestedness. For widget annotations, they kind of break outside their page, and the field name, at least, is document-wide.

And I'll show you the importance of that here on the next slide. So here's an example. Here's a text widget. And I've got a little screenshot there of a tax form, and I've highlighted one of the fields. And what you don't see is that there is a widget annotation that's laid basically just inside that box. I've typed in the string public, for example.

Now, internal in this document, I don't know what the field name is, unless I looked. I mean, the user actually doesn't see what the actual field name is. But I'm going to assume it's something obvious, like last name. So when I typed in the word public, then internal to the PDF document, it kind of goes to the field named public.

So it's a field named last name and assigns it the value public. And now, anywhere else in that PDF document, if there's a text widget, it doesn't matter what page it's on, you can have multiple on the same pages. If you have a text widget that has the same field name, it's going to be updated as well. So you change it in one place, it's going to be changed everywhere.

[Transcript missing]

There are on and off appearance streams. So depending on whether a button is in its on state or off state, its on or off appearance stream is rendered. So the widgets are told to redraw and based on their current state, the correct appearance stream is rendered. So again, let me just show you that.

I'm going to use the same application, PDF Annotation Editor. Except this time I prepared a PDF. I don't know what application you might be creating here, but here's a PDF that's got some nice rectangles in it. Here's name and a nice little box that's just begging for a text widget. So I'll go into the annotation menu and I'll go down to the text widget and we just created a text widget here and I'll try to place it more or less inside this box.

And over here on the inspector now, here's the text widget's field name. So I'll give it something meaningful. I'll call it name for example. Here's some other attributes we can set for that widget. I'll just leave them at their default values. But in order to show you kind of the way two widget annotations can share the same field name, I'll go ahead and create another text widget. And I'll just, I've only got a one page PDF so I'll just leave it on this page. And I'll give it the same name. I'll go ahead and create another text widget. field name.

This one, just to be different though, I'll change its alignment. So if I go back to my test mode here, now all the mouse events are being passed on to PDF view, you'll see already that the cursor has turned into an I-beam. So PDF view recognized that there's a text widget and has changed the cursor to an I-beam. If I click, an NS text field is created in the same place where that text widget was. And I can type a value here. I'll type Conan.

As I'm typing this value, you'll see that internally again the database value for the field name is being set to the string I typed, in this case Conan, the Barbarian, and then elsewhere in the document where there's the same field name shared, it's updated there as well. And I can come here and make changes and it just is reflected in both places.

So I'll show you an example of button widget. Here's gender, male, female, might be nice to have a button widget there. So I need to go back to my edit mode here. Let me make this, turn off the background, make it a radio button and I'll, I'm going to try to size it as best I can. So what do we want for a field name? Well, we're going to have two buttons and we want them to share the same field name. We want to link these buttons.

So I'll give it the name gender. But what I'm going to set for its on state value is male in this case. And then let me try to create another button widget and I'll try to make it more or less look like the other one and I'll try to position it as best I can.

Something like that. That's close. So this one, we also want the same field name, gender, but obviously, gender, but obviously we want a different on state value, so I'll set this one to female. So now when I go to test this, I'm going to go to the I can click in the male and we've just set the field gender to the string male and female doesn't match so it is not redrawn with its on appearance until I click on it and now male is redrawn and doesn't match so it's drawn with its off appearance and then here's my kind of last The proof is in Adobe. I'll call it widget. Save that PDF out, go into Adobe Reader, open up widget, and here's our text field.

"I'm going to try to type this correctly. And you see that it's reflected in both places. The buttons work as you would expect. So there you go." So that's it. Alan Schaffer is the man to contact if you want to email someone about anything, any questions. There's a lot of documentation online. Like I said, you can look in the headers, but if you want more of an overview of PDF Kit, there are documents you can download. Obviously, they're PDFs.

There's a bunch of sample code. I showed you three today that you can download, but there's other sample code I've done for previous WWCs you can download that cover different aspects of PDF Kit. And I think we've got a lab today at 2 o'clock, so if you have any questions or want to come down and see more of this stuff, I'll be here from about 2 o'clock until the end of the show today.