68 lines
2.0 KiB
Dart
68 lines
2.0 KiB
Dart
import 'dart:math' as math;
|
|
import 'dart:typed_data';
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:file_selector/file_selector.dart';
|
|
|
|
class BauteilPhotoService {
|
|
Future<Uint8List?> pickPhoto() async {
|
|
const images = XTypeGroup(
|
|
label: 'Fotos',
|
|
extensions: ['jpg', 'jpeg', 'png', 'webp'],
|
|
uniformTypeIdentifiers: [
|
|
'public.jpeg',
|
|
'public.png',
|
|
'org.webmproject.webp',
|
|
],
|
|
mimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
|
|
);
|
|
final file = await openFile(acceptedTypeGroups: [images]);
|
|
if (file == null) return null;
|
|
if (await file.length() > 15 * 1024 * 1024) {
|
|
throw const FormatException('Das Foto darf höchstens 15 MB groß sein.');
|
|
}
|
|
return preparePhoto(await file.readAsBytes());
|
|
}
|
|
|
|
/// Stores a small, self-contained PNG, independent of temporary file paths.
|
|
Future<Uint8List> preparePhoto(Uint8List bytes) async {
|
|
final buffer = await ui.ImmutableBuffer.fromUint8List(bytes);
|
|
try {
|
|
final descriptor = await ui.ImageDescriptor.encoded(buffer);
|
|
try {
|
|
final scale = math.min(
|
|
1.0,
|
|
960 / math.max(descriptor.width, descriptor.height),
|
|
);
|
|
final codec = await descriptor.instantiateCodec(
|
|
targetWidth: math.max(1, (descriptor.width * scale).round()),
|
|
targetHeight: math.max(1, (descriptor.height * scale).round()),
|
|
);
|
|
try {
|
|
final frame = await codec.getNextFrame();
|
|
try {
|
|
final data = await frame.image.toByteData(
|
|
format: ui.ImageByteFormat.png,
|
|
);
|
|
if (data == null) {
|
|
throw const FormatException('Foto konnte nicht gelesen werden.');
|
|
}
|
|
return data.buffer.asUint8List(
|
|
data.offsetInBytes,
|
|
data.lengthInBytes,
|
|
);
|
|
} finally {
|
|
frame.image.dispose();
|
|
}
|
|
} finally {
|
|
codec.dispose();
|
|
}
|
|
} finally {
|
|
descriptor.dispose();
|
|
}
|
|
} finally {
|
|
buffer.dispose();
|
|
}
|
|
}
|
|
}
|