An open API service indexing awesome lists of open source software.

https://github.com/lexluthor0304/negativeconverter


https://github.com/lexluthor0304/negativeconverter

film javascript linux macos negative photography tauri windows

Last synced: 12 days ago
JSON representation

Awesome Lists containing this project

README

          

# Film Negative โ†’ Positive Converter


Negative Converter sample output

Negative Converter helps film photographers turn scanned or camera-digitized film into clean, natural-looking positives with a workflow made for everyday editing. It brings frame cleanup, film-aware conversion, roll consistency, finishing controls, and export into one focused workspace.

Whether you are reviewing a fresh roll, restoring family negatives, or preparing a consistent set for sharing, the app is designed to make film conversion feel fast, approachable, and dependable while keeping your photos private.

## ๐ŸŒŸ Features

- ๐Ÿ“ท **Supports PNG/JPG file uploads** (including 16-bit PNGs via UPNG.js and .cr2, .nef, .arw, .dng, .raw, .rw2 raw files via LibRaw-Wasm)
- ๐Ÿ”„ **Rotation correction** via slider or number input
- โœ‚๏ธ **Visual cropping** with drag-and-drop overlay
- โš–๏ธ **One-click white balance** by clicking a gray area in the image
- ๐ŸŽ›๏ธ **Live controls** for:
- Temperature & Tint
- Vibrance & Saturation
- Cyan / Magenta / Yellow (CMY) channels
- ๐ŸŽž๏ธ **Film presets** for color negative, B&W negative, and positive slide stocks across Kodak / Fujifilm / Ilford
- ๐Ÿ—‚๏ธ **Data-driven preset system** loaded from `negative2positive/presets/film_presets.json` (supports alias fallback for older preset IDs)
- ๐Ÿ” **Optional lens profile workflow**: search/select Lensfun profiles manually, or skip lens correction and continue
- ๐Ÿงท **Roll-level lens settings**: lens correction on/off and parameters can be applied to selected files or reused via roll reference
- ๐Ÿ›ก๏ธ **Privacy-friendly**: all image processing happens locally in your browser
- ๐Ÿ’พ **Flexible export**: PNG / JPEG / TIFF with selectable bit depth (8-bit, plus 16-bit for PNG/TIFF)

## ๐Ÿš€ How to Use

### Workflow (Step 1 โ†’ 3)

1. **Step 1: Crop**
- Rotate / Auto Frame / Crop until only the film area remains
- Click **Next: Film Settings** (negatives) or **Next: Positive Mode** (slides)
2. **Step 2: Film Settings**
- Pick film type: **Color**, **B&W**, or **Positive**
- **Color negatives**: set the mask baseline (sample manually / auto-detect / roll reference)
- Click **Next: Convert and Continue**
3. **Step 3: Adjust & Export**
- White balance + sliders + curves to taste
- Export PNG / JPEG / TIFF

### Film type quickstart

- **Color negative**: Step 1 โ†’ **Next: Film Settings** โ†’ keep **Color** โ†’ set mask โ†’ **Next: Convert and Continue** โ†’ Step 3
- **B&W negative**: Step 1 โ†’ **Next: Film Settings** โ†’ select **B&W** โ†’ **Next: Convert and Continue** (no mask) โ†’ Step 3
- **Positive slide**: Step 1 โ†’ **Next: Positive Mode** (or select **Positive** in Step 2) โ†’ **Next: Convert and Continue** โ†’ Step 3

### Batch workflow (multiple files)

1. Click **Add** and choose multiple images (File List appears)
2. Process one frame fully to Step 3
3. Use **Save Settings** for the current frame, or **Apply to Selected** for roll-wide settings
4. (Optional) Use **Set Current as Reference** + **Apply Reference to Selected** for roll reference
5. Export via **Export All (ZIP)** or **Download All Individually**

### Guided Mode

- The Workflow panel includes a **Guide** toggle to show/hide in-app instructions (stored in localStorage)

## โš™๏ธ Technical Highlights

