camera_with_gps 2.5.3 copy "camera_with_gps: ^2.5.3" to clipboard
camera_with_gps: ^2.5.3 copied to clipboard

Flutter plugin that captures photos with GPS coordinates embedded in EXIF. Includes pinch zoom, flash, aspect ratio toggle and gallery picker.

camera_with_gps #

pub package pub points likes license

A Flutter plugin that opens a full-screen camera UI and embeds the device's current GPS coordinates into the captured photo's EXIF metadata. Includes pinch-to-zoom, flash, aspect-ratio toggle, and a smart gallery picker.


Features #

  • ๐Ÿ“ธ Full-screen camera UI with shutter, flash, and camera switching.
  • ๐ŸŒ GPS coordinates written straight into the photo's EXIF tags (GPSLatitude, GPSLongitude, GPSLatitudeRef, GPSLongitudeRef).
  • ๐Ÿ” Pinch-to-zoom + preset buttons (0.5x / 1x / 2x), automatically filtered to what the active camera actually supports.
  • ๐Ÿ”ฆ Flash / torch control.
  • ๐Ÿ” Front / back camera switching.
  • ๐Ÿ“ 16:9 โ†” 4:3 aspect-ratio toggle.
  • ๐Ÿ–ผ๏ธ Gallery picker (optional toggle) โ€” on Android reads the original image via MediaStore.setRequireOriginal() so EXIF GPS survives the Android 10+ media redaction; standard image picker elsewhere.
  • โš ๏ธ GPS status banner when location services are disabled or permission is denied โ€” the camera keeps working, GPS is just skipped.
  • ๐Ÿงน Fake-GPS scrubbing โ€” on capture, 0,0 / missing coordinates are treated as no-fix and stripped so photos never ship with placeholder GPS.
  • ๐Ÿ“ฑ Orientation-aware photo rotation via on-device sensors, with platform- specific cropping logic.
  • โšก Low shutter latency โ€” location is pre-warmed in the background and bounded with a 2 s timeout so airplane-mode / cold-start GPS no longer blocks capture.

Installation #

Add the dependency:

dependencies:
  camera_with_gps: ^2.5.3

Then:

flutter pub get

Android #

Minimum SDK: 21. Add to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

The plugin also declares ACCESS_MEDIA_LOCATION (merged into your app automatically). It is required to read GPS EXIF from gallery images on Android 10+; the plugin requests it at runtime the first time you pick an image.

iOS #

Minimum deployment target: 12.0. Add to ios/Runner/Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos with GPS metadata.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to add GPS metadata to photos.</string>

Quick start #

import 'package:camera_with_gps/camera_with_gps.dart';
import 'package:flutter/material.dart';

class CapturePage extends StatelessWidget {
  const CapturePage({super.key});

  Future<void> _shoot(BuildContext context) async {
    final path = await CameraWithGps.openCamera(context);
    if (path != null) {
      // ...use the JPEG file at `path`.
    }
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () => _shoot(context),
          child: const Icon(Icons.camera_alt),
        ),
      );
}

A complete sample lives under example/.

API #

// Open the full-screen camera. `allowGallery` toggles the gallery button.
static Future<String?> openCamera(BuildContext context, {bool allowGallery = true});

// Shortcut: open the camera without the gallery button.
static Future<String?> openCameraPhotoOnly(BuildContext context);

// Pick an existing image (Samsung โ†’ SAF, others โ†’ standard gallery).
static Future<String?> pickFromGallery();

// Write GPS coordinates into the EXIF metadata of an existing JPEG.
static Future<bool> addGps({
  required String path,
  required double latitude,
  required double longitude,
});

// Strip GPS metadata from a JPEG.
static Future<bool> removeGps({required String path});

All Future<String?> results are JPEG file paths (or null on cancel).

Behavior #

GPS attachment. When the shutter is pressed, the plugin tries โ€” in order โ€” (1) the pre-warmed position kept fresh by a background stream, (2) the OS's last-known position, (3) a getCurrentPosition call with a 2 s timeout. If none yield a valid fix, any existing GPS tags on the captured file are scrubbed so the photo never ships with stale or fake coordinates.

