logo

Shapez Theme

· Home Playground About · Prev Next

24


OCTOBER

一些关于访问照片位置信息的资源

by Jason   ·   2011-10-24   ·   28 minutes reading time

用iphone拍的照片,有照片的位置信息,该信息存在与jpeg格式的exit信息中,也并不是苹果公司的原创。其实就是图片文件存储空间中,有一个区域是专门存储附加信息的,比如光圈、快门、日期等等,其实信息量也蛮大的,地理位置信息就是其中一组以gps开头的信息。当然,我们一般使用的图片编辑工具会忽略掉该信息,也就是说iphone拍的照片在使用平常windows下的照片编辑器后可能会丢失该信息。

要读取exit信息,其实就是加载图片文件后,以二进制读取文件中相应的偏移量,从而可以获得照片exif信息。这里查到一个js访问exit信息的脚本,还有一个C#访问exif的类。

通过javascript访问照片exit信息:

http://www.nihilogic.dk/labs/exif/exif.js

如果访问该url有问题,可以参考代码如下:

/\*  
 \* Javascript EXIF Reader 0.1.4  
 \* Copyright (c) 2008 Jacob Seidelin, [email protected], http://blog.nihilogic.dk/  
 \* Licensed under the MPL License \[http://www.nihilogic.dk/licenses/mpl-license.txt\]  
 \*/  
  
  
var EXIF = {};  
  
(function() {  
  
var bDebug = false;  
  
EXIF.Tags = {  
  
    // version tags  
    0x9000 : "ExifVersion",            // EXIF version  
    0xA000 : "FlashpixVersion",        // Flashpix format version  
  
    // colorspace tags  
    0xA001 : "ColorSpace",            // Color space information tag  
  
    // image configuration  
    0xA002 : "PixelXDimension",        // Valid width of meaningful image  
    0xA003 : "PixelYDimension",        // Valid height of meaningful image  
    0x9101 : "ComponentsConfiguration",    // Information about channels  
    0x9102 : "CompressedBitsPerPixel",    // Compressed bits per pixel  
  
    // user information  
    0x927C : "MakerNote",            // Any desired information written by the manufacturer  
    0x9286 : "UserComment",            // Comments by user  
  
    // related file  
    0xA004 : "RelatedSoundFile",        // Name of related sound file  
  
    // date and time  
    0x9003 : "DateTimeOriginal",        // Date and time when the original image was generated  
    0x9004 : "DateTimeDigitized",        // Date and time when the image was stored digitally  
    0x9290 : "SubsecTime",            // Fractions of seconds for DateTime  
    0x9291 : "SubsecTimeOriginal",        // Fractions of seconds for DateTimeOriginal  
    0x9292 : "SubsecTimeDigitized",        // Fractions of seconds for DateTimeDigitized  
  
    // picture-taking conditions  
    0x829A : "ExposureTime",        // Exposure time (in seconds)  
    0x829D : "FNumber",            // F number  
    0x8822 : "ExposureProgram",        // Exposure program  
    0x8824 : "SpectralSensitivity",        // Spectral sensitivity  
    0x8827 : "ISOSpeedRatings",        // ISO speed rating  
    0x8828 : "OECF",            // Optoelectric conversion factor  
    0x9201 : "ShutterSpeedValue",        // Shutter speed  
    0x9202 : "ApertureValue",        // Lens aperture  
    0x9203 : "BrightnessValue",        // Value of brightness  
    0x9204 : "ExposureBias",        // Exposure bias  
    0x9205 : "MaxApertureValue",        // Smallest F number of lens  
    0x9206 : "SubjectDistance",        // Distance to subject in meters  
    0x9207 : "MeteringMode",         // Metering mode  
    0x9208 : "LightSource",            // Kind of light source  
    0x9209 : "Flash",            // Flash status  
    0x9214 : "SubjectArea",            // Location and area of main subject  
    0x920A : "FocalLength",            // Focal length of the lens in mm  
    0xA20B : "FlashEnergy",            // Strobe energy in BCPS  
    0xA20C : "SpatialFrequencyResponse",    //   
    0xA20E : "FocalPlaneXResolution",     // Number of pixels in width direction per FocalPlaneResolutionUnit  
    0xA20F : "FocalPlaneYResolution",     // Number of pixels in height direction per FocalPlaneResolutionUnit  
    0xA210 : "FocalPlaneResolutionUnit",     // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution  
    0xA214 : "SubjectLocation",        // Location of subject in image  
    0xA215 : "ExposureIndex",        // Exposure index selected on camera  
    0xA217 : "SensingMethod",         // Image sensor type  
    0xA300 : "FileSource",             // Image source (3 == DSC)  
    0xA301 : "SceneType",             // Scene type (1 == directly photographed)  
    0xA302 : "CFAPattern",            // Color filter array geometric pattern  
    0xA401 : "CustomRendered",        // Special processing  
    0xA402 : "ExposureMode",        // Exposure mode  
    0xA403 : "WhiteBalance",        // 1 = auto white balance, 2 = manual  
    0xA404 : "DigitalZoomRation",        // Digital zoom ratio  
    0xA405 : "FocalLengthIn35mmFilm",    // Equivalent foacl length assuming 35mm film camera (in mm)  
    0xA406 : "SceneCaptureType",        // Type of scene  
    0xA407 : "GainControl",            // Degree of overall image gain adjustment  
    0xA408 : "Contrast",            // Direction of contrast processing applied by camera  
    0xA409 : "Saturation",             // Direction of saturation processing applied by camera  
    0xA40A : "Sharpness",            // Direction of sharpness processing applied by camera  
    0xA40B : "DeviceSettingDescription",    //   
    0xA40C : "SubjectDistanceRange",    // Distance to subject  
  
    // other tags  
    0xA005 : "InteroperabilityIFDPointer",  
    0xA420 : "ImageUniqueID"        // Identifier assigned uniquely to each image  
};  
  
EXIF.TiffTags = {  
    0x0100 : "ImageWidth",  
    0x0101 : "ImageHeight",  
    0x8769 : "ExifIFDPointer",  
    0x8825 : "GPSInfoIFDPointer",  
    0xA005 : "InteroperabilityIFDPointer",  
    0x0102 : "BitsPerSample",  
    0x0103 : "Compression",  
    0x0106 : "PhotometricInterpretation",  
    0x0112 : "Orientation",  
    0x0115 : "SamplesPerPixel",  
    0x011C : "PlanarConfiguration",  
    0x0212 : "YCbCrSubSampling",  
    0x0213 : "YCbCrPositioning",  
    0x011A : "XResolution",  
    0x011B : "YResolution",  
    0x0128 : "ResolutionUnit",  
    0x0111 : "StripOffsets",  
    0x0116 : "RowsPerStrip",  
    0x0117 : "StripByteCounts",  
    0x0201 : "JPEGInterchangeFormat",  
    0x0202 : "JPEGInterchangeFormatLength",  
    0x012D : "TransferFunction",  
    0x013E : "WhitePoint",  
    0x013F : "PrimaryChromaticities",  
    0x0211 : "YCbCrCoefficients",  
    0x0214 : "ReferenceBlackWhite",  
    0x0132 : "DateTime",  
    0x010E : "ImageDescription",  
    0x010F : "Make",  
    0x0110 : "Model",  
    0x0131 : "Software",  
    0x013B : "Artist",  
    0x8298 : "Copyright"  
}  
  
EXIF.GPSTags = {  
    0x0000 : "GPSVersionID",  
    0x0001 : "GPSLatitudeRef",  
    0x0002 : "GPSLatitude",  
    0x0003 : "GPSLongitudeRef",  
    0x0004 : "GPSLongitude",  
    0x0005 : "GPSAltitudeRef",  
    0x0006 : "GPSAltitude",  
    0x0007 : "GPSTimeStamp",  
    0x0008 : "GPSSatellites",  
    0x0009 : "GPSStatus",  
    0x000A : "GPSMeasureMode",  
    0x000B : "GPSDOP",  
    0x000C : "GPSSpeedRef",  
    0x000D : "GPSSpeed",  
    0x000E : "GPSTrackRef",  
    0x000F : "GPSTrack",  
    0x0010 : "GPSImgDirectionRef",  
    0x0011 : "GPSImgDirection",  
    0x0012 : "GPSMapDatum",  
    0x0013 : "GPSDestLatitudeRef",  
    0x0014 : "GPSDestLatitude",  
    0x0015 : "GPSDestLongitudeRef",  
    0x0016 : "GPSDestLongitude",  
    0x0017 : "GPSDestBearingRef",  
    0x0018 : "GPSDestBearing",  
    0x0019 : "GPSDestDistanceRef",  
    0x001A : "GPSDestDistance",  
    0x001B : "GPSProcessingMethod",  
    0x001C : "GPSAreaInformation",  
    0x001D : "GPSDateStamp",  
    0x001E : "GPSDifferential"  
}  
  
EXIF.StringValues = {  
    ExposureProgram : {  
        0 : "Not defined",  
        1 : "Manual",  
        2 : "Normal program",  
        3 : "Aperture priority",  
        4 : "Shutter priority",  
        5 : "Creative program",  
        6 : "Action program",  
        7 : "Portrait mode",  
        8 : "Landscape mode"  
    },  
    MeteringMode : {  
        0 : "Unknown",  
        1 : "Average",  
        2 : "CenterWeightedAverage",  
        3 : "Spot",  
        4 : "MultiSpot",  
        5 : "Pattern",  
        6 : "Partial",  
        255 : "Other"  
    },  
    LightSource : {  
        0 : "Unknown",  
        1 : "Daylight",  
        2 : "Fluorescent",  
        3 : "Tungsten (incandescent light)",  
        4 : "Flash",  
        9 : "Fine weather",  
        10 : "Cloudy weather",  
        11 : "Shade",  
        12 : "Daylight fluorescent (D 5700 - 7100K)",  
        13 : "Day white fluorescent (N 4600 - 5400K)",  
        14 : "Cool white fluorescent (W 3900 - 4500K)",  
        15 : "White fluorescent (WW 3200 - 3700K)",  
        17 : "Standard light A",  
        18 : "Standard light B",  
        19 : "Standard light C",  
        20 : "D55",  
        21 : "D65",  
        22 : "D75",  
        23 : "D50",  
        24 : "ISO studio tungsten",  
        255 : "Other"  
    },  
    Flash : {  
        0x0000 : "Flash did not fire",  
        0x0001 : "Flash fired",  
        0x0005 : "Strobe return light not detected",  
        0x0007 : "Strobe return light detected",  
        0x0009 : "Flash fired, compulsory flash mode",  
        0x000D : "Flash fired, compulsory flash mode, return light not detected",  
        0x000F : "Flash fired, compulsory flash mode, return light detected",  
        0x0010 : "Flash did not fire, compulsory flash mode",  
        0x0018 : "Flash did not fire, auto mode",  
        0x0019 : "Flash fired, auto mode",  
        0x001D : "Flash fired, auto mode, return light not detected",  
        0x001F : "Flash fired, auto mode, return light detected",  
        0x0020 : "No flash function",  
        0x0041 : "Flash fired, red-eye reduction mode",  
        0x0045 : "Flash fired, red-eye reduction mode, return light not detected",  
        0x0047 : "Flash fired, red-eye reduction mode, return light detected",  
        0x0049 : "Flash fired, compulsory flash mode, red-eye reduction mode",  
        0x004D : "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",  
        0x004F : "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",  
        0x0059 : "Flash fired, auto mode, red-eye reduction mode",  
        0x005D : "Flash fired, auto mode, return light not detected, red-eye reduction mode",  
        0x005F : "Flash fired, auto mode, return light detected, red-eye reduction mode"  
    },  
    SensingMethod : {  
        1 : "Not defined",  
        2 : "One-chip color area sensor",  
        3 : "Two-chip color area sensor",  
        4 : "Three-chip color area sensor",  
        5 : "Color sequential area sensor",  
        7 : "Trilinear sensor",  
        8 : "Color sequential linear sensor"  
    },  
    SceneCaptureType : {  
        0 : "Standard",  
        1 : "Landscape",  
        2 : "Portrait",  
        3 : "Night scene"  
    },  
    SceneType : {  
        1 : "Directly photographed"  
    },  
    CustomRendered : {  
        0 : "Normal process",  
        1 : "Custom process"  
    },  
    WhiteBalance : {  
        0 : "Auto white balance",  
        1 : "Manual white balance"  
    },  
    GainControl : {  
        0 : "None",  
        1 : "Low gain up",  
        2 : "High gain up",  
        3 : "Low gain down",  
        4 : "High gain down"  
    },  
    Contrast : {  
        0 : "Normal",  
        1 : "Soft",  
        2 : "Hard"  
    },  
    Saturation : {  
        0 : "Normal",  
        1 : "Low saturation",  
        2 : "High saturation"  
    },  
    Sharpness : {  
        0 : "Normal",  
        1 : "Soft",  
        2 : "Hard"  
    },  
    SubjectDistanceRange : {  
        0 : "Unknown",  
        1 : "Macro",  
        2 : "Close view",  
        3 : "Distant view"  
    },  
    FileSource : {  
        3 : "DSC"  
    },  
  
    Components : {  
        0 : "",  
        1 : "Y",  
        2 : "Cb",  
        3 : "Cr",  
        4 : "R",  
        5 : "G",  
        6 : "B"  
    }  
}  
  
function addEvent(oElement, strEvent, fncHandler)   
{  
    if (oElement.addEventListener) {   
        oElement.addEventListener(strEvent, fncHandler, false);   
    } else if (oElement.attachEvent) {   
        oElement.attachEvent("on" + strEvent, fncHandler);   
    }  
}  
  
  
function imageHasData(oImg)   
{  
    return !!(oImg.exifdata);  
}  
  
function getImageData(oImg, fncCallback)   
{  
    BinaryAjax(  
        oImg.src,  
        function(oHTTP) {  
            var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse);  
            oImg.exifdata = oEXIF || {};  
            if (fncCallback) fncCallback();  
        }  
    )  
}  
  
function findEXIFinJPEG(oFile) {  
    var aMarkers = \[\];  
  
    if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) {  
        return false; // not a valid jpeg  
    }  
  
    var iOffset = 2;  
    var iLength = oFile.getLength();  
    while (iOffset < iLength) {  
        if (oFile.getByteAt(iOffset) != 0xFF) {  
            if (bDebug) console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset));  
            return false; // not a valid marker, something is wrong  
        }  
  
        var iMarker = oFile.getByteAt(iOffset+1);  
  
        // we could implement handling for other markers here,   
        // but we're only looking for 0xFFE1 for EXIF data  
  
        if (iMarker == 22400) {  
            if (bDebug) console.log("Found 0xFFE1 marker");  
            return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);  
            iOffset += 2 + oFile.getShortAt(iOffset+2, true);  
  
        } else if (iMarker == 225) {  
            // 0xE1 = Application-specific 1 (for EXIF)  
            if (bDebug) console.log("Found 0xFFE1 marker");  
            return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset+2, true)-2);  
  
        } else {  
            iOffset += 2 + oFile.getShortAt(iOffset+2, true);  
        }  
  
    }  
  
}  
  
  
function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd)   
{  
    var iEntries = oFile.getShortAt(iDirStart, bBigEnd);  
    var oTags = {};  
    for (var i=0;i<iEntries;i++) {  
        var iEntryOffset = iDirStart + i\*12 + 2;  
        var strTag = oStrings\[oFile.getShortAt(iEntryOffset, bBigEnd)\];  
        if (!strTag && bDebug) console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd));  
        oTags\[strTag\] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd);  
    }  
    return oTags;  
}  
  
  
function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd)  
{  
    var iType = oFile.getShortAt(iEntryOffset+2, bBigEnd);  
    var iNumValues = oFile.getLongAt(iEntryOffset+4, bBigEnd);  
    var iValueOffset = oFile.getLongAt(iEntryOffset+8, bBigEnd) + iTIFFStart;  
  
    switch (iType) {  
        case 1: // byte, 8-bit unsigned int  
        case 7: // undefined, 8-bit byte, value depending on field  
            if (iNumValues == 1) {  
                return oFile.getByteAt(iEntryOffset + 8, bBigEnd);  
            } else {  
                var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);  
                var aVals = \[\];  
                for (var n=0;n<iNumValues;n++) {  
                    aVals\[n\] = oFile.getByteAt(iValOffset + n);  
                }  
                return aVals;  
            }  
            break;  
  
        case 2: // ascii, 8-bit byte  
            var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);  
            return oFile.getStringAt(iStringOffset, iNumValues-1);  
            break;  
  
        case 3: // short, 16 bit int  
            if (iNumValues == 1) {  
                return oFile.getShortAt(iEntryOffset + 8, bBigEnd);  
            } else {  
                var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8);  
                var aVals = \[\];  
                for (var n=0;n<iNumValues;n++) {  
                    aVals\[n\] = oFile.getShortAt(iValOffset + 2\*n, bBigEnd);  
                }  
                return aVals;  
            }  
            break;  
  
        case 4: // long, 32 bit int  
            if (iNumValues == 1) {  
                return oFile.getLongAt(iEntryOffset + 8, bBigEnd);  
            } else {  
                var aVals = \[\];  
                for (var n=0;n<iNumValues;n++) {  
                    aVals\[n\] = oFile.getLongAt(iValueOffset + 4\*n, bBigEnd);  
                }  
                return aVals;  
            }  
            break;  
        case 5:    // rational = two long values, first is numerator, second is denominator  
            if (iNumValues == 1) {  
                return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset+4, bBigEnd);  
            } else {  
                var aVals = \[\];  
                for (var n=0;n<iNumValues;n++) {  
                    aVals\[n\] = oFile.getLongAt(iValueOffset + 8\*n, bBigEnd) / oFile.getLongAt(iValueOffset+4 + 8\*n, bBigEnd);  
                }  
                return aVals;  
            }  
            break;  
        case 9: // slong, 32 bit signed int  
            if (iNumValues == 1) {  
                return oFile.getSLongAt(iEntryOffset + 8, bBigEnd);  
            } else {  
                var aVals = \[\];  
                for (var n=0;n<iNumValues;n++) {  
                    aVals\[n\] = oFile.getSLongAt(iValueOffset + 4\*n, bBigEnd);  
                }  
                return aVals;  
            }  
            break;  
        case 10: // signed rational, two slongs, first is numerator, second is denominator  
            if (iNumValues == 1) {  
                return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset+4, bBigEnd);  
            } else {  
                var aVals = \[\];  
                for (var n=0;n<iNumValues;n++) {  
                    aVals\[n\] = oFile.getSLongAt(iValueOffset + 8\*n, bBigEnd) / oFile.getSLongAt(iValueOffset+4 + 8\*n, bBigEnd);  
                }  
                return aVals;  
            }  
            break;  
    }  
}  
  
  
function readEXIFData(oFile, iStart, iLength)   
{  
    if (oFile.getStringAt(iStart, 4) != "Exif") {  
        if (bDebug) console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4));  
        return false;  
    }  
  
    var bBigEnd;  
  
    var iTIFFOffset = iStart + 6;  
  
    // test for TIFF validity and endianness  
    if (oFile.getShortAt(iTIFFOffset) == 0x4949) {  
        bBigEnd = false;  
    } else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) {  
        bBigEnd = true;  
    } else {  
        if (bDebug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");  
        return false;  
    }  
  
    if (oFile.getShortAt(iTIFFOffset+2, bBigEnd) != 0x002A) {  
        if (bDebug) console.log("Not valid TIFF data! (no 0x002A)");  
        return false;  
    }  
  
    if (oFile.getLongAt(iTIFFOffset+4, bBigEnd) != 0x00000008) {  
        if (bDebug) console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset+4, bBigEnd));  
        return false;  
    }  
  
    var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset+8, EXIF.TiffTags, bBigEnd);  
  
    if (oTags.ExifIFDPointer) {  
        var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd);  
        for (var strTag in oEXIFTags) {  
            switch (strTag) {  
                case "LightSource" :  
                case "Flash" :  
                case "MeteringMode" :  
                case "ExposureProgram" :  
                case "SensingMethod" :  
                case "SceneCaptureType" :  
                case "SceneType" :  
                case "CustomRendered" :  
                case "WhiteBalance" :   
                case "GainControl" :   
                case "Contrast" :  
                case "Saturation" :  
                case "Sharpness" :   
                case "SubjectDistanceRange" :  
                case "FileSource" :  
                    oEXIFTags\[strTag\] = EXIF.StringValues\[strTag\]\[oEXIFTags\[strTag\]\];  
                    break;  
      
                case "ExifVersion" :  
                case "FlashpixVersion" :  
                    oEXIFTags\[strTag\] = String.fromCharCode(oEXIFTags\[strTag\]\[0\], oEXIFTags\[strTag\]\[1\], oEXIFTags\[strTag\]\[2\], oEXIFTags\[strTag\]\[3\]);  
                    break;  
      
                case "ComponentsConfiguration" :   
                    oEXIFTags\[strTag\] =   
                        EXIF.StringValues.Components\[oEXIFTags\[strTag\]\[0\]\]  
                        + EXIF.StringValues.Components\[oEXIFTags\[strTag\]\[1\]\]  
                        + EXIF.StringValues.Components\[oEXIFTags\[strTag\]\[2\]\]  
                        + EXIF.StringValues.Components\[oEXIFTags\[strTag\]\[3\]\];  
                    break;  
            }  
            oTags\[strTag\] = oEXIFTags\[strTag\];  
        }  
    }  
  
    if (oTags.GPSInfoIFDPointer) {  
        var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd);  
        for (var strTag in oGPSTags) {  
            switch (strTag) {  
                case "GPSVersionID" :   
                    oGPSTags\[strTag\] = oGPSTags\[strTag\]\[0\]   
                        + "." + oGPSTags\[strTag\]\[1\]   
                        + "." + oGPSTags\[strTag\]\[2\]   
                        + "." + oGPSTags\[strTag\]\[3\];  
                    break;  
            }  
            oTags\[strTag\] = oGPSTags\[strTag\];  
        }  
    }  
  
    return oTags;  
}  
  
  
EXIF.getData = function(oImg, fncCallback)   
{  
    if (!oImg.complete) return false;  
    if (!imageHasData(oImg)) {  
        getImageData(oImg, fncCallback);  
    } else {  
        if (fncCallback) fncCallback();  
    }  
    return true;  
}  
  
