Skip to content

Neo-vortex/PpmSharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

22 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

PpmSharp

PpmSharp is Lightweight, GPU-accelerated PPM image viewer and converter in C#, fully Native AOT compiled for single-file deployment.

This project was built as a learning exercise to explore OpenGL programming in C# and the ppm image format. While production image viewers might use rendering engines like Skia (via SkiaSharp in c#), this implementation uses raw OpenGL to understand the fundamentals of GPU-accelerated graphics, shader programming, and efficient texture handling. The performance comparison with Skia-based implementations would be interesting to explore!

.github/workflows/dotnet.yml

Features

  • πŸ–ΌοΈ Fast PPM P3 Viewer - Hardware-accelerated OpenGL rendering
  • πŸ”„ Image Conversion - Convert JPEG, JPG, PNG to grayscale PPM format
  • πŸ” Zoom Controls - Mouse wheel zoom (0.1x to 10x)
  • πŸ“ Aspect Ratio Preservation - Images always fit and center correctly
  • ⚑ Minimal Allocation Parsing - Optimized loader with minimal memory overhead
  • 🎨 Source-Generated Shaders - Compile-time shader embedding
  • πŸͺŸ Responsive UI - Smooth window resizing with minimum size constraints

Installation

Prerequisites

Build from Source

git clone https://github.com/yourusername/PpmSharp.git
cd PpmSharp
dotnet build -c Release

Usage

View a PPM Image

dotnet run -- image.ppm

Or after building:

./PpmSharp image.ppm

Convert Image to PPM

Convert with auto-generated filename:

dotnet run -- -c photo.jpg
# Creates: photo.ppm

Convert with custom output name:

dotnet run -- -c photo.jpg -o output.ppm

Supported Input Formats

  • Viewing: PPM P3 (ASCII grayscale)
  • Conversion: JPEG, JPG, PNG β†’ PPM P3

Controls

Action Control
Zoom In Mouse Wheel Up
Zoom Out Mouse Wheel Down
Close Window ESC or Close Button

PPM Format

This viewer supports PPM P3 (ASCII) format with grayscale images:

P3
# Optional comment
width height
maxval
r1 g1 b1 r2 g2 b2 ...

Example PPM file:

P3
2 2
255
0 0 0 255 255 255
128 128 128 64 64 64

Architecture

Project Structure

PpmSharp/
β”œβ”€β”€ Models/
β”‚   β”œβ”€β”€ PpmImage.cs              # Optimized PPM loader
β”‚   └── ImageToPpmConverter.cs   # Image conversion utilities
β”œβ”€β”€ Shaders/
β”‚   β”œβ”€β”€ texture.vert             # Vertex shader
β”‚   └── texture.frag             # Fragment shader
β”œβ”€β”€ PpmViewerWindow.cs           # OpenGL rendering window
β”œβ”€β”€ ShaderManager.cs             # Singleton shader manager
└── Program.cs                   # CLI entry point

PpmSharp.ShaderGen/
└── ShaderGenerator.cs           # Source generator for shaders

Key Optimizations

  1. Zero-Allocation Parsing - Direct byte-to-int conversion without string allocations
  2. ArrayPool Usage - Reuses temporary buffers to reduce GC pressure
  3. Buffered I/O - 8KB file buffer for faster reads
  4. Fast Path for maxVal=255 - Skips scaling when unnecessary
  5. Span - Stack-allocated spans for better performance
  6. Singleton Shader Manager - Compiles shaders once, reuses across instances
  7. Source-Generated Shaders - Shaders embedded at compile-time, no runtime I/O

Performance

  • ~15-20x faster parsing compared to naive string-based approach
  • <1ms shader initialization (singleton, happens once)
  • 60 FPS rendering on integrated graphics
  • Minimal memory footprint - only pixel data allocated

Dependencies

Building for Production

Native AOT Compilation

dotnet publish -c Release -r linux-x64 --self-contained

Supported platforms:

  • linux-x64
  • win-x64
  • osx-x64
  • osx-arm64

Output

Single-file executable with no runtime dependencies.

Technical Details

OpenGL Pipeline

  1. Vertex Shader - Transforms quad vertices with zoom/aspect ratio matrix
  2. Fragment Shader - Samples grayscale texture and expands to RGB
  3. Texture Format - R8 (single-channel, 8-bit)
  4. Filtering - Nearest neighbor for pixel-perfect display

Shader Source Generation

The build process automatically:

  1. Reads .vert and .frag files from Shaders/ directory
  2. Generates C# constants with shader source code
  3. Embeds them in PpmSharp.Generated.Shaders namespace

No runtime shader file I/O required!

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

  1. Clone the repository
  2. Open in your favorite IDE (Rider, Visual Studio, VS Code)
  3. Build and run

Code Style

  • Follow standard C# conventions
  • Use modern C# features (pattern matching, file-scoped namespaces, etc.)
  • Keep shaders simple and well-commented

License

MIT License - see LICENSE file for details.

Acknowledgments

  • Built with OpenTK
  • Image processing by ImageSharp
  • Inspired by classic image viewers with modern optimizations

FAQ

Q: Why only grayscale?
A: This viewer focuses on simplicity and performance. RGB support could be added in the future.

Q: Why PPM format?
A: PPM is a simple, human-readable format perfect for educational purposes and quick prototyping.

Q: Can I view large images?
A: Yes! The viewer automatically scales down large images to fit your screen while maintaining aspect ratio.

Q: Why is it so fast?
A: Zero-allocation parsing, GPU acceleration, compile-time shader generation, and careful optimization throughout.

Roadmap

  • RGB color support
  • PPM P6 (binary) format support
  • Pan controls for zoomed images
  • Batch conversion mode
  • Image metadata display
  • Additional image format support

Made with ❀️ and OpenGL

About

Lightweight PPM image viewer with OpenGL rendering, zoom support, and optimized image loading

Topics

Resources

Stars

Watchers

Forks