三、CGImageDestination详解
CGImageSource是图片文件数据的抽象对象,而CGImageDestination的作用则是将抽象的图片数据写入指定的目标中。将图片写成文件示例如下:
//创建存储路径
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *newPath = [paths.firstObject stringByAppendingPathComponent:[NSString stringWithFormat:@"image.png"]];
CFURLRef URL = CFURLCreateWithFileSystemPath (
kCFAllocatorDefault,
(CFStringRef)newPath,
kCFURLPOSIXPathStyle,
false);
//创建CGImageDestination对象
CGImageDestinationRef myImageDest = CGImageDestinationCreateWithURL(URL,CFSTR("public.png"), 1, NULL);
UIImage * image = [UIImage imageNamed:@"timg.jpeg"];
//写入图片
CGImageDestinationAddImage(myImageDest, image.CGImage, NULL);
CGImageDestinationFinalize(myImageDest);
CFRelease(myImageDest);
同样,除了可以直接将图片数据写入url外,也可以Data数据或数据消费器,方法如下:
//将图片数据写入数据消费者
CGImageDestinationRef __nullable CGImageDestinationCreateWithDataConsumer(CGDataConsumerRef __nonnull consumer, CFStringRef __nonnull type, size_t count, CFDictionaryRef __nullable options);
//将图片数据写入Data
CGImageDestinationRef __nullable CGImageDestinationCreateWithData(CFMutableDataRef __nonnull data, CFStringRef __nonnull type, size_t count, CFDictionaryRef __nullable options);
需要注意,上面方法的type参数设置写入数据的文件格式,必须为ImageIO框架所支持的格式,前面有方法可以获取所有支持的格式,还有一点,这3个写入方法的中options参数目前并没有什么作用,其是留给未来使用的,目前传入NULL即可。
CGImageDestination类中的其他方法解析如下:
//获取CGImageDestination的CFTypeID
CFTypeID CGImageDestinationGetTypeID(void);
//获取CGImageDestination所支持的图片文件类型
/*
目前支持如下:iOS10.1
(
"public.jpeg",
"public.png",
"com.compuserve.gif",
"public.tiff",
"public.jpeg-2000",
"com.microsoft.ico",
"com.microsoft.bmp",
"com.adobe.photoshop-image",
"com.adobe.pdf",
"com.truevision.tga-image",
"com.ilm.openexr-image",
"public.pbm",
"public.pvr",
"org.khronos.astc",
"org.khronos.ktx",
"com.microsoft.dds",
"com.apple.rjpeg"
)
*/
CFArrayRef __nonnull CGImageDestinationCopyTypeIdentifiers(void);
//设置图片文件属性
/*
可以设置的键值对意义如下:
const CFStringRef kCGImageDestinationLossyCompressionQuality; //设置压缩质量 0-1之间的cfnumberref值
const CFStringRef kCGImageDestinationBackgroundColor; //将图片数据写为无alpha通道时的默认背景色 cgcolor值
*/
void CGImageDestinationSetProperties(CGImageDestinationRef __nonnull idst, CFDictionaryRef __nullable properties);
//向CGImageDestination中添加一张图片 其中的option参数意义和上面一致,设置此图片的质量与无alpha默认背景色
void CGImageDestinationAddImage(CGImageDestinationRef __nonnull idst, CGImageRef __nonnull image, CFDictionaryRef __nullable properties);
//通过CGImageSource对象来向CGImageDestination中添加图片
void CGImageDestinationAddImageFromSource(CGImageDestinationRef __nonnull idst, CGImageSourceRef __nonnull isrc, size_t index, CFDictionaryRef __nullable properties);
//进行写入操作 执行此方法后 不可以在写入其他信息
bool CGImageDestinationFinalize(CGImageDestinationRef __nonnull idst);
//添加图片元信息
void CGImageDestinationAddImageAndMetadata(CGImageDestinationRef __nonnull idst, CGImageRef __nonnull image, CGImageMetadataRef __nullable metadata, CFDictionaryRef __nullable options);
//将CGImageSource信息拷贝进CGImageDestination
/*
options参数可以用来添加元信息
*/
bool CGImageDestinationCopyImageSource(CGImageDestinationRef __nonnull idst, CGImageSourceRef __nonnull isrc, CFDictionaryRef __nullable options, __nullable CFErrorRef * __nullable err);
上面列举的方法中,CGImageDestinationCopyImageSource()方法中的options参数可以添加一些图片的元信息,可以设置的键值对意义如下:
//设置元信息 需要设置为CGImageMetadataRef对象
const CFStringRef kCGImageDestinationMetadata;
//是否将CGImageSource的元信息信息合并操作 默认为kCFBooleanFalse
const CFStringRef kCGImageDestinationMergeMetadata;
//XMP数据是否不被写入 默认为kCFBooleanFalse
const CFStringRef kCGImageMetadataShouldExcludeXMP;
//GPS信息是否不被写入 默认为kCFBooleanFalse
const CFStringRef kCGImageMetadataShouldExcludeGPS;
//更新元数据的时间值 需要设置为CFStringRef或者CFDateRef
const CFStringRef kCGImageDestinationDateTime;
//更新元数据的方向值 需要设置为NSNumber1-8
const CFStringRef kCGImageDestinationOrientation;
四、关于CGImageMetadata
前面我们很多次提到元数据,CGImageMetadata类就是元数据的抽象,其中封装了一些方法供开发者读取或写入元数据信息。奇怪的是Apple的官方文档与API文档中并没有CGImageMetadata的介绍与解释,博客中本部分的内容,多出自我的理解,有疏漏和不对的地方,清楚的朋友可以指点与建议。
前边介绍,CGImageSource中有获取图片元数据的方法,CGImageDestination中也有写入图片元数据的方法,元数据中抽象出的CGImageMetadataTag是对具体数据内容的封装。CGImageMetadata解析如下:
//获取CGImageMetadata类的CFTypeID
CFTypeID CGImageMetadataGetTypeID(void);
//创建一个空的可变的CGImageMetadata对象
CGMutableImageMetadataRef __nonnull CGImageMetadataCreateMutable(void);
//拷贝一个可变的CGImageMetadata对象
CGMutableImageMetadataRef __nullable CGImageMetadataCreateMutableCopy(CGImageMetadataRef __nonnull metadata);
//获取CGImageMetadataTag类的CFTypeID
CFTypeID CGImageMetadataTagGetTypeID(void);
//创建一个CGImageMetadataTag对象
/*
这个方法比较复杂
xmlns参数设置命名空间
prefix参数设置命名空间的缩写或前缀
name参数设置CGImageMetadataTag的名称
type参数设置CGImageMetadataTag对应值的类型
value参数设置CGImageMetadataTag的对应值
*/
CGImageMetadataTagRef __nullable CGImageMetadataTagCreate (CFStringRef __nonnull xmlns, CFStringRef __nullable prefix, CFStringRef __nonnull name, CGImageMetadataType type, CFTypeRef __nonnull value);
上面创建CGImageMetadataTag的方法中,xmlns设置命名空间,必须使用一个预定义的命名空间或者自定义的命名空间,对于自定义的命名空间,必须遵守Adobe的XMP规范。一些共用的命名空间定义如下:
//Exif命名空间
const CFStringRef kCGImageMetadataNamespaceExif;
//ExifAux命名空间
const CFStringRef kCGImageMetadataNamespaceExifAux;
//ExifEX命名空间
const CFStringRef kCGImageMetadataNamespaceExifEX;
//DublineCore命名空间
const CFStringRef kCGImageMetadataNamespaceDublinCore;
//IPTCCore命名空间
const CFStringRef kCGImageMetadataNamespaceIPTCCore;
//Photoshop命名空间
const CFStringRef kCGImageMetadataNamespacePhotoshop;
//TIFF命名空间
const CFStringRef kCGImageMetadataNamespaceTIFF;
//XMPBasic命名空间
const CFStringRef kCGImageMetadataNamespaceXMPBasic;
//XMPRights命名空间
const CFStringRef kCGImageMetadataNamespaceXMPRights;
上面创建CGImageMetadataTag的方法中prefix设置命名空间缩写或前缀,同样一些公用的前缀定义如下:
//Exif命名空间前缀
const CFStringRef kCGImageMetadataPrefixExif;
//ExifAux命名空间前缀
const CFStringRef kCGImageMetadataPrefixExifAux;
//ExifEX命名空间前缀
const CFStringRef kCGImageMetadataPrefixExifEX;
//DublinCore命名空间前缀
const CFStringRef kCGImageMetadataPrefixDublinCore;
//IPCCore命名空间前缀
const CFStringRef kCGImageMetadataPrefixIPTCCore;
//Photoshop命名空间前缀
const CFStringRef kCGImageMetadataPrefixPhotoshop;
//TIFF命名空间前缀
const CFStringRef kCGImageMetadataPrefixTIFF;
//XMPBasic命名空间前缀
const CFStringRef kCGImageMetadataPrefixXMPBasic;
//XMPRights命名空间前缀
const CFStringRef kCGImageMetadataPrefixXMPRights;
上面创建CGImageMetadataTag的方法中type设置对应值的类型,其是一个CGImageMetadataType类型的枚举,意义如下:
typedef CF_ENUM(int32_t, CGImageMetadataType) {
//无效的数据类型
kCGImageMetadataTypeInvalid = -1,
//基本的CFType类型
kCGImageMetadataTypeDefault = 0,
//字符串类型
kCGImageMetadataTypeString = 1,
//无需集合类型
kCGImageMetadataTypeArrayUnordered = 2,
//有序集合类型
kCGImageMetadataTypeArrayOrdered = 3,
//有序阵列
kCGImageMetadataTypeAlternateArray = 4,
//特殊的数组 其中元素进行不同的本地化
kCGImageMetadataTypeAlternateText = 5,
//结构类型 如字典
kCGImageMetadataTypeStructure = 6
};
获取到CGImageMetadataTag后,可以通过如下方法来获取其中封装的信息:
//获取标签的命名空间
CFStringRef __nullable CGImageMetadataTagCopyNamespace(CGImageMetadataTagRef __nonnull tag);
//获取标签的命名空间前缀
CFStringRef __nullable CGImageMetadataTagCopyPrefix(CGImageMetadataTagRef __nonnull tag);
//获取标签名称
CFStringRef __nullable CGImageMetadataTagCopyName(CGImageMetadataTagRef __nonnull tag);
//获取标签的值
CFTypeRef __nullable CGImageMetadataTagCopyValue(CGImageMetadataTagRef __nonnull tag);
//获取标签值的类型
CGImageMetadataType CGImageMetadataTagGetType(CGImageMetadataTagRef __nonnull tag);
//获取标签的Qualifier数组
CFArrayRef __nullable CGImageMetadataTagCopyQualifiers(CGImageMetadataTagRef __nonnull tag);
下面这些方法用于向CGImageMetadata中添加标签或者获取标签:
//获取CGImageMetadata中的所有标签
CFArrayRef __nullable CGImageMetadataCopyTags(CGImageMetadataRef __nonnull metadata);
//通过路径查找特殊的标签
CGImageMetadataTagRef __nullable CGImageMetadataCopyTagWithPath(CGImageMetadataRef __nonnull metadata, CGImageMetadataTagRef __nullable parent, CFStringRef __nonnull path);
//通过路径查找特殊标签的值
CFStringRef __nullable CGImageMetadataCopyStringValueWithPath(CGImageMetadataRef __nonnull metadata, CGImageMetadataTagRef __nullable parent, CFStringRef __nonnull path);
//为一个前缀注册一个命名空间
bool CGImageMetadataRegisterNamespaceForPrefix(CGMutableImageMetadataRef __nonnull metadata, CFStringRef __nonnull xmlns, CFStringRef __nonnull prefix, __nullable CFErrorRef * __nullable err);
//通过路径为CGImageMetadata设置标签
bool CGImageMetadataSetTagWithPath(CGMutableImageMetadataRef __nonnull metadata, CGImageMetadataTagRef __nullable parent, CFStringRef __nonnull path, CGImageMetadataTagRef __nonnull tag);
//通过路径为CGImageMetadata设置标签的值
bool CGImageMetadataSetValueWithPath(CGMutableImageMetadataRef __nonnull metadata, CGImageMetadataTagRef __nullable parent, CFStringRef __nonnull path, CFTypeRef __nonnull value);
//通过路径移除一个标签
bool CGImageMetadataRemoveTagWithPath(CGMutableImageMetadataRef __nonnull metadata, CGImageMetadataTagRef __nullable parent, CFStringRef __nonnull path);
//对标签进行枚举
void CGImageMetadataEnumerateTagsUsingBlock(CGImageMetadataRef __nonnull metadata, CFStringRef __nullable rootPath, CFDictionaryRef __nullable options, CGImageMetadataTagBlock __nonnull block);