iOS Photokit - PHAsset pixelWidth 和 pixelHeight 与高分辨率图像不匹配

Posted

技术标签:

【中文标题】iOS Photokit - PHAsset pixelWidth 和 pixelHeight 与高分辨率图像不匹配【英文标题】:iOS Photokit - PHAsset pixelWidth and pixelHeight does not match high-resolution image 【发布时间】:2017-04-24 13:30:33 【问题描述】:

我的公司在通过获取 PHAsset 获取正确大小的元数据方面遇到了很大问题。 我们开发了一个 ios 应用程序,允许客户从库中选择图片,获取每个图片的大小(以像素为单位),计算坐标以调整我们销售的小工具,然后将高质量的图片版本上传到我们的服务器以打印小工具。 对于我们的一些客户,问题在于发送的一些高质量版本图片的像素大小与 PHAsset 对象给出的 pixelWidth 和 pixelHeight 不匹配。 举个例子,我们有一张图片:

PHAsset 对象报告为 2096x3724 但是,当请求全尺寸图片时,会生成一张 1536x2730 的图片

图片不在 iCloud 中,由运行 iOS 10.2 的 iPhone 6 SE 发送。 这是获取全尺寸图像版本的代码:

PHImageRequestOptions *imgOpts = [[PHImageRequestOptions alloc] init];
imgOpts.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
imgOpts.networkAccessAllowed = YES;
imgOpts.resizeMode = PHImageRequestOptionsResizeModeExact;
imgOpts.version = PHImageRequestOptionsVersionCurrent;  

PHCachingImageManager *imageManager = [[PHCachingImageManager alloc] init];

[imageManager requestImageForAsset:imageAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:imgOpts resultHandler:^(UIImage *  result, NSDictionary *  info) 
    NSData * imageData = UIImageJPEGRepresentation(result, 0.92f);
    //UPLOAD OF imageData TO SERVER HERE
]

也尝试了 requestImageDataForAsset 方法,但没有运气:

PHImageRequestOptions *imgOpts = [[PHImageRequestOptions alloc] init];
imgOpts.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
imgOpts.networkAccessAllowed = YES;
imgOpts.resizeMode = PHImageRequestOptionsResizeModeExact;
imgOpts.version = PHImageRequestOptionsVersionCurrent;  

PHCachingImageManager *imageManager = [[PHCachingImageManager alloc] init];

[imageManager requestImageDataForAsset:imageAsset options:imgOpts resultHandler:^(NSData * imageData, NSString * dataUTI, UIImageOrientation orientation, NSDictionary *  info) 
    //UPLOAD OF imageData TO SERVER HERE
]

在上传之前从每张图片的高分辨率版本中获取精确尺寸对我们来说不是一个选项,因为从库中选择大量资产时会大大降低性能。

我们是错过了还是做错了什么? 有没有办法在不将全分辨率图像加载到内存的情况下以像素为单位获取资产大小? 感谢您的帮助

【问题讨论】:

这方面有什么更新吗?我有完全相同的问题。 其实没有更新。经过多次测试,我们最终向我们的服务器发送了“假设大小”(PHAsset pixelWidth 和 pixelSize),上传后打开图片再次检查实际大小,然后根据实际大小调整坐标 苹果开发者论坛也没有人回答 我最终做了类似的事情,而不是像你的情况那样在后端做,我必须在应用程序端做,即在上传图片之前,获取最大尺寸,并检查图片尺寸 &上传前根据需要进行调整。 【参考方案1】:

这是由于 Photos 框架中的错误造成的。可以在here 找到有关该错误的详细信息。

有时,在编辑照片后,会创建一个较小的版本。这只发生在一些较大的照片上。

调用requestImageForAsset:PHImageManagerMaximumSize)或requestImageDataForAsset:PHImageRequestOptionsDeliveryModeHighQualityFormat)将在尝试检索编辑后的版本(PHImageRequestOptionsVersionCurrent)时从较小的文件版本中读取数据。

