using System; using System.Collections; using System.Text; using com.drew.metadata; using com.drew.lang; using com.utils; /// /// This class was first written by Drew Noakes in Java. /// /// This is public domain software - that is, you can do whatever you want /// with it, and include it software that is licensed under the GNU or the /// BSD license, or whatever other licence you choose, including proprietary /// closed source licenses. I do ask that you leave this header in tact. /// /// If you make modifications to this code that you think would benefit the /// wider community, please send me a copy and I'll post it on my site. /// /// If you make use of this code, Drew Noakes will appreciate hearing /// about it: drew@drewnoakes.com /// /// Latest Java version of this software kept at /// http://drewnoakes.com/ /// /// The C# class was made by Ferret Renaud: /// renaud91@free.fr /// If you find a bug in the C# code, feel free to mail me. /// namespace com.drew.metadata.exif { /// /// Tag descriptor for almost every images /// public class ExifDescriptor : TagDescriptor { /// /// Dictates whether rational values will be represented in decimal format in instances /// where decimal notation is elegant (such as 1/2 -> 0.5, but not 1/3). /// private readonly bool _allowDecimalRepresentationOfRationals = true; /// /// Constructor of the object /// /// a directory public ExifDescriptor(Directory directory) : base(directory) { } /// /// Returns a descriptive value of the the specified tag for this image. /// Where possible, known values will be substituted here in place of the raw tokens actually /// kept in the Exif segment. /// If no substitution is available, the value provided by GetString(int) will be returned. /// This and GetString(int) are the only 'get' methods that won't throw an exception. /// /// the tag to find a description for /// a description of the image's value for the specified tag, or null if the tag hasn't been defined. public override string GetDescription(int tagType) { switch(tagType) { case ExifDirectory.TAG_ORIENTATION: return GetOrientationDescription(); case ExifDirectory.TAG_RESOLUTION_UNIT: return GetResolutionDescription(); case ExifDirectory.TAG_YCBCR_POSITIONING: return GetYCbCrPositioningDescription(); case ExifDirectory.TAG_EXPOSURE_TIME: return GetExposureTimeDescription(); case ExifDirectory.TAG_SHUTTER_SPEED: return GetShutterSpeedDescription(); case ExifDirectory.TAG_FNUMBER: return GetFNumberDescription(); case ExifDirectory.TAG_X_RESOLUTION: return GetXResolutionDescription(); case ExifDirectory.TAG_Y_RESOLUTION: return GetYResolutionDescription(); case ExifDirectory.TAG_THUMBNAIL_OFFSET: return GetThumbnailOffSetDescription(); case ExifDirectory.TAG_THUMBNAIL_LENGTH: return GetThumbnailLengthDescription(); case ExifDirectory.TAG_COMPRESSION_LEVEL: return GetCompressionLevelDescription(); case ExifDirectory.TAG_SUBJECT_DISTANCE: return GetSubjectDistanceDescription(); case ExifDirectory.TAG_METERING_MODE: return GetMeteringModeDescription(); case ExifDirectory.TAG_WHITE_BALANCE: return GetWhiteBalanceDescription(); case ExifDirectory.TAG_FLASH: return GetFlashDescription(); case ExifDirectory.TAG_FOCAL_LENGTH: return GetFocalLengthDescription(); case ExifDirectory.TAG_COLOR_SPACE: return GetColorSpaceDescription(); case ExifDirectory.TAG_EXIF_IMAGE_WIDTH: return GetExifImageWidthDescription(); case ExifDirectory.TAG_EXIF_IMAGE_HEIGHT: return GetExifImageHeightDescription(); case ExifDirectory.TAG_FOCAL_PLANE_UNIT: return GetFocalPlaneResolutionUnitDescription(); case ExifDirectory.TAG_FOCAL_PLANE_X_RES: return GetFocalPlaneXResolutionDescription(); case ExifDirectory.TAG_FOCAL_PLANE_Y_RES: return GetFocalPlaneYResolutionDescription(); case ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH: return GetThumbnailImageWidthDescription(); case ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT: return GetThumbnailImageHeightDescription(); case ExifDirectory.TAG_BITS_PER_SAMPLE: return GetBitsPerSampleDescription(); case ExifDirectory.TAG_COMPRESSION: return GetCompressionDescription(); case ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION: return GetPhotometricInterpretationDescription(); case ExifDirectory.TAG_ROWS_PER_STRIP: return GetRowsPerStripDescription(); case ExifDirectory.TAG_STRIP_BYTE_COUNTS: return GetStripByteCountsDescription(); case ExifDirectory.TAG_SAMPLES_PER_PIXEL: return GetSamplesPerPixelDescription(); case ExifDirectory.TAG_PLANAR_CONFIGURATION: return GetPlanarConfigurationDescription(); case ExifDirectory.TAG_YCBCR_SUBSAMPLING: return GetYCbCrSubsamplingDescription(); case ExifDirectory.TAG_EXPOSURE_PROGRAM: return GetExposureProgramDescription(); case ExifDirectory.TAG_APERTURE: return GetApertureValueDescription(); case ExifDirectory.TAG_MAX_APERTURE: return GetMaxApertureValueDescription(); case ExifDirectory.TAG_SENSING_METHOD: return GetSensingMethodDescription(); case ExifDirectory.TAG_EXPOSURE_BIAS: return GetExposureBiasDescription(); case ExifDirectory.TAG_FILE_SOURCE: return GetFileSourceDescription(); case ExifDirectory.TAG_SCENE_TYPE: return GetSceneTypeDescription(); case ExifDirectory.TAG_COMPONENTS_CONFIGURATION: return GetComponentConfigurationDescription(); case ExifDirectory.TAG_EXIF_VERSION: return GetExifVersionDescription(); case ExifDirectory.TAG_FLASHPIX_VERSION: return GetFlashPixVersionDescription(); case ExifDirectory.TAG_REFERENCE_BLACK_WHITE: return GetReferenceBlackWhiteDescription(); case ExifDirectory.TAG_ISO_EQUIVALENT: return GetIsoEquivalentDescription(); case ExifDirectory.TAG_THUMBNAIL_DATA: return GetThumbnailDescription(); case ExifDirectory.TAG_XP_AUTHOR: return GetXPAuthorDescription(); case ExifDirectory.TAG_XP_COMMENTS: return GetXPCommentsDescription(); case ExifDirectory.TAG_XP_KEYWORDS: return GetXPKeywordsDescription(); case ExifDirectory.TAG_XP_SUBJECT: return GetXPSubjectDescription(); case ExifDirectory.TAG_XP_TITLE: return GetXPTitleDescription(); default : return _directory.GetString(tagType); } } /// /// Returns the Thumbnail Description. /// /// the Thumbnail Description. private string GetThumbnailDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_THUMBNAIL_DATA)) return null; int[] thumbnailBytes = _directory.GetIntArray(ExifDirectory.TAG_THUMBNAIL_DATA); return BUNDLE["THUMBNAIL_BYTES", thumbnailBytes.Length.ToString()]; } /// /// Returns the Iso Equivalent Description. /// /// the Iso Equivalent Description. private string GetIsoEquivalentDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_ISO_EQUIVALENT)) return null; int isoEquiv = _directory.GetInt(ExifDirectory.TAG_ISO_EQUIVALENT); if (isoEquiv < 50) { isoEquiv *= 200; } return isoEquiv.ToString(); } /// /// Returns the Reference Black White Description. /// /// the Reference Black White Description. private string GetReferenceBlackWhiteDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_REFERENCE_BLACK_WHITE)) return null; int[] ints = _directory.GetIntArray(ExifDirectory.TAG_REFERENCE_BLACK_WHITE); string[] sPos = new string[] {ints[0].ToString(), ints[1].ToString(),ints[2].ToString(),ints[3].ToString(),ints[4].ToString(),ints[5].ToString()}; return BUNDLE["POS",sPos]; } /// /// Returns the Exif Version Description. /// /// the Exif Version Description. private string GetExifVersionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_EXIF_VERSION)) return null; int[] ints = _directory.GetIntArray(ExifDirectory.TAG_EXIF_VERSION); return ExifDescriptor.ConvertBytesToVersionString(ints); } /// /// Returns the Flash Pix Version Description. /// /// the Flash Pix Version Description. private string GetFlashPixVersionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_FLASHPIX_VERSION)) return null; int[] ints = _directory.GetIntArray(ExifDirectory.TAG_FLASHPIX_VERSION); return ExifDescriptor.ConvertBytesToVersionString(ints); } /// /// Returns the Scene Type Description. /// /// the Scene Type Description. private string GetSceneTypeDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_SCENE_TYPE)) return null; int sceneType = _directory.GetInt(ExifDirectory.TAG_SCENE_TYPE); if (sceneType == 1) { return BUNDLE["DIRECTLY_PHOTOGRAPHED_IMAGE"]; } else { return BUNDLE["UNKNOWN", sceneType.ToString()]; } } /// /// Returns the File Source Description. /// /// the File Source Description. private string GetFileSourceDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_FILE_SOURCE)) return null; int fileSource = _directory.GetInt(ExifDirectory.TAG_FILE_SOURCE); if (fileSource == 3) { return BUNDLE["DIGITAL_STILL_CAMERA"]; } else { return BUNDLE["UNKNOWN", fileSource.ToString()]; } } /// /// Returns the Exposure Bias Description. /// /// the Exposure Bias Description. private string GetExposureBiasDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_EXPOSURE_BIAS)) return null; Rational exposureBias = _directory.GetRational(ExifDirectory.TAG_EXPOSURE_BIAS); return exposureBias.ToSimpleString(true); } /// /// Returns the Max Aperture Value Description. /// /// the Max Aperture Value Description. private string GetMaxApertureValueDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_MAX_APERTURE)) return null; double apertureApex = _directory.GetDouble(ExifDirectory.TAG_MAX_APERTURE); double rootTwo = Math.Sqrt(2); double fStop = Math.Pow(rootTwo, apertureApex); return BUNDLE["APERTURE", fStop.ToString("0.#")]; } /// /// Returns the Aperture Value Description. /// /// the Aperture Value Description. private string GetApertureValueDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_APERTURE)) return null; double apertureApex = _directory.GetDouble(ExifDirectory.TAG_APERTURE); double rootTwo = Math.Sqrt(2); double fStop = Math.Pow(rootTwo, apertureApex); return BUNDLE["APERTURE", fStop.ToString("0.#")]; } /// /// Returns the Exposure Program Description. /// /// the Exposure Program Description. private string GetExposureProgramDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_EXPOSURE_PROGRAM)) return null; // '1' means manual control, '2' program normal, '3' aperture priority, // '4' shutter priority, '5' program creative (slow program), // '6' program action(high-speed program), '7' portrait mode, '8' landscape mode. switch (_directory.GetInt(ExifDirectory.TAG_EXPOSURE_PROGRAM)) { case 1 : return BUNDLE["MANUAL_CONTROL"]; case 2 : return BUNDLE["PROGRAM_NORMAL"]; case 3 : return BUNDLE["APERTURE_PRIORITY"]; case 4 : return BUNDLE["SHUTTER_PRIORITY"]; case 5 : return BUNDLE["PROGRAM_CREATIVE"]; case 6 : return BUNDLE["PROGRAM_ACTION"]; case 7 : return BUNDLE["PORTRAIT_MODE"]; case 8 : return BUNDLE["LANDSCAPE_MODE"]; default : return BUNDLE["UNKNOWN_PROGRAM", _directory.GetInt(ExifDirectory.TAG_EXPOSURE_PROGRAM).ToString()]; } } /// /// Returns the YCbCr Subsampling Description. /// /// the YCbCr Subsampling Description. private string GetYCbCrSubsamplingDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_YCBCR_SUBSAMPLING)) return null; int[] positions = _directory.GetIntArray(ExifDirectory.TAG_YCBCR_SUBSAMPLING); if (positions[0] == 2 && positions[1] == 1) { return BUNDLE["YCBCR_422"]; } else if (positions[0] == 2 && positions[1] == 2) { return BUNDLE["YCBCR_420"]; } else { return BUNDLE["UNKNOWN"]; } } /// /// Returns the Planar Configuration Description. /// /// the Planar Configuration Description. private string GetPlanarConfigurationDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_PLANAR_CONFIGURATION)) return null; // When image format is no compression YCbCr, this aValue shows byte aligns of YCbCr // data. If aValue is '1', Y/Cb/Cr aValue is chunky format, contiguous for each subsampling // pixel. If aValue is '2', Y/Cb/Cr aValue is separated and stored to Y plane/Cb plane/Cr // plane format. switch (_directory.GetInt(ExifDirectory.TAG_PLANAR_CONFIGURATION)) { case 1 : return BUNDLE["CHUNKY"]; case 2 : return BUNDLE["SEPARATE"]; default : return BUNDLE["UNKNOWN_CONFIGURATION"]; } } /// /// Returns the Samples Per Pixel Description. /// /// the Samples Per Pixel Description. private string GetSamplesPerPixelDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_SAMPLES_PER_PIXEL)) return null; return BUNDLE["SAMPLES_PIXEL", _directory.GetString(ExifDirectory.TAG_SAMPLES_PER_PIXEL)]; } /// /// Returns the Rows Per Strip Description. /// /// the Rows Per Strip Description. private string GetRowsPerStripDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_ROWS_PER_STRIP)) return null; return BUNDLE["ROWS_STRIP", _directory.GetString(ExifDirectory.TAG_ROWS_PER_STRIP)]; } /// /// Returns the Strip Byte Counts Description. /// /// the Strip Byte Counts Description. private string GetStripByteCountsDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_STRIP_BYTE_COUNTS)) return null; return BUNDLE["BYTES", _directory.GetString(ExifDirectory.TAG_STRIP_BYTE_COUNTS)]; } /// /// Returns the Photometric Interpretation Description. /// /// the Photometric Interpretation Description. private string GetPhotometricInterpretationDescription() { if (!_directory .ContainsTag(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION)) return null; // Shows the color space of the image data components. '1' means monochrome, // '2' means RGB, '6' means YCbCr. switch (_directory .GetInt(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION)) { case 1 : return BUNDLE["MONOCHROME"]; case 2 : return BUNDLE["RGB"]; case 6 : return BUNDLE["YCBCR"]; default : return BUNDLE["UNKNOWN_COLOUR_SPACE"]; } } /// /// Returns the Compression Description. /// /// the Compression Description. private string GetCompressionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_COMPRESSION)) return null; // '1' means no compression, '6' means JPEG compression. switch (_directory.GetInt(ExifDirectory.TAG_COMPRESSION)) { case 1 : return BUNDLE["NO_COMPRESSION"]; case 6 : return BUNDLE["JPEG_COMPRESSION"]; default : return BUNDLE["UNKNOWN_COMPRESSION"]; } } /// /// Returns the Bits Per Sample Description. /// /// the Bits Per Sample Description. private string GetBitsPerSampleDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_BITS_PER_SAMPLE)) return null; return BUNDLE["BITS_COMPONENT_PIXEL",_directory.GetString(ExifDirectory.TAG_BITS_PER_SAMPLE)]; } /// /// Returns the Thumbnail Image Width Description. /// /// the Thumbnail Image Width Description. private string GetThumbnailImageWidthDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH)) return null; return BUNDLE["PIXELS", _directory.GetString(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH)]; } /// /// Returns the Thumbnail Image Height Description. /// /// the Thumbnail Image Height Description. private string GetThumbnailImageHeightDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT)) return null; return BUNDLE["PIXELS", _directory.GetString(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT)]; } /// /// Returns the Focal Plane X Resolution Description. /// /// the Focal Plane X Resolution Description. private string GetFocalPlaneXResolutionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_FOCAL_PLANE_X_RES)) return null; Rational rational = _directory.GetRational(ExifDirectory.TAG_FOCAL_PLANE_X_RES); return BUNDLE["FOCAL_PLANE", rational.GetReciprocal().ToSimpleString(_allowDecimalRepresentationOfRationals), GetFocalPlaneResolutionUnitDescription().ToLower()]; } /// /// Returns the Focal Plane Y Resolution Description. /// /// the Focal Plane Y Resolution Description. private string GetFocalPlaneYResolutionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_COMPRESSION)) return null; Rational rational = _directory.GetRational(ExifDirectory.TAG_FOCAL_PLANE_Y_RES); return BUNDLE["FOCAL_PLANE", rational.GetReciprocal().ToSimpleString(_allowDecimalRepresentationOfRationals), GetFocalPlaneResolutionUnitDescription().ToLower()]; } /// /// Returns the Focal Plane Resolution Unit Description. /// /// the Focal Plane Resolution Unit Description. private string GetFocalPlaneResolutionUnitDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_FOCAL_PLANE_UNIT)) return null; // Unit of FocalPlaneXResoluton/FocalPlaneYResolution. '1' means no-unit, // '2' inch, '3' centimeter. switch (_directory.GetInt(ExifDirectory.TAG_FOCAL_PLANE_UNIT)) { case 1 : return BUNDLE["NO_UNIT"]; case 2 : return BUNDLE["INCHES"]; case 3 : return BUNDLE["CM"]; default : return ""; } } /// /// Returns the Exif Image Width Description. /// /// the Exif Image Width Description. private string GetExifImageWidthDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_EXIF_IMAGE_WIDTH)) return null; return BUNDLE["PIXELS", _directory.GetInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH).ToString()]; } /// /// Returns the Exif Image Height Description. /// /// the Exif Image Height Description. private string GetExifImageHeightDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) return null; return BUNDLE["PIXELS", _directory.GetInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT).ToString()]; } /// /// Returns the Color Space Description. /// /// the Color Space Description. private string GetColorSpaceDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_COLOR_SPACE)) return null; int colorSpace = _directory.GetInt(ExifDirectory.TAG_COLOR_SPACE); if (colorSpace == 1) { return BUNDLE["SRGB"]; } else if (colorSpace == 65535) { return BUNDLE["UNDEFINED"]; } else { return BUNDLE["UNKNOWN"]; } } /// /// Returns the Focal Length Description. /// /// the Focal Length Description. private string GetFocalLengthDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_FOCAL_LENGTH)) return null; Rational focalLength = _directory.GetRational(ExifDirectory.TAG_FOCAL_LENGTH); return BUNDLE["DISTANCE_MM", (focalLength.DoubleValue()).ToString("0.0##")]; } /// /// Returns the Flash Description. /// /// the Flash Description. private string GetFlashDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_FLASH)) return null; // '0' means flash did not fire, '1' flash fired, '5' flash fired but strobe return // light not detected, '7' flash fired and strobe return light detected. switch (_directory.GetInt(ExifDirectory.TAG_FLASH)) { case 0 : return BUNDLE["NO_FLASH_FIRED"]; case 1 : return BUNDLE["FLASH_FIRED"]; case 5 : return BUNDLE["FLASH_FIRED_LIGHT_NOT_DETECTED"]; case 7 : return BUNDLE["FLASH_FIRED_LIGHT_DETECTED"]; default : return BUNDLE["UNKNOWN", _directory.GetInt(ExifDirectory.TAG_FLASH).ToString()]; } } /// /// Returns the White Balance Description. /// /// the White Balance Description. private string GetWhiteBalanceDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_WHITE_BALANCE)) return null; // '0' means unknown, '1' daylight, '2' fluorescent, '3' tungsten, '10' flash, // '17' standard light A, '18' standard light B, '19' standard light C, '20' D55, // '21' D65, '22' D75, '255' other. switch (_directory.GetInt(ExifDirectory.TAG_WHITE_BALANCE)) { case 0 : return BUNDLE["UNKNOWN"]; case 1 : return BUNDLE["DAYLIGHT"]; case 2 : return BUNDLE["FLOURESCENT"]; case 3 : return BUNDLE["TUNGSTEN"]; case 10 : return BUNDLE["FLASH"]; case 17 : return BUNDLE["STANDARD_LIGHT"]; case 18 : return BUNDLE["STANDARD_LIGHT_B"]; case 19 : return BUNDLE["STANDARD_LIGHT_C"]; case 20 : return BUNDLE["D55"]; case 21 : return BUNDLE["D65"]; case 22 : return BUNDLE["D75"]; case 255 : return BUNDLE["OTHER"]; default : return BUNDLE["UNKNOWN", _directory.GetInt(ExifDirectory.TAG_WHITE_BALANCE).ToString()]; } } /// /// Returns the Metering Mode Description. /// /// the Metering Mode Description. private string GetMeteringModeDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_METERING_MODE)) return null; // '0' means unknown, '1' average, '2' center weighted average, '3' spot // '4' multi-spot, '5' multi-segment, '6' partial, '255' other int meteringMode = _directory.GetInt(ExifDirectory.TAG_METERING_MODE); switch (meteringMode) { case 0 : return BUNDLE["UNKNOWN"]; case 1 : return BUNDLE["AVERAGE"]; case 2 : return BUNDLE["CENTER_WEIGHTED_AVERAGE"]; case 3 : return BUNDLE["SPOT"]; case 4 : return BUNDLE["MULTI_SPOT"]; case 5 : return BUNDLE["MULTI_SEGMENT"]; case 6 : return BUNDLE["PARTIAL"]; case 255 : return BUNDLE["OTHER"]; default : return ""; } } /// /// Returns the Subject Distance Description. /// /// the Subject Distance Description. private string GetSubjectDistanceDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_SUBJECT_DISTANCE)) return null; Rational distance = _directory.GetRational(ExifDirectory.TAG_SUBJECT_DISTANCE); return BUNDLE["METRES", (distance.DoubleValue()).ToString("0.0##")]; } /// /// Returns the Compression Level Description. /// /// the Compression Level Description. private string GetCompressionLevelDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_COMPRESSION_LEVEL)) return null; Rational compressionRatio = _directory.GetRational(ExifDirectory.TAG_COMPRESSION_LEVEL); string ratio = compressionRatio.ToSimpleString( _allowDecimalRepresentationOfRationals); if (compressionRatio.IsInteger() && compressionRatio.IntValue() == 1) { return BUNDLE["BIT_PIXEL", ratio]; } else { return BUNDLE["BITS_PIXEL", ratio]; } } /// /// Returns the Thumbnail Length Description. /// /// the Thumbnail Length Description. private string GetThumbnailLengthDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_THUMBNAIL_LENGTH)) return null; return BUNDLE["BYTES", _directory.GetString(ExifDirectory.TAG_THUMBNAIL_LENGTH)]; } /// /// Returns the Thumbnail OffSet Description. /// /// the Thumbnail OffSet Description. private string GetThumbnailOffSetDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_THUMBNAIL_OFFSET)) return null; return BUNDLE["BYTES", _directory.GetString(ExifDirectory.TAG_THUMBNAIL_OFFSET)]; } /// /// Returns the Y Resolution Description. /// /// the Y Resolution Description. private string GetYResolutionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_Y_RESOLUTION)) return null; Rational resolution = _directory.GetRational(ExifDirectory.TAG_Y_RESOLUTION); return BUNDLE["DOTS_PER", resolution.ToSimpleString(_allowDecimalRepresentationOfRationals),GetResolutionDescription().ToLower()]; } /// /// Returns the X Resolution Description. /// /// the X Resolution Description. private string GetXResolutionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_X_RESOLUTION)) return null; Rational resolution = _directory.GetRational(ExifDirectory.TAG_X_RESOLUTION); return BUNDLE["DOTS_PER", resolution.ToSimpleString(_allowDecimalRepresentationOfRationals),GetResolutionDescription().ToLower()]; } /// /// Returns the Exposure Time Description. /// /// the Exposure Time Description. private string GetExposureTimeDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_EXPOSURE_TIME)) return null; return BUNDLE["SEC", _directory.GetString(ExifDirectory.TAG_EXPOSURE_TIME)]; } /// /// Returns the Shutter Speed Description. /// /// the Shutter Speed Description. private string GetShutterSpeedDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_SHUTTER_SPEED)) return null; // Incorrect math bug fixed by Hendrik Wördehoff - 20 Sep 2002 int apexValue = _directory.GetInt(ExifDirectory.TAG_SHUTTER_SPEED); // int apexPower = (int)(Math.pow(2.0, apexValue) + 0.5); // addition of 0.5 removed upon suggestion of Varuni Witana, who // detected incorrect values for Canon cameras, // which calculate both shutterspeed and exposuretime int apexPower = (int) Math.Pow(2.0, apexValue); return BUNDLE["SHUTTER_SPEED", apexPower.ToString()]; } /// /// Returns the F Number Description. /// /// the F Number Description. private string GetFNumberDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_FNUMBER)) return null; Rational fNumber = _directory.GetRational(ExifDirectory.TAG_FNUMBER); return BUNDLE["APERTURE", fNumber.DoubleValue().ToString("0.#")]; } /// /// Returns the YCbCr Positioning Description. /// /// the YCbCr Positioning Description. private string GetYCbCrPositioningDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_YCBCR_POSITIONING)) return null; int yCbCrPosition = _directory.GetInt(ExifDirectory.TAG_YCBCR_POSITIONING); switch (yCbCrPosition) { case 1 : return BUNDLE["CENTER_OF_PIXEL_ARRAY"]; case 2 : return BUNDLE["DATUM_POINT"]; default : return yCbCrPosition.ToString(); } } /// /// Returns the Orientation Description. /// /// the Orientation Description. private string GetOrientationDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_ORIENTATION)) return null; int orientation = _directory.GetInt(ExifDirectory.TAG_ORIENTATION); switch (orientation) { case 1 : return BUNDLE["TOP_LEFT_SIDE"]; case 2 : return BUNDLE["TOP_RIGHT_SIDE"]; case 3 : return BUNDLE["BOTTOM_RIGHT_SIDE"]; case 4 : return BUNDLE["BOTTOM_LEFT_SIDE"]; case 5 : return BUNDLE["LEFT_SIDE_TOP"]; case 6 : return BUNDLE["RIGHT_SIDE_TOP"]; case 7 : return BUNDLE["RIGHT_SIDE_BOTTOM"]; case 8 : return BUNDLE["LEFT_SIDE_BOTTOM"]; default : return orientation.ToString(); } } /// /// Returns the Resolution Description. /// /// the Resolution Description. private string GetResolutionDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_RESOLUTION_UNIT)) return ""; // '1' means no-unit, '2' means inch, '3' means centimeter. Default aValue is '2'(inch) int resolutionUnit = _directory.GetInt(ExifDirectory.TAG_RESOLUTION_UNIT); switch (resolutionUnit) { case 1 : return BUNDLE["NO_UNIT"]; case 2 : return BUNDLE["INCHES"]; case 3 : return BUNDLE["CM"]; default : return ""; } } /// /// Returns the Sensing Method Description. /// /// the Sensing Method Description. private string GetSensingMethodDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_SENSING_METHOD)) return null; // '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, 'Other' reserved int sensingMethod = _directory.GetInt(ExifDirectory.TAG_SENSING_METHOD); switch (sensingMethod) { case 1 : return BUNDLE["NOT_DEFINED"]; case 2 : return BUNDLE["ONE_CHIP_COLOR"]; case 3 : return BUNDLE["TWO_CHIP_COLOR"]; case 4 : return BUNDLE["THREE_CHIP_COLOR"]; case 5 : return BUNDLE["COLOR_SEQUENTIAL"]; case 7 : return BUNDLE["TRILINEAR_SENSOR"]; case 8 : return BUNDLE["COLOR_SEQUENTIAL_LINEAR"]; default : return ""; } } /// /// Returns the XP author description. /// /// the XP author description. private string GetXPAuthorDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_XP_AUTHOR)) return null; return Utils.Decode(_directory.GetByteArray(ExifDirectory.TAG_XP_AUTHOR), true); } /// /// Returns the XP comments description. /// /// the XP comments description. private string GetXPCommentsDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_XP_COMMENTS)) return null; return Utils.Decode(_directory.GetByteArray(ExifDirectory.TAG_XP_COMMENTS), true); } /// /// Returns the XP keywords description. /// /// the XP keywords description. private string GetXPKeywordsDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_XP_KEYWORDS)) return null; return Utils.Decode(_directory.GetByteArray(ExifDirectory.TAG_XP_KEYWORDS), true); } /// /// Returns the XP subject description. /// /// the XP subject description. private string GetXPSubjectDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_XP_SUBJECT)) return null; return Utils.Decode(_directory.GetByteArray(ExifDirectory.TAG_XP_SUBJECT), true); } /// /// Returns the XP title description. /// /// the XP title description. private string GetXPTitleDescription() { if (!_directory.ContainsTag(ExifDirectory.TAG_XP_TITLE)) return null; return Utils.Decode(_directory.GetByteArray(ExifDirectory.TAG_XP_TITLE), true); } /// /// Returns the Component Configuration Description. /// /// the Component Configuration Description. private string GetComponentConfigurationDescription() { int[] components = _directory.GetIntArray(ExifDirectory.TAG_COMPONENTS_CONFIGURATION); string[] componentStrings = { "", "Y", "Cb", "Cr", "R", "G", "B" }; StringBuilder componentConfig = new StringBuilder(); for (int i = 0; i < Math.Min(4, components.Length); i++) { int j = components[i]; if (j > 0 && j < componentStrings.Length) { componentConfig.Append(componentStrings[j]); } } return componentConfig.ToString(); } /// /// Takes a series of 4 bytes from the specified offSet, and converts these to a /// well-known version number, where possible. For example, (hex) 30 32 31 30 == 2.10). /// /// the four version values /// the version as a string of form 2.10 public static string ConvertBytesToVersionString(int[] components) { StringBuilder version = new StringBuilder(); for (int i = 0; i < 4 && i < components.Length; i++) { if (i == 2) version.Append('.'); string digit = ((char) components[i]).ToString(); if (i == 0 && "0".Equals(digit)) continue; version.Append(digit); } return version.ToString(); } } }