【问题标题】:How to get only images in the camera roll using Photos Framework如何使用照片框架仅获取相机胶卷中的图像
【发布时间】:2014-11-02 01:27:21
【问题描述】:

以下代码加载也位于 iCloud 上的图像或流图像。我们如何将搜索限制为仅在相机胶卷中的图像?

var assets = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: nil)

【问题讨论】:

  • 您是否对 SO 上的其他一些问题/答案感到满意?
  • 没有。关于看什么有什么建议吗?甚至苹果文档也参差不齐
  • 我只是started here 并检查了几个问题。我自己都没试过。

标签: ios swift photosframework


【解决方案1】:

通过一些实验,我们发现了文档中未列出的隐藏属性 (assetSource)。基本上你必须做一个常规的获取请求,然后使用谓词从相机胶卷中过滤掉那些。这个值应该是 3。

示例代码:

//fetch all assets, then sub fetch only the range we need
var assets = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions)

assets.enumerateObjectsUsingBlock { (obj, idx, bool) -> Void in
    results.addObject(obj)
}

var cameraRollAssets = results.filteredArrayUsingPredicate(NSPredicate(format: "assetSource == %@", argumentArray: [3]))
results = NSMutableArray(array: cameraRollAssets)

【讨论】:

  • 这似乎是目前最稳定的解决方案。我能想到的唯一其他“解决方案”是调用 PHAsset.requestContentEditingInputWithOptions 并检查为每个返回的 PHContentEditingInput 对象以获得 URL,然后过滤掉所有不包含“/DCIM/”的 URL。但与此相比,这是极其缓慢和脆弱的。
  • 这似乎已“修复”,如果您尝试在 GM 中引用 assetSource,现在会引发异常。
  • @RizwanSattar API 已被隐藏,但该属性在当前 8.0.2 版本中仍然可用,问题现在是它的私有 API 并且未记录 - 不值得信任。
  • 对于使用 obj-c 的任何人,assets 将是一个 PHFetchResult 对象,obj 是一个类型为 PHAsset 的对象
【解决方案2】:

如果您不想依赖未记录的 API,请查看 [asset canPerformEditOperation:PHAssetEditOperationContent]。仅当设备上有完整的原件时,才会返回 true。

诚然,这也很脆弱,但测试表明它适用于所有资产来源类型(照片流、iTunes 同步等)。

【讨论】:

  • 在使用 iCloud 照片库时对我不起作用。无论图像是否实际在设备上,它都会返回 true。
【解决方案3】:

添加相机胶卷和照片流相册后,Apple 在 iOS 8.1 中添加了以下PHAssetCollectionSubtype 类型:

  1. PHAssetCollectionSubtypeAlbumMyPhotoStream(连同PHAssetCollectionTypeAlbum) - 获取照片流相册。

  2. PHAssetCollectionSubtypeSmartAlbumUserLibrary(连同PHAssetCollectionTypeSmartAlbum) - 获取相机胶卷相册。

尚未测试这是否与 iOS 8.0.x 向后兼容。

【讨论】:

  • 嗯.. PHAssetCollectionSubtypeSmartAlbumUserLibrary 在我的 iPad 上列出了 14,850 个项目。这是整个照片集,而不是我 iPad 上的...
  • 如果您启用了 iCloud 照片库,它将列出设备上的所有资产以及可通过 iCloud 照片库获得的资产。 AFAIK 没有(记录在案的)方法可以知道哪些资产本地存储在设备上,哪些资产可以通过云获得但尚未同步。
  • 确实可行,但我认为您不会想要迭代所有资产并请求它们以确定它们是否在设备本地。
  • 我在使用 iCloud 照片库时得到了相同的结果。它返回“所有照片”集合中的所有图像,无论它们是否实际在设备上。可以使用 requestContentEditingInputWithOptions 或 requestImageDataForAsset 检查图像是否在设备上,但这是异步的,并且对列表中的每个资产都执行此操作似乎很疯狂。为什么他们没有办法在 fetchAssetsInAssetCollection 中仅指定本地资产?
  • 我不知道有一个公开的 API 揭示了这一点 - 他们似乎试图保持它对客户端透明。如果您愿意使用undocumented APIs,那么如果没有下载资产,很多属性可能是nil