上述方法回调中的info会指向图片的路径。例如:PHImageFileURLKey = "file:///[...]DCIM/100APPLE/IMG_0006/Adjustments/IMG_0006.JPG"; 检查那个文件夹,我找到了另一张图片,FullSizeRender.jpg - 这个有完整的大小并且包含最新的编辑。因此,当存在这样的文件时,一种方法是尝试从FullSizeRender.jpg 中读取。


从 iOS 9 开始,还可以使用 PHAssetResourceManager 以最高分辨率获取最新编辑:
// if (@available(iOS 9.0, *)) 
// check if a high quality edit is available
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:_asset];
PHAssetResource *hqResource = nil;
for (PHAssetResource *res in resources) 
    if (res.type == PHAssetResourceTypeFullSizePhoto) 
        // from my tests so far, this is only present for edited photos
        hqResource = res;
        break;
    


if (hqResource) 
    PHAssetResourceRequestOptions *options = [[PHAssetResourceRequestOptions alloc] init];
    options.networkAccessAllowed = YES;
    long long fileSize = [[hqResource valueForKey:@"fileSize"] longLongValue];
    NSMutableData *fullData = [[NSMutableData alloc] initWithCapacity:fileSize];

    [[PHAssetResourceManager defaultManager] requestDataForAssetResource:hqResource options:options dataReceivedHandler:^(NSData * _Nonnull data) 
        // append the data that we're receiving
        [fullData appendData:data];
     completionHandler:^(NSError * _Nullable error) 
        // handle completion, using `fullData` or `error`
        // uti == hqResource.uniformTypeIdentifier
        // orientation == UIImageOrientationUp
    ];

else 
    // use `requestImageDataForAsset:`, `requestImageForAsset:` or `requestDataForAssetResource:` with a different `PHAssetResource`

【讨论】:

【参考方案2】:

你能试试这个来获取相机胶卷照片吗:

__weak __typeof(self) weakSelf = self;
PHFetchResult<PHAssetCollection *> *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumSelfPortraits options:nil];
[albums enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull album, NSUInteger idx, BOOL * _Nonnull stop) 
    PHFetchOptions *options = [[PHFetchOptions alloc] init];
    options.wantsIncrementalChangeDetails = YES;
    options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeImage];
    options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
    PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:album options:options];
    if(assets.count>0)
    
        [assets enumerateObjectsUsingBlock:^(PHAsset * _Nonnull asset, NSUInteger idx, BOOL * _Nonnull stop) 
            if(asset!=nil)
            
                [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage *result, NSDictionary *info)
                 
                     dispatch_async(dispatch_get_main_queue(), ^
                         [weakSelf addlocalNotificationForFilters:result];
                         // [weakSelf.buttonGalery setImage:result forState:UIControlStateNormal];
                     );
                 ];
                *stop = YES;
            
            else
                [weakSelf getlatestAferSelfie];
            
        ];
    

【讨论】:

使用 PHImageManagerMaximumSize 作为 targetSize 调用 requestImageForAsset 意味着获取全分辨率图像原始数据,这是我们希望避免的,因为我们的客户甚至可以同时选择 200 张图片,这可能意味着等待很长时间是时候让处理完成了。我们想要一种无需实际打开高分辨率图片版本即可获取真实尺寸元数据的方法

以上是关于iOS Photokit - PHAsset pixelWidth 和 pixelHeight 与高分辨率图像不匹配的主要内容,如果未能解决你的问题,请参考以下文章

iOS PhotoKit框架 详解

iOS PhotoKit 教程

iOS PhotoKit 教程

在 PhotoKit 中,修改 PHAsset 会留下原始的。如何?可覆盖?

如何解决 PhotoKit 错误“原始资源选择仅对未调整的基础版本有效”?

使用 UIActivityViewController 共享存储在相机胶卷中的 PHAsset