Browse Source

Photo

master
Marco Schmickler 11 years ago
parent
commit
7e4278d5ca
  1. 4
      kplayer.xcodeproj/project.pbxproj
  2. 2
      kplayer/detail/ItemCell.swift
  3. 139
      kplayer/photo/MediaPhotoController.swift
  4. 62
      kplayer/util/DataLoadOperation.swift
  5. 36
      kplayer/util/ImageLoadOperation.swift

4
kplayer.xcodeproj/project.pbxproj

@ -22,6 +22,7 @@
1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; }; 1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; };
1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */; }; 1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */; };
1C73677CD719D0F82D144BF6 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C43137E3B8391E5F07B /* Bool.swift */; }; 1C73677CD719D0F82D144BF6 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C43137E3B8391E5F07B /* Bool.swift */; };
1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736F9338CE36708244D42A /* DataLoadOperation.swift */; };
1C7368364397315E12E90F05 /* VideoPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367379DEE94EBF3FAFA78 /* VideoPlayerController.swift */; }; 1C7368364397315E12E90F05 /* VideoPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367379DEE94EBF3FAFA78 /* VideoPlayerController.swift */; };
1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; }; 1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; };
1C73689C7E6A25E758B16C54 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73653A9EBCC466FD4E3DA6 /* String.swift */; }; 1C73689C7E6A25E758B16C54 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73653A9EBCC466FD4E3DA6 /* String.swift */; };
@ -93,6 +94,7 @@
1C736DB8164E3EF18FA6F28D /* NSArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSArray.swift; sourceTree = "<group>"; }; 1C736DB8164E3EF18FA6F28D /* NSArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSArray.swift; sourceTree = "<group>"; };
1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; }; 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; };
1C736E7B8BAD989DC544088E /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = "<group>"; }; 1C736E7B8BAD989DC544088E /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = "<group>"; };
1C736F9338CE36708244D42A /* DataLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataLoadOperation.swift; sourceTree = "<group>"; };
5C6CBA548F885BF342F594EA /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; }; 5C6CBA548F885BF342F594EA /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
A170BFB886D61D57F7009BFC /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; }; A170BFB886D61D57F7009BFC /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
C98AF5CF1B124D6A00D196CC /* kplayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = kplayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; C98AF5CF1B124D6A00D196CC /* kplayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = kplayer.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -187,6 +189,7 @@
1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */, 1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */,
1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */, 1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */,
1C736C60C423AE87B8D0F22A /* alamoimage.swift */, 1C736C60C423AE87B8D0F22A /* alamoimage.swift */,
1C736F9338CE36708244D42A /* DataLoadOperation.swift */,
); );
path = util; path = util;
sourceTree = "<group>"; sourceTree = "<group>";
@ -467,6 +470,7 @@
1C736D16E81BA1FB325200E0 /* HanekeFetchOperation.swift in Sources */, 1C736D16E81BA1FB325200E0 /* HanekeFetchOperation.swift in Sources */,
1C736D24891597F2728230EE /* ImageLoadOperation.swift in Sources */, 1C736D24891597F2728230EE /* ImageLoadOperation.swift in Sources */,
1C73626E34BA4D64ACF94AE5 /* alamoimage.swift in Sources */, 1C73626E34BA4D64ACF94AE5 /* alamoimage.swift in Sources */,
1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

2
kplayer/detail/ItemCell.swift

