A modern, Kotlin-based desktop application for compressing PDF files using Ghostscript. Built with Compose Multiplatform for a native desktop experience.
- Drag & Drop Interface: Simply drag PDF files onto the application
- Clipboard Support: Paste files directly with โ+V (macOS)
- Real-time Progress: Visual feedback for compression status
- Batch Processing: Handle multiple files simultaneously
- Compression Stats: Shows file size reduction percentages
- Finder Integration: Click files to reveal in Finder
The application follows a clean, modular architecture designed for maintainability and testability:
src/main/kotlin/
โโโ Main.kt # Application entry point & UI orchestration
โโโ MainViewModel.kt # State management & coordination
โโโ domain/ # Business logic layer
โ โโโ CompressionService.kt # PDF compression interface & implementation
โ โโโ FileProcessingState.kt # Domain models & state
โโโ infrastructure/ # External dependencies
โ โโโ CommandExecutor.kt # System command execution abstraction
โโโ ui/ # User interface components
โ โโโ components/
โ โ โโโ DragDropArea.kt # Drag & drop functionality
โ โ โโโ FileListItem.kt # File list item component
โ โโโ DashedBorder.kt # UI utility for dashed borders
โโโ utils/ # Common utilities
โโโ FileUtils.kt # File operations & formatting
- Separation of Concerns: Domain, UI, and Infrastructure layers are clearly separated
- Dependency Injection: Services can be easily mocked and tested
- Interface Segregation: Clean interfaces enable easy testing and extension
- Single Responsibility: Each class has one clear purpose
-
Kotlin/JVM: Project uses Kotlin with Compose Desktop
-
Ghostscript: Required for PDF compression functionality
# macOS brew install ghostscript # Ubuntu/Debian sudo apt-get install ghostscript
# Clone the repository
git clone <repository-url>
cd shrinkwrap
# Build the application
./gradlew build
# Run the application
./gradlew run
# Create native distribution
./gradlew createDistributableThe modular architecture enables comprehensive testing:
// Service layer testing
class CompressionServiceTest {
@Test
fun `should compress valid PDF file`() {
val mockCommandExecutor = mockk<CommandExecutor>()
val service = GhostscriptCompressionService(mockCommandExecutor)
// Test without system dependencies
}
}
// State management testing
class MainViewModelTest {
@Test
fun `should update state when file is added`() {
val mockService = mockk<CompressionService>()
val viewModel = MainViewModel(mockService)
// Test state transitions
}
}- Test UI components with test state
- Test end-to-end file processing workflows
- Test error handling scenarios
- Add UI controls for high/medium/low quality selection
- Remember user preferences
- Quality preview before compression
- User-friendly error messages
- Retry mechanisms for failed compressions
- Better validation feedback
- Detailed progress bars for large files
- Compression speed metrics
- Estimated time remaining
// Easy to implement with current architecture
class PDFtkCompressionService : CompressionService { ... }
class ImageMagickCompressionService : CompressionService { ... }- Select compression quality per batch
- Pause/resume batch processing
- Export compression reports
- Original file backup options
- Custom output directory selection
- File name templates (e.g.,
{original}_compressed.pdf)
- PDF optimization beyond compression
- Image quality adjustments within PDFs
- Metadata preservation options
- Dark/light theme toggle
- Keyboard shortcuts for common actions
- Recent files list
- Undo/redo functionality
- Compression statistics dashboard
- Export compression reports
- Historical data tracking
- Windows Explorer integration
- Linux file manager integration
- Platform-specific optimizations
- Memory-efficient processing for large files
- Background compression queue
- Multi-threaded processing improvements
- Settings persistence
- Custom Ghostscript parameters
- Advanced user configurations
- Custom compression algorithms
- Third-party integrations
- Extension marketplace
- Follow Kotlin coding conventions
- Use meaningful variable and function names
- Add KDoc comments for public APIs
- Keep functions focused and small
- Unit tests for all business logic
- UI tests for interactive components
- Integration tests for file operations
- Maintain >80% code coverage
- Keep domain logic pure (no UI or infrastructure dependencies)
- Use dependency injection for testability
- Create reusable UI components
- Handle errors gracefully with meaningful messages
- Implement
CompressionServiceinterface - Add to dependency injection in
MainViewModel - Add UI selection controls
- Update tests
- Create in
ui/components/package - Follow existing component patterns
- Make components reusable and configurable
- Add preview functions for development
- Large files should be processed in chunks
- UI should remain responsive during processing
- Memory usage should be monitored for batch operations
[Add your license information here]
- Compose Multiplatform for the UI framework
- Ghostscript for PDF compression engine