diff --git a/flutter_quill_extensions/lib/embeds/builders.dart b/flutter_quill_extensions/lib/embeds/builders.dart
index 9eee9349..e78b3e80 100644
--- a/flutter_quill_extensions/lib/embeds/builders.dart
+++ b/flutter_quill_extensions/lib/embeds/builders.dart
@@ -1,4 +1,4 @@
-import 'dart:io';
+import 'dart:io' show File;
 
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/foundation.dart';
@@ -7,13 +7,13 @@ import 'package:flutter/services.dart';
 import 'package:flutter_quill/extensions.dart' as base;
 import 'package:flutter_quill/flutter_quill.dart' hide Text;
 import 'package:flutter_quill/translations.dart';
-import 'package:gal/gal.dart';
-import 'package:http/http.dart' as http;
 import 'package:math_keyboard/math_keyboard.dart';
 import 'package:universal_html/html.dart' as html;
 
 import '../shims/dart_ui_fake.dart'
-    if (dart.library.html) '../shims/dart_ui_real.dart' as ui;
+    if (dart.library.html) 'package:flutter_quill_extensions/shims/dart_ui_real.dart'
+    as ui;
+import 'embed_types.dart';
 import 'utils.dart';
 import 'widgets/image.dart';
 import 'widgets/image_resizer.dart';