@ -41,7 +41,7 @@ class ItemCell: UICollectionViewCell {
} else { } else {
if let i = item.image { if let i = item.image {
image.image = i.scaleToSize(15 * 16, height: 15 * 9) image.image = i.scaleToSize(15 * 16, height: 15 * 9)
image.sizeToFit()
// image.sizeToFit()
} else { } else {
image.image = defaultImage image.image = defaultImage
} }

139
kplayer/photo/MediaPhotoController.swift

@ -15,61 +15,87 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView
var requests = Array<ImageLoadOperation>() var requests = Array<ImageLoadOperation>()
let THUMBS = "thumb"
var imageCache = NSCache()
var total = 0
var imageCache = Cache<UIImage>(name: "thumbnails")
lazy var backgroundOperationQueue: NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Thumb queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
lazy var operationQueue: NSOperationQueue = { lazy var operationQueue: NSOperationQueue = {
var queue = NSOperationQueue() var queue = NSOperationQueue()
queue.name = "Photo queue" queue.name = "Photo queue"
queue.maxConcurrentOperationCount = 5
queue.maxConcurrentOperationCount = 6
return queue return queue
}() }()
override func viewDidLoad() {
let thumbFormat = Format<UIImage>(name: THUMBS, diskCapacity: 100 * 1024 * 1024)
imageCache.addFormat(thumbFormat)
override func viewDidDisappear(animated: Bool) {
backgroundOperationQueue.cancelAllOperations()
}
override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
imageCache.totalCostLimit = 1024 * 1024 * 50
let backButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("back")) let backButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("back"))
navigationItem.leftBarButtonItems = [backButton] navigationItem.leftBarButtonItems = [backButton]
let playButton = UIBarButtonItem(barButtonSystemItem: .Play, target: self, action: Selector("play")) let playButton = UIBarButtonItem(barButtonSystemItem: .Play, target: self, action: Selector("play"))
navigationItem.rightBarButtonItems = [playButton]
let shotButton = UIBarButtonItem(barButtonSystemItem: .Camera, target: self, action: Selector("shot"))
navigationItem.rightBarButtonItems = [playButton, shotButton]
setChromeVisibility(true, animated: true) setChromeVisibility(true, animated: true)
self.photoAlbumView.reloadData(); self.photoAlbumView.reloadData();
self.photoScrubberView.reloadData(); self.photoScrubberView.reloadData();
let back = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let bsession = NSURLSession(configuration: back)
var j=0;
var j = 0;
for i in items { for i in items {
if j++ > 1000 { if j++ > 1000 {
break break
} }
let URL = NSURL(string: i.thumbUrlAbsolute)! let URL = NSURL(string: i.thumbUrlAbsolute)!
let fetcher = MediaFetcher<UIImage>(URL: URL, session: bsession)
let fetch = imageCache.fetch(fetcher: fetcher, formatName: THUMBS, failure: nil, success: nil)
fetch.onSuccess {
s in
println ("preload \(s)")
}
let op1 = ImageLoadOperation(imageURL: URL, succeeder: {
img in
let imageRef = img.CGImage;
let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8;
let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel;
self.total += cost
println("preload image loaded \(i.thumbUrlAbsolute) cost \(cost) total\(self.total)")
self.imageCache.setObject(img, forKey: i.thumbUrlAbsolute, cost: cost)
}, index: j)
op1.qualityOfService = NSQualityOfService.Background
backgroundOperationQueue.addOperation(op1)
} }
} }
override func didReceiveMemoryWarning() { override func didReceiveMemoryWarning() {
println("warning") println("warning")
imageCache.removeAllObjects()
super.didReceiveMemoryWarning() super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated. // Dispose of any resources that can be recreated.
} }
func shot() {
let currentItem = items[photoAlbumView.centerPageIndex]
var imageUrl = currentItem.thumbUrl!.stringByReplacingOccurrencesOfString("_thumb.jpg", withString: ".jpg")
imageUrl = imageUrl.stringByReplacingOccurrencesOfString("?preview=true", withString: "")
let url = NetworkManager.sharedInstance.baseurl + "/service/linkfavpic" + imageUrl
println(url)
Alamofire.request(.GET, url).responseString {
(_, _, string, _) in
println("ok")
}
}
func back() { func back() {
completionHandler!() completionHandler!()
@ -194,27 +220,6 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView
var size = NIPhotoScrollViewPhotoSizeUnknown var size = NIPhotoScrollViewPhotoSizeUnknown
imageCache.fetch(key: URL.absoluteString!, formatName: THUMBS).onSuccess {
i in
image = i
size = NIPhotoScrollViewPhotoSizeThumbnail
self.photoAlbumView.didLoadPhoto(image, atIndex: photoAtIndex, photoSize: size)
}
if let i = image {
isLoading[0] = false
} else {
let fetcher = NetworkFetcher<UIImage>(URL: URL)
let fetch = imageCache.fetch(fetcher: fetcher, formatName: THUMBS, failure: nil, success: nil)
fetch.onSuccess {
i in
println("thumb loaded \(newItem.imageUrlAbsolute)")
size = NIPhotoScrollViewPhotoSizeThumbnail
self.photoAlbumView.didLoadPhoto(image, atIndex: photoAtIndex, photoSize: size)
}
}
for r in requests { for r in requests {
let pages = self.photoAlbumView.visiblePages() as NSMutableSet! let pages = self.photoAlbumView.visiblePages() as NSMutableSet!
var ok = false var ok = false
@ -231,14 +236,39 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView
} }
} }
image = imageCache.objectForKey(URL.absoluteString!) as? UIImage
if let i = image {
size = NIPhotoScrollViewPhotoSizeThumbnail
isLoading[0] = false
} else {
let URL = NSURL(string: newItem.thumbUrlAbsolute)!
let op3 = ImageLoadOperation(imageURL: URL, succeeder: {
i in
// println("thumb preload image loaded \(newItem.imageUrlAbsolute)")
let imageRef = i.CGImage;
let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8;
let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel;
self.imageCache.setObject(i, forKey: newItem.thumbUrlAbsolute, cost: cost)
size = NIPhotoScrollViewPhotoSizeThumbnail
self.photoAlbumView.didLoadPhoto(i, atIndex: photoAtIndex, photoSize: size)
self.photoScrubberView.didLoadThumbnail(i, atIndex: photoAtIndex);
}, index: photoAtIndex)
op3.qualityOfService = NSQualityOfService.UserInteractive
requests.append(op3)
operationQueue.addOperation(op3)
}
let op2 = ImageLoadOperation(imageURL: hqURL, succeeder: { let op2 = ImageLoadOperation(imageURL: hqURL, succeeder: {
i in i in
println("image loaded \(newItem.imageUrlAbsolute) at \(photoAtIndex)")
// println("image loaded \(newItem.imageUrlAbsolute) at \(photoAtIndex)")
size = NIPhotoScrollViewPhotoSizeOriginal size = NIPhotoScrollViewPhotoSizeOriginal
self.photoAlbumView.didLoadPhoto(i, atIndex: photoAtIndex, photoSize: size) self.photoAlbumView.didLoadPhoto(i, atIndex: photoAtIndex, photoSize: size)
photoSize[0] = size photoSize[0] = size
}, index: photoAtIndex) }, index: photoAtIndex)
op2.qualityOfService = NSQualityOfService.UserInitiated
requests.append(op2) requests.append(op2)
operationQueue.addOperation(op2) operationQueue.addOperation(op2)
@ -288,28 +318,41 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView
let c = count(items) let c = count(items)
let newItem = items[thumbnailIndex] let newItem = items[thumbnailIndex]
let URL = NSURL(string: newItem.thumbUrlAbsolute)!
let fetcher = NetworkFetcher<UIImage>(URL: URL)
let fetch = imageCache.fetch(fetcher: fetcher, formatName: THUMBS, failure: nil, success: nil)
var image: UIImage?
image = imageCache.objectForKey(newItem.thumbUrlAbsolute) as? UIImage
fetch.onSuccess {
if (image == nil) {
let URL = NSURL(string: newItem.thumbUrlAbsolute)!
let op3 = ImageLoadOperation(imageURL: URL, succeeder: {
i in i in
// println("thumb image loaded \(newItem.thumbUrlAbsolute)")
let imageRef = i.CGImage;
let bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8;
let cost = CGImageGetWidth(imageRef) * CGImageGetHeight(imageRef) * bytesPerPixel;
self.imageCache.setObject(i, forKey: newItem.thumbUrlAbsolute, cost: cost)
self.photoScrubberView.didLoadThumbnail(i, atIndex: thumbnailIndex); self.photoScrubberView.didLoadThumbnail(i, atIndex: thumbnailIndex);
}, index: thumbnailIndex)
op3.qualityOfService = NSQualityOfService.UserInitiated
operationQueue.addOperation(op3)
} }
return nil
return image
} }
} }
class MediaFetcher<T : DataConvertible> : NetworkFetcher<T> {
class MediaFetcher<T:DataConvertible>: NetworkFetcher<T> {
let bsession: NSURLSession? let bsession: NSURLSession?
init(URL : NSURL, session: NSURLSession) {
init(URL: NSURL, session: NSURLSession) {
self.bsession = session self.bsession = session
super.init(URL: URL) super.init(URL: URL)
} }
override public var session : NSURLSession { return bsession! }
override public var session: NSURLSession {
return bsession!
}
} }

