Graphics • 47:56
PDFKit is a powerful set of Cocoa classes that allows you to incorporate a rich PDF viewing experience in your application. PDFKit easily handles all the details relating to PDF display, navigation, selection, and searching. PDFKit also supports a variety of ways to customize your application's interaction with PDF documents. View this session to learn about leveraging the power of PDF in your application.
Speaker: John Calhoun
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon, everyone. I'm Travis Brown. I'm the graphics and imaging evangelist for Apple. And I'm one of the people who put together essentially all the content you're seeing in the graphics and media track this year. And if you look at at least what we've talked about in the sessions that we've had thus far, it's been a lot of new technology that's, you know, flashy.
Things like Core Image, really powerful new trends, harnessing the GPU, which are all very exciting. But one of the other things we want to bring to the table this year in Tiger is essentially looking at the technologies that we've already embraced in Mac. And figuring out ways to help developers better leverage those technologies. And one of the significant technologies that we do use in the 2D space in Mac OS X is PDF.
PDF is a fantastic, you know, graphic file format, which is the way we primarily use it to date. Where we use it as sort of a system-wide meta file that is not only, you know, high fidelity, but also gives us ability to interchange our content with other platforms. But really PDF is much more than that.
You know, Adobe's been very innovative with PDF and continues to move forward. And has really created sort of a standard for rich documents. And this is one area where the existing Quartz 2D API, which is primarily about drawing PDF, was, you know, not sufficient for a lot of what needs that PDF could empower or at least solve. So for Tiger we've created something called PDF Kit, which is essentially a technology that's designed to help developers leverage PDF in their applications. By handling a lot of the work we're making.
Relating to managing a PDF document. This is navigation, searching, various other features like printing. And we want to make it as easy as possible for all applications to participate in the PDF experience. Because we think that's a very important feature of Mac OS X. And it's also very beneficial to our mutual users. So I'd like to bring John Calhoun up on stage to actually take you through the session. Thank you.
Let's see. Okay, well, I'm going to talk real quickly about PDFKit just to tell you what it is, and then I'm going to go quickly to a demo to kind of show you what it is. Here's sort of a diagram shows you more or less where your application fits. In PDFKit, it's basically a suite of Cocoa classes, so, you know, to make a parallel to WebKit isn't a big stretch. In fact, there was a lot of inspiration that we had from the WebKit demo last year.
And this year, when we were working on preview for Tiger, what we decided to do was to create like a PDFKit that was a lot like WebKit, and you'll see that the preview application that's in Tiger is using, at least for the PDF portion, of preview is using PDFKit. So, I guess I'll go ahead and show you, yeah, the new preview. So, I'll start the demo.
And this is Tiger. This is on your developer disk. And here's the preview. Probably at this point, this being sort of early in Tiger, there's not going to be a lot different from what you've seen, say, in Panther. But I'll show you a couple of new things. And keep in mind that unlike Panther, this version of Preview is strictly using PDFKit. So I've opened up a PDF. You can select text.
We can scroll through the text as per usual. But also PDFKit is going to handle links. And you'll see the hand turning into a pointer and -- or turning into a pointing hand. The cursor, you click on it, it takes you to that page, that sort of thing. One of the new features we added to Preview by way of PDFKit is you can now view facing pages, for example.
And so here's two up. And if you want the cover sheet to be -- or the front cover sheet to be -- you can do that. And if I want the first page to be separated itself, I can turn on what we call book mode. And so now the first page stands by itself.
And then it starts with the even number of pages from then on. Another nice thing that we're able to do, for example, in 2UP, is you can select text across multiple pages. If I zoom out, I can grab text across four, six, eight, however many pages you can see. And all this, again, is using PDFKit.
I'll show you another document that's kind of interesting. I clicked on this widget up here and it didn't work because this document doesn't have a crop box that's any different from its media box. I do want to point that out because one of the reasons for showing these demos in advance is I'll show you something graphically and then when I get talking more about PDFKit, you'll see, you know, what, you'll know what concepts I'm talking about. So I've got a document here. It's a PDF. And when you default open it up on the screen, you see that it's a PDF.
You see the part of the PDF page that's defined by the PDF's crop box. But if I flip this little widget, you can see the whole PDF and you can see that there are some registration marks and some other things. This is actually the way the PDF would go off to the printer. But one of the things they try to do, not only just for the crop boxes, or sorry, for the registration marks and such, is sometimes the way a PDF gets printed, you'll have a lot of different things.
You'll have a lot of white space around the margin. So oftentimes a PDF will define a crop box so that when you're viewing it on a computer screen, you're not wasting screen real estate with all this, you know, extra margin. So this is the way you might, you might want to, you might view it on a computer.
And the last thing I'll show you on this sort of introduction to preview demo is something we just added for Tiger. Here's a 1040EZ. And if I click somewhere here, I can then... Tab does hit testing, that sort of thing, and I think this check box should check and uncheck and that sort of thing. So we're starting to add more annotation support, and the Panther version of Preview just had links.
Those were the only annotations we supported, and as you'll see when I show you the rest of these slides, we've got a lot more annotation support in the new version of Preview. But the point I'm trying to make is that we got this by way of PDFKit, so in the same sense that if your application uses PDFKit, you're going to get these same features yourself. So I'll switch back to slides.
And where did I leave that clicker? Okay, well, I'm going to backtrack just briefly and talk about the PDF file format. I'm not going to talk a lot about it, but if you know the PDF is a file format, and inside that PDF file you have dictionaries, you have objects like page objects, font objects, that sort of thing. There's streams for drawing. A PDF can be encrypted, in which case you need a password to decrypt it.
They're very rich. It's a very rich file format. And as I showed with the forms in 1040EZ and with links, there can be annotations inside a PDF. And I pointed out the display boxes, the media box, crop box. So PDFs have all this kind of rich features in them. I'll briefly mention the coordinate system, too, because it turns out it comes into play quite a bit when I talk about some of the kind of lower levels of the PDFKit.
PDFs are Cartesian coordinate system. It's quadrant one. So the lower left corner of the page is the origin, 00. And as you move to the right, the numbers increase. As you move up, they increase. And the units that are used inside a PDF are in points. So 72 points to an inch.
Well, so Core Graphics has a rich API for dealing with PDFs, and that's been in there for a long, long time. But they're C functions, and they sit on top of Core Foundation, so they have Core Foundation type objects. You have things like CGPDF document ref, CGPDF page ref, and that sort of thing. But it's relatively low level in that it sits fairly close to the file. It kind of mirrors more or less the file format itself. So what we tried to do in... PDFKit is to create a suite of Cocoa classes.
And in some ways, we mirrored Core Graphics in, you know, our decision to make a document object and a page object. And I'll get more -- I'll talk more about that later. But, you know, it's probably interesting to know that internally we're calling Core Graphics and we're calling Core Foundation and we're doing some of these things. But what we present to the developers is, you know, the Objective C, the methods and objects and that sort of thing. And as I mentioned, you'll see that there's like PDF documents and pages. So in that way, we kind of borrowed from Core Graphics.
Here's a class hierarchy. I'll go into a lot more detail, so I'm just putting this up for now. You see that I haven't shown all the classes here, but you see there are a number of classes in blue that are subclass of NSObject, and then the PDF view, the one orange one, is I guess we'd call more or less the higher level class. That's probably a good way to start talking about PDFKit is that there's kind of, I guess, two levels of classes. There's the high level PDF view, and that's nice because you can just drop it into your app.
It does most of the kinds of things you see in preview. It'll display PDFs. It'll allow you to select text, copy, traverse links, that sort of thing. So it makes it very simple if you want to get PDF display up in your app very quickly. But if you want to do more powerful things and have more flexibility, there's a whole suite of these utility classes. And in fact, the PDF view itself is built on top of those utility classes, and those are the ones in blue, like the PDF border, destination, that sort of thing.
So I'll show you another demo. I'm kind of doing this in reverse order. I'm showing you the demo first and then talking about what you saw. I'm going to do the, I guess this is a kind of a famous no code demo. WebKit did it, so we're going to do it too. So I'm going to fire up Interface Builder.
And one thing that I did before I came up here is I went to Interface Builder and I went ahead and added the PDFKit palette, which you'll find in developer extras palettes. And so since I've added the PDFKit palette, I just created a new Cocoa application here. You'll see that there's this new PDF icon. And so this object here is a PDF view.
I'll just drag it in and into this window here. And let's see. I think I'll just add a couple of buttons. Let's see. I'll put a back button in. And I'll just drag it in. I'll do a zoom button. I'll do some of the worst UI you've ever seen.
Okay, so let's zoom in, zoom out. And let me set the sizes on all these. Make that stretch, and this guy do this, and this guy do that. And that, and I guess the last thing I need to do is wire them up. So I'll just make that do. And here's some of the outlets or some of the methods that are exported from the PDF view. Go back. That's pretty nice when Interface Builder guesses that. Oh, couldn't guess that one. Let's zoom out.
And we'll make this one zoom in. So what I'll do is, so you may wonder how you're going to actually display PDF. I'll test the interface here. And there we go. PDF view supports drag and drop. So let me just take a PDF here. Here's a Nikon documentation. And there you go. So I haven't written any code. It looks like I messed up my bounds on the PDF view when I dropped it in. But I can, let's see, there were some links up front here. Let's see, we can jump down to page, 12, back, good.
We can zoom out, zoom back in. No? Okay, let me try one other thing. The PDF view also has a contextual menu. Oh, there we go. I don't know what my failing is there with those buttons. But so there, there's a PDF view, all done in Interface Builder.
[Transcript missing]
talk about the PDF view itself. So you saw the PDF view. I put it in Interface Builder. It's subclass of NSView. So, good, they fixed that slide. So it inherits everything that NSView inherits. It's a responder, so it has mouse down, mouse up, type methods, that sort of thing. And as I mentioned earlier, it uses all of the utility classes. So it uses a PDF document object, PDF page object, that sort of thing.
In fact, in as much as it's just sitting on top of those utility classes, there's nothing to keep you developers from, you know, if you don't like what PDFView does, maybe one up and two up isn't enough, you want to do three up, you can write your own PDFView.
You can just call the utility classes yourself and do all the sorts of things that PDFView does for displaying the pages and that sort of thing. And it's, I was going to say it's not a lot of work, but obviously it's a lot easier to use the PDFView itself.
And one of the things, but one of the things we tried to do is, so that you didn't have to go and write your own PDFView we tried where we could to make the PDFView itself sort of flexible for subclassers. So that you could come in and subclass and override the events, the mouse down, mouse up, mouse drag, and do your own thing.
And I'll show you at the end of the session here, I'll show you kind of a demo where I do that. There's also, every time the PDF view draws, there's a draw method that gets called. If you want to subclass or override that, then you can handle the page drawing yourself.
So some general features of PDFView. As you saw, you can display PDF in several modes, one up, two up, continuous, not continuous, that sort of thing. It also works with screen readers. So this is kind of interesting. If you're someone in accessibility, like someone who's not sighted and comes across a PDF, if your app is using PDFView, they'll be able to, using screen reader, be able to get the text of the PDF for free. So you don't have to write any code to enable that. Copy, select text, those kinds of preview type things, you get for free in PDFView, as well as printing.
I'm going to get into more specific features then. A PDF view needs a document. You tell PDF view, here's a PDF document, and once a document's been associated with the view, then it'll display that document and allow the user to navigate the pages and that sort of thing.
The way you create a document is you create one of the PDF document objects, and I'll talk about that a little later in the session. But you create these objects with either a URL, which maybe you have a file on disk, so you create a URL for that, create this PDF document, pass it to the view, and now you're looking at that PDF. Or sometimes you might be a plug-in for a browser, and you don't get a PDF file per se, you get a chunk of NSData.
So NSData is another way to initialize to create a PDF document, and then the view is therefore displaying the contents of that NSData. As I showed you in the interface builder demo, the view also supports drag and drop. So there's some pretty complicated display modes, and we tried to make it flexible enough initially for preview, but then we're trying to think sort of beyond preview and what other people might want. So you can... You can choose whether you want one up, two up, continuous, non-continuous, but you can also specify whether you want the crop box or the media box, what display box you want.
There's scaling, you saw me zoom in, zoom out, you can control that. Text greeking, you can specify at what pixel size you want the text to be greeked, which is to say once it falls below a certain size, like say three pixels, it gets to be kind of a waste performance-wise to draw each little curve of the text. So you can choose whether you want one up, two up, continuous, non-continuous, but you can also specify whether you want the crop box or the media box, what display box you want.
There's scaling, you saw me zoom in, zoom out, you can control that. Text greeking, you can specify at what pixel size you want the text to be greeked, which is to say once it falls below a certain size, like say three pixels, it gets to be kind of a waste performance-wise to draw each little curve of the text.
So you can choose whether you want one up, two up, continuous, non-continuous, but you can also specify at what pixel size you want the text to be greeked, which is to say once it falls below a certain size, like say three pixels, it gets to be kind of a waste performance-wise to draw each little curve of the text.
So you turn greeking on, set it to say three pixels, and the text will just be drawn very quickly as gray boxes. And I showed you the book mode. That's another mode. And there's other kinds of ways you can control the display of the PDF view, turning on and off page breaks, that sort of thing.
And then there's a really rich navigation API. So you can say go to the next page, previous page, first page, last page, or go to page in. Also, apart from just sort of that sort of page level navigation, PDF view is maintaining a history for you. So as you tell it go to page in, it's keeping a stack of where the user has been so that go back, go forward, you know, is another way of navigating. And you just tell the PDF view go back, and it's going to go back to where it was.
And it'll jump back to the last place the user was at before you said, you know, go to page in. And finally, there's other ways of navigating the PDF. You can say go to a specific destination, and I'll talk more about destinations later. Or you can say, you know, scroll to make the current selection visible, that sort of thing.
And then there are other kinds that I just called additional functionality, other things that don't really fit into a nice bucket. If the PDF is encrypted, you can pass in, there's a method to pass in a string to try as a password to decrypt it. You can select all, you can specify selection, you can clear a selection, and you can of course select text, copy, and it puts it up on the pasteboard for you. And it also allows you to print. You just tell the PDF view to print and it prints it. the current document.
Okay, so I guess this time around I'm going to show preview again. And what was I going to do this time? I guess I was going to show, I guess what I might call slightly more advanced preview functions. I think they're going to make sense when I start talking about the utility classes. Let's see.
I guess I'll open up a PDF that has a kind of a rich outline, because we'll talk about outlines. Look at that Quartz 2D ref. Okay, on the right-hand side, you'll see the outline, and this is just the way Panther displayed it as well. And I can twist down some of these little outline objects have children, and you can twist down the disclosure triangle and see some of the children of these outline objects. And when I click on one of these things, PDFView just scrolls down to the destination that this outline points to.
Another thing that I'll just show you, it's pretty obvious stuff, but let's do a search. I'll search for PDF. Okay, so. Here's a list of all the instances of PDF that are found. And again, as I go and scroll through this list of the search results, PDF view is jumping around and showing you and selecting and highlighting the selection.
So I want to show you one other thing before I switch back to the slides. I'll show you -- here's an annotations PDF I made up. So here's kind of a nutty file I made up that has all kinds of annotations on it. And you see -- well, the first one up there, it's actually a text annotation. And it's a little bit more complex than the other ones.
So I You see squares and circles and ink and that sort of thing. If I drag across here to select, you'll see that you'll be able to see kind of what part of the PDF is the text and what part is the annotation. All the stuff that's getting selected there is text, obviously. But, you know, I can't select the ink and I can't, you know, select the squares and that sort of thing. So I guess with that, I'll go back to the slides and I'll tell you more about some of the utility classes.
And we'll talk about annotations a little more. So here's actually the full list of utility classes. And what I'd left off on the previous sample when I showed this was I left off all the annotation subclasses. We'll get to those in a second. I have to start with PDF document. PDF document is sort of, well, it represents the file or the data that you have, the actual PDF file. And so it's the most important object. You have to have a PDF document.
Even a PDF view needs a PDF document. And it's kind of the wellspring. I mean, that's where pages are going to come from. That's where, you know, eventually the outline is going to come from and that sort of thing. And as I already told you, you can give it a URL or you can give it data. And that's how you initialize the PDF document.
Once you have this PDF document object, there's all kinds of methods to give you the attributes of the document. What PDF version is it? Is it encrypted? Who is the author, the creator, the title, keywords, that sort of thing. And if it's encrypted, there's methods on the document that allow you to try to decrypt it.
And if it's a kind of document where they have both sort of like owner privileges and user privileges, you can find out what privileges you have. Like, do you have the ability to print? Can you copy? That sort of thing. And in fact, PDF view respects the privileges.
So if you open a PDF using PDF view and the user doesn't have owner privileges and isn't able to print, then the print method will just fail. I mean, you can call down to the document and find out that there's no print permissions if you want to disable the print menu or put up a dialog or something like that.
PDF document also has a writing method. Now, if you got the PDF from a file and you want to write the PDF document out, since you already have it as a file, you might as well just copy the file. But when you call the PDF document's write methods, what it does is it sort of encapsulates any changes you may have made to the PDF document.
So if you've removed a page or rotated a page or removed an annotation or something like that, then when the PDF document is written out to disk, it will reflect all these changes you've made. And I'm going to show you how to do that. And I showed you a quick find and preview. PDF document is the level that you do that.
So you call find methods on the PDF document. What that allows you to do is, since it's at the document level, is first of all, it can start going through in sort of an asynchronous way and walk through page by page by page for you and just send notifications each time it finds the search term that you're looking for. Also, there's the capability to find a phrase, say, that's broken.
So if you were looking for a phrase and part of it was on one page and the second part was following on the next page, at the document level, you'd be able to find that sort of thing. And finally, and I'll have to get into more detail a little later about this, a PDF document is one area where you can ask for a PDF selection object.
Probably a trivial example at the PDF document level is if you wanted to do a select all, then that's where you would do it at the document level. And the document would allow you to do that. It would give you back a PDF selection object that represents all the text in the PDF and the entire document.
And finally, and this is probably the most important part of the PDF document, that's where you get the pages. That's where you get the page objects. So I'll talk about pages next. Oh, I guess obviously there's method on the document where you can ask for the number of pages, say 43. So on the document you would say, okay, 43 pages. Give me page number 41. And what you'll get returned is a PDF page object. Now this one has a graphic.
This slide has a graphic, and that's because pages are the first class that I'm going to talk about that have draw method. So I've got a screenshot, a preview here, and I've circled a few things so that you can see. This gives you an idea of some of the methods that a PDF page has.
You've got, of course, bounds and rotation, so that'll tell you how many points wide and tall, that sort of thing, the page is. A page can return to you a label. Now I've circled that in the lower corner. I think it's page 41 there. So if you're going to draw a page, you're going to want to make sure that you're drawing a page. So if you ask for this page's label, you'd get back the string 41. But there are some PDFs where they'll describe the page label as I or II if it's a preface or something like that.
So the page label gives you a string that represents what to label that page. Of course, you can get text from a PDF, and I've shown an orange box around the bottom. That's at the page levels where you can extract text. Annotations, and I've circled a link in there. So you can get text from a PDF, and I've circled a link in there. It's laying out its views. When a user scrolls and it wants to show page 3, it gets page 3 from the document, tells that page to draw, that sort of thing.
Annotations. So PDF annotation itself, the class PDF annotation, is an abstract class. So it's an error if you call the initializer on it. It doesn't mean anything. The two things that an annotation absolutely is required to have is a type and a bounds. So what we've done is you actually call the subclass initializer.
So if you wanted a PDF annotation circle, for example, you'd call PDF annotation circle, alloc, and then the method is init with bounds. So once you've done that, the annotation is legal. It has a type, circle, and it has a bounds. Now, a lot of the annotations share a lot of things besides the bounds and type, things like color is one that's common.
So you'll find inside the PDF annotation class, you'll find methods like color, kind, bounds, that sort of thing, contents. These are things that are just generally used by annotations. But for some of the annotations, subclasses like circle and ink, annotation line, there are going to be some attributes specific to that subclass. I think line is a good example. You see there's a starting and ending type.
So it can either have a square on the end or triangle or be dashed and that sort of thing. So it's only going to make sense to call get line ending style on a PDF annotation line. So that's kind of the way the annotations are organized. They also have a draw method.
And you can draw them individually if you want, but if a bit is set on the page, when you tell the page to draw, the page will go and draw all of its annotations. And I probably should have mentioned there's a way on PDF page that you can add and remove annotations and turn on and off this bit to say whether or not to display or not display its annotations.
Okay, I'll get to, okay, outline. So I guess we're going to step back again to the document. PDF outline, I showed you that in the preview example. You asked the document, not all PDFs have an outline. In other words, the author that created the PDF may not have taken the time to, you know, Add a list of chapters and subchapters and subheadings and that sort of thing. But if they did, then you ask the PDF document for the root outline. And what you get back is one of these PDF outline objects.
And I guess I can probably best describe them by referring to the example that's on the screen there. So the first thing that PDF outline objects will have are, I probably should describe these in a different order, can have children. And the root outline always has children. It's kind of the one outline object that doesn't have a label. It just has children. And in this example, the children are all the outline objects that you see, I guess the first level, I say, of the objects you see.
So the first child being one that's called contents, the next one figures, and the next one about this book, you see the disclosure triangle, that PDF outline will have children. So if you turn down the triangle, you'll see the children of that PDF outline object. All of these outline objects have a label, and that's what's actually important. So if you turn down the triangle, you'll see the children of that PDF outline object being displayed there. So contents is the label for the first child PDF outline.
And the other important thing, and I showed this in preview, is that PDF outlines have a destination. So that specifies when the user clicks on this outline, where do we go? Most of the time, the destination will refer to some place within the PDF document, you know, maybe page 27, you know, at a certain point on that page. But they can just be a little bit different. They can just as well describe a URL or something. They can actually point to another PDF document itself or point to some place on the web.
And that's a good sort of segue into PDF destination. So PDF destination is kind of an abstraction of this idea of where you're going to go when you click on a thing or something. PDF outlines, as I mentioned, have destinations. But also, a PDF annotation link has a destination.
When a user clicks on this link, is it going to open your browser and take you to a web page? Or is it going to go down to page 13 or whatever of the document? So it can be -- a destination can be a point on a page and a page for the document. Or it can be a URL. And I made a comment here about the back and forward history.
PDF view internally is using PDF destinations to keep the back forward history. So when the user says -- when you say go to page, you know, say 10, PDF view will make a destination for the current location. So the user's at page one. And push that onto a stack. So that then when you later say to the PDF view, go back, it just pulls that destination off the stack and says to the view, says to itself, go to this destination.
And this is PDF selection. So this is another one that's kind of an abstraction. You see an example there. There's some text that's selected. I mean, that's a pretty obvious, you know, that's what a PDF selection is visually. But internally what it is, is it's always associated with a specific PDF document. It doesn't make sense to have, you know, a selection on one document and then you ask another document to make this the current selection.
John Calhoun And so, you know, PDF selections are, you know, document specific. You can span multiple pages. So it's not just a range. It's not just, you know, from character five on this page to character nine. You can span multiple pages and it can be discontinuous. It doesn't have to be continuous. It can be the whole document.
I mentioned that the PDF document class itself has methods where you can say, give me a selection representing, I gave the example, the entire document, if you did select all. And within a page level, there are selection methods so that you can say, within a page, give me a selection that represents text that's inside this rectangle, or from this character to that character. So that's how you create these PDF selections.
Another way you get these PDF selections is that's actually, a PDF selection object is actually sort of the coin that the search uses. So that when you ask to search for a word like PDF in a document, every time it finds the instance of PDF, what it does is creates a PDF selection object for that and returns that to you. And so there are methods that you can call on the selection. You can find out the bounds of the selection for a given page space, or you can find out what page it's in. And that sort of thing.
And as you can also see, a PDF selection has a draw method as well. In this case, it takes whatever the current user's highlight color is and it draws in like a multiply mode to sort of overlay. And PDF page, or PDF view itself will draw the selection for you. So that's the kind of thing that if you're using a higher level PDF view, you don't have to really worry about.
Oh, I skipped this. I might as well mention. You can add PDF selections. They're kind of bullying in that way. If you have a selection here and a selection here, you can tell this selection to add that one. Like I said, they don't have to be contiguous. If they overlap, and you add the two selections, the parts that are overlapped get removed.
So when you ask for the string for a selection, like in this example here, if you ask for the string, you'd get update the in. If there was overlap and you had two selections added, you might get multiple characters, but we get rid of all those overlaps for you. Okay. This is the fun demo. The more fun demo.
Let's see. Okay, so I wrote this little app, and I'd like to say I wrote it in an hour, but it took a little longer than that. And I called it PDFKit Linker. And what I found was that it was a little bit more It's using PDFView. I'm just going to open this document here. But one of the nice things about it is since I'm using -- if I just use PDFView straight, I get all these kinds of things for free, like I can -- you see the tool tip comes up.
This link is going to take me to page 12. You see the cursor change into the hand for free. If I click on it, it handles the mouse down. It jumps me down to page 12. If I say go back, I've got that, go back, it jumps back to the beginning. So it's kind of recorded all that. But what I've done here is I've added this little widget and if you click on this, I call it my edit mode. This is where the subclass of PDFView really kicks in.
When you're not in edit mode, when you're what I call view mode, I'm just letting PDFView handle everything. So I'm still subclassing and I'm still overriding the mouse down, mouse up, but I'm just calling super. I call super and then let PDFView deal with, you know, the -- The link traversal, that sort of thing. But if you're in edit mode, I thought, well, this is where I'll have fun.
I'll take over the mouse down, the mouse drag, that sort of thing. I'll even -- since I've subclassed and overridden the draw method, I'll call super just so PDFView can draw the page, but then I'm going to come along after and I'm going to draw a gray rectangle around any annotation that I find.
So I can ask the view -- since the draw method gets called -- I can say, "Hey, I'm going to draw a gray rectangle around any annotation that I find." And I can say, "Okay, give me all the annotations for that page." I can walk through the annotations, figure out which ones are links. I can get the bounds of those link annotations and I can draw a gray rectangle. And so that's what I'm doing here.
And since I can handle hit testing, I can jump in and say, "Oh, you've clicked on one of these link annotations." So I'm going to remember that one and I'll draw it red and then I'll make this little get info button up here enabled. And then when you click on it, I'll ask that, "Link annotation, what page do you link to?" And it tells me page 12. So I say, "Okay, well I want to change that." I see there's one to 77. Here's some 77 pages. I'll just type in -- I'll type in 77.
Okay, I'll go back into view mode. Now when I move the mouse over, you can see that I've actually modified that annotation. I've changed its destination to point to page 77, and when I click on it, sure enough, I'm down here at page 77. And as just kind of more fun, if I go back into edit mode, click on new link, I've just now created basically a new annotation. And I've told the page to add this. And I've specified the bounds. I'm doing hit testing here myself, so I'm allowing the user to resize the bounds. And if I get info, I've just put some sort of default values in, page one.
Well, here's that URL aspect. I can, a destination can also have a URL. So I'll type in Nikon's web page and hit done. John Calhoun So what I've done now is I've told that, I've created this annotation link. I've set its destination to be this URL. I've added it to the page.
So now when I switch back to the page, I've added it to the page. So now when I switch back to view mode, you can see I'm kind of dragging on and off that PDF view recognizes, oh, there's an annotation here. And if I click on it, sure enough, it grabs the URL. It calls Safari, launches, and takes you to the Nikon website.
I don't know, there's a lot of UI here. It probably took a day or two, probably two days to write this. So I'll switch back to slides and I'll kind of go into a little more detail on the subclassing. And you'll kind of know what I'm talking about because you just saw an example of it there. So PDF view, as I mentioned earlier, it's a subclass of NSView, subclass of NSResponder. So it has mouse down, mouse up, mouse drag.
So you can override all these yourself. And that's what I was doing when I was in edit mode. I handled the mouse down. But when you want to be lazy and you're in, like, I had view mode, you can always just call super and let PDF view handle the mouse down itself.
[Transcript missing]
One thing that you have to do a lot if you subclass, and of course PDFView has to do a lot of this internally, is kind of converting from view space, is what I'll call it, to page space. So if the user has a mouse down, you know by way of PDFView, you have it sort of in view coordinates.
You know that they clicked here in the view. So what you need to figure out is first, what page did they click on? If you're trying to figure out if they clicked on a link annotation, you need to first figure out if they clicked on a page. So we have this page for point method, and you pass in a point, and it returns you the page, a page object representing the point that the user clicked on. You know, since there's border sometimes around the page if the user has zoomed out, sometimes they can click and it's not on a page. But if you pass in true for nearest, then it will return the nearest page.
In case the user didn't actually click physically on a page. So once you have the page, you want to figure out, okay, to figure out what annotation I may have, the user may have clicked on, I need to get that point into that page's space. So there's the methods convert point and convert rect to page, and convert point or convert rect from page. Well, to page means from the view's coordinate system to the page that I pass in.
So, you know, if I found out from page for point that I was on, you know, a PDF page object that represented page two, and then I say convert this point to page, you know, page object that represents page two, then this function will return that point back in that page's coordinates and say, okay, it's this point. This is the coordinate in that space. So then I can ask the PDF page, page two, for example, give me your annotations, and I can do a real simple hit test on the bounds of that point now in page space to all the bounds of the annotations.
Because all these methods on like the PDF annotation and on the page, all the coordinates, all the points and all the bounds and rectangles are all in page space. They don't really care if the user has zoomed in or is in two-up mode or anything like that. So that's what these methods do is they kind of bridge the gap from the PDF view to, you know, the page's space.
And the last thing is the draw method. So every time the PDF view is resized or the user scrolls or jumps to a new page, any time a page needs to be drawn, there's this draw page method that gets called. And the only thing passed to it is the PDF page object that needs to be drawn.
John Calhoun Now, what I was doing, and I kind of described it briefly in my demo app, is I've subclassed PDF view and I've overridden draw page, but I'm lazy and I want to let PDF view sort of draw the PDF, the selection, the annotations, so I just call super, super draw page. John Calhoun But when that returns, then I can go through and draw, you know, the little gray rectangles or that sort of thing. Each time, if you're in two up, for example, it'll get called 24.
John Calhoun If the user's looking at two pages, it'll get called twice. So it's not really, you know, like a draw or act method. I mean, it's not called for the view, it's called for each page in the view. John Calhoun Or if the user has scrolled down and you can see bits and pieces of three pages, then the PDF, the draw page method will get called three times, once for each page.
And I think that's it. Travis is going to come up and describe this stuff. I can tell you right off that the PDFKit palette is in Extras developer, developer Extras palettes, and there's already sample code in developer examples PDFKit. And that app that I just showed, PDFLinker, we'll make that available, but I started in writing that app, I started with the sample code that's on your Tiger DVD. Does Travis or somebody from the--there he is. All right, everyone. So we have some--thank you. Travis Scott: Thank you.
So we have some documentation and other information that will probably be available to you later tonight. What we're doing with our sessions this year is when we complete a session, we have supplementary information that we have basically created after everything was set and frozen to go on the DVDs that you received, the Tiger DVDs. We have these disk images you can download off connect.apple.com. And generally most sessions are going to have them, so you just basically go there and look.
It's sometimes going to be sample code, sometimes it's going to be sample code and preliminary documentation or both. So we evidently have some available for you for PDFKit. And then also we've included a handy URL up there for anyone who needs to really take a close look at the Adobe PDF specification. Because it is a specification that continues to grow and changes and gets more powerful. And it's handy to have the PDF reference on hand if you're doing anything with PDF.