{"id":21585,"date":"2017-09-18T16:38:27","date_gmt":"2017-09-18T16:38:27","guid":{"rendered":"http:\/\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary"},"modified":"2025-03-23T12:33:47","modified_gmt":"2025-03-23T19:33:47","slug":"how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary","title":{"rendered":"How to Build a Simple Multipage PDF Viewer with Vue and Cloudinary"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Cloudinary offers an interesting feature: The ability to generate images from the PDF files and pages. With Cloudinary, you can create thumbnail images of your documents for previewing purposes. It\u2019s useful when you don\u2019t want to grant user access to the content, but need to give them a sneak peek of what they\u2019re missing if they haven\u2019t downloaded the PDF yet.<\/p>\n<p>In this blog, we will share a hands-on example for building such solutions using Cloudinary. Here are the tools you\u2019ll need:<\/p>\n<ul>\n<li>\n<a href=\"https:\/\/cloudinary.com\">Cloudinary<\/a>: End to end image and video management service<\/li>\n<li>\n<a href=\"https:\/\/vuejs.org\">Vue<\/a>: Progressive JavaScript framework<\/li>\n<\/ul>\n<h2>Create a Vue Project<\/h2>\n<p>The best and easiest way to get started on a Vue project is via the command line tool. You can install it with npm using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm install -g vue-cli\n<\/code><\/span><\/pre>\n<p>This installation exposes Vue commands to the CLI, which you could use to perform various tasks including creating a new Vue project. Here is the command that creates a new project:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">vue init simple pdf-viewer\n<\/code><\/span><\/pre>\n<p><code>simple<\/code> is the project template we prefer to use as our very simple example, while <code>pdf-viewer<\/code> is the name of the project we are creating.<\/p>\n<p>This command creates a file, <code>index.html<\/code> with some simple markup. Feel free to empty this file and replace with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>Welcome to Vue<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">link<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.7\/css\/bootstrap.min.css\"<\/span> <span class=\"hljs-attr\">rel<\/span>=<span class=\"hljs-string\">\"stylesheet\"<\/span> <span class=\"hljs-attr\">integrity<\/span>=<span class=\"hljs-string\">\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz\/K68vbdEjh4u\"<\/span> <span class=\"hljs-attr\">crossorigin<\/span>=<span class=\"hljs-string\">\"anonymous\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">link<\/span> <span class=\"hljs-attr\">rel<\/span>=<span class=\"hljs-string\">\"stylesheet\"<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\/style.css\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/unpkg.com\/vue\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"app\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-center\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">\"color:#fff\"<\/span>&gt;<\/span>PDF Viewer<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-md-6 col-md-offset-3\"<\/span> <span class=\"hljs-attr\">v-if<\/span>=<span class=\"hljs-string\">\"file\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"preview\"<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"preview\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row pages\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-md-4\"<\/span> <span class=\"hljs-attr\">v-for<\/span>=<span class=\"hljs-string\">\"page in pages\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"page.url\"<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"img-responsive\"<\/span> @<span class=\"hljs-attr\">click<\/span>=<span class=\"hljs-string\">\"selectImage(page.page)\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row upload\"<\/span> <span class=\"hljs-attr\">v-if<\/span>=<span class=\"hljs-string\">\"!file\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-md-offset-4 col-md-4\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> @<span class=\"hljs-attr\">click<\/span>=<span class=\"hljs-string\">\"openWidget()\"<\/span>&gt;<\/span>Upload PDF<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"\/\/widget.cloudinary.com\/global\/all.js\"<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\/javascript\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"\/script.js\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>\n<p>Most of our dependencies are included via content delivery networks (CDNs) including Bootstrap, Vue and Cloudinary JavaScript SDK. We also include a <code>style.css<\/code> and <code>script.js<\/code> files, which we will need to create.<\/p>\n<\/li>\n<li>\n<p>There are three bootstrap-generated rows:<\/p>\n<ul>\n<li>The first shows a large preview of the PDF pages and is only active when the <code>file<\/code> property on the Vue instance is not null. It has an image whose <code>src<\/code> attribute is bound to a <code>preview<\/code> property.<\/li>\n<li>The second row displays a thumbnail of the PDF as images using a <code>pages<\/code> array on the Vue instance. When each of the images are clicked, the <code>selectImage<\/code> method is called to update the larger viewer.<\/li>\n<li>Finally, the third contains a button to open the Cloudinary upload widget.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Before we start seeing the logic in action, create a <code>.\/style.css<\/code> and update with the following basic CSS:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">html<\/span>, <span class=\"hljs-selector-tag\">body<\/span>, <span class=\"hljs-selector-id\">#app<\/span>, <span class=\"hljs-selector-class\">.container<\/span> {\n  <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100%<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.preview<\/span> {\n  <span class=\"hljs-attribute\">margin-top<\/span>: <span class=\"hljs-number\">40px<\/span>;\n}\n<span class=\"hljs-selector-tag\">img<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: block;\n  <span class=\"hljs-attribute\">margin<\/span>: auto;\n  <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">#E1E1E1<\/span>;\n  <span class=\"hljs-attribute\">box-shadow<\/span>: <span class=\"hljs-number\">0px<\/span> <span class=\"hljs-number\">3px<\/span> <span class=\"hljs-number\">6px<\/span> <span class=\"hljs-number\">0px<\/span> <span class=\"hljs-built_in\">rgba<\/span>(<span class=\"hljs-number\">0<\/span>,<span class=\"hljs-number\">0<\/span>,<span class=\"hljs-number\">0<\/span>,<span class=\"hljs-number\">0.3<\/span>);\n}\n\n<span class=\"hljs-selector-class\">.upload<\/span> {\n  <span class=\"hljs-attribute\">margin-top<\/span>: <span class=\"hljs-number\">30%<\/span>;\n  <span class=\"hljs-attribute\">margin-left<\/span>: <span class=\"hljs-number\">14%<\/span>;\n}\n\n<span class=\"hljs-selector-tag\">button<\/span> {\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#687DDB<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">10px<\/span> <span class=\"hljs-number\">15px<\/span>;\n  <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">#e1e1e1<\/span>;\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#fff<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n}\n\n<span class=\"hljs-selector-id\">#app<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#687DDB<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.pages<\/span> {\n  <span class=\"hljs-attribute\">margin-top<\/span>: <span class=\"hljs-number\">20px<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Image Uploads with Cloudinary Widget<\/h2>\n<p>Now that we have a platform, let\u2019s start uploading PDF files. First create the JavaScript file we included earlier. Next create a Vue instance and add a method for uploading images:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">new<\/span> <span class=\"hljs-selector-tag\">Vue<\/span>({\n  <span class=\"hljs-attribute\">el<\/span>: <span class=\"hljs-string\">'#app'<\/span>,\n  methods: {\n    <span class=\"hljs-built_in\">openWidget<\/span>(url) {\n      window.cloudinary.<span class=\"hljs-built_in\">openUploadWidget<\/span>(\n        {\n          cloud_name: <span class=\"hljs-string\">'CLOUD_NAME'<\/span>,\n          upload_preset: <span class=\"hljs-string\">'UPLOAD_PRESET'<\/span>,\n          tags: &#91;<span class=\"hljs-string\">'pdf'<\/span>],\n          sources: &#91;\n            <span class=\"hljs-string\">'local'<\/span>,\n            <span class=\"hljs-string\">'url'<\/span>,\n          ]\n        },\n        (error, result) =&gt; {\n          console.<span class=\"hljs-built_in\">log<\/span>(error, result);\n        }\n      );\n    }\n  }\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>When the button is clicked, the upload widget pops up and should look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/image\/upload\/w_700,c_fill\/dpr_auto\/Screen_Shot_2017-08-27_at_11.22.59_AM_ckmg2f.png\" alt=\"Upload button\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1400\" height=\"1110\"\/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/image\/upload\/w_700,c_fill\/dpr_auto\/Screen_Shot_2017-08-27_at_1.31.19_PM_m86jzc.png\" alt=\"UPLOAD WIDGET\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1400\" height=\"1074\"\/><\/p>\n<p>The <code>openUploadWidget<\/code> method on the Cloudinary object takes a config and a callback method. The config must have at least a <strong>cloud name<\/strong> that is assigned on creating an account and an unsigned <strong>upload preset<\/strong> that can be generated from the settings dashboard.<\/p>\n<p>The callback function gets triggered once the upload is successful and is passed a payload of the upload information.<\/p>\n<h2>Showing Preview &amp; Thumbnails<\/h2>\n<p>Uploading a PDF file logs the result to the console. Hence, we need to start showing the PDF pages as image thumbnails on the view.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">new<\/span> Vue({\n  <span class=\"hljs-attr\">el<\/span>: <span class=\"hljs-string\">'#app'<\/span>,\n  <span class=\"hljs-attr\">data<\/span>: {\n    <span class=\"hljs-attr\">file<\/span>: <span class=\"hljs-literal\">null<\/span>,\n    <span class=\"hljs-attr\">preview<\/span>: <span class=\"hljs-literal\">null<\/span>,\n    <span class=\"hljs-attr\">pages<\/span>: &#91;]\n  },\n  <span class=\"hljs-attr\">methods<\/span>: {\n    openWidget(url) {\n      <span class=\"hljs-built_in\">window<\/span>.cloudinary.openUploadWidget(\n        {\n          <span class=\"hljs-attr\">cloud_name<\/span>: <span class=\"hljs-string\">'christekh'<\/span>,\n          <span class=\"hljs-attr\">upload_preset<\/span>: <span class=\"hljs-string\">'qbojwl6e'<\/span>,\n          <span class=\"hljs-attr\">tags<\/span>: &#91;<span class=\"hljs-string\">'pdf'<\/span>],\n          <span class=\"hljs-attr\">sources<\/span>: &#91;\n            <span class=\"hljs-string\">'local'<\/span>,\n            <span class=\"hljs-string\">'url'<\/span>,\n          ]\n        },\n        (error, result) =&gt; {\n          <span class=\"hljs-built_in\">console<\/span>.log(error, result);\n          <span class=\"hljs-keyword\">this<\/span>.file = result&#91;<span class=\"hljs-number\">0<\/span>];\n          <span class=\"hljs-keyword\">this<\/span>.preview = <span class=\"hljs-string\">`https:\/\/res.cloudinary.com\/christekh\/image\/upload\/w_350,h_400,c_fill,pg_1\/<span class=\"hljs-subst\">${<span class=\"hljs-keyword\">this<\/span>.file.public_id}<\/span>.jpg`<\/span>;\n          <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">let<\/span> i = <span class=\"hljs-number\">1<\/span>; i &lt;= <span class=\"hljs-keyword\">this<\/span>.file.pages; i++) {\n            <span class=\"hljs-keyword\">this<\/span>.pages.push(\n              {\n                <span class=\"hljs-attr\">url<\/span>: <span class=\"hljs-string\">`https:\/\/res.cloudinary.com\/christekh\/image\/upload\/w_200,h_250,c_fill,pg_<span class=\"hljs-subst\">${i}<\/span>\/<span class=\"hljs-subst\">${<span class=\"hljs-keyword\">this<\/span>.file.public_id}<\/span>.jpg`<\/span>,\n                <span class=\"hljs-attr\">page<\/span>: i\n              }\n            )\n          }\n        }\n      );\n    }\n  }\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Back to the callback function for the upload widget \u2013 when an image is uploaded, we attempt to do two things:<\/p>\n<ol>\n<li>Set a property <code>preview<\/code> with a large preview of the image using Cloudinary\u2019s URL transformation feature. We set the width to 350, height to 400 and page to 1. To convert the PDF page to an image, we just add an image extension at the end of the URL (<code>.jpg<\/code>).<\/li>\n<li>Secondly, we create smaller images (200 x 250) of all the pages in the PDF and store all the image URLs in a <code>pages<\/code> array. This array is iterated over and displayed on the view.<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-res.cloudinary.com\/image\/upload\/w_700,c_fill\/dpr_auto\/Screen_Shot_2017-08-27_at_11.23.19_AM_yuprxl.png\" alt=\"Image of Preview and Pages\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1400\" height=\"1074\"\/><\/p>\n<p>Lastly, we want to update the image preview when the thumbnails are clicked. We already have a bound <code>selectImage<\/code> method. Let\u2019s implement this method now:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">selectImage(page) {\n      <span class=\"hljs-keyword\">this<\/span>.preview = <span class=\"hljs-string\">`https:\/\/res.cloudinary.com\/christekh\/image\/upload\/w_350,h_400,c_fill,pg_<span class=\"hljs-subst\">${page}<\/span>\/<span class=\"hljs-subst\">${<span class=\"hljs-keyword\">this<\/span>.file.public_id}<\/span>.jpg`<\/span>\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>All it does is update the preview property by setting the page URL to the selected page. Of course the width and height will be 300 X 400 to match the dimensions of the previously previewed image.<\/p>\n<p>Another good point to be aware of is you could improve the quality of the image using the <code>dn<\/code> transformation parameter:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>https:\/\/res.cloudinary.com\/christekh\/image\/upload\/dn_50,w_350,h_400,c_fill,pg_${page}\/${this.file.public_id}.jpg\n<\/code><\/pre>\n<p>To even get more strict with the PDF contents, you can use Cloudinary\u2019s overlay feature to add watermarks to the images and protect the content. You can learn more about this feature from the <a href=\"https:\/\/cloudinary.com\/documentation\/image_transformations#image_and_text_overlays\">docs<\/a> provided by Cloudinary.<\/p>\n<h2>Conclusion<\/h2>\n<p>Cloudinary offers a lot more functionality for generating image previews and thumbnails from a PDF. Learn more about more about Cloudinary\u2019s <a href=\"https:\/\/cloudinary.com\/documentation\/transformation_reference\">image manipulation<\/a> capabilities, <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">sign up for free<\/a> to start using these features.<\/p>\n<p><em>This was originally posted on <a href=\"https:\/\/vuejsdevelopers.com\/2017\/09\/05\/vue-js-pdf-viewer\/\">VueJS Developers<\/a><\/em><\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":21586,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,177,315],"class_list":["post-21585","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-javascript","tag-vue"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Build a PDF Viewer with Vue.js and Cloudinary<\/title>\n<meta name=\"description\" content=\"This post shows how simple it is to build a Multi-Page PDF Viewer with Cloudinary and VueJS\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Build a Simple Multipage PDF Viewer with Vue and Cloudinary\" \/>\n<meta property=\"og:description\" content=\"This post shows how simple it is to build a Multi-Page PDF Viewer with Cloudinary and VueJS\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-09-18T16:38:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-23T19:33:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100-jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1540\" \/>\n\t<meta property=\"og:image:height\" content=\"847\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"How to Build a Simple Multipage PDF Viewer with Vue and Cloudinary\",\"datePublished\":\"2017-09-18T16:38:27+00:00\",\"dateModified\":\"2025-03-23T19:33:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary\"},\"wordCount\":12,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Javascript\",\"Vue\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2017\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary\",\"url\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary\",\"name\":\"Build a PDF Viewer with Vue.js and Cloudinary\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA\",\"datePublished\":\"2017-09-18T16:38:27+00:00\",\"dateModified\":\"2025-03-23T19:33:47+00:00\",\"description\":\"This post shows how simple it is to build a Multi-Page PDF Viewer with Cloudinary and VueJS\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA\",\"width\":1540,\"height\":847},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Build a Simple Multipage PDF Viewer with Vue and Cloudinary\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Build a PDF Viewer with Vue.js and Cloudinary","description":"This post shows how simple it is to build a Multi-Page PDF Viewer with Cloudinary and VueJS","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary","og_locale":"en_US","og_type":"article","og_title":"How to Build a Simple Multipage PDF Viewer with Vue and Cloudinary","og_description":"This post shows how simple it is to build a Multi-Page PDF Viewer with Cloudinary and VueJS","og_url":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary","og_site_name":"Cloudinary Blog","article_published_time":"2017-09-18T16:38:27+00:00","article_modified_time":"2025-03-23T19:33:47+00:00","og_image":[{"width":1540,"height":847,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100-jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary"},"author":{"name":"","@id":""},"headline":"How to Build a Simple Multipage PDF Viewer with Vue and Cloudinary","datePublished":"2017-09-18T16:38:27+00:00","dateModified":"2025-03-23T19:33:47+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary"},"wordCount":12,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA","keywords":["Guest Post","Javascript","Vue"],"inLanguage":"en-US","copyrightYear":"2017","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary","url":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary","name":"Build a PDF Viewer with Vue.js and Cloudinary","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA","datePublished":"2017-09-18T16:38:27+00:00","dateModified":"2025-03-23T19:33:47+00:00","description":"This post shows how simple it is to build a Multi-Page PDF Viewer with Cloudinary and VueJS","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA","width":1540,"height":847},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/how_to_build_a_simple_multipage_pdf_viewer_with_vue_and_cloudinary#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Build a Simple Multipage PDF Viewer with Vue and Cloudinary"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649723958\/Web_Assets\/blog\/Multi-Page_PDF_Viewer_2000x1100\/Multi-Page_PDF_Viewer_2000x1100.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21585","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=21585"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21585\/revisions"}],"predecessor-version":[{"id":37249,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/21585\/revisions\/37249"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/21586"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=21585"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=21585"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=21585"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}