feat: add initial release with installation instructions, service configuration, and man page
This commit is contained in:
133
README.md
133
README.md
@@ -1,55 +1,126 @@
|
||||
# K-Shrink
|
||||
# k-shrink
|
||||
|
||||
Utility tool for shrinking/compressing images from the clipboard seamlessly. Built in Rust.
|
||||

|
||||

|
||||

|
||||
|
||||
# Why?
|
||||
Wayland clipboard daemon that automatically compresses images the moment you copy them.
|
||||
Copy a 3 MB screenshot, paste a 300 KB WebP — no extra steps.
|
||||
|
||||
## Quick Install (Arch Linux)
|
||||
|
||||
```bash
|
||||
yay -S k-shrink
|
||||
systemctl --user enable --now k-shrink.service
|
||||
```
|
||||
|
||||
For other installation methods see [INSTALL.md](INSTALL.md).
|
||||
|
||||
## How It Works
|
||||
|
||||
k-shrink runs silently in the background. When it detects an image on the clipboard
|
||||
(from a browser, image viewer, or file manager), it compresses it with your configured
|
||||
format and quality and writes the result back. Your next paste delivers the smaller image.
|
||||
|
||||
A SHA-256 hash of the output bytes prevents k-shrink from reprocessing its own output,
|
||||
so there are no infinite loops.
|
||||
|
||||
## Why?
|
||||
|
||||
Recently, I found myself sharing tons of memes and screenshots with friends, and it has come to my attention that many of those images are HUGE and it makes my blood boil. So, I decided to build a tool that will automatically take the image I have copied, whether from the web/facebook/discord/whatever or local files, or ftp, and shrink using user provided configuration (which format, quality, etc) and then put the shrunk image back to the clipboard, so that when I paste it, it's already shrunk and ready to be shared.
|
||||
|
||||
# How does it work?
|
||||
## Configuration
|
||||
|
||||
It is basically a daemon that runs in the background and listens for clipboard changes. When it detects a change, it checks if the clipboard contains an image. If it does, it processes the image according to the user configuration and then puts the shrunk image back to the clipboard. We need some sort of lock or signature to prevent infinite loops.
|
||||
|
||||
# Configuration
|
||||
|
||||
The configuration is stored in a file called `config.toml` in ~/.config/k-shrink/ directory. The configuration file is in TOML format and contains the following fields:
|
||||
Config file: `~/.config/k-shrink/config.toml` (created with defaults if absent).
|
||||
|
||||
```toml
|
||||
[general]
|
||||
# The format to shrink the image to. Supported formats are: png, jpeg, webp
|
||||
format = "webp"
|
||||
# The quality of the shrunk image. Supported values are: 0-100
|
||||
quality = 80
|
||||
format = "webp" # output format
|
||||
quality = 80 # 0-100, only for jpeg/avif
|
||||
poll_ms = 500 # clipboard polling interval (ms, min 100)
|
||||
extra_mimes = [] # additional MIME aliases (see below)
|
||||
```
|
||||
|
||||
# Portability
|
||||
### Config Reference
|
||||
|
||||
I personally use Arch Linux with Wayland, which is why for now it supports only wayland. But because I value portability and future-proofing, I have designed architecture in a way that it should be easy to add support for x11, windows, macos, what-have-you in the future.
|
||||
| Field | Type | Default | Description |
|
||||
| ------------- | ------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `format` | string | `"webp"` | Output image format. See formats table below. |
|
||||
| `quality` | integer 0–100 | `80` | Compression quality. Applied only for `jpeg` and `avif`. Ignored for all lossless formats. |
|
||||
| `poll_ms` | integer ≥ 100 | `500` | How often to poll the clipboard (ms). Lower = more responsive, more CPU. |
|
||||
| `extra_mimes` | string array | `[]` | Extra MIME types to serve alongside the real one. Same compressed bytes, different label. Useful when the paste target only requests a specific type. |
|
||||
|
||||
# Architecture
|
||||
### Supported Formats
|
||||
|
||||
That being said, let's talk about crates and general architecture.
|
||||
| Format | Lossy | Notes |
|
||||
| ---------- | ----- | ------------------------------------------------------- |
|
||||
| `webp` | No | Best for screenshots/UI. Smaller than PNG. **Default.** |
|
||||
| `jpeg` | Yes | Best for photos. `quality` applies. |
|
||||
| `avif` | Yes | Modern, better than JPEG. `quality` applies. |
|
||||
| `png` | No | Universal lossless. No size reduction vs source PNG. |
|
||||
| `qoi` | No | Fast lossless. Usually larger than PNG. |
|
||||
| `farbfeld` | No | Simple 16-bit lossless. Rarely needed. |
|
||||
| `tiff` | No | Lossless TIFF. Professional workflows. |
|
||||
| `gif` | No | 256 colors only. Avoid for photos. |
|
||||
| `hdr` | No | Radiance HDR floating-point. |
|
||||
| `openexr` | No | OpenEXR high dynamic range. |
|
||||
| `bmp` | No | Uncompressed. Will be larger than source. |
|
||||
| `tga` | No | Uncompressed. |
|
||||
| `pnm` | No | Uncompressed. |
|
||||
| `ico` | No | Uncompressed. |
|
||||
|
||||
All crates live in the `crates` directory. There are three main crates: `lib`, `platform`, and `bin`.
|
||||
## Troubleshooting
|
||||
|
||||
- `lib` crate is pure business logic, it doesn't care or know about the platform, it just provides the functionality to shrink images. It has no dependencies on platform-specific libraries, and it is tested with unit tests and integration tests. It is also the most stable crate, and it should not be changed frequently.
|
||||
- `platform` crate is the crate that provides the platform-specific implementation of the clipboard provider. It depends on the `lib` crate, and it is tested with integration tests. It is also the most volatile crate, and it may change frequently as we add support for more platforms.
|
||||
- `bin` crate is the crate that provides the binary executable. It depends on both `lib` and `platform` crates, and it is tested with integration tests. It is just an orchestrator that ties everything together, and it should not contain any business logic.
|
||||
### Paste fails in Discord / Slack / browser
|
||||
|
||||
Configuration should be handled by new crate called `config`, which will take care of toml, reading and writing config. Also in `platform` crate we should provide a way for `config` crate to properly work across platforms. (this crate could be debated whether it should be separate or not, I am not convinced that separating it is the best idea, but we will see)
|
||||
Some apps only request `image/png` even if other formats are available.
|
||||
Use `extra_mimes` to serve the compressed bytes under that label:
|
||||
|
||||
# Critical things I care about
|
||||
```toml
|
||||
[general]
|
||||
format = "webp"
|
||||
extra_mimes = ["image/png"]
|
||||
```
|
||||
|
||||
- Performance: Entire point of this tool is to be invisible to the user, which means it's gotta be fast. it can't get in the way because then it defeats the purpose.
|
||||
- Reliability: It should work consistently and not crash or cause any issues with the clipboard. It should also handle edge cases gracefully, such as unsupported formats, large images, etc.
|
||||
- Portability: It should work on multiple platforms, and it should be easy to add support for new platforms in the future.
|
||||
- User experience: It should be easy to use and configure, and it should provide feedback to the user when something goes wrong (e.g. unsupported format, etc). It should also have a good default configuration that works well for most users.
|
||||
- Feature flags: We should use feature flags to enable or disable certain features, such as support for specific platforms, or support for specific image formats. This will allow us to keep the binary size small and avoid unnecessary dependencies for users who don't need those features.
|
||||
The image is still encoded as WebP; the label is just what k-shrink advertises.
|
||||
Most apps decode by content rather than MIME type, so this works.
|
||||
|
||||
# Contributing
|
||||
### Images keep getting reprocessed (loop)
|
||||
|
||||
Contributions are welcome! If you want to contribute, please fork the repository and create a pull request. Please make sure to follow the coding style and conventions used in the project. Also, please make sure to write tests for your changes.
|
||||
k-shrink uses a SHA-256 hash of its output to skip reprocessing. If you see a loop,
|
||||
check that `IMAGE_MIMES` priority is intact (webp is listed first so k-shrink's own
|
||||
output is matched before external types). This should not occur in normal usage.
|
||||
|
||||
# License
|
||||
### File-manager copies not detected
|
||||
|
||||
Filesystem copies (Ctrl+C in Nautilus, Dolphin, etc.) are detected via `text/uri-list`.
|
||||
Only single-image files are supported. Multi-file selections and non-image files are
|
||||
ignored silently.
|
||||
|
||||
## Portability
|
||||
|
||||
Wayland only. The architecture isolates platform code in the `platform` crate, so
|
||||
X11/Windows/macOS backends can be added without touching business logic.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
bin (k-shrink) → lib + platform + config
|
||||
platform → lib + wl-clipboard-rs
|
||||
config → lib + serde/toml/dirs
|
||||
lib → image + sha2 (zero platform deps)
|
||||
```
|
||||
|
||||
- **lib** — pure image compression logic, no platform deps, fully unit-tested.
|
||||
- **config** — TOML parsing, validation, and path resolution.
|
||||
- **platform** — Wayland clipboard backend via `wl-clipboard-rs`.
|
||||
- **bin** — tokio event loop; orchestrates the other three crates.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. Fork the repo and open a pull request. Please include
|
||||
tests for new behavior and follow the existing code style.
|
||||
|
||||
## License
|
||||
|
||||
MIT. I seriously don't care what you do with this code or binaries, do whatever you want with it. If somehow it breaks something, it's your problem, not mine. #works-on-my-machine
|
||||
|
||||
Reference in New Issue
Block a user