✨ Client side remove GPS EXIF
This commit is contained in:
parent
e29a2fc054
commit
15a5848785
@ -8,6 +8,7 @@ import 'package:cross_file/cross_file.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
|
import 'package:native_exif/native_exif.dart';
|
||||||
import 'package:tus_client_dart/tus_client_dart.dart';
|
import 'package:tus_client_dart/tus_client_dart.dart';
|
||||||
|
|
||||||
Future<XFile?> cropImage(
|
Future<XFile?> cropImage(
|
||||||
@ -46,7 +47,91 @@ Completer<SnCloudFile?> putMediaToCloud({
|
|||||||
String? mimetype,
|
String? mimetype,
|
||||||
Function(double progress, Duration estimate)? onProgress,
|
Function(double progress, Duration estimate)? onProgress,
|
||||||
}) {
|
}) {
|
||||||
XFile file;
|
final completer = Completer<SnCloudFile?>();
|
||||||
|
|
||||||
|
// Process the image to remove GPS EXIF data if needed
|
||||||
|
if (fileData.isOnDevice && fileData.type == UniversalFileType.image) {
|
||||||
|
final data = fileData.data;
|
||||||
|
if (data is XFile && !kIsWeb && (Platform.isIOS || Platform.isAndroid)) {
|
||||||
|
// Use native_exif to selectively remove GPS data
|
||||||
|
Exif.fromPath(data.path)
|
||||||
|
.then((exif) {
|
||||||
|
// Remove GPS-related attributes
|
||||||
|
final gpsAttributes = [
|
||||||
|
'GPSLatitude',
|
||||||
|
'GPSLatitudeRef',
|
||||||
|
'GPSLongitude',
|
||||||
|
'GPSLongitudeRef',
|
||||||
|
'GPSAltitude',
|
||||||
|
'GPSAltitudeRef',
|
||||||
|
'GPSTimeStamp',
|
||||||
|
'GPSProcessingMethod',
|
||||||
|
'GPSDateStamp',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create a map of attributes to clear
|
||||||
|
final clearAttributes = <String, String>{};
|
||||||
|
for (final attr in gpsAttributes) {
|
||||||
|
clearAttributes[attr] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write empty values to remove GPS data
|
||||||
|
return exif.writeAttributes(clearAttributes);
|
||||||
|
})
|
||||||
|
.then((_) {
|
||||||
|
// Continue with upload after GPS data is removed
|
||||||
|
_processUpload(
|
||||||
|
fileData,
|
||||||
|
atk,
|
||||||
|
baseUrl,
|
||||||
|
filename,
|
||||||
|
mimetype,
|
||||||
|
onProgress,
|
||||||
|
completer,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catchError((e) {
|
||||||
|
// If there's an error, continue with the original file
|
||||||
|
debugPrint('Error removing GPS EXIF data: $e');
|
||||||
|
_processUpload(
|
||||||
|
fileData,
|
||||||
|
atk,
|
||||||
|
baseUrl,
|
||||||
|
filename,
|
||||||
|
mimetype,
|
||||||
|
onProgress,
|
||||||
|
completer,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return completer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not an image or on web, continue with normal upload
|
||||||
|
_processUpload(
|
||||||
|
fileData,
|
||||||
|
atk,
|
||||||
|
baseUrl,
|
||||||
|
filename,
|
||||||
|
mimetype,
|
||||||
|
onProgress,
|
||||||
|
completer,
|
||||||
|
);
|
||||||
|
return completer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to process the upload after any EXIF processing
|
||||||
|
Completer<SnCloudFile?> _processUpload(
|
||||||
|
UniversalFile fileData,
|
||||||
|
String atk,
|
||||||
|
String baseUrl,
|
||||||
|
String? filename,
|
||||||
|
String? mimetype,
|
||||||
|
Function(double progress, Duration estimate)? onProgress,
|
||||||
|
Completer<SnCloudFile?> completer,
|
||||||
|
) {
|
||||||
|
late XFile file;
|
||||||
String actualFilename = filename ?? 'randomly_file';
|
String actualFilename = filename ?? 'randomly_file';
|
||||||
String actualMimetype = mimetype ?? '';
|
String actualMimetype = mimetype ?? '';
|
||||||
Uint8List? byteData;
|
Uint8List? byteData;
|
||||||
@ -63,16 +148,23 @@ Completer<SnCloudFile?> putMediaToCloud({
|
|||||||
actualFilename = filename ?? 'uploaded_file';
|
actualFilename = filename ?? 'uploaded_file';
|
||||||
actualMimetype = mimetype ?? 'application/octet-stream';
|
actualMimetype = mimetype ?? 'application/octet-stream';
|
||||||
if (mimetype == null) {
|
if (mimetype == null) {
|
||||||
throw ArgumentError('Mimetype is required when providing raw bytes.');
|
completer.completeError(
|
||||||
|
ArgumentError('Mimetype is required when providing raw bytes.'),
|
||||||
|
);
|
||||||
|
return completer;
|
||||||
}
|
}
|
||||||
file = XFile.fromData(byteData!, mimeType: actualMimetype);
|
file = XFile.fromData(byteData!, mimeType: actualMimetype);
|
||||||
} else if (data is SnCloudFile) {
|
} else if (data is SnCloudFile) {
|
||||||
// If the file is already on the cloud, just return it
|
// If the file is already on the cloud, just return it
|
||||||
return Completer<SnCloudFile?>()..complete(data);
|
completer.complete(data);
|
||||||
|
return completer;
|
||||||
} else {
|
} else {
|
||||||
throw ArgumentError(
|
completer.completeError(
|
||||||
'Invalid fileData type. Expected data to be XFile, List<int>, Uint8List, or SnCloudFile.',
|
ArgumentError(
|
||||||
|
'Invalid fileData type. Expected data to be XFile, List<int>, Uint8List, or SnCloudFile.',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
return completer;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, String> metadata = {
|
final Map<String, String> metadata = {
|
||||||
@ -80,8 +172,6 @@ Completer<SnCloudFile?> putMediaToCloud({
|
|||||||
'content-type': actualMimetype,
|
'content-type': actualMimetype,
|
||||||
};
|
};
|
||||||
|
|
||||||
final completer = Completer<SnCloudFile?>();
|
|
||||||
|
|
||||||
final client = TusClient(file);
|
final client = TusClient(file);
|
||||||
client
|
client
|
||||||
.upload(
|
.upload(
|
||||||
|
@ -1397,6 +1397,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
native_exif:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: native_exif
|
||||||
|
sha256: "0d37444c1ed00cbcada69b7510aba1d505fed75d3b6ef3ea3c8c2c970040e4f1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.2"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -115,6 +115,7 @@ dependencies:
|
|||||||
fl_chart: ^1.0.0
|
fl_chart: ^1.0.0
|
||||||
sign_in_with_apple: ^7.0.1
|
sign_in_with_apple: ^7.0.1
|
||||||
flutter_svg: ^2.1.0
|
flutter_svg: ^2.1.0
|
||||||
|
native_exif: ^0.6.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user