You have no poppy, and you again found the pages in the incoming letter? What's wrong with them?
The last time after a thorough search "how to view iPages", there was a simple and elegant solution. And note, this is not a satellite-powered chainsaw.

1. Rename the extension to .zip
2. Open the received archive and find a pdf file in it.
3. Profit!
')
Do you think we only stopped at this? We were so inspired by the inspiration that we filed a
service for automatic conversion, we are
considering monetization schemes .
Under the cut you will find a detailed explanation of how this works.
In fact, .pages, like some formats for MacOS, store special preview data in .pdf format.
So that it was not boring in the implementation, instead of processing on the backend, we decided to play muscles on js.
Yes, because of this, the converter does not work in IE10 +
who uses it? , because it has no support for the URL (everything else can be done emulated). But you don’t need to upload anything to the server, everything works on the client, which means instantly (and still safe, you don’t send anything anywhere).
So how does this work?
Pages is a zip-container (by the way, like docx, xslx and other office formats of the new generation).
Inside it lie:
-index.xml - the main presentation file
-buildVersionHistory.plist - a file with metadata, what it does is understandable by name
-QuickLook / Thumbnail.jpg - miniature picture for preview inside the folder
-QuickLook / Preview.pdf - the preview file itself, which opens in macOS by pressing the spacebar.
How we get files by drag-n-drop or via input - was told a hundred times, this is not interesting, let's skip this step.
We received this file, and in order to read the file, we need to run FileReader.
Scripts working with files have a different format at the entrance - someone accepts Blob, someone accepts a binary string. We took js-unzip, one of dozens of easy-to-go solutions. We took for simplicity and clarity.
It requires a string as input, so we run the FileReader in readAsBinaryString format:
if (file.type === "application/x-iwork-pages-sffpages") { var reader = new FileReader(); reader.onload = function (event) { processZip(event.target.result) }; reader.readAsBinaryString(file); }
Note that there is no useful information in the event itself, event.target actually refers to the reader, and one could write processZip (reader.result).
Almost all standards in browsers are very similar to each other in syntax, and FileReader is made with an eye to XMLHttpRequest, so everything will be quite familiar.
We will also skip the work with the zip archive - there are a lot of libraries on the network for this task, and each has its own syntax, especially since in this case zip is just a container, and I didn’t even have to plug in unarchiving mechanisms.
The most interesting thing happens at the end (this code does not correspond to what is on the site, for the sake of readability):
var uintArray = new Uint8Array(dataString.length); for (var i = 0; i < dataString.length; i++) { uintArray[i] = dataString.charCodeAt(i) } var blob = new Blob([uintArray], {type: 'application/pdf'}); gotLink(URL.createObjectURL(blob));
What's going on here:
A binary string in a text expression stores the ascii codes of its bytes. We create a special typed array (uint8array) from single-byte unsigned integers, also in the range from 0 to 255, and by-byte carry the numeric values of the characters of the string into it.
This is necessary so that the blob object (binary object in js) is created taking into account the fact that each number stores one byte - otherwise the characters can be interpreted differently and the file will be generated incorrectly.
At the same time, Blob itself accepts only arrays at the input, so we additionally have to wrap uintArray into a regular array.
Since the output link will be without a format, we additionally specify a mime type for the blob object.
And the biggest piece of magic on the site is through the function
URL.createObjectURL (blob)
we get a link to the blob in memory. That is, literally - as soon as we close the parent document, the link stops working.
The link looks like this:
blob: http: // localhost: 8005 / 4222c9ec-1c66-4143-96a8-4223482148f6
This is how you can get a separate file from the archive and give it back to the client without contacting the server.
Unfortunately, if there was no need for a link from URL.createObjectURL - you could rely on the server to read the file for ie9 - Blob.poly.js exists and you can work with it, but the base64 link on the output turned out to be of such size that the browser simply did not want to open it in a new window and hung.
PS If you find bugs (OS, browser version), write in a personal. I promise to fix it right away.
UPD All sources in a public
githaba repository