Cherry-pick various fixes

This commit is contained in:
Ilya Laktyushin
2024-04-15 16:24:29 +04:00
parent 5dc97b4e3d
commit 669a8719bf
31 changed files with 364 additions and 129 deletions

View File

@@ -5,6 +5,7 @@ import Postbox
import SwiftSignalKit
import ImageCompression
import Accelerate.vImage
import CoreImage
private final class RequestId {
var id: PHImageRequestID?
@@ -15,24 +16,43 @@ private func resizedImage(_ image: UIImage, for size: CGSize) -> UIImage? {
guard let cgImage = image.cgImage else {
return nil
}
if #available(iOS 14.1, *) {
if cgImage.bitsPerComponent == 10, let ciImage = CIImage(image: image, options: [.applyOrientationProperty: true, .toneMapHDRtoSDR: true]) {
let scaleX = size.width / ciImage.extent.width
let filter = CIFilter(name: "CILanczosScaleTransform")!
filter.setValue(ciImage, forKey: kCIInputImageKey)
filter.setValue(scaleX, forKey: kCIInputScaleKey)
filter.setValue(1.0, forKey: kCIInputAspectRatioKey)
guard let outputImage = filter.outputImage else { return nil }
let ciContext = CIContext()
guard let cgImage = ciContext.createCGImage(outputImage, from: outputImage.extent) else { return nil }
return UIImage(cgImage: cgImage)
}
}
var format = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: nil,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue),
version: 0,
decode: nil,
renderingIntent: .defaultIntent)
renderingIntent: cgImage.renderingIntent)
var error: vImage_Error
var sourceBuffer = vImage_Buffer()
defer { sourceBuffer.data.deallocate() }
defer { sourceBuffer.data?.deallocate() }
error = vImageBuffer_InitWithCGImage(&sourceBuffer,
&format,
nil,
cgImage,
vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else { return nil }
guard error == kvImageNoError else {
return nil
}
var destinationBuffer = vImage_Buffer()
error = vImageBuffer_Init(&destinationBuffer,
@@ -84,7 +104,7 @@ extension UIImage.Orientation {
private let fetchPhotoWorkers = ThreadPool(threadCount: 3, threadPriority: 0.2)
public func fetchPhotoLibraryResource(localIdentifier: String, width: Int32?, height: Int32?, format: MediaImageFormat?, quality: Int32?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
public func fetchPhotoLibraryResource(localIdentifier: String, width: Int32?, height: Int32?, format: MediaImageFormat?, quality: Int32?, useExif: Bool) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return Signal { subscriber in
let queue = ThreadPoolQueue(threadPool: fetchPhotoWorkers)
@@ -96,7 +116,7 @@ public func fetchPhotoLibraryResource(localIdentifier: String, width: Int32?, he
option.deliveryMode = .highQualityFormat
option.isNetworkAccessAllowed = true
option.isSynchronous = false
let size: CGSize
if let width, let height {
size = CGSize(width: CGFloat(width), height: CGFloat(height))
@@ -104,11 +124,31 @@ public func fetchPhotoLibraryResource(localIdentifier: String, width: Int32?, he
size = CGSize(width: 1280.0, height: 1280.0)
}
var targetSize = PHImageManagerMaximumSize
//TODO: figure out how to manually read and resize some weird 10-bit heif photos from third-party cameras
if useExif, min(asset.pixelWidth, asset.pixelHeight) > 3800 {
func encodeText(string: String, key: Int16) -> String {
let nsString = string as NSString
let result = NSMutableString()
for i in 0 ..< nsString.length {
var c: unichar = nsString.character(at: i)
c = unichar(Int16(c) + key)
result.append(NSString(characters: &c, length: 1) as String)
}
return result as String
}
if let values = asset.value(forKeyPath: encodeText(string: "jnbhfQspqfsujft", key: -1)) as? [String: Any] {
if let depth = values["Depth"] as? Int, depth == 10 {
targetSize = size
}
}
}
queue.addTask(ThreadPoolTask({ _ in
let startTime = CACurrentMediaTime()
let semaphore = DispatchSemaphore(value: 0)
let requestIdValue = PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: option, resultHandler: { (image, info) -> Void in
let requestIdValue = PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFit, options: option, resultHandler: { (image, info) -> Void in
Queue.concurrentDefaultQueue().async {
requestId.with { current -> Void in
if !current.invalidated {