← projects

$ PixelLab

[2026]
TypeScriptReact NativeExpojpeg-js
code ↗

$ cat README.md· github/jntbatra/pixellab-image-processing

PixelLab — Image Processing Lab 📸

A React Native (Expo) app that captures a photo and applies classic digital image-processing algorithms, each with a built-in "How it works" explainer. Black & orange interface. Every filter is implemented from scratch in TypeScript (no OpenCV) so the math matches the course material.

Algorithms are drawn from the syllabus decks:


Features

Filter catalogue

Category Filters
Intensity Negative · Log · Power-Law (Gamma) · Contrast Stretch · Intensity Slicing · Bit-Plane Slicing
Histogram Histogram Equalization (YCbCr, colour-preserving)
Smoothing / Restoration Box (Mean) · Gaussian · Median · Min · Max · Midpoint · Geometric Mean · Harmonic Mean · Contraharmonic Mean · Alpha-Trimmed Mean · Adaptive Median
Sharpening Laplacian · Laplacian Sharpen · Unsharp / High-Boost
Edges Sobel · Prewitt · Laplacian Edges · Canny · Laplacian of Gaussian · Difference of Gaussians
Features / Segmentation Global Threshold · Otsu · Adaptive Threshold · Local Binary Pattern · Harris Corners · Hough Lines
Noise (for restoration demos) Add Gaussian Noise · Add Salt & Pepper

How the image pipeline works

React Native has no built-in raw-pixel access, so:

  1. expo-image-manipulator resizes the photo (longest edge ≤ MAX_DIM, 620px) and returns base64 JPEG.
  2. jpeg-js decodes it to an RGBAImage (Uint8ClampedArray).
  3. The pure-TS filter runs on the pixel array (src/ip/filters/*).
  4. jpeg-js encodes the result back to a data: URI shown in <Image>.
  5. Saving writes the base64 to a cache file and hands it to expo-media-library.

jpeg-js needs a Node Buffer; src/polyfills.ts provides one and is imported first in index.ts.

Project layout

src/
  ip/
    types.ts          RGBAImage, Filter, FilterDoc definitions
    core.ts           clamp, grayscale, convolution, histogram, Gaussian kernels …
    codec.ts          jpeg-js decode / encode
    pipeline.ts       load photo → RGBA, render RGBA → data URI
    registry.ts       every Filter: metadata + docs + apply()
    filters/          intensity · histogram · smoothing · sharpening · edges · features · noise
  components/         ParamSlider, InfoSheet
  screens/            CameraScreen, EditorScreen
  theme.ts            black & orange design tokens
scripts/
  test-filters.ts     Node smoke test for every algorithm + codec round-trip

Develop / run

Requires Node 18+. (This machine used a conda env: conda activate rnip.)

npm install
npm run typecheck        # tsc --noEmit — should be clean
npm run test:filters     # runs all 35 filters on a synthetic image

npm start                # Expo dev server — scan the QR with Expo Go
# or: npm run android / npm run ios

Camera + saving need a physical device (Expo Go) or a dev build — the simulator has no camera. Library-pick works everywhere.


Notes