【解决方案4】:

如果您像我一样搜索 Objective C 代码,并且您在使用已弃用的 AssetsLibrary 代码时没有得到新库/照片框架的答案,那么这将对您有所帮助: 斯威夫特

全局变量:

  func getAllPhotosFromCameraRoll() -> [UIImage] {
    // TODO: Add `NSPhotoLibraryUsageDescription` to info.plist
    PHPhotoLibrary.requestAuthorization { print($0) } // TODO: Move this line of code to somewhere before attempting to access photos

    var images = [UIImage]()

    let requestOptions: PHImageRequestOptions = PHImageRequestOptions()
    requestOptions.resizeMode = .exact
    requestOptions.deliveryMode = .highQualityFormat
    requestOptions.isSynchronous = true

    let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: .image, options: nil)
    let manager: PHImageManager = PHImageManager.default()

    for i in 0..<fetchResult.count {
      let asset = fetchResult.object(at: i)
      manager.requestImage(
        for: asset,
        targetSize: PHImageManagerMaximumSize,
        contentMode: .default,
        options: requestOptions,
        resultHandler: { (image: UIImage?, info: [AnyHashable: Any]?) -> Void in
          if let image = image {
            images.append(image)
          }
        })
    }

    return images
  }

目标 C

全局变量:

NSArray *imageArray;
NSMutableArray *mutableArray;

下面的方法会帮助你:

-(void)getAllPhotosFromCamera
{
    imageArray=[[NSArray alloc] init];
    mutableArray =[[NSMutableArray alloc]init];

    PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init];
    requestOptions.resizeMode   = PHImageRequestOptionsResizeModeExact;
    requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
    requestOptions.synchronous = true;
    PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];

    NSLog(@"%d",(int)result.count);

    PHImageManager *manager = [PHImageManager defaultManager];
    NSMutableArray *images = [NSMutableArray arrayWithCapacity:[result count]];

    // assets contains PHAsset objects.

    __block UIImage *ima;
    for (PHAsset *asset in result) {
        // Do something with the asset

        [manager requestImageForAsset:asset
                           targetSize:PHImageManagerMaximumSize
                          contentMode:PHImageContentModeDefault
                              options:requestOptions
                        resultHandler:^void(UIImage *image, NSDictionary *info) {
                            ima = image;

                            [images addObject:ima];
                        }];


    }

    imageArray = [images copy];  // You can direct use NSMutuable Array images
}