EXIF.getTag = function(oImg, strTag)   
{  
    if (!imageHasData(oImg)) return;  
    return oImg.exifdata\[strTag\];  
}  
  
EXIF.getAllTags = function(oImg)   
{  
    if (!imageHasData(oImg)) return {};  
    var oData = oImg.exifdata;  
    var oAllTags = {};  
    for (var a in oData) {  
        if (oData.hasOwnProperty(a)) {  
            oAllTags\[a\] = oData\[a\];  
        }  
    }  
    return oAllTags;  
}  
  
  
EXIF.pretty = function(oImg)   
{  
    if (!imageHasData(oImg)) return "";  
    var oData = oImg.exifdata;  
    var strPretty = "";  
    for (var a in oData) {  
        if (oData.hasOwnProperty(a)) {  
            if (typeof oData\[a\] == "object") {  
                strPretty += a + " : \[" + oData\[a\].length + " values\]rn";  
            } else {  
                strPretty += a + " : " + oData\[a\] + "rn";  
            }  
        }  
    }  
    return strPretty;  
}  
  
EXIF.readFromBinaryFile = function(oFile) {  
    return findEXIFinJPEG(oFile);  
}  
  
function loadAllImages()   
{  
    var aImages = document.getElementsByTagName("img");  
    for (var i=0;i<aImages.length;i++) {  
        if (aImages\[i\].getAttribute("exif") == "true") {  
            if (!aImages\[i\].complete) {  
                addEvent(aImages\[i\], "load",   
                    function() {  
                        EXIF.getData(this);  
                    }  
                );   
            } else {  
                EXIF.getData(aImages\[i\]);  
            }  
        }  
    }  
}  
  
