访问 UIImage 属性而不在内存中加载图像

Posted

技术标签:

【中文标题】访问 UIImage 属性而不在内存中加载图像【英文标题】:accessing UIImage properties without loading in memory the image 【发布时间】:2010-11-12 22:33:42 【问题描述】:

如您所知,iphone 指南不鼓励加载大于 1024x1024 的 uiimage。

我必须加载的图像大小各不相同,我想检查我要加载的图像的大小;但是使用 uiimage 的 .size 属性需要加载图像...这正是我想要避免的。

我的推理有问题还是有解决办法?

谢谢大家

【问题讨论】:

这是个好问题。 android 提供了一种方法来做到这一点,但我不知道有什么 ios 解决方案。编辑:这已经被问过了。 ***.com/questions/1551300/… 我之前搜索过,但我找不到!非常感谢! 【参考方案1】:

从 iOS 4.0 开始,iOS SDK 包括 CGImageSource... functions(在 ImageIO 框架中)。这是一个非常灵活的 API,可以在不将图像加载到内存的情况下查询元数据。获取图像的像素尺寸应该像这样(确保在您的目标中包含 ImageIO.framework):

#import <ImageIO/ImageIO.h>

NSURL *imageFileURL = [NSURL fileURLWithPath:...];
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)imageFileURL, NULL);
if (imageSource == NULL) 
    // Error loading image
    ...
    return;


CGFloat width = 0.0f, height = 0.0f;
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);

CFRelease(imageSource);

if (imageProperties != NULL) 

    CFNumberRef widthNum  = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
    if (widthNum != NULL) 
        CFNumberGetValue(widthNum, kCFNumberCGFloatType, &width);
    

    CFNumberRef heightNum = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
    if (heightNum != NULL) 
        CFNumberGetValue(heightNum, kCFNumberCGFloatType, &height);
    

    // Check orientation and flip size if required
    CFNumberRef orientationNum = CFDictionaryGetValue(imageProperties, kCGImagePropertyOrientation);
    if (orientationNum != NULL) 
        int orientation;
        CFNumberGetValue(orientationNum, kCFNumberIntType, &orientation);
        if (orientation > 4) 
            CGFloat temp = width;
            width = height;
            height = temp;
        
    

    CFRelease(imageProperties);


NSLog(@"Image dimensions: %.0f x %.0f px", width, height);

(改编自 Gelphman 和 Laden 的“使用 Quartz 编程”,清单 9.5,第 228 页)

【讨论】:

为什么使用CGImageSourceCopyPropertiesAtIndex 而不仅仅是CGImageSourceCopyProperties 在调用 CFNumberGetValue() 时传递 kCFNumberCGFloatType 而不是 kCFNumberFloatType 非常重要,因为变量 widthheight 被声明为 CGFloat。上面的代码可以在 32 位系统上运行,但值在 64 位系统上会包含垃圾。 @fjoachim:谢谢,已修复。 @OleBegemann 还应该考虑图像方向 (kCGImagePropertyOrientation) - 方向 5 到 8 的翻转宽度和高度。您可以使用 these images 进行测试。 是支持远程镜像还是只支持本地镜像?【参考方案2】:

Swift 3 版本的答案:

import Foundation
import ImageIO

func sizeForImage(at url: URL) -> CGSize? 

    guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
        , let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [AnyHashable: Any]
        , let pixelWidth = imageProperties[kCGImagePropertyPixelWidth as String]
        , let pixelHeight = imageProperties[kCGImagePropertyPixelHeight as String]
        , let orientationNumber = imageProperties[kCGImagePropertyOrientation as String]
        else 
            return nil
    

    var width: CGFloat = 0, height: CGFloat = 0, orientation: Int = 0

    CFNumberGetValue(pixelWidth as! CFNumber, .cgFloatType, &width)
    CFNumberGetValue(pixelHeight as! CFNumber, .cgFloatType, &height)
    CFNumberGetValue(orientationNumber as! CFNumber, .intType, &orientation)

    // Check orientation and flip size if required
    if orientation > 4  let temp = width; width = height; height = temp 

    return CGSize(width: width, height: height)

【讨论】:

小细节:我发现某些图像的 imageProperties[kCGImagePropertyOrientation as String] 可能为零。【参考方案3】:

Swift 5 中,ImageIO

extension URL
    var sizeOfImage: CGSize?
        guard let imageSource = CGImageSourceCreateWithURL(self as CFURL, nil)
            , let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [AnyHashable: Any]
            , let pixelWidth = imageProperties[kCGImagePropertyPixelWidth as String] as! CFNumber?
            , let pixelHeight = imageProperties[kCGImagePropertyPixelHeight as String] as! CFNumber?
            else 
                return nil
        
        var width: CGFloat = 0, height: CGFloat = 0
        CFNumberGetValue(pixelWidth, .cgFloatType, &width)
        CFNumberGetValue(pixelHeight, .cgFloatType, &height)
       
       return CGSize(width: width, height: height)
    


imageProperties[kCGImagePropertyOrientation as String] 可能为零。

是nil,我用png图片文件测试过

作为Apple says

kCGImagePropertyOrientation

此键的数值根据 TIFF 和 Exif 规范对图像的预期显示方向进行编码。

【讨论】:

以上是关于访问 UIImage 属性而不在内存中加载图像的主要内容,如果未能解决你的问题,请参考以下文章

UIImage 未在视图中加载确实在 iOS 中加载

获取文件路径而不在内存中加载文件?

从主线程的资产目录中加载图像?

UIImage 实现/分页?

QDeclarativeImageProvider 不在容器中加载图像

滑行,线圈不在模拟器中加载图像