diff --git a/core/lib/data/network/download/download_client.dart b/core/lib/data/network/download/download_client.dart
index 8686739f1..e3e6461d8 100644
--- a/core/lib/data/network/download/download_client.dart
+++ b/core/lib/data/network/download/download_client.dart
@@ -39,6 +39,7 @@ class DownloadClient {
String cid,
String fileExtension,
String fileName,
+ String mimeType,
{
String? filePath,
double? maxWidth,
@@ -58,10 +59,14 @@ class DownloadClient {
return null;
}
+ final imageType = mimeType == 'application/octet-stream'
+ ? 'image/$fileExtension'
+ : mimeType;
+
if (PlatformInfo.isWeb) {
final base64Uri = encodeToBase64Uri({
'bytesData': bytesData,
- 'mimeType': 'image/$fileExtension',
+ 'mimeType': imageType,
'cid': cid,
'fileName': fileName,
'maxWidth': maxWidth
@@ -76,7 +81,7 @@ class DownloadClient {
final base64Uri = await compute(encodeToBase64Uri, {
'bytesData': bytesDataCompressed,
- 'mimeType': 'image/$fileExtension',
+ 'mimeType': imageType,
'cid': cid,
'fileName': fileName,
'maxWidth': maxWidth
@@ -86,7 +91,7 @@ class DownloadClient {
} else {
final base64Uri = await compute(encodeToBase64Uri, {
'bytesData': bytesData,
- 'mimeType': 'image/$fileExtension',
+ 'mimeType': imageType,
'cid': cid,
'fileName': fileName,
'maxWidth': maxWidth
@@ -113,7 +118,8 @@ class DownloadClient {
if (fileName.contains('.')) {
fileName = fileName.split('.').first;
}
- final base64Uri = '
';
+ mimeType = HtmlUtils.validateHtmlImageResourceMimeType(mimeType);
+ final base64Uri = '
';
return base64Uri;
}
}
\ No newline at end of file
diff --git a/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart b/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart
index f0dd38661..140df0bed 100644
--- a/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart
+++ b/core/lib/presentation/utils/html_transformer/dom/image_transformers.dart
@@ -45,12 +45,13 @@ class ImageTransformer extends DomTransformer {
final src = imageElement.attributes['src'];
if (src == null) return;
-
+ final mimeType = imageElement.attributes['data-mimetype'];
if (src.startsWith('cid:') && mapUrlDownloadCID != null) {
final imageBase64 = await _convertCidToBase64Image(
dioClient: dioClient,
mapUrlDownloadCID: mapUrlDownloadCID,
- imageSource: src
+ imageSource: src,
+ mimeType: mimeType,
);
imageElement.attributes['src'] = imageBase64 ?? src;
imageElement.attributes['id'] ??= src;
@@ -68,7 +69,8 @@ class ImageTransformer extends DomTransformer {
Future _convertCidToBase64Image({
required DioClient dioClient,
required Map mapUrlDownloadCID,
- required String imageSource
+ required String imageSource,
+ required String? mimeType,
}) async {
final cid = imageSource.replaceFirst('cid:', '').trim();
final urlDownloadCid = mapUrlDownloadCID[cid];
@@ -79,7 +81,8 @@ class ImageTransformer extends DomTransformer {
final imgBase64Uri = await loadAsyncNetworkImageToBase64(
dioClient,
compressFileUtils,
- urlDownloadCid
+ urlDownloadCid,
+ mimeType,
);
if (imgBase64Uri.isEmpty) return null;
@@ -90,7 +93,8 @@ class ImageTransformer extends DomTransformer {
Future loadAsyncNetworkImageToBase64(
DioClient dioClient,
CompressFileUtils compressFileUtils,
- String imageUrl
+ String imageUrl,
+ String? mimeType,
) async {
try {
var responseData = await dioClient.get(
@@ -99,10 +103,16 @@ class ImageTransformer extends DomTransformer {
if (responseData != null) {
if (PlatformInfo.isWeb) {
- return encodeToBase64Uri(responseData);
+ return encodeToBase64Uri({
+ 'bytesData': responseData,
+ 'mimeType': mimeType,
+ });
} else {
final bytesCompressed = await compressFileUtils.compressBytesDataImage(responseData);
- final base64Uri = await compute(encodeToBase64Uri, bytesCompressed);
+ final base64Uri = await compute(encodeToBase64Uri, {
+ 'bytesData': bytesCompressed,
+ 'mimeType': mimeType,
+ });
return base64Uri;
}
} else {
@@ -113,12 +123,12 @@ class ImageTransformer extends DomTransformer {
}
}
- static String encodeToBase64Uri(dynamic bytesData) {
- final base64Data = base64Encode(bytesData);
+ static String encodeToBase64Uri(Map entryParam) {
+ final base64Data = base64Encode(entryParam['bytesData']);
if (!base64Data.endsWith('==')) {
base64Data.append('==');
}
- final base64Uri = 'data:image/jpeg;base64,$base64Data';
- return base64Uri;
+ final mimeType = entryParam['mimeType'] ?? 'image/jpeg';
+ return 'data:$mimeType;base64,$base64Data';
}
}
\ No newline at end of file
diff --git a/core/lib/presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart b/core/lib/presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart
index 9ff53ac2a..2c117e151 100644
--- a/core/lib/presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart
+++ b/core/lib/presentation/utils/html_transformer/text/standardize_html_sanitizing_transformers.dart
@@ -11,6 +11,7 @@ class StandardizeHtmlSanitizingTransformers extends TextTransformer {
'bgcolor',
'id',
'class',
+ 'data-mimetype',
];
static const List mailAllowedHtmlTags = [
diff --git a/core/lib/utils/html/html_utils.dart b/core/lib/utils/html/html_utils.dart
index 4bc132aa0..71a465d22 100644
--- a/core/lib/utils/html/html_utils.dart
+++ b/core/lib/utils/html/html_utils.dart
@@ -99,13 +99,10 @@ class HtmlUtils {
required String base64Data,
required String mimeType
}) {
- log('HtmlUtils::convertBase64ToImageResourceData:');
- mimeType = validateHtmlImageResourceMimeType(mimeType);
if (!base64Data.endsWith('==')) {
base64Data.append('==');
}
- final imageResource = 'data:$mimeType;base64,$base64Data';
- return imageResource;
+ return 'data:$mimeType;base64,$base64Data';
}
static String generateHtmlDocument({
diff --git a/lib/features/composer/data/datasource_impl/composer_datasource_impl.dart b/lib/features/composer/data/datasource_impl/composer_datasource_impl.dart
index deef7c58e..4248bd9a6 100644
--- a/lib/features/composer/data/datasource_impl/composer_datasource_impl.dart
+++ b/lib/features/composer/data/datasource_impl/composer_datasource_impl.dart
@@ -27,6 +27,7 @@ class ComposerDataSourceImpl extends ComposerDataSource {
cid,
fileInfo.fileExtension,
fileInfo.fileName,
+ fileInfo.mimeType,
filePath: fileInfo.filePath,
maxWidth: maxWidth,
compress: compress);
diff --git a/lib/features/composer/data/repository/composer_repository_impl.dart b/lib/features/composer/data/repository/composer_repository_impl.dart
index ba5160561..a370f24c9 100644
--- a/lib/features/composer/data/repository/composer_repository_impl.dart
+++ b/lib/features/composer/data/repository/composer_repository_impl.dart
@@ -113,4 +113,14 @@ class ComposerRepositoryImpl extends ComposerRepository {
return Future.value(emailContent);
}
}
+
+ @override
+ Future removeStyleLazyLoadDisplayInlineImages({required String emailContent}) {
+ try {
+ return _htmlDataSource.removeStyleLazyLoadDisplayInlineImages(emailContent: emailContent);
+ } catch (e) {
+ logError('ComposerRepositoryImpl::removeStyleLazyLoadDisplayInlineImages: Exception: $e');
+ return Future.value(emailContent);
+ }
+ }
}
\ No newline at end of file
diff --git a/lib/features/composer/domain/repository/composer_repository.dart b/lib/features/composer/domain/repository/composer_repository.dart
index 5a28d848d..38fdd16ea 100644
--- a/lib/features/composer/domain/repository/composer_repository.dart
+++ b/lib/features/composer/domain/repository/composer_repository.dart
@@ -17,4 +17,6 @@ abstract class ComposerRepository {
Future downloadImageAsBase64(String url, String cid, FileInfo fileInfo, {double? maxWidth, bool? compress});
Future removeCollapsedExpandedSignatureEffect({required String emailContent});
+
+ Future removeStyleLazyLoadDisplayInlineImages({required String emailContent});
}
\ No newline at end of file
diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart
index 0be843b27..91b0c7757 100644
--- a/lib/features/composer/presentation/composer_controller.dart
+++ b/lib/features/composer/presentation/composer_controller.dart
@@ -1112,6 +1112,13 @@ class ComposerController extends BaseController
emailContent = await _composerRepository.removeCollapsedExpandedSignatureEffect(
emailContent: emailContent,
);
+ if (emailIdEditing != null &&
+ savedActionType == EmailActionType.compose &&
+ currentEmailActionType == EmailActionType.reopenComposerBrowser) {
+ emailContent = await _composerRepository.removeStyleLazyLoadDisplayInlineImages(
+ emailContent: emailContent,
+ );
+ }
final savedEmailDraft = SavedEmailDraft(
subject: subjectEmail.value ?? '',
diff --git a/lib/features/composer/presentation/controller/rich_text_web_controller.dart b/lib/features/composer/presentation/controller/rich_text_web_controller.dart
index d4b1e61fd..2eff51dff 100644
--- a/lib/features/composer/presentation/controller/rich_text_web_controller.dart
+++ b/lib/features/composer/presentation/controller/rich_text_web_controller.dart
@@ -282,8 +282,9 @@ class RichTextWebController extends BaseRichTextController {
void insertImageAsBase64({required PlatformFile platformFile, int? maxWidth}) {
if (platformFile.bytes != null) {
final base64Data = base64Encode(platformFile.bytes!);
+ final mimeType = HtmlUtils.validateHtmlImageResourceMimeType('image/${platformFile.extension}');
editorController.insertHtml(
- '
'
+ '
'
);
} else {
logError("RichTextWebController::insertImageAsBase64: bytes is null");
diff --git a/lib/features/email/data/datasource/html_datasource.dart b/lib/features/email/data/datasource/html_datasource.dart
index ec9220ed7..9fccbb094 100644
--- a/lib/features/email/data/datasource/html_datasource.dart
+++ b/lib/features/email/data/datasource/html_datasource.dart
@@ -23,4 +23,6 @@ abstract class HtmlDataSource {
});
Future removeCollapsedExpandedSignatureEffect({required String emailContent});
+
+ Future removeStyleLazyLoadDisplayInlineImages({required String emailContent});
}
\ No newline at end of file
diff --git a/lib/features/email/data/datasource_impl/html_datasource_impl.dart b/lib/features/email/data/datasource_impl/html_datasource_impl.dart
index e5e02faa7..b6cd9659e 100644
--- a/lib/features/email/data/datasource_impl/html_datasource_impl.dart
+++ b/lib/features/email/data/datasource_impl/html_datasource_impl.dart
@@ -62,4 +62,13 @@ class HtmlDataSourceImpl extends HtmlDataSource {
);
}).catchError(_exceptionThrower.throwException);
}
+
+ @override
+ Future removeStyleLazyLoadDisplayInlineImages({required String emailContent}) {
+ return Future.sync(() async {
+ return await _htmlAnalyzer.removeStyleLazyLoadDisplayInlineImages(
+ emailContent: emailContent,
+ );
+ }).catchError(_exceptionThrower.throwException);
+ }
}
\ No newline at end of file
diff --git a/lib/features/email/data/local/html_analyzer.dart b/lib/features/email/data/local/html_analyzer.dart
index 0e14bec5b..7ece84d17 100644
--- a/lib/features/email/data/local/html_analyzer.dart
+++ b/lib/features/email/data/local/html_analyzer.dart
@@ -237,4 +237,30 @@ class HtmlAnalyzer {
return null;
}
}
+
+ Future removeStyleLazyLoadDisplayInlineImages({required String emailContent}) async {
+ try {
+ final document = parse(emailContent);
+ final imgElements = document.querySelectorAll('img[style], img[loading]');
+ await Future.wait(imgElements.map((img) async {
+ String? style = img.attributes['style'];
+ if (style != null) {
+ style = style.replaceAll(RegExp(r'display\s*:\s*inline;?'), '').trim();
+ if (style.isEmpty) {
+ img.attributes.remove('style');
+ } else {
+ img.attributes['style'] = style;
+ }
+ }
+
+ if (img.attributes['loading'] == 'lazy') {
+ img.attributes.remove('loading');
+ }
+ }));
+ return document.body?.innerHtml ?? emailContent;
+ } catch (e) {
+ logError('HtmlAnalyzer::removeStyleLazyLoadDisplayInlineImages:Exception = $e');
+ return emailContent;
+ }
+ }
}
\ No newline at end of file
diff --git a/lib/features/public_asset/presentation/public_asset_controller.dart b/lib/features/public_asset/presentation/public_asset_controller.dart
index c66208475..f79d6b79f 100644
--- a/lib/features/public_asset/presentation/public_asset_controller.dart
+++ b/lib/features/public_asset/presentation/public_asset_controller.dart
@@ -186,7 +186,7 @@ class PublicAssetController extends BaseController {
newlyPickedPublicAssetIds.add(publicAsset.id!);
final imageTag = '
';
if (PlatformInfo.isWeb) {
Get