{"id":28276,"date":"2022-07-11T08:58:27","date_gmt":"2022-07-11T08:58:27","guid":{"rendered":"http:\/\/generate-a-watermarked-multi-paged-pdf"},"modified":"2023-10-11T15:26:13","modified_gmt":"2023-10-11T22:26:13","slug":"generate-a-watermarked-multi-paged-pdf","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/","title":{"rendered":"Generate a Watermarked Multi-Paged PDF"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><h2>Introduction<\/h2>\n<p>One of the ways to present your work is to create a portfolio. In this article, we will create a PDF portfolio with your branding from photos you upload to Cloudinary with a specific tag for instance \u201cWedding\u201d.<\/p>\n<p>Let\u2019s get started.<\/p>\n<h2>PHPSandbox and Github<\/h2>\n<p>The final project can be viewed on <a href=\"https:\/\/phpsandbox.io\/e\/x\/1uzuh?layout=EditorPreview&amp;defaultPath=%2F&amp;theme=dark&amp;showExplorer=no&amp;openedFiles=\">PHPSandbox<\/a> and the entire source code is available on my <a href=\"https:\/\/github.com\/musebe\/cloudinary-laravel-branded-pdf\">Github<\/a> repository.<\/p>\n<h2>Prerequisites<\/h2>\n<p>Using Cloudinary in your Laravel projects is pretty straightforward. However, for you to be able to easily follow along, you need to have a good command of your terminal, Git, and entry knowledge of PHP specifically with the Laravel framework.<\/p>\n<h2>Getting Started<\/h2>\n<p>Being that Laravel is a PHP Framework, we will need Composer. Like any modern PHP framework, Laravel uses Composer to manage its dependencies. Before, we can start ensure you have Composer installed on your machine. Follow step 1 below to install Composer and PHP.<\/p>\n<ol>\n<li>Install <a href=\"https:\/\/getcomposer.org\/\">Composer<\/a> and <a href=\"https:\/\/www.php.net\/manual\/en\/install.windows.tools.php\">PHP<\/a> on<\/li>\n<\/ol>\n<p>your development or production machine.<\/p>\n<ol start=\"2\">\n<li>\n<p>Install Laravel<\/p>\n<\/li>\n<li>\n<p>Via Composer:<\/p>\n<\/li>\n<\/ol>\n<p><code>composer create-project --prefer-dist laravel\/laravel cloudinary-branded-pdf<\/code><\/p>\n<ol start=\"2\">\n<li>Via Laravel Installer<\/li>\n<\/ol>\n<p><code>composer global require laravel\/installer<\/code><\/p>\n<p><code>laravel new cloudinary-branded-pdf<\/code><\/p>\n<ol start=\"3\">\n<li>In step 2 above we have installed the Laravel Installer and used it to scaffold a new application in the<\/li>\n<\/ol>\n<p>folder <code>cloudinary-branded-pdf<\/code>. With Laravel installed, we should be able to start and test the server ensuring<\/p>\n<p>everything is okay. Change the directory to the project folder and run the local development server by typing the<\/p>\n<p>following commands:<\/p>\n<p><code>cd cloudinary-branded-pdf<\/code><\/p>\n<p><code>php artisan serve<\/code><\/p>\n<p>The Laravel project is now up and running. When you open <code>http:\/\/localhost:8000<\/code> on your computer, you should see the<\/p>\n<p>image below:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/dgrpkngjn\/image\/upload\/c_scale,w_940\/c_limit,w_2000\/f_auto\/q_auto\/v1655976836\/assets\/laravel-running.png\" alt=\"Laravel Server Running\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"940\" height=\"484\"\/><\/p>\n<h2>Setting up Cloudinary\u2019s Laravel SDK<\/h2>\n<p>We will be using Cloudinary to generate multi-paged PDFs from images we will tag and upload. We will also perform the<\/p>\n<p>overlay transformation to add a watermark to each of the pages. Sounds fun, we will start by creating a<\/p>\n<p>free <a href=\"https:\/\/cloudinary.com\/\">Cloudinary<\/a> account.<\/p>\n<ol>\n<li>Sign up for a free Cloudinary account then navigate to the Console page and take note of your Cloud name, API Key and<\/li>\n<\/ol>\n<p>API Secret.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/dgrpkngjn\/image\/upload\/c_scale,w_940\/c_limit,w_2000\/f_auto\/q_auto\/v1655976836\/assets\/cloudinary_dashboard.png\" alt=\"Cloudinary Dashboard\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"940\" height=\"441\"\/><\/p>\n<ol start=\"2\">\n<li>Install <a href=\"https:\/\/github.com\/cloudinary-labs\/cloudinary-laravel#installation\">Cloudinary\u2019s Laravel SDK<\/a>:<\/li>\n<\/ol>\n<p><code>composer require cloudinary-labs\/cloudinary-laravel<\/code><\/p>\n<p><strong>Note<\/strong>: Please ensure you follow all the steps in the #Installation section. Publish the configuration file and add<\/p>\n<p>the Cloudinary credentials you noted in Step 1 to the <code>.env<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\"><code>\nCLOUDINARY_API_KEY=YOUR_CLOUDINARY_API_KEY\n\nCLOUDINARY_API_SECRET=YOUR_CLOUDINARY_API_SECRET\n\nCLOUDINARY_CLOUD_NAME=YOUR_CLOUDINARY_CLOUD_NAME\n\n<\/code><\/pre>\n<h2>Generating a Watermarked Multi-paged PDF<\/h2>\n<p>We will use Cloudinary\u2019s Upload API with the <code>multi<\/code> method which will take the images we upload, apply transformations and convert them to a PDF document.<\/p>\n<h2>Multiple File Upload with Livewire<\/h2>\n<p>To generate a PDF document we will need a user interface, we will use the Laravel package Livewire to build this.<\/p>\n<ol>\n<li>Install Livewire Package by running the following command in your Laravel project:<\/li>\n<\/ol>\n<p><code>composer require livewire\/livewire<\/code><\/p>\n<ol start=\"2\">\n<li>Include Livewire scripts and styles on every page that will be using Livewire. In our case <code>welcome.blade.php<\/code>:<\/li>\n<\/ol>\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\">\n...\n\n@livewireStyles\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n\n...\n\n  \n\n@livewireScripts\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n\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<ol start=\"3\">\n<li>We will then create a Livewire Component to handle our image uploads:<\/li>\n<\/ol>\n<p><code>php artisan make:livewire MultipleFileUpload<\/code><\/p>\n<p>This will create two files, first <code>app\/Http\/Livewire\/MultipleFileUpload.php<\/code> and the other one<\/p>\n<p>in <code>resources\/views\/livewire\/multiple-file-upload.blade.php<\/code><\/p>\n<p>Now you can use this component anywhere in your Laravel project using the following snippet:<\/p>\n<p><code>&lt;livewire:multiple-file-upload\/&gt;<\/code><\/p>\n<p>or<\/p>\n<p><code>@livewire('multiple-file-upload')<\/code><\/p>\n<ol start=\"3\">\n<li>Open <code>resources\/views\/welcome.blade.php<\/code> and add the following code within the <code>&lt;body&gt;&lt;\/body&gt;<\/code> tags as shown below:<\/li>\n<\/ol>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">\n  \n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"antialiased\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n@livewire('multiple-file-upload')\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/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\">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<p>This includes the Livewire component we created earlier in our <code>welcome.blade.php<\/code>.<\/p>\n<p><strong>Note:<\/strong> Please ensure you go through the <a href=\"https:\/\/laravel-livewire.com\/docs\/2.x\/quickstart\">Livewire documentation<\/a>,<\/p>\n<p>to learn how to install and set it up.<\/p>\n<ol start=\"3\">\n<li>Open the file <code>resources\/views\/livewire\/multiple-file-upload.blade.php<\/code> and populate it with the following code:<\/li>\n<\/ol>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">\n  \n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mb-5\"<\/span>  <span class=\"hljs-attr\">wire:submit.prevent<\/span>=<span class=\"hljs-string\">\"uploadImages\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"form-group row mt-5 mb-3\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"input-group mb-5\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"watermark\"<\/span>  <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span>  <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"form-control @error('watermark') is-invalid @enderror\"<\/span>\n\n<span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Choose files...\"<\/span>  <span class=\"hljs-attr\">wire:model<\/span>=<span class=\"hljs-string\">\"watermark\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"input-group-text\"<\/span>  <span class=\"hljs-attr\">for<\/span>=<span class=\"hljs-string\">\"media\"<\/span>&gt;<\/span>\n\nChoose watermark...\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n@error('watermark')\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"invalid-feedback\"<\/span>&gt;<\/span>{{ $message }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n@enderror\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"input-group mb-3\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"input-group-text\"<\/span>  <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"basic-addon1\"<\/span>&gt;<\/span>#<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"form-control @error('tag') is-invalid @enderror\"<\/span>  <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Portfolio Tag\"<\/span>\n\n<span class=\"hljs-attr\">aria-label<\/span>=<span class=\"hljs-string\">\"Portfolio Tag\"<\/span>\n\n<span class=\"hljs-attr\">aria-describedby<\/span>=<span class=\"hljs-string\">\"basic-addon1\"<\/span>  <span class=\"hljs-attr\">wire:model<\/span>=<span class=\"hljs-string\">\"tag\"<\/span>&gt;<\/span>\n\n@error('tag')\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"invalid-feedback\"<\/span>&gt;<\/span>{{ $message }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n@enderror\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"input-group\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"files\"<\/span>  <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span>  <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"form-control @error('files'|'files.*') is-invalid @enderror\"<\/span>\n\n<span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Choose files...\"<\/span>  <span class=\"hljs-attr\">wire:model<\/span>=<span class=\"hljs-string\">\"files\"<\/span>  <span class=\"hljs-attr\">multiple<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"input-group-text\"<\/span>  <span class=\"hljs-attr\">for<\/span>=<span class=\"hljs-string\">\"files\"<\/span>&gt;<\/span>\n\nChoose images for portfolio...\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n@error('files'|'files.*')\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"invalid-feedback\"<\/span>&gt;<\/span>{{ $message }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n@enderror\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">small<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-muted text-center mt-2\"<\/span>  <span class=\"hljs-attr\">wire:loading<\/span>  <span class=\"hljs-attr\">wire:target<\/span>=<span class=\"hljs-string\">\"files\"<\/span>&gt;<\/span>\n\n{{ __('Uploading') }}\u2026\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">small<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">small<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-muted text-center mt-2\"<\/span>  <span class=\"hljs-attr\">wire:loading<\/span>  <span class=\"hljs-attr\">wire:target<\/span>=<span class=\"hljs-string\">\"watermark\"<\/span>&gt;<\/span>\n\n{{ __('Uploading') }}\u2026\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">small<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-center\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span>  <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"btn btn-sm btn-primary w-25\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">i<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"fas fa-check mr-1\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">i<\/span>&gt;<\/span> {{ __('Generate PDF') }}\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">i<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"spinner-border spinner-border-sm ml-1 mt-1\"<\/span>  <span class=\"hljs-attr\">wire:loading<\/span>  <span class=\"hljs-attr\">wire:target<\/span>=<span class=\"hljs-string\">\"uploadImages\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">i<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\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\">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<p>This is our Livewire Component view, this basically will display a form with inputs for our watermark, tag, images<\/p>\n<p>files and a button.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/dgrpkngjn\/image\/upload\/c_scale,w_940\/c_limit,w_2000\/f_auto\/q_auto\/v1656858250\/branded-pdf\/assets\/cloudinary_branded_pdf_action_fodyw0.png\" alt=\"Cloudinary PDF UI\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"940\" height=\"719\"\/><\/p>\n<p>You will see the implementation in code shortly.<\/p>\n<h2>Implementation in Code<\/h2>\n<p>Open the file <code>app\/Http\/Livewire\/MultipleFileUpload.php<\/code>. Here, we are going to add a method that will handle the<\/p>\n<p>multiple files selected by the user, upload them to Cloudinary and save their <code>public_id<\/code>\u2019s in an array that we will use<\/p>\n<p>later on.<\/p>\n<p>Add the following code to this file.<\/p>\n<ol>\n<li>First, we use Livewires <code>WithFileUploads<\/code> to help us with file uploads, then create two variables <code>$media<\/code>\n<\/li>\n<\/ol>\n<p>and <code>$optimizedImage<\/code> which is an array that will contain the image URLs we get back from Cloudinary.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n<span class=\"hljs-keyword\">use<\/span>  <span class=\"hljs-title\">WithFileUploads<\/span>;\n\n  \n\n<span class=\"hljs-keyword\">public<\/span>  $files  =  &#91;];\n\n<span class=\"hljs-keyword\">public<\/span>  $watermark;\n\n<span class=\"hljs-keyword\">public<\/span>  $tag;\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\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ol start=\"2\">\n<li>Secondly, we will create the <code>uploadImages<\/code> function which will upload the <a href=\"https:\/\/cloudinary.com\/glossary\/image-watermarking\">watermark<\/a> and image files<\/li>\n<\/ol>\n<p>to <a href=\"https:\/\/cloudinary.com\">Cloudinary<\/a>. Cloudinary will apply specific transformations to each one of the images that will make the pages before generating the PDF document.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n<span class=\"hljs-keyword\">public<\/span>  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span>  <span class=\"hljs-title\">uploadImages<\/span><span class=\"hljs-params\">()<\/span>  <\/span>{\n\n...\n\n}\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\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ol start=\"3\">\n<li>Let\u2019s populate our method in step 2 above:<\/li>\n<\/ol>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n<span class=\"hljs-keyword\">public<\/span>  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span>  <span class=\"hljs-title\">uploadImages<\/span><span class=\"hljs-params\">()<\/span>  <\/span>{\n\n<span class=\"hljs-keyword\">$this<\/span>-&gt;validate(&#91;\n\n<span class=\"hljs-string\">'files'<\/span>  =&gt;  &#91;\n\n<span class=\"hljs-string\">'required'<\/span>,\n\n<span class=\"hljs-string\">'max:10240'<\/span>\n\n],\n\n<span class=\"hljs-string\">'files.*'<\/span>  =&gt;  <span class=\"hljs-string\">'mimes:jpeg,jpg,png'<\/span>,\n\n<span class=\"hljs-string\">'watermark'<\/span>  =&gt;  &#91;\n\n<span class=\"hljs-string\">'required'<\/span>,\n\n<span class=\"hljs-string\">'image'<\/span>,\n\n<span class=\"hljs-string\">'mimes:png'<\/span>,\n\n<span class=\"hljs-string\">'max:100'<\/span>\n\n],\n\n<span class=\"hljs-string\">'tag'<\/span>  =&gt;  &#91;\n\n<span class=\"hljs-string\">'required'<\/span>,\n\n<span class=\"hljs-string\">'string'<\/span>,\n\n<span class=\"hljs-string\">'max:20'<\/span>\n\n],\n\n]);\n\n  \n\n$watermarkPublicId  =  cloudinary()-&gt;upload(<span class=\"hljs-keyword\">$this<\/span>-&gt;watermark-&gt;getRealPath(),  &#91;\n\n<span class=\"hljs-string\">'folder'<\/span>  =&gt;  <span class=\"hljs-string\">'branded-pdf'<\/span>,\n\n<span class=\"hljs-string\">'public_id'<\/span>  =&gt;  <span class=\"hljs-string\">'watermark'<\/span>,\n\n])-&gt;getPublicId();\n\n  \n\n<span class=\"hljs-keyword\">foreach<\/span>  (<span class=\"hljs-keyword\">$this<\/span>-&gt;files  <span class=\"hljs-keyword\">as<\/span>  $file)  {\n\ncloudinary()-&gt;upload($file-&gt;getRealPath(),  &#91;\n\n<span class=\"hljs-string\">'folder'<\/span>  =&gt;  <span class=\"hljs-string\">'branded-pdf'<\/span>,\n\n<span class=\"hljs-string\">'width'<\/span>  =&gt;  <span class=\"hljs-string\">'794'<\/span>,\n\n<span class=\"hljs-string\">'height'<\/span>  =&gt;  <span class=\"hljs-string\">'1123'<\/span>,\n\n<span class=\"hljs-string\">'gravity'<\/span>  =&gt;  <span class=\"hljs-string\">'auto'<\/span>,\n\n<span class=\"hljs-string\">'crop'<\/span>  =&gt;  <span class=\"hljs-string\">'fill'<\/span>,\n\n<span class=\"hljs-string\">'tags'<\/span>  =&gt;  &#91;<span class=\"hljs-string\">\"$this-&gt;tag\"<\/span>],\n\n]);\n\n}\n\n  \n\ncloudinary()-&gt;uploadApi()-&gt;multi(<span class=\"hljs-keyword\">$this<\/span>-&gt;tag,  &#91;\n\n<span class=\"hljs-string\">'transformation'<\/span>  =&gt;  &#91;\n\n<span class=\"hljs-string\">'overlay'<\/span>  =&gt;  $watermarkPublicId,\n\n<span class=\"hljs-string\">'gravity'<\/span>  =&gt;  <span class=\"hljs-string\">'north_east'<\/span>,\n\n<span class=\"hljs-string\">'x'<\/span>  =&gt;  <span class=\"hljs-number\">0.02<\/span>,\n\n<span class=\"hljs-string\">'y'<\/span>  =&gt;  <span class=\"hljs-number\">0.02<\/span>,\n\n<span class=\"hljs-string\">'crop'<\/span>  =&gt;  <span class=\"hljs-string\">'scale'<\/span>,\n\n<span class=\"hljs-string\">'flags'<\/span>  =&gt;  <span class=\"hljs-string\">'relative'<\/span>,\n\n<span class=\"hljs-string\">'width'<\/span>  =&gt;  <span class=\"hljs-number\">0.15<\/span>,\n\n<span class=\"hljs-string\">'opacity'<\/span>  =&gt;  <span class=\"hljs-number\">80<\/span>\n\n],\n\n<span class=\"hljs-string\">'format'<\/span>  =&gt;  <span class=\"hljs-string\">'pdf'<\/span>,\n\n<span class=\"hljs-string\">'notification_url'<\/span>  =&gt;  env(<span class=\"hljs-string\">'CLOUDINARY_NOTIFICATION_URL'<\/span>)\n\n]);\n\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s talk about the code.<\/p>\n<ul>\n<li>\n<h3>Uploading the watermark<\/h3>\n<\/li>\n<\/ul>\n<p>We upload the watermark to Cloudinary and get the <code>public_id<\/code> which we will use later on.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n$watermarkPublicId  =  cloudinary()-&gt;upload(<span class=\"hljs-keyword\">$this<\/span>-&gt;watermark-&gt;getRealPath(),  &#91;\n\n<span class=\"hljs-string\">'folder'<\/span>  =&gt;  <span class=\"hljs-string\">'branded-pdf'<\/span>,\n\n<span class=\"hljs-string\">'public_id'<\/span>  =&gt;  <span class=\"hljs-string\">'watermark'<\/span>,\n\n])-&gt;getPublicId();\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>\n<h3>Uploading the images<\/h3>\n<\/li>\n<\/ul>\n<p>We upload the images selected by the user and apply the tag that they specified and some transformations to each one of them using a <code>for loop<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n<span class=\"hljs-keyword\">foreach<\/span>  (<span class=\"hljs-keyword\">$this<\/span>-&gt;files  <span class=\"hljs-keyword\">as<\/span>  $file)  {\n\ncloudinary()-&gt;upload($file-&gt;getRealPath(),  &#91;\n\n<span class=\"hljs-string\">'folder'<\/span>  =&gt;  <span class=\"hljs-string\">'branded-pdf'<\/span>,\n\n<span class=\"hljs-string\">'width'<\/span>  =&gt;  <span class=\"hljs-string\">'794'<\/span>,\n\n<span class=\"hljs-string\">'height'<\/span>  =&gt;  <span class=\"hljs-string\">'1123'<\/span>,\n\n<span class=\"hljs-string\">'gravity'<\/span>  =&gt;  <span class=\"hljs-string\">'auto'<\/span>,\n\n<span class=\"hljs-string\">'crop'<\/span>  =&gt;  <span class=\"hljs-string\">'fill'<\/span>,\n\n<span class=\"hljs-string\">'tags'<\/span>  =&gt;  &#91;<span class=\"hljs-string\">\"$this-&gt;tag\"<\/span>],\n\n]);\n\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>\n<h3>The <code>multi<\/code> method<\/h3>\n<\/li>\n<\/ul>\n<p>Through the <code>Upload API<\/code>, the <code>multi-method<\/code> allows us to apply transformations and generate the PDF from all the<\/p>\n<p>images with the <code>tag<\/code> that we pass to Cloudinary. We do this by specifying the <code>format<\/code> as <code>pdf<\/code> and applying the<\/p>\n<p>transformations that overlay our watermark on the images with this tag.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\ncloudinary()-&gt;uploadApi()-&gt;multi(<span class=\"hljs-keyword\">$this<\/span>-&gt;tag,  &#91;\n\n<span class=\"hljs-string\">'transformation'<\/span>  =&gt;  &#91;\n\n<span class=\"hljs-string\">'overlay'<\/span>  =&gt;  $watermarkPublicId,\n\n<span class=\"hljs-string\">'gravity'<\/span>  =&gt;  <span class=\"hljs-string\">'north_east'<\/span>,\n\n<span class=\"hljs-string\">'x'<\/span>  =&gt;  <span class=\"hljs-number\">0.02<\/span>,\n\n<span class=\"hljs-string\">'y'<\/span>  =&gt;  <span class=\"hljs-number\">0.02<\/span>,\n\n<span class=\"hljs-string\">'crop'<\/span>  =&gt;  <span class=\"hljs-string\">'scale'<\/span>,\n\n<span class=\"hljs-string\">'flags'<\/span>  =&gt;  <span class=\"hljs-string\">'relative'<\/span>,\n\n<span class=\"hljs-string\">'width'<\/span>  =&gt;  <span class=\"hljs-number\">0.15<\/span>,\n\n<span class=\"hljs-string\">'opacity'<\/span>  =&gt;  <span class=\"hljs-number\">80<\/span>\n\n],\n\n<span class=\"hljs-string\">'format'<\/span>  =&gt;  <span class=\"hljs-string\">'pdf'<\/span>,\n\n<span class=\"hljs-string\">'notification_url'<\/span>  =&gt;  env(<span class=\"hljs-string\">'CLOUDINARY_NOTIFICATION_URL'<\/span>)\n\n]);\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can check out the <a href=\"https:\/\/cloudinary.com\/documentation\/image_upload_api_reference#multi\">reference<\/a> for full<\/p>\n<p>details on the relevant options.<\/p>\n<p>On the <code>notification_url<\/code> we have specified we will receive a response from Cloudinary once our PDF has been<\/p>\n<p>successfully created. The response will be as follows:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">\n{\n\n<span class=\"hljs-attr\">\"url\"<\/span>:  <span class=\"hljs-string\">\"http:\/\/res.cloudinary.com\/dgrpkngjn\/image\/multi\/c_scale,fl_relative,g_north_east,l_branded-pdf:watermark,o_80,w_0.15,x_0.02,y_0.02\/f_pdf\/v1656857502\/Wedding%20Photos.pdf\"<\/span>,\n\n<span class=\"hljs-attr\">\"secure_url\"<\/span>:  <span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/dgrpkngjn\/image\/multi\/c_scale,fl_relative,g_north_east,l_branded-pdf:watermark,o_80,w_0.15,x_0.02,y_0.02\/f_pdf\/v1656857502\/Wedding%20Photos.pdf\"<\/span>,\n\n<span class=\"hljs-attr\">\"asset_id\"<\/span>:  <span class=\"hljs-string\">\"770deef5d2f1285e39565a1a77ebbe3d\"<\/span>,\n\n<span class=\"hljs-attr\">\"public_id\"<\/span>:  <span class=\"hljs-string\">\"Wedding Photos,pdf,c_scale,fl_relative,g_north_east,l_branded-pdf:watermark,o_80,w_0.15,x_0.02,y_0.02\/f_pdf\"<\/span>,\n\n<span class=\"hljs-attr\">\"version\"<\/span>:  <span class=\"hljs-number\">1656857502<\/span>,\n\n<span class=\"hljs-attr\">\"notification_type\"<\/span>:  <span class=\"hljs-string\">\"multi\"<\/span>\n\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><strong>Tip:<\/strong> Please be sure to change your Cloudinary settings to allow delivery of PDFs and ZIP files, this is disabled by default to prevent dthe istribution of malware.<\/p>\n<h2>Handling Cloudinary Responses<\/h2>\n<p>Webhooks are one of a few ways web applications can communicate with each other. We can receive Cloudinary\u2019s responses<\/p>\n<p>through a webhook and run processes that will do something like notify the user or ban the video.<\/p>\n<p>Create a <code>WebhookController.php<\/code> by typing the following command:<\/p>\n<p><code>php artisan make:controller WebhookController<\/code><\/p>\n<p>In the file created <code>app\/Http\/Controllers\/WebhookController.php<\/code> we will add the following code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n<span class=\"hljs-keyword\">public<\/span>  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span>  <span class=\"hljs-title\">cloudinary<\/span><span class=\"hljs-params\">(Request  $request)<\/span>  <\/span>{\n\n<span class=\"hljs-comment\">\/\/Verification<\/span>\n\n$verified  =  SignatureVerifier::verifyNotificationSignature(json_encode($request),  $request-&gt;header(<span class=\"hljs-string\">'X-Cld-Timestamp'<\/span>),  $request-&gt;header(<span class=\"hljs-string\">'X-Cld-Signature'<\/span>));\n\n  \n\n<span class=\"hljs-comment\">\/\/ If the signature is verified and moderation is rejected<\/span>\n\n<span class=\"hljs-keyword\">if<\/span>  ($verified  &amp;&amp;  $request-&gt;notification_type  ===  <span class=\"hljs-string\">'multi'<\/span>)  {\n\n<span class=\"hljs-comment\">\/\/ Get Secure URL<\/span>\n\n$secureUrl  =  $request-&gt;secure_url;\n\n<span class=\"hljs-comment\">\/\/ Notify user<\/span>\n\n...\n\n}\n\n  \n\n<span class=\"hljs-keyword\">return<\/span>  response(<span class=\"hljs-string\">'Unverified'<\/span>,  <span class=\"hljs-number\">401<\/span>);\n\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><em><strong>Tip:<\/strong><\/em> A webhook is a mechanism where an application can notify another application that something has happened.<\/p>\n<p>Since the notification from Cloudinary will be an external request we will need to allow it through the <code>VerifyCsrfToken.php<\/code> middleware to prevent CSRF errors.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n...\n\n<span class=\"hljs-keyword\">protected<\/span>  $except  =  &#91;\n\n<span class=\"hljs-string\">'webhooks'<\/span>\n\n];\n\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we will create the webhook route in <code>routes\/api.php<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n...\n\n<span class=\"hljs-comment\">\/\/webhooks client<\/span>\n\nRoute::post(<span class=\"hljs-string\">'webhooks\/cloudinary'<\/span>,  &#91;WebhookController::class,  <span class=\"hljs-string\">'cloudinary'<\/span>]);\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>And  finally, update  our  <code>CLOUDINARY_NOTIFICATION_URL<\/code>  in  the  environment  variables  file  <code>.env<\/code>  as  follows:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">\nCLOUDINARY_NOTIFICATION_URL=https:\/\/<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">app_url<\/span>&gt;<\/span>\/api\/webhooks\/cloudinary\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><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<p>Finally, we can see the results:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/dgrpkngjn\/image\/upload\/c_scale,w_940\/c_limit,w_2000\/f_auto\/q_auto\/v1656857825\/branded-pdf\/assets\/cloudinary_branded_pdf_success_foe1fn.png\" alt=\"Cloudinary Watermarked PDF Created\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"940\" height=\"468\"\/><\/p>\n<h2>Conclusion<\/h2>\n<p>Cloudinary makes it easy to generate a PDF by automating and applying some transformations. We can use this to create portfolios which we can then present to our clients.<\/p>\n<p>The possibilities are endless, check out Cloudinary for your A to Z media management &#8211; upload, storage, administration, manipulation, optimization, and delivery.<\/p>\n<p><a href=\"https:\/\/cloudinary.com\/signup\">Get started<\/a> with Cloudinary in your Laravel projects for FREE!<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28277,"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,387,229,371],"class_list":["post-28276","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-laravel","tag-php","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>Generate a Watermarked Multi-Paged PDF<\/title>\n<meta name=\"description\" content=\"One of the ways to present your work is to create a portfolio. In this article, we will create a PDF portfolio with your branding from photos you upload to Cloudinary with a specific tag for instance &quot;Wedding&quot;.\" \/>\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\/generate-a-watermarked-multi-paged-pdf\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Generate a Watermarked Multi-Paged PDF\" \/>\n<meta property=\"og:description\" content=\"One of the ways to present your work is to create a portfolio. In this article, we will create a PDF portfolio with your branding from photos you upload to Cloudinary with a specific tag for instance &quot;Wedding&quot;.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-07-11T08:58:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-10-11T22:26:13+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"645\" \/>\n\t<meta property=\"og:image:height\" content=\"645\" \/>\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\/generate-a-watermarked-multi-paged-pdf\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Generate a Watermarked Multi-Paged PDF\",\"datePublished\":\"2022-07-11T08:58:27+00:00\",\"dateModified\":\"2023-10-11T22:26:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/\"},\"wordCount\":5,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"Laravel\",\"PHP\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/\",\"name\":\"Generate a Watermarked Multi-Paged PDF\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA\",\"datePublished\":\"2022-07-11T08:58:27+00:00\",\"dateModified\":\"2023-10-11T22:26:13+00:00\",\"description\":\"One of the ways to present your work is to create a portfolio. In this article, we will create a PDF portfolio with your branding from photos you upload to Cloudinary with a specific tag for instance \\\"Wedding\\\".\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA\",\"width\":645,\"height\":645},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Generate a Watermarked Multi-Paged 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":"Generate a Watermarked Multi-Paged PDF","description":"One of the ways to present your work is to create a portfolio. In this article, we will create a PDF portfolio with your branding from photos you upload to Cloudinary with a specific tag for instance \"Wedding\".","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\/generate-a-watermarked-multi-paged-pdf\/","og_locale":"en_US","og_type":"article","og_title":"Generate a Watermarked Multi-Paged PDF","og_description":"One of the ways to present your work is to create a portfolio. In this article, we will create a PDF portfolio with your branding from photos you upload to Cloudinary with a specific tag for instance \"Wedding\".","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-07-11T08:58:27+00:00","article_modified_time":"2023-10-11T22:26:13+00:00","og_image":[{"width":645,"height":645,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6-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\/generate-a-watermarked-multi-paged-pdf\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/"},"author":{"name":"","@id":""},"headline":"Generate a Watermarked Multi-Paged PDF","datePublished":"2022-07-11T08:58:27+00:00","dateModified":"2023-10-11T22:26:13+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/"},"wordCount":5,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA","keywords":["Guest Post","Image","Laravel","PHP","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/","name":"Generate a Watermarked Multi-Paged PDF","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA","datePublished":"2022-07-11T08:58:27+00:00","dateModified":"2023-10-11T22:26:13+00:00","description":"One of the ways to present your work is to create a portfolio. In this article, we will create a PDF portfolio with your branding from photos you upload to Cloudinary with a specific tag for instance \"Wedding\".","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA","width":645,"height":645},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/generate-a-watermarked-multi-paged-pdf\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Generate a Watermarked Multi-Paged 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\/v1681924957\/Web_Assets\/blog\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6\/2036d9fa1ae00bba1b9205449b272f0fcb68e145-645x645-1_28277f7ba6.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28276","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=28276"}],"version-history":[{"count":3,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28276\/revisions"}],"predecessor-version":[{"id":31429,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28276\/revisions\/31429"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28277"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28276"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28276"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28276"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}