{"id":28393,"date":"2022-03-24T19:56:24","date_gmt":"2022-03-24T19:56:24","guid":{"rendered":"http:\/\/convert-images-to-pdf"},"modified":"2025-03-02T15:07:28","modified_gmt":"2025-03-02T23:07:28","slug":"convert-images-to-pdf","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/","title":{"rendered":"Convert Images to PDF"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>PDF (portable document format) incorporates several technologies, including encryption, data compression, font management, computer graphics, and so on. All of this is designed to describe the contents of read-only documents and make them reliable for sharing among communicating parties while preserving layout and formatting to ensure consistency regardless of the viewing device or underlying software architecture.<\/p>\n<p>The wide adoption and the open-source nature of the PDF standard led to the creation of so many programs (most of which are free) to read or write to PDF files. The most common is the web browser or applications like Adobe Acrobat that fulfill this need. Most PDF writers require us to interact using a GUI to create <a href=\"https:\/\/cloudinary.com\/guides\/web-performance\/the-developers-guide-to-pdfs\">PDF files<\/a>. While this is fantastic for many use cases, it can become rather tiresome when we want to repeatedly generate PDF receipts for end-users or carry out some task of that sort. Several tools have been developed to create PDF files programmatically to fulfill this need.<\/p>\n<p>In this article, we will use <a href=\"https:\/\/pdf-lib.js.org\/\">PDF-LIB<\/a> in a simple <a href=\"https:\/\/reactjs.org\/\">React<\/a> application to create a PDF file, embed an image in it, and finally download the resulting PDF file.<\/p>\n<p>Here is a <a href=\"https:\/\/codesandbox.io\/s\/image-to-pdf-i4k54x\">link<\/a> to the demo on CodeSandbox.<\/p>\n<\/div>\n\n\n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/image-to-pdf-i4k54x?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"image-to-pdf-i4k54x\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n\n<div class=\"wp-block-cloudinary-markdown \"><h2>Project Setup<\/h2>\n<p>Let\u2019s start by creating a new React application using <a href=\"https:\/\/create-react-app.dev\/\">CRA<\/a>.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npx create-react-app image-to-pdf\n<\/code><\/span><\/pre>\n<p>Once that\u2019s done installing, we can install the dependency we\u2019ll need for our application.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npm install pdf-lib \n<\/code><\/span><\/pre>\n<p>The pdf-lib module will provide us with the APIs to create PDF files.<\/p>\n<h2>Building the UI<\/h2>\n<p>Replace the content of your <code>App.js<\/code> file to match the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'.\/App.css'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> { PDFDocument } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'pdf-lib'<\/span>;\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n      <span class=\"hljs-keyword\">const<\/span> &#91;file, setFile] = useState(<span class=\"hljs-literal\">null<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> fileToArrBuffer = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span>\n        <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>(<span class=\"hljs-function\">(<span class=\"hljs-params\">res, rej<\/span>) =&gt;<\/span> {\n          <span class=\"hljs-keyword\">const<\/span> fileReader = <span class=\"hljs-keyword\">new<\/span> FileReader();\n          fileReader.onload = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> res(fileReader.result);\n          fileReader.onerror = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> rej(fileReader.error);\n          fileReader.readAsArrayBuffer(file);\n        });\n      <span class=\"hljs-keyword\">const<\/span> downloadFile = <span class=\"hljs-keyword\">async<\/span> (blob) =&gt; {\n        <span class=\"hljs-keyword\">const<\/span> URL = <span class=\"hljs-built_in\">window<\/span>.URL.createObjectURL(blob);\n        <span class=\"hljs-keyword\">const<\/span> el = <span class=\"hljs-built_in\">document<\/span>.createElement(<span class=\"hljs-string\">'a'<\/span>);\n        el.download = <span class=\"hljs-string\">'mydummyfile.pdf'<\/span>;\n        el.href = URL;\n        el.click();\n        <span class=\"hljs-built_in\">window<\/span>.URL.revokeObjectURL(URL);\n      };\n      <span class=\"hljs-keyword\">const<\/span> embedImageInPdfAndDownload = <span class=\"hljs-keyword\">async<\/span> () =&gt; {};\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"App\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"file\"<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"btn-grey\"<\/span>&gt;<\/span>\n              {' '}\n              select image\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"file\"<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span>\n              <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span> setFile(e.target.files&#91;0])}\n              multiple={false}\n              accept=\"image\/*\"\n              name=\"file\"\n            \/&gt;\n            {file &amp;&amp; (\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/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\">{URL.createObjectURL(file)}<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"some_image\"<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{300}<\/span> \/&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span> {file.name}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n            )}\n            {file &amp;&amp; (\n              <span class=\"hljs-tag\">&lt;&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"btn-green\"<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{embedImageInPdfAndDownload}<\/span>&gt;<\/span>\n                  {'embed image in PDF and download'}\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/&gt;<\/span>\n            )}\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n      );\n    }\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> App;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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>In the body of our <code>App<\/code> component, we start by creating a state variable to hold and set the contents of our image file. Next, we define three functions, from top to bottom; the first two functions expect a Blob as a parameter. The first function, <code>fileToArrBuffer<\/code> uses the <code>FileReader()<\/code> module to read and return an <code>Arraybuffer<\/code> representing the chunk of bytes in the Blob(file).<\/p>\n<p>The second function, <code>downloadFile<\/code> as the name implies, creates a pointer to a Blob in memory and binds it to an anchor tag, after which it specifies the download attribute, which would signify the name of the downloaded file. In our case, we just called the file <code>dummyfile.pdf<\/code> because this function expects the Blob to be a PDF file. The anchor tag is then clicked programmatically to download the file, after which the pointer is deleted by the call to <code>revokeObjectURL<\/code> to avoid memory leak.<\/p>\n<p>The third function is responsible for creating the contents of the PDF file, including the image that will be embedded in it. The body of this function is intentionally left blank. In the sections that follow, we will incrementally update its contents and explain each step as we go.<\/p>\n<p>Our <code>App<\/code> component returns some basic JSX, such as an input field and its associated label to allow the user to select a file, an <code>img<\/code> element to render the selected image on the screen, and a button to trigger our yet to be defined <code>embedImageInPdfAndDownload<\/code> function.<\/p>\n<p>Add the following to your <code>App.css<\/code> file:<\/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\">    * {\n      <span class=\"hljs-attribute\">box-sizing<\/span>: border-box;\n      <span class=\"hljs-attribute\">font-family<\/span>: monospace;\n    }\n    <span class=\"hljs-selector-class\">.App<\/span> {\n      <span class=\"hljs-attribute\">text-align<\/span>: center;\n      <span class=\"hljs-attribute\">display<\/span>: grid;\n      <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">2rem<\/span>;\n      <span class=\"hljs-attribute\">max-width<\/span>: <span class=\"hljs-number\">470px<\/span>;\n      <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1.5rem<\/span>;\n      <span class=\"hljs-attribute\">margin<\/span>: auto;\n      <span class=\"hljs-attribute\">margin-top<\/span>: <span class=\"hljs-number\">4rem<\/span>;\n    }\n    <span class=\"hljs-selector-tag\">label<\/span>,\n    <span class=\"hljs-selector-tag\">button<\/span> {\n      <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1.4rem<\/span>;\n      <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#fff<\/span>;\n      <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0.5em<\/span> <span class=\"hljs-number\">0.9em<\/span>;\n      <span class=\"hljs-attribute\">cursor<\/span>: pointer;\n      <span class=\"hljs-attribute\">border<\/span>: none;\n    }\n    <span class=\"hljs-selector-attr\">&#91;type=<span class=\"hljs-string\">'file'<\/span>]<\/span> {\n      <span class=\"hljs-attribute\">display<\/span>: none;\n    }\n    <span class=\"hljs-selector-attr\">&#91;class*=<span class=\"hljs-string\">'btn'<\/span>]<\/span> {\n      <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">5px<\/span>;\n      <span class=\"hljs-attribute\">text-transform<\/span>: capitalize;\n    }\n    <span class=\"hljs-selector-class\">.btn-grey<\/span> {\n      <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#f2f2f2<\/span>;\n      <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#333<\/span>;\n      <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> solid <span class=\"hljs-number\">#888<\/span>;\n    }\n    <span class=\"hljs-selector-class\">.btn-green<\/span> {\n      <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#63dd47<\/span>;\n    }\n    <span class=\"hljs-selector-class\">.btn-blue<\/span> {\n      <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#0e80c9<\/span>;\n    }\n    <span class=\"hljs-selector-tag\">p<\/span> {\n      <span class=\"hljs-attribute\">display<\/span>: block;\n      <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">60%<\/span>;\n      <span class=\"hljs-attribute\">font-family<\/span>: monospace;\n      <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1.2rem<\/span>;\n      <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#000<\/span>;\n      <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#f00<\/span>;\n      <span class=\"hljs-attribute\">margin<\/span>: auto;\n      <span class=\"hljs-attribute\">text-overflow<\/span>: ellipsis;\n    }\n    <span class=\"hljs-selector-tag\">code<\/span> {\n      <span class=\"hljs-attribute\">display<\/span>: grid;\n      <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">4px<\/span>;\n      <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">1rem<\/span>;\n      <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#000<\/span>;\n    }\n    <span class=\"hljs-selector-tag\">section<\/span> {\n      <span class=\"hljs-attribute\">text-align<\/span>: center;\n      <span class=\"hljs-attribute\">display<\/span>: grid;\n      <span class=\"hljs-attribute\">justify-items<\/span>: center;\n      <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">1.4rem<\/span>;\n    }\n    <span class=\"hljs-selector-tag\">section<\/span> <span class=\"hljs-selector-tag\">span<\/span> {\n      <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">1.8rem<\/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>Create the Pdf File and Embed the Image<\/h2>\n<p>In the current version of our app, we can only select an image, but we are yet to create the PDF file. Over the next steps, we will be updating the contents of the <code>embedImageInPdfAndDownload<\/code> function to achieve this.<\/p>\n<p>First, let\u2019s use the <code>PDFDocument<\/code> class to create an instance of a pdf file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">const<\/span> pdfDoc = <span class=\"hljs-keyword\">await<\/span> PDFDocument.create();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><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>Since we want to display the selected image in the PDF file, we need to store it as a resource in the PDF.<\/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\">const<\/span> buffer = <span class=\"hljs-keyword\">await<\/span> fileToArrBuffer(file);\n    <span class=\"hljs-built_in\">console<\/span>.log({ buffer });\n    <span class=\"hljs-keyword\">let<\/span> image;\n    <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-regexp\">\/jpe?g\/i<\/span>.test(file.type)) image = <span class=\"hljs-keyword\">await<\/span> pdfDoc.embedJpg(buffer);\n    <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-regexp\">\/png\/i<\/span>.test(file.type)) image = <span class=\"hljs-keyword\">await<\/span> pdfDoc.embedPng(buffer);\n    <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">'please choose a JPEG or PNG file to proceed'<\/span>);\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>First, we convert our image to an array buffer by calling the <code>fileToArrBuffer<\/code> function we defined earlier. Next, we define a variable called <code>image<\/code> which will be used to hold information about the embedded image. The pdf-kit module only allows embedding <code>JPEG<\/code> or <code>PNG<\/code> files using the <code>embedJPEG<\/code> and <code>embedPNG<\/code> methods. So based on the image file type, we call the appropriate method, each of which returns an object stored in the <code>image<\/code> variable. The returned object contains information ( width, height, reference id, etc. ) about the image and some helper functions that will be used to manipulate the image.<\/p>\n<blockquote>\n<p>The <code>embedJPEG<\/code> and <code>embedPNG<\/code> functions also accept the image data contents as either base64, an array buffer, or a unit8Array.<\/p>\n<\/blockquote>\n<p>Having an image stored as a resource in a PDF file doesn\u2019t mean the image will be displayed when we view the PDF file. We need to create a page, reference our image as a resource for that page, and then paint it to the screen.<\/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\">    <span class=\"hljs-keyword\">const<\/span> page = pdfDoc.addPage();\n    page.drawImage(image, {\n      <span class=\"hljs-attr\">width<\/span>: image.scale(<span class=\"hljs-number\">0.5<\/span>).width,\n      <span class=\"hljs-attr\">height<\/span>: image.scale(<span class=\"hljs-number\">0.5<\/span>).height,\n      <span class=\"hljs-attr\">x<\/span>: <span class=\"hljs-number\">100<\/span>,\n      <span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-number\">100<\/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>We first create a page then draw the image on the page using the <code>drawImage()<\/code> method, where we specify two parameters: the image we want to draw and an object that defines the image options.<\/p>\n<p>We specified the <code>width<\/code> and <code>height<\/code> of the image to 50% of its original size to maintain its aspect ratio. We also specified the coordinates of the image, 100 points on both the x and y-axis. It is also important to note that in the PDF coordinate system, the bottom left part of a PDF page is the Origin, i.e., the <code>0,0<\/code> point, which means that the measurements will be taken from that point.<\/p>\n<p>Finally, we will need to download the resulting PDF file created.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">let<\/span> b64Chunk = <span class=\"hljs-keyword\">await<\/span> pdfDoc.saveAsBase64();\n    b64Chunk = <span class=\"hljs-string\">'data:application\/pdf;base64,'<\/span> + b64Chunk;\n    <span class=\"hljs-keyword\">const<\/span> blob = <span class=\"hljs-keyword\">await<\/span> (<span class=\"hljs-keyword\">await<\/span> fetch(b64Chunk)).blob();\n    downloadFile(blob);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><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>The pdf-kit module provides several options for getting the data representing the PDF file. In this case, we chose the <code>base64<\/code> option, and we are retrieving the resulting data by calling the <code>saveAsBase64<\/code> function. Remember that the <code>downloadFile<\/code> function we defined earlier expects a blob as its parameter to perform the download. To that end, we convert the <code>base64<\/code> encoded string to a Data URI and then use the <code>fetch<\/code> API to convert this data to a blob, which is then fed to the <code>downloadFile<\/code> function to save the resulting PDF locally.<\/p>\n<p>To view the running application, run this command in your terminal:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npm start\n<\/code><\/span><\/pre>\n<p>We should be able to embed an image in a PDF file and download the resulting PDF file.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_A5623C681B4B91830C0B4B6703EB090D58631BBC5D1B3FA81B027A13FCD18382_1645863444587_CleanShot+2022-02-26+at+12.16.47.gif\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"481\"\/><\/p>\n<p>You can find the complete project <a href=\"https:\/\/github.com\/ifeoma-imoh\/image-to-pdf\">here<\/a> on GitHub.<\/p>\n<h1>Conclusion<\/h1>\n<p>PDF has become the world\u2019s leading page description language for documents, and it can be used for different purposes. This guide describes a simple use case showing how to create a PDF file and embed an image in it.<\/p>\n<p><strong>Resources you may find helpful:<\/strong><\/p>\n<ul>\n<li>\n<a href=\"https:\/\/pdf-lib.js.org\/\">PDF-LIB<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/mozilla.github.io\/pdf.js\/\">PDF.js Documentation<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/reactjs.org\/\">React Documentation<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28394,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,246,371],"class_list":["post-28393","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-react","tag-under-review"],"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>Convert Images to PDF<\/title>\n<meta name=\"description\" content=\"This post describes how to embed images in PDF files.\" \/>\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\/guest_post\/convert-images-to-pdf\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Convert Images to PDF\" \/>\n<meta property=\"og:description\" content=\"This post describes how to embed images in PDF files.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-24T19:56:24+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-02T23:07:28+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"720\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\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\/guest_post\/convert-images-to-pdf\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Convert Images to PDF\",\"datePublished\":\"2022-03-24T19:56:24+00:00\",\"dateModified\":\"2025-03-02T23:07:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/\"},\"wordCount\":4,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/\",\"name\":\"Convert Images to PDF\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA\",\"datePublished\":\"2022-03-24T19:56:24+00:00\",\"dateModified\":\"2025-03-02T23:07:28+00:00\",\"description\":\"This post describes how to embed images in PDF files.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA\",\"width\":1280,\"height\":720},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Convert Images to PDF\"}]},{\"@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":"Convert Images to PDF","description":"This post describes how to embed images in PDF files.","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\/guest_post\/convert-images-to-pdf\/","og_locale":"en_US","og_type":"article","og_title":"Convert Images to PDF","og_description":"This post describes how to embed images in PDF files.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-24T19:56:24+00:00","article_modified_time":"2025-03-02T23:07:28+00:00","og_image":[{"width":1280,"height":720,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0-png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/"},"author":{"name":"","@id":""},"headline":"Convert Images to PDF","datePublished":"2022-03-24T19:56:24+00:00","dateModified":"2025-03-02T23:07:28+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/"},"wordCount":4,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA","keywords":["Guest Post","Image","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/","name":"Convert Images to PDF","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA","datePublished":"2022-03-24T19:56:24+00:00","dateModified":"2025-03-02T23:07:28+00:00","description":"This post describes how to embed images in PDF files.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA","width":1280,"height":720},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/convert-images-to-pdf\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Convert Images to PDF"}]},{"@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\/v1681924622\/Web_Assets\/blog\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0\/1a61b99c85114359389e9424a8383941234d0d2c-1280x720-1_28394645a0.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28393","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=28393"}],"version-history":[{"count":3,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28393\/revisions"}],"predecessor-version":[{"id":37098,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28393\/revisions\/37098"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28394"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}