addEvent(window, "load", loadAllImages);   
  
})();    

该网站同时提供jquery版的exif代码,具体链接为:

http://www.nihilogic.dk/labs/exifjquery/jquery.exif.js

经实际测试发现,该程序仅仅在火狐浏览器和chrome浏览器比较正常,当前的其他浏览器都或多或少有些问题,大多信息读取不全。简单示例代码可在

http://blogs8.sinaapp.com/demo/exif/

中进行查看。可以直接看源代码,写的比较简单。

下面是一个C#访问EXIF的类,网上转来的(自路径http://www.cnblogs.com/fengbp/articles/1403353.html),原作者不清楚

using System;  
using System.Collections.Generic;  
using System.Text;  
  
namespace ExifWorks  
{  
//   
// Utility class for working with EXIF data in images. Provides abstraction  
// for most common data and generic utilities for work with all other.   
//   
//   
// Copyright (c) Michal A. Valášek - Altair Communications, 2003-2005  
// Copmany: http://software.altaircom.net, E-mail: [email protected]  
// Private: http://www.rider.cz, E-mail: [email protected]  
// This is free software licensed under GNU Lesser General Public License  
//   
//   
// \[altair\] 10.09.2003 Created  
// \[altair\] 12.06.2004 Added capability to write EXIF data  
// \[altair\] 11.07.2004 Added option to change encoding  
// \[altair\] 04.09.2005 Changed source of Width and Height properties from EXIF to image  
// \[altair\] 05.09.2005 Code clean-up and minor changes  
// \[[email protected]\] 02-11-2006 C# translation  
//   
public class ExifManager : IDisposable  
{  
  
private System.Drawing.Bitmap \_Image;  
private System.Text.Encoding \_Encoding = System.Text.Encoding.UTF8;  
  
#region Type declarations  
  
//   
// Contains possible values of EXIF tag names (ID)  
//   
// See GdiPlusImaging.h  
//   
// \[altair\] 10.09.2003 Created  
//   
  
public enum TagNames : int  
{  
ExifIFD = 0x8769,  
GpsIFD = 0x8825,  
NewSubfileType = 0xFE,  
SubfileType = 0xFF,  
ImageWidth = 0x100,  
ImageHeight = 0x101,  
BitsPerSample = 0x102,  
Compression = 0x103,  
PhotometricInterp = 0x106,  
ThreshHolding = 0x107,  
CellWidth = 0x108,  
CellHeight = 0x109,  
FillOrder = 0x10A,  
DocumentName = 0x10D,  
ImageDescription = 0x10E,  
EquipMake = 0x10F,  
EquipModel = 0x110,  
StripOffsets = 0x111,  
Orientation = 0x112,  
SamplesPerPixel = 0x115,  
RowsPerStrip = 0x116,  
StripBytesCount = 0x117,  
MinSampleValue = 0x118,  
MaxSampleValue = 0x119,  
XResolution = 0x11A,  
YResolution = 0x11B,  
PlanarConfig = 0x11C,  
PageName = 0x11D,  
XPosition = 0x11E,  
YPosition = 0x11F,  
FreeOffset = 0x120,  
FreeByteCounts = 0x121,  
GrayResponseUnit = 0x122,  
GrayResponseCurve = 0x123,  
T4Option = 0x124,  
T6Option = 0x125,  
ResolutionUnit = 0x128,  
PageNumber = 0x129,  
TransferFuncition = 0x12D,  
SoftwareUsed = 0x131,  
DateTime = 0x132,  
Artist = 0x13B,  
HostComputer = 0x13C,  
Predictor = 0x13D,  
WhitePoint = 0x13E,  
PrimaryChromaticities = 0x13F,  
ColorMap = 0x140,  
HalftoneHints = 0x141,  
TileWidth = 0x142,  
TileLength = 0x143,  
TileOffset = 0x144,  
TileByteCounts = 0x145,  
InkSet = 0x14C,  
InkNames = 0x14D,  
NumberOfInks = 0x14E,  
DotRange = 0x150,  
TargetPrinter = 0x151,  
ExtraSamples = 0x152,  
SampleFormat = 0x153,  
SMinSampleValue = 0x154,  
SMaxSampleValue = 0x155,  
TransferRange = 0x156,  
JPEGProc = 0x200,  
JPEGInterFormat = 0x201,  
JPEGInterLength = 0x202,  
JPEGRestartInterval = 0x203,  
JPEGLosslessPredictors = 0x205,  
JPEGPointTransforms = 0x206,  
JPEGQTables = 0x207,  
JPEGDCTables = 0x208,  
JPEGACTables = 0x209,  
YCbCrCoefficients = 0x211,  
YCbCrSubsampling = 0x212,  
YCbCrPositioning = 0x213,  
REFBlackWhite = 0x214,  
ICCProfile = 0x8773,  
Gamma = 0x301,  
ICCProfileDescriptor = 0x302,  
SRGBRenderingIntent = 0x303,  
ImageTitle = 0x320,  
Copyright = 0x8298,  
ResolutionXUnit = 0x5001,  
ResolutionYUnit = 0x5002,  
ResolutionXLengthUnit = 0x5003,  
ResolutionYLengthUnit = 0x5004,  
PrintFlags = 0x5005,  
PrintFlagsVersion = 0x5006,  
PrintFlagsCrop = 0x5007,  
PrintFlagsBleedWidth = 0x5008,  
PrintFlagsBleedWidthScale = 0x5009,  
HalftoneLPI = 0x500A,  
HalftoneLPIUnit = 0x500B,  
HalftoneDegree = 0x500C,  
HalftoneShape = 0x500D,  
HalftoneMisc = 0x500E,  
HalftoneScreen = 0x500F,  
JPEGQuality = 0x5010,  
GridSize = 0x5011,  
ThumbnailFormat = 0x5012,  
ThumbnailWidth = 0x5013,  
ThumbnailHeight = 0x5014,  
ThumbnailColorDepth = 0x5015,  
ThumbnailPlanes = 0x5016,  
ThumbnailRawBytes = 0x5017,  
ThumbnailSize = 0x5018,  
ThumbnailCompressedSize = 0x5019,  
ColorTransferFunction = 0x501A,  
ThumbnailData = 0x501B,  
ThumbnailImageWidth = 0x5020,  
ThumbnailImageHeight = 0x502,  
ThumbnailBitsPerSample = 0x5022,  
ThumbnailCompression = 0x5023,  
ThumbnailPhotometricInterp = 0x5024,  
ThumbnailImageDescription = 0x5025,  
ThumbnailEquipMake = 0x5026,  
ThumbnailEquipModel = 0x5027,  
ThumbnailStripOffsets = 0x5028,  
ThumbnailOrientation = 0x5029,  
ThumbnailSamplesPerPixel = 0x502A,  
ThumbnailRowsPerStrip = 0x502B,  
ThumbnailStripBytesCount = 0x502C,  
ThumbnailResolutionX = 0x502D,  
ThumbnailResolutionY = 0x502E,  
ThumbnailPlanarConfig = 0x502F,  
ThumbnailResolutionUnit = 0x5030,  
ThumbnailTransferFunction = 0x5031,  
ThumbnailSoftwareUsed = 0x5032,  
ThumbnailDateTime = 0x5033,  
ThumbnailArtist = 0x5034,  
ThumbnailWhitePoint = 0x5035,  
ThumbnailPrimaryChromaticities = 0x5036,  
ThumbnailYCbCrCoefficients = 0x5037,  
ThumbnailYCbCrSubsampling = 0x5038,  
ThumbnailYCbCrPositioning = 0x5039,  
ThumbnailRefBlackWhite = 0x503A,  
ThumbnailCopyRight = 0x503B,  
LuminanceTable = 0x5090,  
ChrominanceTable = 0x5091,  
FrameDelay = 0x5100,  
LoopCount = 0x5101,  
PixelUnit = 0x5110,  
PixelPerUnitX = 0x5111,  
PixelPerUnitY = 0x5112,  
PaletteHistogram = 0x5113,  
ExifExposureTime = 0x829A,  
ExifFNumber = 0x829D,  
ExifExposureProg = 0x8822,  
ExifSpectralSense = 0x8824,  
ExifISOSpeed = 0x8827,  
ExifOECF = 0x8828,  
ExifVer = 0x9000,  
ExifDTOrig = 0x9003,  
ExifDTDigitized = 0x9004,  
ExifCompConfig = 0x9101,  
ExifCompBPP = 0x9102,  
ExifShutterSpeed = 0x9201,  
ExifAperture = 0x9202,  
ExifBrightness = 0x9203,  
ExifExposureBias = 0x9204,  
ExifMaxAperture = 0x9205,  
ExifSubjectDist = 0x9206,  
ExifMeteringMode = 0x9207,  
ExifLightSource = 0x9208,  
ExifFlash = 0x9209,  
ExifFocalLength = 0x920A,  
ExifMakerNote = 0x927C,  
ExifUserComment = 0x9286,  
ExifDTSubsec = 0x9290,  
ExifDTOrigSS = 0x9291,  
ExifDTDigSS = 0x9292,  
ExifFPXVer = 0xA000,  
ExifColorSpace = 0xA001,  
ExifPixXDim = 0xA002,  
ExifPixYDim = 0xA003,  
ExifRelatedWav = 0xA004,  
ExifInterop = 0xA005,  
ExifFlashEnergy = 0xA20B,  
ExifSpatialFR = 0xA20C,  
ExifFocalXRes = 0xA20E,  
ExifFocalYRes = 0xA20F,  
ExifFocalResUnit = 0xA210,  
ExifSubjectLoc = 0xA214,  
ExifExposureIndex = 0xA215,  
ExifSensingMethod = 0xA217,  
ExifFileSource = 0xA300,  
ExifSceneType = 0xA301,  
ExifCfaPattern = 0xA302,  
GpsVer = 0x0,  
GpsLatitudeRef = 0x1,  
GpsLatitude = 0x2,  
GpsLongitudeRef = 0x3,  
GpsLongitude = 0x4,  
GpsAltitudeRef = 0x5,  
GpsAltitude = 0x6,  
GpsGpsTime = 0x7,  
GpsGpsSatellites = 0x8,  
GpsGpsStatus = 0x9,  
GpsGpsMeasureMode = 0xA,  
GpsGpsDop = 0xB,  
GpsSpeedRef = 0xC,  
GpsSpeed = 0xD,  
GpsTrackRef = 0xE,  
GpsTrack = 0xF,  
GpsImgDirRef = 0x10,  
GpsImgDir = 0x11,  
GpsMapDatum = 0x12,  
GpsDestLatRef = 0x13,  
GpsDestLat = 0x14,  
GpsDestLongRef = 0x15,  
GpsDestLong = 0x16,  
GpsDestBearRef = 0x17,  
GpsDestBear = 0x18,  
GpsDestDistRef = 0x19,  
GpsDestDist = 0x1A  
}  
  
  
//   
// Real position of 0th row and column of picture  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
  
public enum Orientations  
{  
TopLeft = 1,  
TopRight = 2,  
BottomRight = 3,  
BottomLeft = 4,  
LeftTop = 5,  
RightTop = 6,  
RightBottom = 7,  
LftBottom = 8  
}  
  
  
//   
// Exposure programs  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
  
public enum ExposurePrograms  
{  
Manual = 1,  
Normal = 2,  
AperturePriority = 3,  
ShutterPriority = 4,  
Creative = 5,  
Action = 6,  
Portrait = 7,  
Landscape = 8,  
}  
  
  
//   
// Exposure metering modes  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
  
public enum ExposureMeteringModes  
{  
Unknown = 0,  
Average = 1,  
CenterWeightedAverage = 2,  
Spot = 3,  
MultiSpot = 4,  
MultiSegment = 5,  
Partial = 6,  
Other = 255  
}  
  
  
//   
// Flash activity modes  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
  
public enum FlashModes  
{  
NotFired = 0,  
Fired = 1,  
FiredButNoStrobeReturned = 5,  
FiredAndStrobeReturned = 7,  
}  
  
  
//   
// Possible light sources (white balance)  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
  
public enum LightSources  
{  
Unknown = 0,  
Daylight = 1,  
Fluorescent = 2,  
Tungsten = 3,  
Flash = 10,  
StandardLightA = 17,  
StandardLightB = 18,  
StandardLightC = 19,  
D55 = 20,  
D65 = 21,  
D75 = 22,  
Other = 255  
}  
  
  
//   
// EXIF data types  
//   
//   
//   
// \[altair\] 12.6.2004 Created  
//   
public enum ExifDataTypes : short  
{  
UnsignedByte = 1,  
AsciiString = 2,  
UnsignedShort = 3,  
UnsignedLong = 4,  
UnsignedRational = 5,  
SignedByte = 6,  
Undefined = 7,  
SignedShort = 8,  
SignedLong = 9,  
SignedRational = 10,  
SingleFloat = 11,  
DoubleFloat = 12  
}  
  
  
//   
// Represents rational which is type of some Exif properties  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public struct Rational  
{  
public Int32 Numerator;  
public Int32 Denominator;  
  
  
//   
// Converts rational to string representation  
//   
// Optional, default "/". String to be used as delimiter of components.  
// String representation of the rational.  
//   
//   
// \[altair\] 10.09.2003 Created  
//   
  
public override string ToString()  
{  
return ToString("/");  
}  
  
public string ToString(string Delimiter)  
{  
return Numerator + "/" + Denominator;  
}  
  
//   
// Converts rational to double precision real number  
//   
// The rational as double precision real number.  
//   
//   
// \[altair\] 10.09.2003 Created  
//   
  
public double ToDouble()  
{  
return (double)Numerator / Denominator;  
}  
}  
  
#endregion  
  
//   
// Initializes new instance of this class.  
//   
// Bitmap to read exif information from  
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public ExifManager(System.Drawing.Bitmap Bitmap)  
{  
if (Bitmap == null)  
throw new ArgumentNullException("Bitmap");  
this.\_Image = Bitmap;  
}  
  
//   
// Initializes new instance of this class.  
//   
// Name of file to be loaded  
//   
//   
// \[altair\] 13.06.2004 Created  
//   
public ExifManager(string FileName)  
{  
this.\_Image = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromFile(FileName);  
}  
  
//   
// Get or set encoding used for string metadata  
//   
// Encoding used for string metadata  
// Default encoding is UTF-8  
//   
// \[altair\] 11.07.2004 Created  
// \[altair\] 05.09.2005 Changed from shared to instance member  
//   
public System.Text.Encoding Encoding  
{  
get  
{  
return this.\_Encoding;  
}  
set  
{  
if (value == null)  
throw new ArgumentNullException();  
this.\_Encoding = value;  
}  
}  
  
//   
// Returns copy of bitmap this instance is working on  
//   
//   
//   
//   
// \[altair\] 13.06.2004 Created  
//   
public System.Drawing.Bitmap GetBitmap()  
{  
return (System.Drawing.Bitmap)this.\_Image.Clone();  
}  
  
//   
// Returns all available data in formatted string form  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public override string ToString()  
{  
System.Text.StringBuilder SB = new StringBuilder();  
  
SB.Append("Image:");  
SB.Append("ntDimensions: " + this.Width + " x " + this.Height + " px");  
SB.Append("ntResolution: " + this.ResolutionX + " x " + this.ResolutionY + " dpi");  
SB.Append("ntOrientation: " + Enum.GetName(typeof(Orientations), this.Orientation));  
SB.Append("ntTitle: " + this.Title);  
SB.Append("ntDescription: " + this.Description);  
SB.Append("ntCopyright: " + this.Copyright);  
SB.Append("nEquipment:");  
SB.Append("ntMaker: " + this.EquipmentMaker);  
SB.Append("ntModel: " + this.EquipmentModel);  
SB.Append("ntSoftware: " + this.Software);  
SB.Append("nDate and time:");  
SB.Append("ntGeneral: " + this.DateTimeLastModified.ToString());  
SB.Append("ntOriginal: " + this.DateTimeOriginal.ToString());  
SB.Append("ntDigitized: " + this.DateTimeDigitized.ToString());  
SB.Append("nShooting conditions:");  
SB.Append("ntExposure time: " + this.ExposureTime.ToString("N4") + " s");  
SB.Append("ntExposure program: " + Enum.GetName(typeof(ExposurePrograms), this.ExposureProgram));  
SB.Append("ntExposure mode: " + Enum.GetName(typeof(ExposureMeteringModes), this.ExposureMeteringMode));  
SB.Append("ntAperture: F" + this.Aperture.ToString("N2"));  
SB.Append("ntISO sensitivity: " + this.ISO);  
SB.Append("ntSubject distance: " + this.SubjectDistance.ToString("N2") + " m");  
SB.Append("ntFocal length: " + this.FocalLength);  
SB.Append("ntFlash: " + Enum.GetName(typeof(FlashModes), this.FlashMode));  
SB.Append("ntLight source (WB): " + Enum.GetName(typeof(LightSources), this.LightSource));  
//SB.Replace("n", vbCrLf);  
//SB.Replace("t", vbTab);  
return SB.ToString();  
}  
  
#region Nicely formatted well-known properties  
  
//   
// Brand of equipment (EXIF EquipMake)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public string EquipmentMaker  
{  
get  
{  
return this.GetPropertyString((int)TagNames.EquipMake);  
}  
}  
  
//   
// Model of equipment (EXIF EquipModel)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public string EquipmentModel  
{  
get  
{  
return this.GetPropertyString((int)TagNames.EquipModel);  
}  
}  
  
//   
// Software used for processing (EXIF Software)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public string Software  
{  
get  
{  
return this.GetPropertyString((int)TagNames.SoftwareUsed);  
}  
}  
  
//   
// Orientation of image (position of row 0, column 0) (EXIF Orientation)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public Orientations Orientation  
{  
get  
{  
Int32 X = this.GetPropertyInt16((int)TagNames.Orientation);  
  
if (!Enum.IsDefined(typeof(Orientations), X))  
return Orientations.TopLeft;  
else  
return (Orientations)Enum.Parse(typeof(Orientations), Enum.GetName(typeof(Orientations), X));  
}  
}  
  
//   
// Time when image was last modified (EXIF DateTime).  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public DateTime DateTimeLastModified  
{  
get  
{  
try  
{  
return DateTime.ParseExact(this.GetPropertyString((int)TagNames.DateTime), @"yyyy:MM:dd HH:mm:ss", null);  
}  
catch  
{  
return DateTime.MinValue;  
}  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.DateTime, value.ToString(@"yyyy:MM:dd HH:mm:ss"));  
}  
catch  
{ }  
}  
}  
  
