FREADIO DIGITAL SERVICES

PDF Tools

Simple, powerful tools to work with your PDF files. Convert, merge, split, compress and manage PDFs in one place.

✓ FREE TOOLS
PDF
PDF
↔ Convert
+ Merge
↘ Compress
PDF TOOLKIT

Everything you need for PDFs.

8 TOOLS
SIMPLE WORKFLOW

Get your PDF task done in 3 steps.

01

Choose a tool

Select the PDF tool you need.

02

Upload your file

Add your PDF or supported file.

03

Get your result

Process your file and get the result.

FREADIO DIGITAL SERVICES

PDF work, made simple.

All PDF tools in one place.

All Digital Services →
'; generatedFiles.push({ blob: new Blob( [html], { type:'application/msword' } ), name: baseName(file.name) + '.doc' }); updateProgress( 100, 'Word-compatible document created.' ); showResults( 'Your Word-compatible document is ready.' ); } function pdfToText() { return extractPdfText(); } /* ===================================================== TEXT LINE GROUPING ===================================================== */ function groupTextLines(items) { const rows = []; items.forEach( function(item) { const y = Math.round( item.transform[5] ); let row = rows.find( function(existing) { return Math.abs( existing.y - y ) < 4; } ); if (!row) { row = { y:y, items:[] }; rows.push(row); } row.items.push(item); } ); rows.sort( function(a,b) { return b.y - a.y; } ); return rows.map( function(row) { row.items.sort( function(a,b) { return ( a.transform[4] - b.transform[4] ); } ); return row.items .map( function(item) { return item.str; } ) .join(' ') .trim(); } ); } /* ===================================================== RESULTS ===================================================== */ function showResults(title) { resultsTitle.textContent = title; resultList.innerHTML = ''; generatedFiles.forEach( function(file,index) { const item = document.createElement( 'div' ); item.className = 'freadio-result-item'; const number = document.createElement( 'div' ); number.className = 'freadio-result-number'; number.textContent = String( index + 1 ).padStart( 2, '0' ); const name = document.createElement( 'div' ); name.className = 'freadio-result-name'; name.textContent = file.name; const button = document.createElement( 'button' ); button.type = 'button'; button.className = 'freadio-result-download'; button.textContent = 'Download'; button.addEventListener( 'click', function() { downloadFile( file ); } ); item.appendChild( number ); item.appendChild( name ); item.appendChild( button ); resultList.appendChild( item ); } ); progress.hidden = true; results.hidden = false; } /* ===================================================== DOWNLOAD ===================================================== */ downloadAll.addEventListener( 'click', async function() { for ( let i = 0; i < generatedFiles.length; i++ ) { downloadFile( generatedFiles[i] ); await wait(250); } } ); function downloadFile(file) { const url = URL.createObjectURL( file.blob ); const link = document.createElement( 'a' ); link.href = url; link.download = file.name; document.body.appendChild( link ); link.click(); link.remove(); setTimeout( function() { URL.revokeObjectURL( url ); }, 1000 ); } /* ===================================================== RESET ===================================================== */ removeFile.addEventListener( 'click', function() { resetTool(true); } ); startAgain.addEventListener( 'click', function() { resetTool(true); workspace.scrollIntoView({ behavior:'smooth', block:'start' }); } ); backButton.addEventListener( 'click', function() { resetTool(true); workspace.hidden = true; root.querySelector( '#freadio-pdf-tool-list-template--30134861889696__freadio_pdf_tools_aXmW3y' ).scrollIntoView({ behavior:'smooth', block:'start' }); } ); function resetTool(clearInput) { generatedFiles = []; selectedFiles = []; if (clearInput) { input.value = ''; } selectedBox.hidden = true; uploadArea.hidden = false; actionButton.disabled = true; progress.hidden = true; results.hidden = true; jpgQualityOption.hidden = activeTool !== 'pdf-to-jpg'; jpgScaleOption.hidden = activeTool !== 'pdf-to-jpg'; splitOption.hidden = activeTool !== 'split-pdf'; compressOption.hidden = activeTool !== 'compress-pdf'; resultList.innerHTML = ''; hideError(); } /* ===================================================== PROGRESS ===================================================== */ function updateProgress( percent, message ) { progressBar.style.width = Math.min( 100, percent ) + '%'; progressPercent.textContent = Math.round( percent ) + '%'; progressText.textContent = message; } /* ===================================================== ERROR ===================================================== */ function showError(message) { errorText.textContent = message; errorBox.hidden = false; } function hideError() { errorBox.hidden = true; errorText.textContent = ''; } /* ===================================================== HELPERS ===================================================== */ function baseName(name) { return name.replace( /\.[^/.]+$/, '' ); } function formatBytes(bytes) { if (bytes < 1024) { return bytes + ' B'; } if (bytes < 1024 * 1024) { return ( bytes / 1024 ).toFixed(1) + ' KB'; } return ( bytes / (1024 * 1024) ).toFixed(1) + ' MB'; } function formatTotalSize(files) { const total = files.reduce( function(sum,file) { return sum + file.size; }, 0 ); return ( files.length + ' files • ' + formatBytes(total) ); } function fileToDataURL(file) { return new Promise( function(resolve,reject) { const reader = new FileReader(); reader.onload = function() { resolve( reader.result ); }; reader.onerror = reject; reader.readAsDataURL( file ); } ); } function blobToDataURL(blob) { return new Promise( function(resolve,reject) { const reader = new FileReader(); reader.onload = function() { resolve( reader.result ); }; reader.onerror = reject; reader.readAsDataURL( blob ); } ); } function getImage(src) { return new Promise( function(resolve,reject) { const image = new Image(); image.onload = function() { resolve(image); }; image.onerror = reject; image.src = src; } ); } function escapeHtml(value) { const div = document.createElement( 'div' ); div.textContent = value; return div.innerHTML; } function wait(ms) { return new Promise( function(resolve) { setTimeout( resolve, ms ); } ); } })();