Private Browser-Based PDF Processing Toolkit
13 PDF Workflows · Browser-Local Processing · Installable PWA · SEO-Ready Laravel Routes
Features · Tools · Installation · Configuration · Deployment · Architecture
- Introduction
- Features
- Complete Tool List
- Technology Stack
- Installation
- Configuration
- Usage Guide
- Architecture
- SEO & PWA
- Privacy & Security
- Development
- Deployment
- Verification
- Troubleshooting
- License
- Acknowledgments
- Support
ILovePDF Studio is a production-minded PDF utility app by Codezela Technologies. It uses Laravel, Inertia, Vue 3, TypeScript, Vite, and Tailwind CSS to deliver direct, indexable pages for each PDF workflow while keeping implemented document processing in the browser.
Laravel serves the application shell, SEO metadata, legal pages, sitemap, robots file, PWA manifest, service worker, and static browser engines. The current PDF tools use browser APIs and JavaScript/WASM libraries instead of uploading user PDFs to a processing endpoint.
- Browser-Local PDF Workflows: Implemented tools operate in browser memory with object URLs.
- Dedicated Laravel Routes: Every tool has its own route for direct loading, refreshes, sharing, and SEO.
- qpdf-Powered Compression: Compress PDF serves qpdf WASM from
public/vendor/qpdf/before using guarded aggressive fallbacks. - Installable Browser App: Manifest, service worker, icons, and install button are included.
- SEO-Ready Output: Titles, descriptions, canonical URLs, Open Graph tags, Twitter tags, JSON-LD, sitemap, and robots are generated server-side.
- Codezela Branding: Footer and structured data identify Codezela Technologies with a direct link to
https://codezela.com.
- Merge PDF: Combine two or more PDFs into one file.
- Split PDF: Export each page into individual PDFs inside a ZIP.
- Extract Pages: Build a new PDF from page ranges like
1,3-5,last. - Delete Pages: Remove selected pages while guarding against deleting every page.
- Organize PDF: Reorder pages using a custom page sequence.
- Compress PDF: Smart, lossless, balanced, strong, and maximum modes.
- Rotate PDF: Rotate all or selected pages by 90, 180, or 270 degrees.
- Add Page Numbers: Add clean footer page numbers with a configurable prefix.
- Watermark PDF: Apply a diagonal text watermark with opacity control.
- Edit PDF Metadata: Update title, author, and subject.
- Flatten PDF: Flatten supported form fields into static page content.
- Images to PDF: Convert JPG and PNG images into a PDF.
- PDF to Images: Render PDF pages as JPG or PNG and download a ZIP.
- Installable via supported Chromium/Edge browser install flows.
- Service worker caches the app shell and core static assets.
- PWA shortcuts open common workflows.
- Generated PNG and Apple touch icons are included.
- Duplicate file detection.
- PDF magic-byte validation.
- 200 MB per-file validation limit.
- Page range validation with useful error messages.
- Object URL cleanup when files/results are cleared or views unmount.
- TypeScript checked build pipeline.
- PHPUnit route/SEO/static-engine coverage.
| Tool | Route | Input | Output | Notes |
|---|---|---|---|---|
| Merge PDF | /merge-pdf |
2+ PDFs | Combines pages in upload order | |
| Compress PDF | /compress-pdf |
qpdf WASM first, safe aggressive fallbacks | ||
| Split PDF | /split-pdf |
ZIP | One PDF per page | |
| Extract PDF Pages | /extract-pdf-pages |
Supports ranges and last |
||
| Delete PDF Pages | /delete-pdf-pages |
Prevents empty output | ||
| Organize PDF | /organize-pdf |
Custom sequence like 3,1,2,4 |
||
| Rotate PDF | /rotate-pdf |
90, 180, or 270 degrees | ||
| Add Page Numbers | /add-page-numbers |
Footer numbering | ||
| Watermark PDF | /watermark-pdf |
Text watermark | ||
| JPG and PNG to PDF | /images-to-pdf |
JPG/PNG | Multi-image document creation | |
| PDF to JPG or PNG | /pdf-to-images |
ZIP | Page rendering through PDF.js | |
| Edit PDF Metadata | /edit-pdf-metadata |
Title, author, subject | ||
| Flatten PDF | /flatten-pdf |
Supported PDF form fields |
| Page | Route | Purpose |
|---|---|---|
| Home | / |
Hero, tools, features, footer |
| Tools | /tools |
Tool directory |
| Features | /features |
Browser-local feature overview |
| Privacy Policy | /privacy |
Privacy terms for browser-local processing |
| Terms of Use | /terms |
Product usage terms |
| Endpoint | Route | Purpose |
|---|---|---|
| Sitemap | /sitemap.xml |
Dynamic XML sitemap |
| Robots | /robots.txt |
Dynamic crawler directives |
| Health | /up |
Laravel health check |
| Manifest | /manifest.webmanifest |
Browser app manifest |
| Service Worker | /sw.js |
PWA cache worker |
| qpdf Engine | /vendor/qpdf/qpdf.mjs |
Browser-served PDF compression engine |
| Technology | Version | Purpose |
|---|---|---|
| PHP | 8.3+ | Runtime |
| Laravel | 13.x | Routing, config, views, sitemap, robots, app shell |
| Inertia Laravel | 3.x | Laravel-to-Vue page transport |
| SQLite | Default | Local database/session/cache driver support |
| PHPUnit | 12.x | Feature and route tests |
| Technology | Version | Purpose |
|---|---|---|
| Vue | 3.5+ | UI |
| TypeScript | 6.x | Type safety |
| Vite | 8.x | Frontend build |
| Tailwind CSS | 4.x | Styling |
| lucide-vue-next | 1.x | Interface icons |
| Inertia Vue | 3.x | SPA navigation |
| Library / Asset | Purpose | Location |
|---|---|---|
| pdf-lib | PDF creation, page copying, metadata, watermarking, numbering | npm dependency |
| PDF.js | PDF rendering for image export and raster fallback | npm dependency |
| qpdf WASM | Browser-served structural compression and safe optimization | public/vendor/qpdf/qpdf.mjs |
| JSZip | ZIP output for split/export workflows | npm dependency |
| Canvas API | Browser raster rendering for PDF-to-image and aggressive compression fallback | browser API |
- PHP 8.3 or newer
- Composer 2.x
- Node.js and npm
- SQLite, MySQL, or PostgreSQL
composer install
npm install
cp .env.example .env
php artisan key:generate
touch database/database.sqlite
php artisan migrate
npm run buildphp artisan serve --host=127.0.0.1 --port=8000
npm run devThe local app is usually available at:
http://127.0.0.1:8000
APP_NAME="ILovePDF Studio"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com
APP_KEY=base64:generated-key
DB_CONNECTION=sqlite
SESSION_DRIVER=database
CACHE_STORE=database
QUEUE_CONNECTION=database
SESSION_SECURE_COOKIE=true
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax
VITE_APP_NAME="${APP_NAME}"
VITE_BUILD_SOURCEMAP=falseAPP_URLcontrols canonical URLs, sitemap URLs, robots output, social metadata, and asset URLs.APP_KEYmust be generated withphp artisan key:generate.SESSION_SECURE_COOKIE=trueshould be used on HTTPS production domains.VITE_BUILD_SOURCEMAP=falsekeeps production builds from publishing source maps unless explicitly enabled.public/vendor/qpdf/qpdf.mjsandpublic/vendor/qpdf/LICENSEmust be present after deploy.
- Open the homepage or a direct tool route such as
/compress-pdf. - Add files by clicking the upload panel or dragging files into it.
- Choose tool options when the selected workflow exposes them.
- Run the processing button.
- Download the generated PDF or ZIP from the results section.
Supported range examples:
1
1,3,5
2-6
1,3-5,last
| Mode | Behavior | Preserves Text/Vectors |
|---|---|---|
| Smart | qpdf optimization first, then strong fallback only when useful | Usually yes |
| Lossless | qpdf/pdf-lib structural cleanup without visual flattening | Yes |
| Balanced | qpdf optimization with safe image cleanup | Yes |
| Strong | Adds raster fallback only when smaller | May flatten |
| Maximum | Prioritizes smallest accepted output | May flatten |
The app compares candidates and avoids returning a larger "compressed" output when the original is already smaller.
ilovepdf/
├── app/
│ ├── Http/Middleware/HandleInertiaRequests.php
│ ├── Models/User.php
│ └── Providers/AppServiceProvider.php
├── bootstrap/
│ └── app.php
├── config/
│ ├── app.php
│ ├── database.php
│ ├── session.php
│ └── studio.php
├── database/
│ ├── migrations/
│ └── seeders/
├── public/
│ ├── build/
│ ├── icons/
│ ├── vendor/qpdf/
│ │ ├── LICENSE
│ │ └── qpdf.mjs
│ ├── manifest.webmanifest
│ └── sw.js
├── resources/
│ ├── css/app.css
│ ├── js/
│ │ ├── app.ts
│ │ ├── Components/
│ │ ├── Pages/
│ │ ├── composables/
│ │ ├── data/tools.ts
│ │ └── pdf/operations.ts
│ └── views/
│ ├── app.blade.php
│ └── sitemap.blade.php
├── routes/
│ └── web.php
├── tests/
│ └── Feature/StudioRoutingTest.php
├── composer.json
├── package.json
├── vite.config.js
└── README.md
| File | Responsibility |
|---|---|
routes/web.php |
Public routes, legal pages, tool route rendering, sitemap, robots |
config/studio.php |
SEO titles/descriptions and tool route metadata |
resources/views/app.blade.php |
Root Inertia view, meta tags, PWA links, JSON-LD |
resources/js/Pages/Studio.vue |
Homepage, tools page, features page, and tool workspace |
resources/js/Pages/Legal.vue |
Privacy and terms pages |
resources/js/Components/InstallAppButton.vue |
PWA/browser install action |
resources/js/Components/AppFooter.vue |
Footer and Codezela link |
resources/js/data/tools.ts |
Frontend tool registry and options |
resources/js/pdf/operations.ts |
Browser-local PDF processing engine |
resources/js/composables/useDocumentTitle.ts |
Inertia navigation title consistency |
public/vendor/qpdf/ |
Browser-served qpdf WASM engine and license |
tests/Feature/StudioRoutingTest.php |
Route, SEO, sitemap, removed-route, and engine checks |
- Unique title and description for every public page and PDF tool.
- Titles consistently end with
- ILovePDF Studio. - Canonical URLs generated from
APP_URL. - Open Graph and Twitter metadata.
- JSON-LD for
Organization,WebPage, and toolSoftwareApplication. - Dynamic
/sitemap.xml. - Dynamic
/robots.txt. - Direct Laravel routes for every tool page.
public/manifest.webmanifestdefines app name, colors, icons, display mode, scope, and shortcuts.public/sw.jscaches the app shell and static assets.public/icons/icon.svgis the primary logo.public/icons/icon-192.png,public/icons/icon-512.png, andpublic/icons/apple-touch-icon.pngare generated install icons.
Regenerate icons after changing the mark:
php scripts/generate-pwa-icons.php- Implemented PDF tools run in browser memory.
- There is no upload endpoint for the implemented processing workflows.
- Files are selected with the browser File API.
- Downloads are produced with browser object URLs.
- Temporary object URLs are revoked when selections/results are cleared or the page unmounts.
- No analytics or advertising scripts are configured in this repository.
- PDF files are checked for
%PDF-magic bytes before processing. - Unsupported, encrypted, or malformed PDFs return user-facing errors where detected.
- Laravel session cookies are HTTP-only by default.
- Production HTTPS deployments should set
SESSION_SECURE_COOKIE=true. - The qpdf WASM engine is served as a static asset and its Apache-2.0 license is committed beside it.
# Frontend typecheck and production build
npm run build
# Frontend dev server only
npm run dev
# Laravel test suite
php artisan test
# Composer-provided test script
composer test- Add route metadata in
config/studio.php. - Add the frontend tool definition in
resources/js/data/tools.ts. - Implement processing behavior in
resources/js/pdf/operations.ts. - Add any tool-specific options in
resources/js/Pages/Studio.vue. - Add the route to
tests/Feature/StudioRoutingTest.php. - Run
npm run buildandphp artisan test.
composer install --no-dev --optimize-autoloader
npm ci
npm run build
php artisan key:generate --force
php artisan migrate --force
php artisan storage:link
php artisan optimizeEnsure these are writable by the PHP user:
database/
storage/
storage/app/public/
storage/framework/cache/data/
storage/framework/sessions/
storage/framework/views/
storage/logs/
bootstrap/cache/
-
APP_ENV=production -
APP_DEBUG=false -
APP_URLis the final HTTPS domain -
APP_KEYis generated - Database migrations are applied
-
SESSION_SECURE_COOKIE=trueon HTTPS -
npm run buildcompleted -
php artisan testcompleted before deploy -
php artisan optimizecompleted after env/config updates -
/sitemap.xmlresolves -
/robots.txtresolves -
/manifest.webmanifestresolves -
/sw.jsresolves -
/icons/icon-512.pngresolves -
/vendor/qpdf/qpdf.mjsresolves -
/compress-pdfloads with the correct title and metadata
git diff --check
npm run build
php artisan test
npm audit --audit-level=moderatecurl -I "$APP_URL/"
curl -I "$APP_URL/compress-pdf"
curl -I "$APP_URL/vendor/qpdf/qpdf.mjs"
curl "$APP_URL/robots.txt"
curl "$APP_URL/sitemap.xml"The compression engine requires both the dependency metadata and static vendor asset:
git add README.md config/studio.php package.json package-lock.json \
resources/js/Pages/Studio.vue resources/js/data/tools.ts resources/js/pdf/operations.ts \
resources/js/vite-env.d.ts tests/Feature/StudioRoutingTest.php \
public/vendor/qpdf/LICENSE public/vendor/qpdf/qpdf.mjsDo not commit local/runtime files such as .env, database/database.sqlite, node_modules/, vendor/, public/build/, cache files, or storage-generated views.
- Confirm
/vendor/qpdf/qpdf.mjsreturns200 OK. - Confirm
public/vendor/qpdf/qpdf.mjswas committed and deployed. - Confirm browser console does not show a blocked module load.
- Try Lossless mode first to separate qpdf loading from raster fallback behavior.
- Install prompts require HTTPS,
localhost, or127.0.0.1. - Some browsers hide install if the app is already installed.
- Edge users can also install from Apps → Install this site as an app.
- Confirm
/manifest.webmanifest,/sw.js, and icon files resolve.
- Confirm the page uses Inertia navigation and the current built asset is deployed.
- Confirm
resources/js/composables/useDocumentTitle.tsis included in the active bundle. - Confirm Blade/Inertia title tags include
data-inertia.
- Run
npm installornpm ci. - Confirm Node/npm are available.
- Clear stale Vite artifacts if needed.
- Re-run
npm run buildand read the first TypeScript error.
- Confirm
.envexists. - Run
php artisan key:generate. - Run
php artisan migrate --force. - Clear and rebuild caches:
php artisan optimize:clear
php artisan optimizeThe application package declares the MIT license in composer.json.
The bundled qpdf WASM engine in public/vendor/qpdf/ is Apache-2.0 licensed; its license text is included at public/vendor/qpdf/LICENSE.
- Laravel - PHP application framework
- Inertia.js - Modern monolith SPA bridge
- Vue.js - Frontend framework
- Vite - Frontend tooling
- Tailwind CSS - Utility-first styling
- pdf-lib - PDF creation and editing
- PDF.js - PDF rendering
- qpdf - PDF structure optimization
- JSZip - ZIP generation
- Lucide - Icon system
- Website: https://codezela.com
- Company: Codezela Technologies
- Product: ILovePDF Studio
Crafted by Codezela Technologies
Colombo, Sri Lanka