//   
// Time when image was taken (EXIF DateTimeOriginal).  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public DateTime DateTimeOriginal  
{  
get  
{  
try  
{  
return DateTime.ParseExact(this.GetPropertyString((int)TagNames.ExifDTOrig), @"yyyy:MM:dd HH:mm:ss", null);  
}  
catch  
{  
return DateTime.MinValue;  
}  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.ExifDTOrig, value.ToString(@"yyyy:MM:dd HH:mm:ss"));  
}  
catch  
{ }  
}  
}  
  
//   
// Time when image was digitized (EXIF DateTimeDigitized).  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public DateTime DateTimeDigitized  
{  
get  
{  
try  
{  
return DateTime.ParseExact(this.GetPropertyString((int)TagNames.ExifDTDigitized), @"yyyy:MM:dd HH:mm:ss", null);  
}  
catch  
{  
return DateTime.MinValue;  
}  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.ExifDTDigitized, value.ToString(@"yyyy:MM:dd HH:mm:ss"));  
}  
catch  
{ }  
}  
}  
  
//   
// Image width  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
// \[altair\] 04.09.2005 Changed output to Int32, load from image instead of EXIF  
//   
public Int32 Width  
{  
get { return this.\_Image.Width; }  
}  
  
//   
// Image height  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
// \[altair\] 04.09.2005 Changed output to Int32, load from image instead of EXIF  
//   
public Int32 Height  
{  
get { return this.\_Image.Height; }  
}  
  