- Uses [`UPNG.js`](https://github.com/photopea/UPNG.js) to decode 16-bit PNGs
- Uses a custom WebAssembly module based on [`LibRaw-Wasm`](https://github.com/ybouane/LibRaw-Wasm) to support `.cr2`, `.nef`, `.arw`, `.dng`, `.raw`, `.rw2` formats
- Uses UTIF.js + an in-app PNG encoder path to support TIFF export and 16-bit PNG/TIFF output options
- Includes a simplified AHD demosaicing algorithm for Bayer-pattern raw data
- Color adjustment logic is based on RGB โ†” HSL and RGB โ†” CMY conversions
- Film preset metadata is loaded from JSON and grouped dynamically by film type in the UI
- Optional lens correction uses [`@neoanaloglabkk/lensfun-wasm`](https://www.jsdelivr.com/package/npm/@neoanaloglabkk/lensfun-wasm) with **npm local assets first + CDN fallback**
- Auto frame detection uses [`@techstark/opencv-js`](https://www.npmjs.com/package/@techstark/opencv-js) loaded dynamically from the npm package asset URL
- Performance optimizations include:
- Cached DOM access
- Offscreen canvas reuse
- Throttled rendering with `requestAnimationFrame`

## Live Demo

[Film Negative โ†’ Positive Converter](https://negative-converter.tokugai.com)

## ๐Ÿ–ฅ๏ธ Desktop App (Tauri)

This repo includes a Tauri wrapper to package the web app as an offline desktop application for Windows / macOS / Linux.

### Development

```bash
npm ci
npm run dev:web
```

### Vercel deployment (important)

This app must be deployed from the **Vite build output**, not by serving source files directly.

Required settings:

- Root Directory: repository root
- Install Command: `npm ci`
- Build Command: `npm run build:web`
- Output Directory: `dist`

`npm run build:web` generates `negative2positive/dist` (for local/Tauri) and also syncs it to root `dist` (for Vercel output pickup).

If Vercel serves `negative2positive/index.html` directly, module imports like `pako` / `utif` / `jszip` will not resolve in browser and upload buttons can stop working.

### Desktop dev (Tauri)

```bash
npm run tauri:dev
```

### Build installers

```bash
npm run tauri:build
```

Build outputs are placed under:
- `src-tauri/target/release/bundle/`

### macOS installation troubleshooting

If macOS shows **"Negative Converter is damaged and can't be opened"**, this is because the app is not yet notarized by Apple. Use one of these methods:

**Method 1 โ€” Terminal command (recommended):**
```bash
xattr -cr /Applications/Negative\ Converter.app
```

**Method 2 โ€” Right-click open:**
Right-click (or Control-click) the app โ†’ select **Open** โ†’ click **Open** in the confirmation dialog.

**Method 3 โ€” System Settings:**
Go to **System Settings โ†’ Privacy & Security**, scroll down and click **Open Anyway** next to the blocked app message.

### Linux AppImage troubleshooting

- Run AppImage directly, not with `sudo`.
- The desktop app now applies AppImage-only runtime guards:
- isolates GIO module loading to avoid host `gvfs`/GLib ABI mismatches
- standard AppImage keeps DMABUF when render nodes are usable, and auto-falls back when not
- compatibility AppImage (`*_legacy-glibc235.AppImage`) defaults DMABUF off for startup stability
- Optional override for DMABUF behavior:
- force enable: `NEGATIVE_CONVERTER_DMABUF=on ./Negative\ Converter*.AppImage`
- force disable: `NEGATIVE_CONVERTER_DMABUF=off ./Negative\ Converter*.AppImage`
- If startup still fails on older distros, use the compatibility AppImage (`*_legacy-glibc235.AppImage`).

### Release (GitHub Actions)

1. Update versions:
- `src-tauri/tauri.conf.json`
- `src-tauri/Cargo.toml`
2. Merge to `main`
3. GitHub Actions automatically:
- creates a `vX.Y.Z` tag
- publishes a GitHub Release with the installers
- (optional) syncs installers to Cloudflare R2 under `negative-converter/release/vX.Y.Z/`

#### Cloudflare R2 sync (optional)

If you want the release workflow to upload installers to R2, add **one** of these GitHub Actions secret sets:

**Option A: R2 S3 API token**

- `R2_ACCESS_KEY_ID`
- `R2_SECRET_ACCESS_KEY`
- `R2_BUCKET`
- `R2_ENDPOINT` (e.g. `https://.r2.cloudflarestorage.com/`)

**Option B: Cloudflare API token (no S3 keys)**

- `CLOUDFLARE_API_TOKEN`
- `CLOUDFLARE_ACCOUNT_ID`
- `R2_BUCKET`

## ๐Ÿ’ก Development & Contributions

Feel free to fork, open issues, or submit pull requests with ideas or improvements.
This tool is designed to be simple, fast, and modifiable.

## ๐Ÿ“„ License

MIT License

## ๐Ÿ™ Acknowledgments

Special thanks to [LibRaw-Wasm by ybouane](https://github.com/ybouane/LibRaw-Wasm),
which made it possible to support various raw image formats such as `.cr2`, `.nef`, `.arw`, `.dng`, `.raw`, and `.rw2` directly in the browser via WebAssembly.
Your work was an essential reference and greatly accelerated development.