【讨论】:

    【解决方案5】:

    如果您使用自己的PHCachingImageManager 而不是共享的PHImageManager 实例,那么当您调用requestImageForAsset:targetSize:contentMode:options:resultHandler: 时,您可以在PHImageRequestOptions 中设置一个选项来指定图像是本地的。

    networkAccessAllowed 属性

    一个布尔值,指定照片是否可以从 iCloud 下载请求的图像。

    networkAccessAllowed

    讨论

    如果是,并且请求的图像未存储在本地设备上,照片将从 iCloud 下载图像。要获得下载进度通知,请使用 progressHandler 属性提供一个块,供照片在下载图像时定期调用。如果为 NO(默认值),并且图像不在本地设备上,则结果处理程序的信息字典中的 PHImageResultIsInCloudKey 值指示图像不可用,除非您启用网络访问。

    【讨论】:

      【解决方案6】:

      这里是苹果提供的Objective-c版本。

      -(NSMutableArray *)getNumberOfPhotoFromCameraRoll:(NSArray *)array{
          PHFetchResult *fetchResult = array[1];
          int index = 0;
          unsigned long pictures = 0;
          for(int i = 0; i < fetchResult.count; i++){
              unsigned long temp = 0;
              temp = [PHAsset fetchAssetsInAssetCollection:fetchResult[i] options:nil].count;
              if(temp > pictures ){
                  pictures = temp;
                  index = i;
              }
          }
          PHCollection *collection = fetchResult[index];
      
             if (![collection isKindOfClass:[PHAssetCollection class]]) {
              // return;
          }
          // Configure the AAPLAssetGridViewController with the asset collection.
          PHAssetCollection *assetCollection = (PHAssetCollection *)collection;
          PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
          self. assetsFetchResults = assetsFetchResult;
          self. assetCollection = assetCollection;
          self.numberOfPhotoArray = [NSMutableArray array];
          for (int i = 0; i<[assetsFetchResult count]; i++) {
              PHAsset *asset = assetsFetchResult[i];
              [self.numberOfPhotoArray addObject:asset];
          }
          NSLog(@"%lu",(unsigned long)[self.numberOfPhotoArray count]);
          return self.numberOfPhotoArray;
      }
      

      您可以在哪里获取以下详细信息

      PHFetchResult *fetchResult = self.sectionFetchResults[1];
              PHCollection *collection = fetchResult[6];
      **value 1,6 used to get camera images**
      **value 1,0 used to get screen shots**
      **value 1,1 used to get hidden**
      **value 1,2 used to get selfies** 
      **value 1,3 used to get recently added**
      **value 1,4 used to get videos**
      **value 1,5 used to get recently deleted**
       **value 1,7 used to get favorites**
      

      苹果演示link

      声明您的财产

      @property (nonatomic, strong) NSArray *sectionFetchResults;
      @property (nonatomic, strong) PHFetchResult *assetsFetchResults;
      @property (nonatomic, strong) PHAssetCollection *assetCollection;
      @property (nonatomic, strong) NSMutableArray *numberOfPhotoArray;
      

      【讨论】:

      • 它可以帮助objective c开发者。谁知道objective-c开发者从来没有进入这个链接?
      • 演示并没有像您那样按索引明确引用每个集合(例如,相机图像为 6);如果他们改变退货的顺序怎么办?
      • 看来更新后的答案只是返回了拥有最多资产的集合的计数。如果收藏的内容不仅仅是相机胶卷怎么办?
      【解决方案7】:

      我也一直在努力解决这个问题。我发现无法使用 fetchAssetsWithMediaType 或 fetchAssetsInAssetCollection 仅过滤设备上的资产。我可以使用 requestContentEditingInputWithOptions 或 requestImageDataForAsset 来确定资产是否在设备上,但这是异步的,似乎它为列表中的每个资产使用了太多资源。一定有更好的办法。

      PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
      
      for (int i=0; i<[fetchResult count]; i++) {
      
          PHAsset *asset = fetchResult[i];
      
          [asset requestContentEditingInputWithOptions:nil
                                     completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
                                         if ([[info objectForKey:PHContentEditingInputResultIsInCloudKey] intValue] == 1) {
                                             NSLog(@"asset is in cloud");
                                         } else {
                                             NSLog(@"asset is on device");
                                         }
                                     }];
      
      }
      

      【讨论】:

        【解决方案8】:

        这会有所帮助。您可以使用自己的数据模型代替我使用的 AlbumModel。

        func getCameraRoll() -> AlbumModel {
                  var cameraRollAlbum : AlbumModel!
        
                  let cameraRoll = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil)
        
                  cameraRoll.enumerateObjects({ (object: AnyObject!, count: Int, stop: UnsafeMutablePointer) in
                    if object is PHAssetCollection {
                      let obj:PHAssetCollection = object as! PHAssetCollection
        
                      let fetchOptions = PHFetchOptions()
                      fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
                      fetchOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue)
                      let assets = PHAsset.fetchAssets(in: obj, options: fetchOptions)
        
                      if assets.count > 0 {
                        let newAlbum = AlbumModel(name: obj.localizedTitle!, count: assets.count, collection:obj, assets: assets)
        
                        cameraRollAlbum = newAlbum
                      }
                    }
                  })
                 return cameraRollAlbum
        
                }
        

        【讨论】:

        • 这应该是答案,我之前遍历所有专辑并按字符串过滤,但它只适用于英文
        猜你喜欢
        • 2011-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多