Extracting pages from a PDF document and saving them as separate image files, JavaScript edition with async


Last time, we converted the JavaScript version of the PDF Document sample program so that it saved the pages to disk as image files. The asynchonous behavior was expressed via Promises. Today we'll use the async and await keywords which didn't make ECMAScript 7, but may make it into ECMAScript 8. Support for it arrived in Microsoft Edge as an experimental feature back in 2015.

async function viewPage() {
  WinJS.log && WinJS.log("", "sample", "status");

  var pageNumber = parseInt(pageNumberBox.value, 10);
  if (isNaN(pageNumber) || (pageNumber < 1) ||
    (pageNumber > pdfDocument.pageCount)) {
    WinJS.log && WinJS.log("Invalid page number.", "sample", "error");
    return;
  }

  output.src = "";
  progressControl.style.display = "block";

  // Convert from 1-based page number to 0-based page index.
  var pageIndex = pageNumber - 1;

  var page = pdfDocument.getPage(pageIndex);

  var picker = new Windows.Storage.Pickers.FileSavePicker();
  picker.fileTypeChoices["PNG image2"] = [".png"];
  var outfile = await picker.pickSaveFileAsync();
  if (outfile) {
    var transaction = await outfile.openTransactedWriteAsync();
    var options = new PdfPageRenderOptions();
    options.destinationHeight = page.size.height * 2;
    options.destinationWidth = page.size.width * 2;
    await page.renderToStreamAsync(transaction.stream, options);
    transaction.close();
  }
  page.close();
  progressControl.style.display = "none";
}

The async and await keywords are analogous to their C# counterparts. Declaring a function as async causes it to return a Promise whose result is the nominal type of the function. Inside an async function, you can use the await keyword to cause the continuation to be connected to the resolution of the Promise you are awaiting.

There's not much interesting to discuss here; it's a straightforward translation of the C# sample. Note that JavaScript doesn't have a using keyword, so we have to close() the closable objects manually.

Next time, we'll move on to C++/CX.

Comments (7)
  1. kantos says:

    Actually you’d need to translate the using into a try/finally because if an awaited promise is rejected the rejection is thrown by the runtime so you would need to ensure that is handled by your continuation. using handles that for you in all cases which is rather nice. My understanding is that RAII still applies to co_await in C++17 so that would be equivalent there.

  2. ECAMScript 8 ? I think you meant ECMAScript 8 (those darn pesky acronymic names)

    1. Scarlet Manuka says:

      ECAMScript, the new scripting language for camera applications. Use ECAMScript to take a set of separate image files from your camera and turn them into a single PDF!

  3. gdalsnes says:

    “Declaring a function as async causes it to return a Promise”
    But there is nothing returned from this function.
    Would be nice with example of the code calling viewPage() too.

    1. Voo says:

      No the function does return a Promise, just one without any additional data.

      It’s the difference between Task and Task.

    2. David Trapp says:

      Not quite – from the view of the outside code, the function is now returning a promise. The promise is resolved to `undefined` however because the function doesn’t “return” a value.

      1. David Trapp says:

        (For clarification: The “not quite” was directed to gdalsnes)

Comments are closed.

Skip to main content