From d4d3f95b965e448f41733c6848154c7f10edfd6a Mon Sep 17 00:00:00 2001 From: Christophe Deschamps Date: Fri, 4 Feb 2022 11:38:49 +0100 Subject: [PATCH] Use of imageWithContentsOfFile to reduce image size Added a cache for height calculation (until chat bubble are moved to autolayout) Added a cache for images to reduce memory footprint --- Classes/LinphoneAppDelegate.m | 1 + Classes/LinphoneUI/UIChatBubblePhotoCell.m | 57 +++++++++++++--------- Classes/LinphoneUI/UIChatBubbleTextCell.m | 14 ++++++ Classes/SwiftUtil.swift | 41 ++++++++++++++++ 4 files changed, 91 insertions(+), 22 deletions(-) diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 005b30421..ad038b276 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -79,6 +79,7 @@ } [CallManager.instance stopLinphoneCore]; } + [SwiftUtil resetCachedAsset]; } - (void)applicationWillEnterForeground:(UIApplication *)application { diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index 1ef810ca1..d8d10c780 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -30,7 +30,7 @@ #define chatView VIEW(ChatConversationView) #define FILE_ICON_TAG 0 #define REALIMAGE_TAG 1 - +#define PHOTO_LIBRARY_FETCH_IMAGE_SIZE CGSizeMake(UIScreen.mainScreen.bounds.size.width * 0.8f,UIScreen.mainScreen.bounds.size.width * 0.8f) @implementation UIChatBubblePhotoCell { @@ -126,19 +126,30 @@ } - (void) loadAsset:(PHAsset *) asset { - PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; - options.synchronous = TRUE; - [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options - resultHandler:^(UIImage *image, NSDictionary * info) { - if (image) { - imageSize = [UIChatBubbleTextCell getMediaMessageSizefromOriginalSize:[image size] withWidth:chatTableView.tableView.frame.size.width - CELL_IMAGE_X_MARGIN]; - [chatTableView.imagesInChatroom setObject:image forKey:[asset localIdentifier]]; - [self loadImageAsset:asset image:image]; - } - else { - LOGE(@"Can't read image"); - } - }]; + + UIImage *image = [SwiftUtil getCachedImageWithKey:asset]; + if (image) { + imageSize = [UIChatBubbleTextCell getMediaMessageSizefromOriginalSize:[image size] withWidth:chatTableView.tableView.frame.size.width - CELL_IMAGE_X_MARGIN]; + [chatTableView.imagesInChatroom setObject:image forKey:[asset localIdentifier]]; + [self loadImageAsset:asset image:image]; + return; + } else { + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; + options.synchronous = FALSE; + options.resizeMode = PHImageRequestOptionsResizeModeNone; + [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHOTO_LIBRARY_FETCH_IMAGE_SIZE contentMode:PHImageContentModeAspectFit options:options + resultHandler:^(UIImage *image, NSDictionary * info) { + if (image) { + imageSize = [UIChatBubbleTextCell getMediaMessageSizefromOriginalSize:[image size] withWidth:chatTableView.tableView.frame.size.width - CELL_IMAGE_X_MARGIN]; + [chatTableView.imagesInChatroom setObject:image forKey:[asset localIdentifier]]; + [self loadImageAsset:asset image:image]; + [SwiftUtil setCachedImageWithKey:asset image:image]; + } + else { + LOGE(@"Can't read image"); + } + }]; + } } - (void) loadFileAsset:(NSString *)name { @@ -316,8 +327,13 @@ if ([key isEqualToString:@"localimage"]) { // we did not load the image yet, so start doing so if (_messageImageView.image == nil) { - NSData *data = [NSData dataWithContentsOfFile:filePath]; - UIImage *image = [[UIImage alloc] initWithData:data]; + UIImage *cachedImage = [SwiftUtil getCachedImageWithKey:filePath] ? : [UIImage imageWithContentsOfFile:filePath]; + UIImage *image = [SwiftUtil getCachedImageWithKey:filePath]; + if (!image) { + image = [UIImage imageWithContentsOfFile:filePath]; + if (image) + [SwiftUtil setCachedImageWithKey:filePath image:image]; + } if (image) { [self loadImageAsset:nil image:image]; _imageGestureRecognizer.enabled = YES; @@ -343,8 +359,7 @@ [self loadImageAsset:nil image:image]; _imageGestureRecognizer.enabled = NO; } else if ([fileName hasSuffix:@"JPG"] || [fileName hasSuffix:@"PNG"] || [fileName hasSuffix:@"jpg"] || [fileName hasSuffix:@"png"]) { - NSData *data = [NSData dataWithContentsOfFile:filePath]; - UIImage *image = [[UIImage alloc] initWithData:data]; + UIImage *image = [UIImage imageWithContentsOfFile:filePath]; [self loadImageAsset:nil image:image]; _imageGestureRecognizer.enabled = YES; } else { @@ -545,8 +560,7 @@ [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; NSString *filePath = [LinphoneManager getMessageAppDataForKey:@"encryptedfile" inMessage:self.message]; if (filePath) { - NSData *data = [NSData dataWithContentsOfFile:filePath]; - UIImage *image = [[UIImage alloc] initWithData:data]; + UIImage *image = [UIImage imageWithContentsOfFile:filePath]; [view setImage:image]; return; } @@ -563,8 +577,7 @@ } if (imageName) { - NSData *data = [NSData dataWithContentsOfFile:[LinphoneManager validFilePath:imageName]]; - UIImage *image = [[UIImage alloc] initWithData:data]; + UIImage *image = [UIImage imageWithContentsOfFile: [LinphoneManager validFilePath:imageName]]; if (image) [view setImage:image]; else diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m index 45d5ca78f..f5b3c47ad 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.m +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m @@ -373,9 +373,23 @@ static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18; + (CGSize)ViewHeightForMessage:(LinphoneChatMessage *)chat withWidth:(int)width { + + CGSize cached = [SwiftUtil getCachedMessageHeightWithCmessage:chat]; + if (cached.height != 0) { + LOGI(@"ViewHeightForMessage - found cached value %f",cached.height); + return cached; + } + LOGI(@"ViewHeightForMessage - computing value"); + CGSize size = [self ViewHeightForMessageText:chat withWidth:width textForImdn:nil]; size.height += linphone_chat_message_is_forward(chat) || linphone_chat_message_is_reply(chat) ? REPLY_OR_FORWARD_TAG_HEIGHT : 0; size.height += linphone_chat_message_is_reply(chat) ? REPLY_CHAT_BUBBLE_HEIGHT+5 : 0; + + // No modifications of size below as it goes into cache + if ([SwiftUtil messageHeightCanBeCachedWithCmessage:chat]) { + [SwiftUtil setCachedMessageHeightWithCmessage:chat size:size]; + } + return size; } diff --git a/Classes/SwiftUtil.swift b/Classes/SwiftUtil.swift index a66edc326..1a0c4e91e 100644 --- a/Classes/SwiftUtil.swift +++ b/Classes/SwiftUtil.swift @@ -18,6 +18,9 @@ */ import UIKit +import Photos +import linphonesw + @objc class SwiftUtil: NSObject { @@ -69,5 +72,43 @@ import UIKit return img } + // Image cache + static var imageCache:[String:UIImage] = [:] + + @objc static func getCachedImage(key:String) -> UIImage? { + return key != nil ? imageCache[key] : nil + } + + @objc static func setCachedImage(key:String,image:UIImage) { + imageCache[key] = image + } + + @objc static func resetCachedAsset() { + imageCache.removeAll() + } + + // Chat bubble height cache : + + static var cacheMessageSize:[String:CGSize] = [:] + + @objc static func getCachedMessageHeight(cmessage:OpaquePointer) -> CGSize { + let message = ChatMessage.getSwiftObject(cObject: cmessage) + if let cached = cacheMessageSize[message.messageId] { + return cached + } else { + return .zero + } + } + + @objc static func setCachedMessageHeight(cmessage:OpaquePointer, size:CGSize) { + let message = ChatMessage.getSwiftObject(cObject: cmessage) + cacheMessageSize[message.messageId] = size + } + + @objc static func messageHeightCanBeCached(cmessage:OpaquePointer) -> Bool { + let message = ChatMessage.getSwiftObject(cObject: cmessage) + return (message.isOutgoing && [.Delivered, .DeliveredToUser, .Displayed].contains(message.state)) || (!message.isOutgoing && ![.InProgress, .FileTransferInProgress, .FileTransferError].contains(message.state)) + } + }