{"id":96475,"date":"2017-06-27T07:00:00","date_gmt":"2017-06-27T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=96475"},"modified":"2019-03-13T01:13:21","modified_gmt":"2019-03-13T08:13:21","slug":"20170627-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170627-00\/?p=96475","title":{"rendered":"Extracting pages from a PDF document and saving them as separate image files, JavaScript edition with Promises"},"content":{"rendered":"<p><!-- backref: Extracting pages from a PDF document and saving them as separate image files, C# edition -->Last time<\/a>, we converted the C# version of the <a HREF=\"https:\/\/github.com\/Microsoft\/Windows-universal-samples\/tree\/v1.0.11\/Samples\/PdfDocument\">PDF Document<\/a> sample program so that it saved the pages to disk as image files. Today we&#8217;ll port those changes to JavaScript with Promises. <\/p>\n<pre>\nfunction viewPage() {\n  WinJS.log &amp;&amp; WinJS.log(\"\", \"sample\", \"status\");\n\n  var pageNumber = parseInt(pageNumberBox.value, 10);\n  if (isNaN(pageNumber) || (pageNumber &lt; 1) ||\n    (pageNumber &gt; pdfDocument.pageCount)) {\n    WinJS.log &amp;&amp; WinJS.log(\"Invalid page number.\", \"sample\", \"error\");\n    return;\n  }\n\n  output.src = \"\";\n  progressControl.style.display = \"block\";\n\n  \/\/ Convert from 1-based page number to 0-based page index.\n  var pageIndex = pageNumber - 1;\n\n  var page = pdfDocument.getPage(pageIndex);\n\n  <font COLOR=\"blue\">var picker = new Windows.Storage.Pickers.FileSavePicker();\n  picker.fileTypeChoices[\"PNG image\"] = [\".png\"];\n  picker.pickSaveFileAsync().then(outfile =&gt; {\n    if (outfile) {\n      outfile.openTransactedWriteAsync().then(transaction =&gt; {\n        var options = new PdfPageRenderOptions();\n        options.destinationHeight = page.size.height * 2;\n        options.destinationWidth = page.size.width * 2;\n        page.renderToStreamAsync(transaction.stream, options).then(() =&gt; {\n          transaction.close();\n        });\n      });\n    }\n  })<\/font>.done(() =&gt; {\n    page.close();\n    \/\/ Delete the code that sets the blob into the image\n    progressControl.style.display = \"none\";\n  });\n}\n<\/pre>\n<p>This is an uninspired direct translation of the C# code to JavaScript. We can imbue it with a little JavaScript inspiration by flattening the promise chain a bit. <\/p>\n<pre>\n  <font COLOR=\"blue\">var transaction;<\/font>\n  var picker = new Windows.Storage.Pickers.FileSavePicker();\n  picker.fileTypeChoices[\"PNG image\"] = [\".png\"];\n  picker.pickSaveFileAsync().then(outfile =&gt; {\n    if (outfile) {\n      <font COLOR=\"blue\">return outfile.openTransactedWriteAsync();<\/font>\n    }\n  })<font COLOR=\"blue\">.then(trans =&gt; {\n    transaction = trans;\n    if (transaction) {<\/font>\n        var options = new PdfPageRenderOptions();\n        options.destinationHeight = page.size.height * 2;\n        options.destinationWidth = page.size.width * 2;\n        <font COLOR=\"blue\">return page.renderToStreamAsync(transaction.stream, options);\n    }\n  }).then(() =&gt; {\n    transaction &amp;&amp;<\/font> transaction.close();<font COLOR=\"blue\">\n  })<\/font>.done(() =&gt; {\n    page.close();\n    \/\/ Delete the code that sets the blob into the image\n    progressControl.style.display = \"none\";\n  });\n<\/pre>\n<p>Instead of nesting the promises, I chained them, and each step of the chain checks whether the previous step succeeded before proceeding. (If not, then that step does nothing.) <\/p>\n<p>Alternatively, I could&#8217;ve thrown the Promise into an error state, but WinRT tries to reserve exceptions for unrecoverable errors, primarily out-of-memory conditions for a small allocation, or a programmer error. Errors that a program is expected to recover from are generally reported by an in-API mechanism. (There are notable exceptions to this principle, primarily in the I\/O area.) <\/p>\n<p>Anyway, you may have noticed that I used arrow functions, which are feature of ES6. Next time, I&#8217;m going to take it even further. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trying it out a different way.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-96475","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Trying it out a different way.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96475","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=96475"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96475\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=96475"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=96475"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=96475"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}