mirror of
https://github.com/immich-app/immich.git
synced 2026-07-28 22:51:21 -07:00
fix(mobile): retry with exact resize when fast resize overshoots the texture bound
This commit is contained in:
@@ -20,7 +20,7 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
requestOptions.version = .current
|
||||
return requestOptions
|
||||
}()
|
||||
private static let maxOriginalPixelSize: CGFloat = 16384
|
||||
private static let maxPixelSize: CGFloat = 16384
|
||||
|
||||
private static let registry = RequestRegistry<ImageRequest>()
|
||||
|
||||
@@ -109,18 +109,16 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
]))
|
||||
}
|
||||
|
||||
// PHImageManagerMaximumSize returns a distorted aspect ratio for images too large to render
|
||||
// (extreme panoramas / long screenshots). Bound the long edge to 16384 (the GPU max texture
|
||||
// size) with aspectFit so the true ratio is kept and the buffer stays renderable. .fast resize
|
||||
// is enough, we only need the long edge under the limit.
|
||||
let isOriginal = !(width > 0 && height > 0)
|
||||
let targetSize = isOriginal
|
||||
? CGSize(width: Self.maxPixelSize, height: Self.maxPixelSize)
|
||||
: CGSize(width: Double(width), height: Double(height))
|
||||
let contentMode: PHImageContentMode = isOriginal ? .aspectFit : .aspectFill
|
||||
var image: UIImage?
|
||||
Self.imageManager.requestImage(
|
||||
for: asset,
|
||||
targetSize: isOriginal
|
||||
? CGSize(width: Self.maxOriginalPixelSize, height: Self.maxOriginalPixelSize)
|
||||
: CGSize(width: Double(width), height: Double(height)),
|
||||
contentMode: isOriginal ? .aspectFit : .aspectFill,
|
||||
targetSize: targetSize,
|
||||
contentMode: contentMode,
|
||||
options: Self.requestOptions,
|
||||
resultHandler: { (_image, info) -> Void in
|
||||
image = _image
|
||||
@@ -131,12 +129,38 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
guard let image = image,
|
||||
let cgImage = image.cgImage else {
|
||||
guard let fastImage = image,
|
||||
var cgImage = fastImage.cgImage else {
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Could not get pixel data for \(assetId)", details: nil)))
|
||||
}
|
||||
|
||||
// .fast can return larger than the target, so retry with .exact to guarantee the bound.
|
||||
if max(cgImage.width, cgImage.height) > Int(Self.maxPixelSize) {
|
||||
let exactOptions = Self.requestOptions.copy() as! PHImageRequestOptions
|
||||
exactOptions.resizeMode = .exact
|
||||
image = nil
|
||||
Self.imageManager.requestImage(
|
||||
for: asset,
|
||||
targetSize: targetSize,
|
||||
contentMode: contentMode,
|
||||
options: exactOptions,
|
||||
resultHandler: { (_image, info) -> Void in
|
||||
image = _image
|
||||
}
|
||||
)
|
||||
|
||||
if request.isCancelled {
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
guard let exactImage = image?.cgImage else {
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Could not resize image for \(assetId)", details: nil)))
|
||||
}
|
||||
cgImage = exactImage
|
||||
}
|
||||
|
||||
if request.isCancelled {
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user