PDF.js & Popcorn Maker

In the weeks after MozFest, the Popcorn team has been focusing on fixing up as many crash bugs ( crash = app breaking script errors ) as we can. In the down time between bugs we were given some free time to work on experimental features.

One feature that David Humphrey suggested we should look into is a way to include PDF's in Popcorn Maker. A while back, humph made a plugin for Popcorn.js that used the pdf.js library from Mozilla. It was the best place to start. I checked out the code, and tested it out. The plugin had some minor issues that needed to be worked out. I fixed up the plugin, fixing some loading issues and display issues, then I headed into Popcorn Maker to hack up an editor.

I "borrowed" the editor for the PDF plugin from the text and image editors. I used the simple layout from the text editor and pulled in the elements and styling for the image drag and drop from the image editor. To start, I used a simple URL input to test that the plugin was actually able to get the PDF to load into the app. It worked, but I had a serious problem. In the image I have above, the canvas that the PDF is being rendered in is the same size of the document. In Popcorn Maker, a plugin's overlay area can be of varying heights and widths, and will likely never be exactly the same size of the PDF. I hacked on it for a bit, but ultimately switched focus when I realized I had no idea what I was doing.

Putting the resizing issue aside, I started working on PDF uploading. Due to cross origin restrictions, it would be impossible to have a user simply drop a document into their browser and have it load in the app. Because the file originates from their local filesystem, the browser would not allow pdf.js to read the contents of the file. What I needed was a way for the PDF to be uploaded to cornfield (Popcorn Makers node.js based server). This wouldn't be too hard to accomplish, because we do something similar with images in the image editor. I created an API endpoint in cornfield that would listen for POST requests containing PDF files. The PDF would be saved into a folder on the server, and the response back to the app would contain the new URL to the resource. The editor could then take that URL and give it to the PDF plugin to load.

I did hit a few issues while attempting to upload the file to the server. Every time I tried to display the uploaded file, it seemed that somewhere in the transfer to cornfield the file was corrupted. It turned out that I was calling a function I didn't need to when sending the file via XHR. Simply passing the File object itself as the POST requests data was enough to have it upload to the server properly.

Once file uploading was working I hooked up the drag and drop code to it so that I could just drop a PDF file into the editor and it would automatically upload. All I had left to do was set up the plugin to automatically scale the PDF before rendering it on the canvas.  To get some headway on fixing the problem, I contacted a guy named Yury (@yurydelendik) in the #pdf channel on IRC.  With Yury's help I was eventually able to work out the kinks in the plugin.  It's now able to render PDF's on any canvas size, while maintaining it's aspect ratio and rotation.

So that's where I am right now. I still need to fix up some styling issues and add more features to the editor. I also need to make the PDF uploading in cornfield better, by ensuring that each PDF is never uploaded more than once. This will probably be achieved by getting a SHA of the file and setting it as the file name on the server, so that it can be compared to incoming data.

The code is up on Github for anyone who want's to try it out: http://github.com/cadecairos/butter/tree/pdf (the actual plugin can be found here)