Zoom range. Calls getMinZoomLevel() / getMaxZoomLevel() on init and on camera switch. Preset buttons (0.5x, 1x, 2x) appear only when they fall inside that range. On iOS the wide-angle lens reports min == 1.0, so the 0.5x button shows only when the active camera is a different lens. On Android CameraX handles automatic lens switching internally on multi-lens flagships (Pixel 6+, Galaxy S21+), so setZoomLevel(0.6) may transparently engage the ultra-wide camera.

Orientation. The UI is locked to portrait. Photo rotation is computed from sensor orientation (OrientationService) and applied per-platform (PhotoProcessorAndroid / PhotoProcessorIOS).

Gallery GPS preservation (Android). On Android 10+ the OS redacts location EXIF from any image read through a content URI unless the app holds ACCESS_MEDIA_LOCATION and reads the original. The plugin therefore picks via ACTION_PICK on the MediaStore images collection, requests ACCESS_MEDIA_LOCATION at runtime, and reads the un-redacted bytes through MediaStore.setRequireOriginal(). This keeps GPS intact on Samsung and other devices where ImagePicker would otherwise return a stripped copy. Picked images are returned as-is โ€” valid GPS is never auto-scrubbed; call removeGps yourself if you want to strip it.

Reading the embedded EXIF #

import 'dart:io';
import 'package:exif/exif.dart';

final bytes = await File(path).readAsBytes();
final tags = await readExifFromBytes(bytes);

final gps = {
  for (final e in tags.entries)
    if (e.key.startsWith('GPS')) e.key: e.value.printable,
};

Project layout #

lib/
โ”œโ”€โ”€ camera_with_gps.dart            โ† public library entry (barrel)
โ”‚
โ”œโ”€โ”€ pages/
โ”‚   โ””โ”€โ”€ camera_preview_page.dart    โ† stateful camera shell
โ”‚
โ”œโ”€โ”€ services/
โ”‚   โ”œโ”€โ”€ camera_with_gps.dart        โ† static API class
โ”‚   โ”œโ”€โ”€ orientation_service.dart    โ† sensor-driven orientation stream
โ”‚   โ”œโ”€โ”€ photo_processor.dart        โ† platform facade
โ”‚   โ”œโ”€โ”€ photo_processor_android.dart
โ”‚   โ””โ”€โ”€ photo_processor_ios.dart
โ”‚
โ””โ”€โ”€ widgets/
    โ”œโ”€โ”€ bottom_bar.dart             โ† shutter row + zoom presets slot
    โ”œโ”€โ”€ top_bar.dart                โ† close / flash / ratio
    โ”œโ”€โ”€ preview_box.dart            โ† platform facade for live preview
    โ”œโ”€โ”€ preview_box_android.dart
    โ”œโ”€โ”€ preview_box_ios.dart
    โ”œโ”€โ”€ zoom_presets.dart           โ† 0.5x / 1x / 2x pill
    โ”œโ”€โ”€ shutter_button.dart
    โ”œโ”€โ”€ rot_icon.dart               โ† orientation-aware icon
    โ”œโ”€โ”€ gps_banner.dart
    โ””โ”€โ”€ error_ui.dart

Limitations #

  • The plugin uses the wide-angle back camera by default. On iPhones with multiple physical lenses, switching to ultra-wide or telephoto requires recreating the CameraController with a different CameraDescription returned by availableCameras() โ€” not implemented out of the box.
  • Pure digital zoom only โ€” no built-in support for AVFoundation's builtInTripleCamera smooth lens transitions.
  • Gallery-picked images are returned as-is; the plugin does not add or strip GPS on them (it only preserves what is already there). Use addGps / removeGps explicitly if you need to modify a picked image.

Contributing #

Issues and pull requests are welcome at https://github.com/RuslanMadzhara/camera_with_gps.

  1. Fork the repository.
  2. Create a feature branch: git checkout -b feature/your-feature.
  3. Commit: git commit -m 'Add some feature'.
  4. Push: git push origin feature/your-feature.
  5. Open a Pull Request.

License #

MIT โ€” see LICENSE.

Author #

Ruslan Madzhara ยท LinkedIn

3
likes
140
points
407
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin that captures photos with GPS coordinates embedded in EXIF. Includes pinch zoom, flash, aspect ratio toggle and gallery picker.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

camera, flutter, geolocator, image, image_picker, native_device_orientation, plugin_platform_interface

More

Packages that depend on camera_with_gps

Packages that implement camera_with_gps