We may need to switch formats whenever we need to deliver image content to our users, depending on business requirements and the user’s device configurations. This is especially true for image/PDF formats. In this article, we review how we can easily achieve this using Cloudinary and Nuxt.Js.
The complete project can be found on the CodeSandbox, you can fork it and add the following environment variables to your sandbox server to make it work.
NUXT_ENV_CLOUDINARY_CLOUD_NAME=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
The complete codebase can also be found on Github
We will be using beginner-level Nuxt.Js and Express.Js in this tutorial. Thus we recommend previous knowledge and experience in JavaScript and Vue.Js.
Node.Js, Express.Js, and Nuxt.Js knowledge and experience are not a requirement.
Ensure Node.Js is installed on your system. Npx also needs to be installed as well. It is shipped by default since npm 5.2.0, npm v6.1, or yarn.
Run the following command to create the project
yarn create nuxt-app nuxtjs-image-pdf-converter
We recommend installing axios
during the prompt as we will use it to interact with the Express.Js server.
Since we will have both client and server-side operations, we recommend selecting the Universal (SSR/SSG)
rendering mode and Server (Node.Js hosting)
deployment mode.
Here is a compilation of our recommended setup:
-
Project Name: nuxtjs-image-pdf-converter
-
Programming Language -> JavaScript
-
Package manager -> Yarn
-
UI Framework -> TailwindCSS
-
Nuxt.Js modules -> Axios
-
Linting tools -> None
-
Rendering mode -> Universal (SSR/SSG)
-
Deployment target -> Server (Node.Js hosting)
-
Development tools -> None
-
Continuous integration -> None
-
Version control -> Git
Once the above setup is complete, Enter the project folder with the following command:
cd nuxtjs-image-pdf-converter
Cloudinary doesn’t come installed by default in Nuxt.Js, thus we need to install the recommended package using the following command
yarn add @nuxtjs/cloudinary
# OR
npm install @nuxtjs/cloudinary
Code language: CSS (css)
Once the dependency has been added to our project, let’s add @nuxt/cloudinary
as a module in our nuxt.config.js
modules section. This registers the package in our Nuxt.Js project.
// nuxt.config.js
export default {
modules: [
'@nuxtjs/cloudinary'
]
}
Code language: JavaScript (javascript)
To configure our Cloudinary instance, we’ll add a cloudinary
section to our nuxt.config.js
// nuxt.config.js
cloudinary: {
cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
secure: true
}
Code language: JavaScript (javascript)
We do not want our cloud name exposed in our project code. For this reason, we’ll create a .env
file. By default, this file is ignored by git
and will not be committed to our remote code repository.
// .env
NUXT_ENV_CLOUDINARY_CLOUD_NAME=my-cloudinary-cloud-name
Code language: JavaScript (javascript)
Nuxt.Js allows us to add our own custom middleware. We are going to use this to create an Express.Js API without creating our own dedicated external server.
We are first going to install Express.Js
yarn add express
# OR
npm install express
Code language: PHP (php)
We will create a file server-middleware/api.js
to handle our API requests:
// server-middleware/api.js
const app = require('express')()
app.all('/generate-pdf', async (req, res) => {
res.json({ data:'data' })
})
module.exports = app
Code language: JavaScript (javascript)
The above code enables our API to handle all api/generate-pdf
requests.
To register our API with Nuxt.Js we will need to register it in the serverMiddleware
section of nuxt.config.js
// nuxt.config.js
serverMiddleware: [
{ path: "/api", handler: "~/server-middleware/api.js" },
],
Code language: JavaScript (javascript)
This will ensure that all /api
requests are routed to our API.
To interact with Cloudinary from our Express.Js server, we’ll need to install the Node.Js SDK as well. We’ll use the following command to install it:
yarn add cloudinary
# OR
npm install cloudinary
Code language: PHP (php)
Once installed, we’ll need to load and configure the SDK in our api.js
// server-middleware/api.js
require('dotenv').config()
const cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
secure: true
});
...
Code language: JavaScript (javascript)
We do not want our API Key and Secret exposed to our code repository. We will thus add them to our .env
file
// .env
...
CLOUDINARY_API_KEY=secret-api-key
CLOUDINARY_API_SECRET=secret-api-secret
Code language: JavaScript (javascript)
Let us render a simple form allowing our users to upload images.
<!-- pages/images-to-pdf.vue -->
<form @submit.prevent="submit">
<input
multiple
accept=".jpeg,.jpg,.png,image/jpeg,image/png"
type="file"
name="images"
/>
<button type="submit">
Convert
</button>
</form>
Code language: HTML, XML (xml)
To convert images to PDF, we’ll first upload them to cloudinary. During the upload process, we’ll assign them a unique tag. We will then use this tag to generate the PDF.
We’ll use a Promise.all to ensure all the images are uploaded. Once the images are uploaded, we then call the api/generate-pdf
endpoint with the new tag as a query parameter. This request should return an instance object containing the secure_url
to our PDF document.
// pages/images-to-pdf.vue
export default {
data() {
return {
pdfUrl: null
};
},
methods: {
async submit(e) {
const randomTag = Math.random().toString(36).substring(7);
this.uploading = true;
const files = e.target.images.files;
const uploadedFiles = await Promise.all(
Array.from(files).map(async (file) => {
/* create a reader */
const readData = (f) =>
new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(f);
});
/* Read data */
const data = await readData(file);
/* upload the converted data */
return await this.$cloudinary.upload(data, {
upload_preset: "nuxtjs-image-pdf-converter",
folder: `nuxtjs-image-pdf-converter/images/${randomTag}`,
tags: [randomTag],
});
})
);
const resp = await this.$axios.get(`/api/generate-pdf?tag=${randomTag}`);
this.pdfUrl = resp.data.pdf.secure_url;
this.uploading = false;
},
},
};
Code language: JavaScript (javascript)
Within our api.js
, we will call on the cloudinary multi method. This is the method we will use to create a single PDF from all the uploaded images.
To do this, we will update the configuration we created for the route /generate.pdf
. This is the code contained in the app.all(..)
method we created earlier.
//server-middleware/api.js
app.all('/generate-pdf', async (req, res) => {
const pdf = await cloudinary.v2.uploader.multi(
req.query.tag,
{ format: "pdf" },
);
res.json({ pdf: pdf })
})
Code language: JavaScript (javascript)
We will call the method requesting cloudinary to create a new pdf
. We will then send back the response to our front-end.
We will then render a link on the front-end allowing our users to view the newly created PDF.
<!-- pages/images-to-pdf.vue -->
<a
:href="pdfUrl"
target="_blank"
>
View PDF
</a>
Code language: HTML, XML (xml)
We will first ensure that only PDF file types can be uploaded by our users. This can be done using simple HTML
<!-- pages/pdf-to-images.vue -->
<form @submit.prevent="submit">
<input
type="file"
accept="application/pdf"
name="pdf"
/>
<button>Convert</button>
</form>
Code language: HTML, XML (xml)
On upload, we will upload the PDF document to cloudinary. We will receive an object containing the public_id
and the pages
in the document on upload. We will then use this data to generate URLs rendering each page as an image.
To achieve this, let us add the following code to the section of our pages/pdf-to-images.vue
file. You can find the whole file on github here.
// pages/pdf-to-images.vue
export default {
data() {
return {
images: null,
};
},
methods: {
async submit(e) {
this.uploading = true;
const file = e.target.pdf.files[0];
/* create a reader */
const readData = (f) =>
new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(f);
});
/* Read data */
const data = await readData(file);
/* upload the converted data */
const upload = await this.$cloudinary.upload(data, {
upload_preset: "nuxtjs-image-pdf-converter",
folder: `nuxtjs-image-pdf-converter/PDFs`,
});
this.images = [];
for (let page = 1; page <= upload.pages; page++) {
this.images.push({
page,
url: this.$cloudinary.image.url(upload.public_id, {
page,
}),
});
}
this.uploading = false;
},
},
};
Code language: JavaScript (javascript)
Once the images
array has been filled with the links, we can then render them for our users to view:
<!-- pages/pdf-to-images.vue -->
<ul>
<li v-for="(image, index) in images" :key="index">
<a
:href="image.url"
target="_blank"
>
Page {{ image.page }}
</a>
</li>
</ul>
Code language: HTML, XML (xml)
To run the project locally, use the following command in the nuxtjs-image-pdf-converter
project folder:
yarn dev
# OR
npm run dev
Code language: PHP (php)
In the above article, we have reviewed how to convert PDFs to images and vice versa with the help of Cloudinary. There are additional formats we can convert between with additional options. Feel free to review the resources to read on what’s possible.