任务是在复制图像时以四种可能的格式(jpg,png,psd,tif)将关键字插入元数据。为游乐场设置了示例,以处理存储在桌面上“ Metadata Test”文件夹中的图像“ foo.jpg”等。所有图像均可正确复制,但在Adobe Bridge中查看时,除PSD外,所有关键词均会出现。有谁知道为什么PSD缺少关键字?
import Cocoa
import ImageIO
import PlaygroundSupport
func copyFileAppendKeywords(at: URL, to: URL, keywords: [String]) -> Bool {
// Create source reference.
guard let sourceRef = CGImageSourceCreateWithURL(at as CFURL, nil) else { return false }
// Get source file type.
guard let uti: CFString = CGImageSourceGetType(sourceRef) else { return false }
// Create destination reference.
guard let destinationRef = CGImageDestinationCreateWithURL(to as CFURL, uti, 1, nil) else { return false }
// Get source metadata.
var metadata: Dictionary<String, AnyObject>
if let v = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, nil) {
metadata = v as! Dictionary
} else { return false }
print("\n======== \(at.lastPathComponent) original metadata ========\n", metadata, separator:"\n")
var iptc: Dictionary<String, AnyObject>
if let v = metadata["{IPTC}"] {
// Image has IPTC data.
iptc = v as! Dictionary
} else {
// Image doesn't have IPTC data; create it.
iptc = Dictionary<String, AnyObject>()
iptc["Keywords"] = [] as AnyObject
}
// Create empty keyword array and fill it keywords provided.
var iptcKeywords: [String] = []
if let v = iptc["Keywords"] {
// Image has existing keywords; append to them.
// To instead replace all keywords, disable this block.
iptcKeywords = v as! [String]
}
// Add each keyword.
keywords.forEach {
iptcKeywords.append($0)
}
// Add keywords array to IPTC dictionary.
iptc["Keywords"] = iptcKeywords as AnyObject
// Write (or overwrite) IPTC dictionary to metadata
metadata["{IPTC}"] = iptc as AnyObject
print("\n======== \(to.lastPathComponent) modified metadata ========\n", metadata, separator:"\n")
// Copy image plus metadata
CGImageDestinationAddImageFromSource(destinationRef, sourceRef, 0, metadata as CFDictionary)
// Save destination
guard CGImageDestinationFinalize(destinationRef) else { return false }
return true
// NOTE: no keywords appear in resulting PSD.
}
let folder = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Desktop").appendingPathComponent("Metadata Test")
var at: URL
var to: URL
let keywords: [String] = ["one", "two", "three"]
at = documents.appendingPathComponent("foo.jpg")
to = documents.appendingPathComponent("bar.jpg")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)
at = documents.appendingPathComponent("foo.png")
to = documents.appendingPathComponent("bar.png")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)
at = documents.appendingPathComponent("foo.psd")
to = documents.appendingPathComponent("bar.psd")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)
at = documents.appendingPathComponent("foo.tif")
to = documents.appendingPathComponent("bar.tif")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)
编辑:我尝试了使用CGImageDestinationCopyImageSource(卷积冒险)而不是CGImageDestinationAddImageFromSource的另一种方法,以查看它是否有所作为,并且因为(我认为)AddImageFromSource将重新压缩JPEG(我不确定)会更可取。 ,但以防万一。不幸的是,这种差异并不能解决问题。实际上,结果更糟-现在PNG也没有关键字。但是这种其他方法一文不值。两者都适用于JPEG。
import Cocoa
import ImageIO
import PlaygroundSupport
func copyFileAppendKeywords(at: URL, to: URL, keywords: [String]) -> Bool {
// Create source reference.
guard let sourceRef = CGImageSourceCreateWithURL(at as CFURL, nil) else { return false }
CGImageSourceGetCount(sourceRef)
// Get source file type.
guard let uti: CFString = CGImageSourceGetType(sourceRef) else { return false }
// Create destination reference.
guard let destinationRef = CGImageDestinationCreateWithURL(to as CFURL, uti, 1, nil) else { return false }
// Get source metadata.
var metadata: CGMutableImageMetadata
if let v = CGImageSourceCopyMetadataAtIndex(sourceRef, 0, nil) {
metadata = CGImageMetadataCreateMutableCopy(v)!
} else { return false }
print("\n======== \(at.lastPathComponent) original metadata ========\n", metadata, separator:"\n")
// Create empty keyword array and fill it keywords provided.
var iptcKeywords: [String] = []
// Add each keyword.
keywords.forEach {
iptcKeywords.append($0)
}
// Update dc:subject with new keywords.
CGImageMetadataSetValueWithPath(metadata, nil, "dc:subject" as CFString, iptcKeywords as CFTypeRef)
print("\n======== \(to.lastPathComponent) modified metadata ========\n", metadata, separator:"\n")
// Copy file with new metadata.
let destMetadata: [String: AnyObject] = [
kCGImageDestinationMetadata as String: metadata as CGImageMetadata
]
var errorRef: Unmanaged<CFError>?
if !CGImageDestinationCopyImageSource(destinationRef, sourceRef, destMetadata as CFDictionary, &errorRef) {
print (errorRef.debugDescription)
}
// NOTE: documentation claims...
// "the CGImageDestinationCopyImageSource API supports the following image formats: JPEG, PNG, PSD, TIFF."
// Does not appear true. Only formats affected are JPEG and TIFF. Keywords do not appear in PNG or PSD.
return true
}
let folder = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Desktop").appendingPathComponent("Metadata Test")
var at: URL
var to: URL
let keywords: [String] = ["one", "two", "three"]
at = folder.appendingPathComponent("foo.jpg")
to = folder.appendingPathComponent("bar.jpg")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)
at = folder.appendingPathComponent("foo.png")
to = folder.appendingPathComponent("bar.png")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)
at = folder.appendingPathComponent("foo.psd")
to = folder.appendingPathComponent("bar.psd")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)
at = folder.appendingPathComponent("foo.tif")
to = folder.appendingPathComponent("bar.tif")
copyFileAppendKeywords(at: at, to: to, keywords: keywords)