Swift: 如何删除用AVFoundation拍摄的照片中的EXIF数据?
Swift: How to Delete EXIF data from picture taken with AVFoundation?
我正在尝试从使用 AVFoundation 拍摄的照片中删除 EXIF 数据,如何在 swift (2) preferred, Objective-C 也可以,我知道怎么把代码转成swift。
为什么?
我做了我的研究,我看到很多著名的 Social Media(Reddit 源等)确实出于身份目的和其他目的删除了 EXIF 数据。
如果您认为这是重复的 post,请阅读我的问题并提供 link。谢谢。
我的回答很大程度上基于 this previous question。我修改了代码以在 Swift 2.0.
上工作
class ImageHelper {
static func removeExifData(data: NSData) -> NSData? {
guard let source = CGImageSourceCreateWithData(data, nil) else {
return nil
}
guard let type = CGImageSourceGetType(source) else {
return nil
}
let count = CGImageSourceGetCount(source)
let mutableData = NSMutableData(data: data)
guard let destination = CGImageDestinationCreateWithData(mutableData, type, count, nil) else {
return nil
}
// Check the keys for what you need to remove
// As per documentation, if you need a key removed, assign it kCFNull
let removeExifProperties: CFDictionary = [String(kCGImagePropertyExifDictionary) : kCFNull, String(kCGImagePropertyOrientation): kCFNull]
for i in 0..<count {
CGImageDestinationAddImageFromSource(destination, source, i, removeExifProperties)
}
guard CGImageDestinationFinalize(destination) else {
return nil
}
return mutableData;
}
}
然后你可以简单地做这样的事情:
let imageData = ImageHelper.removeExifData(UIImagePNGRepresentation(image))
在我的示例中,我删除了旋转和 EXIF 数据。如果您需要删除任何其他内容,您可以轻松搜索密钥。只需对生成的数据进行额外检查,因为它是可选的。
你有 UIImage 吧?
然后你可以将 UIImage 转换为数据并再次将其保存到图像新图像将没有任何 EXIF 数据
Swift 3
let imageData:Data = UIImagePNGRepresentation(image!)!
func saveToPhotoLibrary_iOS9(data:NSData, completionHandler: @escaping (PHAsset?)->()) {
var assetIdentifier: String?
PHPhotoLibrary.requestAuthorization { (status:PHAuthorizationStatus) in
if(status == PHAuthorizationStatus.authorized){
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.forAsset()
let placeholder = creationRequest.placeholderForCreatedAsset
creationRequest.addResource(with: PHAssetResourceType.photo, data: data as Data, options: nil)
assetIdentifier = placeholder?.localIdentifier
}, completionHandler: { (success, error) in
if let error = error {
print("There was an error saving to the photo library: \(error)")
}
var asset: PHAsset? = nil
if let assetIdentifier = assetIdentifier{
asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier], options: nil).firstObject//fetchAssetsWithLocalIdentifiers([assetIdentifier], options: nil).firstObject as? PHAsset
}
completionHandler(asset)
})
}else {
print("Need authorisation to write to the photo library")
completionHandler(nil)
}
}
}
Swift 5 个版本的接受答案:
extension Data {
func byRemovingEXIF() -> Data? {
guard let source = CGImageSourceCreateWithData(self as NSData, nil),
let type = CGImageSourceGetType(source) else
{
return nil
}
let count = CGImageSourceGetCount(source)
let mutableData = NSMutableData()
guard let destination = CGImageDestinationCreateWithData(mutableData, type, count, nil) else {
return nil
}
let exifToRemove: CFDictionary = [
kCGImagePropertyExifDictionary: kCFNull,
kCGImagePropertyGPSDictionary: kCFNull,
] as CFDictionary
for index in 0 ..< count {
CGImageDestinationAddImageFromSource(destination, source, index, exifToRemove)
if !CGImageDestinationFinalize(destination) {
print("Failed to finalize")
}
}
return mutableData as Data
}
}
这是一个从原始数据中删除 exif 的解决方案。 jpeg 中的 Exif 在 APP1 框架内。帧开始用 FF_E1 表示。帧结束于下一个不跟在 00 值之后的 FF 字节。
var data: Data = ... // read jpeg one way or another
var app1_start = 0
var app1_end = Int.max
for i in 0 ..< data.count {
if data[i] == 0xFF {
if data[i + 1] == 0xE1 {
print("found start \(i)")
app1_start = i
} else if app1_start > 0, data [i] != 0x00 {
app1_end = i - 1
print("found end \(i-1)")
break
}
}
}
data.removeSubrange(Range(app1_start...app1_end))
假设此示例中的数据为 jpeg。代码循环遍历字节数组并存储 APP1 的开始和结束。然后从原始可变数据中删除数据。更多关于 jpeg 结构的信息 https://en.wikipedia.org/wiki/JPEG
我正在尝试从使用 AVFoundation 拍摄的照片中删除 EXIF 数据,如何在 swift (2) preferred, Objective-C 也可以,我知道怎么把代码转成swift。
为什么? 我做了我的研究,我看到很多著名的 Social Media(Reddit 源等)确实出于身份目的和其他目的删除了 EXIF 数据。
如果您认为这是重复的 post,请阅读我的问题并提供 link。谢谢。
我的回答很大程度上基于 this previous question。我修改了代码以在 Swift 2.0.
上工作class ImageHelper {
static func removeExifData(data: NSData) -> NSData? {
guard let source = CGImageSourceCreateWithData(data, nil) else {
return nil
}
guard let type = CGImageSourceGetType(source) else {
return nil
}
let count = CGImageSourceGetCount(source)
let mutableData = NSMutableData(data: data)
guard let destination = CGImageDestinationCreateWithData(mutableData, type, count, nil) else {
return nil
}
// Check the keys for what you need to remove
// As per documentation, if you need a key removed, assign it kCFNull
let removeExifProperties: CFDictionary = [String(kCGImagePropertyExifDictionary) : kCFNull, String(kCGImagePropertyOrientation): kCFNull]
for i in 0..<count {
CGImageDestinationAddImageFromSource(destination, source, i, removeExifProperties)
}
guard CGImageDestinationFinalize(destination) else {
return nil
}
return mutableData;
}
}
然后你可以简单地做这样的事情:
let imageData = ImageHelper.removeExifData(UIImagePNGRepresentation(image))
在我的示例中,我删除了旋转和 EXIF 数据。如果您需要删除任何其他内容,您可以轻松搜索密钥。只需对生成的数据进行额外检查,因为它是可选的。
你有 UIImage 吧? 然后你可以将 UIImage 转换为数据并再次将其保存到图像新图像将没有任何 EXIF 数据
Swift 3
let imageData:Data = UIImagePNGRepresentation(image!)!
func saveToPhotoLibrary_iOS9(data:NSData, completionHandler: @escaping (PHAsset?)->()) {
var assetIdentifier: String?
PHPhotoLibrary.requestAuthorization { (status:PHAuthorizationStatus) in
if(status == PHAuthorizationStatus.authorized){
PHPhotoLibrary.shared().performChanges({
let creationRequest = PHAssetCreationRequest.forAsset()
let placeholder = creationRequest.placeholderForCreatedAsset
creationRequest.addResource(with: PHAssetResourceType.photo, data: data as Data, options: nil)
assetIdentifier = placeholder?.localIdentifier
}, completionHandler: { (success, error) in
if let error = error {
print("There was an error saving to the photo library: \(error)")
}
var asset: PHAsset? = nil
if let assetIdentifier = assetIdentifier{
asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier], options: nil).firstObject//fetchAssetsWithLocalIdentifiers([assetIdentifier], options: nil).firstObject as? PHAsset
}
completionHandler(asset)
})
}else {
print("Need authorisation to write to the photo library")
completionHandler(nil)
}
}
}
Swift 5 个版本的接受答案:
extension Data {
func byRemovingEXIF() -> Data? {
guard let source = CGImageSourceCreateWithData(self as NSData, nil),
let type = CGImageSourceGetType(source) else
{
return nil
}
let count = CGImageSourceGetCount(source)
let mutableData = NSMutableData()
guard let destination = CGImageDestinationCreateWithData(mutableData, type, count, nil) else {
return nil
}
let exifToRemove: CFDictionary = [
kCGImagePropertyExifDictionary: kCFNull,
kCGImagePropertyGPSDictionary: kCFNull,
] as CFDictionary
for index in 0 ..< count {
CGImageDestinationAddImageFromSource(destination, source, index, exifToRemove)
if !CGImageDestinationFinalize(destination) {
print("Failed to finalize")
}
}
return mutableData as Data
}
}
这是一个从原始数据中删除 exif 的解决方案。 jpeg 中的 Exif 在 APP1 框架内。帧开始用 FF_E1 表示。帧结束于下一个不跟在 00 值之后的 FF 字节。
var data: Data = ... // read jpeg one way or another
var app1_start = 0
var app1_end = Int.max
for i in 0 ..< data.count {
if data[i] == 0xFF {
if data[i + 1] == 0xE1 {
print("found start \(i)")
app1_start = i
} else if app1_start > 0, data [i] != 0x00 {
app1_end = i - 1
print("found end \(i-1)")
break
}
}
}
data.removeSubrange(Range(app1_start...app1_end))
假设此示例中的数据为 jpeg。代码循环遍历字节数组并存储 APP1 的开始和结束。然后从原始可变数据中删除数据。更多关于 jpeg 结构的信息 https://en.wikipedia.org/wiki/JPEG