♻️ Improved image analyzer in attachments
This commit is contained in:
		@@ -31,23 +31,27 @@ Future<String> calculateFileSha256(File file) async {
 | 
				
			|||||||
  return await calculateBytesSha256(bytes);
 | 
					  return await calculateBytesSha256(bytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Future<double> calculateDataAspectRatio(Uint8List data) async {
 | 
					Future<Map<String, dynamic>> calculateImageData(Uint8List data) async {
 | 
				
			||||||
  if (PlatformInfo.isWeb) {
 | 
					  if (PlatformInfo.isWeb) {
 | 
				
			||||||
    return 1;
 | 
					    return {};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  final decoder = await Isolate.run(() => img.findDecoderForData(data));
 | 
					  final decoder = await Isolate.run(() => img.findDecoderForData(data));
 | 
				
			||||||
  if (decoder == null) return 1;
 | 
					  if (decoder == null) return {};
 | 
				
			||||||
  final image = await Isolate.run(() => decoder.decode(data));
 | 
					  final image = await Isolate.run(() => decoder.decode(data));
 | 
				
			||||||
  if (image == null) return 1;
 | 
					  if (image == null) return {};
 | 
				
			||||||
  return image.width / image.height;
 | 
					  return {
 | 
				
			||||||
 | 
					    'width': image.width,
 | 
				
			||||||
 | 
					    'height': image.height,
 | 
				
			||||||
 | 
					    'ratio': image.width / image.height
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Future<double> calculateFileAspectRatio(File file) async {
 | 
					Future<Map<String, dynamic>> calculateImageMetaFromFile(File file) async {
 | 
				
			||||||
  if (PlatformInfo.isWeb) {
 | 
					  if (PlatformInfo.isWeb) {
 | 
				
			||||||
    return 1;
 | 
					    return {};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  final bytes = await Isolate.run(() => file.readAsBytesSync());
 | 
					  final bytes = await Isolate.run(() => file.readAsBytesSync());
 | 
				
			||||||
  return await calculateDataAspectRatio(bytes);
 | 
					  return await calculateImageData(bytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AttachmentProvider extends GetConnect {
 | 
					class AttachmentProvider extends GetConnect {
 | 
				
			||||||
@@ -75,8 +79,12 @@ class AttachmentProvider extends GetConnect {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<Response> createAttachment(
 | 
					  Future<Response> createAttachment(
 | 
				
			||||||
      Uint8List data, String path, String hash, String usage,
 | 
					    Uint8List data,
 | 
				
			||||||
      {double? ratio}) async {
 | 
					    String path,
 | 
				
			||||||
 | 
					    String hash,
 | 
				
			||||||
 | 
					    String usage,
 | 
				
			||||||
 | 
					    Map<String, dynamic>? metadata,
 | 
				
			||||||
 | 
					  ) async {
 | 
				
			||||||
    final AuthProvider auth = Get.find();
 | 
					    final AuthProvider auth = Get.find();
 | 
				
			||||||
    if (!await auth.isAuthorized) throw Exception('unauthorized');
 | 
					    if (!await auth.isAuthorized) throw Exception('unauthorized');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -104,9 +112,7 @@ class AttachmentProvider extends GetConnect {
 | 
				
			|||||||
      'hash': hash,
 | 
					      'hash': hash,
 | 
				
			||||||
      'usage': usage,
 | 
					      'usage': usage,
 | 
				
			||||||
      if (mimetypeOverride != null) 'mimetype': mimetypeOverride,
 | 
					      if (mimetypeOverride != null) 'mimetype': mimetypeOverride,
 | 
				
			||||||
      'metadata': jsonEncode({
 | 
					      'metadata': jsonEncode(metadata),
 | 
				
			||||||
        if (ratio != null) 'ratio': ratio,
 | 
					 | 
				
			||||||
      }),
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    final resp = await client.post('/attachments', payload);
 | 
					    final resp = await client.post('/attachments', payload);
 | 
				
			||||||
    if (resp.statusCode != 200) {
 | 
					    if (resp.statusCode != 200) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,12 +87,14 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> {
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      final file = File(image.path);
 | 
					      final file = File(image.path);
 | 
				
			||||||
      final hash = await calculateFileSha256(file);
 | 
					      final hash = await calculateFileSha256(file);
 | 
				
			||||||
 | 
					      final meta =  await calculateImageMetaFromFile(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      attachResp = await provider.createAttachment(
 | 
					      attachResp = await provider.createAttachment(
 | 
				
			||||||
        await file.readAsBytes(),
 | 
					        await file.readAsBytes(),
 | 
				
			||||||
        file.path,
 | 
					        file.path,
 | 
				
			||||||
        hash,
 | 
					        hash,
 | 
				
			||||||
        'p.$position',
 | 
					        'p.$position',
 | 
				
			||||||
        ratio: await calculateFileAspectRatio(file),
 | 
					        {...meta},
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      setState(() => _isBusy = false);
 | 
					      setState(() => _isBusy = false);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,13 +54,14 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
    for (final media in medias) {
 | 
					    for (final media in medias) {
 | 
				
			||||||
      final file = File(media.path);
 | 
					      final file = File(media.path);
 | 
				
			||||||
      final hash = await calculateFileSha256(file);
 | 
					      final hash = await calculateFileSha256(file);
 | 
				
			||||||
 | 
					      final meta = await calculateImageMetaFromFile(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        await uploadAttachment(
 | 
					        await uploadAttachment(
 | 
				
			||||||
          await file.readAsBytes(),
 | 
					          await file.readAsBytes(),
 | 
				
			||||||
          file.path,
 | 
					          file.path,
 | 
				
			||||||
          hash,
 | 
					          hash,
 | 
				
			||||||
          ratio: await calculateFileAspectRatio(file),
 | 
					          {...meta},
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } catch (err) {
 | 
					      } catch (err) {
 | 
				
			||||||
        context.showErrorDialog(err);
 | 
					        context.showErrorDialog(err);
 | 
				
			||||||
@@ -81,11 +82,11 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    final file = File(media.path);
 | 
					    final file = File(media.path);
 | 
				
			||||||
    final hash = await calculateFileSha256(file);
 | 
					    final hash = await calculateFileSha256(file);
 | 
				
			||||||
    const ratio = 16 / 9;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      await uploadAttachment(await file.readAsBytes(), file.path, hash,
 | 
					      await uploadAttachment(await file.readAsBytes(), file.path, hash, {
 | 
				
			||||||
          ratio: ratio);
 | 
					        'ratio': 16 / 9,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    } catch (err) {
 | 
					    } catch (err) {
 | 
				
			||||||
      context.showErrorDialog(err);
 | 
					      context.showErrorDialog(err);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -97,8 +98,9 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
    final AuthProvider auth = Get.find();
 | 
					    final AuthProvider auth = Get.find();
 | 
				
			||||||
    if (!await auth.isAuthorized) return;
 | 
					    if (!await auth.isAuthorized) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FilePickerResult? result =
 | 
					    FilePickerResult? result = await FilePicker.platform.pickFiles(
 | 
				
			||||||
        await FilePicker.platform.pickFiles(allowMultiple: true);
 | 
					      allowMultiple: true,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    if (result == null) return;
 | 
					    if (result == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setState(() => _isBusy = true);
 | 
					    setState(() => _isBusy = true);
 | 
				
			||||||
@@ -108,7 +110,7 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
    for (final file in files) {
 | 
					    for (final file in files) {
 | 
				
			||||||
      final hash = await calculateFileSha256(file);
 | 
					      final hash = await calculateFileSha256(file);
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        await uploadAttachment(await file.readAsBytes(), file.path, hash);
 | 
					        await uploadAttachment(await file.readAsBytes(), file.path, hash, null);
 | 
				
			||||||
      } catch (err) {
 | 
					      } catch (err) {
 | 
				
			||||||
        context.showErrorDialog(err);
 | 
					        context.showErrorDialog(err);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -131,23 +133,20 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    setState(() => _isBusy = true);
 | 
					    setState(() => _isBusy = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    double? ratio;
 | 
					    Map<String, dynamic> metadata;
 | 
				
			||||||
    final file = File(media.path);
 | 
					    final file = File(media.path);
 | 
				
			||||||
    final hash = await calculateFileSha256(file);
 | 
					    final hash = await calculateFileSha256(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isVideo) {
 | 
					    if (isVideo) {
 | 
				
			||||||
      ratio = 16 / 9;
 | 
					      metadata = {'ratio': 16 / 9};
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      ratio = await calculateFileAspectRatio(file);
 | 
					      metadata = await calculateImageMetaFromFile(file);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      await uploadAttachment(
 | 
					      await uploadAttachment(await file.readAsBytes(), file.path, hash, {
 | 
				
			||||||
        await file.readAsBytes(),
 | 
					        ...metadata,
 | 
				
			||||||
        file.path,
 | 
					      });
 | 
				
			||||||
        hash,
 | 
					 | 
				
			||||||
        ratio: ratio,
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					    } catch (err) {
 | 
				
			||||||
      context.showErrorDialog(err);
 | 
					      context.showErrorDialog(err);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -162,14 +161,14 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
    setState(() => _isBusy = true);
 | 
					    setState(() => _isBusy = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final hash = await calculateBytesSha256(data);
 | 
					    final hash = await calculateBytesSha256(data);
 | 
				
			||||||
    final ratio = await calculateDataAspectRatio(data);
 | 
					    final meta = await calculateImageData(data);
 | 
				
			||||||
    uploadAttachment(data, 'pasted image', hash, ratio: ratio);
 | 
					    uploadAttachment(data, 'Pasted Image', hash, {...meta});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setState(() => _isBusy = false);
 | 
					    setState(() => _isBusy = false);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> uploadAttachment(Uint8List data, String path, String hash,
 | 
					  Future<void> uploadAttachment(Uint8List data, String path, String hash,
 | 
				
			||||||
      {double? ratio}) async {
 | 
					      Map<String, dynamic>? metadata) async {
 | 
				
			||||||
    final AttachmentProvider provider = Get.find();
 | 
					    final AttachmentProvider provider = Get.find();
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      context.showSnackbar((PlatformInfo.isWeb
 | 
					      context.showSnackbar((PlatformInfo.isWeb
 | 
				
			||||||
@@ -181,7 +180,7 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
        path,
 | 
					        path,
 | 
				
			||||||
        hash,
 | 
					        hash,
 | 
				
			||||||
        widget.usage,
 | 
					        widget.usage,
 | 
				
			||||||
        ratio: ratio,
 | 
					        metadata,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      var result = Attachment.fromJson(resp.body);
 | 
					      var result = Attachment.fromJson(resp.body);
 | 
				
			||||||
      setState(() => _attachments.add(result));
 | 
					      setState(() => _attachments.add(result));
 | 
				
			||||||
@@ -281,11 +280,14 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
            for (final file in detail.files) {
 | 
					            for (final file in detail.files) {
 | 
				
			||||||
              final data = await file.readAsBytes();
 | 
					              final data = await file.readAsBytes();
 | 
				
			||||||
              final hash = await calculateBytesSha256(data);
 | 
					              final hash = await calculateBytesSha256(data);
 | 
				
			||||||
              double? ratio;
 | 
					
 | 
				
			||||||
 | 
					              Map<String, dynamic> meta = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              if (file.mimeType?.split('/').firstOrNull == 'image') {
 | 
					              if (file.mimeType?.split('/').firstOrNull == 'image') {
 | 
				
			||||||
                ratio = await calculateDataAspectRatio(data);
 | 
					                meta = await calculateImageData(data);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              uploadAttachment(data, file.path, hash, ratio: ratio);
 | 
					
 | 
				
			||||||
 | 
					              uploadAttachment(data, file.path, hash, {...meta});
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            setState(() => _isBusy = false);
 | 
					            setState(() => _isBusy = false);
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
@@ -348,8 +350,7 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
 | 
				
			|||||||
                                            maxLines: 1,
 | 
					                                            maxLines: 1,
 | 
				
			||||||
                                            style: const TextStyle(
 | 
					                                            style: const TextStyle(
 | 
				
			||||||
                                                fontWeight: FontWeight.bold,
 | 
					                                                fontWeight: FontWeight.bold,
 | 
				
			||||||
                                              fontFamily: 'monospace'
 | 
					                                                fontFamily: 'monospace'),
 | 
				
			||||||
                                            ),
 | 
					 | 
				
			||||||
                                          ),
 | 
					                                          ),
 | 
				
			||||||
                                          Text(
 | 
					                                          Text(
 | 
				
			||||||
                                            '${fileType[0].toUpperCase()}${fileType.substring(1)} · ${formatBytes(element.size)}',
 | 
					                                            '${fileType[0].toUpperCase()}${fileType.substring(1)} · ${formatBytes(element.size)}',
 | 
				
			||||||
@@ -506,7 +507,7 @@ class _AttachmentEditorDialogState extends State<AttachmentEditorDialog> {
 | 
				
			|||||||
    _isMature = widget.item.isMature;
 | 
					    _isMature = widget.item.isMature;
 | 
				
			||||||
    _altController.text = widget.item.alt;
 | 
					    _altController.text = widget.item.alt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (['image', 'video'].contains(widget.item.mimetype.split('/').first)) {
 | 
					    if (['image', 'video'].contains(widget.item.mimetype.split('/').firstOrNull)) {
 | 
				
			||||||
      _ratioController.text =
 | 
					      _ratioController.text =
 | 
				
			||||||
          widget.item.metadata?['ratio']?.toString() ?? 1.toString();
 | 
					          widget.item.metadata?['ratio']?.toString() ?? 1.toString();
 | 
				
			||||||
      _hasAspectRatio = true;
 | 
					      _hasAspectRatio = true;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user