build: compile release APK and update dependencies (expo-image-manipulator/loader)
This commit is contained in:
+128
@@ -0,0 +1,128 @@
|
||||
import SDWebImageWebPCoder
|
||||
import Photos
|
||||
import ExpoModulesCore
|
||||
|
||||
internal typealias SaveImageResult = (url: URL, data: Data)
|
||||
|
||||
/**
|
||||
Loads the image from given URL.
|
||||
*/
|
||||
internal func loadImage(atUrl url: URL, appContext: AppContext) async throws -> UIImage {
|
||||
if url.scheme == "data" {
|
||||
guard let data = try? Data(contentsOf: url), let image = UIImage(data: data) else {
|
||||
throw CorruptedImageDataException()
|
||||
}
|
||||
return image
|
||||
}
|
||||
if url.scheme == "ph" || url.scheme == "assets-library" {
|
||||
return try await loadImageFromPhotoLibrary(url: url)
|
||||
}
|
||||
|
||||
guard let imageLoader = appContext.imageLoader else {
|
||||
throw ImageLoaderNotFoundException()
|
||||
}
|
||||
guard FileSystemUtilities.permissions(appContext, for: url).contains(.read) && FileManager.default.isReadableFile(atPath: url.path) else {
|
||||
throw FileSystemReadPermissionException(url.absoluteString)
|
||||
}
|
||||
|
||||
do {
|
||||
if let result = try await imageLoader.loadImage(for: url) {
|
||||
return result
|
||||
}
|
||||
} catch {
|
||||
throw ImageLoadingFailedException((error as NSError).debugDescription)
|
||||
}
|
||||
// TODO: throw something better
|
||||
throw ImageLoadingFailedException("")
|
||||
}
|
||||
|
||||
/**
|
||||
Loads the image from user's photo library.
|
||||
*/
|
||||
internal func loadImageFromPhotoLibrary(url: URL) async throws -> UIImage {
|
||||
guard let asset = retrieveAsset(from: url) else {
|
||||
throw ImageNotFoundException()
|
||||
}
|
||||
let size = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
|
||||
let options = PHImageRequestOptions()
|
||||
|
||||
options.resizeMode = .exact
|
||||
options.isNetworkAccessAllowed = true
|
||||
options.isSynchronous = true
|
||||
options.deliveryMode = .highQualityFormat
|
||||
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFit, options: options) { image, _ in
|
||||
if let image {
|
||||
continuation.resume(returning: image)
|
||||
} else {
|
||||
continuation.resume(throwing: ImageNotFoundException())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns pixel data representation of the image.
|
||||
*/
|
||||
func imageData(from image: UIImage, format: ImageFormat, compression: Double) -> Data? {
|
||||
switch format {
|
||||
case .jpeg, .jpg:
|
||||
return image.jpegData(compressionQuality: compression)
|
||||
case .png:
|
||||
return image.pngData()
|
||||
case .webp:
|
||||
return SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: [.encodeCompressionQuality: compression])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if we are dealing with a ph asset URL and uses the correct method to fetch it.
|
||||
*/
|
||||
func retrieveAsset(from url: URL) -> PHAsset? {
|
||||
if url.scheme == "ph" {
|
||||
let identifier = String(url.absoluteString.dropFirst(5)) // removes ph://
|
||||
return PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: nil).firstObject
|
||||
}
|
||||
return PHAsset.fetchAssets(withALAssetURLs: [url], options: nil).firstObject
|
||||
}
|
||||
|
||||
/**
|
||||
Helper function for drawing the image in graphics context.
|
||||
Throws appropriate exceptions when the context is missing or the image couldn't be rendered.
|
||||
*/
|
||||
internal func drawInNewContext(size: CGSize, drawing: (UIGraphicsImageRendererContext) -> Void) -> UIImage {
|
||||
let format = UIGraphicsImageRendererFormat()
|
||||
format.scale = 1
|
||||
|
||||
let renderer = UIGraphicsImageRenderer(size: size, format: format)
|
||||
|
||||
return renderer.image { context in
|
||||
drawing(context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Saves the image as a file.
|
||||
*/
|
||||
internal func saveImage(_ image: UIImage, options: ManipulateOptions, appContext: AppContext) throws -> SaveImageResult {
|
||||
guard let cachesDirectory = appContext.config.cacheDirectory else {
|
||||
throw FileSystemNotFoundException()
|
||||
}
|
||||
|
||||
let directory = URL(fileURLWithPath: cachesDirectory.path).appendingPathComponent("ImageManipulator")
|
||||
let filename = UUID().uuidString.appending(options.format.fileExtension)
|
||||
let fileUrl = directory.appendingPathComponent(filename)
|
||||
|
||||
FileSystemUtilities.ensureDirExists(at: directory)
|
||||
|
||||
guard let data = imageData(from: image, format: options.format, compression: options.compress) else {
|
||||
throw CorruptedImageDataException()
|
||||
}
|
||||
do {
|
||||
try data.write(to: fileUrl, options: .atomic)
|
||||
} catch let error {
|
||||
throw ImageWriteFailedException(error.localizedDescription)
|
||||
}
|
||||
return (url: fileUrl, data: data)
|
||||
}
|
||||
Reference in New Issue
Block a user