//   
// X resolution in dpi (EXIF XResolution/ResolutionUnit)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public double ResolutionX  
{  
get  
{  
double R = this.GetPropertyRational((int)TagNames.XResolution).ToDouble();  
  
if (this.GetPropertyInt16((int)TagNames.ResolutionUnit) == 3)  
{  
// -- resolution is in points/cm  
return R \* 2.54;  
}  
else  
{  
// -- resolution is in points/inch  
return R;  
}  
}  
}  
  
//   
// Y resolution in dpi (EXIF YResolution/ResolutionUnit)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public double ResolutionY  
{  
get  
{  
double R = this.GetPropertyRational((int)TagNames.YResolution).ToDouble();  
  
if (this.GetPropertyInt16((int)TagNames.ResolutionUnit) == 3)  
{  
// -- resolution is in points/cm  
return R \* 2.54;  
}  
else  
{  
// -- resolution is in points/inch  
return R;  
}  
}  
}  
  
//   
// Image title (EXIF ImageTitle)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public string Title  
{  
get  
{  
return this.GetPropertyString((int)TagNames.ImageTitle);  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.ImageTitle, value);  
}  
catch { }  
}  
}  
  
//   
// User comment (EXIF UserComment)  
//   
//   
//   
//   
// \[altair\] 13.06.2004 Created  
//   
public string UserComment  
{  
get  
{  
return this.GetPropertyString((int)TagNames.ExifUserComment);  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.ExifUserComment, value);  
}  
catch { }  
}  
}  
  
