728x90

플러터에서 사진촬영 또는 사진 이미지에서 위치좌표를 추출하는 방법을 알아보자.

 

사진을 찍을 때 위치좌표값이 포함되어 저장되도록 하는 방법은 카메라에서 위치정보를 활성화시켜야 한다.

아이폰

설정 → 개인정보 보호 및 보안 → 위치서비스 → 카메라 → 앱을 사용하는 동안

안드로이드폰

카메라 앱 → 카메라 설정 → 위치태그 활성화

 

위와 같이 하면 기본적으로 사진을 찍으면 이미지에 위치정보가 포함된다.

하지만 구현하는 앱에서 카메라로 촬영해도 위치정보가 포함되지 않을 수도 있다.

이 경우에는 사진을 찍는 시점의 GPS 위치정보를 기준으로 위치정보를 수집해야 한다.

 

pubspec.yaml 파일

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  dio: ^5.4.0
  retrofit: ^4.0.3
  flutter_riverpod: ^2.4.9
  json_annotation: ^4.8.1
  freezed_annotation: ^2.4.1
  permission_handler: ^11.2.0
  flutter_secure_storage: ^9.0.0
  image_picker: ^1.0.7
  exif: ^3.3.0
  geolocator: ^10.1.0
 
 
dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0
  build_runner: ^2.4.8
  json_serializable: ^6.7.1
  freezed: ^2.4.6
  retrofit_generator: ^8.0.6

 

 

앨범 및 사진촬영한 이미지를 앱 화면에 보여주는 예제 코드

import 'dart:io';
 
import 'package:exif/exif.dart';
import 'package:fileupload/presentation/view/file_upload_screen.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:image_picker/image_picker.dart';
 
class ImageViewScreen extends StatefulWidget {
  const ImageViewScreen({super.key});
 
  @override
  State<ImageViewScreen> createState() => _ImageViewScreenState();
}
 
class _ImageViewScreenState extends State<ImageViewScreen> {
  XFile? _image; //이미지 담을 변수 선언
  double latitude = 0;
  double longitude = 0;
  bool isLocation = false;
 
  @override
  void initState() {
    super.initState();
    getLocationPermission();
  }
 
  Future<void> getLocationPermission() async {
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
    }
  }
 
  Future<void> getImage(ImageSource imageSource) async {
    var picker = ImagePicker();
    var pickerImage = await picker.pickImage(source: imageSource);
 
    // 이미지를 읽을 때마다 위치정보 좌표값 초기화 처리
    latitude = 0;
    longitude = 0;
 
    if (pickerImage != null) {
      var metadata = await readExifFromBytes(File(pickerImage.path).readAsBytesSync());
      if (metadata.containsKey('GPS GPSLatitude')) {
        print("location enabled");
        isLocation = true;
        getCurrentLocationFromexif(metadata);
      } else {
        isLocation = false;
        print("location disabled");
        try {
          Position position = await Geolocator.getCurrentPosition(
              desiredAccuracy: LocationAccuracy.high);
          latitude = position.latitude;
          longitude = position.longitude;
        } catch (e) {
          print(e);
        }
      }
      // 이미지를 출력하기 위해 상태 변경
      setState(() {
        _image = XFile(pickerImage.path);
      });
    }
  }
 
  Future<void> getCurrentLocationFromexif(var data) async {
    if (data.containsKey('GPS GPSLongitude')) {
      final gpsLatitude = data['GPS GPSLatitude'];
      final latitudeSignal = data['GPS GPSLatitudeRef']!.printable;
      List latitudeRation = gpsLatitude!.values.toList();
      List latitudeValue = latitudeRation.map((item) {
        return (item.numerator.toDouble() / item.denominator.toDouble());
      }).toList();
      latitude = latitudeValue[0+ (latitudeValue[1/ 60+
          (latitudeValue[2/ 3600);
      if (latitudeSignal == 'S') latitude = -latitude;
      print('latitude ::: ${latitude}');
 
      final gpsLongitude = data['GPS GPSLongitude'];
      final longitudeSignal = data['GPS GPSLongitude']!.printable;
      List longitudeRation = gpsLongitude!.values.toList();
      List longitudeValue = longitudeRation.map((item) {
        return (item.numerator.toDouble() / item.denominator.toDouble());
      }).toList();
      longitude = longitudeValue[0+ (longitudeValue[1/ 60+
          (longitudeValue[2/ 3600);
      if (longitudeSignal == 'W') longitude = -longitude;
      print('longitude ::: ${longitude}');
    }
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _buildPhotoArea(),
          if(latitude > 0) _buildLocation(),
        ],
      ),
      floatingActionButton: Stack(
        children: [
          Align(
            alignment: Alignment(
                Alignment.bottomRight.x, Alignment.bottomRight.y - 0.4),
            child: FloatingActionButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => const FileUploadScreen(),
                ));
              },
              tooltip: 'back',
              heroTag: UniqueKey(),
              child: const Icon(Icons.arrow_back),
            ),
          ),
          Align(
            alignment: Alignment(
                Alignment.bottomRight.x, Alignment.bottomRight.y - 0.2),
            child: FloatingActionButton(
              onPressed: () async {
                getImage(ImageSource.camera);
              },
              tooltip: 'image',
              heroTag: UniqueKey(),
              child: const Icon(Icons.camera_alt),
            ),
          ),
          Align(
            alignment: Alignment.bottomRight,
            child: FloatingActionButton(
              onPressed: () async {
                getImage(ImageSource.gallery);
              },
              tooltip: 'image',
              heroTag: UniqueKey(),
              child: const Icon(Icons.image),
            ),
          ),
        ],
      ),
    );
  }
 
  Widget _buildPhotoArea() {
    return _image != null
        ? Container(
            width: 400,
            height: 400,
            child: Image.file(File(_image!.path)), //가져온 이미지 화면에 띄워주는 코드
          )
        : const Center(
            child: Text("불러온 이미지가 없습니다."),
          );
  }
 
  Widget _buildLocation() {
    return Column(
      children: [
        Container(
          child: Text('GPS Location ::: $isLocation'),
        ),
        Container(
          child: Text('위도: ${latitude} ,경도: ${longitude}'),
        ),
      ],
    );
  }
 
}

 

 

위 소스코드를 보다 정리한 모든 소스코드 파일은 GitHub 에 올려두었다.

https://github.com/jsk005/Flutter/tree/main/fileupload/2nd

 

블로그 이미지

Link2Me

,