A fully offline, production-ready Android PDF utility app built with Jetpack Compose and iText7. Twelve powerful PDF operations in a single clean UI, with background processing via WorkManager and Firebase-powered force-update control.
| Operation | Description |
|---|---|
| Edit PDF | Freehand drawing, text annotations, redaction (erase content), undo/redo per page |
| Scan / Images to PDF | Live CameraX scan or gallery multi-select — any image to PDF |
| Merge PDFs | Combine any number of PDFs into one, in order |
| Extract Pages | Pull specific pages out into a new PDF |
| Delete Pages | Remove unwanted pages and save the rest |
| Reorder Pages | Rearrange page order freely |
| Rotate Pages | Rotate individual or all pages by 90°, 180°, or 270° |
| Compress PDF | Three quality levels — Low / Medium / High — with JPEG image recompression |
| Add Watermark | Text or image watermark with 7 placement positions, opacity, color, and rotation control |
| Password Protect | AES-128 encryption with separate user/owner passwords and print/copy permission toggles |
| Unlock PDF | Strip password protection from an encrypted PDF |
| Extract Text | Dump all plain text from every page to clipboard or share |
All operations run fully offline — no data ever leaves the device.
Main Screen![]() |
Edit PDF![]() |
Scan / Images to PDF![]() |
Merge PDFs![]() |
Extract Pages![]() |
Delete Pages![]() |
Reorder Pages![]() |
Rotate Pages![]() |
Compress PDF![]() |
Add Watermark![]() |
Password Protect![]() |
Unlock PDF![]() |
Extract Text![]() |
app/
├── com.example.pdf_utility_app/ # UI layer
│ ├── ui/<feature>/ # Screen + ViewModel per feature
│ ├── theme/ # Material3 color, type, theme
│ ├── Navigation.kt # Navigation3 route graph
│ └── MainActivity.kt
│
└── com.offlinepdf.toolkit/ # Core domain + data layer
├── core/
│ ├── domain/
│ │ ├── model/ # PdfDocument, WatermarkConfig, PasswordConfig, SplitMode, …
│ │ ├── repository/ # PdfRepository, FileRepository interfaces
│ │ └── usecase/pdf/ # One UseCase per operation
│ └── data/
│ ├── processor/
│ │ ├── ITextPdfProcessor # iText7 PDF engine
│ │ └── AndroidPdfRenderer # Android PdfRenderer for page preview bitmaps
│ ├── repository/ # PdfRepositoryImpl, FileRepositoryImpl
│ └── source/ # PdfDataSource
├── di/ # Hilt modules
├── worker/ # WorkManager HiltWorker for background jobs
└── update/ # Firebase Remote Config update-check service
- Clean Architecture — strict domain / data / UI separation
- MVVM — each screen has its own
ViewModelexposingStateFlow - Use Cases — one class per operation, composable and testable in isolation
- Hilt DI — constructor injection throughout;
@Singletonscoped processors - WorkManager — all heavy PDF operations run as
CoroutineWorker, survive process death, and report progress back to the UI viaFlow<ProcessingProgress>
| Layer | Library | Version |
|---|---|---|
| Language | Kotlin | 2.3.20 |
| UI | Jetpack Compose + Material3 | BOM latest |
| Navigation | Navigation3 | runtime + UI |
| DI | Hilt | 2.59.2 |
| Background | WorkManager + Hilt integration | 2.9.1 / 1.2.0 |
| PDF engine | iText7 (kernel, io, layout, forms) | 7.2.5 |
| Cryptography | BouncyCastle | 1.78.1 |
| Camera | CameraX (core, camera2, lifecycle, view) | 1.4.1 |
| Serialization | Kotlinx Serialization JSON | 1.7.1 |
| Analytics | Firebase Analytics | BOM 34.15.0 |
| Crash reporting | Firebase Crashlytics | BOM 34.15.0 |
| Remote config | Firebase Remote Config | BOM 34.15.0 |
| Build | AGP + KSP | latest |
A canvas-based editor rendered on top of iText7 page bitmaps. Supports:
- Freehand drawing with configurable stroke color and width
- Text annotation — tap to place a text box at any position
- Redaction — eraser tool using
BlendMode.Clearto permanently black out content - Undo / Redo per page
- Page-by-page navigation; edits are composited as PNG overlays and written back into the PDF
Two tabs in one screen:
- Camera — live CameraX preview with a capture button; captured frames are queued in a thumbnail row
- Gallery — multi-image picker via
ActivityResultContracts
Images are scaled to fit A4 page dimensions and assembled into a PDF using iText7's Document API.
Images embedded in the PDF are re-encoded as JPEG at a reduced quality factor:
| Level | JPEG Quality |
|---|---|
| Low | 80% |
| Medium | 60% |
| High | 35% |
iText7 SmartMode is also applied to deduplicate redundant PDF objects, and document metadata is stripped to shrink the file further.
- Text watermark — custom text, font size, opacity (0–1), color (ARGB), rotation angle, 7 fixed positions (top-left → bottom-right)
- Image watermark — pick any image from gallery, set opacity and scale factor, choose position
Applies AES-128 encryption via iText7 WriterProperties.setStandardEncryption with:
- Separate user password (open) and owner password (permissions)
- Configurable allow printing and allow copying permission flags
Three split strategies available at the domain layer:
ByRange— explicit list of page rangesEveryN— chunk every N pagesAtPages— split at specific page boundaries
UpdateCheckService fetches version_name and force_update from Remote Config on every app launch. If the remote version is higher than the installed version, a non-dismissable overlay is shown (Box with pointerInput consumption) directing the user to the Play Store. No network = silent pass-through.
- Android 8.0+ (minSdk 26)
- Target Android 16 (SDK 36)
- Camera permission required only for the scan feature; all other features use the Storage/MediaStore picker
- Clone the repo
git clone https://github.com/Asad-noor/pdf-toolkit-android.git
- Open in Android Studio Ladybug or newer
- Add your
google-services.jsontoapp/(Firebase project required for Remote Config and Crashlytics) - Build & run on a device or emulator running API 26+
The app runs fully without Firebase if
google-services.jsonis absent — Remote Config silently falls back to defaults and Crashlytics is a no-op.
Commercial use of this project code is not allowed This project is for my portfolio and demonstration purposes.












