65.9K
CodeProject 正在变化。 阅读更多。
Home

EXIFextractor 库用于提取 EXIF 信息

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (37投票s)

2005 年 8 月 13 日

4分钟阅读

viewsIcon

493308

downloadIcon

19338

EXIFextractor 库用于提取 EXIF 信息。

引言

好的,问题在于,您有一张图片,您要么想在其中设置某个 EXIF 标签,要么想读取其中嵌入的某个 EXIF 标签。解决方案……嗯,MS 在 .NET 中已经实现了一部分,但那只是标签号及其关联的原始数据。显然,这对于用户只想读取图片注释的情况毫无帮助。首先,您必须知道标签号,然后使用 .NET 提取该标签并进行转换。首先,这听起来并不坏(如果您只关心 ASCII 字符串,它确实不算糟,但如果您想提取 ISO 速度,它实际上是合理数格式,或者需要转换的其他数据类型,您就会同意,这不仅糟糕,有时甚至愚蠢。如果您像我一样,您会先挠头,想他们为什么要把数据嵌入成这样来戏弄我们?他们本可以很容易地用其他更简单的格式实现,但猜猜怎么着?它已经完成了,而您就是那个要进行所有解码的幸运儿。您在前面的几行读到的都是我的情绪,当时我着手为这个网站制作一个 EXIF 控件。

我将继续在我的网站上更新这个控件,所以如果您在 2006 年看到这篇文章(并且人类没有开始第三次世界大战),您很有可能在那里找到最新版本。

背景

基础的匹配知识,以及基础的 C# 知识和对 Bitmap 类的了解。哦,对了,还有一个大脑(但它是可选的)。

使用代码

EXIFextractor 是一个非常轻量级的类,您可以将其作为引用传递给您的 Bitmap,然后该类将使用它。除非您调用 setTag 函数来更改特定标签,否则位图不会被修改。一旦您添加/修改了标签,您就需要负责存储/保存位图。

下面是一个示例代码,展示了如何将所有标签转储到控制台。

System.Drawing.Bitmap bmp = 
             new System.Drawing.Bitmap("F:\\DSCI0006.JPG");

// create a new instance of Extractor 
// class. Here "\n" is the newline 
// that is used to seprate output of two tags. 
// You can replace it with "," if you want
Goheer.EXIF.EXIFextractor er = 
             new Goheer.EXIF.EXIFextractor(ref bmp,"\n");

// now dump all the tags on console
Console.Write(er); 

// to set a tag you have to specify the tag id
// code 0x13B is for artist name
// since this number has ascii string with 
// it pass the string you want to set
er.setTag(0x13B,"http://www.goheer.com");

// dispose the image here or do whatever you want.
//

如果您想获取单独的项目,例如艺术家姓名。请记住,对于系统中不存在的 EXIF 属性,这可能会返回 null,因此在进行任何操作之前检查 null 值是正确的做法。

Console.Write(er["Equip Make"]);

您也可以使用枚举器,如 foreach,逐个获取所有属性。这里值得一提的一点是,数据是以 System.Web.UI.Pair 对象的形式返回的。

Goheer.EXIF.EXIFextractor er = 
              new Goheer.EXIF.EXIFextractor(ref bmp,"");
foreach(System.Web.UI.Pair s in er )
{
    // Remember the data is returned 
    // in a Key,Value Pair object
    Console.Write(s.First+"  " + s.Second +"\n");
}

这是您可以通过此方法获取的属性列表,在这种情况下,所有返回的值都将转换为字符串值。

/// <SUMMARY>
/// Get the individual property value by supplying property name
/// These are the valid property names :
/// 
/// "Exif IFD"
/// "Gps IFD"
/// "New Subfile Type"
/// "Subfile Type"
/// "Image Width"
/// "Image Height"
/// "Bits Per Sample"
/// "Compression"
/// "Photometric Interp"
/// "Thresh Holding"
/// "Cell Width"
/// "Cell Height"
/// "Fill Order"
/// "Document Name"
/// "Image Description"
/// "Equip Make"
/// "Equip Model"
/// "Strip Offsets"
/// "Orientation"
/// "Samples PerPixel"
/// "Rows Per Strip"
/// "Strip Bytes Count"
/// "Min Sample Value"
/// "Max Sample Value"
/// "X Resolution"
/// "Y Resolution"
/// "Planar Config"
/// "Page Name"
/// "X Position"
/// "Y Position"
/// "Free Offset"
/// "Free Byte Counts"
/// "Gray Response Unit"
/// "Gray Response Curve"
/// "T4 Option"
/// "T6 Option"
/// "Resolution Unit"
/// "Page Number"
/// "Transfer Funcition"
/// "Software Used"
/// "Date Time"
/// "Artist"
/// "Host Computer"
/// "Predictor"
/// "White Point"
/// "Primary Chromaticities"
/// "ColorMap"
/// "Halftone Hints"
/// "Tile Width"
/// "Tile Length"
/// "Tile Offset"
/// "Tile ByteCounts"
/// "InkSet"
/// "Ink Names"
/// "Number Of Inks"
/// "Dot Range"
/// "Target Printer"
/// "Extra Samples"
/// "Sample Format"
/// "S Min Sample Value"
/// "S Max Sample Value"
/// "Transfer Range"
/// "JPEG Proc"
/// "JPEG InterFormat"
/// "JPEG InterLength"
/// "JPEG RestartInterval"
/// "JPEG LosslessPredictors"
/// "JPEG PointTransforms"
/// "JPEG QTables"
/// "JPEG DCTables"
/// "JPEG ACTables"
/// "YCbCr Coefficients"
/// "YCbCr Subsampling"
/// "YCbCr Positioning"
/// "REF Black White"
/// "ICC Profile"
/// "Gamma"
/// "ICC Profile Descriptor"
/// "SRGB RenderingIntent"
/// "Image Title"
/// "Copyright"
/// "Resolution X Unit"
/// "Resolution Y Unit"
/// "Resolution X LengthUnit"
/// "Resolution Y LengthUnit"
/// "Print Flags"
/// "Print Flags Version"
/// "Print Flags Crop"
/// "Print Flags Bleed Width"
/// "Print Flags Bleed Width Scale"
/// "Halftone LPI"
/// "Halftone LPIUnit"
/// "Halftone Degree"
/// "Halftone Shape"
/// "Halftone Misc"
/// "Halftone Screen"
/// "JPEG Quality"
/// "Grid Size"
/// "Thumbnail Format"
/// "Thumbnail Width"
/// "Thumbnail Height"
/// "Thumbnail ColorDepth"
/// "Thumbnail Planes"
/// "Thumbnail RawBytes"
/// "Thumbnail Size"
/// "Thumbnail CompressedSize"
/// "Color Transfer Function"
/// "Thumbnail Data"
/// "Thumbnail ImageWidth"
/// "Thumbnail ImageHeight"
/// "Thumbnail BitsPerSample"
/// "Thumbnail Compression"
/// "Thumbnail PhotometricInterp"
/// "Thumbnail ImageDescription"
/// "Thumbnail EquipMake"
/// "Thumbnail EquipModel"
/// "Thumbnail StripOffsets"
/// "Thumbnail Orientation"
/// "Thumbnail SamplesPerPixel"
/// "Thumbnail RowsPerStrip"
/// "Thumbnail StripBytesCount"
/// "Thumbnail ResolutionX"
/// "Thumbnail ResolutionY"
/// "Thumbnail PlanarConfig"
/// "Thumbnail ResolutionUnit"
/// "Thumbnail TransferFunction"
/// "Thumbnail SoftwareUsed"
/// "Thumbnail DateTime"
/// "Thumbnail Artist"
/// "Thumbnail WhitePoint"
/// "Thumbnail PrimaryChromaticities"
/// "Thumbnail YCbCrCoefficients"
/// "Thumbnail YCbCrSubsampling"
/// "Thumbnail YCbCrPositioning"
/// "Thumbnail RefBlackWhite"
/// "Thumbnail CopyRight"
/// "Luminance Table"
/// "Chrominance Table"
/// "Frame Delay"
/// "Loop Count"
/// "Pixel Unit"
/// "Pixel PerUnit X"
/// "Pixel PerUnit Y"
/// "Palette Histogram"
/// "Exposure Time"
/// "F-Number"
/// "Exposure Prog"
/// "Spectral Sense"
/// "ISO Speed"
/// "OECF"
/// "Ver"
/// "DTOrig"
/// "DTDigitized"
/// "CompConfig"
/// "CompBPP"
/// "Shutter Speed"
/// "Aperture"
/// "Brightness"
/// "Exposure Bias"
/// "MaxAperture"
/// "SubjectDist"
/// "Metering Mode"
/// "LightSource"
/// "Flash"
/// "FocalLength"
/// "Maker Note"
/// "User Comment"
/// "DTSubsec"
/// "DTOrigSS"
/// "DTDigSS"
/// "FPXVer"
/// "ColorSpace"
/// "PixXDim"
/// "PixYDim"
/// "RelatedWav"
/// "Interop"
/// "FlashEnergy"
/// "SpatialFR"
/// "FocalXRes"
/// "FocalYRes"
/// "FocalResUnit"
/// "Subject Loc"
/// "Exposure Index"
/// "Sensing Method"
/// "FileSource"
/// "SceneType"
</SUMMARY>

该类的工作原理如下。我们获取 .NET 提供的 PropertyItem 数组,然后根据 EXIF 标准将其转换为人类可读的形式。我省略了额外的细节,您可以在提供的代码中看到它们。基本上,图像中通常嵌入有 6 种数据类型。我们分别处理它们。有时,对于特定数据类型,我们需要对特定标签(例如 iso)进行额外的转换,在获取人类可读的形式之前,我们需要对数据进行特定的计算。在这个循环中进行了许多此类转换,我再次故意将其删除。

System.Drawing.Imaging.PropertyItem [] y = 
                                 bmp.PropertyItems;
//
foreach(System.Drawing.Imaging.PropertyItem p in y)
{
    //1 = BYTE An 8-bit unsigned integer.,
    if( p.Type == 0x1 )
    {
        //byte
    }
        //2 = ASCII An 8-bit byte 
        //containing one 7-bit ASCII 
        //code. The final byte 
        //is terminated with NULL.,
    else if( p.Type == 0x2 )
    {
        // string                    

    }
        //3 = SHORT A 16-bit (2 -byte) 
        //unsigned integer,
    else if( p.Type == 0x3 )
    {
        // short int
    }
        //4 = LONG A 32-bit (4 -byte) 
        //unsigned integer,
    else if( p.Type == 0x4 )
    {
        // unsigned int

    }
        //5 = RATIONAL Two LONGs. The 
        //first LONG is the numerator 
        //and the second LONG expresses 
        //the denominator.,
    else if( p.Type == 0x5 )
    {
        // rational
        
    }
        //7 = UNDEFINED An 8-bit 
        //byte that can take 
        //any value depending on 
        //the field definition,
    else if( p.Type == 0x7 )
    {
        // depends upon the tag what form the 
        // data can take. no universal rule
    }
}

正如您所见,基本概念很直接,但数据转换需要做的事情却让人抓狂。

最后要记住的是,此代码按原样提供,如果它不幸破坏了您所有的宝贵图像收藏,那么除了您自己,没有人应受责备;)。

关注点

如果您想了解此控件的可扩展性,那么您绝对应该访问这个网站。在该网站上,当用户上传图片时,所有数据都会从图像中自动提取,同时还会检查图像是否有重复,即是否有人上传了相同的图像。然后在下一阶段创建缩略图,所以基本上可以说这个网站是自给自足的。

历史

我写的第一篇文章是如何在双显示器的两个屏幕上显示屏幕保护程序。如果您有空,请查看一下,并给我一些关于它的建议/评论。它叫做 GxTS

© . All rights reserved.