62
kplayer/util/DataLoadOperation.swift

@ -0,0 +1,62 @@
//
// Created by Marco Schmickler on 21.03.15.
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
//
import Foundation
import Alamofire
import Darwin
class ImageLoadOperation: NSOperation {
public typealias Succeeder = (NSData) -> ()
let imageURL: NSURL
let succeeder: Succeeder
let index: Int
var request: Request?
var manager: Manager?
var ready1 = false
init(imageURL: NSURL, succeeder: Succeeder, index: Int) {
self.imageURL = imageURL
self.succeeder = succeeder
self.index = index
}
override func main() {
if self.cancelled {
return
}
// println("do load \(imageURL.absoluteString!)")
if let m = manager {
request = m.request(.GET, imageURL)
} else {
request = Alamofire.request(.GET, imageURL)
}
request!.validate().response { (request, response, data, error) in
self.succeeder(data)
}
while !ready1 {
usleep(10000)
}
}
override func cancel() {
// println("cancel load \(imageURL.absoluteString!)")
ready1 = true
if let r = request {
r.cancel()
}
super.cancel()
}
}

36
kplayer/util/ImageLoadOperation.swift

@ -13,6 +13,11 @@ class ImageLoadOperation: NSOperation {
let imageURL: NSURL let imageURL: NSURL
let succeeder: Succeeder let succeeder: Succeeder
let index: Int let index: Int
var request: Request?
var manager: Manager?
var ready1 = false
init(imageURL: NSURL, succeeder: Succeeder, index: Int) { init(imageURL: NSURL, succeeder: Succeeder, index: Int) {
@ -26,21 +31,42 @@ class ImageLoadOperation: NSOperation {
return return
} }
usleep(100000)
// println("do load \(imageURL.absoluteString!)")
if self.cancelled {
return
if let m = manager {
request = m.request(.GET, imageURL)
} else {
request = Alamofire.request(.GET, imageURL)
} }
Alamofire.request(.GET, imageURL).validate().responseImage() {
request!.validate().responseImage() {
(request, _, image, error) in (request, _, image, error) in
if error == nil { if error == nil {
// if request.URLString.isEqual(self.imageURL) {
self.ready1 = true
// if request.URLString.isEqual(self.imageURL) {
// dispatch_async(dispatch_get_main_queue()) {
self.succeeder(image!) self.succeeder(image!)
// } // }
// }
} }
} }
while !ready1 {
usleep(10000)
}
}
override func cancel() {
// println("cancel load \(imageURL.absoluteString!)")
ready1 = true
if let r = request {
r.cancel()
}
super.cancel()
} }
} }
Loading…
Cancel
Save