【问题标题】:PHAsset to UIImagePHAsset 到 UIImage
【发布时间】:2015-08-28 23:51:39
【问题描述】:

我正在尝试从 PHAsset 创建一个 UIImage(如缩略图或其他东西),以便我可以将它传递给需要 UIImage 的东西。我已经尝试过调整我在 SO 上找到的解决方案(因为它们都只是直接将它传递给一个 tableview 之类的东西),但我没有成功(可能是因为我做得不对)。

func getAssetThumbnail(asset: PHAsset) -> UIImage {
    var retimage = UIImage()
    println(retimage)
    let manager = PHImageManager.defaultManager()
    manager.requestImageForAsset(asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .AspectFit, options: nil, resultHandler: {(result, info)->Void in
            retimage = result
    })
    println(retimage)
    return retimage
}

printlns 告诉我 manager.request 行现在没有做任何事情。如何获得它以将资产作为 UIImage 提供给我。

谢谢。

【问题讨论】:

标签: swift phasset


【解决方案1】:

问题在于 requestImageForAsset 是一个 resultHandler ,并且在您的函数已经打印并返回您期望的值之后,此代码块将在将来发生。我确实进行了更改以向您展示这种情况,并提出了一些简单的解决方案。

func getAssetThumbnail(asset: PHAsset) {
    var retimage = UIImage()
    println(retimage)
    let manager = PHImageManager.defaultManager()
    manager.requestImageForAsset(asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .AspectFit, options: nil, resultHandler: {
    (result, info)->Void in
            retimage = result
      println("This happens after")
      println(retimage)
      callReturnImage(retimage) // <- create this method
    })
    println("This happens before")
}

Apple documentation了解更多关于闭包和完成句柄和异步函数的信息

希望对你有帮助!

【讨论】:

  • 还是有点困惑。所以我们正在改变 getAssetThumbnail 不返回任何东西?在这种情况下,我们如何将 retimage 传递给我们需要的东西?何时以及如何让块执行,以便获得有用的东西。希望 callReturnImage 与我们尝试将 retimage 传递给的其他函数分开。
  • 您不能返回任何东西,因为您的返回将在您检索它之前发生,添加另一个函数来执行您想要对图像执行的操作或添加您想要对图像执行的操作完成块。这是解决此问题的两种更简单的方法。
  • 对。好的,可以说我有 2 个函数(x 和 y)都采用 UIImages。我希望他们对我们在该块中创建的 UIImage 进行操作。通过将 UIImage 传递给 x & y 并从请求方法中获取该图像,我是否不可能在该块之外执行此操作?还是我必须将 x & y 作为您暗示的 callReturnImage 函数。如果不可能,那么如果我以后要创建函数 z,我是不是必须回去编辑这个函数才能让它工作?
  • 我不是说不可能我说这是更简单的方法,您可以创建也返回完成块的函数,但问题对您来说只会变得更大,我将在答案中发布一个链接以便您了解更多信息。
【解决方案2】:

这完成了我需要它做的事情,以防万一有人也需要它。

func getAssetThumbnail(asset: PHAsset) -> UIImage {
    let manager = PHImageManager.defaultManager()
    let option = PHImageRequestOptions()
    var thumbnail = UIImage()
    option.synchronous = true
    manager.requestImageForAsset(asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .AspectFit, options: option, resultHandler: {(result, info)->Void in
            thumbnail = result!
    })
    return thumbnail
}

编辑:Swift 3 更新

func getAssetThumbnail(asset: PHAsset) -> UIImage {
    let manager = PHImageManager.default()
    let option = PHImageRequestOptions()
    var thumbnail = UIImage()
    option.isSynchronous = true
    manager.requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
        thumbnail = result!
    })
    return thumbnail
}

【讨论】:

  • 如何获得 PHAsset 的原始宽度 + 高度?
  • 我也想知道如何获得原始的宽度和高度,您找到解决方案了吗,@TimNuwin?
  • 如果您谈论的是 pixelWidth 和 pixelHeight 属性,那么您将使用它。如果没有,我需要更多信息来提供帮助。希望此链接有所帮助:developer.apple.com/library/ios/documentation/Photos/Reference/…
  • targetSize设置PHImageManagerMaximumSize可以得到原图。
  • @BorutTomazin 当我更改targetSize 时,我似乎遇到了This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes. 的奇怪崩溃
【解决方案3】:

我建议使用 Apple 的 PHCachingImageManager(继承自 PHImageManager):

PHCachingImageManager 对象获取或生成照片或视频资产的图像数据

另外,PHCachingImageManager 支持更好的缓存机制。

