天天看点

iOS中ImageIO框架详解与应用分析(二)

三、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);