This repository has been archived by the owner on Feb 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from teambition/feature/high-resolution-image
fix memory issues when display image with high resolution
- Loading branch information
Showing
28 changed files
with
539 additions
and
323 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
github "onevcat/Kingfisher" | ||
github "Quick/Nimble" | ||
github "Quick/Quick" | ||
github "onevcat/Kingfisher" ~> 4.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github "Quick/Nimble" ~> 7.3.0 | ||
github "Quick/Quick" ~> 1.3.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file removed
BIN
-115 KB
PhotoBrowser.xcworkspace/xcuserdata/wangwei.xcuserdatad/UserInterfaceState.xcuserstate
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// | ||
// HighResolutionImageView.swift | ||
// PhotoBrowser | ||
// | ||
// Created by WangWei on 2019/3/22. | ||
// Copyright © 2019 Teambition. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
private class FastTiledLayer: CATiledLayer { | ||
override class func fadeDuration() -> CFTimeInterval { | ||
return 0.0 | ||
} | ||
} | ||
|
||
// swiftlint:disable force_cast | ||
final class HighResolutionImageView: UIView { | ||
override class var layerClass: AnyClass { | ||
return FastTiledLayer.self | ||
} | ||
|
||
private var tiledLayer: FastTiledLayer { | ||
return self.layer as! FastTiledLayer | ||
} | ||
|
||
var image: UIImage? { | ||
didSet { | ||
updateTileSize() | ||
} | ||
} | ||
|
||
override init(frame: CGRect) { | ||
super.init(frame: frame) | ||
|
||
contentMode = .scaleAspectFit | ||
layer.contentsGravity = .resizeAspect | ||
|
||
backgroundColor = .white | ||
} | ||
|
||
required init?(coder aDecoder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
private var imageScale: CGFloat = 1.0 | ||
|
||
private var tileSize = CGSize(width: 400, height: 400) | ||
|
||
private func updateTileSize() { | ||
guard let imageSize = image?.size else { return } | ||
|
||
tiledLayer.tileSize = tileSize | ||
|
||
// cal imageScale | ||
imageScale = max(bounds.width / imageSize.width, bounds.height / imageSize.height) | ||
|
||
tiledLayer.levelsOfDetail = 7 | ||
tiledLayer.levelsOfDetailBias = Int(exactly: ceil(log2(1 / imageScale))) ?? 3 | ||
} | ||
|
||
override func draw(_ rect: CGRect) { | ||
guard let cgImage = image?.cgImage else { return } | ||
let scaledRect = rect.applying(CGAffineTransform(scaleX: 1 / imageScale, y: 1 / imageScale)) | ||
let croppedCGImage = cgImage.cropping(to: scaledRect)! | ||
let croppedImage = UIImage(cgImage: croppedCGImage) | ||
croppedImage.draw(in: rect) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// | ||
// ImageContainerView.swift | ||
// PhotoBrowser | ||
// | ||
// Created by WangWei on 2019/3/26. | ||
// Copyright © 2019 Teambition. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
import Kingfisher | ||
|
||
final class ImageContainerView: UIView { | ||
lazy var highResImageView: HighResolutionImageView = { | ||
let imageView = HighResolutionImageView() | ||
imageView.layer.masksToBounds = true | ||
return imageView | ||
}() | ||
|
||
lazy var normalImageView: UIImageView = { | ||
let imageView = UIImageView() | ||
imageView.layer.masksToBounds = true | ||
imageView.contentMode = .scaleAspectFit | ||
return imageView | ||
}() | ||
|
||
var image: UIImage? { | ||
didSet { | ||
update(with: image) | ||
} | ||
} | ||
|
||
override init(frame: CGRect) { | ||
super.init(frame: frame) | ||
|
||
setup() | ||
} | ||
|
||
required init?(coder aDecoder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
private func setup() { | ||
addSubview(normalImageView) | ||
addSubview(highResImageView) | ||
normalImageView.frame = bounds | ||
highResImageView.frame = bounds | ||
} | ||
|
||
override func layoutSubviews() { | ||
super.layoutSubviews() | ||
normalImageView.frame = bounds | ||
highResImageView.frame = bounds | ||
} | ||
|
||
private func update(with image: UIImage?) { | ||
guard let image = image else { | ||
highResImageView.image = nil | ||
normalImageView.image = nil | ||
return | ||
} | ||
let shouldUseHighResImageView = | ||
image.size.width * image.size.height > 3000 * 3000 | ||
highResImageView.isHidden = !shouldUseHighResImageView | ||
if shouldUseHighResImageView { | ||
highResImageView.frame = bounds | ||
highResImageView.image = image | ||
let size = bounds.size | ||
DispatchQueue.global().async { [weak self] in | ||
let downsampled = image.kf.resize(to: size, for: .aspectFit) | ||
DispatchQueue.main.async { | ||
self?.normalImageView.image = downsampled | ||
} | ||
} | ||
} else { | ||
normalImageView.frame = bounds | ||
normalImageView.image = image | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// | ||
// Kingfisher+CacheSerializer.swift | ||
// PhotoBrowser | ||
// | ||
// Created by WangWei on 2019/4/2. | ||
// Copyright © 2019 Teambition. All rights reserved. | ||
// | ||
|
||
import Kingfisher | ||
|
||
struct CustomCacheSerializer: CacheSerializer { | ||
static let `default` = CustomCacheSerializer() | ||
private init() {} | ||
|
||
func data(with image: Image, original: Data?) -> Data? { | ||
// do nothing when image.size is too large | ||
if image.size.width * image.size.height > 3000 * 3000 { | ||
return original | ||
} | ||
|
||
let imageFormat = original?.kf.imageFormat ?? .unknown | ||
|
||
let data: Data? | ||
switch imageFormat { | ||
case .PNG: data = image.kf.pngRepresentation() | ||
case .JPEG: data = image.kf.jpegRepresentation(compressionQuality: 1.0) | ||
case .GIF: data = image.kf.gifRepresentation() | ||
case .unknown: data = original ?? image.kf.normalized.kf.pngRepresentation() | ||
} | ||
|
||
return data | ||
} | ||
|
||
func image(with data: Data, options: KingfisherParsedOptionsInfo) -> Image? { | ||
let imageCreatingOptions = | ||
ImageCreatingOptions(scale: options.scaleFactor, | ||
duration: 0.0, | ||
preloadAll: options.preloadAllAnimationData, | ||
onlyFirstFrame: options.onlyLoadFirstFrame) | ||
return KingfisherWrapper<Image>.image(data: data, | ||
options: imageCreatingOptions) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.