同步获取缩略图示例:

let options = PHImageRequestOptions()
options.deliveryMode = .HighQualityFormat
options.synchronous = true // Set it to false for async callback

let imageManager = PHCachingImageManager()
imageManager.requestImageForAsset(YourPHAssetVar,
                                  targetSize: CGSizeMake(CGFloat(160), CGFloat(160)),
                                  contentMode: .AspectFill,
                                  options: options,
                                  resultHandler: { (resultThumbnail : UIImage?, info : [NSObject : AnyObject]?) in

                                                   // Assign your thumbnail which is the *resultThumbnail*
                                                  }

此外,您可以使用 PHCachingImageManager 来缓存您的图像以获得更快的 UI 响应:

要使用缓存图像管理器:

  1. 创建一个 PHCachingImageManager 实例。 (此步骤替换使用 共享 PHImageManager 实例。)

  2. 使用 PHAsset 类方法获取您感兴趣的资产。

  3. 要为这些资产准备图像,请调用 startCachingImagesForAssets:targetSize:contentMode:options: 方法 包含您计划在何时使用的目标大小、内容模式和选项 稍后为每个单独的资产请求图像。

  4. 当您需要单个资产的图像时,请调用 requestImageForAsset:targetSize:contentMode:options:resultHandler: 方法,并传递您在准备时使用的相同参数 资产。

如果您请求的图片属于已经准备好的图片,则 PHCachingImageManager 对象立即返回该图像。 否则,Photos 会按需准备图像并将其缓存以备后用 使用。

在我们的示例中:

var phAssetArray : [PHAsset] = []

for i in 0..<assets.count
{
  phAssetArray.append(assets[i] as! PHAsset)
}

let options = PHImageRequestOptions()
options.deliveryMode = .Opportunistic
options.synchronous = false

self.imageManager.startCachingImagesForAssets(phAssetArray,
                                              targetSize: CGSizeMake(CGFloat(160), CGFloat(160)),
                                              contentMode: .AspectFill,
                                              options: options)

【讨论】:

    【解决方案4】:

    对于 Swift 3.0.1:

    func getAssetThumbnail(asset: PHAsset, size: CGFloat) -> UIImage {
        let retinaScale = UIScreen.main.scale
        let retinaSquare = CGSize(width: size * retinaScale, height: size * retinaScale)//(size * retinaScale, size * retinaScale)
        let cropSizeLength = min(asset.pixelWidth, asset.pixelHeight)
        let square = CGRect(x:0, y: 0,width: CGFloat(cropSizeLength),height: CGFloat(cropSizeLength))
        let cropRect = square.applying(CGAffineTransform(scaleX: 1.0/CGFloat(asset.pixelWidth), y: 1.0/CGFloat(asset.pixelHeight)))
    
        let manager = PHImageManager.default()
        let options = PHImageRequestOptions()
        var thumbnail = UIImage()
    
        options.isSynchronous = true
        options.deliveryMode = .highQualityFormat
        options.resizeMode = .exact
        options.normalizedCropRect = cropRect
    
        manager.requestImage(for: asset, targetSize: retinaSquare, contentMode: .aspectFit, options: options, resultHandler: {(result, info)->Void in
            thumbnail = result!
        })
        return thumbnail
    }
    

    资源:https://gist.github.com/lvterry/f062cf9ae13bca76b0c6#file-getassetthumbnail-swift

    【讨论】:

      【解决方案5】:

      试试这个对我有用,希望对你也有帮助,

      func getUIImage(asset: PHAsset) -> UIImage? {
      
          var img: UIImage?
          let manager = PHImageManager.default()
          let options = PHImageRequestOptions()
          options.version = .original
          options.isSynchronous = true
          manager.requestImageData(for: asset, options: options) { data, _, _, _ in
      
              if let data = data {
                  img = UIImage(data: data)
              }
          }
          return img
      }
      

      【讨论】:

      • 我收到错误消息“无法为资产 加载图像数据”
      • 它对我没有帮助,但是很好的尝试
      【解决方案6】:

      Objective-c 版本的代码基于 dcheng 答案。

      -(UIImage *)getAssetThumbnail:(PHAsset * )asset {
      
          PHImageRequestOptions *options = [[PHImageRequestOptions alloc]init];
          options.synchronous = true;
      
          __block UIImage *image;
          [PHCachingImageManager.defaultManager requestImageForAsset:asset targetSize:CGSizeMake(100, 100) contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
              image = result;
          }];
          return image;
        }
      

      【讨论】:

        【解决方案7】:

        斯威夫特 4.

        resizeMode,deliveryMode - 可根据用户要求设置。

        isNetworkAccessAllowed - 将此设置为“true”以从云端获取图像

        imageSize- 所需图片尺寸

        func getImageFromAsset(asset:PHAsset,imageSize:CGSize, callback:@escaping (_ result:UIImage) -> Void) -> Void{
        
            let requestOptions = PHImageRequestOptions()
            requestOptions.resizeMode = PHImageRequestOptionsResizeMode.fast
            requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
            requestOptions.isNetworkAccessAllowed = true
            requestOptions.isSynchronous = true
            PHImageManager.default().requestImage(for: asset, targetSize: imageSize, contentMode: PHImageContentMode.default, options: requestOptions, resultHandler: { (currentImage, info) in
                callback(currentImage!)
            })
        }
        

        【讨论】:

          【解决方案8】:

          简单的解决方案(Swift 4.2)

          方法一:

          extension PHAsset {
          
              var image : UIImage {
                  var thumbnail = UIImage()
                  let imageManager = PHCachingImageManager()
                  imageManager.requestImage(for: self, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: nil, resultHandler: { image, _ in
                      thumbnail = image!
                  })
                  return thumbnail
              }
          }                          
          
          let image = asset.image 
          

          如果您只需要来自PHAssetUIImage,请使用此方法。

          extension PHAsset {
              func image(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?) -> UIImage {
                  var thumbnail = UIImage()
                  let imageManager = PHCachingImageManager()
                  imageManager.requestImage(for: self, targetSize: targetSize, contentMode: contentMode, options: options, resultHandler: { image, _ in
                      thumbnail = image!
                  })
                  return thumbnail
              }
          }
          
          let image = asset.image(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?)
          

          将此方法用于您想要的UIImage

          extension PHAsset {
          
              func image(completionHandler: @escaping (UIImage) -> ()){
                  var thumbnail = UIImage()
                  let imageManager = PHCachingImageManager()
                  imageManager.requestImage(for: self, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: nil, resultHandler: { img, _ in
                      thumbnail = img!
                  })
                  completionHandler(thumbnail)
              }
          }
          
          let image = asset.image(completionHandler: {(img) in
              print("Finished")
          })
          

          完成后使用此方法进行通知。

          方法二:

          extension PHAsset {
              var data : (UIImage, [AnyHashable : Any]) {
                  var img = UIImage(); var information = [AnyHashable : Any](); let imageManager = PHCachingImageManager()
                  imageManager.requestImage(for: self, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: nil, resultHandler: { image,info in
                      img = image!
                      information = info!
                  })
                  return (img,information)
              }
          } 
          
          
          let image_withData : (UIImage, [AnyHashable : Any]) = asset.data
          

          如果您想要UIImagePHAsset 的结果信息,请使用此方法

          extension PHAsset {
          
              func data(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?) -> (UIImage, [AnyHashable : Any]) {
                  var img = UIImage(); var information = [AnyHashable : Any](); let imageManager = PHCachingImageManager()
                  imageManager.requestImage(for: self, targetSize: targetSize, contentMode: contentMode, options: options, resultHandler: { image,info in
                      img = image!
                      information = info!
                  })
                  return (img,information)
              }
          }
          
          let data = asset?.data(targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions?)
          

          将此方法用于您想要的数据。

          【讨论】:

          • 这需要得到更高的支持。很好的解决方案。
          【解决方案9】:

          斯威夫特 5

          extension PHAsset {
          func getAssetThumbnail() -> UIImage {
              let manager = PHImageManager.default()
              let option = PHImageRequestOptions()
              var thumbnail = UIImage()
              option.isSynchronous = true
              manager.requestImage(for: self,
                                   targetSize: CGSize(width: self.pixelWidth, height: self.pixelHeight),
                                   contentMode: .aspectFit,
                                   options: option,
                                   resultHandler: {(result, info) -> Void in
                                      thumbnail = result!
                                   })
              return thumbnail
              }
          }
          

          【讨论】:

            【解决方案10】:

            Swift 5 工作函数

            func getImageForAsset(asset: PHAsset) -> UIImage {
                    let manager = PHImageManager.default
                    let option = PHImageRequestOptions()
                    var thumbnail = UIImage()
                    option.isSynchronous = true
                    manager().requestImage(for: asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .aspectFit, options: nil, resultHandler: {(result, info) -> Void in
                            thumbnail = result!
                    })
                    return thumbnail
                }
            

            【讨论】:

              猜你喜欢
              • 2016-08-30
              • 2021-12-04
              • 2020-04-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-02-15
              相关资源
              最近更新 更多