import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:file_selector/file_selector.dart'; class BauteilPhotoService { Future 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 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(); } } }