native_exif 0.6.0 native_exif: ^0.6.0 copied to clipboard
A plugin to read and write exif data of images.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:native_exif/native_exif.dart';
void main() {
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({
super.key,
});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final picker = ImagePicker();
XFile? pickedFile;
Exif? exif;
Map<String, Object>? attributes;
DateTime? shootingDate;
ExifLatLong? coordinates;
@override
void initState() {
super.initState();
}
Future<void> showError(Object e) async {
debugPrintStack(label: e.toString(), stackTrace: e is Error ? e.stackTrace : null);
return showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Error'),
content: SingleChildScrollView(
child: ListBody(
children: [
Text(e.toString()),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Future getImage() async {
pickedFile = await picker.pickImage(source: ImageSource.gallery);
if (pickedFile == null) {
return;
}
exif = await Exif.fromPath(pickedFile!.path);
attributes = await exif!.getAttributes();
shootingDate = await exif!.getOriginalDate();
coordinates = await exif!.getLatLong();
setState(() {});
}
Future closeImage() async {
await exif?.close();
shootingDate = null;
attributes = {};
exif = null;
coordinates = null;
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (pickedFile == null)
const Text("Please open an image.")
else
Column(
children: [
Text("The selected image has ${attributes?.length ?? 0} attributes."),
Text("It was taken at ${shootingDate.toString()}"),
Text(attributes?["UserComment"]?.toString() ?? ''),
Text("Attributes: $attributes"),
Text("Coordinates: $coordinates"),
TextButton(
onPressed: () async {
try {
final dateFormat = DateFormat('yyyy:MM:dd HH:mm:ss');
await exif!.writeAttribute('DateTimeOriginal', dateFormat.format(DateTime.now()));
shootingDate = await exif!.getOriginalDate();
attributes = await exif!.getAttributes();
setState(() {});
} catch (e) {
showError(e);
}
},
child: const Text('Update date attribute'),
),
TextButton(
onPressed: () async {
try {
// Get original attributes.
final attrs = await exif!.getAttributes();
debugPrint('Original attributes of ${pickedFile!.path}:');
debugPrint(attrs.toString());
final dateFormat = DateFormat('yyyy:MM:dd HH:mm:ss');
debugPrint('Write DateTimeOriginal ${dateFormat.format(DateTime.now())}');
await exif!.writeAttribute('DateTimeOriginal', dateFormat.format(DateTime.now()));
await exif!.writeAttributes({
'GPSLatitude': '1.0',
'GPSLatitudeRef': 'N',
'GPSLongitude': '2.0',
'GPSLongitudeRef': 'W',
});
shootingDate = await exif!.getOriginalDate();
attributes = await exif!.getAttributes();
debugPrint('New attributes:');
debugPrint(shootingDate.toString());
debugPrint(attributes.toString());
final dir = await getApplicationDocumentsDirectory();
final newPath = p.join(dir.path, p.basename(pickedFile!.path));
debugPrint('New path:');
debugPrint(newPath);
final newFile = File(newPath);
await newFile.writeAsBytes(await pickedFile!.readAsBytes());
pickedFile = XFile(newPath);
exif = await Exif.fromPath(newPath);
attributes = await exif!.getAttributes();
shootingDate = await exif!.getOriginalDate();
coordinates = await exif!.getLatLong();
debugPrint('Attributes of $newPath:');
debugPrint(shootingDate.toString());
debugPrint(coordinates.toString());
debugPrint(attributes.toString());
setState(() {});
} catch (e) {
showError(e);
}
},
child: const Text('Update, store and reload attributes'),
),
TextButton(
onPressed: () async {
try {
await exif!.writeAttribute('Orientation', '1');
attributes = await exif!.getAttributes();
setState(() {});
} catch (e) {
showError(e);
}
},
child: const Text('Set orientation to 1'),
),
TextButton(
onPressed: () async {
try {
await exif!.writeAttributes({
'GPSLatitude': '1.0',
'GPSLatitudeRef': 'N',
'GPSLongitude': '2.0',
'GPSLongitudeRef': 'W',
});
shootingDate = await exif!.getOriginalDate();
attributes = await exif!.getAttributes();
coordinates = await exif!.getLatLong();
setState(() {});
} catch (e) {
showError(e);
}
},
child: const Text('Update GPS attributes'),
),
ElevatedButton(
onPressed: closeImage,
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.red)),
child: const Text('Close image'),
)
],
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: getImage,
child: const Text('Open image'),
),
if (pickedFile != null)
ElevatedButton(
onPressed: () async {
try {
final file = File(p.join(Directory.systemTemp.path, 'tempimage.jpg'));
final imageBytes = await pickedFile!.readAsBytes();
await file.create();
await file.writeAsBytes(imageBytes);
final _attributes = await exif?.getAttributes() ?? {};
final newExif = await Exif.fromPath(file.path);
_attributes['DateTimeOriginal'] = '2021:05:15 13:00:00';
_attributes['UserComment'] = "This file is user generated!";
await newExif.writeAttributes(_attributes);
shootingDate = await newExif.getOriginalDate();
attributes = await newExif.getAttributes();
coordinates = await newExif.getLatLong();
setState(() {});
} catch (e) {
showError(e);
}
},
child: const Text("Create file and write exif data"),
),
],
),
),
);
}
}