@@ -21,6 +21,9 @@ import 'widgets/video_app.dart';
 import 'widgets/youtube_video_app.dart';
 
 class ImageEmbedBuilder extends EmbedBuilder {
+  ImageEmbedBuilder({required this.afterRemoveImageFromEditor});
+  final ImageEmbedBuilderAfterRemoveImageFromEditor afterRemoveImageFromEditor;
+
   @override
   String get key => BlockEmbed.imageType;
 
@@ -38,112 +41,118 @@ class ImageEmbedBuilder extends EmbedBuilder {
   ) {
     assert(!kIsWeb, 'Please provide image EmbedBuilder for Web');
 
-    var image;
+    Widget image = const SizedBox.shrink();
     final imageUrl = standardizeImageUrl(node.value.data);
-    OptionalSize? _imageSize;
+    OptionalSize? imageSize;
     final style = node.style.attributes['style'];
     if (base.isMobile() && style != null) {
-      final _attrs = base.parseKeyValuePairs(style.value.toString(), {
+      final attrs = base.parseKeyValuePairs(style.value.toString(), {
         Attribute.mobileWidth,
         Attribute.mobileHeight,
         Attribute.mobileMargin,
         Attribute.mobileAlignment
       });
-      if (_attrs.isNotEmpty) {
+      if (attrs.isNotEmpty) {
         assert(
-            _attrs[Attribute.mobileWidth] != null &&
-                _attrs[Attribute.mobileHeight] != null,
+            attrs[Attribute.mobileWidth] != null &&
+                attrs[Attribute.mobileHeight] != null,
             'mobileWidth and mobileHeight must be specified');
-        final w = double.parse(_attrs[Attribute.mobileWidth]!);
-        final h = double.parse(_attrs[Attribute.mobileHeight]!);
-        _imageSize = OptionalSize(w, h);
-        final m = _attrs[Attribute.mobileMargin] == null
+        final w = double.parse(attrs[Attribute.mobileWidth]!);
+        final h = double.parse(attrs[Attribute.mobileHeight]!);
+        imageSize = OptionalSize(w, h);
+        final m = attrs[Attribute.mobileMargin] == null
             ? 0.0
-            : double.parse(_attrs[Attribute.mobileMargin]!);
-        final a = base.getAlignment(_attrs[Attribute.mobileAlignment]);
+            : double.parse(attrs[Attribute.mobileMargin]!);
+        final a = base.getAlignment(attrs[Attribute.mobileAlignment]);
         image = Padding(
             padding: EdgeInsets.all(m),
             child: imageByUrl(imageUrl, width: w, height: h, alignment: a));
       }
     }
 
-    if (_imageSize == null) {
+    if (imageSize == null) {
       image = imageByUrl(imageUrl);
-      _imageSize = OptionalSize((image as Image).width, image.height);
+      imageSize = OptionalSize((image as Image).width, image.height);
     }
 
     if (!readOnly && base.isMobile()) {
       return GestureDetector(
-          onTap: () {
-            showDialog(
-                context: context,
-                builder: (context) {
-                  final resizeOption = _SimpleDialogItem(
-                    icon: Icons.settings_outlined,
-                    color: Colors.lightBlueAccent,
-                    text: 'Resize'.i18n,
-                    onPressed: () {
-                      Navigator.pop(context);
-                      showCupertinoModalPopup<void>(
-                          context: context,
-                          builder: (context) {
-                            final _screenSize = MediaQuery.of(context).size;
-                            return ImageResizer(
-                                onImageResize: (w, h) {
-                                  final res = getEmbedNode(
-                                      controller, controller.selection.start);
-                                  final attr = base.replaceStyleString(
-                                      getImageStyleString(controller), w, h);
-                                  controller
-                                    ..skipRequestKeyboard = true
-                                    ..formatText(
-                                        res.offset, 1, StyleAttribute(attr));
-                                },
-                                imageWidth: _imageSize?.width,
-                                imageHeight: _imageSize?.height,
-                                maxWidth: _screenSize.width,
-                                maxHeight: _screenSize.height);
-                          });
-                    },
-                  );
-                  final copyOption = _SimpleDialogItem(
-                    icon: Icons.copy_all_outlined,
-                    color: Colors.cyanAccent,
-                    text: 'Copy'.i18n,
-                    onPressed: () {
-                      final imageNode =
-                          getEmbedNode(controller, controller.selection.start)
-                              .value;
-                      final imageUrl = imageNode.value.data;
-                      controller.copiedImageUrl =
-                          ImageUrl(imageUrl, getImageStyleString(controller));
-                      Navigator.pop(context);
-                    },
-                  );
-                  final removeOption = _SimpleDialogItem(
-                    icon: Icons.delete_forever_outlined,
-                    color: Colors.red.shade200,
-                    text: 'Remove'.i18n,
-                    onPressed: () {
-                      final offset =
-                          getEmbedNode(controller, controller.selection.start)
-                              .offset;
-                      controller.replaceText(offset, 1, '',
-                          TextSelection.collapsed(offset: offset));
-                      Navigator.pop(context);
-                    },
-                  );
-                  return Padding(
-                    padding: const EdgeInsets.fromLTRB(50, 0, 50, 0),
-                    child: SimpleDialog(
-                        shape: const RoundedRectangleBorder(
-                            borderRadius:
-                                BorderRadius.all(Radius.circular(10))),
-                        children: [resizeOption, copyOption, removeOption]),
-                  );
-                });
-          },
-          child: image);
+        onTap: () {
+          showDialog(
+              context: context,
+              builder: (context) {
+                final resizeOption = _SimpleDialogItem(
+                  icon: Icons.settings_outlined,
+                  color: Colors.lightBlueAccent,
+                  text: 'Resize'.i18n,
+                  onPressed: () {
+                    Navigator.pop(context);
+                    showCupertinoModalPopup<void>(
+                        context: context,
+                        builder: (context) {
+                          final screenSize = MediaQuery.of(context).size;
+                          return ImageResizer(
+                              onImageResize: (w, h) {
+                                final res = getEmbedNode(
+                                    controller, controller.selection.start);
+                                final attr = base.replaceStyleString(
+                                    getImageStyleString(controller), w, h);
+                                controller
+                                  ..skipRequestKeyboard = true
+                                  ..formatText(
+                                      res.offset, 1, StyleAttribute(attr));
+                              },
+                              imageWidth: imageSize?.width,
+                              imageHeight: imageSize?.height,
+                              maxWidth: screenSize.width,
+                              maxHeight: screenSize.height);
+                        });
+                  },
+                );
+                final copyOption = _SimpleDialogItem(
+                  icon: Icons.copy_all_outlined,
+                  color: Colors.cyanAccent,
+                  text: 'Copy'.i18n,
+                  onPressed: () {
+                    final imageNode =
+                        getEmbedNode(controller, controller.selection.start)
+                            .value;
+                    final imageUrl = imageNode.value.data;
+                    controller.copiedImageUrl =
+                        ImageUrl(imageUrl, getImageStyleString(controller));
+                    Navigator.pop(context);
+                  },
+                );
+                final removeOption = _SimpleDialogItem(
+                  icon: Icons.delete_forever_outlined,
+                  color: Colors.red.shade200,
+                  text: 'Remove'.i18n,
+                  onPressed: () async {
+                    final navigator = Navigator.of(context);
+                    final offset =
+                        getEmbedNode(controller, controller.selection.start)
+                            .offset;
+                    controller.replaceText(
+                      offset,
+                      1,
+                      '',
+                      TextSelection.collapsed(offset: offset),
+                    );
+                    navigator.pop();
+                    await afterRemoveImageFromEditor(File(imageUrl));
+                  },
+                );
+                return Padding(
+                  padding: const EdgeInsets.fromLTRB(50, 0, 50, 0),
+                  child: SimpleDialog(
+                      shape: const RoundedRectangleBorder(
+                          borderRadius: BorderRadius.all(Radius.circular(10))),
+                      children: [resizeOption, copyOption, removeOption]),
+                );
+              });
+        },
+        child: image,
+      );
     }
 
     if (!readOnly || !base.isMobile() || isImageBase64(imageUrl)) {
@@ -151,7 +160,11 @@ class ImageEmbedBuilder extends EmbedBuilder {
     }
 
     // We provide option menu for mobile platform excluding base64 image
-    return _menuOptionsForReadonlyImage(context, imageUrl, image);
+    return _menuOptionsForReadonlyImage(
+      context,
+      imageUrl,
+      image,
+    );
   }
 }
 
@@ -271,29 +284,39 @@ Widget _menuOptionsForReadonlyImage(
                 text: 'Save'.i18n,
                 onPressed: () async {
                   imageUrl = appendFileExtensionToImageUrl(imageUrl);
+                  final messenger = ScaffoldMessenger.of(context);
+                  Navigator.of(context).pop();
 
-                  // Download image
-                  final uri = Uri.parse(imageUrl);
-                  final response = await http.get(uri);
-                  if (response.statusCode != 200) {
-                    throw Exception(
-                      'failed to download image: ${response.statusCode}',
-                    );
-                  }
+                  final saveImageResult = await saveImage(imageUrl);
+                  final imageSavedSuccessfully = saveImageResult.isSuccess;
+
+                  messenger.clearSnackBars();
 
-                  // Save image to a temporary path
-                  final fileName = uri.pathSegments.isEmpty ? 'image.jpg'
-                      : uri.pathSegments.last;
-                  final imagePath = '${Directory.systemTemp.path}/menu-opt-$fileName';
-                  final imageFile = File(imagePath);
-                  await imageFile.writeAsBytes(response.bodyBytes);
+                  if (!imageSavedSuccessfully) {
+                    // TODO: Please translate this
+                    messenger.showSnackBar(const SnackBar(
+                        content: Text(
+                      'Error while saveing the image',
+                    )));
+                    return;
+                  }
 
-                  // Save image to gallery
-                  await Gal.putImage(imagePath);
+                  var message = 'Saved'.i18n;
+                  switch (saveImageResult.method) {
+                    // TODO: Please translate this too
+                    case SaveImageResultMethod.network:
+                      message += ' using the network.';
+                      break;
+                    case SaveImageResultMethod.localStorage:
+                      message += ' using the local storage.';
+                      break;
+                  }
 
-                  ScaffoldMessenger.of(context)
-                      .showSnackBar(SnackBar(content: Text('Saved'.i18n)));
-                  Navigator.pop(context);
+                  messenger.showSnackBar(
+                    SnackBar(
+                      content: Text(message),
+                    ),
+                  );
                 },
               );
               final zoomOption = _SimpleDialogItem(
diff --git a/flutter_quill_extensions/lib/embeds/embed_types.dart b/flutter_quill_extensions/lib/embeds/embed_types.dart
index 6a48f066..8e54954e 100644
--- a/flutter_quill_extensions/lib/embeds/embed_types.dart
+++ b/flutter_quill_extensions/lib/embeds/embed_types.dart
@@ -44,3 +44,6 @@ class QuillFile {
   final String path;
   final Uint8List bytes;
 }
+
+typedef ImageEmbedBuilderAfterRemoveImageFromEditor = Future<void> Function(
+    File imageFile);
diff --git a/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart b/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart
index 77b1eb60..497822ae 100644
--- a/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart
+++ b/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart
@@ -35,6 +35,12 @@ class LinkDialogState extends State<LinkDialog> {
     super.initState();
     _link = widget.link ?? '';
     _controller = TextEditingController(text: _link);
+    // TODO: Consider replace the default Regex with this one
+    // Since that is not the reason I sent the changes then I will not edit it
+
+    // final defaultLinkNonSecureRegExp = RegExp(r'https?://.*?\.(?:png|jpe?g|gif|bmp|webp|tiff?)'); // Not secure
+    // final defaultLinkRegExp = RegExp(r'https://.*?\.(?:png|jpe?g|gif|bmp|webp|tiff?)'); // Secure
+    // _linkRegExp = widget.linkRegExp ?? defaultLinkRegExp;
     _linkRegExp = widget.linkRegExp ?? AutoFormatMultipleLinksRule.linkRegExp;
   }
 
diff --git a/flutter_quill_extensions/lib/embeds/utils.dart b/flutter_quill_extensions/lib/embeds/utils.dart
index 360fb5d5..d4b937a3 100644
--- a/flutter_quill_extensions/lib/embeds/utils.dart
+++ b/flutter_quill_extensions/lib/embeds/utils.dart
@@ -1,5 +1,84 @@
-import 'package:string_validator/string_validator.dart';
+import 'dart:io';
+
+import 'package:flutter/foundation.dart' show Uint8List;
+import 'package:http/http.dart' as http;
+import 'package:image_gallery_saver/image_gallery_saver.dart';
+
+// I would like to orgnize the project structure and the code more
+// but here I don't want to change too much since that is a community project
+
+RegExp _base64 = RegExp(
+  r'^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$',
+);
+
+bool isBase64(String str) {
+  return _base64.hasMatch(str);
+}
 
 bool isImageBase64(String imageUrl) {
   return !imageUrl.startsWith('http') && isBase64(imageUrl);
 }
+
+enum SaveImageResultMethod { network, localStorage }
+
+class _SaveImageResult {
+  const _SaveImageResult({required this.isSuccess, required this.method});
+
+  final bool isSuccess;
+  final SaveImageResultMethod method;
+}
+
+Future<_SaveImageResult> saveImage(String imageUrl) async {
+  final imageFile = File(imageUrl);
+  final imageExistsLocally = await imageFile.exists();
+  if (!imageExistsLocally) {
+    final success = await _saveNetworkImageToLocal(imageUrl);
+    return _SaveImageResult(
+      isSuccess: success,
+      method: SaveImageResultMethod.network,
+    );
+  }
+  final success = await _saveImageLocally(imageFile);
+  return _SaveImageResult(
+    isSuccess: success,
+    method: SaveImageResultMethod.localStorage,
+  );
+}
+
+Future<bool> _saveNetworkImageToLocal(String imageUrl) async {
+  try {
+    final response = await http.get(
+      Uri.parse(imageUrl),
+    );
+    if (response.statusCode != 200) {
+      return false;
+    }
+    final imageBytes = response.bodyBytes;
+    final result = await ImageGallerySaver.saveImage(
+      Uint8List.fromList(imageBytes),
+    );
+    return result['isSuccess'];
+  } catch (e) {
+    return false;
+  }
+}
+
+Future<Uint8List> _convertFileToUint8List(File file) async {
+  try {
+    final uint8list = await file.readAsBytes();
+    return uint8list;
+  } catch (e) {
+    return Uint8List(0);
+  }
+}
+
+Future<bool> _saveImageLocally(File imageFile) async {
+  try {
+    final imageBytes = await _convertFileToUint8List(imageFile);
+    final result = await ImageGallerySaver.saveImage(imageBytes);
+
+    return result['isSuccess'];
+  } catch (e) {
+    return false;
+  }
+}
diff --git a/flutter_quill_extensions/lib/flutter_quill_extensions.dart b/flutter_quill_extensions/lib/flutter_quill_extensions.dart
index a1945ab7..f2f56fb8 100644
--- a/flutter_quill_extensions/lib/flutter_quill_extensions.dart
+++ b/flutter_quill_extensions/lib/flutter_quill_extensions.dart
@@ -20,11 +20,36 @@ export 'embeds/toolbar/video_button.dart';
 export 'embeds/utils.dart';
 
 class FlutterQuillEmbeds {
+  /// Returns a list of embed builders for Quill editors.
+  ///
+  /// [onVideoInit] is called when a video is initialized.
+  /// [onRemoveImage] is called when an image is removed from the editor.
+  /// By default, [onRemoveImage] deletes the cached image if it still exists.
+  /// If you want to customize
+  /// the behavior, pass your own function that handles the removal.
+  ///
+  /// Example of [onRemoveImage] customization:
+  /// ```dart
+  /// onRemoveImage: (imageFile) async {
+  ///   // Your custom logic here
+  ///   // or leave it empty to do nothing
+  /// }
+  /// ```
   static List<EmbedBuilder> builders({
     void Function(GlobalKey videoContainerKey)? onVideoInit,
+    ImageEmbedBuilderAfterRemoveImageFromEditor? afterRemoveImageFromEditor,
   }) =>
       [
-        ImageEmbedBuilder(),
+        ImageEmbedBuilder(
+          afterRemoveImageFromEditor: afterRemoveImageFromEditor ??
+              (imageFile) async {
+                // TODO: Please change this default code
+                final fileExists = await imageFile.exists();
+                if (fileExists) {
+                  await imageFile.delete();
+                }
+              },
+        ),
         VideoEmbedBuilder(onVideoInit: onVideoInit),
         FormulaEmbedBuilder(),
       ];
@@ -80,7 +105,7 @@ class FlutterQuillEmbeds {
                 iconTheme: iconTheme,
                 dialogTheme: dialogTheme,
                 linkRegExp: videoLinkRegExp,
-          ),
+              ),
         if ((onImagePickCallback != null || onVideoPickCallback != null) &&
             showCameraButton)
           (controller, toolbarIconSize, iconTheme, dialogTheme) => CameraButton(
diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml
index 45c97270..9216304d 100644
--- a/flutter_quill_extensions/pubspec.yaml
+++ b/flutter_quill_extensions/pubspec.yaml
@@ -12,18 +12,21 @@ dependencies:
   flutter:
     sdk: flutter
 
-  flutter_quill: ^7.2.19
+  flutter_quill: ^7.4.7
 
   http: ^1.1.0
-  image_picker: ">=0.8.5 <2.0.0"
+  image_picker: ">=1.0.4"
   photo_view: ^0.14.0
-  video_player: ^2.7.0
-  youtube_player_flutter: ^8.1.1
-  gal: ^2.1.1
-  math_keyboard: ">=0.1.8 <0.3.0"
-  string_validator: ^1.0.0
-  universal_html: ^2.2.1
-  url_launcher: ^6.1.9
+  video_player: ^2.7.2
+  youtube_player_flutter: ^8.1.2
+  # gallery_saver: ^2.1.1
+  math_keyboard: ">=0.2.1"
+  # string_validator: ^1.0.0
+  universal_html: ^2.2.4
+  # url_launcher: ^6.1.14
+  # dio: ^5.3.3
+
+  image_gallery_saver: ^2.0.3
 
 dev_dependencies:
   flutter_test: