Skip to content

valentinnsoare/noir

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Noir

Converting your world to grayscale, one image at a time.

Kotlin Java 21 Spring Boot

FeaturesQuick StartInstallationUsageArchitectureDemo


A modern CLI tool for fetching images from URLs and converting them to grayscale (black and white).

Built with Kotlin, Spring Boot 4, and Picocli, demonstrating clean architecture principles and modern development practices.


Note

Project is 💯 completed!


Features

Feature Description
Multi-Format Support Process JPEG, PNG, GIF, BMP, and WebP images seamlessly
Async Operations Non-blocking I/O using Kotlin Coroutines for optimal performance
Progress Tracking Real-time progress indicators for long-running operations
Flexible Output Configurable output directory and custom filenames
Developer Friendly Verbose and quiet modes for different use cases
Clean Architecture SOLID principles and design patterns for maintainability

Highlights

+------------------------+     +------------------------+     +------------------------+
|     URL Fetching       |     |   Grayscale Convert    |     |     PNG Output         |
|------------------------|     |------------------------|     |------------------------|
| - HTTP/HTTPS support   |     | - High-quality algo    |     | - Lossless format      |
| - Async WebClient      | --> | - Luminosity method    | --> | - Configurable path    |
| - 3MB buffer limit     |     | - AWT ImageIO          |     | - Custom naming        |
+------------------------+     +------------------------+     +------------------------+

Quick Start

# Build the application
./mvnw clean package

# Run with a URL
java -jar target/noir-1.0.0.jar https://example.com/image.jpg

# Custom output filename
java -jar target/noir-1.0.0.jar https://example.com/image.jpg -o my_image.png

# Custom output directory
java -jar target/noir-1.0.0.jar https://example.com/image.jpg -d ./processed

Table of Contents

Prerequisites

  • Java 21 or higher
  • Maven 3.8+ (or use the included Maven Wrapper)

Installation

Using Maven Wrapper (Recommended)

# Clone the repository
git clone https://github.com/valentinsoare/noir.git
cd noir

# Build the project
./mvnw clean package

# The executable JAR will be at target/noir-1.0.0.jar

Using Installed Maven

mvn clean package

Usage

Basic Usage

# Convert an image to grayscale
java -jar target/noir-1.0.0.jar <image-url>

# Example
java -jar target/noir-1.0.0.jar https://picsum.photos/800/600

Command Options

Option Short Description Default
--output -o Custom output filename processed_image_<timestamp>.png
--output-dir -d Output directory Current directory (.)
--quiet -q Suppress progress output false
--verbose -v Enable verbose logging false
--help -h Show help message -
--version -V Show version info -

Examples

# Save with custom filename
java -jar target/noir-1.0.0.jar https://example.com/photo.jpg -o vacation.png

# Save to specific directory
java -jar target/noir-1.0.0.jar https://example.com/photo.jpg -d ./grayscale-images

# Quiet mode (no progress output)
java -jar target/noir-1.0.0.jar https://example.com/photo.jpg -q

# Verbose mode (debug logging)
java -jar target/noir-1.0.0.jar https://example.com/photo.jpg -v

# Combine options
java -jar target/noir-1.0.0.jar https://example.com/photo.jpg -o result.png -d ./output -v

Architecture

Noir follows a layered architecture with clear separation of concerns:

┌─────────────────────────────────────────────────────────┐
│                    CLI Layer                            │
│    ImageProcessorCommand (Picocli Command)              │
│    CLIRunner (Spring CommandLineRunner)                 │
└─────────────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│               Service Layer (Abstractions)              │
│    ImageFetcherService    ImageProcessingService        │
│    InputParserService     CatchThatExceptionHandler     │
└─────────────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│            Service Implementation Layer                 │
│    ImageFetcherServiceImpl    ImageProcessingServiceImpl│
│    InputParserServiceImpl     CatchThatExceptionHandler │
└─────────────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────┐
│                Infrastructure Layer                     │
│    Spring WebClient    Java AWT/ImageIO                 │
│    Kotlin Coroutines   Java NIO                         │
└─────────────────────────────────────────────────────────┘

Data Flow

User Input (CLI args)
        │
        ▼
┌───────────────────┐
│  CLIRunner        │ ──→ Parses args, invokes command
└───────────────────┘
        │
        ▼
┌───────────────────┐
│ ImageProcessor    │ ──→ Validates input, orchestrates pipeline
│ Command           │
└───────────────────┘
        │
        ├──→ InputParserService (URL validation)
        │
        ├──→ ImageFetcherService (HTTP GET → ByteArray)
        │
        ├──→ ImageProcessingService (Grayscale conversion)
        │
        └──→ Files.write() (Save to disk)

Concurrency Model

The application uses Kotlin Coroutines with specialized dispatcher scopes:

  • IO Scope (Dispatchers.IO): Network operations, file I/O
  • Processing Scope (Dispatchers.Default): CPU-intensive image processing
@IOScope private val ioScope: CoroutineScope
@ProcessingScope private val processingScope: CoroutineScope

Technology Stack

Technology Version Purpose
Kotlin 2.2.21 Programming language
Java 21 Runtime
Spring Boot 4.0.0 Application framework
Picocli 4.7.7 CLI framework
Kotlinx Coroutines 1.10.2 Async programming
Spring WebClient - Reactive HTTP client
Kotlin Logging 7.0.3 Logging facade
Logback - Logging implementation
Maven 3.8+ Build tool

Exit Codes

Code Name Description
0 SUCCESS Image processed successfully
1 GENERAL_ERROR Unexpected error occurred
2 INVALID_INPUT Invalid URL or arguments
3 NETWORK_ERROR Failed to fetch image
4 PROCESSING_ERROR Failed to convert image
5 IO_ERROR Failed to save output file
6 USER_CANCELLED Operation cancelled by user

Demo

NoirIsRunning.mp4

Acknowledgments

License

This project is licensed under the MIT License - see the LICENSE file for details.


Made with Kotlin

About

Converting your world to grayscale, one image at a time.

Resources

Stars

Watchers

Forks

Contributors

Languages