在阅读有关gif编解码相关的内容时,有见到使用ImageIO相关的内容
参考Accessing Image Properties Without Loading the Image Into Memory提到其一些应用
比如说你想获取图片的一些属性,比如图片的尺寸和一些其他的元数据,但是这张图片你并不需要再屏幕上显示。最简单的方式就是使用UIImage
:
UIImage *image = [UIImage imageWithContentsOfFile:...];
CGSize imageSize = image.size;
...
这样做所带来的问题是整张图片都会被加载到内存中。由于在内存中是未压缩的,所以一个512 × 512
的图片就有1M
此时就可以使用ImageIO.framework
如下的例子,获取一张网络上的图片,输出图片的大小:
NSString *urlStr = @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524748621307&di=46209fd530717b3c1621468c5e22e063&imgtype=0&src=http%3A%2F%2Fa.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F0ff41bd5ad6eddc4c984b29335dbb6fd52663372.jpg";
NSURL *imageFileURL = [NSURL URLWithString:urlStr];
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)imageFileURL, NULL);
if (imageSource == NULL) {
// Error loading image
return;
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], (NSString *)kCGImageSourceShouldCache,
nil];
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (CFDictionaryRef)options);
if (imageProperties) {
NSNumber *width = (NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
NSNumber *height = (NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
NSLog(@"Image dimensions: %@ x %@ px", width, height);
CFRelease(imageProperties);
}
CFRelease(imageSource);
输出结果为:
Image dimensions: 1280 x 1920 px
CGImageSourceCopyPropertiesAtIndex()
返回的字典包含许多信息
如下可以获取拍摄的日期、相机的模式和GPS信息等:
CFDictionaryRef exif = CFDictionaryGetValue(imageProperties, kCGImagePropertyExifDictionary);
if (exif) {
NSString *dateTakenString = (NSString *)CFDictionaryGetValue(exif, kCGImagePropertyExifDateTimeOriginal);
NSLog(@"Date Taken: %@", dateTakenString);
}
CFDictionaryRef tiff = CFDictionaryGetValue(imageProperties, kCGImagePropertyTIFFDictionary);
if (tiff) {
NSString *cameraModel = (NSString *)CFDictionaryGetValue(tiff, kCGImagePropertyTIFFModel);
NSLog(@"Camera Model: %@", cameraModel);
}
CFDictionaryRef gps = CFDictionaryGetValue(imageProperties, kCGImagePropertyGPSDictionary);
if (gps) {
NSString *latitudeString = (NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLatitude);
NSString *latitudeRef = (NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLatitudeRef);
NSString *longitudeString = (NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLongitude);
NSString *longitudeRef = (NSString *)CFDictionaryGetValue(gps, kCGImagePropertyGPSLongitudeRef);
NSLog(@"GPS Coordinates: %@ %@ / %@ %@", longitudeString, longitudeRef, latitudeString, latitudeRef);
}
在Programming iOS 10 Dive Deep into Views View Controllers and Frameworks
一书中,就有这样的使用形式:
let url = Bundle.main.url(forResource:"colson", withExtension: "jpg")!
let src = CGImageSourceCreateWithURL(url as CFURL, nil)!
let result = CGImageSourceCopyPropertiesAtIndex(src, 0, nil)!
let d = result as! [AnyHashable:Any] // :) works because CFString is now AnyHashable
print(d)
// just proving it really is a dictionary
let width = d[kCGImagePropertyPixelWidth] as! CGFloat
let height = d[kCGImagePropertyPixelHeight] as! CGFloat
print("\(width) by \(height)")
// another way; no one in his right mind would do this, though
do {
let result = CGImageSourceCopyPropertiesAtIndex(src, 0, nil)!
let key = kCGImagePropertyPixelWidth // CFString
let p1 = Unmanaged.passUnretained(key).toOpaque() // UnsafeMutableRawPointer
let p2 = CFDictionaryGetValue(result, p1) // UnsafeRawPointer
let n = Unmanaged.fromOpaque(p2!).takeUnretainedValue() // CFNumber
var width : CGFloat = 0
CFNumberGetValue(n, .cgFloatType, &width) // width is now 640.0
print(width)
}
缩略图
如果你在显示某个图片的时候,不关心原始的图片数据,缩率图thumbnail
正是你所需要的
使用CGImageSourceCreateThumbnailAtIndex
时传递一个字典。需要注意的是我们使用的CGImage
是实际的像素,所以要考虑到设备的scale
let url = Bundle.main.url(forResource:"colson", withExtension: "jpg")!
let src = CGImageSourceCreateWithURL(url as CFURL, nil)!
let scale = UIScreen.main.scale
let w = self.iv.bounds.width * scale
let d : [AnyHashable:Any] = [
kCGImageSourceShouldAllowFloat : true,
kCGImageSourceCreateThumbnailWithTransform : true,
kCGImageSourceCreateThumbnailFromImageAlways : true,
kCGImageSourceThumbnailMaxPixelSize : w
]
let imref = CGImageSourceCreateThumbnailAtIndex(src, 0, d as CFDictionary)!
let im = UIImage(cgImage: imref, scale: scale, orientation: .up)
self.iv.image = im
print(im)
print(im.size)
保存图片为特定的格式
需要使用到image destination,如下的例子,保存为TIFF
let url = Bundle.main.url(forResource:"colson", withExtension: "jpg")!
let src = CGImageSourceCreateWithURL(url as CFURL, nil)!
let fm = FileManager.default
let suppurl = try! fm.url(for:.applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let tiff = suppurl.appendingPathComponent("mytiff.tiff")
let dest = CGImageDestinationCreateWithURL(tiff as CFURL, kUTTypeTIFF, 1, nil)!
CGImageDestinationAddImageFromSource(dest, src, 0, nil)
let ok = CGImageDestinationFinalize(dest)
if ok {
print("tiff image written to disk")
} else {
print("something went wrong")
}