//   
// Artist name (EXIF Artist)  
//   
//   
//   
//   
// \[altair\] 13.06.2004 Created  
//   
public string Artist  
{  
get  
{  
return this.GetPropertyString((int)TagNames.Artist);  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.Artist, value);  
}  
catch { }  
}  
}  
  
//   
// Image description (EXIF ImageDescription)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public string Description  
{  
get  
{  
return this.GetPropertyString((int)TagNames.ImageDescription);  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.ImageDescription, value);  
}  
catch { }  
}  
}  
  
//   
// Image copyright (EXIF Copyright)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public string Copyright  
{  
get  
{  
return this.GetPropertyString((int)TagNames.Copyright);  
}  
set  
{  
try  
{  
this.SetPropertyString((int)TagNames.Copyright, value);  
}  
catch { }  
}  
}  
  
  
//   
// Exposure time in seconds (EXIF ExifExposureTime/ExifShutterSpeed)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public double ExposureTimeAbs  
{  
get  
{  
if (this.IsPropertyDefined((int)TagNames.ExifExposureTime))  
// -- Exposure time is explicitly specified  
return this.GetPropertyRational((int)TagNames.ExifExposureTime).ToDouble();  
else  
if (this.IsPropertyDefined((int)TagNames.ExifShutterSpeed))  
//'-- Compute exposure time from shutter spee   
return (1 / Math.Pow(2, this.GetPropertyRational((int)TagNames.ExifShutterSpeed).ToDouble()));  
else  
// -- Can't figure out   
return 0;  
}  
}  
  
