用户正在拍照时,我目前正在抓拍照片:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
// create a jpeg
NSData *jpegData = UIImageJPEGRepresentation(image, 1.0f);
// write jpeg image to file in app space
NSString *filePath =
// create file path in app space
[imageData writeToFile:filePath atomically:NO];
}
这很好用,该文件使用其EXIF数据创建了一个jpeg。
现在,我想将图像缩小一些以使其更小。但是,我想保留原始UIImage中存在的部分或全部EXIF数据,然后将其复制到缩放的图像中。
当前缩放图像:
UIImage *scaledImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext*_Nonnull myContext) {
[image drawInRect:(CGRect) {.origin = CGPointZero, .size = size}];
}];
这可以很好地创建缩放图像,但是其中不包含任何EXIF数据。
是否可以缩放图像并保留原始图像的EXIF数据?我可以从原始图像中获取EXIF数据并将其复制到缩放后的图像吗?
我还使用ALAssetsLibrary
搜索了很多答案,现在已弃用了这些答案。似乎替代方法是PhotoKit
。哪个状态:
在iOS和macOS中,PhotoKit提供了支持构建的类 “照片”应用的照片编辑扩展程序。在iOS和tvOS中,PhotoKit 还可以直接访问由管理的照片和视频资产 照片应用程序。
但是我不使用“照片”应用程序,但是我的图像不是来自本地照片库或icloud,因为我只想将照片存储在我的私人应用程序空间中。
答案 0 :(得分:0)
请参见This Article。
下面是我的实现
```
import ImageIO
public struct ImageMetadataNamespace {
/// The schema namespace URI(eg. http://ns.adobe.com/exif/1.0/)
public var scheme: CFString
/// The preferred schema namespace prefix(eg. exif)
public var prefix: CFString
public init(scheme: CFString, prefix: CFString) {
self.scheme = scheme
self.prefix = prefix
}
}
public extension ImageMetadataNamespace {
/// Dublin Core(URI="http://purl.org/dc/elements/1.1/" Prefix="dc").
public static let dc = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceDublinCore, prefix: kCGImageMetadataPrefixDublinCore)
/// Exchangeable Image File format, Exif 2.2 or earlier(URI="http://ns.adobe.com/exif/1.0/" Prefix="exif").
public static let exif = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceExif, prefix: kCGImageMetadataPrefixExif)
/// EXIF Auxiliary(URI="http://ns.adobe.com/exif/1.0/aux/" Prefix="aux").
public static let exifAux = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceExifAux, prefix: kCGImageMetadataPrefixExifAux)
/// Exif 2.21 or later(URI="http://cipa.jp/exif/1.0/" Prefix="exifEX").
public static let exifEX = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceExifEX, prefix: kCGImageMetadataPrefixExifEX)
/// International Press Telecommunications Council, IPTC Core(URI="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" Prefix="Iptc4xmpCore").
public static let iptc = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceIPTCCore, prefix: kCGImageMetadataPrefixIPTCCore)
/// IPTC Extension(URI="http://iptc.org/std/Iptc4xmpExt/2008-02-29/" Prefix="Iptc4xmpExt").
@available(iOS 11.3, *)
public static let iptcExtension = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceIPTCExtension, prefix: kCGImageMetadataPrefixIPTCExtension)
/// Photoshop(URI="http://ns.adobe.com/photoshop/1.0/" Prefix="photoshop").
public static let photoshop = ImageMetadataNamespace(scheme: kCGImageMetadataNamespacePhotoshop, prefix: kCGImageMetadataPrefixPhotoshop)
/// Tagged Image File Format, TIFF Rev. 6.0(URI="http://ns.adobe.com/tiff/1.0/" Prefix="tiff").
public static let tiff = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceTIFF, prefix: kCGImageMetadataPrefixTIFF)
/// Extensible Metadata Platform Basic(URI="http://ns.adobe.com/xap/1.0/" Prefix="xmp").
public static let xmpBasic = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceXMPBasic, prefix: kCGImageMetadataPrefixXMPBasic)
/// Extensible Metadata Platform Rights(URI="http://ns.adobe.com/xap/1.0/rights/" Prefix="xmpRights").
public static let xmpRights = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceXMPRights, prefix: kCGImageMetadataPrefixXMPRights)
}
/// About detail tutorial for ImageIO, you can refer below website:
/// http://www.qingpingshan.com/rjbc/ios/214889.html
public final class ImageMetadataVistor {
public enum SaveError: Error {
case unsupportedImageFormat
case destinationFileNotFound
case writeMetadataToFileFailed
}
private var mutableMetadata: CGMutableImageMetadata
private var imageSource: CGImageSource
public init(imageSource: CGImageSource) {
self.imageSource = imageSource
if let originalMetadata = CGImageSourceCopyMetadataAtIndex(imageSource, 0, nil) {
mutableMetadata = CGImageMetadataCreateMutableCopy(originalMetadata)!
} else {
mutableMetadata = CGImageMetadataCreateMutable()
}
}
public convenience init(image: UIImage) {
let imageData = image.jpegData(compressionQuality: 1.0)!
let source = CGImageSourceCreateWithData(imageData as CFData, nil)
self.init(imageSource: source!)
}
/// If image file not exist, or image is invalid, creating ImageMetadataVistor will fail.
public convenience init?(imageFileURL: URL) {
guard let source = CGImageSourceCreateWithURL(imageFileURL as CFURL, nil) else {
return nil
}
self.init(imageSource: source)
}
/// If imageData is invalid, creating ImageMetadataVistor will fail.
public convenience init?(imageData: Data) {
guard let source = CGImageSourceCreateWithData(imageData as CFData, nil) else {
return nil
}
self.init(imageSource: source)
}
/// Set metadata for image using property dictionary.
///
/// - Parameters:
/// - propertyName: The name of a metadata property.
/// - value: The value of a metadata property.
/// - propertyDictionary: The property dictionary which the given property name belongs to.
/// - Returns: The result of setting metadata.
func setMetadata(forProperty propertyName: CFString, value: CFTypeRef, propertyDictionary: ImagePropertyDictionary) -> Bool {
return CGImageMetadataSetValueMatchingImageProperty(mutableMetadata, propertyDictionary.name, propertyName, value)
}
/// Set metadata for image using metata tag.
///
/// - Parameters:
/// - propertyName: The name of a metadata property.
/// - value: The value of a metadata property.
/// - valueType: The data type of value.
/// - namespace: The namespace info which the given property name belongs to.
/// - Returns: The result of setting metadata.
func setMetadata(forProperty propertyName: CFString, value: CFTypeRef, valueType: CGImageMetadataType, namespace: ImageMetadataNamespace) -> Bool {
guard let tag = CGImageMetadataTagCreate(namespace.scheme, namespace.prefix, propertyName, valueType, value) else {
return false
}
let propertyPath = getPropertyPath(prefix: namespace.prefix, propertyName: propertyName)
return CGImageMetadataSetValueWithPath(mutableMetadata, nil, propertyPath, tag)
}
func getProperties() -> ImageProperties? {
if let rawValue = CGImageSourceCopyProperties(imageSource, nil) as? [CFString: Any] {
return ImageProperties(rawValue: rawValue)
}
return nil
}
/// Save image and metadata to the specified image file url.
func saveImageAndMetadata(toFile fileURL: URL) throws {
guard let type = CGImageSourceGetType(imageSource) else {
throw SaveError.unsupportedImageFormat
}
guard let destination = CGImageDestinationCreateWithURL(fileURL as CFURL, type, 1, nil) else {
throw SaveError.destinationFileNotFound
}
let cgImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil)
CGImageDestinationAddImageAndMetadata(destination, cgImage!, mutableMetadata, nil)
guard CGImageDestinationFinalize(destination) else {
throw SaveError.writeMetadataToFileFailed
}
}
}
fileprivate extension ImageMetadataVistor {
func getPropertyPath(prefix: CFString, propertyName: CFString) -> CFString {
return "\(prefix):\(propertyName)" as CFString
}
}
```
答案 1 :(得分:0)
使用UIImagePickerController进行摄像头捕获的元数据到达UIImagePickerControllerMediaMetadata键下的info
字典。可以使用ImageIO框架将其复制到另一个UIImage的数据中(您将需要import ImageIO
)。我的代码是Swift,但是它使用了Objective-C可可类和ImageIO C函数,因此您应该可以轻松地将其转换为Objective-C:
let jpeg = im!.jpegData(compressionQuality:1) // im is the new UIImage
let src = CGImageSourceCreateWithData(jpeg as CFData, nil)!
let data = NSMutableData()
let uti = CGImageSourceGetType(src)!
let dest = CGImageDestinationCreateWithData(data as CFMutableData, uti, 1, nil)!
CGImageDestinationAddImageFromSource(dest, src, 0, m) // m is the metadata
CGImageDestinationFinalize(dest)
此后,data
是图像im
的数据以及捕获中的元数据m
。