<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tools on Thezida</title><link>https://www.thezida.com/tools/</link><description>Recent content in Tools on Thezida</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 01 Feb 2026 12:00:00 +0200</lastBuildDate><atom:link href="https://www.thezida.com/tools/index.xml" rel="self" type="application/rss+xml"/><item><title>PDF merger</title><link>https://www.thezida.com/tools/pdf-merger/</link><pubDate>Sun, 01 Feb 2026 12:00:00 +0200</pubDate><guid>https://www.thezida.com/tools/pdf-merger/</guid><description>&lt;div class="pdf-merger"&gt;&#10; &lt;p&gt;Select two or more PDF files, arrange them in the order you want, and merge them in your browser.&lt;/p&gt;&#10; &lt;p&gt;&#10; &lt;label for="pdf-merger-files"&gt;PDF files&lt;/label&gt;&lt;br&gt;&#10; &lt;input id="pdf-merger-files" type="file" multiple accept="application/pdf,.pdf"&gt;&#10; &lt;/p&gt;&#10; &lt;ol id="pdf-merger-list" aria-label="PDFs in merge order"&gt;&lt;/ol&gt;&#10; &lt;button id="pdf-merger-submit" type="button"&gt;Merge PDFs&lt;/button&gt;&#10; &lt;p id="pdf-merger-status" role="status" aria-live="polite"&gt;&lt;/p&gt;&#10; &lt;a id="pdf-merger-download" hidden download="merged.pdf"&gt;Download merged PDF&lt;/a&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;style&gt;&#10;.pdf-merger ol { padding-left: 1.5rem; }&#10;.pdf-merger li { margin: .5rem 0; }&#10;.pdf-merger li button { margin-left: .4rem; }&#10;.pdf-merger #pdf-merger-files { max-width: 100%; }&#10;.pdf-merger [hidden] { display: none; }&#10;&lt;/style&gt;&#10;&#10;&lt;script type="module"&gt;&#10;import createQpdf from 'https://cdn.jsdelivr.net/npm/qpdf-wasm-esm-embedded@1.1.1/qpdf.mjs';&#10;&#10;const fileInput = document.getElementById('pdf-merger-files');&#10;const fileList = document.getElementById('pdf-merger-list');&#10;const mergeButton = document.getElementById('pdf-merger-submit');&#10;const status = document.getElementById('pdf-merger-status');&#10;const download = document.getElementById('pdf-merger-download');&#10;let files = [];&#10;let qpdfPromise;&#10;&#10;function renderFiles() {&#10; fileList.replaceChildren();&#10; files.forEach((file, index) =&gt; {&#10; const item = document.createElement('li');&#10; item.append(document.createTextNode(file.name + ' '));&#10;&#10; const moveUp = document.createElement('button');&#10; moveUp.type = 'button';&#10; moveUp.textContent = 'Move up';&#10; moveUp.disabled = index === 0;&#10; moveUp.setAttribute('aria-label', `Move ${file.name} up`);&#10; moveUp.addEventListener('click', () =&gt; {&#10; [files[index - 1], files[index]] = [files[index], files[index - 1]];&#10; renderFiles();&#10; });&#10;&#10; const moveDown = document.createElement('button');&#10; moveDown.type = 'button';&#10; moveDown.textContent = 'Move down';&#10; moveDown.disabled = index === files.length - 1;&#10; moveDown.setAttribute('aria-label', `Move ${file.name} down`);&#10; moveDown.addEventListener('click', () =&gt; {&#10; [files[index], files[index + 1]] = [files[index + 1], files[index]];&#10; renderFiles();&#10; });&#10;&#10; const remove = document.createElement('button');&#10; remove.type = 'button';&#10; remove.textContent = 'Remove';&#10; remove.setAttribute('aria-label', `Remove ${file.name}`);&#10; remove.addEventListener('click', () =&gt; {&#10; files.splice(index, 1);&#10; renderFiles();&#10; });&#10;&#10; item.append(moveUp, moveDown, remove);&#10; fileList.append(item);&#10; });&#10;}&#10;&#10;fileInput.addEventListener('change', (event) =&gt; {&#10; files.push(...Array.from(event.target.files));&#10; renderFiles();&#10; status.textContent = `${files.length} PDF${files.length === 1 ? '' : 's'} selected.`;&#10; download.hidden = true;&#10; event.target.value = '';&#10;});&#10;&#10;mergeButton.addEventListener('click', async () =&gt; {&#10; if (files.length &lt; 2) {&#10; status.textContent = 'Select at least two PDF files.';&#10; return;&#10; }&#10;&#10; mergeButton.disabled = true;&#10; download.hidden = true;&#10; status.textContent = 'Loading PDF merger…';&#10; try {&#10; qpdfPromise ??= createQpdf();&#10; const qpdf = await qpdfPromise;&#10; status.textContent = 'Merging PDFs…';&#10;&#10; for (let i = 0; i &lt; files.length; i++) {&#10; qpdf.FS.writeFile(`/in${i}.pdf`, new Uint8Array(await files[i].arrayBuffer()));&#10; }&#10;&#10; const args = ['--empty', '--pages'];&#10; for (let i = 0; i &lt; files.length; i++) args.push(`/in${i}.pdf`, '1-z');&#10; args.push('--', '/merged.pdf');&#10; await qpdf.callMain(args);&#10;&#10; const output = qpdf.FS.readFile('/merged.pdf');&#10; const url = URL.createObjectURL(new Blob([output], { type: 'application/pdf' }));&#10; download.href = url;&#10; download.hidden = false;&#10; status.textContent = 'Your merged PDF is ready.';&#10; } catch (error) {&#10; console.error(error);&#10; status.textContent = 'Could not merge these PDFs. Check that they are valid PDF files and try again.';&#10; } finally {&#10; mergeButton.disabled = false;&#10; }&#10;});&#10;&lt;/script&gt;</description></item></channel></rss>