public Rational ExposureTime  
{  
get  
{  
if (this.IsPropertyDefined((int)TagNames.ExifExposureTime))  
// -- Exposure time is explicitly specified  
return this.GetPropertyRational((int)TagNames.ExifExposureTime);  
else  
return new Rational();  
}  
}  
  
//   
// Aperture value as F number (EXIF ExifFNumber/ExifApertureValue)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public double Aperture  
{  
get  
{  
if (this.IsPropertyDefined((int)TagNames.ExifFNumber))  
return this.GetPropertyRational((int)TagNames.ExifFNumber).ToDouble();  
else  
if (this.IsPropertyDefined((int)TagNames.ExifAperture))  
return Math.Pow(System.Math.Sqrt(2), this.GetPropertyRational((int)TagNames.ExifAperture).ToDouble());  
else  
return 0;  
}  
}  
  
//   
// Exposure program used (EXIF ExifExposureProg)  
//   
//   
// If not specified, returns Normal (2)  
//   
// \[altair\] 10.09.2003 Created  
//   
public ExposurePrograms ExposureProgram  
{  
get  
{  
Int32 X = this.GetPropertyInt16((int)TagNames.ExifExposureProg);  
  
if (Enum.IsDefined(typeof(ExposurePrograms), X))  
return (ExposurePrograms)Enum.Parse(typeof(ExposurePrograms), Enum.GetName(typeof(ExposurePrograms), X));  
else  
return ExposurePrograms.Normal;  
}  
}  
  
//   
// ISO sensitivity  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public Int16 ISO  
{  
get { return this.GetPropertyInt16((int)TagNames.ExifISOSpeed); }  
}  
  
//   
// Subject distance in meters (EXIF SubjectDistance)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public double SubjectDistance  
{  
get { return this.GetPropertyRational((int)TagNames.ExifSubjectDist).ToDouble(); }  
}  
  
//   
// Exposure method metering mode used (EXIF MeteringMode)  
//   
//   
// If not specified, returns Unknown (0)  
//   
// \[altair\] 10.09.2003 Created  
//   
public ExposureMeteringModes ExposureMeteringMode  
{  
get  
{  
Int32 X = this.GetPropertyInt16((int)TagNames.ExifMeteringMode);  
  
if (Enum.IsDefined(typeof(ExposureMeteringModes), X))  
return (ExposureMeteringModes)Enum.Parse(typeof(ExposureMeteringModes), Enum.GetName(typeof(ExposureMeteringModes), X));  
else  
return ExposureMeteringModes.Unknown;  
}  
}  
  
//   
// Focal length of lenses in mm (EXIF FocalLength)  
//   
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public double FocalLength  
{  
get { return this.GetPropertyRational((int)TagNames.ExifFocalLength).ToDouble(); }  
}  
  
//   
// Flash mode (EXIF Flash)  
//   
//   
// If not present, value NotFired (0) is returned  
//   
// \[altair\] 10.09.2003 Created  
//   
public FlashModes FlashMode  
{  
get  
{  
Int32 X = this.GetPropertyInt16((int)TagNames.ExifFlash);  
  
if (Enum.IsDefined(typeof(FlashModes), X))  
return (FlashModes)Enum.Parse(typeof(FlashModes), Enum.GetName(typeof(FlashModes), X));  
else  
return FlashModes.NotFired;  
}  
}  
  
//   
// Light source / white balance (EXIF LightSource)  
//   
//   
// If not specified, returns Unknown (0).  
//   
// \[altair\] 10.09.2003 Created  
//   
public LightSources LightSource  
{  
get  
{  
Int32 X = this.GetPropertyInt16((int)TagNames.ExifLightSource);  
  
if (Enum.IsDefined(typeof(LightSources), X))  
return (LightSources)Enum.Parse(typeof(LightSources), Enum.GetName(typeof(LightSources), X));  
else  
return LightSources.Unknown;  
}  
}  
  
