ImageIO
在阅读有关gif编解码相关的内容时,有见到使用ImageIO相关的内容
- iOS中ImageIO框架详解与应用分析
- Image I/O Programming Guide
参考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) {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] print(d)let width = d[kCGImagePropertyPixelWidth] as! CGFloatlet height = d[kCGImagePropertyPixelHeight] as! CGFloatprint("\(width) by \(height)")do {let result = CGImageSourceCopyPropertiesAtIndex(src, 0, nil)!let key = kCGImagePropertyPixelWidth let p1 = Unmanaged.passUnretained(key).toOpaque() let p2 = CFDictionaryGetValue(result, p1) let n = Unmanaged.fromOpaque(p2!).takeUnretainedValue() var width : CGFloat = 0CFNumberGetValue(n, .cgFloatType, &width) 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.scalelet w = self.iv.bounds.width * scalelet 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 = imprint(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.defaultlet 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")}