diff --git a/Yep.xcodeproj/project.pbxproj b/Yep.xcodeproj/project.pbxproj index 9969e86c..4bbb246c 100644 --- a/Yep.xcodeproj/project.pbxproj +++ b/Yep.xcodeproj/project.pbxproj @@ -246,6 +246,7 @@ 50AFBF4B1BB2A44C007D19DA /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50AFBF4A1BB2A44C007D19DA /* InfoView.swift */; }; 50AFBF4E1BB3A594007D19DA /* bub3.caf in Resources */ = {isa = PBXBuildFile; fileRef = 50AFBF4D1BB3A594007D19DA /* bub3.caf */; }; 50AFBF5F1BB4F332007D19DA /* FeedsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50AFBF5E1BB4F332007D19DA /* FeedsViewController.swift */; }; + 50B22E461C588B6200219625 /* CGImage+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B22E451C588B6200219625 /* CGImage+Yep.swift */; }; 50B2CA921BD0BF3800668AC6 /* FeedTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B2CA911BD0BF3800668AC6 /* FeedTextView.swift */; }; 50B2CA941BD0EF7900668AC6 /* MoreMessageTypesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B2CA931BD0EF7900668AC6 /* MoreMessageTypesView.swift */; }; 50B38FB71B69CD960064C132 /* Array+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50B38FB61B69CD960064C132 /* Array+Yep.swift */; }; @@ -619,6 +620,7 @@ 50AFBF4A1BB2A44C007D19DA /* InfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InfoView.swift; path = Views/InfoView/InfoView.swift; sourceTree = ""; }; 50AFBF4D1BB3A594007D19DA /* bub3.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = bub3.caf; path = Sounds/bub3.caf; sourceTree = ""; }; 50AFBF5E1BB4F332007D19DA /* FeedsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedsViewController.swift; path = ViewControllers/Feeds/FeedsViewController.swift; sourceTree = ""; }; + 50B22E451C588B6200219625 /* CGImage+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CGImage+Yep.swift"; path = "Extensions/CGImage+Yep.swift"; sourceTree = ""; }; 50B2CA911BD0BF3800668AC6 /* FeedTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedTextView.swift; path = Views/TextViews/FeedTextView.swift; sourceTree = ""; }; 50B2CA931BD0EF7900668AC6 /* MoreMessageTypesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MoreMessageTypesView.swift; path = Views/MoreMessageTypes/MoreMessageTypesView.swift; sourceTree = ""; }; 50B38FB61B69CD960064C132 /* Array+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Array+Yep.swift"; path = "Extensions/Array+Yep.swift"; sourceTree = ""; }; @@ -1137,6 +1139,7 @@ 50DBDF041C4DD9530044E21B /* CGSize+Yep.swift */, 5023DE511AB6C51300B3EE96 /* CGRect+Yep.swift */, 5023DE581AB6DBC100B3EE96 /* UIImage+Yep.swift */, + 50B22E451C588B6200219625 /* CGImage+Yep.swift */, 506EC2091AC95BFC00CE42B3 /* UIFont+Yep.swift */, 0A3E605F1ACCA9C0003DC853 /* String+Yep.swift */, 50A9D44A1ACD37A8000B2599 /* NSFileManager+Yep.swift */, @@ -2649,6 +2652,7 @@ 50CDBE421ACA9B4200459CE0 /* ChatRightImageCell.swift in Sources */, 5099B9C41AB9510D002F940B /* RankView.swift in Sources */, 502AE5311AB85067005BD199 /* RegisterPickMobileViewController.swift in Sources */, + 50B22E461C588B6200219625 /* CGImage+Yep.swift in Sources */, 50535D1A1BCD19AE002FE1A4 /* TouchClosuresView.swift in Sources */, 506E241E1AE6391A00A33C1A /* TouchZoomButton.swift in Sources */, 5020B8A51C059662006CE8EA /* VoiceRecordSampleView.swift in Sources */, diff --git a/Yep/Caches/ImageCache.swift b/Yep/Caches/ImageCache.swift index 64f6cf79..22033782 100644 --- a/Yep/Caches/ImageCache.swift +++ b/Yep/Caches/ImageCache.swift @@ -213,11 +213,14 @@ class ImageCache { let mediaType = message.mediaType - YepDownloader.downloadAttachmentsOfMessage(message, reportProgress: { progress in + YepDownloader.downloadAttachmentsOfMessage(message, reportProgress: { progress, image in dispatch_async(dispatch_get_main_queue()) { - completion(loadingProgress: progress, image: nil) + completion(loadingProgress: progress, image: image) } + }, imageTransform: { image in + return image.bubbleImageWithTailDirection(tailDirection, size: size).decodedImage() + }, imageFinished: { image in let messageImage = image.bubbleImageWithTailDirection(tailDirection, size: size).decodedImage() diff --git a/Yep/Extensions/CGImage+Yep.swift b/Yep/Extensions/CGImage+Yep.swift new file mode 100644 index 00000000..97c7c1bc --- /dev/null +++ b/Yep/Extensions/CGImage+Yep.swift @@ -0,0 +1,52 @@ +// +// CGImage+Yep.swift +// Yep +// +// Created by nixzhu on 16/1/27. +// Copyright © 2016年 Catch Inc. All rights reserved. +// + +import Foundation + +extension CGImage { + + var yep_extendedCanvasCGImage: CGImage { + + let width = CGImageGetWidth(self) + let height = CGImageGetHeight(self) + + guard width > 0 && height > 0 else { + return self + } + + func hasAlpha() -> Bool { + let alpha = CGImageGetAlphaInfo(self) + switch alpha { + case .First, .Last, .PremultipliedFirst, .PremultipliedLast: + return true + default: + return false + } + } + + var bitmapInfo = CGBitmapInfo.ByteOrder32Little.rawValue + if hasAlpha() { + bitmapInfo |= CGImageAlphaInfo.PremultipliedFirst.rawValue + } else { + bitmapInfo |= CGImageAlphaInfo.NoneSkipFirst.rawValue + } + + guard let context = CGBitmapContextCreate(nil, width, height, 8, 0, CGColorSpaceCreateDeviceRGB(), bitmapInfo) else { + return self + } + + CGContextDrawImage(context, CGRect(x: 0, y: 0, width: width, height: height), self) + + guard let newCGImage = CGBitmapContextCreateImage(context) else { + return self + } + + return newCGImage + } +} + diff --git a/Yep/Extensions/UIImage+Yep.swift b/Yep/Extensions/UIImage+Yep.swift index 88991e10..97ce17bd 100644 --- a/Yep/Extensions/UIImage+Yep.swift +++ b/Yep/Extensions/UIImage+Yep.swift @@ -8,6 +8,8 @@ import UIKit import Ruler +import ImageIO +import MobileCoreServices extension UIImage { @@ -572,3 +574,49 @@ extension UIImage { } } +// MARK: Progressive + +extension UIImage { + + var yep_progressiveImage: UIImage? { + + guard let cgImage = CGImage else { + return nil + } + + let data = NSMutableData() + + guard let distination = CGImageDestinationCreateWithData(data, kUTTypeJPEG, 1, nil) else { + return nil + } + + let jfifProperties = [ + kCGImagePropertyJFIFIsProgressive as String: kCFBooleanTrue as Bool, + kCGImagePropertyJFIFXDensity as String: 72, + kCGImagePropertyJFIFYDensity as String: 72, + kCGImagePropertyJFIFDensityUnit as String: 1, + ] + + let properties = [ + kCGImageDestinationLossyCompressionQuality as String: 0.9, + kCGImagePropertyJFIFDictionary as String: jfifProperties, + ] + + CGImageDestinationAddImage(distination, cgImage, properties) + + guard CGImageDestinationFinalize(distination) else { + return nil + } + + guard data.length > 0 else { + return nil + } + + guard let progressiveImage = UIImage(data: data) else { + return nil + } + + return progressiveImage + } +} + diff --git a/Yep/Services/YepDownloader.swift b/Yep/Services/YepDownloader.swift index b9354b6c..5a2e5f31 100644 --- a/Yep/Services/YepDownloader.swift +++ b/Yep/Services/YepDownloader.swift @@ -8,6 +8,7 @@ import Foundation import RealmSwift +import ImageIO class YepDownloader: NSObject { @@ -47,17 +48,20 @@ class YepDownloader: NSObject { struct ProgressReporter { struct Task { - let downloadTask: NSURLSessionDownloadTask + let downloadTask: NSURLSessionDataTask typealias FinishedAction = NSData -> Void let finishedAction: FinishedAction let progress = NSProgress() + let tempData = NSMutableData() + let imageSource = CGImageSourceCreateIncremental(nil) + let imageTransform: (UIImage -> UIImage)? } let tasks: [Task] var finishedTasksCount = 0 - typealias ReportProgress = Double -> Void + typealias ReportProgress = (progress: Double, image: UIImage?) -> Void let reportProgress: ReportProgress? init(tasks: [Task], reportProgress: ReportProgress?) { @@ -77,10 +81,10 @@ class YepDownloader: NSObject { var progressReporters = [ProgressReporter]() class func downloadAttachmentsOfMessage(message: Message, reportProgress: ProgressReporter.ReportProgress?) { - downloadAttachmentsOfMessage(message, reportProgress: reportProgress, imageFinished: nil) + downloadAttachmentsOfMessage(message, reportProgress: reportProgress, imageTransform: nil, imageFinished: nil) } - class func downloadAttachmentsOfMessage(message: Message, reportProgress: ProgressReporter.ReportProgress?, imageFinished: (UIImage -> Void)?) { + class func downloadAttachmentsOfMessage(message: Message, reportProgress: ProgressReporter.ReportProgress?, imageTransform: (UIImage -> UIImage)?, imageFinished: (UIImage -> Void)?) { let downloadState = message.downloadState @@ -91,14 +95,14 @@ class YepDownloader: NSObject { let messageID = message.messageID let mediaType = message.mediaType - var attachmentDownloadTask: NSURLSessionDownloadTask? + var attachmentDownloadTask: NSURLSessionDataTask? var attachmentFinishedAction: ProgressReporter.Task.FinishedAction? let attachmentURLString = message.attachmentURLString if !attachmentURLString.isEmpty && message.localAttachmentName.isEmpty, let URL = NSURL(string: attachmentURLString) { - attachmentDownloadTask = sharedDownloader.session.downloadTaskWithURL(URL) + attachmentDownloadTask = sharedDownloader.session.dataTaskWithURL(URL) attachmentFinishedAction = { data in @@ -152,7 +156,7 @@ class YepDownloader: NSObject { } } - var thumbnailDownloadTask: NSURLSessionDownloadTask? + var thumbnailDownloadTask: NSURLSessionDataTask? var thumbnailFinishedAction: ProgressReporter.Task.FinishedAction? if mediaType == MessageMediaType.Video.rawValue { @@ -161,7 +165,7 @@ class YepDownloader: NSObject { if !thumbnailURLString.isEmpty && message.localThumbnailName.isEmpty, let URL = NSURL(string: thumbnailURLString) { - thumbnailDownloadTask = sharedDownloader.session.downloadTaskWithURL(URL) + thumbnailDownloadTask = sharedDownloader.session.dataTaskWithURL(URL) thumbnailFinishedAction = { data in @@ -196,11 +200,11 @@ class YepDownloader: NSObject { var tasks: [ProgressReporter.Task] = [] if let attachmentDownloadTask = attachmentDownloadTask, attachmentFinishedAction = attachmentFinishedAction { - tasks.append(ProgressReporter.Task(downloadTask: attachmentDownloadTask, finishedAction: attachmentFinishedAction)) + tasks.append(ProgressReporter.Task(downloadTask: attachmentDownloadTask, finishedAction: attachmentFinishedAction, imageTransform: imageTransform)) } if let thumbnailDownloadTask = thumbnailDownloadTask, thumbnailFinishedAction = thumbnailFinishedAction { - tasks.append(ProgressReporter.Task(downloadTask: thumbnailDownloadTask, finishedAction: thumbnailFinishedAction)) + tasks.append(ProgressReporter.Task(downloadTask: thumbnailDownloadTask, finishedAction: thumbnailFinishedAction, imageTransform: imageTransform)) } if tasks.count > 0 { @@ -218,8 +222,8 @@ class YepDownloader: NSObject { class func downloadDataFromURL(URL: NSURL, reportProgress: ProgressReporter.ReportProgress?, finishedAction: ProgressReporter.Task.FinishedAction) { - let downloadTask = sharedDownloader.session.downloadTaskWithURL(URL) - let task = ProgressReporter.Task(downloadTask: downloadTask, finishedAction: finishedAction) + let downloadTask = sharedDownloader.session.dataTaskWithURL(URL) + let task = ProgressReporter.Task(downloadTask: downloadTask, finishedAction: finishedAction, imageTransform: nil) let progressReporter = ProgressReporter(tasks: [task], reportProgress: reportProgress) sharedDownloader.progressReporters.append(progressReporter) @@ -232,6 +236,130 @@ extension YepDownloader: NSURLSessionDelegate { } +extension YepDownloader: NSURLSessionDataDelegate { + + private func reportProgressAssociatedWithDownloadTask(downloadTask: NSURLSessionDataTask, totalBytes: Int64) { + + for progressReporter in progressReporters { + + for i in 0.. Bool { + + for progressReporter in progressReporters { + + for i in 0.. 0.3 { + print("imageTransform") + }*/ + } + } + } + */ + } + + progressReporter.reportProgress?(progress: progressReporter.totalProgress, image: tranformedImage) + */ + + return final + } + } + } + + return false + } + + private func finishDownloadTask(downloadTask: NSURLSessionDataTask) { + + for i in 0.. Void) { + println("YepDownloader begin, expectedContentLength:\(response.expectedContentLength)") + reportProgressAssociatedWithDownloadTask(dataTask, totalBytes: response.expectedContentLength) + completionHandler(.Allow) + } + + func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) { + println("YepDownloader data.length: \(data.length)") + + let finish = reportProgressAssociatedWithDownloadTask(dataTask, didReceiveData: data) + + if finish { + println("YepDownloader finish") + + finishDownloadTask(dataTask) + } + } +} + +/* extension YepDownloader: NSURLSessionDownloadDelegate { private func handleData(data: NSData, ofDownloadTask downloadTask: NSURLSessionDownloadTask) { @@ -300,4 +428,4 @@ extension YepDownloader: NSURLSessionDownloadDelegate { reportProgressAssociatedWithDownloadTask(downloadTask, totalBytesWritten: totalBytesWritten, totalBytesExpectedToWrite: totalBytesExpectedToWrite) } } - +*/ diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 4fc2149b..32b1bf23 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -4633,6 +4633,14 @@ extension ConversationViewController: UIImagePickerControllerDelegate, UINavigat // Do send let imageData = UIImageJPEGRepresentation(image, YepConfig.messageImageCompressionQuality())! + /* + var imageData = UIImageJPEGRepresentation(image, YepConfig.messageImageCompressionQuality())! + + if let progressiveImage = UIImage(data: imageData)?.yep_progressiveImage { + + imageData = UIImageJPEGRepresentation(progressiveImage, YepConfig.messageImageCompressionQuality())! + } + */ let messageImageName = NSUUID().UUIDString diff --git a/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift b/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift index a48eef87..d99c252f 100644 --- a/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift +++ b/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift @@ -143,7 +143,7 @@ class ChatLeftAudioCell: ChatBaseCell { self.audioPlayedDuration = audioPlayedDuration - YepDownloader.downloadAttachmentsOfMessage(message, reportProgress: { [weak self] progress in + YepDownloader.downloadAttachmentsOfMessage(message, reportProgress: { [weak self] progress, _ in dispatch_async(dispatch_get_main_queue()) { self?.loadingWithProgress(progress) } diff --git a/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift b/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift index 12acd130..c8eb90a9 100644 --- a/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift +++ b/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift @@ -114,7 +114,7 @@ class ChatRightAudioCell: ChatRightBaseCell { self.audioPlayedDuration = audioPlayedDuration - YepDownloader.downloadAttachmentsOfMessage(message, reportProgress: { _ in }) + YepDownloader.downloadAttachmentsOfMessage(message, reportProgress: { _, _ in }) UIView.performWithoutAnimation { [weak self] in self?.makeUI()