#endregion  
  
#region Support methods for working with EXIF properties  
  
//   
// Checks if current image has specified certain property  
//   
//   
// True if image has specified property, False otherwise.  
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public bool IsPropertyDefined(Int32 PID)  
{  
return (Array.IndexOf(this.\_Image.PropertyIdList, PID) > -1);  
}  
  
//   
// Gets specified Int32 property  
//   
// Property ID  
// Optional, default 0. Default value returned if property is not present.  
// Value of property or DefaultValue if property is not present.  
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public Int32 GetPropertyInt32(Int32 PID)  
{  
return GetPropertyInt32(PID, 0);  
}  
  
public Int32 GetPropertyInt32(Int32 PID, Int32 DefaultValue)  
{  
if (IsPropertyDefined(PID))  
return GetInt32(this.\_Image.GetPropertyItem(PID).Value);  
else  
return DefaultValue;  
}  
  
//   
// Gets specified Int16 property  
//   
// Property ID  
// Optional, default 0. Default value returned if property is not present.  
// Value of property or DefaultValue if property is not present.  
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public Int16 GetPropertyInt16(Int32 PID)  
{  
return GetPropertyInt16(PID, 0);  
}  
  
public Int16 GetPropertyInt16(Int32 PID, Int16 DefaultValue)  
{  
if (IsPropertyDefined(PID))  
return GetInt16(this.\_Image.GetPropertyItem(PID).Value);  
else  
return DefaultValue;  
}  
  
//   
// Gets specified string property  
//   
// Property ID  
// Optional, default String.Empty. Default value returned if property is not present.  
//   
// Value of property or DefaultValue if property is not present.  
//   
// \[altair\] 10.09.2003 Created  
//   
public string GetPropertyString(Int32 PID)  
{  
return GetPropertyString(PID, "");  
}  
  
public string GetPropertyString(Int32 PID, string DefaultValue)  
{  
if (IsPropertyDefined(PID))  
return GetString(this.\_Image.GetPropertyItem(PID).Value);  
else  
return DefaultValue;  
}  
  
//   
// Gets specified property in raw form  
//   
// Property ID  
// Optional, default Nothing. Default value returned if property is not present.  
//   
// Is recommended to use typed methods (like etc.) instead, when possible.  
//   
// \[altair\] 05.09.2005 Created  
//   
public byte\[\] GetProperty(Int32 PID, byte\[\] DefaultValue)  
{  
if (IsPropertyDefined(PID))  
return this.\_Image.GetPropertyItem(PID).Value;  
else  
return DefaultValue;  
}  
  
public byte\[\] GetProperty(Int32 PID)  
{  
return GetProperty(PID, null);  
}  
  
//   
// Gets specified rational property  
//   
// Property ID  
//   
// Value of property or 0/1 if not present.  
//   
// \[altair\] 10.09.2003 Created  
//   
public Rational GetPropertyRational(Int32 PID)  
{  
if (IsPropertyDefined(PID))  
return GetRational(this.\_Image.GetPropertyItem(PID).Value);  
else  
{  
Rational R;  
R.Numerator = 0;  
R.Denominator = 1;  
return R;  
}  
}  
  
//   
// Sets specified string property  
//   
// Property ID  
// Value to be set  
//   
//   
// \[altair\] 12.6.2004 Created  
//   
public void SetPropertyString(Int32 PID, string Value)  
{  
byte\[\] Data = this.\_Encoding.GetBytes(Value + ' ');  
SetProperty(PID, Data, ExifDataTypes.AsciiString);  
}  
  
//   
// Sets specified Int16 property  
//   
// Property ID  
// Value to be set  
//   
//   
// \[altair\] 12.6.2004 Created  
//   
public void SetPropertyInt16(Int32 PID, Int16 Value)  
{  
byte\[\] Data = new byte\[2\];  
Data\[0\] = (byte)(Value & 0xFF);  
Data\[1\] = (byte)((Value & 0xFF00) >> 8);  
SetProperty(PID, Data, ExifDataTypes.SignedShort);  
}  
  
//   
// Sets specified Int32 property  
//   
// Property ID  
// Value to be set  
//   
//   
// \[altair\] 13.06.2004 Created  
//   
public void SetPropertyInt32(Int32 PID, Int32 Value)  
{  
byte\[\] Data = new byte\[4\];  
for (int I = 0; I < 4; I++)  
{  
Data\[I\] = (byte)(Value & 0xFF);  
Value >>= 8;  
}  
SetProperty(PID, Data, ExifDataTypes.SignedLong);  
}  
  
//   
// Sets specified property in raw form  
//   
// Property ID  
// Raw data  
// EXIF data type  
// Is recommended to use typed methods (like etc.) instead, when possible.  
//   
// \[altair\] 12.6.2004 Created  
//   
public void SetProperty(Int32 PID, byte\[\] Data, ExifDataTypes Type)  
{  
System.Drawing.Imaging.PropertyItem P = this.\_Image.PropertyItems\[0\];  
P.Id = PID;  
P.Value = Data;  
P.Type = (Int16)Type;  
P.Len = Data.Length;  
this.\_Image.SetPropertyItem(P);  
}  
  
//   
// Reads Int32 from EXIF bytearray.  
//   
// EXIF bytearray to process  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
// \[altair\] 05.09.2005 Changed from public shared to private instance method  
//   
private Int32 GetInt32(byte\[\] B)  
{  
if (B.Length < 4)  
throw new ArgumentException("Data too short (4 bytes expected)", "B");  
  
return B\[3\] << 24 | B\[2\] << 16 | B\[1\] << 8 | B\[0\];  
}  
  
//   
// Reads Int16 from EXIF bytearray.  
//   
// EXIF bytearray to process  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
// \[altair\] 05.09.2005 Changed from public shared to private instance method  
//   
private Int16 GetInt16(byte\[\] B)  
{  
if (B.Length < 2)  
throw new ArgumentException("Data too short (2 bytes expected)", "B");  
  
return (short)(B\[1\] << 8 | B\[0\]);  
}  
  
//   
// Reads string from EXIF bytearray.  
//   
// EXIF bytearray to process  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
// \[altair\] 05.09.2005 Changed from public shared to private instance method  
//   
private string GetString(byte\[\] B)  
{  
string R = this.\_Encoding.GetString(B);  
if (R.EndsWith(" "))  
R = R.Substring(0, R.Length - 1);  
return R;  
}  
  
//   
// Reads rational from EXIF bytearray.  
//   
// EXIF bytearray to process  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
// \[altair\] 05.09.2005 Changed from public shared to private instance method  
//   
private Rational GetRational(byte\[\] B)  
{  
Rational R = new Rational();  
byte\[\] N = new byte\[4\];  
byte\[\] D = new byte\[4\];  
Array.Copy(B, 0, N, 0, 4);  
Array.Copy(B, 4, D, 0, 4);  
R.Denominator = this.GetInt32(D);  
R.Numerator = this.GetInt32(N);  
return R;  
}  
  
#endregion  
  
#region " IDisposable implementation "  
  
//   
// Disposes unmanaged resources of this class  
//   
//   
//   
// \[altair\] 10.09.2003 Created  
//   
public void Dispose()  
{  
this.\_Image.Dispose();  
}  
  
#endregion  
  
}  
  
}