No description
  • Kotlin 96.5%
  • GLSL 2.9%
  • Shell 0.6%
Find a file
Ole-Morten Duesund 5b553c7196 Drive renderer rotation from Display.rotation, not OrientationEventListener
OrientationEventListener fires continuously on the raw accelerometer
tilt and crosses the ROTATION_90 / ROTATION_270 boundary at 45° — well
before the system actually rotates the activity. The renderer was
swapping its texcoord buffer at 45° tilt while the GL surface and
Compose layout were still in the previous orientation, so for the few
degrees between "OrientationEventListener fires" and "activity
rotates" the camera image rendered at the wrong rotation. Past that
window it snapped back into sync.

Use LocalConfiguration + Display.rotation to source the renderer's
rotation. Configuration only changes when the activity has actually
rotated, so the texcoord buffer flips in lock-step with the GL surface
and there is no transient mis-orientation. OrientationEventListener
is still used by capture for EXIF metadata.

Bump to 1.1.13.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:22:54 +02:00
.dogcats Add dcat issue tracking setup 2026-05-11 13:50:39 +02:00
app Drive renderer rotation from Display.rotation, not OrientationEventListener 2026-05-11 16:22:54 +02:00
gradle Update all dependencies to March 2026 versions 2026-03-18 17:46:37 +01:00
.gitattributes Add dcat issue tracking setup 2026-05-11 13:50:39 +02:00
.gitignore Add dcat issue tracking setup 2026-05-11 13:50:39 +02:00
AGENTS.md Add dcat issue tracking setup 2026-05-11 13:50:39 +02:00
build.gradle.kts Update all dependencies to March 2026 versions 2026-03-18 17:46:37 +01:00
bump-version.sh Add version management with auto-bump script 2026-03-05 13:58:22 +01:00
CLAUDE.md Add dcat issue tracking setup 2026-05-11 13:50:39 +02:00
gradle.properties Initial implementation of Tilt-Shift Camera Android app 2026-01-28 15:26:41 +01:00
gradlew Initial implementation of Tilt-Shift Camera Android app 2026-01-28 15:26:41 +01:00
gradlew.bat Initial implementation of Tilt-Shift Camera Android app 2026-01-28 15:26:41 +01:00
LICENSE Add MIT license 2026-03-05 13:50:37 +01:00
README.md Remove dead code 2026-02-27 15:24:17 +01:00
settings.gradle.kts Initial implementation of Tilt-Shift Camera Android app 2026-01-28 15:26:41 +01:00
tiltshift-spec.md Add radial mode, UI controls, front camera, update to API 35 2026-01-29 11:13:31 +01:00
version.properties Drive renderer rotation from Display.rotation, not OrientationEventListener 2026-05-11 16:22:54 +02:00

Tilt-Shift Camera

A dedicated Android camera app for tilt-shift photography with real-time preview, touch-based controls, and proper EXIF handling.

Features

  • Real-time tilt-shift effect preview - See the blur effect as you compose your shot
  • Touch-based controls:
    • Single finger drag to move the focus line position
    • Two-finger rotation to adjust blur angle
    • Pinch gesture to adjust blur zone size
    • Pinch in center to zoom camera
  • Zoom controls - Quick presets (0.5x, 1x, 2x, 5x) plus pinch-to-zoom
  • Auto picture orientation detection - Photos saved with correct EXIF orientation
  • GPS location tagging - Optional EXIF GPS data from device location
  • Haptic feedback - Tactile response for all interactions
  • Saves to gallery - Photos saved to Pictures/TiltShift/ folder

Requirements

  • Android 15 (API 35) or higher
  • Device with camera
  • OpenGL ES 2.0 support

Building

  1. Open the project in Android Studio
  2. Sync Gradle files
  3. Build and run on a physical device (camera preview won't work on emulator)

Or from command line:

./gradlew assembleDebug

Permissions

  • Camera (required) - For capturing photos
  • Location (optional) - For GPS tagging in EXIF data
  • Vibrate - For haptic feedback

Architecture

The app uses:

  • CameraX - Jetpack camera library for camera preview and capture
  • OpenGL ES 2.0 - Real-time shader-based blur effect
  • Jetpack Compose - Modern declarative UI
  • Kotlin Coroutines & Flow - Asynchronous operations and state management

Project Structure

app/src/main/java/no/naiv/tiltshift/
├── MainActivity.kt           # Entry point with permission handling
├── camera/
│   ├── CameraManager.kt      # CameraX setup and control
│   ├── LensController.kt     # Lens/zoom switching
│   └── ImageCaptureHandler.kt # Photo capture with effect
├── effect/
│   ├── TiltShiftRenderer.kt  # OpenGL renderer
│   ├── TiltShiftShader.kt    # GLSL shader management
│   └── BlurParameters.kt     # Effect state
├── ui/
│   ├── CameraScreen.kt       # Main Compose screen
│   ├── TiltShiftOverlay.kt   # Touch gesture handling & visualization
│   ├── ZoomControl.kt        # Zoom UI component
│   └── LensSwitcher.kt       # Lens selection UI
├── storage/
│   └── PhotoSaver.kt         # MediaStore integration & EXIF handling
└── util/
    ├── OrientationDetector.kt
    ├── LocationProvider.kt
    └── HapticFeedback.kt

How the Tilt-Shift Effect Works

The tilt-shift effect simulates a selective focus lens that makes scenes appear miniature. The app achieves this through:

  1. Camera Preview → OpenGL SurfaceTexture
  2. Fragment Shader calculates distance from the focus line for each pixel
  3. Gradient blur is applied based on distance - center stays sharp, edges blur
  4. Two-pass Gaussian blur (optimized as separable passes) for quality and performance

License

MIT