Drag files in Finder, hold a modifier, and drop on a wheel of outputs. Conversions run entirely on-device through ImageIO, PDFKit, AVFoundation, the bundled CLI tools, and optional ffmpeg/LibreOffice. Includes a --self-test suite (41 checks) and a --convert CLI mode so the conversion matrix can be verified without the UI.
181 lines
6.8 KiB
Markdown
181 lines
6.8 KiB
Markdown
# Konverter
|
|
|
|
A macOS menu bar file converter in the spirit of [Tangerine](https://tangerineformac.com):
|
|
drag a file in Finder, hold a modifier key, get a wheel of outputs around the
|
|
cursor, drop on one, and the converted file appears next to the original.
|
|
Everything runs locally — no uploads, no accounts, no analytics.
|
|
|
|
<p align="center">
|
|
<em>Shift = convert · Command (+Shift) = tools · Control = actions</em>
|
|
</p>
|
|
|
|
## Using it
|
|
|
|
1. Launch Konverter. It lives in the menu bar (`LSUIElement`, no Dock icon).
|
|
2. In Finder, drag one or more files (folders work for archives).
|
|
3. **Hold a trigger key while dragging** — the wheel fades in under the pointer:
|
|
- **Shift ⇧** — conversion targets (`PNG`, `JPG`, `PDF`, `MP4`, `ZIP`, …).
|
|
- **Command ⌘ + Shift** — file tools (`Compress`, `Resize`, `Trim`,
|
|
`Watermark`, `Merge`, `Extract`, …), each with its own small form.
|
|
- **Control ⌃** — actions (`AirDrop`, `Float`, `Copy`, `Move`, `Copy Path`,
|
|
`Terminal`, `Reveal`).
|
|
4. Move the pointer onto a segment (or use ←/→ and Return) and **drop**.
|
|
Dropping on the dead zone in the middle, pressing Escape, or dropping the
|
|
file anywhere else cancels and lets Finder do its normal thing.
|
|
|
|
The wheel also works without dragging: the menu bar item and the Finder Quick
|
|
Action **Convert with Konverter…** open the same options as a menu.
|
|
|
|
Keyboard/pointer alone is enough to use it. The optional keys (Escape, arrows,
|
|
Return) come from a global key monitor, so they need Accessibility permission —
|
|
without it the wheel still works by pointer, it just cannot read those keys.
|
|
|
|
### Preferences
|
|
|
|
Trigger keys (Shift/Command/Control/Option/fn), wheel style (radial/list),
|
|
radius, labels, dimming, output folder (beside the original or a chosen
|
|
folder), conflict policy (keep both / replace), progress window, reveal when
|
|
finished, sound, use of external tools, and open at login. Stored in
|
|
`UserDefaults` under the `konverter.` prefix.
|
|
|
|
## What it converts
|
|
|
|
94 input extensions are recognised. Outputs offered per kind of file:
|
|
|
|
| Input kind | Outputs |
|
|
| --- | --- |
|
|
| Image | PNG, JPG, HEIC, WebP, TIFF, BMP, GIF, AVIF, PDF |
|
|
| Video | MP4, MOV, MKV, WebM, AVI, WMV, GIF, MP3, M4A, WAV |
|
|
| Audio | MP3, M4A, WAV, FLAC, OGG, Opus, AIFF, WMA |
|
|
| PDF | DOCX, PPTX, XLSX, JPG, PNG, EPUB, TXT, MD, HTML |
|
|
| Document | DOCX, MD, TXT, RTF, HTML, EPUB, PDF |
|
|
| Slides | PDF, JPG, PNG |
|
|
| Spreadsheet | XLSX, ODS, CSV, TSV, PDF |
|
|
| Ebook | TXT, HTML, MD, PDF |
|
|
| Subtitle | SRT, VTT, TXT |
|
|
| Archive / folder | ZIP, TAR, GZIP |
|
|
|
|
Plus 38 tools:
|
|
|
|
| Group | Tools |
|
|
| --- | --- |
|
|
| Image | Compress, Resize, Crop, Rotate, Flip, Grayscale, Strip Metadata, Watermark, Read QR |
|
|
| Video | Compress, Trim, Mute, Speed, Snapshot, To GIF, Resize |
|
|
| Audio | Trim, Normalize, Channels, Speed, Bleep, Compress |
|
|
| PDF | Merge, Split, Rotate, Compress, Encrypt, Decrypt, Images to PDF, Collage, Extract Text |
|
|
| Document | To PDF, Statistics |
|
|
| Spreadsheet | To CSV |
|
|
| Subtitle | Shift Time |
|
|
| Archive | Extract, List Contents |
|
|
| Any | Info |
|
|
|
|
### Engines and fallbacks
|
|
|
|
| Layer | Used for | Ships with macOS |
|
|
| --- | --- | --- |
|
|
| ImageIO / Core Graphics | raster image decode/encode | yes |
|
|
| PDFKit / Core Text | PDF read/write, text extraction | yes |
|
|
| AVFoundation | MP4/MOV/M4A/WAV/AIFF/GIF | yes |
|
|
| `textutil`, `afconvert`, `ditto`, `tar`, `gzip`, `zip` | documents, audio, archives | yes |
|
|
| Hand-written XLSX / EPUB / Markdown / CSV / TSV / SRT-VTT | office and ebook plumbing | yes |
|
|
| ffmpeg / ffprobe | MKV, WebM, AVI, WMV, MP3, FLAC, OGG, Opus, WMA, bleep | optional |
|
|
| LibreOffice | PAGES, KEY, NUMBERS, PPT, PPTX, XLS, ODS | optional |
|
|
| `cwebp` | WebP encoding | optional |
|
|
|
|
Optional helpers are detected once at launch and are only ever *additive*: a
|
|
format whose engine is missing shows as unavailable in the wheel (with the
|
|
reason) instead of failing after you drop. Install them with:
|
|
|
|
```bash
|
|
brew install ffmpeg webp # cwebp comes from the webp formula
|
|
brew install --cask libreoffice
|
|
```
|
|
|
|
Notes on specific formats:
|
|
|
|
- **WebP out** needs `cwebp` or an ffmpeg built with libwebp. ImageIO on macOS
|
|
has no WebP encoder, and `sips` cannot write it either.
|
|
- **SVG / PSD / RAW in** are rasterised through Quick Look (`qlmanage`) when
|
|
ImageIO refuses them.
|
|
- **PAGES / KEY / NUMBERS out** only exist through LibreOffice. In Safari-style
|
|
document conversion, the Apple formats keep their layout via LibreOffice's
|
|
filter, not a hand-rolled writer.
|
|
- **Compressing a PNG** has no lossy quality knob, so the slider drives colour
|
|
depth (posterisation) instead — a real size drop, at the cost of banding at
|
|
low settings.
|
|
|
|
## Building
|
|
|
|
Requires Xcode (Swift 6 toolchain) and macOS 13+.
|
|
|
|
```bash
|
|
swift build # debug binary
|
|
swift build -c release
|
|
|
|
./.build/debug/Konverter --self-test # 41 checks over every engine
|
|
./.build/debug/Konverter --convert photo.heic --to png
|
|
./.build/debug/Konverter --convert clip.mov --tool trimVideo \
|
|
--param start=0:02 --param end=0:05
|
|
./.build/debug/Konverter --convert image.png --tool compressImage --param quality=50
|
|
```
|
|
|
|
`--self-test` builds its own fixtures in a temp directory and asserts that each
|
|
engine produces a non-empty, plausible file. Skips (printed as `SKIP`) mean an
|
|
optional engine is absent on this machine.
|
|
|
|
Build the app bundle (ad-hoc signed when no Developer ID identity is present):
|
|
|
|
```bash
|
|
./build-app.sh 0.1.0 # → Konverter.app, signed with Developer ID
|
|
open Konverter.app
|
|
```
|
|
|
|
## Releasing
|
|
|
|
```bash
|
|
./release.sh 0.1.0 # build → sign → notarize → staple → zip + sha256
|
|
```
|
|
|
|
`release.sh` refuses to hand back a build that is not notarized and stapled;
|
|
it also verifies `spctl -a -vv Konverter.app` reports
|
|
`source=Notarized Developer ID` before printing the sha256. Notary credentials
|
|
default to the shared App Store Connect key and can be overridden with
|
|
`KONVERTER_NOTARY_API_KEY_PATH`, `KONVERTER_NOTARY_API_KEY_ID`, and
|
|
`KONVERTER_NOTARY_API_ISSUER`.
|
|
|
|
Then tag, publish, and attach the zip:
|
|
|
|
```bash
|
|
git tag v0.1.0 && git push origin v0.1.0
|
|
tea releases create --tag v0.1.0 --title "Konverter 0.1.0" \
|
|
--note "<what changed>" --asset dist/Konverter.zip \
|
|
--repo TZGyn/konverter --login gitea.tzgyn.dev
|
|
```
|
|
|
|
## Install (Homebrew)
|
|
|
|
```bash
|
|
brew tap TZGyn/tap https://gitea.tzgyn.dev/TZGyn/homebrew-tap.git
|
|
brew trust TZGyn/tap
|
|
brew install --cask konverter
|
|
```
|
|
|
|
Upgrade script:
|
|
|
|
```bash
|
|
brew update
|
|
brew upgrade --cask konverter
|
|
```
|
|
|
|
## Privacy
|
|
|
|
Nothing leaves the machine. There is no networking code in the app, no
|
|
telemetry, and no third-party dependencies in `Package.swift`. Conversions are
|
|
performed by Apple frameworks, the bundled CLI tools, and (optionally) local
|
|
`ffmpeg` / LibreOffice.
|
|
|
|
## Development docs
|
|
|
|
`AGENTS.md` covers the architecture, the drag/wheel mechanics, and the sharp
|
|
edges worth knowing before changing the code.
|