准确地说,图像的属性是指所有构成图片的数据元素。从编程的角度来讲,属性与图片的文件头对文件信息的约束是一样的。对于一个图形文件,文件的属性根据图片的不同格式而具有不同的属性值。对于BMP文件,它的属性值有宽度、高度、色彩浓度及编码方式等;对于JPEG文件,它的属性有压缩使用的方式、压缩的质量、压缩的数据区数据等;而对于所有的图形文件,都具备有文件的作者、文件创建时间等属性。属性实际上是对图片的一个完整详细的描述。
接下来介绍GDI+处理属性的方式。
GDI+使用214种属性名来表示不同格式的图片可能具有的各种属性。具体内容请参见MSDN的“Image Property TagConstants(属性标记常量)”相关内容。这里列出几个简单、常用的属性名,如表1-1所示。
|
|
PropertyTagExifVer | EXIF文件版本号 |
PropertyTagFrameDelay | GIF图片的子图片之间的时间延迟 |
PropertyTagLoopCount | GIF文件的循环播放次数 |
PropertyTagJPEGQuality | JPEG丈件的质量 |
PropertyTagCopyright | 版权信息 |
PropertyTagDateTime | 文件创建时间 |
PropertyTagGamma | 文件的Gamma较正 |
PropertyTagArtist | 文件的作者 |
表1-1中列出的属性名实际上对应着一个常量,所以,属性名也称为属性标记(PropertyTag)。图形文件的属性标记究竟有什么用处?可以做一个这样的比喻,如果把整个图形文件看成是一个注册表,那么,属性标记(PropertyID)就是主键,属性项(PropertyItem)就是键值。属性标记为GDI+查询图形文件提供查询条件,而属性项保存具体的查询结果。
在使用属性标记之前,应该明白这样一个概念:属性标记不具有通用性,比如,程序 开发人员不可能在BMP文件中查找ProperyTagJPEGQuality标记。换句话说,在进行属性 标记、属性项的查找时,首先应在程序中查找可供查询的属性标记列表。
在GDI+中查询图形文件属性标记,可以通过Image类的下列成员函数来完成。
·GetPropertyCount:获取图形文件中存储的属性总数。
·GetPropertyIdList:获取属性列表。
·GetProperCyItem;获取属性项。
·GetPropertyItemSize:获取属性项大小。
·GetPropertySize:获取属性大小。
以上5个函数的使用并不复杂,这里略去函数的调用方法。这5个函数在使用中也是有规律可循的:先获取属性标记(项)的数目(大小),然后据此分配内存空间。例程1-2演示了这5个函数的所有使用方法,即如何获取图形文件的属性列表。
void CEncodersDecodersView::OnQueryImage() { Graphics graphics(this->m_hWnd); this->RedrawWindow(); SolidBrush brush(Color(255, 0, 0, 255)); FontFamily fontFamily(L"宋体"); Font myFont(&fontFamily, 16, FontStyleRegular, UnitPixel); UINT count = O; Image image(L"father.jpg"); ∥图片中共有多少属性名可供查询 count= image.GetPropertyCount(); if(count==0) { AfxMessageBox("无属性名可供查询"); return; } ∥为属性项分配空间 PROPID* propIDs = new PROPID[count]; ∥获取属性标识列表 image.GetPropertyIdList(count, propIDs); CString tmp,msg; for(UINTj=O;j < count; ++j) { tmp.Format("第%d个可供查找的属性名的标记值为:%x\n",j,propIDs[j]); msg+=tmp; } msg.AppendChar('\n\n'); ∥查找每一个属性标记对应的属性项信息 UINT size=O; PropertyItem* propertyItem = NULL; for(int i=O;i < count;i++) { size= image.GetPropertyItemSize(propIDs[i]); tmp.Format("第%d个属性名对应的属性项需要%d个字节来描述\n",i,size); msg+=tmp; ∥为属性项分配空间 propertyItem= (PropertyItem*)malloc(size); tmp.Format("第%d个属性名对应的属性项的信息为:\n",i); msg+=tmp; ∥获取属性项详细描述信息 image.GetPropertyItem(propIDs[i], size, propertyItem); tmp.Format("\t属性项的长度为%u\n\t数据类型为%d\n”, propertyItem->length,propertyItem->type); msg+=tmp; } ∥输出属性名信息 CStringW msgW((LPCSTR)msg); graphics.DrawString (msgW, -l,&myFont, PointF(O,O),NULL,&SolidBrush(Color::Black)); delete[] propIDs; }
例程1-2头两行的输出信息为:
第O个可供查找的属性名的标记值为:5090
第1个可供查找的属性名的标记值为:5091
在查询MSDN的“Image Property Tag Constants”之后,5090和5091这两个十六进制值分别对应属性名PropertyTagLuminanceTable(属性标记高亮度)和PropertyTagChrominanceTable(属性标记色度表),即JPEG的亮度表和色度表属性。也就是说,这两项属性标记是可供程序查询的。因此,例程1-2获取了属性标记之后,继续对这两个标记的属性项进行详细查询。GetPropertyItem函数将属性项的信息保存在一个PropertyItem对象中。
PropertyItem是GDI+中的一个类,它的类成员很简单,只有id(属性标记值)、length(属性项长度)、type(类型)、value(属性项值)4个部分。一般来说,PropertyItem类前3个数据成员是可以随意访问的,但是最后一个value是指向一个void类型的指针,在明白这个值所具体表示的值之前,不要去访问这个指针值。
与GetPropertyItem函数相对应的是,GDI+也提供了对图片的属性信息进行修改的函数SetPropertyItem,该函数的调用格式为:
Status SetPropertyItem( const PropertyItem* item );
参数item表示指向PropertyItem对象的一个指针。
例程1-3演示了将一幅图片的作者更改为“ZhouMingYang”的过程。
void CEncodersDecodersView::OnSetProp() { ∥载入图片以供修改 Image image(L"beetle.jpg"); ∥设置图片的作者为ZhouZY PropertyItem* propItem= new PropedyItem; CHAR newWriterValue[]= "ZhouMingYang"; ∥初始化属性项对象PropertyItem propItem->id = PropertyTagArtist; propItem->length= strlen(newWriterValue); ∥数据类型 propItem->type= PropertyTagTypeASCⅡ; //数据值 propItem->value= newWriterValue; ∥设置图形属性 if(image.SetPropertyItem(propItem)!=Ok) { AfxMessageBox(”属性修政失败!"); return; } ∥获取JPEG文件的解码器信息 CLSID encoderClsid; GetEncoderClsid(L"image/jpeg", &encoderClsid); ∥按照修改后的图形属性保存文件 image.Save(L"newwriter.jpg",&encoderClsid); ∥重新加载修改后的图片 Image image2(L"newwriter.jpg"); ∥查看图片的作者信息 UINT size= image2.GetPropertyItemSize(PropertyTagArtist); PropertyItem* title= (PropertyItem*)malloc(size); image2.GetPropertyItem(PropertyTagArtist, size, title); char* writer=(char*)title->value; CString msg; msg.Format("图片的作者已经更改为\n%s",writer); AfxMessageBox(msg); }
在使用SetPropertyItem函数时,一定要注意其返回值,它表明了对属性的修改是否成功。图1-4所示为使用UltraEdit程序查看例程1-3中新生成的图片“newwriter.jpg”的效果。从图中可以看出,文件的作者已经修改成功了。